diff --git a/vsphere/helper_test.go b/vsphere/helper_test.go index d89086e19..d29ac81d6 100644 --- a/vsphere/helper_test.go +++ b/vsphere/helper_test.go @@ -508,6 +508,16 @@ func testGetDatastore(s *terraform.State, resAddr string) (*object.Datastore, er return datastore.FromID(vars.client, vars.resourceID) } +// testGetDatastoreProperties is a convenience method that adds an extra step +// to testGetDatastore to get the properties of a datastore. +func testGetDatastoreProperties(s *terraform.State, resourceName string) (*mo.Datastore, error) { + ds, err := testGetDatastore(s, "vsphere_vmfs_datastore."+resourceName) + if err != nil { + return nil, err + } + return datastore.Properties(ds) +} + // testAccResourceVSphereDatastoreCheckTags is a check to ensure that the // supplied datastore has had the tags that have been created with the supplied // tag resource name attached. diff --git a/vsphere/resource_vsphere_vmfs_datastore.go b/vsphere/resource_vsphere_vmfs_datastore.go index fc24dad02..332927f81 100644 --- a/vsphere/resource_vsphere_vmfs_datastore.go +++ b/vsphere/resource_vsphere_vmfs_datastore.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/customattribute" "github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/datastore" "github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/folder" "github.com/terraform-providers/terraform-provider-vsphere/vsphere/internal/helper/structure" @@ -90,6 +91,8 @@ func resourceVSphereVmfsDatastore() *schema.Resource { // Add tags schema s[vSphereTagAttributeKey] = tagsSchema() + // Add custom attributes schema + s[customattribute.ConfigKey] = customattribute.ConfigSchema() return &schema.Resource{ Create: resourceVSphereVmfsDatastoreCreate, @@ -113,6 +116,11 @@ func resourceVSphereVmfsDatastoreCreate(d *schema.ResourceData, meta interface{} if err != nil { return err } + // Verify a proper vCenter before proceeding if custom attributes are defined + attrsProcessor, err := customattribute.GetDiffProcessorIfAttributesDefined(client, d) + if err != nil { + return err + } hsID := d.Get("host_system_id").(string) dss, err := hostDatastoreSystemFromHostSystemID(client, hsID) @@ -158,6 +166,13 @@ func resourceVSphereVmfsDatastoreCreate(d *schema.ResourceData, meta interface{} } } + // Set custom attributes + if attrsProcessor != nil { + if err := attrsProcessor.ProcessDiff(ds); err != nil { + return err + } + } + // Now add any remaining disks. for _, disk := range disks[1:] { spec, err := diskSpecForExtend(dss, ds, disk.(string)) @@ -228,6 +243,11 @@ func resourceVSphereVmfsDatastoreRead(d *schema.ResourceData, meta interface{}) } } + // Read custom attributes + if customattribute.IsSupported(client) { + customattribute.ReadFromResource(client, props.Entity(), d) + } + return nil } @@ -240,6 +260,11 @@ func resourceVSphereVmfsDatastoreUpdate(d *schema.ResourceData, meta interface{} if err != nil { return err } + // Verify a proper vCenter before proceeding if custom attributes are defined + attrsProcessor, err := customattribute.GetDiffProcessorIfAttributesDefined(client, d) + if err != nil { + return err + } hsID := d.Get("host_system_id").(string) dss, err := hostDatastoreSystemFromHostSystemID(client, hsID) @@ -275,6 +300,13 @@ func resourceVSphereVmfsDatastoreUpdate(d *schema.ResourceData, meta interface{} } } + // Apply custom attribute updates + if attrsProcessor != nil { + if err := attrsProcessor.ProcessDiff(ds); err != nil { + return err + } + } + // Veto this update if it means a disk was removed. Shrinking // datastores/removing extents is not supported. old, new := d.GetChange("disks") diff --git a/vsphere/resource_vsphere_vmfs_datastore_test.go b/vsphere/resource_vsphere_vmfs_datastore_test.go index c7b2fc388..f7828f687 100644 --- a/vsphere/resource_vsphere_vmfs_datastore_test.go +++ b/vsphere/resource_vsphere_vmfs_datastore_test.go @@ -303,6 +303,53 @@ func TestAccResourceVSphereVmfsDatastore(t *testing.T) { }, }, }, + { + "single custom attribute", + resource.TestCase{ + PreCheck: func() { + testAccPreCheck(tp) + testAccResourceVSphereVmfsDatastorePreCheck(tp) + }, + Providers: testAccProviders, + CheckDestroy: testAccResourceVSphereVmfsDatastoreExists(false), + Steps: []resource.TestStep{ + { + Config: testAccResourceVSphereVmfsDatastoreConfigCustomAttributes(), + Check: resource.ComposeTestCheckFunc( + testAccResourceVSphereVmfsDatastoreExists(true), + testAccResourceVSphereVmfsDatastoreHasCustomAttributes(), + ), + }, + }, + }, + }, + { + "multi custom attribute", + resource.TestCase{ + PreCheck: func() { + testAccPreCheck(tp) + testAccResourceVSphereVmfsDatastorePreCheck(tp) + }, + Providers: testAccProviders, + CheckDestroy: testAccResourceVSphereVmfsDatastoreExists(false), + Steps: []resource.TestStep{ + { + Config: testAccResourceVSphereVmfsDatastoreConfigCustomAttributes(), + Check: resource.ComposeTestCheckFunc( + testAccResourceVSphereVmfsDatastoreExists(true), + testAccResourceVSphereVmfsDatastoreHasCustomAttributes(), + ), + }, + { + Config: testAccResourceVSphereVmfsDatastoreConfigMultiCustomAttributes(), + Check: resource.ComposeTestCheckFunc( + testAccResourceVSphereVmfsDatastoreExists(true), + testAccResourceVSphereVmfsDatastoreHasCustomAttributes(), + ), + }, + }, + }, + }, } for _, tc := range testAccResourceVSphereVmfsDatastoreCases { @@ -390,6 +437,16 @@ func testAccResourceVSphereVmfsDatastoreMatchInventoryPath(expected string) reso } } +func testAccResourceVSphereVmfsDatastoreHasCustomAttributes() resource.TestCheckFunc { + return func(s *terraform.State) error { + props, err := testGetDatastoreProperties(s, "datastore") + if err != nil { + return err + } + return testResourceHasCustomAttributeValues(s, "vsphere_vmfs_datastore", "datastore", props.Entity()) + } +} + func testAccResourceVSphereVmfsDatastoreConfigStaticSingle() string { return fmt.Sprintf(` variable "disk0" { @@ -713,3 +770,89 @@ resource "vsphere_vmfs_datastore" "datastore" { } `, os.Getenv("VSPHERE_DS_VMFS_DISK0"), os.Getenv("VSPHERE_DS_VMFS_DISK1"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST")) } + +func testAccResourceVSphereVmfsDatastoreConfigCustomAttributes() string { + return fmt.Sprintf(` +variable "disk0" { + type = "string" + default = "%s" +} + +data "vsphere_datacenter" "datacenter" { + name = "%s" +} + +data "vsphere_host" "esxi_host" { + name = "%s" + datacenter_id = "${data.vsphere_datacenter.datacenter.id}" +} + +resource "vsphere_custom_attribute" "terraform-test-attribute" { + name = "terraform-test-attribute" + managed_object_type = "Datastore" +} + +locals { + vmfs_attrs = { + "${vsphere_custom_attribute.terraform-test-attribute.id}" = "value" + } +} + +resource "vsphere_vmfs_datastore" "datastore" { + name = "terraform-test" + host_system_id = "${data.vsphere_host.esxi_host.id}" + + disks = [ + "${var.disk0}", + ] + + custom_attributes = "${local.vmfs_attrs}" +} +`, os.Getenv("VSPHERE_DS_VMFS_DISK0"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST")) +} + +func testAccResourceVSphereVmfsDatastoreConfigMultiCustomAttributes() string { + return fmt.Sprintf(` +variable "disk0" { + type = "string" + default = "%s" +} + +data "vsphere_datacenter" "datacenter" { + name = "%s" +} + +data "vsphere_host" "esxi_host" { + name = "%s" + datacenter_id = "${data.vsphere_datacenter.datacenter.id}" +} + +resource "vsphere_custom_attribute" "terraform-test-attribute" { + name = "terraform-test-attribute" + managed_object_type = "Datastore" +} + +resource "vsphere_custom_attribute" "terraform-test-attribute-2" { + name = "terraform-test-attribute-2" + managed_object_type = "Datastore" +} + +locals { + vmfs_attrs = { + "${vsphere_custom_attribute.terraform-test-attribute.id}" = "value" + "${vsphere_custom_attribute.terraform-test-attribute-2.id}" = "value-2" + } +} + +resource "vsphere_vmfs_datastore" "datastore" { + name = "terraform-test" + host_system_id = "${data.vsphere_host.esxi_host.id}" + + disks = [ + "${var.disk0}", + ] + + custom_attributes = "${local.vmfs_attrs}" +} +`, os.Getenv("VSPHERE_DS_VMFS_DISK0"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST")) +} diff --git a/website/docs/r/vmfs_datastore.html.markdown b/website/docs/r/vmfs_datastore.html.markdown index cfa1be7fe..a979d3fcc 100644 --- a/website/docs/r/vmfs_datastore.html.markdown +++ b/website/docs/r/vmfs_datastore.html.markdown @@ -143,6 +143,16 @@ The following arguments are supported: ~> **NOTE:** Tagging support is unsupported on direct ESXi connections and requires vCenter 6.0 or higher. +* `custom_attributes` (Optional) Map of custom attribute ids to attribute + value string to set on datastore resource. See + [here][docs-setting-custom-attributes] for a reference on how to set values + for custom attributes. + +[docs-setting-custom-attributes]: /docs/providers/vsphere/r/custom_attribute.html#using-custom-attributes-in-a-supported-resource + +~> **NOTE:** Custom attributes are unsupported on direct ESXi connections +and require vCenter. + ## Attribute Reference The following attributes are exported: