-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2147 from terraform-providers/paddy_new_appengine
Add google_app_engine_application resource.
- Loading branch information
Showing
6 changed files
with
452 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/hashicorp/terraform/helper/customdiff" | ||
"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, | ||
}, | ||
|
||
CustomizeDiff: customdiff.All( | ||
appEngineApplicationLocationIDCustomizeDiff, | ||
), | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"project": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
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, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
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 | ||
} | ||
|
||
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 { | ||
d.SetId("") | ||
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() | ||
if err != nil { | ||
return handleNotFoundError(err, d, fmt.Sprintf("App Engine Application %q", pid)) | ||
} | ||
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 { | ||
log.Println("[WARN] App Engine applications cannot be destroyed once created. The project must be deleted to delete the application.") | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccAppEngineApplication_basic(t *testing.T) { | ||
t.Parallel() | ||
|
||
org := getTestOrgFromEnv(t) | ||
pid := acctest.RandomWithPrefix("tf-test") | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAppEngineApplication_basic(pid, org), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrSet("google_app_engine_application.acceptance", "url_dispatch_rule.#"), | ||
resource.TestCheckResourceAttrSet("google_app_engine_application.acceptance", "name"), | ||
resource.TestCheckResourceAttrSet("google_app_engine_application.acceptance", "code_bucket"), | ||
resource.TestCheckResourceAttrSet("google_app_engine_application.acceptance", "default_hostname"), | ||
resource.TestCheckResourceAttrSet("google_app_engine_application.acceptance", "default_bucket"), | ||
), | ||
}, | ||
{ | ||
ResourceName: "google_app_engine_application.acceptance", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
{ | ||
Config: testAccAppEngineApplication_update(pid, org), | ||
}, | ||
{ | ||
ResourceName: "google_app_engine_application.acceptance", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccAppEngineApplication_basic(pid, org string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
project_id = "%s" | ||
name = "%s" | ||
org_id = "%s" | ||
} | ||
resource "google_app_engine_application" "acceptance" { | ||
project = "${google_project.acceptance.project_id}" | ||
auth_domain = "hashicorptest.com" | ||
location_id = "us-central" | ||
serving_status = "SERVING" | ||
}`, pid, pid, org) | ||
} | ||
|
||
func testAccAppEngineApplication_update(pid, org string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
project_id = "%s" | ||
name = "%s" | ||
org_id = "%s" | ||
} | ||
resource "google_app_engine_application" "acceptance" { | ||
project = "${google_project.acceptance.project_id}" | ||
auth_domain = "tf-test.club" | ||
location_id = "us-central" | ||
serving_status = "USER_DISABLED" | ||
}`, pid, pid, org) | ||
} |
Oops, something went wrong.