diff --git a/.changelog/10105.txt b/.changelog/10105.txt new file mode 100644 index 00000000000..e618b65aef2 --- /dev/null +++ b/.changelog/10105.txt @@ -0,0 +1,3 @@ +```release-note:new-datasource +`google_apphub_discovered_service` +``` \ No newline at end of file diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index 4b7c627352f..81d3339ab44 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -138,6 +138,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_alloydb_supported_database_flags": alloydb.DataSourceAlloydbSupportedDatabaseFlags(), "google_artifact_registry_repository": artifactregistry.DataSourceArtifactRegistryRepository(), "google_app_engine_default_service_account": appengine.DataSourceGoogleAppEngineDefaultServiceAccount(), + "google_apphub_discovered_service": apphub.DataSourceApphubDiscoveredService(), "google_beyondcorp_app_connection": beyondcorp.DataSourceGoogleBeyondcorpAppConnection(), "google_beyondcorp_app_connector": beyondcorp.DataSourceGoogleBeyondcorpAppConnector(), "google_beyondcorp_app_gateway": beyondcorp.DataSourceGoogleBeyondcorpAppGateway(), diff --git a/google/services/apphub/data_source_apphub_discovered_service.go b/google/services/apphub/data_source_apphub_discovered_service.go new file mode 100644 index 00000000000..ae590982a49 --- /dev/null +++ b/google/services/apphub/data_source_apphub_discovered_service.go @@ -0,0 +1,173 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package apphub + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func DataSourceApphubDiscoveredService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceApphubDiscoveredServiceRead, + Schema: map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Optional: true, + }, + "location": { + Type: schema.TypeString, + Required: true, + }, + "service_uri": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "service_reference": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "uri": { + Type: schema.TypeString, + Computed: true, + }, + "path": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "service_properties": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "gcp_project": { + Type: schema.TypeString, + Computed: true, + }, + "location": { + Type: schema.TypeString, + Computed: true, + }, + "zone": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceApphubDiscoveredServiceRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ApphubBasePath}}projects/{{project}}/locations/{{location}}/discoveredServices:lookup?uri={{service_uri}}") + if err != nil { + return err + } + + billingProject := "" + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + + if err != nil { + return transport_tpg.HandleDataSourceNotFoundError(err, d, fmt.Sprintf("ApphubDiscoveredService %q", d.Id()), url) + } + + if err := d.Set("name", flattenApphubDiscoveredServiceName(res["discoveredService"].(map[string]interface{})["name"], d, config)); err != nil { + return fmt.Errorf("Error setting service name: %s", err) + } + + if err := d.Set("service_reference", flattenApphubDiscoveredServiceReference(res["discoveredService"].(map[string]interface{})["serviceReference"], d, config)); err != nil { + return fmt.Errorf("Error setting service reference: %s", err) + } + + if err := d.Set("service_properties", flattenApphubDiscoveredServiceProperties(res["discoveredService"].(map[string]interface{})["serviceProperties"], d, config)); err != nil { + return fmt.Errorf("Error setting service properties: %s", err) + } + + d.SetId(res["discoveredService"].(map[string]interface{})["name"].(string)) + + return nil + +} + +func flattenApphubDiscoveredServiceReference(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["uri"] = flattenApphubDiscoveredServiceDataUri(original["uri"], d, config) + transformed["path"] = flattenApphubDiscoveredServiceDataPath(original["path"], d, config) + return []interface{}{transformed} +} + +func flattenApphubDiscoveredServiceProperties(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["gcp_project"] = flattenApphubDiscoveredServiceDataGcpProject(original["gcpProject"], d, config) + transformed["location"] = flattenApphubDiscoveredServiceDataLocation(original["location"], d, config) + transformed["zone"] = flattenApphubDiscoveredServiceDataZone(original["zone"], d, config) + return []interface{}{transformed} +} + +func flattenApphubDiscoveredServiceName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApphubDiscoveredServiceDataUri(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApphubDiscoveredServiceDataPath(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApphubDiscoveredServiceDataGcpProject(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApphubDiscoveredServiceDataLocation(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApphubDiscoveredServiceDataZone(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} diff --git a/google/services/apphub/data_source_apphub_discovered_service_test.go b/google/services/apphub/data_source_apphub_discovered_service_test.go new file mode 100644 index 00000000000..2f1b900d237 --- /dev/null +++ b/google/services/apphub/data_source_apphub_discovered_service_test.go @@ -0,0 +1,130 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package apphub_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccDataSourceApphubDiscoveredService_basic(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testDataSourceApphubDiscoveredService_basic(context), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.google_apphub_discovered_service.catalog-service", "name"), + ), + }, + }, + }) +} + +func testDataSourceApphubDiscoveredService_basic(context map[string]interface{}) string { + return acctest.Nprintf( + ` +resource "google_project" "service_project" { + project_id ="tf-test-ah-%{random_suffix}" + name = "Service Project" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +# Enable Compute API +resource "google_project_service" "compute_service_project" { + project = google_project.service_project.project_id + service = "compute.googleapis.com" +} + +resource "time_sleep" "wait_120s" { + depends_on = [google_project_service.compute_service_project] + create_duration = "120s" +} + +resource "google_apphub_service_project_attachment" "service_project_attachment" { + service_project_attachment_id = google_project.service_project.project_id + depends_on = [time_sleep.wait_120s] +} + +# discovered service block +data "google_apphub_discovered_service" "catalog-service" { + location = "us-central1" + # ServiceReference | Application Hub | Google Cloud + # Using this reference means that this resource will not be provisioned until the forwarding rule is fully created + service_uri = "//compute.googleapis.com/${google_compute_forwarding_rule.forwarding_rule.id}" + depends_on = [time_sleep.wait_120s_for_resource_ingestion] +} + +# VPC network +resource "google_compute_network" "ilb_network" { + name = "ilb-network-%{random_suffix}" + project = google_project.service_project.project_id + auto_create_subnetworks = false + depends_on = [time_sleep.wait_120s] +} + +# backend subnet +resource "google_compute_subnetwork" "ilb_subnet" { + name = "ilb-subnet-%{random_suffix}" + project = google_project.service_project.project_id + ip_cidr_range = "10.0.1.0/24" + region = "us-central1" + network = google_compute_network.ilb_network.id +} + +# forwarding rule +resource "google_compute_forwarding_rule" "forwarding_rule" { + name = "forwarding-rule-%{random_suffix}" + project = google_project.service_project.project_id + region = "us-central1" + ip_version = "IPV4" + load_balancing_scheme = "INTERNAL" + all_ports = true + backend_service = google_compute_region_backend_service.backend.id + network = google_compute_network.ilb_network.id + subnetwork = google_compute_subnetwork.ilb_subnet.id +} + +resource "time_sleep" "wait_120s_for_resource_ingestion" { + depends_on = [google_compute_forwarding_rule.forwarding_rule] + create_duration = "120s" +} + +# backend service +resource "google_compute_region_backend_service" "backend" { + name = "backend-service-%{random_suffix}" + project = google_project.service_project.project_id + region = "us-central1" + health_checks = [google_compute_health_check.default.id] +} + +# health check +resource "google_compute_health_check" "default" { + name = "health-check-%{random_suffix}" + project = google_project.service_project.project_id + check_interval_sec = 1 + timeout_sec = 1 + + tcp_health_check { + port = "80" + } + depends_on = [time_sleep.wait_120s] +} +`, context) +} diff --git a/website/docs/d/apphub_discovered_service.html.markdown b/website/docs/d/apphub_discovered_service.html.markdown new file mode 100644 index 00000000000..272491b8d08 --- /dev/null +++ b/website/docs/d/apphub_discovered_service.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Apphub" +description: |- + Get information about a discovered service. +--- + +# google\_apphub\_discovered_service + +Get information about a discovered service from its uri. + + +## Example Usage + + +```hcl +data "google_apphub_discovered_service" "my-service" { + location = "my-location" + service_uri = "my-service-uri" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `project` - The host project of the discovered service. +* `service_uri` - (Required) The uri of the service. +* `location` - (Required) The location of the discovered service. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `name` - Resource name of a Service. Format: "projects/{host-project-id}/locations/{location}/applications/{application-id}/services/{service-id}". + +* `service_reference` - Reference to an underlying networking resource that can comprise a Service. Structure is [documented below](#nested_service_reference) + +A `service_reference` object would contain the following fields: + +* `uri` - The underlying resource URI. + +* `path` - Additional path under the resource URI. + +* `service_properties` - Properties of an underlying compute resource that can comprise a Service. Structure is [documented below](#nested_service_properties) + +A `service_properties` object would contain the following fields: + +* `gcp_project` - The service project identifier that the underlying cloud resource resides in. + +* `location` - The location that the underlying resource resides in. + +* `zone` - The location that the underlying resource resides in if it is zonal. \ No newline at end of file