Automation

 View Only
  • 1.  Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Oct 01, 2019 01:11 PM

    Hello there.

    I need to set the IOPS limit on VMDKs with particular Storage Policy assigned, and the amount of IOPS should be set depending on the size of the VMDK. For example, 2 IOPS per gigabyte for Tier1, 1 IOPS per gigabyte for Tier2 and 0.5 IOPS per GB for Tier3. There will be 3 Policies total (maybe 4 later), and disks with Policy, which is different from the described three tiers (or with Default policy), should not get a limit.

    I have written such script:

    #Set the IOPS per Gigabyte for particular Storage Policy ("Tier1", "Tier2" and "Tier3" in my case and 2, 1 and 0.5 IOPS per GB accordingly)

    $Tier1IOPSperGB = 2

    $Tier2IOPSperGB = 1

    $Tier3IOPSperGB = 0.5

    #To store credentials in the XML file you should get credentials in a variable:

    #$credentials = Get-Credential

    #An then export it into file (which can be used only on the same machine):

    #$credentials | Export-Clixml -Path "C:\Users\anatoliy\credentials.cred"

    #Import credentials from XML file

    $credentials = Import-Clixml -Path "C:\Users\anatoliy\credentials.cred"

    #Connect the vCenter

    Connect-VIServer vcsa1.nokogerra.lab -Credential $credentials

    #Names of the VMs to be excluded from setting the IOPS limit are stored in the CSV. You can use a full name of the VM or a wildcard ("excludevms" if a column name):

    #excludevms

    #exclude1-test

    #*clude2*

    $csv = Import-Csv "C:\Users\anatoliy\Desktop\ExcludeVMs.csv"

    #Fill the string array with names of the VMs to be excluded

    foreach ($statement in $csv) {[string[]]$exclude += Get-VM -Name $statement.excludevms}

    #Now get all VMs of the Virtual infrastructure except the VMs, which names were specified in the CSV file

    $vms = Get-VM | ?{$exclude -notcontains $_.Name}

    foreach ($vm in $vms){

    #For each VM get all VMDKs   

        $VMDisk = $vm | Get-HardDisk

    #For each VMDK get it's Storage Policy

            foreach ($disk in $VMDisk){

                $Policy = ($disk | get-SpbmEntityConfiguration).StoragePolicy.Name

    #If "Tier1" Policy is assigned for the disk AND the correct limit is not already set

                if (($Policy -eq "Tier1") -and

                (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ($disk.CapacityGB * $Tier1IOPSperGB))) {

    #then set the limit, which depends of the disk size and Storage Policy

                $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ($disk.CapacityGB * $Tier1IOPSperGB)

                }

    #Same for "Tier2"

                elseif (($Policy -eq "Tier2") -and

                (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ($disk.CapacityGB * $Tier2IOPSperGB))) {

                $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ($disk.CapacityGB * $Tier2IOPSperGB)}

    #Same for "Tier3"

                elseif (($Policy -eq "Tier3") -and

                (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ($disk.CapacityGB * $Tier3IOPSperGB))) {

                $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ($disk.CapacityGB * $Tier3IOPSperGB)}

    #Do nothing for other policies

                else {Write-Host "Doing nothing"}

                                      }

                         }

    Remove-Variable exclude -Force -ErrorAction SilentlyContinue

    Remove-Variable vms -Force -ErrorAction SilentlyContinue

    Disconnect-VIServer vcsa1.nokogerra.lab -Confirm:$false

    It seems that the script works properly, however I still need help to make some things:

    1. I need to "trim" the size of a VMDK, which is returned by "$disk.CapacityGB". For example, if the disk size somehow became 100.825367 GB, then it should be counted as 101 GB. Actually, if it will be counted as 100GB it will be OK too, the difference in 2 IO per second is not significant.

    2. I think, I need some report, which will cover the script execution result. To be honest, I'm still not sure how it should look like, may be an email with errors? I'm planning to run this script periodically (every day, I guess), so I need some info if the execution was sucessful.

    3. Any idea how to optimize this script in any other way? I'm a pretty bad writer, so it would be nice to get some advice :smileyhappy:



  • 2.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Oct 01, 2019 01:31 PM

    1. Use the Round method

    [math]::Round($disk.CapacityGB)

    2.You could use a try-catch construct.


    If there is a terminating error, the code in catch block will be executed.

    You can force a terminating error by adding an ErrorAction on most cmdlets.

    try{

        Get-VM -ErrorAction Stop

    }

    catch{

        Write-Error "Something went wrong"

    }

    3. No real "big" timesavers at first sight.

    You could convert the script to work with vSphere objects (Get-View and ExtensionData), but it would make the code more complex.

    A smaller one, since you are already sure you are looking at HardDisk object, there is really no need to test $_ -is [VMware.Vim.VirtualDisk]



  • 3.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Oct 08, 2019 01:11 PM

    Hello.

    My apologies for the delay, I couldn't try your tips before.

    1. [math]::Round works perfectly, thank you.

    2. I've read few articles about try/catch, but I'm still not sure how to use it in my case. Where should I put "try", and when to put "catch". Also, it seems, that I should not use "stop" error action, if I want the script to continue after a non-terminating exception. I guess, it is just too hard for me.

    3. > A smaller one, since you are already sure you are looking at HardDisk object, there is really no need to test $_ -is [VMware.Vim.VirtualDisk]

    Do you mean, that I can change this expression:

    $disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}

    to this one:

    $disk.Parent.ExtensionData.Config.Hardware.Device |  where {$_.deviceinfo.label -eq $disk.name}

    So the script will rely only on the object name, not on the object type?

    Also I'm looking a way to add the additional condition to the script: if the calculated IOPS limit (IOPSperGB * CapacityGB) is lower (or equal) than the LowWatermark (which will be set in the script's beginning), then use the LowWatermark value for the disk IOPS limit. However, I'm not sure how to do it. Can I just add "if/else" block into the parent "if" block?

    update:

    Okay, my last question is seems to be solved now. For example:

    How it was:

    foreach ($vm in $vms){

    #For each VM get all VMDKs   

        $VMDisk = $vm | Get-HardDisk

    #For each VMDK get it's Storage Policy

            foreach ($disk in $VMDisk){

                $Policy = ($disk | get-SpbmEntityConfiguration).StoragePolicy.Name

    #If "Tier1" Policy is assigned for the disk AND the correct limit is not already set

                if (($Policy -eq "Tier1") -and

                (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB))) {

    #then set the limit, which depends of the disk size and Storage Policy

                $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB)

                }

    #Same for "Tier2"

                elseif (($Policy -eq "Tier2") -and

    ...............

    And how it became:

    foreach ($vm in $vms){

    #For each VM get all VMDKs   

        $VMDisk = $vm | Get-HardDisk

    #For each VMDK get it's Storage Policy

            foreach ($disk in $VMDisk){

                $Policy = ($disk | get-SpbmEntityConfiguration).StoragePolicy.Name

    #If "Tier1" Policy is assigned for the disk AND the correct limit is not already set

                if ($Policy -eq "Tier1") {

                    if ((([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB) -le $Tier1MinimumIOPS) -and

                    (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne $Tier1MinimumIOPS)){

                    $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond $Tier1MinimumIOPS}

                    elseif ((([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB) -gt $Tier1MinimumIOPS) -and

                    (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB))){

                    $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB)}

                    else {}

                    }

    #Same for "Tier2"

                elseif (($Policy -eq "Tier2") {

    ................

    Feels like it is working fine.



  • 4.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size
    Best Answer

    Posted Oct 08, 2019 02:42 PM

    No problem.

    I meant that since you are already handling objects produced by Get-HardDisk, you don't have to test if the object is a VirtualDisk.

    Your If test could be

    foreach ($vm in $vms){

        #For each VM get all VMDKs     

            $VMDisk = $vm | Get-HardDisk

        #For each VMDK get it's Storage Policy 

                foreach ($disk in $VMDisk){

                    $Policy = ($disk | get-SpbmEntityConfiguration).StoragePolicy.Name

        #If "Tier1" Policy is assigned for the disk AND the correct limit is not already set 

                    if ($Policy -eq "Tier1") {

                        if ((([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB) -le $Tier1MinimumIOPS) -and

                        (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne $Tier1MinimumIOPS)){

                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond $Tier1MinimumIOPS}

                        elseif ((([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB) -gt $Tier1MinimumIOPS) -and

                        (($disk.Parent.ExtensionData.Config.Hardware.Device |  where {($_.deviceinfo.label -eq $disk.name)}).StorageIOAllocation.Limit -ne ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB))){

                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Round($disk.CapacityGB) * $Tier1IOPSperGB)}

                        else {}

                        }

        #Same for "Tier2" 



  • 5.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Oct 08, 2019 02:45 PM

    My Try-Catch remark was primarily to handle some edge cases.
    Like for example there are no VMs, or there is a VM without a harddisk.

    This could produce errors, which you could avoid by using a try-catch, and provide a meaningful message to the user of the script.



  • 6.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Mar 26, 2020 11:01 AM

    Hello there!

    I'm not sure if I should create another thread for this question, so I'll try to ask it here: I need to collect some results of this script processing.

    Actually, I need to colelct VM names, disks (if possible), IOPS limit (if possible) and Storage Policy (if possible) into csv or html file, but for only those VMs, which were modified.

    The script block is here [PowerShell] set iops - Pastebin.com .

    I guess it should looks like

    $vmreport += $vm

    $diskreport += $disk

    etc, and then push it into a csv or something.

    But this will collect all processed VMs and disks, not only those, which were modidfed.

    Too hard for me.



  • 7.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Mar 26, 2020 11:45 AM

    Try something like this.

    $report = @()

    foreach ($vm in $vms) {

        #For each VM get all VMDKs

        $VMDisk = $vm | Get-HardDisk

        #For each VMDK get it's Storage Policy

        foreach ($disk in $VMDisk) {

            $obj = [ordered]@{

                VM = $vm.Name

                Disk = $disk.Name

                Tier = ''

                OldIOPS = ''

                NewIOPS = ''

            }

            $Policy = ($disk | get-SpbmEntityConfiguration).StoragePolicy.Name

            if ($Tier1, $Tier2, $Tier3 -contains $Policy) {

                $currentIOPS = ($disk.Parent.ExtensionData.Config.Hardware.Device | Where-Object { ($_ -is [VMware.Vim.VirtualDisk]) -and ($_.deviceinfo.label -eq $disk.name) }).StorageIOAllocation.Limit

                $obj.OldIOPS = $currentIOPS


                #If "Tier1" Policy is assigned for the disk:

                if ($Policy -eq $Tier1) {

                    $obj.Tier = $Tier1

                    #If the calculated IOPS limit is lower or equal than Minimum IOPS watermark for Tier1 and the IOPS limit is not already set equal to Tier1MinimumIOPS, then set the limit:

                    if ((([math]::Truncate(($disk.CapacityGB) * $Tier1IOPSperGB)) -le $Tier1MinimumIOPS) -and ($currentIOPS -ne $Tier1MinimumIOPS)) {

                        $obj.NewIOPS = $Tier1MinimumIOPS


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond $Tier1MinimumIOPS

                    }

                    #If the calculated IOPS limit it greater than Minimum IOPS watermark for Tier1 and the IOPS limit is not already set equal to this calculated value, then set the limit:

                    elseif ((([math]::Truncate(($disk.CapacityGB) * $Tier1IOPSperGB)) -gt $Tier1MinimumIOPS) -and ($currentIOPS -ne ([math]::Truncate(($disk.CapacityGB) * $Tier1IOPSperGB)))) {

                        $obj.NewIOPS = [math]::Truncate(($disk.CapacityGB) * $Tier1IOPSperGB)


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Truncate(($disk.CapacityGB) * $Tier1IOPSperGB))

                    }

                }

                #Same for "Tier2"

                elseif ($Policy -eq $Tier2) {

                    $obj.Tier = $Tier2

                    if ((([math]::Truncate(($disk.CapacityGB) * $Tier2IOPSperGB)) -le $Tier2MinimumIOPS) -and ($currentIOPS -ne $Tier2MinimumIOPS)) {

                        $obj.NewIOPS = $Tier2MinimumIOPS


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond $Tier2MinimumIOPS

                    } elseif ((([math]::Truncate(($disk.CapacityGB) * $Tier2IOPSperGB)) -gt $Tier2MinimumIOPS) -and ($currentIOPS -ne ([math]::Truncate(($disk.CapacityGB) * $Tier2IOPSperGB)))) {

                        $obj.NewIOPS = [math]::Truncate(($disk.CapacityGB) * $Tier2IOPSperGB)


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Truncate(($disk.CapacityGB) * $Tier2IOPSperGB))

                    }

                }

                #Same for "Tier3"

                elseif ($Policy -eq $Tier3) {

                    $obj.Tier = $Tier3

                    if ((([math]::Truncate(($disk.CapacityGB) * $Tier3IOPSperGB)) -le $Tier3MinimumIOPS) -and ($currentIOPS -ne $Tier3MinimumIOPS)) {

                        $obj.NewIOPS = $Tier3MinimumIOPS


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond $Tier3MinimumIOPS

                    } elseif ((([math]::Truncate(($disk.CapacityGB) * $Tier3IOPSperGB)) -gt $Tier3MinimumIOPS) -and ($currentIOPS -ne ([math]::Truncate(($disk.CapacityGB) * $Tier3IOPSperGB)))) {

                        $obj.NewIOPS = [math]::Truncate(($disk.CapacityGB) * $Tier3IOPSperGB)


                        $disk.Parent | Get-VMResourceConfiguration | Set-VMResourceConfiguration -Disk $disk -DiskLimitIOPerSecond ([math]::Truncate(($disk.CapacityGB) * $Tier3IOPSperGB))

                    }

                }

                $report += New-Object -TypeName PSObject -Property $obj

            }

        }

    }

    $report | Export-Csv -Path .\report.csv -NotypeInformation -UseCulture



  • 8.  RE: Set IOPS limit on VMDK depending on Storage Policy and disk size

    Posted Mar 26, 2020 12:21 PM

    Thank you a lot.

    The thing you suggested, gives me a full report, and then I can use this block to get a report only for modified VMs/Disks:

    $csv = import-csv "C:\Users\user\Desktop\Set IOPS limit per VMDK\report.csv"

    $noemptys = foreach($line in $csv){

        if(-not($line.NewIOPS -like '')){

            $line

        }

    }

    $noemptys | export-csv "C:\Users\user\Desktop\Set IOPS limit per VMDK\report-mod.csv" -NoTypeInformation