From c1f5fe171e2c47130195b2f4714693b469f4f229 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Thu, 8 Aug 2024 22:19:41 -0400 Subject: [PATCH 1/2] Added NVME Namespace storage --- .../Get-AbrOntapVserverNamespaceStorage.ps1 | 96 +++++++++++++++++++ .../Invoke-AsBuiltReport.NetApp.ONTAP.ps1 | 25 ++++- 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100755 Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 diff --git a/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 b/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 new file mode 100755 index 0000000..3674b95 --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverNamespaceStorage.ps1 @@ -0,0 +1,96 @@ +function Get-AbrOntapVserverNamespaceStorage { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver namespace information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.7 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage "Collecting ONTAP Vserver namespace information." + } + + process { + try { + $VserverNamespace = Get-NcNvmeNamespace -VserverContext $Vserver -Controller $Arra + $VserverObj = @() + if ($VserverNamespace) { + foreach ($Item in $VserverNamespace) { + try { + $namespacemap = Get-NcNvmeSubsystemMap -Vserver $Vserver -Controller $Array | Where-Object { $_.Path -eq $Item.Path } + $namespacepath = $Item.Path.split('/') + $namespace = $namespacepath[3] + $available = $Item.Size - $Item.SizeUsed + $used = ($Item.SizeUsed / $Item.Size) * 100 + $inObj = [ordered] @{ + 'Namespace Name' = $namespace + 'Parent Volume' = $Item.Volume + 'Path' = $Item.Path + 'Serial Number' = $Item.Uuid + 'Subsystem Map' = Switch (($namespacemap).count) { + 0 { "None" } + default { $namespacemap.Subsystem } + } + 'Home Node ' = $Item.Node + 'Capacity' = $Item.Size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Available' = $available | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue + 'Used' = $used | ConvertTo-FormattedNumber -Type Percent -ErrorAction SilentlyContinue + 'OS Type' = $Item.Ostype + 'Is Mapped' = Switch ([string]::IsNullOrEmpty($Item.Subsystem)) { + $true { "No" } + $false { "Yes" } + default { $Item.Subsystem } + } + 'ReadOnly' = ConvertTo-TextYN $Item.IsReadOnly + 'Status' = Switch ($Item.State) { + 'online' { 'Up' } + 'offline' { 'Down' } + default { $Item.Online } + } + } + $VserverObj = [pscustomobject]$inobj + + if ($Healthcheck.Vserver.Status) { + $VserverObj | Where-Object { $_.'Status' -like 'Down' } | Set-Style -Style Warning -Property 'Status' + $VserverObj | Where-Object { $_.'Used' -ge 90 } | Set-Style -Style Critical -Property 'Used' + $VserverObj | Where-Object { $_.'Is Mapped' -eq 'No' } | Set-Style -Style Warning -Property 'Is Mapped' + } + + $TableParams = @{ + Name = "Namespace - $($namespace)" + List = $true + ColumnWidths = 25, 75 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VserverObj | Sort-Object -Property 'Namespace Name' | Table @TableParams + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index 11c788c..7d8dbf9 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 @@ -448,7 +448,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapVserverNvmeFcAdapter -Vserver $SVM } } - HomePort if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'ethernet' }) { + if (Get-NcNvmeInterface -VserverContext $Vserver -Controller $Array | Where-Object { $_.PhysicalProtocol -eq 'ethernet' }) { Section -ExcludeFromTOC -Style Heading6 'Nvme TCP Physical Adapter' { Get-AbrOntapVserverNvmeTcpAdapter -Vserver $SVM } @@ -518,6 +518,29 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { } } #---------------------------------------------------------------------------------------------# + # NameSpace & Subsystem Storage Section # + #---------------------------------------------------------------------------------------------# + if (Get-NcNvmeNamespace -Controller $Array | Where-Object { $_.Vserver -eq $SVM }) { + Section -Style Heading5 'Namespace Storage' { + Paragraph "The following section provides the Namespace Storage Information on $($SVM)." + BlankLine + Get-AbrOntapVserverNamespaceStorage -Vserver $SVM + # if (Get-NcIgroup -Vserver $SVM -Controller $Array) { + # Section -ExcludeFromTOC -Style Heading6 'Igroup Mapping' { + # Get-AbrOntapVserverLunIgroup -Vserver $SVM + # } + # $NonMappedLun = Get-AbrOntapVserverNonMappedLun -Vserver $SVM + # if ($Healthcheck.Vserver.Status -and $NonMappedLunFCP) { + # Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Lun Information' { + # Paragraph "The following section provides information of Non Mapped Lun on $($SVM)." + # BlankLine + # $NonMappedLun + # } + # } + # } + } + } + #---------------------------------------------------------------------------------------------# # Consistency Groups Section # #---------------------------------------------------------------------------------------------# $CGs = Get-NetAppOntapAPI -uri "/api/application/consistency-groups?svm=$SVM&fields=**&return_records=true&return_timeout=15" From 7090cb2872dfebedb3d11f1cccd117a0c3acbb17 Mon Sep 17 00:00:00 2001 From: Jonathan Colon Date: Fri, 9 Aug 2024 15:43:28 -0400 Subject: [PATCH 2/2] Improvements to NVME section --- Src/Private/Get-AbrOntapEfficiencyAggr.ps1 | 2 +- Src/Private/Get-AbrOntapNetworkMGMT.ps1 | 2 +- .../Get-AbrOntapVserverCGNamespace.ps1 | 85 +++++++++++++++++++ .../Get-AbrOntapVserverNonMappedNamespace.ps1 | 70 +++++++++++++++ Src/Private/Get-AbrOntapVserverSubsystem.ps1 | 82 ++++++++++++++++++ .../Invoke-AsBuiltReport.NetApp.ONTAP.ps1 | 33 ++++--- 6 files changed, 258 insertions(+), 16 deletions(-) create mode 100755 Src/Private/Get-AbrOntapVserverCGNamespace.ps1 create mode 100755 Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 create mode 100755 Src/Private/Get-AbrOntapVserverSubsystem.ps1 diff --git a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 b/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 index cfa2dfd..b6d7e08 100755 --- a/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 +++ b/Src/Private/Get-AbrOntapEfficiencyAggr.ps1 @@ -91,7 +91,7 @@ function Get-AbrOntapEfficiencyAggr { } if ($OutObj) { Section -Style Heading4 'HealthCheck - Volume with Disabled Deduplication' { - Paragraph "The following section provides the Volume efficiency healthcheck Information on $($ClusterInfo.ClusterName)." + Paragraph "The following table provides the Volume efficiency healthcheck Information on $($ClusterInfo.ClusterName)." BlankLine $OutObj | Table @TableParams } diff --git a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 index 829583d..c21f426 100755 --- a/Src/Private/Get-AbrOntapNetworkMGMT.ps1 +++ b/Src/Private/Get-AbrOntapNetworkMGMT.ps1 @@ -198,7 +198,7 @@ function Get-AbrOntapNetworkMgmt { try { if ((Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like "False" }) -and $Healthcheck.Network.Interface) { Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Check If Network Interface is Home' { - Paragraph "The following section provides the LIF Home Status Information on $($ClusterInfo.ClusterName)." + Paragraph "The following table provides the LIF Home Status Information on $($ClusterInfo.ClusterName)." BlankLine $ClusterData = Get-NcNetInterface -Controller $Array | Where-Object { $_.DataProtocols -ne 'fcp' -and $_.IsHome -like "False" } $ClusterObj = @() diff --git a/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 b/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 new file mode 100755 index 0000000..f7e093a --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverCGNamespace.ps1 @@ -0,0 +1,85 @@ +function Get-AbrOntapVserverCGNamespace { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP Vserver Consistency Groups Namespace information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.7 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + $CGObj + ) + + begin { + Write-PScriboMessage "Collecting ONTAP Vserver Consistency Groups namespace information." + } + + process { + try { + $NamespaceData = $CGObj.namespaces + $CGNamespaceObj = @() + if ($NamespaceData) { + foreach ($Item in $NamespaceData) { + try { + $inObj = [ordered] @{ + 'Name' = $Item.Name.Split('/')[3] + 'Capacity' = Switch ([string]::IsNullOrEmpty($Item.space.size)) { + $true { '-' } + $false { $Item.space.size | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } + default { '-' } + } + 'Used' = Switch ([string]::IsNullOrEmpty($Item.space.used)) { + $true { '-' } + $false { $Item.space.used | ConvertTo-FormattedNumber -Type Datasize -ErrorAction SilentlyContinue } + default { '-' } + } + 'OS Type' = ConvertTo-EmptyToFiller $Item.os_type + 'Volume State' = $Item.status.container_state + 'Mapped' = ConvertTo-TextYN $Item.status.mapped + 'Read Only' = ConvertTo-TextYN $Item.status.read_only + 'State' = $Item.status.state + + + } + $CGNamespaceObj += [pscustomobject]$inobj + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + if ($Healthcheck.Vserver.CG) { + $CGNamespaceObj | Where-Object { $_.'Volume State' -ne 'online' } | Set-Style -Style Warning -Property 'Volume State' + $CGNamespaceObj | Where-Object { $_.'Mapped' -eq 'No' } | Set-Style -Style Warning -Property 'Mapped' + $CGNamespaceObj | Where-Object { $_.'Read Only' -eq 'Yes' } | Set-Style -Style Warning -Property 'Read Only' + $CGNamespaceObj | Where-Object { $_.'State' -eq 'offline' } | Set-Style -Style Warning -Property 'State' + } + + $TableParams = @{ + Name = "Consistency Group Namespace - $($CGObj.Name)" + List = $false + ColumnWidths = 30, 10, 9, 10, 11, 10, 10, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $CGNamespaceObj | Sort-Object -Property Name | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 b/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 new file mode 100755 index 0000000..9b49d31 --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverNonMappedNamespace.ps1 @@ -0,0 +1,70 @@ +function Get-AbrOntapVserverNonMappedNamespace { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP NVMW Non Mapped amespace information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.7 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage "Collecting ONTAP NVME Non Mapped Namespace information." + } + + process { + try { + $NamespaceFilter = Get-NcNvmeNamespace -VserverContext $Vserver -Controller $Array | Where-Object { -Not $_.Subsystem } + $OutObj = @() + if ($NamespaceFilter) { + foreach ($Item in $NamespaceFilter) { + try { + $namespacename = (($Item.Path).split('/'))[3] + $inObj = [ordered] @{ + 'Volume Name' = $Item.Volume + 'Lun Name' = $namespacename + 'Type' = $Item.Ostype + 'Mapped' = "No" + 'State' = $Item.State + } + $OutObj += [pscustomobject]$inobj + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + if ($Healthcheck.Vserver.Status) { + $OutObj | Set-Style -Style Warning + } + + $TableParams = @{ + Name = "HealthCheck - Non-Mapped Namespace - $($Vserver)" + List = $false + ColumnWidths = 30, 30, 10, 10, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Private/Get-AbrOntapVserverSubsystem.ps1 b/Src/Private/Get-AbrOntapVserverSubsystem.ps1 new file mode 100755 index 0000000..1b90ff6 --- /dev/null +++ b/Src/Private/Get-AbrOntapVserverSubsystem.ps1 @@ -0,0 +1,82 @@ +function Get-AbrOntapVserverSubsystem { + <# + .SYNOPSIS + Used by As Built Report to retrieve NetApp ONTAP vserver subsystem information from the Cluster Management Network + .DESCRIPTION + + .NOTES + Version: 0.6.7 + Author: Jonathan Colon + Twitter: @jcolonfzenpr + Github: rebelinux + .EXAMPLE + + .LINK + + #> + param ( + [Parameter ( + Position = 0, + Mandatory)] + [string] + $Vserver + ) + + begin { + Write-PScriboMessage "Collecting ONTAP Vserver Subsystem information." + } + + process { + try { + $VserverSubsystem = Get-NcNvmeSubsystem -VserverContext $Vserver -Controller $Array + $VserverObj = @() + if ($VserverSubsystem) { + foreach ($Item in $VserverSubsystem) { + try { + $namespacemap = Get-NcNvmeSubsystemMap -Controller $Array | Where-Object { $_.Subsystem -eq $Item.Subsystem } | Select-Object -ExpandProperty Path + $MappedNamespace = @() + foreach ($namespace in $namespacemap) { + try { + $namespacename = $namespace.split('/') + $MappedNamespace += $namespacename[3] + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + $inObj = [ordered] @{ + 'Subsystem Name' = $Item.Subsystem + 'Type' = $Item.Ostype + 'Target NQN' = $Item.TargetNqn + 'Host NQN' = $Item.Hosts.Nqn + 'Mapped Namespace' = Switch (($MappedNamespace).count) { + 0 { "None" } + default { $MappedNamespace } + } + } + $VserverObj = [pscustomobject]$inobj + if ($Healthcheck.Vserver.Status) { + $VserverObj | Where-Object { ($_.'Mapped Namespace').count -eq 0 } | Set-Style -Style Warning -Property 'Mapped Namespace' + } + + $TableParams = @{ + Name = "Subsystem - $($Item.Subsystem)" + List = $true + ColumnWidths = 25, 75 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VserverObj | Table @TableParams + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + + end {} + +} \ No newline at end of file diff --git a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 index 7d8dbf9..a3a2f2b 100755 --- a/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 +++ b/Src/Public/Invoke-AsBuiltReport.NetApp.ONTAP.ps1 @@ -507,7 +507,7 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapVserverLunIgroup -Vserver $SVM } $NonMappedLun = Get-AbrOntapVserverNonMappedLun -Vserver $SVM - if ($Healthcheck.Vserver.Status -and $NonMappedLunFCP) { + if ($Healthcheck.Vserver.Status -and $NonMappedLun) { Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Lun Information' { Paragraph "The following section provides information of Non Mapped Lun on $($SVM)." BlankLine @@ -525,19 +525,19 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Paragraph "The following section provides the Namespace Storage Information on $($SVM)." BlankLine Get-AbrOntapVserverNamespaceStorage -Vserver $SVM - # if (Get-NcIgroup -Vserver $SVM -Controller $Array) { - # Section -ExcludeFromTOC -Style Heading6 'Igroup Mapping' { - # Get-AbrOntapVserverLunIgroup -Vserver $SVM - # } - # $NonMappedLun = Get-AbrOntapVserverNonMappedLun -Vserver $SVM - # if ($Healthcheck.Vserver.Status -and $NonMappedLunFCP) { - # Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Lun Information' { - # Paragraph "The following section provides information of Non Mapped Lun on $($SVM)." - # BlankLine - # $NonMappedLun - # } - # } - # } + if (Get-NcNvmeSubsystem -Vserver $SVM -Controller $Array) { + Section -ExcludeFromTOC -Style Heading6 'Subsystem Mapping' { + Get-AbrOntapVserverSubsystem -Vserver $SVM + } + $NonMappedNamespace = Get-AbrOntapVserverNonMappedNamespace -Vserver $SVM + if ($Healthcheck.Vserver.Status -and $NonMappedNamespace) { + Section -ExcludeFromTOC -Style Heading6 'HealthCheck - Non-Mapped Namespace Information' { + Paragraph "The following table provides information about Non Mapped Namespace on $($SVM)." + BlankLine + $NonMappedNamespace + } + } + } } } #---------------------------------------------------------------------------------------------# @@ -555,6 +555,11 @@ function Invoke-AsBuiltReport.NetApp.ONTAP { Get-AbrOntapVserverCGLun -CGObj $CG } } + if ($CG.namespaces) { + Section -ExcludeFromTOC -Style Heading6 "$($CG.name) Namespaces" { + Get-AbrOntapVserverCGNamespace -CGObj $CG + } + } } } }