Following the last blog post on create vSphere Port Groups, let’s take a look at creating Tags and Tag Categories.
Let’s first look at the process via the GUI, in this case, the vSphere Client. (Based on vSphere 7.0.3c)
vSphere Client
I wont go into to much detail here as this information is readily available, but here is a brief run through.
After logging into the vSphere Client, select the menu followed by Tags & Custom Attributes.
You the have the option to select either Tags or Categories, followed by the ‘New’ option.
For Categories you need to provide the Category name, optional description, the cardinality (single or multiple) and select the objects that can have this tag associated with it.
Then with Tags, you need to provide the name, optional description and the category the tag will be part of.
Now this may be ok for one or two, but if you need to create in bulk, this will take a while! Lets look as some alternatives.
PowerShell
Firstly, PowerShell, specifically the VMware PowerCLI PowerShell module. Here are examples of the using the cmdlets New-TagCategory and New-Tag to create the same thing we did in the vSphere Client.
1#Tag Categories
2New-TagCategory -Name "costcentre" -Description "Created with PowerCLI" -Cardinality "MULTIPLE" -EntityType "VirtualMachine", "Datastore"
3#Tags
4New-Tag -Name "0001" -Category "costcentre" -Description "Created with PowerCLI"
Below is the output from PowerShell after running the script above:
1Name Cardinality Description
2---- ----------- -----------
3costcentre Multiple Created with PowerCLI
4
5Name Category Description
6---- -------- -----------
70001 costcentre Created with PowerCLI
Now this isn’t much quicker than doing it in the vSphere Client so here is one way to create in bulk.
Here is a custom array with multiple categories and the additional values needed to create a Category.
1$TagCategories = @(
2 [pscustomobject]@{Name = "costcentre"; Cardinality = "MULTIPLE"; EntityType = "VirtualMachine", "Datastore" }
3 [pscustomobject]@{Name = "environment"; Cardinality = "SINGLE"; EntityType = "VirtualMachine", "Datastore" }
4 [pscustomobject]@{Name = "nsx-tier"; Cardinality = "MULTIPLE"; EntityType = "VirtualMachine" }
5)
6foreach ($Category in $TagCategories) {
7 New-TagCategory -Name $Category.Name -Cardinality $Category.Cardinality -EntityType $Category.EntityType -Description "Created with PowerCLI"
8}
Here is the output:
1Name Cardinality Description
2---- ----------- -----------
3costcentre Multiple Created with PowerCLI
4environment Single Created with PowerCLI
5nsx-tier Multiple Created with PowerCLI
And now the same principal but with Tags.
1$Tags = @(
2 [pscustomobject]@{Name = "0001"; Category = "costcentre" }
3 [pscustomobject]@{Name = "0002"; Category = "costcentre" }
4 [pscustomobject]@{Name = "0003"; Category = "costcentre" }
5 [pscustomobject]@{Name = "0004"; Category = "costcentre" }
6 [pscustomobject]@{Name = "environment"; Category = "environment" }
7 [pscustomobject]@{Name = "production"; Category = "environment" }
8 [pscustomobject]@{Name = "pre-production"; Category = "environment" }
9 [pscustomobject]@{Name = "test"; Category = "environment" }
10 [pscustomobject]@{Name = "development"; Category = "environment" }
11 [pscustomobject]@{Name = "web"; Category = "nsx-tier" }
12 [pscustomobject]@{Name = "app"; Category = "nsx-tier" }
13 [pscustomobject]@{Name = "data"; Category = "nsx-tier" }
14)
15foreach ($Tag in $Tags) {
16 New-Tag -Name $Tag.Name -Category $Tag.Category -Description "Created with PowerCLI"
17}
Output:
1Name Category Description
2---- -------- -----------
30001 costcentre Created with PowerCLI
40002 costcentre Created with PowerCLI
50003 costcentre Created with PowerCLI
60004 costcentre Created with PowerCLI
7environment environment Created with PowerCLI
8production environment Created with PowerCLI
9pre-production environment Created with PowerCLI
10test environment Created with PowerCLI
11development environment Created with PowerCLI
12web nsx-tier Created with PowerCLI
13app nsx-tier Created with PowerCLI
14data nsx-tier Created with PowerCLI
That is just one way to create multiple Categories and Tags. You could take this information from a CSV file using the ‘Get-Content’ cmdlet as an alternative to creating the array manually.
Terraform
Now let’s take a look at using Terraform to achieve the same result. Terraform is an infrastructure and code tool used to manage infrastructure in the form of configuration files and state:
1#Providers
2provider "vsphere" {
3 vsphere_server = "vcsa-fqdn"
4 user = "domain\\user"
5 password = "password"
6 allow_unverified_ssl = false
7}
8#Tag categories
9resource "vsphere_tag_category" "costcentre" {
10 name = "costcentre"
11 description = "Managed by Terraform"
12 cardinality = "MULTIPLE"
13 associable_types = [
14 "VirtualMachine",
15 "Datastore",
16 ]
17}
18resource "vsphere_tag_category" "environment" {
19 name = "environment"
20 description = "Managed by Terraform"
21 cardinality = "SINGLE"
22 associable_types = [
23 "VirtualMachine",
24 "Datastore",
25 ]
26}
27resource "vsphere_tag_category" "nsx-tier" {
28 name = "nsx-tier"
29 description = "Managed by Terraform"
30 cardinality = "MULTIPLE"
31 associable_types = [
32 "VirtualMachine"
33 ]
34}
35#Tags
36#Local values
37locals {
38 costcentre_tags = ["0001", "0002", "0003", "0004"]
39 environment_tags = ["production", "pre-production", "test", "development"]
40 nsx_tier_tags = ["web", "app", "data"]
41}
42#Resources
43resource "vsphere_tag" "costcentre-tags" {
44 for_each = toset(local.costcentre_tags)
45 name = each.key
46 category_id = vsphere_tag_category.costcentre.id
47 description = "Managed by Terraform"
48}
49resource "vsphere_tag" "environment-tags" {
50 for_each = toset(local.environment_tags)
51 name = each.key
52 category_id = vsphere_tag_category.environment.id
53 description = "Managed by Terraform"
54}
55resource "vsphere_tag" "nsx-tier-tags" {
56 for_each = toset(local.nsx_tier_tags)
57 name = each.key
58 category_id = vsphere_tag_category.nsx-tier.id
59 description = "Managed by Terraform"
60}
Lets break this down.
First we are specifying which terraform provider we want to use, this will be the vSphere provider in this case. We are then providing some parameters for the provider to connect to your vCenter instance; VCSA FQDN and credentials. You would want make use of variables for this data, but for this blog I am keeping it simple.
1provider "vsphere" {
2 vsphere_server = "vcsa-fqdn"
3 user = "domain\\user"
4 password = "password"
5 allow_unverified_ssl = false
6}
We then have three vsphere_tag_category resource blocks, one for each of the categories we want to create. This again provides values for cardinality and associable types like we did in PowerShell.
1resource "vsphere_tag_category" "costcentre" {
2 name = "costcentre"
3 description = "Managed by Terraform"
4 cardinality = "MULTIPLE"
5 associable_types = [
6 "VirtualMachine",
7 "Datastore",
8 ]
9}
10resource "vsphere_tag_category" "environment" {
11 name = "environment"
12 description = "Managed by Terraform"
13 cardinality = "SINGLE"
14 associable_types = [
15 "VirtualMachine",
16 "Datastore",
17 ]
18}
19resource "vsphere_tag_category" "nsx-tier" {
20 name = "nsx-tier"
21 description = "Managed by Terraform"
22 cardinality = "MULTIPLE"
23 associable_types = [
24 "VirtualMachine"
25 ]
26}
Next we are going to create the tags, but I am going to use a set of local variables to then pass into the three vsphere_tag resource blocks to reduce the amount of repeating code.
Here are the local variables. This is similar to creating the array we did in PowerShell.
1locals {
2 costcentre_tags = ["0001", "0002", "0003", "0004"]
3 environment_tags = ["production", "pre-production", "test", "development"]
4 nsx_tier_tags = ["web", "app", "data"]
5}
And then the resource blocks, notice the for_each parameter. For each Tag Category, it will cycle through each value in the locals array for each category. This is just like we did in PowerShell foreach function earlier.
1resource "vsphere_tag" "costcentre-tags" {
2 for_each = toset(local.costcentre_tags)
3 name = each.key
4 category_id = vsphere_tag_category.costcentre.id
5 description = "Managed by Terraform"
6}
7resource "vsphere_tag" "environment-tags" {
8 for_each = toset(local.environment_tags)
9 name = each.key
10 category_id = vsphere_tag_category.environment.id
11 description = "Managed by Terraform"
12}
13resource "vsphere_tag" "nsx-tier-tags" {
14 for_each = toset(local.nsx_tier_tags)
15 name = each.key
16 category_id = vsphere_tag_category.nsx-tier.id
17 description = "Managed by Terraform"
18}
Now when we run ’terraform apply’ from the command line to apply for code, this is the output:
1Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
2 + create
3
4Terraform will perform the following actions:
5
6 # vsphere_tag.costcentre-tags["0001"] will be created
7 + resource "vsphere_tag" "costcentre-tags" {
8 + category_id = (known after apply)
9 + description = "Managed by Terraform"
10 + id = (known after apply)
11 + name = "0001"
12 }
13
14 # vsphere_tag.costcentre-tags["0002"] will be created
15 + resource "vsphere_tag" "costcentre-tags" {
16 + category_id = (known after apply)
17 + description = "Managed by Terraform"
18 + id = (known after apply)
19 + name = "0002"
20 }
21
22 # vsphere_tag.costcentre-tags["0003"] will be created
23 + resource "vsphere_tag" "costcentre-tags" {
24 + category_id = (known after apply)
25 + description = "Managed by Terraform"
26 + id = (known after apply)
27 + name = "0003"
28 }
29
30 # vsphere_tag.costcentre-tags["0004"] will be created
31 + resource "vsphere_tag" "costcentre-tags" {
32 + category_id = (known after apply)
33 + description = "Managed by Terraform"
34 + id = (known after apply)
35 + name = "0004"
36 }
37
38 # vsphere_tag.environment-tags["development"] will be created
39 + resource "vsphere_tag" "environment-tags" {
40 + category_id = (known after apply)
41 + description = "Managed by Terraform"
42 + id = (known after apply)
43 + name = "development"
44 }
45
46 # vsphere_tag.environment-tags["pre-production"] will be created
47 + resource "vsphere_tag" "environment-tags" {
48 + category_id = (known after apply)
49 + description = "Managed by Terraform"
50 + id = (known after apply)
51 + name = "pre-production"
52 }
53
54 # vsphere_tag.environment-tags["production"] will be created
55 + resource "vsphere_tag" "environment-tags" {
56 + category_id = (known after apply)
57 + description = "Managed by Terraform"
58 + id = (known after apply)
59 + name = "production"
60 }
61
62 # vsphere_tag.environment-tags["test"] will be created
63 + resource "vsphere_tag" "environment-tags" {
64 + category_id = (known after apply)
65 + description = "Managed by Terraform"
66 + id = (known after apply)
67 + name = "test"
68 }
69
70 # vsphere_tag.nsx-tier-tags["app"] will be created
71 + resource "vsphere_tag" "nsx-tier-tags" {
72 + category_id = (known after apply)
73 + description = "Managed by Terraform"
74 + id = (known after apply)
75 + name = "app"
76 }
77
78 # vsphere_tag.nsx-tier-tags["data"] will be created
79 + resource "vsphere_tag" "nsx-tier-tags" {
80 + category_id = (known after apply)
81 + description = "Managed by Terraform"
82 + id = (known after apply)
83 + name = "data"
84 }
85
86 # vsphere_tag.nsx-tier-tags["web"] will be created
87 + resource "vsphere_tag" "nsx-tier-tags" {
88 + category_id = (known after apply)
89 + description = "Managed by Terraform"
90 + id = (known after apply)
91 + name = "web"
92 }
93
94 # vsphere_tag_category.costcentre will be created
95 + resource "vsphere_tag_category" "costcentre" {
96 + associable_types = [
97 + "Datastore",
98 + "VirtualMachine",
99 ]
100 + cardinality = "MULTIPLE"
101 + description = "Managed by Terraform"
102 + id = (known after apply)
103 + name = "costcentre"
104 }
105
106 # vsphere_tag_category.environment will be created
107 + resource "vsphere_tag_category" "environment" {
108 + associable_types = [
109 + "Datastore",
110 + "VirtualMachine",
111 ]
112vsphere_tag.environment-tags["production"]: Creating...
113vsphere_tag.environment-tags["pre-production"]: Creating...
114vsphere_tag_category.nsx-tier: Creation complete after 0s [id=urn:vmomi:InventoryServiceCategory:20a2167a-b0f8-4a60-9d29-6c7ca57711ef:GLOBAL]
115vsphere_tag.nsx-tier-tags["data"]: Creating...
116vsphere_tag.nsx-tier-tags["app"]: Creating...
117vsphere_tag.nsx-tier-tags["web"]: Creating...
118vsphere_tag_category.costcentre: Creation complete after 0s [id=urn:vmomi:InventoryServiceCategory:28a909f5-ee41-4d94-b228-b5e96e09284e:GLOBAL]
119vsphere_tag.costcentre-tags["0004"]: Creating...
120vsphere_tag.costcentre-tags["0002"]: Creating...
121vsphere_tag.costcentre-tags["0003"]: Creating...
122vsphere_tag.environment-tags["development"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:5b63e350-ef6e-4bbc-a633-09c9047b327b:GLOBAL]
123vsphere_tag.costcentre-tags["0001"]: Creating...
124vsphere_tag.environment-tags["pre-production"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:e2a8737c-e42a-4c6f-b9a8-716a1681d0c0:GLOBAL]
125vsphere_tag.nsx-tier-tags["data"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:b9d3394d-388c-4018-b7b2-9e4d3da8287b:GLOBAL]
126vsphere_tag.costcentre-tags["0002"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:8a482528-5d67-40e9-86cb-4dbf566f85ac:GLOBAL]
127vsphere_tag.nsx-tier-tags["web"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:5a325904-4dfd-46ac-b0db-37fd6fda1533:GLOBAL]
128vsphere_tag.environment-tags["production"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:89c609b9-7f90-457d-9f71-0bd0b7cc667d:GLOBAL]
129vsphere_tag.nsx-tier-tags["app"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:45c2dd0e-533a-4917-82be-987d3245137a:GLOBAL]
130vsphere_tag.costcentre-tags["0004"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:230db56e-7352-4e14-ba63-0ad4b4c0ba18:GLOBAL]
131vsphere_tag.environment-tags["test"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:ebcf1809-8cae-4cb2-a5fa-82a492e54227:GLOBAL]
132vsphere_tag.costcentre-tags["0001"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:e4649ad2-08d2-4dcd-aabf-4e2d74f93a36:GLOBAL]
133vsphere_tag.costcentre-tags["0003"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:18de9eca-456c-4539-ad6c-19d625ac5be7:GLOBAL]
134
135Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
For more information on the vSphere provider from Terraform, check out this link.
I hope this has given you some idea’s on how you can perhaps leverage other options beside the GUI, especially when looking to build or configure in bulk. All the code in this blog can be found on my GitHub here.
Thanks for reading!
If you like my content, consider following me on Twitter so you don’t miss out!