diff --git a/.changelog/5637.txt b/.changelog/5637.txt new file mode 100644 index 00000000000..a03d9b51b56 --- /dev/null +++ b/.changelog/5637.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +google_apikeys_key +``` diff --git a/go.mod b/go.mod index 2282769d92a..c6ef301953e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/hashicorp/terraform-provider-google require ( cloud.google.com/go/bigtable v1.10.1 cloud.google.com/go/iam v0.1.1 // indirect - github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220225200700-e76d50f1e637 + github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220304175357-35332d17a512 github.com/apparentlymart/go-cidr v1.1.0 github.com/client9/misspell v0.3.4 github.com/davecgh/go-spew v1.1.1 diff --git a/go.sum b/go.sum index 679de1d14a9..a34049ff869 100644 --- a/go.sum +++ b/go.sum @@ -1530,4 +1530,6 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220225200700-e76d50f1e637 h1:+s2wWcAciNo96AT+Ci9pwXuWm9qlY/ubLFWRaqE0tZg= -github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220225200700-e76d50f1e637/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= \ No newline at end of file +github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220225200700-e76d50f1e637/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= +github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220304175357-35332d17a512 h1:8/Sn9pDdk/RxECtLUh4xum2eyUvf0h7bpx8h+lYvE+Q= +github.com/GoogleCloudPlatform/declarative-resource-client-library v0.0.0-20220304175357-35332d17a512/go.mod h1:UJoDYx6t3+xCOd+dZX8+NrEB+Y/eW1pQlvxh2Gt7y5E= diff --git a/google/config.go b/google/config.go index a8e5d43c89c..46c30396b4b 100644 --- a/google/config.go +++ b/google/config.go @@ -253,6 +253,7 @@ type Config struct { NetworkConnectivityBasePath string OrgPolicyBasePath string RecaptchaEnterpriseBasePath string + ApikeysBasePath string // CloudBuild WorkerPool uses a different endpoint (v1beta1) than any other CloudBuild resources CloudBuildWorkerPoolBasePath string } diff --git a/google/provider.go b/google/provider.go index 4ae7ccff3e0..c24a7b52711 100644 --- a/google/provider.go +++ b/google/provider.go @@ -702,6 +702,7 @@ func Provider() *schema.Provider { RecaptchaEnterpriseEndpointEntryKey: RecaptchaEnterpriseEndpointEntry, ContainerAwsCustomEndpointEntryKey: ContainerAwsCustomEndpointEntry, ContainerAzureCustomEndpointEntryKey: ContainerAzureCustomEndpointEntry, + ApikeysEndpointEntryKey: ApikeysEndpointEntry, CloudBuildWorkerPoolEndpointEntryKey: CloudBuildWorkerPoolEndpointEntry, }, @@ -1219,6 +1220,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { }, // resources implemented within tpgtools map[string]*schema.Resource{ + "google_apikeys_key": resourceApikeysKey(), "google_assured_workloads_workload": resourceAssuredWorkloadsWorkload(), "google_cloudbuild_worker_pool": resourceCloudbuildWorkerPool(), "google_compute_firewall_policy_association": resourceComputeFirewallPolicyAssociation(), @@ -1466,6 +1468,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.BigtableAdminBasePath = d.Get(BigtableAdminCustomEndpointEntryKey).(string) // dcl + config.ApikeysBasePath = d.Get(ApikeysEndpointEntryKey).(string) config.AssuredWorkloadsBasePath = d.Get(AssuredWorkloadsEndpointEntryKey).(string) config.CloudResourceManagerBasePath = d.Get(CloudResourceManagerEndpointEntryKey).(string) config.EventarcBasePath = d.Get(EventarcEndpointEntryKey).(string) diff --git a/google/provider_dcl_client_creation.go b/google/provider_dcl_client_creation.go index 7f5363944c1..dfd3a7d6fa3 100644 --- a/google/provider_dcl_client_creation.go +++ b/google/provider_dcl_client_creation.go @@ -19,6 +19,7 @@ import ( dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" "time" + apikeys "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/apikeys" assuredworkloads "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/assuredworkloads" bigqueryreservation "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/bigqueryreservation" cloudbuild "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/cloudbuild" @@ -35,6 +36,29 @@ import ( recaptchaenterprise "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/recaptchaenterprise" ) +func NewDCLApikeysClient(config *Config, userAgent, billingProject string, timeout time.Duration) *apikeys.Client { + configOptions := []dcl.ConfigOption{ + dcl.WithHTTPClient(config.client), + dcl.WithUserAgent(userAgent), + dcl.WithLogger(dclLogger{}), + dcl.WithBasePath(config.ApikeysBasePath), + } + + if timeout != 0 { + configOptions = append(configOptions, dcl.WithTimeout(timeout)) + } + + if config.UserProjectOverride { + configOptions = append(configOptions, dcl.WithUserProjectOverride()) + if billingProject != "" { + configOptions = append(configOptions, dcl.WithBillingProject(billingProject)) + } + } + + dclConfig := dcl.NewConfig(configOptions...) + return apikeys.NewClient(dclConfig) +} + func NewDCLAssuredWorkloadsClient(config *Config, userAgent, billingProject string, timeout time.Duration) *assuredworkloads.Client { configOptions := []dcl.ConfigOption{ dcl.WithHTTPClient(config.client), diff --git a/google/provider_dcl_endpoints.go b/google/provider_dcl_endpoints.go index 2fef6c6294e..632335d2831 100644 --- a/google/provider_dcl_endpoints.go +++ b/google/provider_dcl_endpoints.go @@ -22,6 +22,15 @@ import ( // empty string is passed for dcl default since dcl // [hardcodes the values](https://github.com/GoogleCloudPlatform/declarative-resource-client-library/blob/main/services/google/eventarc/beta/trigger_internal.go#L96-L103) +var ApikeysEndpointEntryKey = "apikeys_custom_endpoint" +var ApikeysEndpointEntry = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.MultiEnvDefaultFunc([]string{ + "GOOGLE_APIKEYS_CUSTOM_ENDPOINT", + }, ""), +} + var AssuredWorkloadsEndpointEntryKey = "assured_workloads_custom_endpoint" var AssuredWorkloadsEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -131,6 +140,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ } //Add new values to config.go.erb config object declaration +//ApikeysBasePath string //AssuredWorkloadsBasePath string //CloudBuildWorkerPoolBasePath string //CloudResourceManagerBasePath string @@ -145,6 +155,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ //RecaptchaEnterpriseBasePath string //Add new values to provider.go.erb schema initialization +// ApikeysEndpointEntryKey: ApikeysEndpointEntry, // AssuredWorkloadsEndpointEntryKey: AssuredWorkloadsEndpointEntry, // CloudBuildWorkerPoolEndpointEntryKey: CloudBuildWorkerPoolEndpointEntry, // CloudResourceManagerEndpointEntryKey: CloudResourceManagerEndpointEntry, @@ -159,6 +170,7 @@ var RecaptchaEnterpriseEndpointEntry = &schema.Schema{ // RecaptchaEnterpriseEndpointEntryKey: RecaptchaEnterpriseEndpointEntry, //Add new values to provider.go.erb - provider block read +// config.ApikeysBasePath = d.Get(ApikeysEndpointEntryKey).(string) // config.AssuredWorkloadsBasePath = d.Get(AssuredWorkloadsEndpointEntryKey).(string) // config.CloudBuildWorkerPoolBasePath = d.Get(CloudBuildWorkerPoolEndpointEntryKey).(string) // config.CloudResourceManagerBasePath = d.Get(CloudResourceManagerEndpointEntryKey).(string) diff --git a/google/resource_apikeys_key.go b/google/resource_apikeys_key.go new file mode 100644 index 00000000000..2c2914cfc30 --- /dev/null +++ b/google/resource_apikeys_key.go @@ -0,0 +1,680 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + apikeys "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/apikeys" +) + +func resourceApikeysKey() *schema.Resource { + return &schema.Resource{ + Create: resourceApikeysKeyCreate, + Read: resourceApikeysKeyRead, + Update: resourceApikeysKeyUpdate, + Delete: resourceApikeysKeyDelete, + + Importer: &schema.ResourceImporter{ + State: resourceApikeysKeyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The resource name of the key. The name must be unique within the project, must conform with RFC-1034, is restricted to lower-cased letters, and has a maximum length of 63 characters. In another word, the name must match the regular expression: [a-z]([a-z0-9-]{0,61}[a-z0-9])?.", + }, + + "display_name": { + Type: schema.TypeString, + Optional: true, + Description: "Human-readable display name of this API key. Modifiable by user.", + }, + + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + Description: "The project for the resource", + }, + + "restrictions": { + Type: schema.TypeList, + Optional: true, + Description: "Key restrictions.", + MaxItems: 1, + Elem: ApikeysKeyRestrictionsSchema(), + }, + + "key_string": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Output only. An encrypted and signed value held by this key. This field can be accessed only through the `GetKeyString` method.", + }, + }, + } +} + +func ApikeysKeyRestrictionsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "android_key_restrictions": { + Type: schema.TypeList, + Optional: true, + Description: "The Android apps that are allowed to use the key.", + MaxItems: 1, + Elem: ApikeysKeyRestrictionsAndroidKeyRestrictionsSchema(), + }, + + "api_targets": { + Type: schema.TypeList, + Optional: true, + Description: "A restriction for a specific service and optionally one or more specific methods. Requests are allowed if they match any of these restrictions. If no restrictions are specified, all targets are allowed.", + Elem: ApikeysKeyRestrictionsApiTargetsSchema(), + }, + + "browser_key_restrictions": { + Type: schema.TypeList, + Optional: true, + Description: "The HTTP referrers (websites) that are allowed to use the key.", + MaxItems: 1, + Elem: ApikeysKeyRestrictionsBrowserKeyRestrictionsSchema(), + }, + + "ios_key_restrictions": { + Type: schema.TypeList, + Optional: true, + Description: "The iOS apps that are allowed to use the key.", + MaxItems: 1, + Elem: ApikeysKeyRestrictionsIosKeyRestrictionsSchema(), + }, + + "server_key_restrictions": { + Type: schema.TypeList, + Optional: true, + Description: "The IP addresses of callers that are allowed to use the key.", + MaxItems: 1, + Elem: ApikeysKeyRestrictionsServerKeyRestrictionsSchema(), + }, + }, + } +} + +func ApikeysKeyRestrictionsAndroidKeyRestrictionsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_applications": { + Type: schema.TypeList, + Required: true, + Description: "A list of Android applications that are allowed to make API calls with this key.", + Elem: ApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsSchema(), + }, + }, + } +} + +func ApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "package_name": { + Type: schema.TypeString, + Required: true, + Description: "The package name of the application.", + }, + + "sha1_fingerprint": { + Type: schema.TypeString, + Required: true, + Description: "The SHA1 fingerprint of the application. For example, both sha1 formats are acceptable : DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 or DA39A3EE5E6B4B0D3255BFEF95601890AFD80709. Output format is the latter.", + }, + }, + } +} + +func ApikeysKeyRestrictionsApiTargetsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "service": { + Type: schema.TypeString, + Required: true, + Description: "The service for this restriction. It should be the canonical service name, for example: `translate.googleapis.com`. You can use `gcloud services list` to get a list of services that are enabled in the project.", + }, + + "methods": { + Type: schema.TypeList, + Optional: true, + Description: "Optional. List of one or more methods that can be called. If empty, all methods for the service are allowed. A wildcard (*) can be used as the last symbol. Valid examples: `google.cloud.translate.v2.TranslateService.GetSupportedLanguage` `TranslateText` `Get*` `translate.googleapis.com.Get*`", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ApikeysKeyRestrictionsBrowserKeyRestrictionsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_referrers": { + Type: schema.TypeList, + Required: true, + Description: "A list of regular expressions for the referrer URLs that are allowed to make API calls with this key.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ApikeysKeyRestrictionsIosKeyRestrictionsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_bundle_ids": { + Type: schema.TypeList, + Required: true, + Description: "A list of bundle IDs that are allowed when making API calls with this key.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ApikeysKeyRestrictionsServerKeyRestrictionsSchema() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_ips": { + Type: schema.TypeList, + Required: true, + Description: "A list of the caller IP addresses that are allowed to make API calls with this key.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func resourceApikeysKeyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &apikeys.Key{ + Name: dcl.String(d.Get("name").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Project: dcl.String(project), + Restrictions: expandApikeysKeyRestrictions(d.Get("restrictions")), + } + + id, err := replaceVarsForId(d, config, "projects/{{project}}/locations/global/keys/{{name}}") + if err != nil { + return fmt.Errorf("error constructing id: %s", err) + } + d.SetId(id) + createDirective := CreateDirective + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLApikeysClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutCreate)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.ApplyKey(context.Background(), obj, createDirective...) + + if _, ok := err.(dcl.DiffAfterApplyError); ok { + log.Printf("[DEBUG] Diff after apply returned from the DCL: %s", err) + } else if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error creating Key: %s", err) + } + + log.Printf("[DEBUG] Finished creating Key %q: %#v", d.Id(), res) + + return resourceApikeysKeyRead(d, meta) +} + +func resourceApikeysKeyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &apikeys.Key{ + Name: dcl.String(d.Get("name").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Project: dcl.String(project), + Restrictions: expandApikeysKeyRestrictions(d.Get("restrictions")), + } + + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLApikeysClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutRead)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.GetKey(context.Background(), obj) + if err != nil { + resourceName := fmt.Sprintf("ApikeysKey %q", d.Id()) + return handleNotFoundDCLError(err, d, resourceName) + } + + if err = d.Set("name", res.Name); err != nil { + return fmt.Errorf("error setting name in state: %s", err) + } + if err = d.Set("display_name", res.DisplayName); err != nil { + return fmt.Errorf("error setting display_name in state: %s", err) + } + if err = d.Set("project", res.Project); err != nil { + return fmt.Errorf("error setting project in state: %s", err) + } + if err = d.Set("restrictions", flattenApikeysKeyRestrictions(res.Restrictions)); err != nil { + return fmt.Errorf("error setting restrictions in state: %s", err) + } + + return nil +} +func resourceApikeysKeyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &apikeys.Key{ + Name: dcl.String(d.Get("name").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Project: dcl.String(project), + Restrictions: expandApikeysKeyRestrictions(d.Get("restrictions")), + } + directive := UpdateDirective + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + billingProject := "" + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLApikeysClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutUpdate)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + res, err := client.ApplyKey(context.Background(), obj, directive...) + + if _, ok := err.(dcl.DiffAfterApplyError); ok { + log.Printf("[DEBUG] Diff after apply returned from the DCL: %s", err) + } else if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error updating Key: %s", err) + } + + log.Printf("[DEBUG] Finished creating Key %q: %#v", d.Id(), res) + + return resourceApikeysKeyRead(d, meta) +} + +func resourceApikeysKeyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + project, err := getProject(d, config) + if err != nil { + return err + } + + obj := &apikeys.Key{ + Name: dcl.String(d.Get("name").(string)), + DisplayName: dcl.String(d.Get("display_name").(string)), + Project: dcl.String(project), + Restrictions: expandApikeysKeyRestrictions(d.Get("restrictions")), + } + + log.Printf("[DEBUG] Deleting Key %q", d.Id()) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + billingProject := project + // err == nil indicates that the billing_project value was found + if bp, err := getBillingProject(d, config); err == nil { + billingProject = bp + } + client := NewDCLApikeysClient(config, userAgent, billingProject, d.Timeout(schema.TimeoutDelete)) + if bp, err := replaceVars(d, config, client.Config.BasePath); err != nil { + d.SetId("") + return fmt.Errorf("Could not format %q: %w", client.Config.BasePath, err) + } else { + client.Config.BasePath = bp + } + if err := client.DeleteKey(context.Background(), obj); err != nil { + return fmt.Errorf("Error deleting Key: %s", err) + } + + log.Printf("[DEBUG] Finished deleting Key %q", d.Id()) + return nil +} + +func resourceApikeysKeyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + + if err := parseImportId([]string{ + "projects/(?P[^/]+)/locations/global/keys/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := replaceVarsForId(d, config, "projects/{{project}}/locations/global/keys/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func expandApikeysKeyRestrictions(o interface{}) *apikeys.KeyRestrictions { + if o == nil { + return apikeys.EmptyKeyRestrictions + } + objArr := o.([]interface{}) + if len(objArr) == 0 { + return apikeys.EmptyKeyRestrictions + } + obj := objArr[0].(map[string]interface{}) + return &apikeys.KeyRestrictions{ + AndroidKeyRestrictions: expandApikeysKeyRestrictionsAndroidKeyRestrictions(obj["android_key_restrictions"]), + ApiTargets: expandApikeysKeyRestrictionsApiTargetsArray(obj["api_targets"]), + BrowserKeyRestrictions: expandApikeysKeyRestrictionsBrowserKeyRestrictions(obj["browser_key_restrictions"]), + IosKeyRestrictions: expandApikeysKeyRestrictionsIosKeyRestrictions(obj["ios_key_restrictions"]), + ServerKeyRestrictions: expandApikeysKeyRestrictionsServerKeyRestrictions(obj["server_key_restrictions"]), + } +} + +func flattenApikeysKeyRestrictions(obj *apikeys.KeyRestrictions) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "android_key_restrictions": flattenApikeysKeyRestrictionsAndroidKeyRestrictions(obj.AndroidKeyRestrictions), + "api_targets": flattenApikeysKeyRestrictionsApiTargetsArray(obj.ApiTargets), + "browser_key_restrictions": flattenApikeysKeyRestrictionsBrowserKeyRestrictions(obj.BrowserKeyRestrictions), + "ios_key_restrictions": flattenApikeysKeyRestrictionsIosKeyRestrictions(obj.IosKeyRestrictions), + "server_key_restrictions": flattenApikeysKeyRestrictionsServerKeyRestrictions(obj.ServerKeyRestrictions), + } + + return []interface{}{transformed} + +} + +func expandApikeysKeyRestrictionsAndroidKeyRestrictions(o interface{}) *apikeys.KeyRestrictionsAndroidKeyRestrictions { + if o == nil { + return apikeys.EmptyKeyRestrictionsAndroidKeyRestrictions + } + objArr := o.([]interface{}) + if len(objArr) == 0 { + return apikeys.EmptyKeyRestrictionsAndroidKeyRestrictions + } + obj := objArr[0].(map[string]interface{}) + return &apikeys.KeyRestrictionsAndroidKeyRestrictions{ + AllowedApplications: expandApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsArray(obj["allowed_applications"]), + } +} + +func flattenApikeysKeyRestrictionsAndroidKeyRestrictions(obj *apikeys.KeyRestrictionsAndroidKeyRestrictions) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "allowed_applications": flattenApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsArray(obj.AllowedApplications), + } + + return []interface{}{transformed} + +} +func expandApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsArray(o interface{}) []apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications { + if o == nil { + return make([]apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications, 0) + } + + objs := o.([]interface{}) + if len(objs) == 0 { + return make([]apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications, 0) + } + + items := make([]apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications, 0, len(objs)) + for _, item := range objs { + i := expandApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplications(item) + items = append(items, *i) + } + + return items +} + +func expandApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplications(o interface{}) *apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications { + if o == nil { + return apikeys.EmptyKeyRestrictionsAndroidKeyRestrictionsAllowedApplications + } + + obj := o.(map[string]interface{}) + return &apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications{ + PackageName: dcl.String(obj["package_name"].(string)), + Sha1Fingerprint: dcl.String(obj["sha1_fingerprint"].(string)), + } +} + +func flattenApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplicationsArray(objs []apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications) []interface{} { + if objs == nil { + return nil + } + + items := []interface{}{} + for _, item := range objs { + i := flattenApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplications(&item) + items = append(items, i) + } + + return items +} + +func flattenApikeysKeyRestrictionsAndroidKeyRestrictionsAllowedApplications(obj *apikeys.KeyRestrictionsAndroidKeyRestrictionsAllowedApplications) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "package_name": obj.PackageName, + "sha1_fingerprint": obj.Sha1Fingerprint, + } + + return transformed + +} +func expandApikeysKeyRestrictionsApiTargetsArray(o interface{}) []apikeys.KeyRestrictionsApiTargets { + if o == nil { + return make([]apikeys.KeyRestrictionsApiTargets, 0) + } + + objs := o.([]interface{}) + if len(objs) == 0 { + return make([]apikeys.KeyRestrictionsApiTargets, 0) + } + + items := make([]apikeys.KeyRestrictionsApiTargets, 0, len(objs)) + for _, item := range objs { + i := expandApikeysKeyRestrictionsApiTargets(item) + items = append(items, *i) + } + + return items +} + +func expandApikeysKeyRestrictionsApiTargets(o interface{}) *apikeys.KeyRestrictionsApiTargets { + if o == nil { + return apikeys.EmptyKeyRestrictionsApiTargets + } + + obj := o.(map[string]interface{}) + return &apikeys.KeyRestrictionsApiTargets{ + Service: dcl.String(obj["service"].(string)), + Methods: expandStringArray(obj["methods"]), + } +} + +func flattenApikeysKeyRestrictionsApiTargetsArray(objs []apikeys.KeyRestrictionsApiTargets) []interface{} { + if objs == nil { + return nil + } + + items := []interface{}{} + for _, item := range objs { + i := flattenApikeysKeyRestrictionsApiTargets(&item) + items = append(items, i) + } + + return items +} + +func flattenApikeysKeyRestrictionsApiTargets(obj *apikeys.KeyRestrictionsApiTargets) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "service": obj.Service, + "methods": obj.Methods, + } + + return transformed + +} + +func expandApikeysKeyRestrictionsBrowserKeyRestrictions(o interface{}) *apikeys.KeyRestrictionsBrowserKeyRestrictions { + if o == nil { + return apikeys.EmptyKeyRestrictionsBrowserKeyRestrictions + } + objArr := o.([]interface{}) + if len(objArr) == 0 { + return apikeys.EmptyKeyRestrictionsBrowserKeyRestrictions + } + obj := objArr[0].(map[string]interface{}) + return &apikeys.KeyRestrictionsBrowserKeyRestrictions{ + AllowedReferrers: expandStringArray(obj["allowed_referrers"]), + } +} + +func flattenApikeysKeyRestrictionsBrowserKeyRestrictions(obj *apikeys.KeyRestrictionsBrowserKeyRestrictions) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "allowed_referrers": obj.AllowedReferrers, + } + + return []interface{}{transformed} + +} + +func expandApikeysKeyRestrictionsIosKeyRestrictions(o interface{}) *apikeys.KeyRestrictionsIosKeyRestrictions { + if o == nil { + return apikeys.EmptyKeyRestrictionsIosKeyRestrictions + } + objArr := o.([]interface{}) + if len(objArr) == 0 { + return apikeys.EmptyKeyRestrictionsIosKeyRestrictions + } + obj := objArr[0].(map[string]interface{}) + return &apikeys.KeyRestrictionsIosKeyRestrictions{ + AllowedBundleIds: expandStringArray(obj["allowed_bundle_ids"]), + } +} + +func flattenApikeysKeyRestrictionsIosKeyRestrictions(obj *apikeys.KeyRestrictionsIosKeyRestrictions) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "allowed_bundle_ids": obj.AllowedBundleIds, + } + + return []interface{}{transformed} + +} + +func expandApikeysKeyRestrictionsServerKeyRestrictions(o interface{}) *apikeys.KeyRestrictionsServerKeyRestrictions { + if o == nil { + return apikeys.EmptyKeyRestrictionsServerKeyRestrictions + } + objArr := o.([]interface{}) + if len(objArr) == 0 { + return apikeys.EmptyKeyRestrictionsServerKeyRestrictions + } + obj := objArr[0].(map[string]interface{}) + return &apikeys.KeyRestrictionsServerKeyRestrictions{ + AllowedIps: expandStringArray(obj["allowed_ips"]), + } +} + +func flattenApikeysKeyRestrictionsServerKeyRestrictions(obj *apikeys.KeyRestrictionsServerKeyRestrictions) interface{} { + if obj == nil || obj.Empty() { + return nil + } + transformed := map[string]interface{}{ + "allowed_ips": obj.AllowedIps, + } + + return []interface{}{transformed} + +} diff --git a/google/resource_apikeys_key_generated_test.go b/google/resource_apikeys_key_generated_test.go new file mode 100644 index 00000000000..94479cfc069 --- /dev/null +++ b/google/resource_apikeys_key_generated_test.go @@ -0,0 +1,475 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "fmt" + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + apikeys "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/apikeys" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "strings" + "testing" +) + +func TestAccApikeysKey_AndroidKey(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "billing_acct": getTestBillingAccountFromEnv(t), + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApikeysKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApikeysKey_AndroidKey(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccApikeysKey_AndroidKeyUpdate0(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccApikeysKey_BasicKey(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "billing_acct": getTestBillingAccountFromEnv(t), + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApikeysKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApikeysKey_BasicKey(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccApikeysKey_BasicKeyUpdate0(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccApikeysKey_IosKey(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "billing_acct": getTestBillingAccountFromEnv(t), + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApikeysKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApikeysKey_IosKey(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccApikeysKey_IosKeyUpdate0(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccApikeysKey_MinimalKey(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "billing_acct": getTestBillingAccountFromEnv(t), + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApikeysKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApikeysKey_MinimalKey(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} +func TestAccApikeysKey_ServerKey(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "billing_acct": getTestBillingAccountFromEnv(t), + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApikeysKeyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApikeysKey_ServerKey(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccApikeysKey_ServerKeyUpdate0(context), + }, + { + ResourceName: "google_apikeys_key.primary", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccApikeysKey_AndroidKey(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + android_key_restrictions { + allowed_applications { + package_name = "com.example.app123" + sha1_fingerprint = "1699466a142d4682a5f91b50fdf400f2358e2b0b" + } + } + + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_AndroidKeyUpdate0(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + android_key_restrictions { + allowed_applications { + package_name = "com.example.app124" + sha1_fingerprint = "1cf89aa28625da86a7e5a7550cf7fd33d611f6fd" + } + } + + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_BasicKey(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + browser_key_restrictions { + allowed_referrers = [".*"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_BasicKeyUpdate0(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key-update" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["POST*"] + service = "maps.googleapis.com" + } + + browser_key_restrictions { + allowed_referrers = [".*com"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_IosKey(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + ios_key_restrictions { + allowed_bundle_ids = ["com.google.app.macos"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_IosKeyUpdate0(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + ios_key_restrictions { + allowed_bundle_ids = ["com.google.alex.ios"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_MinimalKey(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_ServerKey(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + server_key_restrictions { + allowed_ips = ["127.0.0.1"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccApikeysKey_ServerKeyUpdate0(context map[string]interface{}) string { + return Nprintf(` +resource "google_apikeys_key" "primary" { + name = "tf-test-key%{random_suffix}" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + server_key_restrictions { + allowed_ips = ["127.0.0.2", "192.168.1.1"] + } + } +} + +resource "google_project" "basic" { + project_id = "tf-test-app%{random_suffix}" + name = "tf-test-app%{random_suffix}" + org_id = "%{org_id}" +} + + +`, context) +} + +func testAccCheckApikeysKeyDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "rs.google_apikeys_key" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := googleProviderConfig(t) + + billingProject := "" + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + obj := &apikeys.Key{ + Name: dcl.String(rs.Primary.Attributes["name"]), + DisplayName: dcl.String(rs.Primary.Attributes["display_name"]), + Project: dcl.StringOrNil(rs.Primary.Attributes["project"]), + KeyString: dcl.StringOrNil(rs.Primary.Attributes["key_string"]), + } + + client := NewDCLApikeysClient(config, config.userAgent, billingProject, 0) + _, err := client.GetKey(context.Background(), obj) + if err == nil { + return fmt.Errorf("google_apikeys_key still exists %v", obj) + } + } + return nil + } +} diff --git a/google/resource_apikeys_key_sweeper_test.go b/google/resource_apikeys_key_sweeper_test.go new file mode 100644 index 00000000000..104d23d71c6 --- /dev/null +++ b/google/resource_apikeys_key_sweeper_test.go @@ -0,0 +1,71 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: DCL *** +// +// ---------------------------------------------------------------------------- +// +// This file is managed by Magic Modules (https://github.com/GoogleCloudPlatform/magic-modules) +// and is based on the DCL (https://github.com/GoogleCloudPlatform/declarative-resource-client-library). +// Changes will need to be made to the DCL or Magic Modules instead of here. +// +// We are not currently able to accept contributions to this file. If changes +// are required, please file an issue at https://github.com/hashicorp/terraform-provider-google/issues/new/choose +// +// ---------------------------------------------------------------------------- + +package google + +import ( + "context" + "log" + "testing" + + apikeys "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/apikeys" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("ApikeysKey", &resource.Sweeper{ + Name: "ApikeysKey", + F: testSweepApikeysKey, + }) +} + +func testSweepApikeysKey(region string) error { + log.Print("[INFO][SWEEPER_LOG] Starting sweeper for ApikeysKey") + + config, err := sharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := getTestBillingAccountFromEnv(t) + + // Setup variables to be used for Delete arguments. + d := map[string]string{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + } + + client := NewDCLApikeysClient(config, config.userAgent, "", 0) + err = client.DeleteAllKey(context.Background(), d["project"], isDeletableApikeysKey) + if err != nil { + return err + } + return nil +} + +func isDeletableApikeysKey(r *apikeys.Key) bool { + return isSweepableTestResource(*r.Name) +} diff --git a/google/resource_container_aws_cluster.go b/google/resource_container_aws_cluster.go index 00204cd3086..85607990b81 100644 --- a/google/resource_container_aws_cluster.go +++ b/google/resource_container_aws_cluster.go @@ -48,7 +48,6 @@ func resourceContainerAwsCluster() *schema.Resource { "authorization": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. Configuration related to the cluster RBAC settings.", MaxItems: 1, Elem: ContainerAwsClusterAuthorizationSchema(), @@ -181,7 +180,6 @@ func ContainerAwsClusterAuthorizationSchema() *schema.Resource { "admin_users": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. Users to perform operations as a cluster admin. A managed ClusterRoleBinding will be created to grant the `cluster-admin` ClusterRole to the users. At most one user can be specified. For more info on RBAC, see https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles", Elem: ContainerAwsClusterAuthorizationAdminUsersSchema(), }, @@ -195,7 +193,6 @@ func ContainerAwsClusterAuthorizationAdminUsersSchema() *schema.Resource { "username": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "Required. The name of the user, e.g. `my-gcp-id@gmail.com`.", }, }, @@ -208,7 +205,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { "aws_services_authentication": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. Authentication configuration for management of AWS resources.", MaxItems: 1, Elem: ContainerAwsClusterControlPlaneAwsServicesAuthenticationSchema(), @@ -217,7 +213,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { "config_encryption": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. The ARN of the AWS KMS key used to encrypt cluster configuration.", MaxItems: 1, Elem: ContainerAwsClusterControlPlaneConfigEncryptionSchema(), @@ -257,7 +252,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. The AWS instance type. When unspecified, it defaults to `t3.medium`.", }, @@ -274,7 +268,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { "proxy_config": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: "Proxy configuration for outbound HTTP(S) traffic.", MaxItems: 1, Elem: ContainerAwsClusterControlPlaneProxyConfigSchema(), @@ -284,7 +277,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { Type: schema.TypeList, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. Configuration related to the root volume provisioned for each control plane replica. Volumes will be provisioned in the availability zone associated with the corresponding subnet. When unspecified, it defaults to 32 GiB with the GP2 volume type.", MaxItems: 1, Elem: ContainerAwsClusterControlPlaneRootVolumeSchema(), @@ -293,7 +285,6 @@ func ContainerAwsClusterControlPlaneSchema() *schema.Resource { "security_group_ids": { Type: schema.TypeList, Optional: true, - ForceNew: true, Description: "Optional. The IDs of additional security groups to add to control plane replicas. The Anthos Multi-Cloud API will automatically create and manage security groups with the minimum rules needed for a functioning cluster.", Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -324,7 +315,6 @@ func ContainerAwsClusterControlPlaneAwsServicesAuthenticationSchema() *schema.Re "role_arn": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "Required. The Amazon Resource Name (ARN) of the role that the Anthos Multi-Cloud API will assume when managing AWS resources on your account.", }, @@ -332,7 +322,6 @@ func ContainerAwsClusterControlPlaneAwsServicesAuthenticationSchema() *schema.Re Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. An identifier for the assumed role session. When unspecified, it defaults to `multicloud-service-agent`.", }, }, @@ -345,7 +334,6 @@ func ContainerAwsClusterControlPlaneConfigEncryptionSchema() *schema.Resource { "kms_key_arn": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "Required. The ARN of the AWS KMS key used to encrypt cluster configuration.", }, }, @@ -408,14 +396,12 @@ func ContainerAwsClusterControlPlaneProxyConfigSchema() *schema.Resource { "secret_arn": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "The ARN of the AWS Secret Manager secret that contains the HTTP(S) proxy configuration.", }, "secret_version": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "The version string of the AWS Secret Manager secret that contains the HTTP(S) proxy configuration.", }, }, @@ -429,14 +415,12 @@ func ContainerAwsClusterControlPlaneRootVolumeSchema() *schema.Resource { Type: schema.TypeInt, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. The number of I/O operations per second (IOPS) to provision for GP3 volume.", }, "kms_key_arn": { Type: schema.TypeString, Optional: true, - ForceNew: true, Description: "Optional. The Amazon Resource Name (ARN) of the Customer Managed Key (CMK) used to encrypt AWS EBS volumes. If not specified, the default Amazon managed key associated to the AWS region where this cluster runs will be used.", }, @@ -444,7 +428,6 @@ func ContainerAwsClusterControlPlaneRootVolumeSchema() *schema.Resource { Type: schema.TypeInt, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. The size of the volume, in GiBs. When unspecified, a default value is provided. See the specific reference in the parent resource.", }, @@ -452,7 +435,6 @@ func ContainerAwsClusterControlPlaneRootVolumeSchema() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. Type of the EBS volume. When unspecified, it defaults to GP2 volume. Possible values: VOLUME_TYPE_UNSPECIFIED, GP2, GP3", }, }, diff --git a/google/resource_container_azure_cluster.go b/google/resource_container_azure_cluster.go index 99c7db9218c..23f7a0b941f 100644 --- a/google/resource_container_azure_cluster.go +++ b/google/resource_container_azure_cluster.go @@ -48,7 +48,6 @@ func resourceContainerAzureCluster() *schema.Resource { "authorization": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. Configuration related to the cluster RBAC settings.", MaxItems: 1, Elem: ContainerAzureClusterAuthorizationSchema(), @@ -196,7 +195,6 @@ func ContainerAzureClusterAuthorizationSchema() *schema.Resource { "admin_users": { Type: schema.TypeList, Required: true, - ForceNew: true, Description: "Required. Users that can perform operations as a cluster admin. A new ClusterRoleBinding will be created to grant the cluster-admin ClusterRole to the users. At most one user can be specified. For more info on RBAC, see https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles", Elem: ContainerAzureClusterAuthorizationAdminUsersSchema(), }, @@ -210,7 +208,6 @@ func ContainerAzureClusterAuthorizationAdminUsersSchema() *schema.Resource { "username": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "Required. The name of the user, e.g. `my-gcp-id@gmail.com`.", }, }, @@ -300,7 +297,6 @@ func ContainerAzureClusterControlPlaneSchema() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, - ForceNew: true, Description: "Optional. The Azure VM size name. Example: `Standard_DS2_v2`. For available VM sizes, see https://docs.microsoft.com/en-us/azure/virtual-machines/vm-naming-conventions. When unspecified, it defaults to `Standard_DS2_v2`.", }, }, diff --git a/google/resource_dataproc_workflow_template.go b/google/resource_dataproc_workflow_template.go index df549adec12..e296b111b9e 100644 --- a/google/resource_dataproc_workflow_template.go +++ b/google/resource_dataproc_workflow_template.go @@ -1297,7 +1297,7 @@ func DataprocWorkflowTemplatePlacementManagedClusterConfigInitializationActionsS Schema: map[string]*schema.Schema{ "executable_file": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, Description: "Required. Cloud Storage URI of executable file.", }, diff --git a/website/docs/r/apikeys_key.html.markdown b/website/docs/r/apikeys_key.html.markdown new file mode 100644 index 00000000000..40c790919cb --- /dev/null +++ b/website/docs/r/apikeys_key.html.markdown @@ -0,0 +1,281 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: DCL *** +# +# ---------------------------------------------------------------------------- +# +# This file is managed by Magic Modules (https:#github.com/GoogleCloudPlatform/magic-modules) +# and is based on the DCL (https:#github.com/GoogleCloudPlatform/declarative-resource-client-library). +# Changes will need to be made to the DCL or Magic Modules instead of here. +# +# We are not currently able to accept contributions to this file. If changes +# are required, please file an issue at https:#github.com/hashicorp/terraform-provider-google/issues/new/choose +# +# ---------------------------------------------------------------------------- +subcategory: "Apikeys" +layout: "google" +page_title: "Google: google_apikeys_key" +description: |- +The Apikeys Key resource +--- + +# google_apikeys_key + +The Apikeys Key resource + +## Example Usage - android_key +A basic example of a android api keys key +```hcl +resource "google_apikeys_key" "primary" { + name = "key" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + android_key_restrictions { + allowed_applications { + package_name = "com.example.app123" + sha1_fingerprint = "1699466a142d4682a5f91b50fdf400f2358e2b0b" + } + } + + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + } +} + +resource "google_project" "basic" { + project_id = "app" + name = "app" + org_id = "123456789" +} + + +``` +## Example Usage - basic_key +A basic example of a api keys key +```hcl +resource "google_apikeys_key" "primary" { + name = "key" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + browser_key_restrictions { + allowed_referrers = [".*"] + } + } +} + +resource "google_project" "basic" { + project_id = "app" + name = "app" + org_id = "123456789" +} + + +``` +## Example Usage - ios_key +A basic example of a ios api keys key +```hcl +resource "google_apikeys_key" "primary" { + name = "key" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + ios_key_restrictions { + allowed_bundle_ids = ["com.google.app.macos"] + } + } +} + +resource "google_project" "basic" { + project_id = "app" + name = "app" + org_id = "123456789" +} + + +``` +## Example Usage - minimal_key +A minimal example of a api keys key +```hcl +resource "google_apikeys_key" "primary" { + name = "key" + display_name = "sample-key" + project = google_project.basic.name +} + +resource "google_project" "basic" { + project_id = "app" + name = "app" + org_id = "123456789" +} + + +``` +## Example Usage - server_key +A basic example of a server api keys key +```hcl +resource "google_apikeys_key" "primary" { + name = "key" + display_name = "sample-key" + project = google_project.basic.name + + restrictions { + api_targets { + methods = ["GET*"] + service = "translate.googleapis.com" + } + + server_key_restrictions { + allowed_ips = ["127.0.0.1"] + } + } +} + +resource "google_project" "basic" { + project_id = "app" + name = "app" + org_id = "123456789" +} + + +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - + (Required) + The resource name of the key. The name must be unique within the project, must conform with RFC-1034, is restricted to lower-cased letters, and has a maximum length of 63 characters. In another word, the name must match the regular expression: [a-z]([a-z0-9-]{0,61}[a-z0-9])?. + + + +The `allowed_applications` block supports: + +* `package_name` - + (Required) + The package name of the application. + +* `sha1_fingerprint` - + (Required) + The SHA1 fingerprint of the application. For example, both sha1 formats are acceptable : DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 or DA39A3EE5E6B4B0D3255BFEF95601890AFD80709. Output format is the latter. + +- - - + +* `display_name` - + (Optional) + Human-readable display name of this API key. Modifiable by user. + +* `project` - + (Optional) + The project for the resource + +* `restrictions` - + (Optional) + Key restrictions. + + + +The `restrictions` block supports: + +* `android_key_restrictions` - + (Optional) + The Android apps that are allowed to use the key. + +* `api_targets` - + (Optional) + A restriction for a specific service and optionally one or more specific methods. Requests are allowed if they match any of these restrictions. If no restrictions are specified, all targets are allowed. + +* `browser_key_restrictions` - + (Optional) + The HTTP referrers (websites) that are allowed to use the key. + +* `ios_key_restrictions` - + (Optional) + The iOS apps that are allowed to use the key. + +* `server_key_restrictions` - + (Optional) + The IP addresses of callers that are allowed to use the key. + +The `android_key_restrictions` block supports: + +* `allowed_applications` - + (Required) + A list of Android applications that are allowed to make API calls with this key. + +The `api_targets` block supports: + +* `methods` - + (Optional) + Optional. List of one or more methods that can be called. If empty, all methods for the service are allowed. A wildcard (*) can be used as the last symbol. Valid examples: `google.cloud.translate.v2.TranslateService.GetSupportedLanguage` `TranslateText` `Get*` `translate.googleapis.com.Get*` + +* `service` - + (Required) + The service for this restriction. It should be the canonical service name, for example: `translate.googleapis.com`. You can use `gcloud services list` to get a list of services that are enabled in the project. + +The `browser_key_restrictions` block supports: + +* `allowed_referrers` - + (Required) + A list of regular expressions for the referrer URLs that are allowed to make API calls with this key. + +The `ios_key_restrictions` block supports: + +* `allowed_bundle_ids` - + (Required) + A list of bundle IDs that are allowed when making API calls with this key. + +The `server_key_restrictions` block supports: + +* `allowed_ips` - + (Required) + A list of the caller IP addresses that are allowed to make API calls with this key. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/global/keys/{{name}}` + +* `key_string` - + Output only. An encrypted and signed value held by this key. This field can be accessed only through the `GetKeyString` method. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + +Key can be imported using any of these accepted formats: + +``` +$ terraform import google_apikeys_key.default projects/{{project}}/locations/global/keys/{{name}} +$ terraform import google_apikeys_key.default {{project}}/{{name}} +$ terraform import google_apikeys_key.default {{name}} +``` + + + diff --git a/website/google.erb b/website/google.erb index ab568c24512..5bfa0e5c854 100644 --- a/website/google.erb +++ b/website/google.erb @@ -194,6 +194,22 @@ +
  • + Apikeys + +
  • +
  • App Engine