Category Archives: VMware

NSX-T Edge Node 3.2 Upgrade Issue – Hugepage Support

I recently did the first NSX upgrade in my Homelab! My Lab is running older hardware, HPE DL380 Gen8’s to be exact and this lead to an upgrade issue when attempting to upgrade my Edge node!

Here is the error I was faced with:

Edge 3.2.0.0.0.19067356/Edge/nub/VMware-NSX-edge-3.2.0.0.0.19067362.nub switch OS task failed on edge TransportNode c7aa6c6e-1a49-423a-a5c2-87cfa0ba9e1c: clientType EDGE , target edge fabric node id c7aa6c6e-1a49-423a-a5c2-87cfa0ba9e1c, return status switch_os execution failed with msg: An unexpected exception occurred: CommandFailedError: Command ['chroot', '/os_bak', '/opt/vmware/nsx-edge/bin/config.py', '--update-only'] returned non-zero code 1: b"lspci: Unable to load libkmod resources: error -12\nlspci: Unable to load libkmod resources: error -12\nlspci: Unable to load libkmod resources: error -12\nlspci: Unable to load libkmod resources: error -12\nlspci: Unable to load libkmod resources: error -12\nSystem has not been booted with systemd as init system (PID 1). Can't operate.\nERROR: Unable to get maintenance mode information\nNsxRpcClient encountered an error: [Errno 2] No such file or directory\nWARNING: Exception reading InbandMgmtInterfaceMsg from nestdb, Command '['/opt/vmware/nsx-nestdb/bin/nestdb-cli', '--json', '--cmd', 'get', 'InbandMgmtInterfaceMsg']' returned non-zero exit status 1.\nINFO: Corelist count is rounded to 2 from 3\nERROR: NSX Edge configuration has failed. 1G hugepage support required\n" .

This thread on VMTN provided the answer and an explanation, so I won’t repeat that here but I did want to share this.

In order to work around this issue, you need to power off the Edge node VM, add the following advanced setting and power back on.

featMask.vm.cpuid.pdpe1gb = Val:1

Once back online, you can continue with the upgrade!

Hopefully this will help any homelabbers out there running older hardware!

As always, thanks for reading!

If you like my content, consider following me on Twitter so you don’t miss out!

https://platform.twitter.com/widgets.js

Configuring vSphere 7 Auto Deploy

Whilst continuing to prepare for my VMware Certified Advanced Professional Deploy Exam, I have been configuring vSphere Auto Deploy. As with my blog post on vCenter Profiles, I am covering Auto Deploy as its not something I have ever used in any great depth. As always, I used the official VMware documentation to guide me.

Lets get started!

In my lab I am using vCenter 7.0 Update 3c and using nested hosts for the Auto Deploy hosts. I am also using a RHEL server for the TFTP requirement along with DHCP provided by my layer 3 switch.

Depending on whether you are using BIOS or UEFI you will need to set the appropriate DHCP options; 66 & 67.

I am using EFI, therefore using UEFI DHCP Boot File Name : snponly64.efi.vmw-hardwired as the value for DHCP option 067.

Here are the two DHCP options I have set:

066 : 10.200.15.22
067 : snponly64.efi.vmw-hardwired

In the vSphere Client Select the Auto Deploy menu:

If you haven’t setup Auto Deploy previously, click Enable Auto Deploy and Image Builder.

You now need to download the required files, including the boot files mentioned earlier, that you will need to host on your TFTP server by selecting the Download TFTP Zip File link:

Copy the downloaded file to your TFTP server using something like WinSCP and extract the ZIP file to the TFTPRoot directory you configured as part of the TFTP server installation/setup.

Your directory should then look something like this:

Now using PowerShell 5.1 (PowerShell 7 is not supported by the VMware.ImageBuilder module), connect to the vCenter Server and run the following commands to set up the software depots:

Connect-VIServer <vcsa-fqdn> -Credential $creds
Add-EsxSoftwareDepot https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml

You can check you have added the depot successfully by running the following:

Get-EsxImageProfile

Now to create the Deploy Rules. I will be using the latest image; ESXi-7.0U3c-19193900-standard, deploying to my ‘virtual-cluster’ and providing it with a host profile I already had. I have also provided an IP address range for the hosts I want to include. You can also just use the ‘-AllHosts’ parameter if you don’t want to restrict.

New-DeployRule -Name "Lab Auto Deploy Rule" -Item "virtual-cluster", "ESXi-7.0U3c-19193900-standard", "Virtual Cluster Hosts" -Pattern "ipv4=10.200.40.10-10.200.40.20"

My host profile contains a few basic settings such as the root password, NTP settings & NIC configurations. There are plenty of host configuration options that can be set in this profile, configure the settings you need for your environment or lab.

You will be able to see the rules in the vSphere Client once complete.

<Side Note>

If you want to be able to manually add rules in the vSphere Client, you will need to manually add the software depot using the same URL used earlier.

You will then be able to manually create Deploy Rules.

</Side Note>

Now back to it…

You will see the Deploy Rule is currently inactive:

Running the following activates the rule:

Add-DeployRule -DeployRule "Lab Auto Deploy Rule"

You can now see the status is Active in the UI.

If using the vSphere Client, you can use the ‘Activate/Deactivate Rules’ button instead if you didn’t want to use PowerShell.

Now before we start deploying hosts, we need to create some! In this case they will be nested hosts with minimum configurations. We will also need some DHCP reservations and appropriate DNS records.

Once in place, we can go ahead an boot the hosts.

Now heading back to the vSphere UI, you will find your newly deployed host(s)!

From a troubleshooting perspective, you will be wanting to take a look in syslog.log on the host. This helped me identify my issues when I hadn’t applied a firewall rule correctly!

As always, thanks for reading!

If you like my content, consider following me on Twitter so you don’t miss out!

https://platform.twitter.com/widgets.js

Different Tools; Same Result – vSphere Tags

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.

#Tag Categories
New-TagCategory -Name "costcentre" -Description "Created with PowerCLI" -Cardinality "MULTIPLE" -EntityType "VirtualMachine", "Datastore"
#Tags
New-Tag -Name "0001" -Category "costcentre" -Description "Created with PowerCLI"

Below is the output from PowerShell after running the script above:

Name                                     Cardinality Description
----                                     ----------- -----------
costcentre                               Multiple    Created with PowerCLI

Name                           Category                       Description
----                           --------                       -----------
0001                           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.

$TagCategories = @(
    [pscustomobject]@{Name = "costcentre"; Cardinality = "MULTIPLE"; EntityType = "VirtualMachine", "Datastore" }
    [pscustomobject]@{Name = "environment"; Cardinality = "SINGLE"; EntityType = "VirtualMachine", "Datastore" }
    [pscustomobject]@{Name = "nsx-tier"; Cardinality = "MULTIPLE"; EntityType = "VirtualMachine" }
)
foreach ($Category in $TagCategories) {
    New-TagCategory -Name $Category.Name -Cardinality $Category.Cardinality -EntityType $Category.EntityType -Description "Created with PowerCLI"
}

Here is the output:

Name                                     Cardinality Description
----                                     ----------- -----------
costcentre                               Multiple    Created with PowerCLI
environment                              Single      Created with PowerCLI
nsx-tier                                 Multiple    Created with PowerCLI

And now the same principal but with Tags.

$Tags = @(
    [pscustomobject]@{Name = "0001"; Category = "costcentre" }
    [pscustomobject]@{Name = "0002"; Category = "costcentre" }
    [pscustomobject]@{Name = "0003"; Category = "costcentre" }
    [pscustomobject]@{Name = "0004"; Category = "costcentre" }
    [pscustomobject]@{Name = "environment"; Category = "environment" }
    [pscustomobject]@{Name = "production"; Category = "environment" }
    [pscustomobject]@{Name = "pre-production"; Category = "environment" }
    [pscustomobject]@{Name = "test"; Category = "environment" }
    [pscustomobject]@{Name = "development"; Category = "environment" }
    [pscustomobject]@{Name = "web"; Category = "nsx-tier" }
    [pscustomobject]@{Name = "app"; Category = "nsx-tier" }
    [pscustomobject]@{Name = "data"; Category = "nsx-tier" }
)
foreach ($Tag in $Tags) {
    New-Tag -Name $Tag.Name -Category $Tag.Category -Description "Created with PowerCLI"
}

Output:

Name                           Category                       Description
----                           --------                       -----------
0001                           costcentre                     Created with PowerCLI
0002                           costcentre                     Created with PowerCLI
0003                           costcentre                     Created with PowerCLI
0004                           costcentre                     Created with PowerCLI
environment                    environment                    Created with PowerCLI
production                     environment                    Created with PowerCLI
pre-production                 environment                    Created with PowerCLI
test                           environment                    Created with PowerCLI
development                    environment                    Created with PowerCLI
web                            nsx-tier                       Created with PowerCLI
app                            nsx-tier                       Created with PowerCLI
data                           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:

#Providers
provider "vsphere" {
  vsphere_server       = "vcsa-fqdn"
  user                 = "domain\\user"
  password             = "password"
  allow_unverified_ssl = false
}
#Tag categories
resource "vsphere_tag_category" "costcentre" {
  name        = "costcentre"
  description = "Managed by Terraform"
  cardinality = "MULTIPLE"
  associable_types = [
    "VirtualMachine",
    "Datastore",
  ]
}
resource "vsphere_tag_category" "environment" {
  name        = "environment"
  description = "Managed by Terraform"
  cardinality = "SINGLE"
  associable_types = [
    "VirtualMachine",
    "Datastore",
  ]
}
resource "vsphere_tag_category" "nsx-tier" {
  name        = "nsx-tier"
  description = "Managed by Terraform"
  cardinality = "MULTIPLE"
  associable_types = [
    "VirtualMachine"
  ]
}
#Tags
#Local values
locals {
  costcentre_tags  = ["0001", "0002", "0003", "0004"]
  environment_tags = ["production", "pre-production", "test", "development"]
  nsx_tier_tags    = ["web", "app", "data"]
}
#Resources
resource "vsphere_tag" "costcentre-tags" {
  for_each    = toset(local.costcentre_tags)
  name        = each.key
  category_id = vsphere_tag_category.costcentre.id
  description = "Managed by Terraform"
}
resource "vsphere_tag" "environment-tags" {
  for_each    = toset(local.environment_tags)
  name        = each.key
  category_id = vsphere_tag_category.environment.id
  description = "Managed by Terraform"
}
resource "vsphere_tag" "nsx-tier-tags" {
  for_each    = toset(local.nsx_tier_tags)
  name        = each.key
  category_id = vsphere_tag_category.nsx-tier.id
  description = "Managed by Terraform"
}

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.

provider "vsphere" {
  vsphere_server       = "vcsa-fqdn"
  user                 = "domain\\user"
  password             = "password"
  allow_unverified_ssl = false
}

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.

resource "vsphere_tag_category" "costcentre" {
  name        = "costcentre"
  description = "Managed by Terraform"
  cardinality = "MULTIPLE"
  associable_types = [
    "VirtualMachine",
    "Datastore",
  ]
}
resource "vsphere_tag_category" "environment" {
  name        = "environment"
  description = "Managed by Terraform"
  cardinality = "SINGLE"
  associable_types = [
    "VirtualMachine",
    "Datastore",
  ]
}
resource "vsphere_tag_category" "nsx-tier" {
  name        = "nsx-tier"
  description = "Managed by Terraform"
  cardinality = "MULTIPLE"
  associable_types = [
    "VirtualMachine"
  ]
}

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.

locals {
  costcentre_tags  = ["0001", "0002", "0003", "0004"]
  environment_tags = ["production", "pre-production", "test", "development"]
  nsx_tier_tags    = ["web", "app", "data"]
}

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.

resource "vsphere_tag" "costcentre-tags" {
  for_each    = toset(local.costcentre_tags)
  name        = each.key
  category_id = vsphere_tag_category.costcentre.id
  description = "Managed by Terraform"
}
resource "vsphere_tag" "environment-tags" {
  for_each    = toset(local.environment_tags)
  name        = each.key
  category_id = vsphere_tag_category.environment.id
  description = "Managed by Terraform"
}
resource "vsphere_tag" "nsx-tier-tags" {
  for_each    = toset(local.nsx_tier_tags)
  name        = each.key
  category_id = vsphere_tag_category.nsx-tier.id
  description = "Managed by Terraform"
}

Now when we run ‘terraform apply’ from the command line to apply for code, this is the output:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
    
Terraform will perform the following actions:

  # vsphere_tag.costcentre-tags["0001"] will be created
  + resource "vsphere_tag" "costcentre-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "0001"
    }

  # vsphere_tag.costcentre-tags["0002"] will be created
  + resource "vsphere_tag" "costcentre-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "0002"
    }

  # vsphere_tag.costcentre-tags["0003"] will be created
  + resource "vsphere_tag" "costcentre-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "0003"
    }

  # vsphere_tag.costcentre-tags["0004"] will be created
  + resource "vsphere_tag" "costcentre-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "0004"
    }

  # vsphere_tag.environment-tags["development"] will be created
  + resource "vsphere_tag" "environment-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "development"
    }

  # vsphere_tag.environment-tags["pre-production"] will be created
  + resource "vsphere_tag" "environment-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "pre-production"
    }

  # vsphere_tag.environment-tags["production"] will be created
  + resource "vsphere_tag" "environment-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "production"
    }

  # vsphere_tag.environment-tags["test"] will be created
  + resource "vsphere_tag" "environment-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "test"
    }

  # vsphere_tag.nsx-tier-tags["app"] will be created
  + resource "vsphere_tag" "nsx-tier-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "app"
    }

  # vsphere_tag.nsx-tier-tags["data"] will be created
  + resource "vsphere_tag" "nsx-tier-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "data"
    }

  # vsphere_tag.nsx-tier-tags["web"] will be created
  + resource "vsphere_tag" "nsx-tier-tags" {
      + category_id = (known after apply)
      + description = "Managed by Terraform"
      + id          = (known after apply)
      + name        = "web"
    }

  # vsphere_tag_category.costcentre will be created
  + resource "vsphere_tag_category" "costcentre" {
      + associable_types = [
          + "Datastore",
          + "VirtualMachine",
        ]
      + cardinality      = "MULTIPLE"
      + description      = "Managed by Terraform"
      + id               = (known after apply)
      + name             = "costcentre"
    }

  # vsphere_tag_category.environment will be created
  + resource "vsphere_tag_category" "environment" {
      + associable_types = [
          + "Datastore",
          + "VirtualMachine",
        ]
vsphere_tag.environment-tags["production"]: Creating...
vsphere_tag.environment-tags["pre-production"]: Creating...
vsphere_tag_category.nsx-tier: Creation complete after 0s [id=urn:vmomi:InventoryServiceCategory:20a2167a-b0f8-4a60-9d29-6c7ca57711ef:GLOBAL]
vsphere_tag.nsx-tier-tags["data"]: Creating...
vsphere_tag.nsx-tier-tags["app"]: Creating...
vsphere_tag.nsx-tier-tags["web"]: Creating...
vsphere_tag_category.costcentre: Creation complete after 0s [id=urn:vmomi:InventoryServiceCategory:28a909f5-ee41-4d94-b228-b5e96e09284e:GLOBAL]
vsphere_tag.costcentre-tags["0004"]: Creating...
vsphere_tag.costcentre-tags["0002"]: Creating...
vsphere_tag.costcentre-tags["0003"]: Creating...
vsphere_tag.environment-tags["development"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:5b63e350-ef6e-4bbc-a633-09c9047b327b:GLOBAL]
vsphere_tag.costcentre-tags["0001"]: Creating...
vsphere_tag.environment-tags["pre-production"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:e2a8737c-e42a-4c6f-b9a8-716a1681d0c0:GLOBAL]
vsphere_tag.nsx-tier-tags["data"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:b9d3394d-388c-4018-b7b2-9e4d3da8287b:GLOBAL]
vsphere_tag.costcentre-tags["0002"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:8a482528-5d67-40e9-86cb-4dbf566f85ac:GLOBAL]
vsphere_tag.nsx-tier-tags["web"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:5a325904-4dfd-46ac-b0db-37fd6fda1533:GLOBAL]
vsphere_tag.environment-tags["production"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:89c609b9-7f90-457d-9f71-0bd0b7cc667d:GLOBAL]
vsphere_tag.nsx-tier-tags["app"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:45c2dd0e-533a-4917-82be-987d3245137a:GLOBAL]
vsphere_tag.costcentre-tags["0004"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:230db56e-7352-4e14-ba63-0ad4b4c0ba18:GLOBAL]
vsphere_tag.environment-tags["test"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:ebcf1809-8cae-4cb2-a5fa-82a492e54227:GLOBAL]
vsphere_tag.costcentre-tags["0001"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:e4649ad2-08d2-4dcd-aabf-4e2d74f93a36:GLOBAL]
vsphere_tag.costcentre-tags["0003"]: Creation complete after 0s [id=urn:vmomi:InventoryServiceTag:18de9eca-456c-4539-ad6c-19d625ac5be7:GLOBAL]

Apply 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!

vCenter Server Profiles

Whilst beginning preparations to take the VMware Certificated Advanced Professional Deploy exam, I have started to look into the features and topics that I’m not overly familiar with. To help with the learning process, I am going to be deploying and configuring these features, and writing blogs on many of the topics to help cement the information. Hopefully these will be useful for anyone else learning or researching these topics!

The first one; vCenter Server Profiles!

Background

vCenter Server Profiles (Section 7.2.4 Configure VMware vCenter Server® profiles in the Exam Blueprint) were first introduced in vSphere 7.0. These addressed the challenges around configuration consistency in large multi vCenter environments by allowing a ‘base’ or ‘source’ vCenter configuration to be exported, modified and imported into multiple other vCenter’s.

Not only does this help ensure a consistent configuration for things like NTP, Syslog, SSH and security settings on the appliance, but also Roles and Users can be copied to all vCenter servers quickly and easily. The Roles and Users can be a great help if you have a role on all vCenter servers for things like backup solutions or templating.

The profile or configuration is exported as a JSON file, therefore this easily allows you to store this as a source control tool such as GitHub to enable you to track and review changes to the configuration. This can be really useful when it comes to larger teams with many updates happening.

The export and import process is all done via API’s. More on that later, first lets take a look at this in the form of a high level diagram!

API’s

As mentioned earlier, vCenter Server Profiles are currently managed via API’s, not the GUI. They can be found in the Developer Center within vCenter itself as you can see below:

There are 5 API’s in total I am going to be working with as part of this blog:

  • Acquiring a SessionID token – Required to authenticate.
  • Getting a list of profiles.
  • Exporting a profile.
  • Validating a profile.
  • Importing a profile.

I will be using PowerShell to make the API calls, lets take a look at the code to do each step as well as the output.

Acquiring a SessionID Token

There are a few variable values you will need to fill out here; Username, Password and the FQDN of the source vCenter Server.

#Authentication
$User = "administrator@vsphere.local"
$Pass = "SecurePassword!"
$Auth = $User + ":" + $Pass
$Encoded = [System.Text.Encoding]::UTF8.GetBytes($Auth)
$EncodedAuth = [System.Convert]::ToBase64String($Encoded)
$Headers = @{"Authorization" = "Basic $($EncodedAuth)" }
$sourcevcenter = "vm-vcsa-01.smt.com"
#Get Session ID
$Session = Invoke-RestMethod -Method POST -Uri "https://$($sourcevcenter)/rest/com/vmware/cis/session" -Headers $Headers
$SessionID = $Session.Value
$SessionID

Now when you run this, a value is outputted. This is what we will use to authenticate the other API calls.

d84b95e370f1ed68b997f4affbe6feba

Listing Profiles

Now lets look at listing the available profiles. You will notice the output may remind you of the diagram above.

$SessionHeaders = @{'vmware-api-session-id' = "$($SessionID)"
}
Invoke-RestMethod -Method GET -Uri "https://$($sourcevcenter)/api/appliance/infraprofile/configs" -Headers $SessionHeaders

Note the SessionID variable being used here. This is the value from the previous step.

name                info
----                ----
ApplianceManagement Appliance Mangment Service
ApplianceNetwork    Appliance Network Configuration
AuthManagement      Authentication & Authorization Management

Exporting a Profile

Now to export the profile. As mentioned earlier, the configuration is outputted to a JSON file to a path of your choosing.

$SessionHeaders = @{
    "vmware-api-session-id" = "$($SessionID)"
    "Content-type"          = "application/json"
}
$Export = Invoke-RestMethod -Method POST -Uri "https://$($sourcevcenter)/api/appliance/infraprofile/configs?action=export" -Headers $SessionHeaders
$Export | Out-File "C:\temp\vcenter-profile-export.json"

Here is a trimmed look at the content of the file:

{"action":"RESTART_SERVICE","productName":"VMware vCenter Server","creationTime":"2021-12-30T18:12:42+0000","version":"7.0.3.00100","profiles":{"ApplianceNetwork":{"description":"Appliance Network Configuration","action":"RESTART_SERVICE","actionOn":{"VC_SERVICES":["applmgmt"],"SYSTEMD":["systemd-networkd","systemd-resolved"]},"version":"7.0","config":{"/etc/sysconfig/proxy":{"HTTPS PROXY":"\"\"","SOCKS PROXY":"\"\"","FTP PROXY":"\"\"","GOPHER PROXY":"\"\"","PROXY ENABLED":"\"no\"","SOCKS5 SERVER":"\"\"","HTTP PROXY":"\"\"","NO PROXY":["\"localhost","127.0.0.1\""]},"/etc/systemd/resolved.conf":{"Fallback DNS":null,"LLMNR is enabled":"false","DNS":"127.0.0.1 10.200.15.1"}},"name":"ApplianceNetwork"},"AuthManagement":{"description":"Authentication & Authorization Management","action":"NO_ACTION","version":"1.0","config":{"Lockout Policy":{"Maximum number of failed login attempts":5,"Time interval between failures":180,"Unlock time":300},"Password Policy":{"Minimum special characters":1,"Minimum alphabetic characters":2,"Minimum uppercase characters":1,"Minimum lowercase characters":1,"Minimum numeric characters":1,"Minimum adjacent identical characters":3,"Previous password reuse restriction":5,"Maximum lifetime":90,"Maximum length":20,"Minimum length":8},"Token Policy":{"Clock tolerance ms":600000,"Maximum token renewal count":10,"Maximum token delegation count":10,"Maximum Bearer RefreshToken lifetime":21600000,"Maximum HoK RefreshToken lifetime":2592000000}
...
Trimmed to save the scrolling...
...
{"principal":{"name":"VSPHERE.LOCAL\\NsxAuditors","group":true},"roles":[741131114],"propagate":true},{"principal":{"name":"VSPHERE.LOCAL\\NsxViAdministrators","group":true},"roles":[-2094871953],"propagate":true},{"principal":{"name":"VSPHERE.LOCAL\\NsxAdministrators","group":true},"roles":[-1723127349],"propagate":true},{"principal":{"name":"VSPHERE.LOCAL\\RegistryAdministrators","group":true},"roles":[1006],"propagate":true},{"principal":{"name":"SMT.COM\\stephan","group":false},"roles":[-1],"propagate":true},{"principal":{"name":"VSPHERE.LOCAL\\vStatsGroup","group":true},"roles":[-292639496],"propagate":true}]},"name":"AuthManagement"},"ApplianceManagement":{"description":"Appliance Mangment Service","action":"RESTART_SERVICE","actionOn":{"VC_SERVICES":["applmgmt"],"SYSTEMD":["sendmail","rsyslog"]},"version":"7.0","config":{"/etc/applmgmt/appliance/appliance.conf":{"Is shell Enabled":false,"Shell Expiration Time":null,"TimeSync Mode (Host/NTP)":"NTP"},"/etc/sysconfig/clock":{"Time zone":"\"Europe/London\"","UTC":"1"},"/usr/bin/systemctl/sshd.service":{"Enable SSH":"true"},"/etc/ntp.conf":{"Time servers":["uk.pool.ntp.org"]},"/etc/mail/sendmail.cf":{"SMTP Port":null,"Mail server":null},"/etc/vmware-syslog/syslog.conf":{"Port [2]":null,"Port [1]":null,"Port [0]":null,"Protocol [2]":null,"Remote Syslog Host [1]":null,"Protocol [1]":null,"Remote Syslog Host [0]":null,"Protocol [0]":null,"Remote Syslog Host [2]":null},"/etc/pam.d/system-auth":{"Deny Login after these many Unsuccessful Attempts.":"3","Unlock root after (seconds)":"300","On Error Login will be.":"fail","Include Root user for SSH lockout.":true,"Unlock user after (seconds)":"900"},"/etc/shadow":{"root":{"maximumDays":"","warningDays":"7"},"bin":{"maximumDays":"90","warningDays":"7"},"daemon":{"maximumDays":"90","warningDays":"7"},"messagebus":{"maximumDays":"90","warningDays":"7"},"systemd-bus-proxy":{"maximumDays":"90","warningDays":"7"},"systemd-journal-gateway":{"maximumDays":"90","warningDays":"7"},"systemd-journal-remote":{"maximumDays":"90","warningDays":"7"},"systemd-journal-upload":{"maximumDays":"90","warningDays":"7"},"systemd-network":{"maximumDays":"90","warningDays":"7"},"systemd-resolve":{"maximumDays":"90","warningDays":"7"},"systemd-timesync":{"maximumDays":"90","warningDays":"7"},"nobody":{"maximumDays":"90","warningDays":"7"},"rpc":{"maximumDays":"90","warningDays":"7"},"ntp":{"maximumDays":"90","warningDays":"7"},"sshd":{"maximumDays":"90","warningDays":"7"},"smmsp":{"maximumDays":"90","warningDays":"7"},"apache":{"maximumDays":"90","warningDays":"7"},"sso-user":{"maximumDays":"90","warningDays":"7"},"vpostgres":{"maximumDays":"","warningDays":"7"},"vapiEndpoint":{"maximumDays":"90","warningDays":"7"},"eam":{"maximumDays":"90","warningDays":"7"},"vlcm":{"maximumDays":"90","warningDays":"7"},"vsan-health":{"maximumDays":"90","warningDays":"7"},"vsm":{"maximumDays":"90","warningDays":"7"},"vsphere-ui":{"maximumDays":"90","warningDays":"7"},"wcp":{"maximumDays":"","warningDays":"7"},"content-library":{"maximumDays":"90","warningDays":"7"},"imagebuilder":{"maximumDays":"90","warningDays":"7"},"perfcharts":{"maximumDays":"90","warningDays":"7"},"vpgmonusr":{"maximumDays":"","warningDays":"7"},"vtsdbmonusr":{"maximumDays":"","warningDays":"7"},"Send Waring before this No of Days.":null,"Password validity (days)":null}},"name":"ApplianceManagement"}}}

At this point you can modify this file as needed. For example, you may need to modify the DNS configuration for a group of vCenter Servers to use a different one than that of the source vCenter, or you may want to remove all but the Appliance configuration.

Validating a Profile

Next we are looking at validating the profile against the target/remote vCenter that you want to apply it to. Be sure to get a session ID for the target vCenter Server to pass into this command!

$destinationvcenter = "vm-vcsa-02.smt.com"
$SessionHeaders = @{
    "vmware-api-session-id" = "$($SessionID)"
    "Content-type"          = "application/json"
}
$body = Convertto-json @{
    'config_spec' = Get-Content "C:\temp\vcenter-profile-export.json"
}
$validate = Invoke-RestMethod -Method POST -Uri "https://$($destinationvcenter)/api/appliance/infraprofile/configs?action=validate&vmw-task=true" -Headers $SessionHeaders -Body $body
$validate

The below output confirms the file is good to go.

912f7205-2e8f-429f-8b86-9610e5eac8f4:com.vmware.appliance.infraprofile.configs

Importing a Profile

Now to the good bit, importing the config! Like before, make sure to get a session ID for the target vCenter Server to pass into this command!

$destinationvcenter = "vm-vcsa-02.smt.com"
$SessionHeaders = @{
    "vmware-api-session-id" = "$($SessionID)"
    "Content-type"          = "application/json"
}
$body = @{
    'config_spec' = Get-Content "C:\temp\vcenter-profile-export.json"
}
$Import = Invoke-RestMethod -Method POST -Uri "https://$($destinationvcenter)/api/appliance/infraprofile/configs?action=import&vmw-task=true" -Headers $SessionHeaders -Body (Convertto-json $body)
$Import

Before:

Output from running the import commands:

d843c731-c631-4b9b-87fe-4894134f433c:com.vmware.appliance.infraprofile.configs

After:

PowerShell Functions

Now to make this a bit easier (and to practice my PowerShell Function skills), I have made 5 PowerShell Functions that can be used. The code for each can be found here.

Get-vCenterAPISessionID

Get-vCenterAPISessionID -vCenterFQDN vm-vcsa-02.smt.com -UserName administrator@vsphere.local -Password SecurePassword!
9ee52fe13c7ae8d42f777cadccf6b70d

Get-vCenterProfiles

Get-vCenterProfiles -vCenterFQDN vm-vcsa-01.smt.com -SessionID 9ee52fe13c7ae8d42f777cadccf6b70d
name                info
----                ----
ApplianceManagement ApplianceManagement
ApplianceNetwork    ApplianceNetwork
AuthManagement      Authentication & Authorization Management

Export-vCenterProfiles

Export-vCenterProfiles -vCenterFQDN vm-vcsa-02.smt.com -SessionID 9ee52fe13c7ae8d42f777cadccf6b70d -ExportPath C:\temp

Validate-vCenterProfiles

Validate-vCenterProfiles -vCenterFQDN vm-vcsa-03.smt.com -SessionID 2b3fdd91604f67d124af041a23b46a1a -jsonPath C:\temp
21bfd471-95e3-48d3-841d-8452f2a09527:com.vmware.appliance.infraprofile.configs

Import-vCenterProfiles

Import-vCenterProfiles -vCenterFQDN vm-vcsa-03.smt.com -SessionID 2b3fdd91604f67d124af041a23b46a1a -jsonPath C:\temp
4a742b45-c52e-4aa9-a67b-fe588084f02c:com.vmware.appliance.infraprofile.configs

Log File location on the vCenter Server: /var/log/vmware/infraprofile/infraprofile-svcs.log. This is were you need to be looking when troubleshooting!

Here’s a snippet:

2022-01-01T14:31:30.911Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.core.ProfileOperations  opId=] Complete importProfile ApplianceManagement
2022-01-01T14:31:31.072Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Start importing non generic format file /usr/bin/systemctl/sshd.service
2022-01-01T14:31:31.074Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.util.MiscUtils  opId=] Performing unmask operation on following System services: [[sshd.service]]
2022-01-01T14:31:31.439Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.util.MiscUtils  opId=] Performing enable operation on following System services: [[sshd.service]]
2022-01-01T14:31:31.864Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.util.MiscUtils  opId=] Performing start operation on following System services: [[sshd.service]]
2022-01-01T14:31:31.877Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Complete importing non generic format file /usr/bin/systemctl/sshd.service
2022-01-01T14:31:31.877Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Start importing non generic format file /etc/ntp.conf
2022-01-01T14:31:31.878Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Complete importing non generic format file /etc/ntp.conf
2022-01-01T14:31:31.878Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Start importing non generic format file /etc/mail/sendmail.cf
2022-01-01T14:31:31.882Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Complete importing non generic format file /etc/mail/sendmail.cf
2022-01-01T14:31:31.882Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Start importing non generic format file /etc/vmware-syslog/syslog.conf
2022-01-01T14:31:32.963Z [Thread-45 [] INFO  com.vmware.appliance.infraprofilev1.plugins.ApplianceManagementPlugin  opId=] Complete importing non generic format file /etc/vmware-syslog/syslog.conf

Thanks for reading!

Auto Connecting Devices to a VMware Workstation VM

As part of my latest homelab setup, I run my vCenter Server VM and Domain Controller VM on VMware Workstation Pro 16 and not on an ESXi host. This is mainly so I don’t have to fire up a noisy rack mount server when I only need my vCenter Server for something.

This did leave me with the problem of a lack of physical ports in my Windows PC to be able to bridge my VM’s with, so out came the trusty USB Ethernet adapter!

By default, this USB device is connected to the host machine. As I would always forget to connect this to my domain controller VM(which is the VM I bridged with this interface), I would end up having to reboot it once I had connected it as I would get all sorts of problems, including DNS issues.

To address this, there is a line that can be added to the vmx file of the VM to auto connect a specific device to a VM. It took me a while to find the information that was pertinent to specifically version 16 of VMware Workstation so I thought I would write a quick article on it.

Firstly, you need to grab the VID and PID values from the registry by looking through the devices in the following path, or searching if you have an idea on what its friendly name is:

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB

Once you have these values, open up the VMX file of the VM you want to auto connect the device to in a text editor, making sure the VM is in a powered off state first.

Add the following line to the file, replacing the VID and PID values with the ones you located in the registry earlier.

usb_xhci.autoconnect.device0 = "vid:0bda pid:8152"

Now, power on the VM and you will see the device is automatically connected to the VM and not the Host!

I hope this has been useful. I aim to get some more blog posts up on my lab setup this year, so keep an eye out if you are looking for idea’s for your own home lab.

Thanks for reading!

Failed to Deploy OVF Package – vSphere Content Libraries

I recently came across an issue with creating subscribed VMware Content Libraries, and deploying templates from a Content Library.

An error similar to the one below, would be received when attempting to deploy a VM template or OVF from a Content Library, or an error related to connection issues when setting up a subscribed Content Library.

Failed to deploy OVF Package.  ThrowablePrxy.cause A general system error occurred: Transfer failed.

After some investigation, I came to see that vCenter was attempting to communicate with linked vCenter’s and hosts via the web proxy that was configured in the VAMI, when attempting to deploy an OVF from a Content Library or when trying to synchronise a library.

As I didn’t want this traffic going via the proxy as it is internal traffic, a support ticket was logged. It was advised to add proxy exceptions, or bypasses, to the proxy file located here on a vCenter Server Appliance:

/etc/sysconfig/proxy

As this information isn’t something I managed to find documented publicly and support couldn’t provide me with anything as they were using internal documentation to assist, I thought I would write a quick post on it to help anyone facing the same issue!

Note: Always test in a non production environment and contact official support channels!

To begin reviewing and editing this file, you will need to SSH to the VCSA using the below command using your SSH tooling of choice.

ssh root@vm-vcsa-01.smt-lab.local

Using the following cat command you can then view the file:

cat /etc/sysconfig/proxy

Here is what the default file looks like with the HTTP and HTTPS options set:

# Enable a generation of the proxy settings to the profile.
# This setting allows to turn the proxy on and off while
# preserving the particular proxy setup.
#
PROXY_ENABLED="no"

# Some programs (e.g. wget) support proxies, if set in
# the environment.
# Example: HTTP_PROXY="http://proxy.provider.de:3128/"
HTTP_PROXY="proxy.smt-lab.local"

# Example: HTTPS_PROXY="https://proxy.provider.de:3128/"
HTTPS_PROXY="proxy.smt-lab.local"

# Example: FTP_PROXY="http://proxy.provider.de:3128/"
FTP_PROXY=""

# Example: GOPHER_PROXY="http://proxy.provider.de:3128/"
GOPHER_PROXY=""

# Example: SOCKS_PROXY="socks://proxy.example.com:8080"
SOCKS_PROXY=""

# Example: SOCKS5_SERVER="office-proxy.example.com:8881"
SOCKS5_SERVER=""

# Example: NO_PROXY="www.me.de, do.main, localhost"
NO_PROXY="localhost, 127.0.0.1"

Take note of the section at the bottom, “NO_PROXY”. This is where we need to add the fqdn’s of any hosts and VCSA’s you wish to deploy to, or subscribe with. If however you don’t want to maintain this for each and every host, you can add a wild card:

.*.domain.name

Note the ‘.’ at the beginning!

For instance, in my lab I would add the following entry to the NO_PROXY list:

.*.smt-lab.local

To edit this we can use the VI editor (More info on using VI here.):

vi /etc/sysconfig/proxy

Edit the file to include the FQDN’s or a wildcard, based on your requirements.

# Example: NO_PROXY="www.me.de, do.main, localhost"
NO_PROXY="localhost, 127.0.0.1, .*.smt-lab.local"

I found a short period of time is needed for this to take effect. Or you can reboot the VCSA to speed things along.

Following this, you will then be able to deploy or subscribe without issue!

Hope this has been useful and thanks for reading!

Different Tools; Same Result – vSphere Distributed Port Groups

As technology moves forward, more and more ways to achieve your goal become available. Many people still rely on the good old trusty GUI to achieve their goal, I know I do at times. Is this because it’s quicker, more comfortable or familiar? Or perhaps because they don’t realise there are other options out there!?

This blog post will be one of many, where I highlight some of the options available for completing various technical tasks or configurations, in the hope it can provide additional options or tools for consideration.

To kick off, let’s take a look at a common example for a vSphere Administrator, creating Port Groups on a Distributed Switch.

vSphere Client

So let’s first look at the process via the GUI, in this case, the vSphere Client. I wont go into too much detail on the steps involved, as it is a well documented process, but the screenshots are below:

Repeat for the remaining Port Groups and you will be left with the finished article.

And there we have it, three Port Groups on a distributed Switch. Now, imagine doing this for 10’s or 100’s of Port Groups? It’s going to be slow and painful, so let’s look at some other options.

PowerShell

Firstly, PowerShell, specifically the VMware PowerCLI PowerShell module. Here is an example script that will create the same three Port Groups that we did using the GUI:

$vDSName = "vDS-Workload-Networks"
$Ports = "8"
$LoadBalancing = "LoadBalanceLoadBased" 
$ActiveUP = "Uplink 1", "Uplink 2"

$vdpgs = @(
    [pscustomobject]@{PG = 'dvPG-Guest-VM-1'; VLANID = '20'}
    [pscustomobject]@{PG = 'dvPG-Guest-VM-2'; VLANID = '21'}
    [pscustomobject]@{PG = 'dvPG-Secure-VM-1'; VLANID = '25'}
)

#Create Distributed Virtual Port Group.
ForEach ($vdpg in $vdpgs) {
    Get-VDSwitch -Name $vDSName | New-VDPortGroup -Name $VDPG.PG -VLanId $VDPG.VLANID -NumPorts $Ports
    #Set Load Balancing option
    Get-VDswitch -Name $vDSName | Get-VDPortgroup $VDPG.PG | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy $LoadBalancing -ActiveUplinkPort $ActiveUP
}

So lets break down this code. Firstly we are defining some variables;

  • $vDSName – This is the name of an existing virtual distributed switch in which you will be creating your Port Groups.
  • $Ports – This defines the number of ports the Port Group will be initially configured with. (By default 128 ports are created, there is nothing wrong with using the default, see the note further down as to why I have specified 8.)
  • $LoadBalancing – This is the load balancing policy I wish to set for the Port Group. Available options are:LoadBalanceLoadBased, LoadBalanceIP, LoadBalanceSrcMac, LoadBalanceSrcId, ExplicitFailover. This can be adjusted as required.
  • $ActiveUP – This variable defines the uplinks you wish to set as active for the Port Group. (If you want to add standby uplinks, you could add this parameter in too)
  • $VDPGS – Finally, this is an array containing both the name and VLAN ID for each Port Group.

Now we have our input information in variables, we move onto the next two lines of code. These are within a ‘ForEach Loop’. This will take each entry within an array and run a block of code against it. In this case, each Port Group we wish to create.

So for each entry in the array, ‘Get-VDswitch -Name $vDSName‘ gets the existing Virtual Distributed Switch based on the variable and then pipes (‘|’) this into the command (New-VDPortGroup -Name $VDPG.PG -VLanId $VDPG.VLANID -NumPorts $Ports) to create the Port Group on the Distributed Switch, using the properties set for each line of the array.

Secondly, we get the Port Group we just created (Get-VDswitch -Name $vDSName | Get-VDPortgroup $VDPG.PG) and then ‘Get & Set’ the Teaming and Loadbalancing options (Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -LoadBalancingPolicy $LoadBalancing -ActiveUplinkPort $ActiveUP), again ‘piping’ the results into the next command.

Below is the output from PowerShell after running the script above:

Name                           NumPorts PortBinding
----                           -------- -----------
dvPG-Guest-VM-1                8        Static

VDPortgroup                      : dvPG-Guest-VM-1
NotifySwitches                   : True
NotifySwitchesInherited          : True
LoadBalancingPolicy              : LoadBalanceLoadBased
LoadBalancingPolicyInherited     : False
FailoverDetectionPolicy          : LinkStatus
ActiveUplinkPort                 : {Uplink 1, Uplink 2}
StandbyUplinkPort                : {}
UplinkPortOrderInherited         : False
Failback                         : False
EnableFailback                   : True
FailbackInherited                : True
UnusedUplinkPort                 : {}
FailoverDetectionPolicyInherited : True
Uid                              : /VIServer=vsphere.local\administrator@vm-vcsa-01.smt-lab.local:443/VDPortgroupUplinkTeamingPolicy=cec49f0b7f124d0c9f37814392494a31/

dvPG-Guest-VM-2                8        Static

VDPortgroup                      : dvPG-Guest-VM-2
NotifySwitches                   : True
NotifySwitchesInherited          : True
LoadBalancingPolicy              : LoadBalanceLoadBased
LoadBalancingPolicyInherited     : False
FailoverDetectionPolicy          : LinkStatus
ActiveUplinkPort                 : {Uplink 1, Uplink 2}
StandbyUplinkPort                : {}
UplinkPortOrderInherited         : False
Failback                         : False
EnableFailback                   : True
FailbackInherited                : True
UnusedUplinkPort                 : {}
FailoverDetectionPolicyInherited : True
Uid                              : /VIServer=vsphere.local\administrator@vm-vcsa-01.smt-lab.local:443/VDPortgroupUplinkTeamingPolicy=e126093ed67f45a3b7c42874c5affc20/

dvPG-Secure-VM-1               8        Static

VDPortgroup                      : dvPG-Secure-VM-1
NotifySwitches                   : True
NotifySwitchesInherited          : True
LoadBalancingPolicy              : LoadBalanceLoadBased
LoadBalancingPolicyInherited     : False
FailoverDetectionPolicy          : LinkStatus
ActiveUplinkPort                 : {Uplink 1, Uplink 2}
StandbyUplinkPort                : {}
UplinkPortOrderInherited         : False
Failback                         : False
EnableFailback                   : True
FailbackInherited                : True
UnusedUplinkPort                 : {}
FailoverDetectionPolicyInherited : True
Uid                              : /VIServer=vsphere.local\administrator@vm-vcsa-01.smt-lab.local:443/VDPortgroupUplinkTeamingPolicy=b5f1889461584b1daf314379cd935f50/

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:

provider "vsphere" {
  vsphere_server = "vCenter Server FQDN"
  user           = "Domain\\Username"
  password       = "Password"
}
data "vsphere_datacenter" "datacenter" {
  name = "dc-smt-01"
}
data "vsphere_distributed_virtual_switch" "vds" {
  name          = "vDS-Workload-Networks"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}
resource "vsphere_distributed_port_group" "pg20" {
  name                            = "dvPG-Guest-VM-1"
  distributed_virtual_switch_uuid = data.vsphere_distributed_virtual_switch.vds.id
  number_of_ports                 = 8
  vlan_id                         = 20
}
resource "vsphere_distributed_port_group" "pg21" {
  name                            = "dvPG-Guest-VM-2"
  distributed_virtual_switch_uuid = data.vsphere_distributed_virtual_switch.vds.id
  number_of_ports                 = 8
  vlan_id                         = 21
}
resource "vsphere_distributed_port_group" "pg25" {
  name                            = "dvPG-Secure-VM-1"
  distributed_virtual_switch_uuid = data.vsphere_distributed_virtual_switch.vds.id
  number_of_ports                 = 8
  vlan_id                         = 25
}

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 Terraform to connect to your vCenter instance; VCSA FQDN and credentials.

We then have two ‘data’ blocks. These are used to get information about an existing resource, such as the Distributed Switch and the Datacenter it resides in. You could loosely consider this similar to populating variables in the PowerShell example.

Next we have three ‘resource’ blocks. Each block represents one of the three Port Groups we want to configure. It provides parameters for Name, number of ports and vlan ID for each, along with a reference to the Distributed Switch from the ‘data’ block.

Now when you run ‘terraform apply’ to apply for code, here is the output:

terraform apply  


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # vsphere_distributed_port_group.pg20 will be created
  + resource "vsphere_distributed_port_group" "pg20" {
      + active_uplinks                    = (known after apply)
      + allow_forged_transmits            = (known after apply)
      + allow_mac_changes                 = (known after apply)
      + allow_promiscuous                 = (known after apply)
      + auto_expand                       = true
      + block_all_ports                   = (known after apply)
      + check_beacon                      = (known after apply)
      + config_version                    = (known after apply)
      + directpath_gen2_allowed           = (known after apply)
      + distributed_virtual_switch_uuid   = "50 33 5e 01 05 1e 32 66-ea f7 7c 42 ce fa f1 96"
      + egress_shaping_average_bandwidth  = (known after apply)
      + egress_shaping_burst_size         = (known after apply)
      + egress_shaping_enabled            = (known after apply)
      + egress_shaping_peak_bandwidth     = (known after apply)
      + failback                          = (known after apply)
      + id                                = (known after apply)
      + ingress_shaping_average_bandwidth = (known after apply)
      + ingress_shaping_burst_size        = (known after apply)
      + ingress_shaping_enabled           = (known after apply)
      + ingress_shaping_peak_bandwidth    = (known after apply)
      + key                               = (known after apply)
      + lacp_enabled                      = (known after apply)
      + lacp_mode                         = (known after apply)
      + name                              = "dvPG-Guest-VM-1"
      + netflow_enabled                   = (known after apply)
      + network_resource_pool_key         = "-1"
      + notify_switches                   = (known after apply)
      + number_of_ports                   = 8
      + port_private_secondary_vlan_id    = (known after apply)
      + standby_uplinks                   = (known after apply)
      + teaming_policy                    = (known after apply)
      + tx_uplink                         = (known after apply)
      + type                              = "earlyBinding"
      + vlan_id                           = 20

      + vlan_range {
          + max_vlan = (known after apply)
          + min_vlan = (known after apply)
        }
    }

  # vsphere_distributed_port_group.pg21 will be created
  + resource "vsphere_distributed_port_group" "pg21" {
      + active_uplinks                    = (known after apply)
      + allow_forged_transmits            = (known after apply)
      + allow_mac_changes                 = (known after apply)
      + allow_promiscuous                 = (known after apply)
      + auto_expand                       = true
      + block_all_ports                   = (known after apply)
      + check_beacon                      = (known after apply)
      + config_version                    = (known after apply)
      + directpath_gen2_allowed           = (known after apply)
      + distributed_virtual_switch_uuid   = "50 33 5e 01 05 1e 32 66-ea f7 7c 42 ce fa f1 96"
      + egress_shaping_average_bandwidth  = (known after apply)
      + egress_shaping_burst_size         = (known after apply)
      + egress_shaping_enabled            = (known after apply)
      + egress_shaping_peak_bandwidth     = (known after apply)
      + failback                          = (known after apply)
      + id                                = (known after apply)
      + ingress_shaping_average_bandwidth = (known after apply)
      + ingress_shaping_burst_size        = (known after apply)
      + ingress_shaping_enabled           = (known after apply)
      + ingress_shaping_peak_bandwidth    = (known after apply)
      + key                               = (known after apply)
      + lacp_enabled                      = (known after apply)
      + lacp_mode                         = (known after apply)
      + name                              = "dvPG-Guest-VM-2"
      + netflow_enabled                   = (known after apply)
      + network_resource_pool_key         = "-1"
      + notify_switches                   = (known after apply)
      + number_of_ports                   = 8
      + port_private_secondary_vlan_id    = (known after apply)
      + standby_uplinks                   = (known after apply)
      + teaming_policy                    = (known after apply)
      + tx_uplink                         = (known after apply)
      + type                              = "earlyBinding"
      + vlan_id                           = 21

      + vlan_range {
          + max_vlan = (known after apply)
          + min_vlan = (known after apply)
        }
    }

  # vsphere_distributed_port_group.pg25 will be created
  + resource "vsphere_distributed_port_group" "pg25" {
      + active_uplinks                    = (known after apply)
      + allow_forged_transmits            = (known after apply)
      + allow_mac_changes                 = (known after apply)
      + allow_promiscuous                 = (known after apply)
      + auto_expand                       = true
      + block_all_ports                   = (known after apply)
      + check_beacon                      = (known after apply)
      + config_version                    = (known after apply)
      + directpath_gen2_allowed           = (known after apply)
      + distributed_virtual_switch_uuid   = "50 33 5e 01 05 1e 32 66-ea f7 7c 42 ce fa f1 96"
      + egress_shaping_average_bandwidth  = (known after apply)
      + egress_shaping_burst_size         = (known after apply)
      + egress_shaping_enabled            = (known after apply)
      + egress_shaping_peak_bandwidth     = (known after apply)
      + failback                          = (known after apply)
      + id                                = (known after apply)
      + ingress_shaping_average_bandwidth = (known after apply)
      + ingress_shaping_burst_size        = (known after apply)
      + ingress_shaping_enabled           = (known after apply)
      + ingress_shaping_peak_bandwidth    = (known after apply)
      + key                               = (known after apply)
      + lacp_enabled                      = (known after apply)
      + lacp_mode                         = (known after apply)
      + name                              = "dvPG-Secure-VM-1"
      + netflow_enabled                   = (known after apply)
      + network_resource_pool_key         = "-1"
      + notify_switches                   = (known after apply)
      + number_of_ports                   = 8
      + port_private_secondary_vlan_id    = (known after apply)
      + standby_uplinks                   = (known after apply)
      + teaming_policy                    = (known after apply)
      + tx_uplink                         = (known after apply)
      + type                              = "earlyBinding"
      + vlan_id                           = 25

      + vlan_range {
          + max_vlan = (known after apply)
          + min_vlan = (known after apply)
        }
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

vsphere_distributed_port_group.pg20: Creating...
vsphere_distributed_port_group.pg21: Creating...
vsphere_distributed_port_group.pg25: Creating...
vsphere_distributed_port_group.pg25: Creation complete after 0s [id=dvportgroup-2669728]
vsphere_distributed_port_group.pg21: Creation complete after 0s [id=dvportgroup-2669730]
vsphere_distributed_port_group.pg20: Creation complete after 0s [id=dvportgroup-2669729]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

For more information on the vSphere provider from Terraform, check out this link.

You will have noticed that I have explicitly defined the number of ports in both the PowerShell and Terraform examples. This is purely to match up with the default value that is set when using the vSphere Client; 8. By default the port allocation automatically expands as required, so this is for consistency rather than anything else.

If you are someone who relies heavily on a GUI as part of your work, I hope this have given you some idea’s on how you can perhaps leverage other options, especially when looking to build or configure in bulk.

Thanks for reading!

NSX-T Manager Certificate Replacement

I decided it was time to add VMware NSX-T to my HomeLab. I had been putting it off for a while but I couldn’t avoid it any longer!

Once I had fired up my NSX Manager Nodes and Cluster (I am using version 3.1), I looked to installing certificates. I choose to use a single certificate for all 3 of the NSX managers and the cluster using Subject Alternative Names (SAN’s) to simplify the process and this means I don’t need to renew 4 certificates each time.

As this is a different process to other VMware products I have put together a quick run through on how to achieve this.

Firstly, we need to generate the CSR from one of the NSX Manager nodes using openssl. SSH to one of your nodes and run the following command to create a new file called ‘ssl.conf’:

vim ssl.conf

Then populate this file with the below text, changing the values to suit your environment. I have left my values in to help with reading the file. If you are using a single NSX manager in your lab, you can remove the lines for DNS.3, DNS.4, IP.3 and IP.4.

[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[ req_distinguished_name ]
countryName = GB
stateOrProvinceName = Labshire
localityName = Lab City
organizationName = SMT-Lab
organizationalUnitName = SMT-Lab
commonName = vm-nsx-00.smt-lab.local

[ req_ext ]
subjectAltName = @alt_names

[alt_names]
DNS.1 = vm-nsx-00.smt-lab.local
DNS.2 = vm-nsx-01.smt-lab.local
DNS.3 = vm-nsx-02.smt-lab.local
DNS.4 = vm-nsx-03.smt-lab.local
IP.1 = 10.200.15.34
IP.2 = 10.200.15.35
IP.3 = 10.200.15.36
IP.4 = 10.200.15.37

Now to generate the CSR, run the following, but replacing the files names to suit:

openssl req -out vm-nsx-00.smt-lab.local.csr -newkey rsa:2048 -nodes -keyout vm-nsx-00.smt-lab.local.key -config ssl.conf -sha256

This will generate 2 files in the current working directory. You will have your CSR and the private key. Using something like WinSCP, copy the files off the NSX manager to a location of your choice.

Head off to your CA and issue the certificate using the CSR.

Now you need to copy the root and issuing (if you have an issuing CA) certificate to certificate you just created. This will complete the chain. Also have the private key handy as you are going to need it.

We are now ready to import import the certificate. Head to System > Certificates > Import and select Import Certificate.

Give it a name, browse to the certificate file that now includes the certificate chain, followed by browsing the the private key file. Be sure to change the ‘Service Certificate’ slider to ‘No’ and then click Import.

Once imported you can select it and see that it includes the certificates in the chain.

Now to assign them! Firstly, click on the identifier next to the name and copy the value. This is what will be used to target the certificate in the next steps.

To validate and replace the certificates in NSX we need to use API’s. Using a tool like Postman, validate then replace the certificate on the NSX Manager Cluster by running the following as a GET request. Note you need to provide credentials for the NSX managers on the Authorization tab.

https://vm-nsx-00.smt-lab.local/api/v1/trust-management/certificates/82c80092-3571-40cd-8960-3189594ec0f1?action=validate 

The result of ‘”status” : “ok”‘ is what we are looking for here.

Now its confirmed valid, lets replace the certificate by running the following POST request:

https://vm-nsx-00.smt-lab.local/api/v1/cluster/api-certificate?action=set_cluster_certificate&certificate_id=82c80092-3571-40cd-8960-3189594ec0f1

Then its time to apply to all nodes by running each line below:

https://vm-nsx-01.smt-lab.local/api/v1/node/services/http?action=apply_certificate&certificate_id=a94b3600-696b-43bf-a2df-c1e8e2180c3a

https://vm-nsx-02.smt-lab.local/api/v1/node/services/http?action=apply_certificate&certificate_id=a94b3600-696b-43bf-a2df-c1e8e2180c3a

https://vm-nsx-03.smt-lab.local/api/v1/node/services/http?action=apply_certificate&certificate_id=a94b3600-696b-43bf-a2df-c1e8e2180c3a

And that completes the replacement. If you browse to either your cluster address or individual nodes, you will see your new certificate in place.

You can find the full VMWare documentation on this here.

Thanks for reading!

Sessions I’ll Be Attending at VMworld 2021

VMworld 2021 is right around the corner! This year we are again unable to attend in person due to COVID-19, however this still gives everyone the chance to attend as its an online event!

It is running from the 5th to the 7th October this year –

Like many, I have been marking various sessions as favourites in the catalog ready for when they can be booked. Here are a few that are on my list this year.

Firstly, Frank’s session on NUMA has been on my list for all 3 years I have been attending. For anyone who uses vSphere, this is a must.

60 Minutes of Non-Uniform Memory Access (NUMA) 3rd Edition [MCL1853]

Pass Type: General and Tech+ Passes
Session by: Frank Denneman
Description:

“Although we enrich the stack with multiple layers of abstraction, obtaining consistent performance boils down to understanding the fundamentals. This requires the admin and the architect to focus on individual host components again. In this session, we dive into the impact the Multi-chip Module (MCM) has on scheduler behavior and workload sizing. Learn the underlying configuration of a virtual machine and discover the connection between the General-Purpose Graphics Processing Unit (GPGPU) and the NUMA node. Determine how the cores-per-socket impact a virtual NUMA configuration. We will look at the impact of heterogeneous clusters on workload performance and how you can detect faux-wide virtual machine configurations. You will understand how your knowledge of NUMA concepts in your cluster can help the developer by aligning the Kubernetes nodes to the physical infrastructure with the help of VM Service.”


The next two are sessions are focused on performance. I’m personally always looking for ways to improve performance via configuration and tuning, but also ways to identify performance issues.

Extreme Performance Series: vSphere Advanced Performance Boot Camp [MCL2033]

Pass Type: Tech+ Pass Only
Session by: Mark Achtemichuk & Valentin Bondzio
Description:

“The VMware vSphere Advanced Performance Boot Camp provides the most advanced technical performance-oriented training available about vSphere performance design, tuning and troubleshooting. Hosted by VMware Certified Design Expert Mark Achtemichuk, we will cover a broad range of topics on all resource dimensions, including the VMware ESXi scheduler, memory management, storage and network optimization. The student will become empowered to identify the location of performance issues, diagnose their root cause, and remediate a wide variety of performance conundrums using the many techniques practiced by the most seasoned vSphere veterans and VMware internal experts. Armed with the knowledge provided in the class will allow you to confidently approach virtual performance and manage it successfully.”

Not got the Tech+ Pass? Here is an alternative session available on the General Pass – Extreme Performance Series: Performance Best Practices [MCL1635].

Deep Dive: VM Performance and Best Practices [VI2158]

Pass Type: Tech+ Pass Only
Session by: Jimmy Arias
Description:

“This session will provide a very detailed and technical explanation of the utilization of resources by VM, how to evaluate the performance indicators using ESXtop, and how to better architect and create solutions for performance issues.”


Having watched a couple of sessions this year by David Klee on performance tuning SQL on vSphere, this session was one of the first on my favourite list. Having supported SQL in some fashion my entire career, I am always looking to learn how to get the best performance possible.

Meet the Experts: Virtualizing Microsoft SQL Server on vSphere – Stories from the Trenches [MCL1318]

Pass Type: Tech+ Pass Only
Session by: Deji Akomolafe & David Klee
Description:

“Virtualizing Microsoft SQL Server (the most virtualized mission-critical application) on VMware vSphere has become the standard for SQL Server deployments around the world. As vSphere continues to be the target platform for most SQL Server workloads and, with vSphere now being available in all major public cloud infrastructures, it is a given that you will virtualize your SQL Server workloads. The degree to which you will achieve bare-metal performance is up to how well you align SQL Server with the underlying infrastructure. This session (based on more than two decades of field experience) presents the common pitfalls you need to avoid and those you need to embrace as you run (or plan) your SQL Server instances on premises or in one of the various hybrid cloud options based on vSphere available from AWS, Microsoft, Google, and more.”


Another topic I have really enjoyed getting involved in this year has been Infrastructure as Code (IaC), Packer & Terraform specifically. So this year, I was for sure going to have this session on my list.

Automation Showdown: Imperative vs Declarative [CODE2786]

Pass Type: General and Tech+ Passes
Session by: Luc Dekens & Kyle Ruddy
Description:

“The automation landscape has always been a source of rapid innovation. Historically, the languages, whether it’s Perl, Python, vRealize Orchestrator JavaScript, or PowerCLI, may have changed, but the imperative, step-by-step workflows you’ve learned and know have not. However, a new challenger has appeared. Declarative workflows upended the usual processes and even the languages all in the name of infrastructure as code. Human readable, plain text files can be interpreted by products like HashiCorp Terraform and RedHat Ansible to do the heavy lifting of the imperative process. The key is knowing when, how, and where to use each method within your VMware environment. Join Luc and Kyle for this session where they will discuss these different styles of automation, complete with practical examples that you can use in your own environment!”

If like me you like to see things in action, Kyle also has a Live Coding session – Live Coding: Terraforming Your vSphere Environment [CODE2755].

Both of theses session are available on the General Pass so no excuses to miss out on them!


Finally, a session on Azure VMware Solution (AVS). As I am currently studying for my Microsoft AZ-104 exam, I wanted to start exploring and learning about this offering. Perhaps you are already using Azure or O365 and want to begin looking into the options for extending your vSphere solution to the cloud? If so, this session is definitely worth looking at!

Azure VMware Solution: Deployment Deep Dive [MCL2036]

Pass Type: Tech+ Pass Only
Session by: Jeremiah Megie & Steve Pantol
Description:

“In this session, we will discuss planning and deployment of Azure VMware Solution beyond the quick start. We will cover planning for network addressing, connectivity, integrating into an existing Azure hub and spoke or virtual WAN deployment, configuring monitoring and management, and establishing governance controls.”


If you haven’t already, head over to the VMworld website and register for the event! All content can be found in the Content Catalog, so get browsing!

As always, thanks for reading!

Enabling VM Rightsizing in vRealize Operations Manager (vROPS)

One of the many great features of vRealize Operations Manager (vROPS) is the ability to identify and address over or under sized virtual machines.

I was asked a short while ago why the option to resize a VM was unavailable or ‘greyed out’ as you can see below.

This feature is something that you need to a enable for a connection or ‘Cloud Account’. In this instance, this is my connection with vCenter.

You can check this by heading to Administration, Cloud Accounts and then select the three ‘dots’ next to the connection you want to check, or enable it for.

When reviewing the connection configuration you can see that the enable ‘Operational Actions’ is not selected.

Go ahead and select it.

Now if you head back to the rightsizing section, you will see that you have the option to resize the VM’s (for the connection or Cloud account you have enabled it for). One thing to note, the account you have used for the credentials on this connection require the appropriate privileges to modify the VM’s!

Once you click resize, you can then confirm the suggested resizing and continue.

Hope you found this useful. Once again thank you for reading!

« Older Entries