Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tags: Support tagging in datastore resources #176

Merged
merged 2 commits into from
Sep 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vsphere/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type VSphereClient struct {
// are, read them from the object and save them in the resource:
//
// if tagsClient, _ := meta.(*VSphereClient).TagsClient(); tagsClient != nil {
// if err := readTagsForResoruce(tagsClient, obj, d); err != nil {
// if err := readTagsForResource(tagsClient, obj, d); err != nil {
// return err
// }
// }
Expand Down
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 := readTagsForResource(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"))
}
2 changes: 1 addition & 1 deletion vsphere/resource_vsphere_virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,7 @@ func resourceVSphereVirtualMachineRead(d *schema.ResourceData, meta interface{})

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