Public/Get-KubeNodeDescription.ps1
|
Function Get-KubeNodeDescription { <# .SYNOPSIS Returns a rich description of one or more Kubernetes nodes, including labels, taints, conditions, addresses, system info, allocated resources, and the non-terminated pods currently running on each node. This command is the detailed node inspection tool in KubePS and is used by other node-oriented commands to gather capacity and workload information before summarizing it for users. .EXAMPLE Get-KubeNodeDescription -Node worker-1 # Returns the full metadata and scheduling information for worker-1. .EXAMPLE Get-KubeNodeDescription -Node worker-1 | Select-Object -ExpandProperty Conditions # Lists the current readiness, memory pressure, disk pressure, and PID pressure conditions for the node. .EXAMPLE Get-KubeNodeDescription -Node worker-1 | Select-Object -ExpandProperty AllocatedResources # Displays how much CPU and memory requests/limits are currently used by workloads on that node. #> [CmdletBinding()] param() DynamicParam { $DynamicParameterDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() $NewDynamicParams = @{ DynamicParameterDictionary = $DynamicParameterDictionary } $Nodes = Get-KubeNode $ParamList = @( @{ ParameterName = 'Node' ParameterType = ([string[]]) Mandatory = $True ValidateSet = [array]$Nodes.Name Alias = 'Name' ValueFromPipeline = $True ValueFromPipelineByPropertyName = $True HelpMessage = 'The node to describe' Position = 1 ParameterSetName = 'Node' } ) ForEach($Param in $ParamList) { Add-DynamicParameter @NewDynamicParams @Param } Return $DynamicParameterDictionary } Begin { [System.Collections.Generic.List[object]]$NodeNames = @() } Process { $NodeValues = $DynamicParameterDictionary['Node'].Value ForEach($NodeName in $NodeValues) { $NodeNames.Add($NodeName) } } End { ForEach($NodeName in $NodeNames) { $NodeItem = [k8s.CoreV1OperationsExtensions]::ReadNodeAsync( $Script:KubePSDirectClient.CoreV1, $NodeName ).GetAwaiter().GetResult() $Pods = [k8s.CoreV1OperationsExtensions]::ListPodForAllNamespacesAsync( $Script:KubePSDirectClient.CoreV1, $null, $null, "spec.nodeName=$NodeName" ).GetAwaiter().GetResult().Items | Where-Object { $_.Status.Phase -notin @('Succeeded', 'Failed') } $Capacity = [ordered]@{} $Allocatable = [ordered]@{} ForEach($Resource in $NodeItem.Status.Capacity.Keys) { $Capacity[$Resource] = [string]$NodeItem.Status.Capacity[$Resource] } ForEach($Resource in $NodeItem.Status.Allocatable.Keys) { $Allocatable[$Resource] = [string]$NodeItem.Status.Allocatable[$Resource] } $NonTerminatedPods = Get-NodeNonTerminatedPod -Pods $Pods -Node $NodeItem $AllocatedResources = Get-NodeAllocatedResource -Pod $Pods -Node $NodeItem $Labels = [ordered]@{} $Annotations = [ordered]@{} If($NodeItem.Metadata.Labels) { ForEach($Key in $NodeItem.Metadata.Labels.Keys) { $Labels[$Key] = $NodeItem.Metadata.Labels[$Key] } } If($NodeItem.Metadata.Annotations) { ForEach($Key in $NodeItem.Metadata.Annotations.Keys) { $Annotations[$Key] = $NodeItem.Metadata.Annotations[$Key] } } $Addresses = [ordered]@{} ForEach($Address in $NodeItem.Status.Addresses) { $Addresses[$Address.Type] = $Address.Address } $Conditions = @($NodeItem.Status.Conditions | ForEach-Object { [pscustomobject]@{ Type = $_.Type Status = $_.Status LastHeartbeatTime = $_.LastHeartbeatTime LastTransitionTime = $_.LastTransitionTime Reason = $_.Reason Message = $_.Message } }) $SystemInfo = [ordered]@{ MachineID = $NodeItem.Status.NodeInfo.MachineID SystemUUID = $NodeItem.Status.NodeInfo.SystemUUID BootID = $NodeItem.Status.NodeInfo.BootID KernelVersion = $NodeItem.Status.NodeInfo.KernelVersion OSImage = $NodeItem.Status.NodeInfo.OsImage ContainerRuntimeVersion = $NodeItem.Status.NodeInfo.ContainerRuntimeVersion KubeletVersion = $NodeItem.Status.NodeInfo.KubeletVersion KubeProxyVersion = $NodeItem.Status.NodeInfo.KubeProxyVersion OperatingSystem = $NodeItem.Status.NodeInfo.OperatingSystem Architecture = $NodeItem.Status.NodeInfo.Architecture } $Lease = [ordered]@{} Try { $LeaseItem = [k8s.CoordinationV1OperationsExtensions]::ReadNamespacedLeaseAsync( $Script:KubePSDirectClient.CoordinationV1, $NodeName, 'kube-node-lease' ).GetAwaiter().GetResult() $Lease = [ordered]@{ HolderIdentity = $LeaseItem.Spec.HolderIdentity LeaseDurationSeconds = $LeaseItem.Spec.LeaseDurationSeconds AcquireTime = $LeaseItem.Spec.AcquireTime RenewTime = $LeaseItem.Spec.RenewTime LeaseTransitions = $LeaseItem.Spec.LeaseTransitions } } Catch [k8s.Autorest.HttpOperationException] { If($_.Exception.Response.StatusCode -ne [System.Net.HttpStatusCode]::NotFound) { Throw } } $Events = [k8s.CoreV1OperationsExtensions]::ListEventForAllNamespacesAsync( $Script:KubePSDirectClient.CoreV1, $null, $null, "involvedObject.name=$NodeName,involvedObject.kind=Node" ).GetAwaiter().GetResult().Items | Where-Object { $_.InvolvedObject.Name -eq $NodeName -and $_.InvolvedObject.Kind -eq 'Node' } | ForEach-Object { $EventTime = If($_.LastTimestamp) { $_.LastTimestamp } ElseIf($_.EventTime) { $_.EventTime } Else { $_.Metadata.CreationTimestamp } [pscustomobject]@{ Type = $_.Type Reason = $_.Reason Age = Resolve-KubeResourceAge -Timestamp ([string]$EventTime) From = $_.Source.Component Message = $_.Message } } [pscustomobject]@{ PSTypeName = 'KubePS.NodeDescription' Name = $NodeItem.Metadata.Name Roles = (@($Labels.Keys | Where-Object { $_ -like 'node-role.kubernetes.io/*' } | ForEach-Object { $_.Substring('node-role.kubernetes.io/'.Length) }) -join ',') Labels = $Labels Annotations = $Annotations CreationTimestamp = $NodeItem.Metadata.CreationTimestamp Taints = @($NodeItem.Spec.Taints | ForEach-Object { "$($_.Key)=$($_.Value):$($_.Effect)" }) -join ',' Unschedulable = [bool]$NodeItem.Spec.Unschedulable Addresses = $Addresses Lease = $Lease Conditions = $Conditions Capacity = $Capacity Allocatable = $Allocatable SystemInfo = $SystemInfo NonTerminatedPods = @($NonTerminatedPods) AllocatedResources = @($AllocatedResources) Events = @($Events) Sections = [ordered]@{} } } } } |