staging/cse/windows/configfunc.ps1 (587 lines of code) (raw):
# Set the service telemetry GUID. This is used with Windows Analytics https://docs.microsoft.com/en-us/sccm/core/clients/manage/monitor-windows-analytics
function Set-TelemetrySetting
{
Param(
[Parameter(Mandatory=$true)][string]
$WindowsTelemetryGUID
)
Logs-To-Event -TaskName "AKS.WindowsCSE.SetTelemetrySetting" -TaskMessage "Start to apply telemetry data setting. WindowsTelemetryGUID: $global:WindowsTelemetryGUID"
Set-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name "CommercialId" -Value $WindowsTelemetryGUID -Force
}
# Resize the system partition to the max available size. Azure can resize a managed disk, but the VM still needs to extend the partition boundary
# This approach was recommended by the Windows Storage team to avoid performance delay when calling Get-PartitionSupportedSize
function Resize-OSDrive
{
Logs-To-Event -TaskName "AKS.WindowsCSE.ResizeOSDrive" -TaskMessage "Start to resize os drive if possible"
try {
$osDrive = ((Get-WmiObject Win32_OperatingSystem -ErrorAction Stop).SystemDrive).TrimEnd(":")
# Ensure the OS volume needs to be expanded, diskpart will fail if the partition is already expanded
$osDisk = Get-Partition -DriveLetter $osDrive | Get-Disk
if ($osDisk.Size - $osDisk.AllocatedSize -gt 1GB)
{
Write-Log "Expanding the OS volume"
# Create a diskpart script (text file) that will select the OS volume, extend it and exit.
$diskpartScriptPath = [String]::Format("{0}\\diskpart_extendOSVol.script", $env:temp)
[String]::Format("select volume {0}`nextend`nexit", $osDrive) | Out-File -Encoding "UTF8" $diskpartScriptPath
Invoke-Executable -Executable "diskpart.exe" -ArgList @("/s", $diskpartScriptPath) -ExitCode $global:WINDOWS_CSE_ERROR_RESIZE_OS_DRIVE
Remove-Item -Path $diskpartScriptPath -Force
} else {
Write-Log "No need to expand the OS volume due to ScheduledTask executed before CSE."
}
} catch {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_RESIZE_OS_DRIVE -ErrorMessage "Failed to resize os drive. Error: $_"
}
}
# https://docs.microsoft.com/en-us/powershell/module/storage/new-partition
function Initialize-DataDisks
{
Logs-To-Event -TaskName "AKS.WindowsCSE.InitializeDataDisks" -TaskMessage "Start to initialize data disks"
Get-Disk | Where-Object PartitionStyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -UseMaximumSize -AssignDriveLetter | Format-Volume -FileSystem NTFS -Force
}
# Set the Internet Explorer to use the latest rendering mode on all sites
# https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-ie-internetexplorer-intranetcompatibilitymode
# (This only affects installations with UI)
function Set-Explorer
{
Logs-To-Event -TaskName "AKS.WindowsCSE.SetExplorer" -TaskMessage "Start to disable Internet Explorer compat mode and set homepage"
New-Item -Path HKLM:"\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer"
New-Item -Path HKLM:"\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\BrowserEmulation"
New-ItemProperty -Path HKLM:"\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\BrowserEmulation" -Name IntranetCompatibilityMode -Value 0 -Type DWord
New-Item -Path HKLM:"\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main"
New-ItemProperty -Path HKLM:"\\SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main" -Name "Start Page" -Type String -Value http://bing.com
}
# Pagefile adjustments
function Adjust-PageFileSize()
{
Logs-To-Event -TaskName "AKS.WindowsCSE.AdjustPageFileSize" -TaskMessage "Start to adjust pagefile size"
try {
$computersys = Get-WmiObject Win32_ComputerSystem -EnableAllPrivileges;
$computersys.AutomaticManagedPagefile = $False;
$computersys.Put();
$pagefile = Get-WmiObject -Query "Select * From Win32_PageFileSetting Where Name like '%pagefile.sys'";
$pagefile.InitialSize = 8096;
$pagefile.MaximumSize = 8096;
$pagefile.Put();
} catch {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_ADJUST_PAGEFILE_SIZE -ErrorMessage "Failed to adjust pagefile size. Error: $_"
}
}
function Adjust-DynamicPortRange()
{
Logs-To-Event -TaskName "AKS.WindowsCSE.AdjustDynamicPortRange" -TaskMessage "Start to adjust dynamic port range"
# Kube-proxy reserves 63 ports per service which limits clusters with Windows nodes
# to ~225 services if default port reservations are used.
# https://docs.microsoft.com/en-us/virtualization/windowscontainers/kubernetes/common-problems#load-balancers-are-plumbed-inconsistently-across-the-cluster-nodes
# Kube-proxy load balancing should be set to DSR mode when it releases with future versions of the OS
#
# The fix which reduces dynamic port usage is still needed for DSR mode
# Update the range to avoid that it conflicts with NodePort range (30000 - 32767)
if ($global:EnableIncreaseDynamicPortRange) {
# UDP port 65330 is excluded in vhdbuilder/packer/windows/configure-windows-vhd.ps1 since it may fail when it is set in provisioning nodes
Invoke-Executable -Executable "netsh.exe" -ArgList @("int", "ipv4", "set", "dynamicportrange", "tcp", "16385", "49151") -ExitCode $global:WINDOWS_CSE_ERROR_SET_TCP_DYNAMIC_PORT_RANGE
Invoke-Executable -Executable "netsh.exe" -ArgList @("int", "ipv4", "add", "excludedportrange", "tcp", "30000", "2768") -ExitCode $global:WINDOWS_CSE_ERROR_SET_TCP_EXCLUDE_PORT_RANGE
Invoke-Executable -Executable "netsh.exe" -ArgList @("int", "ipv4", "set", "dynamicportrange", "udp", "16385", "49151") -ExitCode $global:WINDOWS_CSE_ERROR_SET_UDP_DYNAMIC_PORT_RANGE
Invoke-Executable -Executable "netsh.exe" -ArgList @("int", "ipv4", "add", "excludedportrange", "udp", "30000", "2768") -ExitCode $global:WINDOWS_CSE_ERROR_SET_UDP_EXCLUDE_PORT_RANGE
} else {
Invoke-Executable -Executable "netsh.exe" -ArgList @("int", "ipv4", "set", "dynamicportrange", "tcp", "33000", "32536") -ExitCode $global:WINDOWS_CSE_ERROR_SET_TCP_DYNAMIC_PORT_RANGE
}
}
# TODO: should this be in this PR?
# Service start actions. These should be split up later and included in each install step
function Update-ServiceFailureActions
{
Logs-To-Event -TaskName "AKS.WindowsCSE.UpdateServiceFailureActions" -TaskMessage "Start to update service failure actions"
sc.exe failure "kubelet" actions= restart/60000/restart/60000/restart/60000 reset= 900
sc.exe failure "kubeproxy" actions= restart/60000/restart/60000/restart/60000 reset= 900
sc.exe failure "containerd" actions= restart/60000/restart/60000/restart/60000 reset= 900
}
function Add-SystemPathEntry
{
Param(
[Parameter(Mandatory = $true)][string]
$Directory
)
# update the path variable if it doesn't have the needed paths
$path = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::Machine)
$updated = $false
if(-not ($path -match $Directory.Replace("\","\\")+"(;|$)"))
{
$path += ";"+$Directory
$updated = $true
}
if($updated)
{
Write-Log "Updating path, added $Directory"
[Environment]::SetEnvironmentVariable("Path", $path, [EnvironmentVariableTarget]::Machine)
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}
}
function Enable-FIPSMode
{
Param(
[Parameter(Mandatory = $true)][bool]
$FipsEnabled
)
Logs-To-Event -TaskName "AKS.WindowsCSE.EnableFIPSMode" -TaskMessage "Start to enable FIPS mode: $FipsEnabled."
if ( $FipsEnabled ) {
Write-Log "Set the registry to enable fips-mode"
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy" -Name "Enabled" -Value 1 -Type DWORD -Force
}
else
{
Write-Log "Leave FipsAlgorithmPolicy as it is."
}
}
function Enable-Privilege {
param($Privilege)
$Definition = @'
using System;
using System.Runtime.InteropServices;
public class AdjPriv {
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid {
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege) {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero,
IntPtr.Zero);
return retVal;
}
}
'@
$ProcessHandle = (Get-Process -id $pid).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege)
}
function Install-GmsaPlugin {
Param(
[Parameter(Mandatory=$true)]
[String] $GmsaPackageUrl
)
Logs-To-Event -TaskName "AKS.WindowsCSE.InstallGmsaPlugin" -TaskMessage "Start to install Windows gmsa package. WindowsGmsaPackageUrl: $global:WindowsGmsaPackageUrl"
$tempInstallPackageFoler = [Io.path]::Combine($env:TEMP, "CCGAKVPlugin")
$tempPluginZipFile = [Io.path]::Combine($ENV:TEMP, "gmsa.zip")
Write-Log "Getting the GMSA plugin package"
DownloadFileOverHttp -Url $GmsaPackageUrl -DestinationPath $tempPluginZipFile -ExitCode $global:WINDOWS_CSE_ERROR_DOWNLOAD_GMSA_PACKAGE
Expand-Archive -Path $tempPluginZipFile -DestinationPath $tempInstallPackageFoler -Force
if ($LASTEXITCODE) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_EXPAND_ARCHIVE -ErrorMessage "Failed to extract the '$tempPluginZipFile' archive."
}
Remove-Item -Path $tempPluginZipFile -Force
# Copy the plugin DLL file.
Write-Log "Installing the GMSA plugin"
Copy-Item -Force -Path "$tempInstallPackageFoler\CCGAKVPlugin.dll" -Destination "${env:SystemRoot}\System32\"
# Enable the PowerShell privilege to set the registry permissions.
Write-Log "Enabling the PowerShell privilege"
$enablePrivilegeResponse=$false
for($i = 0; $i -lt 10; $i++) {
Write-Log "Retry $i : Trying to enable the PowerShell privilege"
$enablePrivilegeResponse = Enable-Privilege -Privilege "SeTakeOwnershipPrivilege"
if ($enablePrivilegeResponse) {
break
}
Start-Sleep 1
}
if(!$enablePrivilegeResponse) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_ENABLE_POWERSHELL_PRIVILEGE -ErrorMessage "Failed to enable the PowerShell privilege."
}
# Set the registry permissions.
Write-Log "Setting GMSA plugin registry permissions"
try {
$ccgKeyPath = "System\CurrentControlSet\Control\CCG\COMClasses"
$owner = [System.Security.Principal.NTAccount]"BUILTIN\Administrators"
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
$ccgKeyPath,
[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
[System.Security.AccessControl.RegistryRights]::TakeOwnership)
$acl = $key.GetAccessControl()
$acl.SetOwner($owner)
$key.SetAccessControl($acl)
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
$ccgKeyPath,
[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
[System.Security.AccessControl.RegistryRights]::ChangePermissions)
$acl = $key.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
$owner,
[System.Security.AccessControl.RegistryRights]::FullControl,
[System.Security.AccessControl.AccessControlType]::Allow)
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
} catch {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_SET_REGISTRY_PERMISSION -ErrorMessage "Failed to set GMSA plugin registry permissions. $_"
}
# Set the appropriate registry values.
try {
Write-Log "Setting the appropriate GMSA plugin registry values"
reg.exe import "$tempInstallPackageFoler\registerplugin.reg" 2>$null 1>$null
} catch {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_SET_REGISTRY_VALUES -ErrorMessage "Failed to set GMSA plugin registry values. $_"
}
# Enable the logging manifest.
Write-Log "Importing the CCGEvents manifest file"
wevtutil.exe im "$tempInstallPackageFoler\CCGEvents.man"
if ($LASTEXITCODE) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_IMPORT_CCGEVENTS -ErrorMessage "Failed to import the CCGEvents.man manifest file. $LASTEXITCODE"
}
# Enable the CCGAKVPlugin logging manifest.
# Introduced since v1.1.3
if (Test-Path -Path "$tempInstallPackageFoler\CCGAKVPluginEvents.man" -PathType Leaf) {
Write-Log "Importing the CCGAKVPluginEvents manifest file"
wevtutil.exe im "$tempInstallPackageFoler\CCGAKVPluginEvents.man"
if ($LASTEXITCODE) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_GMSA_IMPORT_CCGAKVPPLUGINEVENTS -ErrorMessage "Failed to import the CCGAKVPluginEvents.man manifest file. $LASTEXITCODE"
}
} else {
Write-Log "CCGAKVPluginEvents.man does not exist in the package"
}
Write-Log "Removing $tempInstallPackageFoler"
Remove-Item -Path $tempInstallPackageFoler -Force -Recurse
Write-Log "Successfully installed the GMSA plugin"
}
function Install-OpenSSH {
Param(
[Parameter(Mandatory = $true)][string[]]
$SSHKeys
)
Logs-To-Event -TaskName "AKS.WindowsCSE.InstallOpenSSH" -TaskMessage "Start to install OpenSSH"
$adminpath = "c:\ProgramData\ssh"
$adminfile = "administrators_authorized_keys"
$sshdService = Get-Service | ? Name -like 'sshd'
if ($sshdService.Count -eq 0)
{
Write-Log "Installing OpenSSH"
$isAvailable = Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'
if (!$isAvailable) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_OPENSSH_NOT_INSTALLED -ErrorMessage "OpenSSH is not available on this machine"
}
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
}
else
{
Write-Log "OpenSSH Server service detected - skipping online install..."
}
Start-Service sshd
if (!(Test-Path "$adminpath")) {
Write-Log "Created new file and text content added"
New-Item -path $adminpath -name $adminfile -type "file" -value ""
}
Write-Log "$adminpath found."
Write-Log "Adding keys to: $adminpath\$adminfile ..."
$SSHKeys | foreach-object {
Add-Content $adminpath\$adminfile $_
}
Write-Log "Setting required permissions..."
icacls $adminpath\$adminfile /remove "NT AUTHORITY\Authenticated Users"
icacls $adminpath\$adminfile /inheritance:r
icacls $adminpath\$adminfile /grant SYSTEM:`(F`)
icacls $adminpath\$adminfile /grant BUILTIN\Administrators:`(F`)
Write-Log "Restarting sshd service..."
Restart-Service sshd
# OPTIONAL but recommended:
Set-Service -Name sshd -StartupType 'Automatic'
# Confirm the Firewall rule is configured. It should be created automatically by setup.
$firewall = Get-NetFirewallRule -Name *ssh*
if (!$firewall) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_OPENSSH_FIREWALL_NOT_CONFIGURED -ErrorMessage "OpenSSH's firewall is not configured properly"
}
Write-Log "OpenSSH installed and configured successfully"
}
function Config-CredentialProvider {
Param(
[Parameter(Mandatory=$true)][string]
$KubeDir,
[Parameter(Mandatory=$true)][string]
$CredentialProviderConfPath,
[Parameter(Mandatory = $false)][string]
$CustomCloudContainerRegistryDNSSuffix
)
Write-Log "Configuring kubelet credential provider"
$azureConfigFile = [io.path]::Combine("$KubeDir", "azure.json")
$credentialProviderConfig = @"
apiVersion: kubelet.config.k8s.io/v1
kind: CredentialProviderConfig
providers:
- name: acr-credential-provider
matchImages:
- "*.azurecr.io"
- "*.azurecr.cn"
- "*.azurecr.de"
- "*.azurecr.us"
defaultCacheDuration: "10m"
apiVersion: credentialprovider.kubelet.k8s.io/v1
args:
- $azureConfigFile
"@
if (![string]::IsNullOrEmpty($CustomCloudContainerRegistryDNSSuffix)) {
$credentialProviderConfig = @"
apiVersion: kubelet.config.k8s.io/v1
kind: CredentialProviderConfig
providers:
- name: acr-credential-provider
matchImages:
- "*.azurecr.io"
- "*.azurecr.cn"
- "*.azurecr.de"
- "*.azurecr.us"
- "*$CustomCloudContainerRegistryDNSSuffix"
defaultCacheDuration: "10m"
apiVersion: credentialprovider.kubelet.k8s.io/v1
args:
- $azureConfigFile
"@
}
$credentialProviderConfig | Out-File -encoding ASCII -filepath "$CredentialProviderConfPATH"
}
function Validate-CredentialProviderConfigFlags {
function get-KubeletFlagValue {
Param(
[Parameter(Mandatory=$true)][string]
$KubeletConfigArg
)
$splitResult=($KubeletConfigArg -split "=")
if ($splitResult.Length -ne 2 -or [string]::IsNullOrEmpty($splitResult[1])){
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_CREDENTIAL_PROVIDER_CONFIG -ErrorMessage "Failed to get kubelet flag value from flag $KubeletConfigArg"
}
return $splitResult[1]
}
ForEach ($kubeletConfigArg in $global:KubeletConfigArgs){
if ($kubeletConfigArg -like "--image-credential-provider-config=*") {
$global:credentialProviderConfigPath=get-KubeletFlagValue -KubeletConfigArg $kubeletConfigArg
}
if ($kubeletConfigArg -like "--image-credential-provider-bin-dir=*") {
$global:credentialProviderBinDir=get-KubeletFlagValue -KubeletConfigArg $kubeletConfigArg
}
}
# Both flags should be set to enable out of tree credential provider or not set at the same time to disable it.
if ([string]::IsNullOrEmpty($credentialProviderConfigPath) -xor [string]::IsNullOrEmpty($credentialProviderBinDir)) {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_CREDENTIAL_PROVIDER_CONFIG -ErrorMessage "Not all credential provider flags are configured: --image-credential-provider-config=$credentialProviderConfigPath, --image-credential-provider-bin-dir=$credentialProviderBinDir"
}
}
function Install-CredentialProvider {
Param(
[Parameter(Mandatory=$true)][string]
$KubeDir,
[Parameter(Mandatory = $false)][string]
$CustomCloudContainerRegistryDNSSuffix
)
try {
# Out of tree credential provider is turned on as a must after 1.30, and is optinal in 1.29, for cluster < 1.29, it's not enabled.
# And only when it's enabled, the credential provider flags are set.
$global:credentialProviderConfigPath = ""
$global:credentialProviderBinDir = ""
Validate-CredentialProviderConfigFlags
if ([string]::IsNullOrEmpty($global:credentialProviderConfigPath) -and [string]::IsNullOrEmpty($global:credentialProviderBinDir)) {
Write-Log "Out of tree credential provider is not enabled"
return
}
Logs-To-Event -TaskName "AKS.WindowsCSE.Install-CredentialProvider" -TaskMessage "Start to install out of tree credential provider"
Write-Log "Create credential provider configuration file"
Config-CredentialProvider -KubeDir $KubeDir -CredentialProviderConfPath $global:credentialProviderConfigPath -CustomCloudContainerRegistryDNSSuffix $CustomCloudContainerRegistryDNSSuffix
Write-Log "Download credential provider binary from $global:CredentialProviderURL to $global:credentialProviderBinDir"
$tempDir = New-TemporaryDirectory
$credentialproviderbinaryPackage = "$tempDir\credentialprovider.tar.gz"
DownloadFileOverHttp -Url $global:CredentialProviderURL -DestinationPath $credentialproviderbinaryPackage -ExitCode $global:WINDOWS_CSE_ERROR_DOWNLOAD_CREDEDNTIAL_PROVIDER
tar -xzf $credentialproviderbinaryPackage -C $tempDir
if ($LASTEXITCODE -ne 0) {
throw "Failed to extract the '$credentialproviderbinaryPackage' archive."
}
Create-Directory -FullPath $global:credentialProviderBinDir
cp "$tempDir\azure-acr-credential-provider.exe" "$global:credentialProviderBinDir\acr-credential-provider.exe"
# acr-credential-provider.exe cannot be found by kubelet through provider name before the fix https://github.com/kubernetes/kubernetes/pull/120291
# so we copy the exe file to acr-credential-provider to make all 1.29 release work.
cp "$global:credentialProviderBinDir\acr-credential-provider.exe" "$global:credentialProviderBinDir\acr-credential-provider"
del $tempDir -Recurse
} catch {
Set-ExitCode -ExitCode $global:WINDOWS_CSE_ERROR_INSTALL_CREDENTIAL_PROVIDER -ErrorMessage "Error installing credential provider. Error: $_"
}
}
function New-CsiProxyService {
Param(
[Parameter(Mandatory = $true)][string]
$CsiProxyPackageUrl,
[Parameter(Mandatory = $true)][string]
$KubeDir
)
Logs-To-Event -TaskName "AKS.WindowsCSE.StartCsiProxyService" -TaskMessage "Start Csi proxy service. CsiProxyUrl: $global:CsiProxyUrl"
$tempdir = New-TemporaryDirectory
$binaryPackage = "$tempdir\csiproxy.tar"
DownloadFileOverHttp -Url $CsiProxyPackageUrl -DestinationPath $binaryPackage -ExitCode $global:WINDOWS_CSE_ERROR_DOWNLOAD_CSI_PROXY_PACKAGE
tar -xzf $binaryPackage -C $tempdir
if ($LASTEXITCODE -ne 0) {
throw "Failed to extract the '$binaryPackage' archive."
}
cp "$tempdir\bin\csi-proxy.exe" "$KubeDir\csi-proxy.exe"
del $tempdir -Recurse
& "$KubeDir\nssm.exe" install csi-proxy "$KubeDir\csi-proxy.exe" | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppDirectory "$KubeDir" | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppRestartDelay 5000 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy Description csi-proxy | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy Start SERVICE_DEMAND_START | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy ObjectName LocalSystem | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy Type SERVICE_WIN32_OWN_PROCESS | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppThrottle 1500 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppStdout "$KubeDir\csi-proxy.log" | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppStderr "$KubeDir\csi-proxy.err.log" | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppStdoutCreationDisposition 4 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppStderrCreationDisposition 4 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppRotateFiles 1 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppRotateOnline 1 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppRotateSeconds 86400 | RemoveNulls
& "$KubeDir\nssm.exe" set csi-proxy AppRotateBytes 10485760 | RemoveNulls
}
function New-HostsConfigService {
Logs-To-Event -TaskName "AKS.WindowsCSE.StartHostConfigService" -TaskMessage "Start hosts config agent"
$HostsConfigParameters = [io.path]::Combine($KubeDir, "hostsconfigagent.ps1")
& "$KubeDir\nssm.exe" install hosts-config-agent C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppDirectory "$KubeDir" | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppParameters $HostsConfigParameters | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppRestartDelay 5000 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent Description hosts-config-agent | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent Start SERVICE_DEMAND_START | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent ObjectName LocalSystem | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent Type SERVICE_WIN32_OWN_PROCESS | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppThrottle 1500 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppStdout "$KubeDir\hosts-config-agent.log" | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppStderr "$KubeDir\hosts-config-agent.err.log" | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppStdoutCreationDisposition 4 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppStderrCreationDisposition 4 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppRotateFiles 1 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppRotateOnline 1 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppRotateSeconds 86400 | RemoveNulls
& "$KubeDir\nssm.exe" set hosts-config-agent AppRotateBytes 10485760 | RemoveNulls
}
function Register-LogCollectorScriptTask {
Param(
[Parameter(Mandatory = $true)][int]
$IntervalInMinutes
)
Write-Log "Creating a scheduled task to run loggenerator.ps1"
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File `"c:\k\loggenerator.ps1`""
$principal = New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount -RunLevel Highest
$trigger = New-JobTrigger -Once -At (Get-Date).Date -RepeatIndefinitely -RepetitionInterval (New-TimeSpan -Minutes $IntervalInMinutes)
$definition = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Description "aks-log-generator-task"
Register-ScheduledTask -TaskName "aks-log-generator-task" -InputObject $definition
}
function Enable-GuestVMLogs {
Param(
[Parameter(Mandatory = $true)][int]
$IntervalInMinutes
)
Logs-To-Event -TaskName "AKS.WindowsCSE.EnableGuestVMLogs" -TaskMessage "Start to enable Guest VM Logs. LogGeneratorIntervalInMinutes: $LogGeneratorIntervalInMinutes"
if ($IntervalInMinutes -le 0) {
Write-Log "Do not add AKS logs in GuestVMLogs"
return
}
Register-LogCollectorScriptTask -IntervalInMinutes $IntervalInMinutes
}
function Upload-GuestVMLogs {
Param(
[Parameter(Mandatory = $true)][int]
$ExitCode
)
try {
if ($ExitCode -ne 0) {
# We do not reuse aks-log-generator-task or loggenerator.ps1 since neither may exist
Write-Log "Start to upload guestvmlogs when failing in node provisioning"
$aksLogFolder="C:\WindowsAzure\Logs\aks"
$tempWorkFoler = [Io.path]::Combine($env:TEMP, "guestvmlogs")
Write-Log "Creating $aksLogFolder"
# The folder "C:\WindowsAzure\Logs" may not exist
New-Item -ItemType Directory -Force -Path $aksLogFolder > $null
Write-Log "Creating SymbolicLink for C:\AzureData\CustomDataSetupScript.log in $aksLogFolder"
New-Item -ItemType SymbolicLink -Path (Join-Path $aksLogFolder "CustomDataSetupScript.log") -Target "C:\AzureData\CustomDataSetupScript.log" > $null
# Create a work folder
Write-Log "Creating $tempWorkFoler"
Create-Directory -FullPath $tempWorkFoler
cd $tempWorkFoler
# Generate logs
Write-Log "Generating guestvmlogs"
Invoke-Expression(Get-Childitem -Path "C:\WindowsAzure\" -Filter "CollectGuestLogs.exe" -Recurse | sort LastAccessTime -desc | select -first 1).FullName
# Get the output
$logFile=(Get-Childitem -Path $tempWorkFoler -Filter "*.zip").FullName
# Upload logs
Write-Log "Start to uploading $logFile"
C:\AzureData\windows\sendlogs.ps1 -Path $logFile
} elseif (Get-ScheduledTask -TaskName 'aks-log-generator-task' -ErrorAction Ignore) {
Write-Log "Start the scheduled task aks-log-generator-task to upload the CSE log immediately"
# Upload the full node logs if it succeeds and it is enabled
Start-ScheduledTask -TaskName 'aks-log-generator-task'
}
} catch {
# This should not impact the node provisioning result
Write-Log "Failed to upload CustomDataSetupScript.log. $_"
}
}
# Retag-ImagesForAzureChinaCloud add tags for images for AzureChinaCloud to
# use cached images instead of pulling them from MCR
# This must be run after installing containerd but before New-InfraContainer
function Retag-ImagesForAzureChinaCloud {
param(
[Parameter(Mandatory=$true)][string]
$TargetEnvironment
)
Logs-To-Event -TaskName "AKS.WindowsCSE.RetagImagesForAzureChinaCloud" -TaskMessage "Start to retag images for Azure China Cloud"
$isExist=$false
$imageList=$(ctr.exe -n k8s.io image ls | select -Skip 1)
foreach ($imageInfo in $imageList) {
$splitResult=($imageInfo -split '\s+')
$image=$splitResult[0]
if ($image -like 'mcr.azk8s.cn*') {
$isExist=$true
break
}
}
if ($TargetEnvironment -ne "AzureChinaCloud") {
if ($isExist) {
Write-Log "Clear existing tags for AzureChinaCloud in $TargetEnvironment"
foreach ($imageInfo in $imageList) {
$splitResult=($imageInfo -split '\s+')
$image=$splitResult[0]
if ($image -like 'mcr.azk8s.cn*' -and (-not $image.Contains("@sha256:"))) {
ctr.exe -n k8s.io image delete $image
}
}
}
Write-Log "Not retagging images for $TargetEnvironment"
return
}
# Skip if we have already retagged the images in building VHDs
if ($isExist) {
Write-Log "Skip because images have already been retagged for AzureChinaCloud"
return
}
Write-Log "Retagging images for AzureChinaCloud"
foreach ($imageInfo in $imageList) {
$splitResult=($imageInfo -split '\s+')
$image=$splitResult[0]
if ($image -like 'mcr.microsoft.com*' -and (-not $image.Contains("@sha256:"))) {
Write-Log "Retagging image $image for AzureChinaCloud"
$retagImageUrl=$image.replace('mcr.microsoft.com', 'mcr.azk8s.cn')
ctr.exe -n k8s.io image tag $image $retagImageUrl
}
}
}