|
function format-file-size { |
|
param ($size) |
|
|
|
if ($size -gt 1TB) {[string]::Format("{0:n2} TB", $size / 1TB)} |
|
elseIf ($size -gt 1GB) {[string]::Format("{0:n2} GB", $size / 1GB)} |
|
elseIf ($size -gt 1MB) {[string]::Format("{0:n2} MB", $size / 1MB)} |
|
elseIf ($size -gt 1KB) {[string]::Format("{0:n2} KB", $size / 1KB)} |
|
elseIf ($size -gt 0) {[string]::Format("{0:n2} B", $size)} |
|
else {"0 B"} |
|
} |
|
|
|
$resultDir = (Resolve-Path ".").Path |
|
$resultDir = "$resultDir\$($(hostname).ToLower())_$((get-date).ToString('yyyyMMdd'))" |
|
|
|
Remove-Item -Path $resultDir -Recurse -Force -ErrorAction Ignore | Out-Null |
|
New-Item -Type Directory -Path $resultDir -ErrorAction Ignore | Out-Null |
|
|
|
Describe "Host" { |
|
$osVersion = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' |
|
|
|
Context "Prerequisites" { |
|
It "Is Windows Server" { |
|
(Get-ComputerInfo).WindowsInstallationType | Should Be 'Server' |
|
} |
|
|
|
It "Is 'Windows Server 2019' or 'Windows Server, version 1809'" { |
|
$osVersion.CurrentBuildNumber -ge 17763 | Should Be $true |
|
} |
|
|
|
It "Support 'VxLAN' network (has KB4489899 installed)" { |
|
$osVersion.UBR | Should Not BeLessThan 379 |
|
} |
|
|
|
It "Not in the non-recommended Windows Server UBR version range: [404, 504]" { |
|
# https://github.com/rancher/rancher/issues/20440 reports that could not schedule more than 10 Pods on the Windows node which belongs to the UBR version range [404, 504]: |
|
|
|
(($osVersion.UBR -ge 404) -and ($osVersion.UBR -le 504)) | Should Be $false |
|
} |
|
|
|
It "Has 'Containers' feature installed" { |
|
(Get-WindowsFeature -Name Containers).InstallState | Should Be 'Installed' |
|
} |
|
} |
|
|
|
Context "Snapshot" { |
|
It "Get OS info" { |
|
{ "`n# OS info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
$osVersion | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get system info" { |
|
{ |
|
"`n# System info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
systeminfo | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
|
|
} | Should Not Throw |
|
} |
|
|
|
It "Get CPU info" { |
|
{ |
|
"`n# CPU info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
Get-WmiObject -Class Win32_Processor | Select DeviceID,Name,NumberOfCores,NumberOfLogicalProcessors | ` |
|
Format-List | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
|
|
} | Should Not Throw |
|
} |
|
|
|
It "Get disk info" { |
|
{ |
|
"`n# Disk info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
Get-Volume | Format-List | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
|
|
} | Should Not Throw |
|
} |
|
|
|
It "Get memory info" { |
|
{ |
|
"`n# Memory info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
New-Object -Typename PSObject -Property @{ ` |
|
Total=(Get-WmiObject -Class Win32_PhysicalMemory | Measure-Object -Sum -Property Capacity | % { format-file-size($_.Sum) }); ` |
|
Available=(Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Memory | Measure-Object -Sum -Property AvailableBytes | % { format-file-size($_.Sum) }); |
|
} | Format-List | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get hotfix" { |
|
{ |
|
"`n# Hotfix info #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
Get-hotfix | Sort-Object InstalledOn -Descending | Format-List | Out-File -Append -Encoding utf8 -FilePath "$resultDir\host-info.txt" |
|
} | Should Not Throw |
|
} |
|
} |
|
} |
|
|
|
Describe "Docker" { |
|
$dockerService = Get-Service -Name Docker -ErrorAction Ignore |
|
$dockerService | Select Name,Status,DisplayName,StartType | Out-File -Append -Encoding utf8 -FilePath "$resultDir\docker-info.txt" |
|
|
|
Context "Prerequisites" { |
|
It "Has Docker installed" { |
|
$dockerService | Should Not BeNullOrEmpty |
|
} |
|
|
|
It "Is Dockerd start automatically" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} |
|
|
|
$dockerService.StartType | Should Be 'Automatic' |
|
} |
|
|
|
It "Is Dockerd registered in the EventLog service" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} |
|
|
|
Test-Path "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\docker" | Should Be $true |
|
} |
|
|
|
It "Is Dockerd running" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} |
|
|
|
$dockerService.Status | Should Be 'Running' |
|
} |
|
|
|
It "Has permissions to use Dockerd" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
$stdout = New-TemporaryFile |
|
$stderr = New-TemporaryFile |
|
|
|
{ |
|
Start-Process -NoNewWindow -Wait ` |
|
-FilePath docker.exe ` |
|
-ArgumentList "info" ` |
|
-RedirectStandardOutput $stdout.FullName ` |
|
-RedirectStandardError $stderr.FullName |
|
} | Should Not Throw |
|
$stdout.FullName | Should Not Contain "access is denied" |
|
$stderr.FullName | Should Not Contain "access is denied" |
|
|
|
$stdout.Delete() |
|
$stderr.Delete() |
|
} |
|
|
|
It "Is Enterprise Docker" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
$stdout = New-TemporaryFile |
|
$stderr = New-TemporaryFile |
|
|
|
{ |
|
Start-Process -NoNewWindow -Wait ` |
|
-FilePath docker.exe ` |
|
-ArgumentList @("version", "-f", "{{.Server.Platform.Name}}") ` |
|
-RedirectStandardOutput $stdout.FullName ` |
|
-RedirectStandardError $stderr.FullName |
|
} | Should Not Throw |
|
$stdout.FullName | Should Contain "Enterprise" |
|
|
|
$stdout.Delete() |
|
$stderr.Delete() |
|
} |
|
|
|
It "Should install at least one of 'mcr.microsoft.com/windows/servercore', 'mcr.microsoft.com/windows/nanoserver', 'mcr.microsoft.com/windows' or deprecated microsoft/windowsservercore, microsoft/nanoserver" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
$dockerImages = docker.exe image ls --format '{{json .}}' | ConvertFrom-Json | ? { ($_.Repository -like 'mcr.microsoft.com/*') -or ($_.Repository -like 'microsoft/*') } |
|
|
|
($dockerImages | Measure-Object).Count | Should Not BeNullOrEmpty |
|
} |
|
} |
|
|
|
Context "Snapshot" { |
|
function dck { |
|
$stdout = New-TemporaryFile |
|
$stderr = New-TemporaryFile |
|
|
|
Start-Process -NoNewWindow -Wait ` |
|
-FilePath docker.exe ` |
|
-ArgumentList $args ` |
|
-RedirectStandardOutput $stdout.FullName ` |
|
-RedirectStandardError $stderr.FullName |
|
|
|
"`n# docker $($args -join " ") #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\docker-info.txt" |
|
Get-Content $stdout.FullName, $stderr.FullName | Out-File -Append -Encoding utf8 -FilePath "$resultDir\docker-info.txt" |
|
|
|
$stdout.Delete() |
|
$stderr.Delete() |
|
} |
|
|
|
It "docker info" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
{ |
|
dck info |
|
} | Should Not Throw |
|
} |
|
|
|
It "docker version" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
{ |
|
dck version |
|
} | Should Not Throw |
|
} |
|
|
|
It "docker image ls" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
{ |
|
dck image ls |
|
} | Should Not Throw |
|
} |
|
|
|
It "docker ps -a" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
{ |
|
dck ps -a |
|
} | Should Not Throw |
|
} |
|
|
|
It "docker system df" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} elseif ($dockerService.Status -ne 'Running') { |
|
Set-TestInconclusive -Message ('Docker service is {0}' -f $dockerService.Status) |
|
} |
|
|
|
{ |
|
dck system df |
|
} | Should Not Throw |
|
} |
|
} |
|
|
|
Context "Collect EventLogs" { |
|
$eventLogProviders = @("Docker") |
|
|
|
It "Export logs in last hour" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} |
|
|
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-1))} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\docker-lasthour-logs.csv" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export warning & error logs in last day" { |
|
if (-not $dockerService) { |
|
Set-TestInconclusive -Message 'Could not find Docker service' |
|
} |
|
|
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-24)); Level=@(3,2,1,0)} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\docker-lastday-errlogs.csv" |
|
} | Should Not Throw |
|
} |
|
} |
|
} |
|
|
|
Describe "Rancher Agent" { |
|
$rancherService = Get-Service -Name rancher-agent -ErrorAction Ignore |
|
$rancherService | Select Name,Status,DisplayName,StartType | Out-File -Encoding utf8 -FilePath "$resultDir\agent-info.txt" |
|
|
|
Context "Prerequisites" { |
|
It "Has Rancher Agent installed" { |
|
$rancherService | Should Not BeNullOrEmpty |
|
} |
|
|
|
It "Is Rancher Agent start automatically" { |
|
if (-not $rancherService) { |
|
Set-TestInconclusive -Message 'Could not find Rancher Agent service' |
|
} |
|
|
|
$rancherService.StartType | Should Be 'Automatic' |
|
} |
|
} |
|
|
|
Context "Collect EventLogs" { |
|
$eventLogProviders = @("rancher-agent") |
|
|
|
It "Export logs in last week hours" { |
|
if (-not $rancherService) { |
|
Set-TestInconclusive -Message 'Could not find Rancher Agent service' |
|
} |
|
|
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(7 * -24))} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\agent-lastweek-logs.csv" |
|
} | Should Not Throw |
|
} |
|
} |
|
} |
|
|
|
Describe "Kubernetes Components" { |
|
Context "Prerequisites" { |
|
function log-process-info { |
|
param ( |
|
[parameter(Mandatory = $true)] [string]$Name, |
|
[parameter(Mandatory = $false)] [string]$ID, |
|
[parameter(Mandatory = $false)] [string]$Path |
|
) |
|
|
|
"`n# $Name #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\kubecmp-info.txt" |
|
|
|
$ret = $null |
|
if ($ID) { |
|
$ret = (Get-WmiObject -Class Win32_Process -Filter "Handle=$ID").CommandLine |
|
} else { |
|
$ret = Get-Content -Path $path |
|
} |
|
$ret | Out-File -Append -Encoding utf8 -FilePath "$resultDir\kubecmp-info.txt" |
|
} |
|
|
|
It "Is kubelet running" { |
|
$process = Get-Process -Name "kubelet" -ErrorAction Ignore |
|
$process | Should Not BeNullOrEmpty |
|
|
|
log-process-info -Name "kubelet" -ID $process.ID |
|
} |
|
|
|
It "Is kube-proxy running" { |
|
$process = Get-Process -Name "kube-proxy" -ErrorAction Ignore |
|
$process | Should Not BeNullOrEmpty |
|
|
|
log-process-info -Name "kube-proxy" -ID $process.ID |
|
} |
|
|
|
It "Is flanneld running" { |
|
$process = Get-Process -Name "flanneld" -ErrorAction Ignore |
|
$process | Should Not BeNullOrEmpty |
|
|
|
log-process-info -Name "flanneld" -ID $process.ID |
|
} |
|
|
|
It "Is nginx running" { |
|
$process = Get-Process -Name "nginx*" -ErrorAction Ignore |
|
$process | Should Not BeNullOrEmpty |
|
|
|
log-process-info -Name "nginx" -Path c:\etc\nginx\nginx.conf |
|
} |
|
} |
|
|
|
Context "Collect Logs" { |
|
$count = 100 |
|
|
|
It "Copy kubelet last $count logs" { |
|
$path = "c:\var\log\kubelet.log" |
|
if (-not (Test-Path $path)) { |
|
Set-TestInconclusive -Message "Could not find $path" |
|
} |
|
|
|
{ |
|
Get-Content -Path $path -Tail $count -ErrorAction Ignore | Out-File -Encoding utf8 -FilePath "$resultDir\kubelet-last$count-logs.txt" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Copy kube-proxy last $count logs" { |
|
$path = "c:\var\log\kubeproxy.log" |
|
if (-not (Test-Path $path)) { |
|
Set-TestInconclusive -Message "Could not find $path" |
|
} |
|
|
|
{ |
|
Get-Content -Path $path -Tail $count -ErrorAction Ignore | Out-File -Encoding utf8 -FilePath "$resultDir\kubeproxy-last$count-logs.txt" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Copy flanneld last $count logs" { |
|
$path = "c:\var\log\flanneld.log" |
|
if (-not (Test-Path $path)) { |
|
Set-TestInconclusive -Message "Could not find $path" |
|
} |
|
|
|
{ |
|
Get-Content -Path $path -Tail $count -ErrorAction Ignore | Out-File -Encoding utf8 -FilePath "$resultDir\flanneld-last$count-logs.txt" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Copy nginx last $count logs" { |
|
$path = "c:\var\log\nginx.log" |
|
if (-not (Test-Path $path)) { |
|
Set-TestInconclusive -Message "Could not find $path" |
|
} |
|
|
|
{ |
|
Get-Content -Path $path -Tail $count -ErrorAction Ignore | Out-File -Encoding utf8 -FilePath "$resultDir\nginx-last$count-logs.txt" |
|
} | Should Not Throw |
|
} |
|
} |
|
|
|
Context "Collect EventLogs" { |
|
$eventLogProviders = @("KubeSMB"; "KubeISCSI") |
|
|
|
It "Export flexvolume plugin logs in last hour" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-1))} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\flexvolumes-lasthour-logs.csv" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export flexvolume plugin & error logs in last day" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-24)); Level=@(3,2,1,0)} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\flexvolumes-lastday-errlogs.csv" |
|
} | Should Not Throw |
|
} |
|
} |
|
} |
|
|
|
Describe "Host Compute Network" { |
|
$eventLogProviders = @("Microsoft-Windows-Hyper-V-VmSwitch") |
|
|
|
function log-ret { |
|
param ( |
|
[parameter(Mandatory = $true)] [string]$Name, |
|
[parameter(Mandatory = $false)] $Ret |
|
) |
|
|
|
"`n# $Name #`n" | Out-File -Append -Encoding utf8 -FilePath "$resultDir\hcn-info.txt" |
|
$Ret | Out-File -Append -Encoding utf8 -FilePath "$resultDir\hcn-info.txt" |
|
} |
|
|
|
It "Get-NetIPAddress" { |
|
{ |
|
log-ret -Name "Get-NetIPAddress" -Ret (Get-NetIPAddress | Format-List) |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get-NetAdapter | fl" { |
|
{ |
|
log-ret -Name "Get-NetAdapter" -Ret (Get-NetAdapter | Format-List) |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get-HnsNetwork" { |
|
{ |
|
log-ret -Name "Get-HnsNetwork" -Ret (Get-HnsNetwork | ? {($_.Name -like "vxlan*") -or ($_.Name -like "cbr*")} | Format-List) |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get-HnsEndpoint" { |
|
{ |
|
log-ret -Name "Get-HnsEndpoint" -Ret (Get-HnsEndpoint | Format-List) |
|
} | Should Not Throw |
|
} |
|
|
|
It "Get-HnsPolicyList" { |
|
{ |
|
log-ret -Name "Get-HnsPolicyList" -Ret (Get-HnsPolicyList | Format-List) |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export logs in last hour" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-1))} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\hcn-last15mins-logs.csv" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export warning & error logs in last day" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-24)); Level=@(3,2,1,0)} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\hcn-lastday-errlogs.csv" |
|
} | Should Not Throw |
|
} |
|
} |
|
|
|
Describe "Host Compute Service" { |
|
$eventLogNames = @( |
|
"Microsoft-Windows-Containers-Wcifs/Operational", |
|
"Microsoft-Windows-Containers-Wcnfs/Operational", |
|
"Microsoft-Windows-Hyper-V-Compute-Admin", |
|
"Microsoft-Windows-Hyper-V-Compute-Operational", |
|
"Application" |
|
) |
|
$eventLogProviders = @("Microsoft-Windows-Hyper-V-Compute") |
|
|
|
It "Export logs in last hour" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{LogName=$eventLogNames; ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-1))} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\hcs-lasthour-logs.csv" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export warning & error logs in last day" { |
|
{ |
|
Get-WinEvent -FilterHashtable @{LogName=$eventLogNames; ProviderName=$eventLogProviders; StartTime=((Get-Date).AddHours(-24)); Level=@(3,2,1,0)} -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\hcs-lastday-errlogs.csv" |
|
} | Should Not Throw |
|
} |
|
|
|
It "Export operation analytic logs" { |
|
{ |
|
Get-WinEvent -LogName "Microsoft-Windows-Hyper-V-Compute-Analytic" -Oldest -ErrorAction Ignore | ` |
|
Sort-Object ProviderName,TimeCreated,Index | ` |
|
Export-CSV "$resultDir\hcs-analytic-logs.csv" |
|
} | Should Not Throw |
|
} |
|
} |
|
|
|
Remove-Item -Path "$resultDir.zip" -ErrorAction Ignore | Out-Null |
|
Compress-Archive -Path $resultDir -DestinationPath "$resultDir.zip" |
|
|
|
Write-Host -ForegroundColor Gray "#########################################" |
|
Write-Host -ForegroundColor Gray "Collection:" |
|
Write-Host -ForegroundColor Gray " - Package : $resultDir.zip" |
|
Write-Host -ForegroundColor Gray " - Directory : $resultDir" |
|
Get-ChildItem $resultDir | Select @{Label="Name"; Expression={" |- $($_.Name)"}}, @{Label="Size"; Expression={format-file-size($_.Length)}} | Format-Table -HideTableHeaders |
|
Write-Host -ForegroundColor Gray "#########################################" |