Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions agents/windows/plugins/hyperv_cluster.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#
# all the output should be changed to a tables format with keys as column names
# or better you should get directly json output
#

function Get-ClusterInfo()
{
'<<<hyperv_cluster_general>>>'
# get cluster core data
$cluster = Get-Cluster
Write-Host 'cluster.name' $cluster.Name

# get cluster IP address
$clusterGroup = Get-ClusterGroup | Where-Object { $_.GroupType -eq 'Cluster' }
$clusterIP = Get-ClusterResource | Where-Object { $_.ResourceType -eq 'IP Address' -and $_.OwnerGroup -eq $clusterGroup } | Get-ClusterParameter Address
$clusterSubnet = Get-ClusterResource | Where-Object { $_.ResourceType -eq 'IP Address' -and $_.OwnerGroup -eq $clusterGroup } | Get-ClusterParameter SubnetMask
Write-Host 'cluster.ip' $clusterIP.Value
Write-Host 'cluster.subnet' $clusterSubnet.Value

# get quorum config and resource
$quorum = Get-ClusterQuorum
Write-Host 'quorum.resourcename' ($quorum.QuorumResource.Name)
Write-Host 'quorum.type' ($quorum.QuorumType)


# check for S2D presence
'<<<hyperv_cluster_s2d>>>'
if ($null -ne (Get-Command Get-ClusterStorageSpacesDirect -ErrorAction SilentlyContinue)) {
$S2D = (Get-ClusterStorageSpacesDirect -ErrorAction SilentlyContinue)
if ($null -ne $S2D) {
Write-Host 'S2D' ($S2D.State)
Write-Host 'S2D.name' ($S2D.Name)
Write-Host 'S2D.cachemode.HDD' ($S2D.CacheModeHDD)
Write-Host 'S2D.cachemode.SSD' ($S2D.CacheModeSSD)
Write-Host 'S2D.cache.device_model' ($S2D.CacheDeviceModel)
Write-Host 'S2D.cache.metadata_reserve_bytes' ($S2D.CacheMetadataReserveBytes)
Write-Host 'S2D.cache.page_size_kbytes' ($S2D.CachePageSizeKBytes)

}
}

# get cluster nodes
'<<<hyperv_cluster_nodes>>>'
$clusterNodes = (Get-ClusterNode | Sort-Object ID)
Write-Host 'cluster.number_of_nodes' ($clusterNodes.Count)

foreach ($clusterNode in $clusterNodes)
{
Write-Host 'cluster.node.name' ($clusterNode.Name)
Write-Host 'cluster.node.id ' ($clusterNode.ID)
Write-Host 'cluster.node.state' ($clusterNode.State)
Write-Host 'cluster.node.info' ($clusterNoder.StatusInformation)
Write-Host 'cluster.node.weight' ($clusterNode.NodeWeight)
Write-Host 'cluster.node_vendor.manufacturer' ($clusterNode.Manufacturer)
Write-Host 'cluster.node_vendor.model' ($clusterNode.Model)
Write-Host 'cluster.node_vendor.serial' ($clusterNode.SerialNumber)
}

# get cluster networks
'<<<hyperv_cluster_network>>>'
$clusterNetworks = (Get-ClusterNetwork | Sort-Object Name)
Write-Host 'cluster.number_of_networks' ($clusterNetworks.Count)
foreach($clusterNetwork in $clusterNetworks)
{
Write-Host 'cluster.network.name' ($clusterNetwork.Name)
Write-Host 'cluster.network.role' ([string]$clusterNetwork.Role)
Write-Host 'cluster.network.state' ($clusterNetwork.State)
Write-Host 'cluster.network.ip' ($clusterNetwork.Address)
Write-Host 'cluster.network.netmask' ($clusterNetwork.Addressmask)
Write-Host 'cluster.network.ipv4_address' ($clusterNetwork.Ipv4Addresses)
Write-Host 'cluster.network.ipv6_address' ($clusterNetwork.Ipv6Addresses)
}

# get cluster disks (non-CSV first, then CSV)
'<<<hyperv_cluster_disks>>>'
$ClusterDisks = (Get-ClusterResource | Where-Object {$_.ResourceType -eq 'Physical Disk'} | Sort-Object OwnerGroup,Name)
Write-Host 'cluster.number_of_disks' ($ClusterDisks.Count)

foreach ($Disk in $ClusterDisks)
{
Write-Host 'cluster.disk.name' ($Disk.Name)
Write-Host 'cluster.disk.owner_group' ($Disk.OwnerGroup)
Write-Host 'cluster.disk.owner_node' ($Disk.OwnerNode)
Write-Host 'cluster.disk.state' ($Disk.State)

}

# get CSVs
'<<<hyperv_cluster_csv>>>'
$clusterSharedVolume = (Get-ClusterSharedVolume -Cluster $cluster | Sort-Object Name)
Write-Host 'cluster.number_of_csv' ($clusterSharedVolume.Count)

foreach ($CSV in $clusterSharedVolume)
{
Write-Host 'cluster.csv.name' ($CSV.Name)
Write-Host 'cluster.csv.owner' ($CSV.OwnerNode)
foreach ($CSVInfo in $CSV.SharedVolumeInfo)
{
Write-Host 'cluster.csv.volume' ($CSVInfo.FriendlyVolumeName)
$CSVVolume = Get-ClusterSharedVolume -Name $CSV.Name | select -Expand SharedVolumeInfo | select -Expand Partition
Write-Host 'cluster.csv.size' ($CSVVolume.Size)
Write-Host 'cluster.csv.free_space' ($CSVVolume.FreeSpace)
Write-Host 'cluster.csv.used_space' ($CSVVolume.UsedSpace)
}
}

# get clustered VMs
'<<<hyperv_cluster_roles>>>'
$arrClusterVMs = (Get-ClusterGroup -Cluster $cluster | Where-Object {$_.GroupType -eq 'VirtualMachine'} | Sort-Object Name)
if ($arrClusterVMs.length -ne 0)
{
Write-Host 'cluster.number_of_vms' $arrClusterVMs.length
foreach ($clusterVM in $arrClusterVMs)
{
Write-Host 'cluster.vm.name' ($clusterVM.Name)
Write-Host 'cluster.vm.state' ($clusterVM.State)
Write-Host 'cluster.vm.owner' ($clusterVM.OwnerNode)
}
}

# get additional cluster roles
'<<<hyperv_cluster_additional_roles>>>'
$arrRolesToIgnore = 'VirtualMachine', 'Cluster', 'AvailableStorage'
$arrClusterGroups = (Get-ClusterGroup -Cluster $cluster | Where-Object {$arrRolesToIgnore -notcontains $_.GroupType} | Sort-Object Name)
if ($arrClusterGroups.length -ne 0)
{
Write-Host 'cluster.number_of_roles' ($arrClusterGroups.length)

foreach ($clusterRole in $arrClusterGroups)
{
Write-Host 'cluster.role.name' ($clusterRole.Name)
Write-Host 'cluster.role.state' ($clusterRole.State)
Write-Host 'cluster.role.type' ($clusterRole.GroupType)
Write-Host 'cluster.role.owner' ($clusterRole.OwnerNode)
}
}

# determine CAU availability
'<<<hyperv_cluster_updater>>>'
$CAU = (Get-ClusterResource -Cluster $cluster | Where-Object { $_.ResourceType -eq 'ClusterAwareUpdatingResource' })
if ($null -ne $CAU) {
Write-Host 'cluster.cau.state' ($CAU.State)
Write-Host 'cluster.cau.name' ($CAU.OwnerGroup)
} else {
Write-Host 'cluster.cau.state not installed'
Write-Host 'cluster.cau.name -'
}
}

Get-ClusterInfo
91 changes: 91 additions & 0 deletions agents/windows/plugins/hyperv_host_csv_io.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#
# all the output should be changed to a tables format with keys as column names
# or better you should get directly json output
#


"<<<hyperv_host_io_local>>>"

$MaxSamples = 1
$Interval = 1

$Counters = @('\PhysicalDisk(*)\Current Disk Queue Length','\PhysicalDisk(*)\% Disk Time','\PhysicalDisk(*)\Avg. Disk Queue Length','\PhysicalDisk(*)\% Disk Read Time','\PhysicalDisk(*)\Avg. Disk Read Queue Length','\PhysicalDisk(*)\% Disk Write Time','\PhysicalDisk(*)\Avg. Disk Write Queue Length','\PhysicalDisk(*)\Avg. Disk sec/Transfer','\PhysicalDisk(*)\Avg. Disk sec/Read','\PhysicalDisk(*)\Avg. Disk sec/Write','\PhysicalDisk(*)\Disk Transfers/sec','\PhysicalDisk(*)\Disk Reads/sec','\PhysicalDisk(*)\Disk Writes/sec','\PhysicalDisk(*)\Disk Bytes/sec','\PhysicalDisk(*)\Disk Read Bytes/sec','\PhysicalDisk(*)\Disk Write Bytes/sec','\PhysicalDisk(*)\Avg. Disk Bytes/Transfer','\PhysicalDisk(*)\Avg. Disk Bytes/Read','\PhysicalDisk(*)\Avg. Disk Bytes/Write','\PhysicalDisk(*)\% Idle Time','\PhysicalDisk(*)\Split IO/Sec')

$Splat = @{
Counter = $Counters
MaxSamples = $MaxSamples
SampleInterval = $Interval
}

$customobjects = @()

Get-Counter @Splat | ForEach {
$_.CounterSamples | ForEach {
$customobjects += [pscustomobject]@{
Path = $_.Path
Value = $_.CookedValue
}
}
}

$counts = @()
$remotecounts = @()
$idtolun = @{}

$csvs = Get-ClusterSharedVolume
foreach ( $csv in $csvs )
{
if ($csv | Where-Object {$_.OwnerNode -match $env:COMPUTERNAME})
{
$diskguid = ($csv | Get-ClusterParameter DiskIdGuid).Value
$lunid = $csv.Name
$disk = get-disk | Where-Object {$_.guid -match $diskguid}
$diskid = $disk.DiskNumber
$idtolun[$diskid] = $lunid
$counts += $disk
}
else {
$diskguid = ($csv | Get-ClusterParameter DiskIdGuid).Value
$lunid = $csv.Name
$disk = get-disk | Where-Object {$_.guid -match $diskguid}
$diskid = $disk.DiskNumber
$idtolun[$diskid] = $lunid
$remotecounts += $disk
}
}

$resultlist = @()

foreach ( $volume in $counts) {
foreach ( $element in $customobjects) {
$checkString = $volume.Number
if ($element.Path -match "\($checkString\)") {
$element.Path = [regex]::Replace($element.Path, '\\\\.*\\physicaldisk\(.*\)\\',$idtolun[$checkString]+'\')
$resultlist += $element
}
}
}

$hostname = $env:COMPUTERNAME.ToLower()

$resultlist | select Path, Value | % {
$_.Path = [regex]::Replace($_.Path, "\\\\$hostname\\physicaldisk\([0-9]+\)","");
$_.Value = $_.Value;
return $_;
} | ft -HideTableHeaders

'<<<hyperv_host_io_remote>>>'

$resultlist = @()

foreach ( $volume in $remotecounts) {
foreach ( $element in $customobjects) {
$checkString = $volume.Number
if ($element.Path -match "\($checkString\)") {
$element.Path = [regex]::Replace($element.Path, '\\\\.*\\physicaldisk\(.*\)\\',$idtolun[$checkString]+'\')
$resultlist += $element
}
}
}

$resultlist | ft -HideTableHeaders
72 changes: 72 additions & 0 deletions cmk/plugins/hyperv/agent_based/hyperv_cluster_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/python
# # -*- encoding: utf-8; py-indent-offset: 4 -*-

from collections.abc import Mapping
from typing import Any, Dict

from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
CheckResult,
DiscoveryResult,
Result,
Service,
State,
get_value_store,
render,
)
from cmk.plugins.lib.df import FILESYSTEM_DEFAULT_PARAMS, df_check_filesystem_single
from cmk.plugins.hyperv.lib import parse_hyperv

Section = Dict[str, Mapping[str, Any]]


def discovery_hyperv_cluster_csv(section: Section) -> DiscoveryResult:
for csv in section.keys():
yield Service(item=csv)


def check_hyperv_cluster_csv(
item: str, params: Mapping[str, Any], section: Section
) -> CheckResult:
value_store = get_value_store()
csv = section.get(item, "")

if not csv:
yield Result(state=State(3), summary="CSV not found in agent output")
return

mega = 1024.0 * 1024.0
size_total = int(csv.get("cluster.csv.size")) / mega
size_avail = int(csv.get("cluster.csv.free_space")) / mega

if section.get("ignore_levels"):
message = f"Total size: {render.bytes(size_total)}, Used space is ignored"
yield Result(state=State(0), summary=message)
else:
yield from df_check_filesystem_single(
value_store,
item,
size_total,
size_avail,
0,
None,
None,
params=params,
)


agent_section_hyperv_cluster_csv = AgentSection(
name="hyperv_cluster_csv",
parse_function=parse_hyperv,
)

check_plugin_hyperv_cluster_csv = CheckPlugin(
name="hyperv_cluster_csv",
service_name="HyperV CSV %s",
sections=["hyperv_cluster_csv"],
discovery_function=discovery_hyperv_cluster_csv,
check_function=check_hyperv_cluster_csv,
check_ruleset_name="filesystem",
check_default_parameters=FILESYSTEM_DEFAULT_PARAMS,
)
51 changes: 51 additions & 0 deletions cmk/plugins/hyperv/agent_based/hyperv_cluster_disks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/python
# # -*- encoding: utf-8; py-indent-offset: 4 -*-

from cmk.agent_based.v2 import (
AgentSection,
CheckPlugin,
CheckResult,
DiscoveryResult,
Result,
Service,
State,
)
from cmk.plugins.hyperv.lib import parse_hyperv


def discovery_hyperv_cluster_disks(section) -> DiscoveryResult:
for disk in section.keys():
yield Service(item=disk)


def check_hyperv_cluster_disks(item: str, section) -> CheckResult:

disk = section.get(item, "")

if not disk:
yield Result(state=State(3), summary="Disk not found in agent output")
return

state = 0
if disk["cluster.disk.state"] != "Online":
state = 3
message = "is %s, with owner %s and group %s." % (
disk["cluster.disk.state"],
disk["cluster.disk.owner_node"],
disk["cluster.disk.owner_group"],
)
yield Result(state=State(state), summary=message)


agent_section_hyperv_cluster_disks = AgentSection(
name="hyperv_cluster_disks",
parse_function=parse_hyperv,
)

check_plugin_hyperv_cluster_disks = CheckPlugin(
name="hyperv_cluster_disks",
service_name="HyperV Disk %s",
sections=["hyperv_cluster_disks"],
discovery_function=discovery_hyperv_cluster_disks,
check_function=check_hyperv_cluster_disks,
)
Loading
Loading