Removing Values in XML Using PowerShell

We’ve gathered values from our XML file and we’ve managed to add values to an XML file using PowerShell, but what about deleting? What I’m talking about is deleting XML tags and attributes, not deleting the value in an existing tag. Let’s look at our sample file and I’ll explain.

Above is our sample.xml file that was updated in the last post. Inside we have individual portgroups with a name and elements that we were added. In the context of the project I was working on, I needed the ability to delete a portgroup and all of its elements (VLAN, virtual switch, and cluster), but in some situations I needed to just delete the cluster. If a portgroup needed to be removed from one specific cluster, but remaining available to another cluster I couldn’t have the entire portgroup removed as it could affect virtual machines that are still running.

How do we do it? Let’s find out.

Just like before, let’s get the contents of our XML file so we can work with the data.

$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

The two things we need in order to remove a portgroup are the name of the portgroup and the name of the cluster. Based on the sample.xml file, we see that “VM Network” is on two clusters (cluster1 and NestedCluster) so let’s start there. Let’s get some simple variables setup just like we did last time.

$name = Read-Host -Prompt "Enter the name of the Portgroup (ex: Management Network)"
$cluster = Read-Host -Prompt "Enter the name of the cluster for this Portgroup (ex: Cluster1)"

I’ve created a new powershell file called “removePortgroup.ps1” and it has the above variables in there prompting me to enter the name and the cluster of the portgroup to be removed.

Now that we have the XML contents and our variables defined it’s time to see what data is there. If you recall from my earlier post about getting data from XML, we can see the contents of our file by following the hierarchy. With the following command we can see all portgroups that have been defined.

$xmlConfig.config.portgroups.ChildNodes

Now that we know what’s there, we need to filter the results and only display the Web Network. We’ll pass this as a variable so we can use that info later.

$clusters = $xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name}

Using the same command as before but passing it as a variable, we added a parameter to search for the name of our Portgroup (VM Network) using the $name variable we created earlier and we are trying to match it with another portgroup of the same name. When we run the command “$clusters” we see what portgroup came back as a match. We can see the VM Network portgroup that has 2 clusters.

With this portgroup living on two clusters we are only interested in removing it from one which is NestedCluster. We’ll work on the logic for this later one, for now let’s focus on how you remove a single from this portgroup.

The following commands will remove the element that matches our $name and $cluster variables we created earlier.

$text = "#text"
$clusterTag = $xmlConfig.config.portgroups.portgroup | Where {$_.name -eq $name}
$updateTag = $clusterTag.SelectNodes("cluster") | Where {$_.$text -eq $cluster}
$updateTag.ParentNode.RemoveChild($updateTag)

We are looking for the Text inside of the tag. As you can see from the output at the bottom, it has a label (or whatever it is called) of #text. The problem is, when working within PowerShell, if I add a “#” to a line, it will comment out everything after it. We get around that limitation but creating a variable called $text and given it a value of #text. Maybe there is a better way of doing it, but this worked so I went with it.

The next line is looking for a portgroup matching $name. The next line is selecting the tag that matches $cluster. The final line is performing the removal of that tag. This still needs to be saved, so we’re not done yet, but at this point we have removed from .  If you run the command below you can see that “NestedCluster” has been removed as a cluster in the “VM Network” portgroup.

$xmlConfig.config.portgroups.ChildNodes

Now what if this portgroup is only on one cluster and we want to delete it and all of its attributes completely? We can do so with the following command.

$xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name} | % {$xmlConfig.config.portgroups.RemoveChild($_)} | Out-Null

In this command, we are getting all the portgroups in the first part, then filtering the results where $name matches the name of an existing portgroup. Then we are removing that entire and all its contents from the XML file. The Out-Null is required to make it work, but I don’t really know why. Once again, this isn’t saved yet, we can do that in the next step.

In order to save we need to run the following command.

$xmlConfig.Save($xmlFile)

Now that this file is saved, we can re-check the XML file using the commands below

$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

If we run the command $xmlConfig.config.portgroups.childnodes we will see that “VM Network” is now gone

We can remove just an attribute or we can remove an entire element. How can we create a script to determine which one to use? If we wrap this all in an IF/ELSE statement we can do it pretty easily.

Using the $clusters variable we created earlier, we can perform a count of how many tags there are. Running the following command will show many clusters a portgroup is provisioned to.

$clusters.cluster.count

In our IF/ELSE statement, we are checking to see if the count is greater than 1 (-gt 1) and then performing the command to remove just the cluster tag. If it’s not greater than 1, we are running the command to remove the entire portgroup and all of its attributes.

$clusters = $xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name}
IF ($clusters.cluster.count -gt 1){
$text = "#text"
$clusterTag = $xmlConfig.config.portgroups.portgroup | Where {$_.name -eq $name}
$updateTag = $clusterTag.SelectNodes("cluster") | Where {$_.$text -eq $cluster}
$updateTag.ParentNode.RemoveChild($updateTag)
$xmlConfig.Save($xmlFile) } ELSE {
$xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name} | % {$xmlConfig.config.portgroups.RemoveChild($_)} | Out-Null
$xmlConfig.Save($xmlFile) }

Notice how we see the same #text and “NestedCluster” output after the commands ran when we were just trying to remove a cluster? That’s because powershell sees there are more than 1 cluster assigned to the VM Network portgroup and it just removed it.

Here is the full script to check if there are multiple XML attributes named “cluster” and remove it or remove the entire portgroup element.

#Define XML file and Get its contents
$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

#Define variables and prompt for input
$name = Read-Host -Prompt "Enter the name of the Portgroup (ex: Management Network)"
$cluster = Read-Host -Prompt "Enter the name of the cluster for this Portgroup (ex: Cluster1)"

#IF/ELSE Statement to remove a single attribute or an entire element
$clusters = $xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name}
IF ($clusters.cluster.count -gt 1){
$text = "#text"
$clusterTag = $xmlConfig.config.portgroups.portgroup | Where {$_.name -eq $name}
$updateTag = $clusterTag.SelectNodes("cluster") | Where {$_.$text -eq $cluster}
$updateTag.ParentNode.RemoveChild($updateTag)
$xmlConfig.Save($xmlFile) } ELSE {
$xmlConfig.config.portgroups.ChildNodes | ? {$name -eq $_.name} | % {$xmlConfig.config.portgroups.RemoveChild($_)} | Out-Null
$xmlConfig.Save($xmlFile) }

Removing Values in XML Using PowerShell

Adding Values to XML Using PowerShell

Continuing on from the previous post on getting values from an XML file using PowerShell, I’m going to talk about how to add values to an XML files. With the recent project I was working on I needed a way to easily add new portgroups into the XML configuration file. Every environment changes and while having something manually update an XML file would work there is always the possibility of messing up the syntax or something much worse.

Let’s have a look at the sample XML file again.

What we have here is 3 port groups (Management Network, VM Network, Web Network) with a VLAN, VirtualSwitch, and Cluster defined. The entire file sits inside the “config” tags. Each portgroup lives inside the “portgroups” tag, and the values for each portgroup live inside the individual “portgroup” tags.

The goal here is to add a brand new portgroup to this XML file so when we can then add that portgroup with the correct values to our ESXi hosts. Given our existing structure we’ll need a name, VLAN, Virtual Switch, and Cluster for this new portgroup.

In order to update our XML file we need to get the XML file contents and we do that by using the following command (again, using the file path as a variable so I can easily change it later).

$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

Now that we have the contents of the XML file, we need to gather the name, VLAN, Virtual Switch, and Cluster for this new portgroup. The question you’ll have to ask yourself is do you want to update the script file with each new portgroup you need to add or do you just want the script to prompt for those values each time it’s run?

If you want to manually update the file and let it run by itself just define the following variables in your script. For this example we’re creating a new portgroup called “App Network” with VLAN 31, on vSwitch1 and on cluster2.

$name = "App Network"
$vlanID = "31"
$virtualSwitch = "vSwitch1"
$cluster = "cluster2"

When we need to add these values into our XML file, we will refer to them using $name, $vlanID, $virtualSwitch, and $cluster.

Let’s do the same thing, but where we’re prompted for the values each time.

$name = Read-Host -Prompt "Enter the name of the new Portgroup (ex: Management Network)"
$vlanId = Read-Host -Prompt "Enter the VLAN Id number for the Portgroup (ex: 13)"
$virtualSwitch = Read-Host -Prompt "Enter the name of the Virtual Switch for Portgroup (ex: vSwitch1)"
$cluster = Read-Host -Prompt "Enter the name of the cluster for this Portgroup (ex: Cluster1)"

I saved the variables above as a file named “addPortgroup.ps1” in the C:\Scripts directory. Running that script in PowerShell prompted for my input for each of those lines. Instead of updating a script file each time I need to add a new Portgroup, I can run the script and enter the values myself.

Now that we’ve recorded these values, let’s start using them.

First off we need to create a new portgroup tag since we’re adding a new portgroup. We use a variable name (in this case $newPortgroup) to define where this tag will live. $xmlConfig.config.Portgroups is the parent of each of the Portgroups we currently have. What we’re doing here is saying make a change to by adding a new element called .

$newPortgroup = $xmlConfig.config.Portgroups.AppendChild($xmlConfig.CreateElement("Portgroup"))

Once we do that, now we’re going to start adding those attributes we already defined. We’ll start with name.

$newPortgroup.SetAttribute("Name",$name)

In the new Portgroup element we created, we set an attribute for and set it to the value of $name (“App Network” for our example).

Now, we can repeat that process for each attribute just like above and save our work (I’ll show how to save in a later step), but if we do that our XML formatting may not be what we’re looking for.

On line 20 of our sample.xml file we see how this data gets saved.

As you can see each attribute is added on the same line. Maybe this works for you, and if so, great. For me, I wanted to maintain the existing formatting, so there is a little more work to do.

Now we need to add each remaining attribute as a child to the already created “App Network” portgroup. We do that with the following command.

$newvlanIdAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("vlanId"))
$newvlanIdValue = $newvlanIdAttribute.AppendChild($xmlConfig.CreateTextNode($vlanId))

The first line creates a new attribute called “vlanId” that’s been added to our new then the second line set the value of that attribute to $vlanId (VLAN 31 for this example).

We can now add Virtual Switch and Cluster the exact same way.

$newvirtualSwitchAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("virtualSwitch"))
$newvirtualSwitchValue = $newvirtualSwitchAttribute.AppendChild($xmlConfig.CreateTextNode($virtualSwitch))
$newclusterAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("cluster"))
$newclusterValue = $newclusterAttribute.AppendChild($xmlConfig.CreateTextNode($cluster))

With all the new elements created and the values set, we need to save this configuration. If we close down PowerShell right now none of our updates are saved. Save using the following command

$xmlConfig.Save($xmlFile)

Now that we’ve updated the xml file, let’s see what it looks like In PowerShell. We’ll need to re-check the contents of the XML file as it changed since we lasted checked.

$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

And now let’s look at $xmlConfig.config.portgroup.portgroups

And if we look at the contents of the XML file we can see that “App Network” matches the layout of our other portgroups

And here is what the script looks like all together:

#Define XML file and Get its contents
$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

#Define variables and prompt for input
$name = Read-Host -Prompt "Enter the name of the new Portgroup (ex: Management Network)"
$vlanId = Read-Host -Prompt "Enter the VLAN Id number for the Portgroup (ex: 13)"
$virtualSwitch = Read-Host -Prompt "Enter the name of the Virtual Switch for Portgroup (ex: vSwitch1)"
$cluster = Read-Host -Prompt "Enter the name of the cluster for this Portgroup (ex: Cluster1)"

#Create a new XML element with the input entered above and save
$newPortgroup = $xmlConfig.config.Portgroups.AppendChild($xmlConfig.CreateElement("Portgroup"));
$newPortgroup.SetAttribute("Name",$name);
$newvlanIdAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("vlanId"));
$newvlanIdValue = $newvlanIdAttribute.AppendChild($xmlConfig.CreateTextNode($vlanId));
$newvirtualSwitchAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("virtualSwitch"));
$newvirtualSwitchValue = $newvirtualSwitchAttribute.AppendChild($xmlConfig.CreateTextNode($virtualSwitch));
$newclusterAttribute = $newPortgroup.AppendChild($xmlConfig.CreateElement("cluster"));
$newclusterValue = $newclusterAttribute.AppendChild($xmlConfig.CreateTextNode($cluster));
$xmlConfig.Save($xmlFile)

Adding Values to XML Using PowerShell

Getting Values from XML Using PowerShell

Working on a recent project I was tasked with maintaining VMware host configuration via XML files. The goal was to have a central location to modify the settings of a host (DNS, vmkernel interfaces, vswitch config, port groups) without having to update each host by hand. This lead me down the path of using PowerShell with XML files as the configuration source.

Below is the sample of my XML file.

What we have here is 3 port groups (Management Network, VM Network, Web Network) with a VLAN, Virtual Switch, and Cluster defined. The entire file sits inside the “config” tags. Each portgroup lives inside the “portgroups” tag, and the values for each portgroup live inside the individual “portgroup” tags.

Below is a sample command to get values from an XML file. We pass the file location as a variable and then we store all those values inside another variable to make working with the values easier.

$xmlFile = "C:\Scripts\sample.xml"
$xmlConfig = [System.Xml.XmlDocument](Get-Content $xmlFile)

And once we type in $xmlConfig into Powershell we can see that it is pulling in the data from our XML file.

We can see the “config” section, but how do we dig deeper? Type in $xmlconfig.config and let’s look at the output

Now we can see the “portgroups” section. Let’s go deeper and see what’s inside of that by typing the following:

$xmlconfig.config.portgroups

Nice! Now we can see all the portgroups we have defined. In order to get detail on each of these, we can type $xmlconfig.config.portgroups.portgroup and we’ll get a list of all the portgroups and all their values.

Now let’s say we are only concerned about retrieving values from one of those portgroups. We can add a Where clause to find only the Portgroups that exist on vSwitch1 as an example with the following command:

$xmlconfig.config.portgroups.portgroup | Where {$_.virtualswitch -eq "vSwitch1"}

Grabbing values out of an XML file is pretty straightforward. In the next post we’ll talk about how to add information to an XML file.

Getting Values from XML Using PowerShell

vSAN – Check VM Storage Policy & Compliance

As I continue to work with vSAN I discover there’s way more to do than just move some VMs over and you’re on your way. With multiple vSAN clusters each with different configurations I needed a way to monitor the current setup and check for changes. While creating a simple script to check which VM Storage Policy is assigned to each VM isn’t very difficult, a creating a script to check the storage policy of VMs across multiple vSAN datastores proved to be a little more difficult.

We run multiple PowerCLI scripts to check health and configuration drift (thanks to a special tool created by Nick Farmer) in our environment. In the event that a new vCenter is added or new vSAN datastore is deployed, we needed a simple script that can be run without any intervention or modification. Now we can be alerted when the proper VM storage policies isn’t assigned or the current policy is out of compliance.

To further complicate things in our setup, we create a new VM Storage Policy that contains the name of the cluster in which it’s assigned.  Due to the potential differences in each vSAN cluster (stripes, failures to tolerate, replication factor, RAID, etc) having a single Storage Policy does not work for us. In the event a VM is migrated from one vSAN cluster to another we need to check that the VM storage policy matches vSAN datastore cluster policy.

What this script does is grab all the clusters in a vCenter that have vSAN enabled. For each cluster that is found with vSAN enabled, it is filtering only the VMs that live on vSAN storage (with the name of “<cluster>-vsan”. Then we get the storage based policy management (Get-SpbmEntityConfiguration) of those VMs. The script then filters for a storage policy that doesn’t contain the cluster name OR a compliance status that is compliant.

$vsanClusters = Get-cluster | Where-Object {$_.vsanenabled -eq "True"}
foreach ($cluster in $vsanClusters)
{
$Cluster | get-vm |?{($_.extensiondata.config.datastoreurl|%{$_.name}) -like "*-vsan*"} |
Get-SpbmEntityConfiguration | Where-Object {$_.storagepolicy -notlike "*$Cluster*" -or $_.compliancestatus -notlike "*compliant*"} |
Select-Object Entity,storagepolicy,compliancestatus
}

Once this is run we can see the output below. I’ve obscured the names of the VMs, but we can see that there are still 12 VMs that are using the default vSAN Storage Policy instead of the cluster-specific storage policy they should be using. In addition, we see that the compliance status is currently out of date on most of these VMs. These VMs reside on 2 separate clusters and there are also 2 VMs that were filtered because they are on local storage in these clusters instead of vSAN.

storagepolicy01-12202016

 

vSAN – Check VM Storage Policy & Compliance

Cohesity – DataPlatform in the Cloud

cohesityWhat separates vendors is focus and execution. In a crowded market, finding the right backup provider is no easy task. While each product has its pros and cons, finding the differentiator can be a daunting task. While Cohesity is relatively new to this space (founded in 2013), they have that focus and execution necessary to be a leader in the backup space.

But Cohesity is more than just backups. The Cohesity storage appliance not only handles your backup storage needs, but can also run your dev and test workloads. Cohesity is focused on your secondary storage needs. That secondary storage consists of any workloads or data that isn’t production. By avoiding the draw of being another primary storage vendor, Cohesity is listening to customers, learning their needs and creating a solution that can fit any size business.

storageiceberg

The Cohesity solution was built for a virtualized (VMware-only) environment. Connecting directly to your vCenter servers and pulling your inventory allowing administrators to create backup jobs and policies. While their start was in virtualization, there are still many physical workloads in the datacenter. Creating agents for physical Windows, Linux, and SQL server all backing up to the same storage system and with the same policies prove no workloads can’t be protected by Cohesity.

But wait, there’s more!

While data protection is important, that’s only a small portion of the Cohesity offering. Running these backups directly from the Cohesity storage arrays allows you to free up primary storage resources and (potential) bottlenecks when running multiple instances of the same VM on a single array. Leveraging the SSDs that come in each Cohesity node as a cache tier, testing software patches and deployments from your backed up production VMs means that your performance doesn’t suffer. And with a built in QoS engine your dev/test workloads don’t have to affect the speed of your backups.

Cohesity provides a scale-out solution, meaning as storage demand increases so can your secondary storage space. Operating under a single namespace, as new nodes are added, your space increases without needing to reconfigure jobs to point to a new array or manually re-striping data. Cohesity has customers that have scaled up to as much as 60 nodes with over a petabyte of storage.

To the cloud!

Policy-based backups and replication ensures that your data will be available. Cohesity has the ability to distribute data across the nodes in a cluster, replicate to clusters in another locations, and also replicate your data to a cloud provider in order to satisfy offsite backup requirements. The latest addition to the Cohesity software portfolio is the DataPlatform Cloud Edition. This gives you the ability to run Cohesity in the cloud.

DataPlatform CE is more than just replicating data to the cloud. Your VMs can be backed up to your on-premises cluster and that data can be replicated to your cloud-based array. From that cloud-based array, you can then clone virtual machines to a native cloud format. This means your servers can be run in the cloud in their native format and available to test or even run in the event of migrations or datacenter outages.

Many backup and data protection software vendors are doing replication to the cloud such as Veeam and Zerto. While the features isn’t new, its addition makes Cohesity a serious contender in this space. DataPlatform CE is available currently in tech preview in the Microsoft Azure Marketplace, but Cohesity hopes to release it in the first half of 2017 with support for Azure as well as AWS.

Wrapping Up

Data protection and availability is never going to be exciting. Swapping tapes and deploying agents is tedious work. A fully integrated software solution that not only protects your data, but also helps solve the problem of data sprawl, a platform for developers to test against production data in an isolated environment and the ability to migrate workloads to the cloud. That’s about as exciting as it gets in data protection and that is just the tip of the (storage) iceberg.

________________________________________

Take a look at posts by my fellow delegates from Tech Field Day 12 and watch the videos here.

First Look at Cohesity Cloud Edition
The Silent Threat of Dark Data
Cohesity Provides All of Your Secondary Storage Needs
Secondary Storage is Cohesity’s Primary Goal

________________________________________

Disclaimer: During Tech Field Day 12, my expenses (flight, hotel, transportation) were paid for by Gestalt IT. Cohesity provided each delegate with a gift bag, but I am under no obligation to write about any of the presented content nor am I compensated for such writing.

Cohesity – DataPlatform in the Cloud

VSAN – Compliance Status is Out of Date

Occasionally the Compliance status of the performance service will go to the “out of date” status. This is not an alert that is thrown anywhere within vCenter. You will have to check this status by logging into the vSphere web client, locating your vCenter, choose the cluster, clicking on “Manage” then choosing “Health and Performance” under “Virtual SAN”
ComplianceStatus-a

As I have recently fixed this issue the above screenshot shows the “Compliant” status. Below are the steps to get to that point.

1. In the box for “Performance Service” click “Edit storage policy”
ComplianceStatus-01

2. If there is a storage policy available in the drop down, select it and click “OK”. This will apply that policy and perform the compliance check.
ComplianceStatus-02

For the lucky few where that works, that’s all you need to do. If the storage policy list is empty you’ll need to restart the vsanmgmtd service on each of the hosts.

3. Enable SSH on each of the hosts in the VSAN cluster and using an SSH client (like putty), SSH to a host and run the following command to restart the vsanmgmtd service (this is a non-impactful operation and should be able to be performed during production hours with no impact)
a. /etc/init.d/vsanmgmtd restart

4. Repeat that command on each of the hosts in the cluster until they have all restarted their services
ComplianceStatus-04

5. Wait 5 minutes and then check to see if you are able to select a storage policy for the performance service. If not, move on to step 6

6. Now we’ll need to restart the vSphere Profile-Driven Storage Service on the vCenter server. This is also non-impactful and should be able to be performed in the middle of the day. If you’re using vCenter on windows, connect to the Windows server and restart the “Vmware vSphere Profile-Driven Storage Service”. If using VCSA (like this example) you’ll need to SSH to the VCSA and run the command below
a. Service vmware-sps restart

7. After the vmware-sps service restarts, log out of the web client and wait for 5 minutes while the storage profile service  completes its restart.

8. Log back in to the web client, navigate to the vCenter server, click “Manage” then choose the “Storage Providers” tab
ComplianceStatus-08

9. Click the Synchronize Providers button to resync the state of the environment
ComplianceStatus-09

10. Wait another 5 minutes while these synchronize completes. After 5 minutes, navigate to the VSAN cluster in the web client. Click on “Manage” then choose “Settings” and locate “Health and Performance” under the “Virtual SAN” section
ComplianceStatus-10

11. In the Performance Service box, click the “Edit Storage Policy” button
ComplianceStatus-11

12. From the drop down list you should be able to select the appropriate VSAN storage policy and then click “OK”
ComplianceStatus-12

13. After this is selected the compliance status should change to “Compliant” and you should be all set.

So far these are the only steps that I have needed to follow in order to fix this issue. Let me know if there are any other fixes available.

 

 

 

VSAN – Compliance Status is Out of Date

VSAN – Host Not Contributing Stats

After an upgrade or maintenance on one or more of the nodes in a VSAN cluster one of the hosts can stop contributing performance stats. This is not a production down issue, but should be addressed to see the most up-to-date stats across all the nodes.

The fix for this is one of three things, but each of them involves turning off performance statistics on the cluster which will cause all historical performance stats to be removed. My hope is that VMware will fix this issue in an upcoming release because a loss of historical is not tolerable in all environments.

1. View the health of the VSAN by logging into the vCenter web client. Navigate to the appropriate vCenter and cluster, then click the “Monitor” tab, followed by “Virtual SAN” then click on “Health.” Expanded “Performance service” and click the warning for “All hosts contributing stats”
step01

2. At the bottom you will now see the list of hosts that are not contributing stats
step02

3. Now that we’ve identified the problem host, we need to disable VSAN performance service temporarily. Navigate to the “Manage” tab for this cluster then click on “Health and Performance” under “Virtual SAN”
step03

4. Click “Turn off” in the “Performance Service” box

a. Click “OK” to confirm stopping the service which will erase all existing performance data
step04a

5. Confirm Perform Service has been disabled by refreshing the page
step05

6. SSH to the affected host (using putty or similar SSH client) we identified in step 2 (you may have to enable SSH on the host before you can connect).
step06

7. Run the command below to restart the VSAN management agent. This should have no production impact so it is safe to perform outside of a maintenance window.
a. /etc/init.d/vsanmgmtd restart
step07a

8. Once the service has been restarted, go back to the vCenter web client and the click the “Edit” button for the Performance Service box
step08

9. Select the appropriate storage policy from the drop down list, ensure the “Turn ON Virtual SAN performance service” box is checked and click “OK”
step09

10. Confirm that the performance service is turned on and reporting healthy
step10

11. Navigate back to the “Monitor” tab and then “Virtual SAN” clicking the on the “Health” section. Click “Retest” to verify that all hosts are contributing stats.
step11

If this does not fix the issue, you can restart the process, but this time instead of restarting the vsanmgmt service on the one node, do it on all of the nodes in the cluster. Once the services have been restarted across all nodes then restart the performance service and all nodes should be contributing stats.

I have also seen a case where restarting the service on all nodes didn’t fix the problem. In that scenario I was able to fix the problem by entering maintenance mode on the problem node and choose “full data migration” so all the data would be removed from the cluster. After that was complete I completely rebuilt the host from scratch (including wiping the disks claimed by VSAN) then moving it back into the cluster. I haven’t heard from VMware of any other ways to fix this issue.

VSAN – Host Not Contributing Stats