Saturday, 11 February 2017

Using PowerShell to Generate Reports for your Cluster (Get-ClusterInfo.ps1)

Reporting is not fun! And since I like to have fun, and PowerShell is fun, thet’s generate reports for our NetApp ONTAP clusters with PowerShell!

The following script generates 3 CSV reports (working with CSV’s has certain advantages):

- Report_on_Clusters.CSV (with: Cluster, Cluster IP, Serial, Version)
- Report_on_ClusterSwitches.CSV (with: Cluster, Cluster Switch, IP Address, Model, Serial, Version)
- Report_on_Nodes.CSV (with: Cluster, Node Name, Mgmt IP, SP IP, Model, Serial, Sysid, Version)

Image: CSVs generated by Get-ClusterInfo.ps1

There’s two modes: -Collect and -Report. The first collects the data and saves as XML. The second reports the data using the saved XMLs for input.


.\Get-ClusterInfo.ps1 -Collect
.\Get-ClusterInfo.ps1 -Report


It requires a file (default is “Clusters.txt”) with cluster names/IPs in. And you’ll want to use Add-NcCredential to add cluster credentials into your PowerShell credentials cache first.

Note: Since there’s no API for “cluster-switch show”, I had to be a little bit creative.

The Script


#######################
### Get-ClusterInfo ###
#######################

## TIP: Add cluster credentials with Add-NcCredential ##
Param(
  [Switch]$Collect, # Use this switch to collect data
  [Switch]$Report,  # Use this switch to generate CSVs
  [String]$Clusters_Text_File = "Clusters.txt"
)
If(!(Test-Path $Clusters_Text_File)){ "Failed to load clusters!"; EXIT }
[System.Array]$Clusters = Get-Content $Clusters_Text_File

## INPUTS ##
[System.Array]$CluData = ,
"Get-NcCluster",
"Get-NcNode",
"Get-NcNetInterface",
"Get-NcNetOption",
"Get-NcServiceProcessor",
"Get-NcSystemVersion",
"Get-NcVserver"

## COLLECT DATA ##
Function Collect-CluData{
  Foreach($Clu in $Clusters){
    [Void](New-Item $Clu -ItemType Directory -Force)
    "INFO.: CONNECTING TO $Clu"
    [Void](Connect-NcController -Name $Clu)
    $CluData | Foreach{ (Invoke-Expression "$_") | Export-CLIXML "$Clu\$Clu.$_.XML" }
    If(Test-Path "$Clu\$Clu.Get-NcNetOption.XML"){ Collect-NcClusterSwitchData }
  }
}

## COLLECT CLUSTER SWITCH DATA ##
# There's no API for "cluster-switch show"*, hence using invoke-ncssh
# *no results for::> show-ontapi -command "system cluster-switch show"
Function Collect-NcClusterSwitchData{
  [String]$Switchless = (Import-CLIXML "$Clu\$Clu.Get-NcNetOption.XML").SwitchlessClusterEnabled
  If(!$Switchless){
    [String]$SwitchShow = Invoke-ncssh -Command "cluster-switch show"
    $SwitchShow | Out-File "$Clu\$Clu.cluster-switch_show.TXT"
    Process-NcClusterSwitchData
  }
}

## PROCESS CLUSTER SWITCH DATA ##
# Required to parse the TXT file output from "cluster-switch show"
Function Process-NcClusterSwitchData{
  $CS = @{}; $SW = "1"; $CS."1" = @{}; $CS."2" = @{}
  [System.Array]$CluSwArr = Get-Content "$Clu\$Clu.cluster-switch_show.TXT"
  Foreach($line in $CluSwArr){
    [System.Array]$Split = $line.split(" ") | Where{ $_ -ne "" }
    If($line.Contains("cluster-network")){                         
      [String]$CS.$SW.Name  = $Split[0]
      [String]$CS.$SW.IP    = $Split[2]
      [String]$CS.$SW.Model = $Split[3]
    }
    elseif($line.Contains("Serial Number:")){ [String]$CS.$SW.SN    = $Split[2] }
    elseif($line.Contains("Software Version:")){ [String]$CS.$SW.SW = $Split[2] }
    elseif($line.Contains("Version Source:")){ $SW = "2" }
  }
  $CS | Export-CLIXML "$Clu\$Clu.Get-NcClusterSwitch.XML"
}

## GENERIC ADD MEMBER FUNCTION ##
Function AddM{
  Param([System.Object]$O,[String]$N,[String]$V)
  Add-Member -InputObject $O -MemberType NoteProperty -Name $N -Value $V
}

## GENERATE CSV REPORT DATA ##
Function Report-CluData{
  [System.Object]$Reports = @{}
  "Clusters","ClusterSwitches","Nodes" | Foreach{ [System.Array]$Reports.$_ = @() }
  Foreach($Clu in $Clusters){
    [System.Object]$D = @{}
    $CluData | Foreach{ $D."$_" = Import-CLIXML "$Clu\$Clu.$_.XML" }
    $Interfaces = $D."Get-NcNetInterface"
    
    ## CLUSTERS REPORT ##
    [String]$ClusterName = $D."Get-NcCluster".ClusterName
    $Report = New-Object PSObject
    AddM $Report "CLUSTER"    $ClusterName
    AddM $Report "CLUSTER IP" (($Interfaces | where{$_.Role -eq "cluster_mgmt"}).address)
    AddM $Report "SERIAL"     ($D."Get-NcCluster".ClusterSerialNumber)
    AddM $Report "VERSION"    ($D."Get-NcSystemVersion".Value.Split(":")[0])
    $Reports."Clusters" += $Report          
   
    ## CLUSTER SWITCHES REPORT ##
    [String]$SwitchlessCluster = (Import-CLIXML "$Clu\$Clu.Get-NcNetOption.XML").SwitchlessClusterEnabled
    If($SwitchlessCluster -eq $False){
      [System.Object]$CS = Import-CLIXML "$Clu\$Clu.Get-NcClusterSwitch.XML"
      Foreach($SW in "1","2") {
        $Report = New-Object PSObject
        AddM $Report "CLUSTER"        $ClusterName
        AddM $Report "CLUSTER SWITCH" $CS.$SW.Name
        AddM $Report "IP ADDRESS"     $CS.$SW.IP
        AddM $Report "MODEL"          $CS.$SW.Model
        AddM $Report "SERIAL"         $CS.$SW.SN
        AddM $Report "VERSION"        $CS.$SW.SW
        $Reports."ClusterSwitches" += $Report
      }
    }
   
    ## NODES REPORT ##
    [System.Array]$Nodes = $D."Get-NcNode"
    Foreach($Node in $Nodes){
      $Report = New-Object PSObject
      AddM $Report "CLUSTER"   $ClusterName
      AddM $Report "NODE NAME" $Node.Node
      AddM $Report "MGMT IP"   ($Interfaces | where{ ($_.homenode -eq $Node.Node) -and ($_.role -eq "node_mgmt") }).address
      AddM $Report "SP IP"     ($D."Get-NcServiceProcessor" | where{$_.node -eq $Node.Node}).IpAddress
      AddM $Report "MODEL"     $Node.NodeModel
      AddM $Report "SERIAL"    $Node.NodeSerialNumber
      AddM $Report "SYSID"     $Node.NodeSystemId
      AddM $Report "VERSION"   $Node.ProductVersion.Split(":")[0]
      $Reports."Nodes" += $Report
    }         
  }
  "Clusters","ClusterSwitches","Nodes" | Foreach{ $Reports.$_ | Export-CSV "Report_on_$_.CSV" -NoTypeInformation }
}

## MAIN PROGRAM ##
If($Collect){
  If(!(Get-Module DataONTAP)){ Import-Module DataONTAP }
  If(!(Get-Module DataONTAP)){ "No DataONTAP PSTK!"; EXIT }
  Collect-CluData
}
If($Report){ Report-CluData }


No comments:

Post a Comment