...
1# Copyright 2019 The Kubernetes Authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15<#
16.SYNOPSIS
17 Top-level script that runs on Windows nodes to join them to the K8s cluster.
18#>
19
20# IMPORTANT PLEASE NOTE:
21# Any time the file structure in the `windows` directory changes, `windows/BUILD`
22# and `k8s.io/release/lib/releaselib.sh` must be manually updated with the changes.
23# We HIGHLY recommend not changing the file structure, because consumers of
24# Kubernetes releases depend on the release structure remaining stable.
25
26$ErrorActionPreference = 'Stop'
27
28# Turn on tracing to debug
29# Set-PSDebug -Trace 1
30
31# Update TLS setting to enable Github downloads and disable progress bar to
32# increase download speed.
33[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
34$ProgressPreference = 'SilentlyContinue'
35
36# Returns the GCE instance metadata value for $Key where key is an "attribute"
37# of the instance. If the key is not present in the instance metadata returns
38# $Default if set, otherwise returns $null.
39function Get-InstanceMetadataAttribute {
40 param (
41 [parameter(Mandatory=$true)] [string]$Key,
42 [parameter(Mandatory=$false)] [string]$Default
43 )
44
45 $url = ("http://metadata.google.internal/computeMetadata/v1/instance/" +
46 "attributes/$Key")
47 try {
48 $client = New-Object Net.WebClient
49 $client.Headers.Add('Metadata-Flavor', 'Google')
50 return ($client.DownloadString($url)).Trim()
51 }
52 catch [System.Net.WebException] {
53 if ($Default) {
54 return $Default
55 }
56 else {
57 Write-Host "Failed to retrieve value for $Key."
58 return $null
59 }
60 }
61}
62
63# Fetches the value of $MetadataKey, saves it to C:\$Filename and imports it as
64# a PowerShell module.
65#
66# Note: this function depends on common.psm1.
67function FetchAndImport-ModuleFromMetadata {
68 param (
69 [parameter(Mandatory=$true)] [string]$MetadataKey,
70 [parameter(Mandatory=$true)] [string]$Filename
71 )
72
73 $module = Get-InstanceMetadataAttribute $MetadataKey
74 if (Test-Path C:\$Filename) {
75 if (-not $REDO_STEPS) {
76 Log-Output "Skip: C:\$Filename already exists, not overwriting"
77 Import-Module -Force C:\$Filename
78 return
79 }
80 Log-Output "Warning: C:\$Filename already exists, will overwrite it."
81 }
82 New-Item -ItemType file -Force C:\$Filename | Out-Null
83 Set-Content C:\$Filename $module
84 Import-Module -Force C:\$Filename
85}
86
87# Returns true if the ENABLE_STACKDRIVER_WINDOWS or ENABLE_NODE_LOGGING field in kube_env is true.
88# $KubeEnv is a hash table containing the kube-env metadata keys+values.
89# ENABLE_NODE_LOGGING is used for legacy Stackdriver Logging, and will be deprecated (always set to False)
90# soon. ENABLE_STACKDRIVER_WINDOWS is added to indicate whether logging is enabled for windows nodes.
91function IsLoggingEnabled {
92 param (
93 [parameter(Mandatory=$true)] [hashtable]$KubeEnv
94 )
95
96 if ($KubeEnv.Contains('ENABLE_STACKDRIVER_WINDOWS') -and `
97 ($KubeEnv['ENABLE_STACKDRIVER_WINDOWS'] -eq 'true')) {
98 return $true
99 } elseif ($KubeEnv.Contains('ENABLE_NODE_LOGGING') -and `
100 ($KubeEnv['ENABLE_NODE_LOGGING'] -eq 'true')) {
101 return $true
102 }
103 return $false
104}
105
106try {
107 # Don't use FetchAndImport-ModuleFromMetadata for common.psm1 - the common
108 # module includes variables and functions that any other function may depend
109 # on.
110 $module = Get-InstanceMetadataAttribute 'common-psm1'
111 New-Item -ItemType file -Force C:\common.psm1 | Out-Null
112 Set-Content C:\common.psm1 $module
113 Import-Module -Force C:\common.psm1
114
115 # TODO(pjh): update the function to set $Filename automatically from the key,
116 # then put these calls into a loop over a list of XYZ-psm1 keys.
117 FetchAndImport-ModuleFromMetadata 'k8s-node-setup-psm1' 'k8s-node-setup.psm1'
118
119 Dump-DebugInfoToConsole
120
121 $kube_env = Fetch-KubeEnv
122 Set-EnvironmentVars
123
124 # Set to true if there's a feature that needs a reboot
125 $restart_computer = $false
126
127 $should_enable_hyperv = Test-ShouldEnableHyperVFeature
128 $hyperv_feature_enabled = Test-HyperVFeatureEnabled
129 if ($should_enable_hyperv -and -not ($hyperv_feature_enabled)) {
130 Enable-HyperVFeature
131 Log-Output 'Restarting computer after enabling Windows Hyper-V feature'
132 $restart_computer = $true
133 }
134
135 if (-not (Test-ContainersFeatureInstalled)) {
136 Install-ContainersFeature
137 Log-Output 'Restarting computer after enabling Windows Containers feature'
138 $restart_computer = $true
139 }
140
141 if ($restart_computer) {
142 Restart-Computer -Force
143 # Restart-Computer does not stop the rest of the script from executing.
144 exit 0
145 }
146
147 # Set the TCP/IP Parameters to keep idle connections alive.
148 Set-WindowsTCPParameters
149
150 Set-PrerequisiteOptions
151
152 if (Test-IsTestCluster $kube_env) {
153 Log-Output 'Test cluster detected, installing OpenSSH.'
154 FetchAndImport-ModuleFromMetadata 'install-ssh-psm1' 'install-ssh.psm1'
155 InstallAndStart-OpenSsh
156 StartProcess-WriteSshKeys
157 }
158
159 Create-Directories
160 Download-HelperScripts
161
162 DownloadAndInstall-Crictl
163 Configure-Crictl
164 Setup-ContainerRuntime
165 DownloadAndInstall-KubernetesBinaries
166 DownloadAndInstall-NodeProblemDetector
167 DownloadAndInstall-CSIProxyBinaries
168 DownloadAndInstall-AuthProviderGcpBinary
169 Start-CSIProxy
170 Create-NodePki
171 Create-KubeletKubeconfig
172 Create-KubeproxyKubeconfig
173 Create-NodeProblemDetectorKubeConfig
174 Create-AuthProviderGcpConfig
175 Set-PodCidr
176 Configure-HostNetworkingService
177 Prepare-CniNetworking
178 Configure-HostDnsConf
179 Configure-GcePdTools
180 Configure-Kubelet
181 Configure-NodeProblemDetector
182
183 # Even if Logging agent is already installed, the function will still [re]start the service.
184 if (IsLoggingEnabled $kube_env) {
185 Install-LoggingAgent
186 Configure-LoggingAgent
187 Restart-LoggingAgent
188 }
189 # Flush cache to disk before starting kubelet & kube-proxy services
190 # to make metadata server route and stackdriver service more persistent.
191 Write-Volumecache C -PassThru
192 Start-WorkerServices
193 Log-Output 'Waiting 15 seconds for node to join cluster.'
194 Start-Sleep 15
195 Verify-WorkerServices
196
197 $config = New-FileRotationConfig
198 # TODO(random-liu): Generate containerd log into the log directory.
199 Schedule-LogRotation -Pattern '.*\.log$' -Path ${env:LOGS_DIR} -RepetitionInterval $(New-Timespan -Hour 1) -Config $config
200
201 Pull-InfraContainer
202 # Flush cache to disk to persist the setup status
203 Write-Volumecache C -PassThru
204}
205catch {
206 Write-Host 'Exception caught in script:'
207 Write-Host $_.InvocationInfo.PositionMessage
208 Write-Host "Kubernetes Windows node setup failed: $($_.Exception.Message)"
209 # Make sure kubelet won't remain running in case any failure happened during the startup.
210 Write-Host "Cleaning up, Unregistering WorkerServices..."
211 Unregister-WorkerServices
212 exit 1
213}
View as plain text