I’ve been working on a fairly major tool - in-between doing lots of other stuff - over
the last half a year or so (I won’t
divulge here what it does here, maybe later ...) One of the features I
wanted to add to the tool was automatic placement of a list of volumes to data
aggregates in the NetApp Clustered ONTAP cluster (to save time manually working
this out.) So I thought I’d write a standalone function to do this, with the
view to adding this code to my major tool at a later date.
The code is designed to be used in other tools, but can
be run standalone also. In the below example I connect to a simple test one
node cluster, which has just two aggregates, and ask it to tell me which
aggregates to put 5 new volumes on.
Image: VolsToAggrsAutoPlacer.ps1
in action
The Script
Note: As always,
formatted for blogger (replacing tabs with two spaces)
##
GENERIC INPUT DETAILS ##
$Cluster = Read-Host "Cluster "
$UserName = Read-Host "Username "
$Password = Read-Host "Password "
-AsSecureString
$Credential
= New-Object System.Management.Automation.PsCredential($UserName,$Password)
[VOID](Connect-NcController
-Name $Cluster -Credential $Credential); Write-Host
##
FUNCTION TO FIND AGGREGATE WITH LARGEST FREE SPACE ##
FUNCTION
Place-OnLargestAggregate {
$JustStarted = $TRUE
$NodeList | Foreach {
Foreach ($Aggr in $Aggrs.$_.DataAggrsList){
If($JustStarted){
$NodeWithLargestAggr = $_
$LargestAggr = $Aggr
$LargestAvailSize = $Aggrs.$_.AggrInfo.$Aggr.AvailSize
$JustStarted = $FALSE
}
elseif ($Aggrs.$_.AggrInfo.$Aggr.AvailSize
-gt $LargestAvailSize) {
$NodeWithLargestAggr = $_
$LargestAggr = $Aggr
$LargestAvailSize = $Aggrs.$_.AggrInfo.$Aggr.AvailSize
}
}
}
RETURN @{"node" =
$NodeWithLargestAggr; "aggr" = $LargestAggr}
}
##
FUNCTION TO FIND THE LARGEST VOLUME FROM THE SUPPLIED LIST (RECURSIVE) ##
FUNCTION
Find-LargestVolRecursive {
$JustStarted = $TRUE
[System.Array]$NewUnPlacedVols = @()
$UnPlacedVols | Foreach {
If($JustStarted){
$currentLargest = $_
$largestSize = $VolSizes[$_]
$JustStarted = $FALSE
} elseif ($VolSizes[$_] -gt $largestSize){
$NewUnPlacedVols += $currentLargest
$currentLargest = $_
$largestSize = $VolSizes[$_]
} else {
$NewUnPlacedVols += $_
}
}
## GET PLACEMENT AGGR INFO ##
$LargestFreeAggr = Place-OnLargestAggregate
$Node = $LargestFreeAggr.Node
$Aggr = $LargestFreeAggr.Aggr
$Aggrs.$Node.AggrInfo.$Aggr.AvailSize -=
$VolSizes[$CurrentLargest]
$ReturnAggrsObject.$CurrentLargest = $Aggr
## SCREEN OUTPUT SECTION ##
$ScreenOutputString = ("Place " +
$VolsToPlace[$CurrentLargest] + " on " + $Node + " and " +
$Aggr + ". Remaining free space = " + $Aggrs.$Node.AggrInfo.$Aggr.AvailSize)
If ($Aggrs.$Node.AggrInfo.$Aggr.AvailSize -ge
0){ Write-Host $ScreenOutputString -ForegroundColor GREEN }
else { Write-Host $ScreenOutputString
-ForegroundColor RED }
## UPDATE $UnPlacedVols AND RECURSE (if not
empty) ##
$UnPlacedVols = $NewUnPlacedVols
If($UnPlacedVols.count -ne 0){
[VOID](Find-LargestVolRecursive) }
}
##
[MAIN FUNCTION] VOLUMES TO AGGREGATES AUTO PLACER ##
FUNCTION
VolsToAggrsAutoPlacer {
Param(
[Parameter(Mandatory=$TRUE,HelpMessage="Enter comma separated list
of volumes to place")][String]$VolsToPlaceCSL,
[Parameter(Mandatory=$TRUE,HelpMessage="Enter comma separated list
of sizes of the vols")][String]$VolumeSizesCSL
)
## PROCESS VOL SIZE UNITS ##
[System.Array]$VolsToPlace = $VolsToPlaceCSL.Split(",")
[System.Array]$VolSizes = @()
$VolumeSizesCSL.Split(",") |
Foreach{
If($_ -match("k")){ $_ =
([Int64]($_.Replace("k",""))) * 1024 }
If($_ -match("m")){ $_ =
([Int64]($_.Replace("m",""))) * 1024 * 1024 }
If($_ -match("g")){ $_ =
([Int64]($_.Replace("g",""))) * 1024 * 1024 * 1024 }
$VolSizes += [Int64]$_
}
If($VolsToPlace.Count -ne $VolSizes.Count){
Write-Host "`n'Volumes To Place List' and 'Volume Sizes List' have
mistmatched length - exiting! `n" -ForegroundColor RED; EXIT}
## GET CLUSTER NODES ##
$AttrsNode = Get-NcNode -Template
$AttrsNode.Node = ""
[System.Array]$NodeList = (Get-NcNode
-Attributes $AttrsNode).Node
## GET ROOT AGGREGATES AND BUILD $Aggrs
OBJECT ##
$AttrsAggr = Get-NcAggr -Template
$QueryAggr = Get-NcAggr -Template
Initialize-NcObjectProperty -Object
$AttrsAggr -Name AggrOwnershipAttributes
Initialize-NcObjectProperty -Object
$QueryAggr -Name AggrRaidAttributes
$AttrsAggr.AggrOwnershipAttributes.OwnerName
= ""
$QueryAggr.AggrRaidAttributes.HasLocalRoot = "True"
$RootAggrs = Get-NcAggr -Query $QueryAggr
-Attributes $AttrsAggr
[System.Object]$Aggrs = @{}
$RootAggrs | Foreach {
[String ]$Owner =
$_.AggrOwnershipAttributes.OwnerName
[System.Object]$Aggrs.$Owner = @{}
[String ]$Aggrs.$Owner.Root = $_.Name
[System.Array ]$Aggrs.$Owner.DataAggrsList
= @()
[System.Object]$Aggrs.$Owner.AggrInfo = @{}
}
## GET DATA AGGRS INFO ##
Initialize-NcObjectProperty -Object
$AttrsAggr -Name AggrSpaceAttributes
$AttrsAggr.AggrSpaceAttributes.SizeAvailable
= ""
$AggrsInfo = Get-NcAggr -Attributes
$AttrsAggr
$AggrsInfo | Foreach {
[String]$Owner = $_.AggrOwnershipAttributes.OwnerName
[Int64 ]$AvailableSize =
$_.AggrSpaceAttributes.SizeAvailable
If($_.Name -ne $Aggrs.$Owner.Root){
$Aggrs.$Owner.DataAggrsList += $_.Name
$Aggrs.$Owner.AggrInfo.($_.Name) = @{}
$Aggrs.$Owner.AggrInfo.($_.Name).AvailSize
= $AvailableSize
}
}
## CYCLE THROUGH VOLUMES PLACING IN ORDER
FROM LARGEST TO SMALLEST ##
[System.Array]$UnPlacedVols = @(); $i = 0
$VolsToPlace | Foreach { $UnPlacedVols += $i;
$i ++ }
[System.Object]$ReturnAggrsObject = @{}
Write-Host; [VOID](Find-LargestVolRecursive);
Write-Host
## RETURN AGGREGATE PLACEMENTS (SAME ORDER AS
INPUT VOLS) ##
[System.Array]$ReturnArray = @(); $i = 0
$VolsToPlace | Foreach { $ReturnArray += $ReturnAggrsObject.$i;
$i ++ }
, $ReturnArray
}
VolsToAggrsAutoPlacer
Comments
Post a Comment