Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
package google
import (
"fmt"
"log"
2018-10-02 23:34:34 +00:00
"github.com/hashicorp/terraform/helper/customdiff"
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
appengine "google.golang.org/api/appengine/v1"
)
func resourceAppEngineApplication ( ) * schema . Resource {
return & schema . Resource {
Create : resourceAppEngineApplicationCreate ,
Read : resourceAppEngineApplicationRead ,
Update : resourceAppEngineApplicationUpdate ,
Delete : resourceAppEngineApplicationDelete ,
Importer : & schema . ResourceImporter {
State : schema . ImportStatePassthrough ,
} ,
2018-10-02 23:34:34 +00:00
CustomizeDiff : customdiff . All (
appEngineApplicationLocationIDCustomizeDiff ,
) ,
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
Schema : map [ string ] * schema . Schema {
"project" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
2018-10-02 23:34:34 +00:00
Computed : true ,
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
ForceNew : true ,
ValidateFunc : validateProjectID ( ) ,
} ,
"auth_domain" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
} ,
"location_id" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
ValidateFunc : validation . StringInSlice ( [ ] string {
"northamerica-northeast1" ,
"us-central" ,
"us-west2" ,
"us-east1" ,
"us-east4" ,
"southamerica-east1" ,
"europe-west" ,
"europe-west2" ,
"europe-west3" ,
"asia-northeast1" ,
"asia-south1" ,
"australia-southeast1" ,
} , false ) ,
} ,
"serving_status" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
ValidateFunc : validation . StringInSlice ( [ ] string {
"UNSPECIFIED" ,
"SERVING" ,
"USER_DISABLED" ,
"SYSTEM_DISABLED" ,
} , false ) ,
Computed : true ,
} ,
"feature_settings" : & schema . Schema {
Type : schema . TypeList ,
Optional : true ,
Computed : true ,
MaxItems : 1 ,
Elem : appEngineApplicationFeatureSettingsResource ( ) ,
} ,
"name" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"url_dispatch_rule" : & schema . Schema {
Type : schema . TypeList ,
Computed : true ,
Elem : appEngineApplicationURLDispatchRuleResource ( ) ,
} ,
"code_bucket" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"default_hostname" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"default_bucket" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"gcr_domain" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
}
}
func appEngineApplicationURLDispatchRuleResource ( ) * schema . Resource {
return & schema . Resource {
Schema : map [ string ] * schema . Schema {
"domain" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"path" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
"service" : & schema . Schema {
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
}
}
func appEngineApplicationFeatureSettingsResource ( ) * schema . Resource {
return & schema . Resource {
Schema : map [ string ] * schema . Schema {
"split_health_checks" : & schema . Schema {
Type : schema . TypeBool ,
Optional : true ,
} ,
} ,
}
}
2018-10-02 23:34:34 +00:00
func appEngineApplicationLocationIDCustomizeDiff ( d * schema . ResourceDiff , meta interface { } ) error {
old , new := d . GetChange ( "location_id" )
if old != "" && old != new {
return fmt . Errorf ( "Cannot change location_id once the resource is created." )
}
return nil
}
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
func resourceAppEngineApplicationCreate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
project , err := getProject ( d , config )
if err != nil {
return err
}
app , err := expandAppEngineApplication ( d , project )
if err != nil {
return err
}
log . Printf ( "[DEBUG] Creating App Engine App" )
op , err := config . clientAppEngine . Apps . Create ( app ) . Do ( )
if err != nil {
return fmt . Errorf ( "Error creating App Engine application: %s" , err . Error ( ) )
}
d . SetId ( project )
// Wait for the operation to complete
waitErr := appEngineOperationWait ( config . clientAppEngine , op , project , "App Engine app to create" )
if waitErr != nil {
2018-10-03 06:41:31 +00:00
d . SetId ( "" )
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
return waitErr
}
log . Printf ( "[DEBUG] Created App Engine App" )
return resourceAppEngineApplicationRead ( d , meta )
}
func resourceAppEngineApplicationRead ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
pid := d . Id ( )
app , err := config . clientAppEngine . Apps . Get ( pid ) . Do ( )
2018-10-02 23:34:34 +00:00
if err != nil {
return handleNotFoundError ( err , d , fmt . Sprintf ( "App Engine Application %q" , pid ) )
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
}
d . Set ( "auth_domain" , app . AuthDomain )
d . Set ( "code_bucket" , app . CodeBucket )
d . Set ( "default_bucket" , app . DefaultBucket )
d . Set ( "default_hostname" , app . DefaultHostname )
d . Set ( "location_id" , app . LocationId )
d . Set ( "name" , app . Name )
d . Set ( "serving_status" , app . ServingStatus )
d . Set ( "project" , pid )
dispatchRules , err := flattenAppEngineApplicationDispatchRules ( app . DispatchRules )
if err != nil {
return err
}
err = d . Set ( "url_dispatch_rule" , dispatchRules )
if err != nil {
return fmt . Errorf ( "Error setting dispatch rules in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s" , err . Error ( ) )
}
featureSettings , err := flattenAppEngineApplicationFeatureSettings ( app . FeatureSettings )
if err != nil {
return err
}
err = d . Set ( "feature_settings" , featureSettings )
if err != nil {
return fmt . Errorf ( "Error setting feature settings in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s" , err . Error ( ) )
}
return nil
}
func resourceAppEngineApplicationUpdate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
pid := d . Id ( )
app , err := expandAppEngineApplication ( d , pid )
if err != nil {
return err
}
log . Printf ( "[DEBUG] Updating App Engine App" )
op , err := config . clientAppEngine . Apps . Patch ( pid , app ) . UpdateMask ( "authDomain,servingStatus,featureSettings.splitHealthChecks" ) . Do ( )
if err != nil {
return fmt . Errorf ( "Error updating App Engine application: %s" , err . Error ( ) )
}
// Wait for the operation to complete
waitErr := appEngineOperationWait ( config . clientAppEngine , op , pid , "App Engine app to update" )
if waitErr != nil {
return waitErr
}
log . Printf ( "[DEBUG] Updated App Engine App" )
return resourceAppEngineApplicationRead ( d , meta )
}
func resourceAppEngineApplicationDelete ( d * schema . ResourceData , meta interface { } ) error {
2018-10-02 23:34:34 +00:00
log . Println ( "[WARN] App Engine applications cannot be destroyed once created. The project must be deleted to delete the application." )
Add google_app_engine_application resource.
Deprecate the app_engine sub-block of google_project, and create a
google_app_engine_application resource instead. Also, add some tests for
its behaviour, as well as some documentation for it.
Note that this is largely an implementation of the ideas discussed in
#2118, except we're not using CustomizeDiff to reject deletions without
our special flag set, because CustomizeDiff apparently doesn't run on
Delete. Who knew? This leaves us rejecting the deletion at apply time,
which is less than ideal, but the only other option I see is to silently
not delete the resource, and that's... not ideal, either.
This also stops the app_engine sub-block on google_project from forcing
new when it's removed, and sets it to computed, so users can safely move
from using the sub-block to using the resource without state surgery or
deleting their entire project. This does mean it's impossible to delete
an App Engine application from a sub-block now, but seeing as that was
the same situation before, and we just papered over it by making the
project recreate itself in that situation, and people Were Not Fans of
that, I'm considering that an acceptable casualty.
2018-10-02 09:59:17 +00:00
return nil
}
func expandAppEngineApplication ( d * schema . ResourceData , project string ) ( * appengine . Application , error ) {
result := & appengine . Application {
AuthDomain : d . Get ( "auth_domain" ) . ( string ) ,
LocationId : d . Get ( "location_id" ) . ( string ) ,
Id : project ,
GcrDomain : d . Get ( "gcr_domain" ) . ( string ) ,
ServingStatus : d . Get ( "serving_status" ) . ( string ) ,
}
featureSettings , err := expandAppEngineApplicationFeatureSettings ( d )
if err != nil {
return nil , err
}
result . FeatureSettings = featureSettings
return result , nil
}
func expandAppEngineApplicationFeatureSettings ( d * schema . ResourceData ) ( * appengine . FeatureSettings , error ) {
blocks := d . Get ( "feature_settings" ) . ( [ ] interface { } )
if len ( blocks ) < 1 {
return nil , nil
}
return & appengine . FeatureSettings {
SplitHealthChecks : d . Get ( "feature_settings.0.split_health_checks" ) . ( bool ) ,
// force send SplitHealthChecks, so if it's set to false it still gets disabled
ForceSendFields : [ ] string { "SplitHealthChecks" } ,
} , nil
}
func flattenAppEngineApplicationFeatureSettings ( settings * appengine . FeatureSettings ) ( [ ] map [ string ] interface { } , error ) {
if settings == nil {
return [ ] map [ string ] interface { } { } , nil
}
result := map [ string ] interface { } {
"split_health_checks" : settings . SplitHealthChecks ,
}
return [ ] map [ string ] interface { } { result } , nil
}
func flattenAppEngineApplicationDispatchRules ( rules [ ] * appengine . UrlDispatchRule ) ( [ ] map [ string ] interface { } , error ) {
results := make ( [ ] map [ string ] interface { } , 0 , len ( rules ) )
for _ , rule := range rules {
results = append ( results , map [ string ] interface { } {
"domain" : rule . Domain ,
"path" : rule . Path ,
"service" : rule . Service ,
} )
}
return results , nil
}