diff --git a/mmv1/products/vmwareengine/Datastore.yaml b/mmv1/products/vmwareengine/Datastore.yaml new file mode 100644 index 000000000000..0b1c8fba8888 --- /dev/null +++ b/mmv1/products/vmwareengine/Datastore.yaml @@ -0,0 +1,179 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +name: Datastore +description: A datastore resource that can be mounted on a privatecloud cluster +base_url: projects/{{project}}/locations/{{location}}/datastores +update_mask: true +self_link: projects/{{project}}/locations/{{location}}/datastores/{{name}} +create_url: projects/{{project}}/locations/{{location}}/datastores?datastoreId={{name}} +update_verb: PATCH +id_format: projects/{{project}}/locations/{{location}}/datastores/{{name}} +import_format: + - projects/{{project}}/locations/{{location}}/datastores/{{name}} +datasource: + generate: true + exclude_test: true +examples: + - name: vmware_engine_datastore_thirdparty + primary_resource_id: example_thirdparty + vars: + resource_name: thirdparty-datastore + test_env_vars: + region: "REGION" + project: "PROJECT" + # Update tests take care of both create and update - Datastore deletion requires some additional setup + exclude_test: true + - name: vmware_engine_datastore_filestore + primary_resource_id: example_filestore + vars: + resource_name: filestore-datastore + network_name: default + test_env_vars: + region: "REGION" + zone: "ZONE" + project: "PROJECT" + # Update tests take care of both create and update - Datastore deletion requires some additional setup + exclude_test: true + - name: vmware_engine_datastore_netapp + primary_resource_id: example_netapp + vars: + resource_name: netapp-datastore + network_name: default + test_env_vars: + region: "REGION" + project: "PROJECT" + # Update tests take care of both create and update - Datastore deletion requires some additional setup + exclude_test: true +autogen_async: true +async: + operation: + timeouts: + insert_minutes: 20 + update_minutes: 20 + delete_minutes: 20 + base_url: "{{op_id}}" + actions: + - create + - delete + - update + type: OpAsync + result: + resource_inside_response: true + include_project: false +autogen_status: RGF0YXN0b3Jl +parameters: + - name: location + type: String + description: Resource ID segment making up resource `name`. It identifies the resource within its parent collection as described in https://google.aip.dev/122. + immutable: true + url_param_only: true + required: true + - name: name + type: String + description: |- + The user-provided identifier of the datastore to be created. + This identifier must be unique among each `Datastore` within the parent + and becomes the final token in the name URI. + The identifier must meet the following requirements: + + * Only contains 1-63 alphanumeric characters and hyphens + * Begins with an alphabetical character + * Ends with a non-hyphen character + * Not formatted as a UUID + * Complies with [RFC 1034](https://datatracker.ietf.org/doc/html/rfc1034) + (section 3.5) + immutable: true + url_param_only: true + required: true +properties: + - name: clusters + type: Array + description: Clusters to which the datastore is attached. + output: true + item_type: + type: String + - name: createTime + type: String + description: Creation time of this resource. + output: true + - name: description + type: String + description: User-provided description for this datastore + - name: nfsDatastore + type: NestedObject + description: The NFS datastore configuration. + required: true + properties: + - name: googleFileService + type: NestedObject + description: Google service file service configuration + properties: + - name: filestoreInstance + type: String + description: |- + Google filestore instance resource name + e.g. projects/my-project/locations/me-west1-b/instances/my-instance + - name: netappVolume + type: String + description: |- + Google netapp volume resource name + e.g. projects/my-project/locations/me-west1-b/volumes/my-volume + - name: thirdPartyFileService + type: NestedObject + description: Third party file service configuration + properties: + - name: fileShare + type: String + description: |- + Required + Mount Folder name + required: true + - name: network + type: String + description: |- + Required to identify vpc peering used for NFS access + network name of NFS's vpc + e.g. projects/project-id/global/networks/my-network_id + required: true + - name: servers + type: Array + description: |- + Server IP addresses of the NFS file service. + NFS v3, provide a single IP address or DNS name. + Multiple servers can be supported in future when NFS 4.1 protocol support + is enabled. + required: true + item_type: + type: String + - name: state + type: String + description: |- + The state of the Datastore. + Possible values: + CREATING + ACTIVE + UPDATING + DELETING + SOFT_DELETING + SOFT_DELETED + output: true + - name: uid + type: String + description: System-generated unique identifier for the resource. + output: true + - name: updateTime + type: String + description: Last update time of this resource. + output: true diff --git a/mmv1/templates/terraform/examples/vmware_engine_datastore_filestore.tf.tmpl b/mmv1/templates/terraform/examples/vmware_engine_datastore_filestore.tf.tmpl new file mode 100644 index 000000000000..633c9022aee8 --- /dev/null +++ b/mmv1/templates/terraform/examples/vmware_engine_datastore_filestore.tf.tmpl @@ -0,0 +1,18 @@ +# Use existing filestore instance +data "google_filestore_instance" "test_instance" { + name = "fs-instance" + location = "{{index $.TestEnvVars "zone"}}" +} + +# Create a VmwareEngine Datastore, referencing the filestore instance +resource "google_vmwareengine_datastore" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "resource_name"}}" + location = "{{index $.TestEnvVars "zone"}}" + description = "example google_file_service.filestore datastore." + + nfs_datastore { + google_file_service { + filestore_instance = google_filestore_instance.test_instance.id + } + } +} diff --git a/mmv1/templates/terraform/examples/vmware_engine_datastore_netapp.tf.tmpl b/mmv1/templates/terraform/examples/vmware_engine_datastore_netapp.tf.tmpl new file mode 100644 index 000000000000..038f249bc111 --- /dev/null +++ b/mmv1/templates/terraform/examples/vmware_engine_datastore_netapp.tf.tmpl @@ -0,0 +1,18 @@ +# Use existing netapp volume +resource "google_netapp_volume" "test_volume" { + name = "netapp-volume" + location = "{{index $.TestEnvVars "region"}}" +} + +# Create a VmwareEngine Datastore, referencing the netapp volume +resource "google_vmwareengine_datastore" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "resource_name"}}" + location = "{{index $.TestEnvVars "region"}}" + description = "example google_file_service.netapp datastore." + + nfs_datastore { + google_file_service { + netapp_volume = google_netapp_volume.test_volume.id + } + } +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/vmware_engine_datastore_thirdparty.tf.tmpl b/mmv1/templates/terraform/examples/vmware_engine_datastore_thirdparty.tf.tmpl new file mode 100644 index 000000000000..7598e5312b06 --- /dev/null +++ b/mmv1/templates/terraform/examples/vmware_engine_datastore_thirdparty.tf.tmpl @@ -0,0 +1,19 @@ +# use existing network with connectivity to the thirdparty datastore +data "google_compute_network" "default" { + name = "default" +} + +# create a thirdparty datastore +resource "google_vmwareengine_datastore" "{{$.PrimaryResourceId}}" { + name = "{{index $.Vars "resource_name"}}" + location = "{{index $.TestEnvVars "region"}}-a" + description = "example thirdparty datastore." + + nfs_datastore { + third_party_file_service { + file_share = "/share1" + network = data.google_compute_network.default.id + servers = ["10.0.0.4"] + } + } +} diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl index f498c41fcf3b..8f1a8dcb04c0 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.tmpl @@ -308,6 +308,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_vmwareengine_private_cloud": vmwareengine.DataSourceVmwareenginePrivateCloud(), "google_vmwareengine_subnet": vmwareengine.DataSourceVmwareengineSubnet(), "google_vmwareengine_vcenter_credentials": vmwareengine.DataSourceVmwareengineVcenterCredentials(), + "google_vmwareengine_datastore": vmwareengine.DataSourceVmwareengineDatastore(), "google_compute_region_backend_service": compute.DataSourceGoogleComputeRegionBackendService(), "google_network_management_connectivity_test_run": networkmanagement.DataSourceGoogleNetworkManagementTestRun(), "google_network_management_connectivity_tests": networkmanagement.DataSourceGoogleNetworkManagementConnectivityTests(), diff --git a/mmv1/third_party/terraform/services/vmwareengine/resource_vmwareengine_datastore_test.go b/mmv1/third_party/terraform/services/vmwareengine/resource_vmwareengine_datastore_test.go new file mode 100644 index 000000000000..1cf8a4954e02 --- /dev/null +++ b/mmv1/third_party/terraform/services/vmwareengine/resource_vmwareengine_datastore_test.go @@ -0,0 +1,294 @@ +package vmwareengine_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccVmwareengineDatastore_vmwareEngineDatastoreThirdparty_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "region": envvar.GetTestRegionFromEnv(), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckVmwareengineDatastoreDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreThirdparty(context, "test description"), + }, + { + ResourceName: "google_vmwareengine_datastore.example_thirdparty", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location"}, + }, + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreThirdparty(context, "updated test description"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_vmwareengine_datastore.example_thirdparty", plancheck.ResourceActionUpdate), + }, + }, + }, + }, + }) +} + +func testAccVmwareengineDatastore_vmwareEngineDatastoreThirdparty(context map[string]interface{}, description string) string { + context["description"] = description + return acctest.Nprintf(` +data "google_compute_network" "default" { + name = "default" + provider = google +} + +resource "google_vmwareengine_datastore" "example_thirdparty" { + name = "tf-test-thirdparty-datastore%{random_suffix}" + location = "%{region}-a" + description = "%{description}" + + nfs_datastore { + third_party_file_service { + file_share = "/share1" + network = data.google_compute_network.default.id + servers = ["10.0.0.4"] + } + } +} +`, context) +} + +func TestAccVmwareengineDatastore_vmwareEngineDatastoreFilestore_update(t *testing.T) { + t.Parallel() + acctest.BootstrapIamMembers(t, []acctest.IamMember{ + { + Member: "serviceAccount:service-{project_number}@gcp-sa-vmwareengine.iam.gserviceaccount.com", + Role: "roles/file.viewer", + }, + }) + + context := map[string]interface{}{ + "region": envvar.GetTestRegionFromEnv(), + "zone": envvar.GetTestZoneFromEnv(), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "datastore-test"), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckVmwareengineDatastoreDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreFilestore(context, true, "example google_file_service.filestore datastore."), + }, + { + ResourceName: "google_vmwareengine_datastore.example_filestore", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreFilestore(context, true, "updated example google_file_service.filestore datastore."), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_vmwareengine_datastore.example_filestore", plancheck.ResourceActionUpdate), + }, + }, + }, + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreFilestore(context, false, "updated example google_file_service.filestore datastore."), + }, + }, + }) +} + +func testAccVmwareengineDatastore_vmwareEngineDatastoreFilestore(context map[string]interface{}, delete_protection bool, description string) string { + context["delete_protection"] = delete_protection + context["description"] = description + return acctest.Nprintf(` +# Use existing network with address created and PSA enabled. +data "google_compute_network" "test_network" { + name = "%{network_name}" +} + +# Create a filestore instance with delete protection enabled +resource "google_filestore_instance" "test_instance" { + name = "tf-test-datastore-fs-instance%{random_suffix}" + location = "%{zone}" + tier = "ZONAL" + deletion_protection_enabled = "%{delete_protection}" + + file_shares { + capacity_gb = 1024 + name = "share1" + } + + networks { + network = data.google_compute_network.test_network.id + modes = ["MODE_IPV4"] + connect_mode = "PRIVATE_SERVICE_ACCESS" + } +} + +# Create a VmwareEngine Datastore, referencing the filestore instance +resource "google_vmwareengine_datastore" "example_filestore" { + name = "tf-test-filestore-datastore%{random_suffix}" + location = "%{zone}" + description = "%{description}" + + nfs_datastore { + google_file_service { + filestore_instance = google_filestore_instance.test_instance.id + } + } +} +`, context) +} + +func TestAccVmwareengineDatastore_vmwareEngineDatastoreNetapp_update(t *testing.T) { + t.Parallel() + acctest.BootstrapIamMembers(t, []acctest.IamMember{ + { + Member: "serviceAccount:service-{project_number}@gcp-sa-vmwareengine.iam.gserviceaccount.com", + Role: "roles/netapp.viewer", + }, + }) + + context := map[string]interface{}{ + "region": envvar.GetTestRegionFromEnv(), + "zone": envvar.GetTestZoneFromEnv(), + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "datastore-test", acctest.ServiceNetworkWithParentService("netapp.servicenetworking.goog")), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckVmwareengineDatastoreDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreNetapp(context, "example google_file_service.netapp datastore."), + }, + { + ResourceName: "google_vmwareengine_datastore.example_netapp", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name"}, + }, + { + Config: testAccVmwareengineDatastore_vmwareEngineDatastoreNetapp(context, "updated example google_file_service.netapp datastore."), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_vmwareengine_datastore.example_netapp", plancheck.ResourceActionUpdate), + }, + }, + }, + }, + }) +} + +func testAccVmwareengineDatastore_vmwareEngineDatastoreNetapp(context map[string]interface{}, description string) string { + context["description"] = description + return acctest.Nprintf(` +# Create a network or use datasource to reference existing network +data "google_compute_network" "vpc_network" { + name = "%{network_name}" +} + +# Create a Netapp storage pool +resource "google_netapp_storage_pool" "test_pool" { + name = "tf-test-netapp-storage-pool%{random_suffix}" + location = "%{region}" + zone = "%{region}-b" + replica_zone = "%{region}-a" + service_level = "FLEX" + capacity_gib = "2048" + network = data.google_compute_network.vpc_network.id + lifecycle { + ignore_changes = [ + qos_type, + ] + } +} + +# Create a netapp volume +resource "google_netapp_volume" "test_volume" { + location = "%{region}" + name = "tf-test-netapp-volume%{random_suffix}" + capacity_gib = "1024" + share_name = "share1" + storage_pool = google_netapp_storage_pool.test_pool.name + protocols = [ "NFSV3" ] + deletion_policy = "DEFAULT" + restricted_actions = [ "DELETE" ] +} + +# Create a VmwareEngine Datastore, referencing the netapp volume +resource "google_vmwareengine_datastore" "example_netapp" { + name = "tf-test-netapp-datastore%{random_suffix}" + location = "%{region}" + description = "%{description}" + + nfs_datastore { + google_file_service { + netapp_volume = google_netapp_volume.test_volume.id + } + } +} +`, context) +} + +func testAccCheckVmwareengineDatastoreDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_vmwareengine_datastore" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{VmwareengineBasePath}}projects/{{project}}/locations/{{location}}/datastores/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("VmwareengineDatastore still exists at %s", url) + } + } + + return nil + } +}