From f20185eafe90236b1b42f99ea53f2f3ea39092bb Mon Sep 17 00:00:00 2001 From: The Magician Date: Tue, 9 Jul 2024 15:23:43 -0700 Subject: [PATCH] Add data_source_google_site_verification_token (#10999) (#7704) [upstream:b33d6de70b36556872c5d0d870116b057878daf2] Signed-off-by: Modular Magician --- .changelog/10999.txt | 3 + google-beta/fwmodels/provider_model.go | 1 + google-beta/fwprovider/framework_provider.go | 6 + google-beta/fwtransport/framework_config.go | 10 ++ google-beta/provider/provider.go | 6 + .../provider/provider_mmv1_resources.go | 2 + ...a_source_google_site_verification_token.go | 149 ++++++++++++++++++ ...rce_google_site_verification_token_test.go | 105 ++++++++++++ google-beta/sweeper/gcp_sweeper_test.go | 1 + google-beta/transport/config.go | 9 ++ .../d/site_verification_token.html.markdown | 84 ++++++++++ 11 files changed, 376 insertions(+) create mode 100644 .changelog/10999.txt create mode 100644 google-beta/services/siteverification/data_source_google_site_verification_token.go create mode 100644 google-beta/services/siteverification/data_source_google_site_verification_token_test.go create mode 100644 website/docs/d/site_verification_token.html.markdown diff --git a/.changelog/10999.txt b/.changelog/10999.txt new file mode 100644 index 0000000000..2de90ada00 --- /dev/null +++ b/.changelog/10999.txt @@ -0,0 +1,3 @@ +```release-note:new-datasource +`google_site_verification_token` +``` \ No newline at end of file diff --git a/google-beta/fwmodels/provider_model.go b/google-beta/fwmodels/provider_model.go index 8500f33274..2512d64d6a 100644 --- a/google-beta/fwmodels/provider_model.go +++ b/google-beta/fwmodels/provider_model.go @@ -148,6 +148,7 @@ type ProviderModel struct { ServiceManagementCustomEndpoint types.String `tfsdk:"service_management_custom_endpoint"` ServiceNetworkingCustomEndpoint types.String `tfsdk:"service_networking_custom_endpoint"` ServiceUsageCustomEndpoint types.String `tfsdk:"service_usage_custom_endpoint"` + SiteVerificationCustomEndpoint types.String `tfsdk:"site_verification_custom_endpoint"` SourceRepoCustomEndpoint types.String `tfsdk:"source_repo_custom_endpoint"` SpannerCustomEndpoint types.String `tfsdk:"spanner_custom_endpoint"` SQLCustomEndpoint types.String `tfsdk:"sql_custom_endpoint"` diff --git a/google-beta/fwprovider/framework_provider.go b/google-beta/fwprovider/framework_provider.go index f9aa372e9f..32d5a6200f 100644 --- a/google-beta/fwprovider/framework_provider.go +++ b/google-beta/fwprovider/framework_provider.go @@ -865,6 +865,12 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, transport_tpg.CustomEndpointValidator(), }, }, + "site_verification_custom_endpoint": &schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + transport_tpg.CustomEndpointValidator(), + }, + }, "source_repo_custom_endpoint": &schema.StringAttribute{ Optional: true, Validators: []validator.String{ diff --git a/google-beta/fwtransport/framework_config.go b/google-beta/fwtransport/framework_config.go index 9215f0ede7..0084069017 100644 --- a/google-beta/fwtransport/framework_config.go +++ b/google-beta/fwtransport/framework_config.go @@ -171,6 +171,7 @@ type FrameworkProviderConfig struct { ServiceManagementBasePath string ServiceNetworkingBasePath string ServiceUsageBasePath string + SiteVerificationBasePath string SourceRepoBasePath string SpannerBasePath string SQLBasePath string @@ -345,6 +346,7 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context, p.ServiceManagementBasePath = data.ServiceManagementCustomEndpoint.ValueString() p.ServiceNetworkingBasePath = data.ServiceNetworkingCustomEndpoint.ValueString() p.ServiceUsageBasePath = data.ServiceUsageCustomEndpoint.ValueString() + p.SiteVerificationBasePath = data.SiteVerificationCustomEndpoint.ValueString() p.SourceRepoBasePath = data.SourceRepoCustomEndpoint.ValueString() p.SpannerBasePath = data.SpannerCustomEndpoint.ValueString() p.SQLBasePath = data.SQLCustomEndpoint.ValueString() @@ -1447,6 +1449,14 @@ func (p *FrameworkProviderConfig) HandleDefaults(ctx context.Context, data *fwmo data.ServiceUsageCustomEndpoint = types.StringValue(customEndpoint.(string)) } } + if data.SiteVerificationCustomEndpoint.IsNull() { + customEndpoint := transport_tpg.MultiEnvDefault([]string{ + "GOOGLE_SITE_VERIFICATION_CUSTOM_ENDPOINT", + }, transport_tpg.DefaultBasePaths[transport_tpg.SiteVerificationBasePathKey]) + if customEndpoint != nil { + data.SiteVerificationCustomEndpoint = types.StringValue(customEndpoint.(string)) + } + } if data.SourceRepoCustomEndpoint.IsNull() { customEndpoint := transport_tpg.MultiEnvDefault([]string{ "GOOGLE_SOURCE_REPO_CUSTOM_ENDPOINT", diff --git a/google-beta/provider/provider.go b/google-beta/provider/provider.go index f11a3545de..a9cbb421e1 100644 --- a/google-beta/provider/provider.go +++ b/google-beta/provider/provider.go @@ -744,6 +744,11 @@ func Provider() *schema.Provider { Optional: true, ValidateFunc: transport_tpg.ValidateCustomEndpoint, }, + "site_verification_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: transport_tpg.ValidateCustomEndpoint, + }, "source_repo_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -1132,6 +1137,7 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.ServiceManagementBasePath = d.Get("service_management_custom_endpoint").(string) config.ServiceNetworkingBasePath = d.Get("service_networking_custom_endpoint").(string) config.ServiceUsageBasePath = d.Get("service_usage_custom_endpoint").(string) + config.SiteVerificationBasePath = d.Get("site_verification_custom_endpoint").(string) config.SourceRepoBasePath = d.Get("source_repo_custom_endpoint").(string) config.SpannerBasePath = d.Get("spanner_custom_endpoint").(string) config.SQLBasePath = d.Get("sql_custom_endpoint").(string) diff --git a/google-beta/provider/provider_mmv1_resources.go b/google-beta/provider/provider_mmv1_resources.go index de8418f97c..a1dfb157f3 100644 --- a/google-beta/provider/provider_mmv1_resources.go +++ b/google-beta/provider/provider_mmv1_resources.go @@ -125,6 +125,7 @@ import ( "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/servicemanagement" "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/servicenetworking" "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/serviceusage" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/siteverification" "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/sourcerepo" "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/spanner" "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/sql" @@ -301,6 +302,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_service_account_id_token": resourcemanager.DataSourceGoogleServiceAccountIdToken(), "google_service_account_jwt": resourcemanager.DataSourceGoogleServiceAccountJwt(), "google_service_account_key": resourcemanager.DataSourceGoogleServiceAccountKey(), + "google_site_verification_token": siteverification.DataSourceSiteVerificationToken(), "google_sourcerepo_repository": sourcerepo.DataSourceGoogleSourceRepoRepository(), "google_spanner_instance": spanner.DataSourceSpannerInstance(), "google_sql_ca_certs": sql.DataSourceGoogleSQLCaCerts(), diff --git a/google-beta/services/siteverification/data_source_google_site_verification_token.go b/google-beta/services/siteverification/data_source_google_site_verification_token.go new file mode 100644 index 0000000000..b3cc22027e --- /dev/null +++ b/google-beta/services/siteverification/data_source_google_site_verification_token.go @@ -0,0 +1,149 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package siteverification + +import ( + "fmt" + "log" + "net/http" + "reflect" + "regexp" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/verify" +) + +func DataSourceSiteVerificationToken() *schema.Resource { + return &schema.Resource{ + Read: dataSourceSiteVerificationTokenRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "identifier": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The site identifier. If the type is set to SITE, the identifier is a URL. If the type is +set to INET_DOMAIN, the identifier is a domain name.`, + }, + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"INET_DOMAIN", "SITE"}), + Description: `The type of resource to be verified, either a domain or a web site. Possible values: ["INET_DOMAIN", "SITE"]`, + }, + "verification_method": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"ANALYTICS", "DNS_CNAME", "DNS_TXT", "FILE", "META", "TAG_MANAGER"}), + Description: `The verification method for the Site Verification system to use to verify +this site or domain. Possible values: ["ANALYTICS", "DNS_CNAME", "DNS_TXT", "FILE", "META", "TAG_MANAGER"]`, + }, + "token": { + Type: schema.TypeString, + Computed: true, + Description: `The returned token for use in subsequent verification steps.`, + }, + }, + UseJSONNumber: true, + } +} + +func dataSourceSiteVerificationTokenRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + site := make(map[string]interface{}) + typeProp, err := expandSiteVerificationTokenType(d.Get("type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("type"); !tpgresource.IsEmptyValue(reflect.ValueOf(typeProp)) && (ok || !reflect.DeepEqual(v, typeProp)) { + site["type"] = typeProp + } + identifierProp, err := expandSiteVerificationTokenIdentifier(d.Get("identifier"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("identifier"); !tpgresource.IsEmptyValue(reflect.ValueOf(identifierProp)) && (ok || !reflect.DeepEqual(v, identifierProp)) { + site["identifier"] = identifierProp + } + obj["site"] = site + verification_methodProp, err := expandSiteVerificationTokenVerificationMethod(d.Get("verification_method"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("verification_method"); !tpgresource.IsEmptyValue(reflect.ValueOf(verification_methodProp)) && (ok || !reflect.DeepEqual(v, verification_methodProp)) { + obj["verificationMethod"] = verification_methodProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{SiteVerificationBasePath}}token") + if err != nil { + return err + } + + log.Printf("[DEBUG] Reading Token: %#v", obj) + billingProject := "" + + if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil { + billingProject = parts[1] + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + headers := make(http.Header) + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + Headers: headers, + }) + if err != nil { + return fmt.Errorf("Error reading Token: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "{{identifier}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + if token, ok := res["token"].(string); ok { + d.Set("token", token) + } + + log.Printf("[DEBUG] Finished reading Token %q: %#v", d.Id(), res) + + return nil +} + +func expandSiteVerificationTokenType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSiteVerificationTokenIdentifier(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandSiteVerificationTokenVerificationMethod(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/services/siteverification/data_source_google_site_verification_token_test.go b/google-beta/services/siteverification/data_source_google_site_verification_token_test.go new file mode 100644 index 0000000000..ac2424591e --- /dev/null +++ b/google-beta/services/siteverification/data_source_google_site_verification_token_test.go @@ -0,0 +1,105 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package siteverification_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" +) + +func TestAccSiteVerificationToken_siteverificationTokenSite(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "site": "https://www.example.com", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccSiteVerificationToken_siteverificationTokenSite(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.google_site_verification_token.site_meta", "token"), + resource.TestCheckResourceAttr("data.google_site_verification_token.site_meta", "type", "SITE"), + resource.TestCheckResourceAttr("data.google_site_verification_token.site_meta", "identifier", context["site"].(string)), + resource.TestCheckResourceAttr("data.google_site_verification_token.site_meta", "verification_method", "META"), + ), + }, + }, + }) +} + +func testAccSiteVerificationToken_siteverificationTokenSite(context map[string]interface{}) string { + return acctest.Nprintf(` +provider "google" { + alias = "scoped" + user_project_override = true + scopes = [ + "https://www.googleapis.com/auth/siteverification", + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/userinfo.email", + ] +} + +data "google_site_verification_token" "site_meta" { + provider = google.scoped + type = "SITE" + identifier = "%{site}" + verification_method = "META" +} +`, context) +} + +func TestAccSiteVerificationToken_siteverificationTokenDomain(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "domain": "www.example.com", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccSiteVerificationToken_siteverificationTokenDomain(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.google_site_verification_token.dns_text", "token"), + resource.TestCheckResourceAttr("data.google_site_verification_token.dns_text", "type", "INET_DOMAIN"), + resource.TestCheckResourceAttr("data.google_site_verification_token.dns_text", "identifier", context["domain"].(string)), + resource.TestCheckResourceAttr("data.google_site_verification_token.dns_text", "verification_method", "DNS_TXT"), + ), + }, + }, + }) +} + +func testAccSiteVerificationToken_siteverificationTokenDomain(context map[string]interface{}) string { + return acctest.Nprintf(` +provider "google" { + alias = "scoped" + user_project_override = true + scopes = [ + "https://www.googleapis.com/auth/siteverification", + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/userinfo.email", + ] +} + +data "google_site_verification_token" "dns_text" { + provider = google.scoped + type = "INET_DOMAIN" + identifier = "%{domain}" + verification_method = "DNS_TXT" +} +`, context) +} diff --git a/google-beta/sweeper/gcp_sweeper_test.go b/google-beta/sweeper/gcp_sweeper_test.go index 1d0f4baae6..add0c9a0a5 100644 --- a/google-beta/sweeper/gcp_sweeper_test.go +++ b/google-beta/sweeper/gcp_sweeper_test.go @@ -127,6 +127,7 @@ import ( _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/servicemanagement" _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/servicenetworking" _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/serviceusage" + _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/siteverification" _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/sourcerepo" _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/spanner" _ "github.com/hashicorp/terraform-provider-google-beta/google-beta/services/sql" diff --git a/google-beta/transport/config.go b/google-beta/transport/config.go index a14977655b..297e676fe5 100644 --- a/google-beta/transport/config.go +++ b/google-beta/transport/config.go @@ -308,6 +308,7 @@ type Config struct { ServiceManagementBasePath string ServiceNetworkingBasePath string ServiceUsageBasePath string + SiteVerificationBasePath string SourceRepoBasePath string SpannerBasePath string SQLBasePath string @@ -462,6 +463,7 @@ const ServiceDirectoryBasePathKey = "ServiceDirectory" const ServiceManagementBasePathKey = "ServiceManagement" const ServiceNetworkingBasePathKey = "ServiceNetworking" const ServiceUsageBasePathKey = "ServiceUsage" +const SiteVerificationBasePathKey = "SiteVerification" const SourceRepoBasePathKey = "SourceRepo" const SpannerBasePathKey = "Spanner" const SQLBasePathKey = "SQL" @@ -610,6 +612,7 @@ var DefaultBasePaths = map[string]string{ ServiceManagementBasePathKey: "https://servicemanagement.googleapis.com/v1/", ServiceNetworkingBasePathKey: "https://servicenetworking.googleapis.com/v1/", ServiceUsageBasePathKey: "https://serviceusage.googleapis.com/v1beta1/", + SiteVerificationBasePathKey: "https://www.googleapis.com/siteVerification/v1/", SourceRepoBasePathKey: "https://sourcerepo.googleapis.com/v1/", SpannerBasePathKey: "https://spanner.googleapis.com/v1/", SQLBasePathKey: "https://sqladmin.googleapis.com/sql/v1beta4/", @@ -1309,6 +1312,11 @@ func SetEndpointDefaults(d *schema.ResourceData) error { "GOOGLE_SERVICE_USAGE_CUSTOM_ENDPOINT", }, DefaultBasePaths[ServiceUsageBasePathKey])) } + if d.Get("site_verification_custom_endpoint") == "" { + d.Set("site_verification_custom_endpoint", MultiEnvDefault([]string{ + "GOOGLE_SITE_VERIFICATION_CUSTOM_ENDPOINT", + }, DefaultBasePaths[SiteVerificationBasePathKey])) + } if d.Get("source_repo_custom_endpoint") == "" { d.Set("source_repo_custom_endpoint", MultiEnvDefault([]string{ "GOOGLE_SOURCE_REPO_CUSTOM_ENDPOINT", @@ -2417,6 +2425,7 @@ func ConfigureBasePaths(c *Config) { c.ServiceManagementBasePath = DefaultBasePaths[ServiceManagementBasePathKey] c.ServiceNetworkingBasePath = DefaultBasePaths[ServiceNetworkingBasePathKey] c.ServiceUsageBasePath = DefaultBasePaths[ServiceUsageBasePathKey] + c.SiteVerificationBasePath = DefaultBasePaths[SiteVerificationBasePathKey] c.SourceRepoBasePath = DefaultBasePaths[SourceRepoBasePathKey] c.SpannerBasePath = DefaultBasePaths[SpannerBasePathKey] c.SQLBasePath = DefaultBasePaths[SQLBasePathKey] diff --git a/website/docs/d/site_verification_token.html.markdown b/website/docs/d/site_verification_token.html.markdown new file mode 100644 index 0000000000..066370eda2 --- /dev/null +++ b/website/docs/d/site_verification_token.html.markdown @@ -0,0 +1,84 @@ +subcategory: "Site Verification" +description: |- + A verification token is used to demonstrate ownership of a website or domain. +--- + +# google_site_verification_token + +A verification token is used to demonstrate ownership of a website or domain. + + +To get more information about Token, see: + +* [API documentation](https://developers.google.com/site-verification/v1) +* How-to Guides + * [Getting Started](https://developers.google.com/site-verification/v1/getting_started) + + + +## Example Usage - Site Verification via Site META Tag + +```hcl +data "google_site_verification_token" "example" { + type = "SITE" + identifier = "https://www.example.com" + verification_method = "META" +} +``` + +## Example Usage - Site Verification via DNS TXT Record + +```hcl +data "google_site_verification_token" "example" { + type = "INET_DOMAIN" + identifier = "www.example.com" + verification_method = "DNS_TXT" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `type` - + (Required) + The type of resource to be verified, either a domain or a web site. + Possible values are: `INET_DOMAIN`, `SITE`. + +* `identifier` - + (Required) + The site identifier. If the type is set to SITE, the identifier is a URL. If the type is + set to INET_DOMAIN, the identifier is a domain name. + +* `verification_method` - + (Required) + The verification method for the Site Verification system to use to verify + this site or domain. + Possible values are: `ANALYTICS`, `DNS_CNAME`, `DNS_TXT`, `FILE`, `META`, `TAG_MANAGER`. + + +- - - + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `token` - + The generated token for use in subsequent verification steps. + + +## Timeouts + +This data source provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `read` - Default is 5 minutes. + +## User Project Overrides + +This data source supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).