Skip to content

Commit

Permalink
tags: Support tagging in datastore resources
Browse files Browse the repository at this point in the history
This update supports tagging in the vsphere_nas_datastore and
vsphere_vmfs_datastore resources. Using the same workflows applied to
the virtual machine resource.

In addition to the tests supplied for the datastore resources, I've
re-enabled the import test for vsphere_vmfs_datastore now that we have
ImportStateIdFunc to help generate the ID.
  • Loading branch information
vancluever committed Sep 25, 2017
1 parent 92fbfdf commit 76c3e13
Show file tree
Hide file tree
Showing 7 changed files with 473 additions and 64 deletions.
32 changes: 32 additions & 0 deletions vsphere/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,35 @@ func testObjectHasTags(s *terraform.State, client *tags.RestClient, obj object.R

return nil
}

// testGetDatastore gets the datastore at the supplied full address. This
// function works for multiple datastore resources (example:
// vsphere_nas_datastore and vsphere_vmfs_datastore), hence the need for the
// full resource address including the resource type.
func testGetDatastore(s *terraform.State, resAddr string) (*object.Datastore, error) {
vars, err := testClientVariablesForResource(s, resAddr)
if err != nil {
return nil, err
}
return datastoreFromID(vars.client, vars.resourceID)
}

// 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.
//
// The full datastore resource address is needed as this functions across
// multiple datastore resource types.
func testAccResourceVSphereDatastoreCheckTags(dsResAddr, tagResName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ds, err := testGetDatastore(s, dsResAddr)
if err != nil {
return err
}
tagsClient, err := testAccProvider.Meta().(*VSphereClient).TagsClient()
if err != nil {
return err
}
return testObjectHasTags(s, tagsClient, ds, tagResName)
}
}
40 changes: 40 additions & 0 deletions vsphere/resource_vsphere_nas_datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func resourceVSphereNasDatastore() *schema.Resource {
mergeSchema(s, schemaHostNasVolumeSpec())
mergeSchema(s, schemaDatastoreSummary())

// Add tags schema
s[vSphereTagAttributeKey] = tagsSchema()

return &schema.Resource{
Create: resourceVSphereNasDatastoreCreate,
Read: resourceVSphereNasDatastoreRead,
Expand All @@ -50,6 +53,14 @@ func resourceVSphereNasDatastore() *schema.Resource {

func resourceVSphereNasDatastoreCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*VSphereClient).vimClient

// Load up the tags client, which will validate a proper vCenter before
// attempting to proceed if we have tags defined.
tagsClient, err := tagsClientIfDefined(d, meta)
if err != nil {
return err
}

hosts := sliceInterfacesToStrings(d.Get("host_system_ids").(*schema.Set).List())
p := &nasDatastoreMountProcessor{
client: client,
Expand All @@ -73,6 +84,13 @@ func resourceVSphereNasDatastoreCreate(d *schema.ResourceData, meta interface{})
}
}

// Apply any pending tags now
if tagsClient != nil {
if err := processTagDiff(tagsClient, d, ds); err != nil {
return err
}
}

// Done
return resourceVSphereNasDatastoreRead(d, meta)
}
Expand Down Expand Up @@ -113,11 +131,26 @@ func resourceVSphereNasDatastoreRead(d *schema.ResourceData, meta interface{}) e
return err
}

// Read tags if we have the ability to do so
if tagsClient, _ := meta.(*VSphereClient).TagsClient(); tagsClient != nil {
if err := readTagsForResoruce(tagsClient, ds, d); err != nil {
return err
}
}

return nil
}

func resourceVSphereNasDatastoreUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*VSphereClient).vimClient

// Load up the tags client, which will validate a proper vCenter before
// attempting to proceed if we have tags defined.
tagsClient, err := tagsClientIfDefined(d, meta)
if err != nil {
return err
}

id := d.Id()
ds, err := datastoreFromID(client, id)
if err != nil {
Expand All @@ -139,6 +172,13 @@ func resourceVSphereNasDatastoreUpdate(d *schema.ResourceData, meta interface{})
}
}

// Apply any pending tags now
if tagsClient != nil {
if err := processTagDiff(tagsClient, d, ds); err != nil {
return err
}
}

// Process mount/unmount operations.
o, n := d.GetChange("host_system_ids")

Expand Down
179 changes: 160 additions & 19 deletions vsphere/resource_vsphere_nas_datastore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,53 @@ func TestAccResourceVSphereNasDatastore(t *testing.T) {
},
},
},
{
"single tag",
resource.TestCase{
PreCheck: func() {
testAccPreCheck(tp)
testAccResourceVSphereNasDatastorePreCheck(tp)
},
Providers: testAccProviders,
CheckDestroy: testAccResourceVSphereNasDatastoreExists(false),
Steps: []resource.TestStep{
{
Config: testAccResourceVSphereNasDatastoreConfigBasicTags(),
Check: resource.ComposeTestCheckFunc(
testAccResourceVSphereNasDatastoreExists(true),
testAccResourceVSphereDatastoreCheckTags("vsphere_nas_datastore.datastore", "terraform-test-tag"),
),
},
},
},
},
{
"modify tags",
resource.TestCase{
PreCheck: func() {
testAccPreCheck(tp)
testAccResourceVSphereNasDatastorePreCheck(tp)
},
Providers: testAccProviders,
CheckDestroy: testAccResourceVSphereNasDatastoreExists(false),
Steps: []resource.TestStep{
{
Config: testAccResourceVSphereNasDatastoreConfigBasicTags(),
Check: resource.ComposeTestCheckFunc(
testAccResourceVSphereNasDatastoreExists(true),
testAccResourceVSphereDatastoreCheckTags("vsphere_nas_datastore.datastore", "terraform-test-tag"),
),
},
{
Config: testAccResourceVSphereNasDatastoreConfigMultiTags(),
Check: resource.ComposeTestCheckFunc(
testAccResourceVSphereNasDatastoreExists(true),
testAccResourceVSphereDatastoreCheckTags("vsphere_nas_datastore.datastore", "terraform-test-tags-alt"),
),
},
},
},
},
{
"import",
resource.TestCase{
Expand Down Expand Up @@ -241,12 +288,7 @@ func testAccResourceVSphereNasDatastorePreCheck(t *testing.T) {

func testAccResourceVSphereNasDatastoreExists(expected bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
vars, err := testClientVariablesForResource(s, "vsphere_nas_datastore.datastore")
if err != nil {
return err
}

_, err = datastoreFromID(vars.client, vars.resourceID)
ds, err := testGetDatastore(s, "vsphere_nas_datastore.datastore")
if err != nil {
if isManagedObjectNotFoundError(err) && expected == false {
// Expected missing
Expand All @@ -255,20 +297,15 @@ func testAccResourceVSphereNasDatastoreExists(expected bool) resource.TestCheckF
return err
}
if !expected {
return fmt.Errorf("expected datastore %s to be missing", vars.resourceID)
return fmt.Errorf("expected datastore %q to be missing", ds.Reference().Value)
}
return nil
}
}

func testAccResourceVSphereNasDatastoreHasName(expected string) resource.TestCheckFunc {
return func(s *terraform.State) error {
vars, err := testClientVariablesForResource(s, "vsphere_nas_datastore.datastore")
if err != nil {
return err
}

ds, err := datastoreFromID(vars.client, vars.resourceID)
ds, err := testGetDatastore(s, "vsphere_nas_datastore.datastore")
if err != nil {
return err
}
Expand All @@ -288,12 +325,7 @@ func testAccResourceVSphereNasDatastoreHasName(expected string) resource.TestChe

func testAccResourceVSphereNasDatastoreMatchInventoryPath(expected string) resource.TestCheckFunc {
return func(s *terraform.State) error {
vars, err := testClientVariablesForResource(s, "vsphere_nas_datastore.datastore")
if err != nil {
return err
}

ds, err := datastoreFromID(vars.client, vars.resourceID)
ds, err := testGetDatastore(s, "vsphere_nas_datastore.datastore")
if err != nil {
return err
}
Expand Down Expand Up @@ -452,3 +484,112 @@ resource "vsphere_nas_datastore" "datastore" {
}
`, os.Getenv("VSPHERE_NAS_HOST"), os.Getenv("VSPHERE_NFS_PATH"), os.Getenv("VSPHERE_DS_FOLDER"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST"))
}

func testAccResourceVSphereNasDatastoreConfigBasicTags() string {
return fmt.Sprintf(`
variable "nfs_host" {
type = "string"
default = "%s"
}
variable "nfs_path" {
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_tag_category" "terraform-test-category" {
name = "terraform-test-tag-category"
cardinality = "MULTIPLE"
associable_types = [
"Datastore",
]
}
resource "vsphere_tag" "terraform-test-tag" {
name = "terraform-test-tag"
category_id = "${vsphere_tag_category.terraform-test-category.id}"
}
resource "vsphere_nas_datastore" "datastore" {
name = "terraform-test-nas"
host_system_ids = ["${data.vsphere_host.esxi_host.id}"]
type = "NFS"
remote_hosts = ["${var.nfs_host}"]
remote_path = "${var.nfs_path}"
tags = ["${vsphere_tag.terraform-test-tag.id}"]
}
`, os.Getenv("VSPHERE_NAS_HOST"), os.Getenv("VSPHERE_NFS_PATH"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST"))
}

func testAccResourceVSphereNasDatastoreConfigMultiTags() string {
return fmt.Sprintf(`
variable "nfs_host" {
type = "string"
default = "%s"
}
variable "nfs_path" {
type = "string"
default = "%s"
}
variable "extra_tags" {
default = [
"terraform-test-thing1",
"terraform-test-thing2",
]
}
data "vsphere_datacenter" "datacenter" {
name = "%s"
}
data "vsphere_host" "esxi_host" {
name = "%s"
datacenter_id = "${data.vsphere_datacenter.datacenter.id}"
}
resource "vsphere_tag_category" "terraform-test-category" {
name = "terraform-test-tag-category"
cardinality = "MULTIPLE"
associable_types = [
"Datastore",
]
}
resource "vsphere_tag" "terraform-test-tag" {
name = "terraform-test-tag"
category_id = "${vsphere_tag_category.terraform-test-category.id}"
}
resource "vsphere_tag" "terraform-test-tags-alt" {
count = "${length(var.extra_tags)}"
name = "${var.extra_tags[count.index]}"
category_id = "${vsphere_tag_category.terraform-test-category.id}"
}
resource "vsphere_nas_datastore" "datastore" {
name = "terraform-test-nas"
host_system_ids = ["${data.vsphere_host.esxi_host.id}"]
type = "NFS"
remote_hosts = ["${var.nfs_host}"]
remote_path = "${var.nfs_path}"
tags = ["${vsphere_tag.terraform-test-tags-alt.*.id}"]
}
`, os.Getenv("VSPHERE_NAS_HOST"), os.Getenv("VSPHERE_NFS_PATH"), os.Getenv("VSPHERE_DATACENTER"), os.Getenv("VSPHERE_ESXI_HOST"))
}
Loading

0 comments on commit 76c3e13

Please sign in to comment.