k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cluster/gce/gci/master-helper.sh (about) 1 #!/usr/bin/env bash 2 3 # Copyright 2016 The Kubernetes Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # A library of helper functions and constant for GCI distro 18 source "${KUBE_ROOT}/cluster/gce/gci/helper.sh" 19 20 # create-master-instance creates the master instance. If called with 21 # an argument, the argument is used as the name to a reserved IP 22 # address for the master. (In the case of upgrade/repair, we re-use 23 # the same IP.) 24 # 25 # It requires a whole slew of assumed variables, partially due to to 26 # the call to write-master-env. Listing them would be rather 27 # futile. Instead, we list the required calls to ensure any additional 28 # 29 # variables are set: 30 # ensure-temp-dir 31 # detect-project 32 # get-bearer-token 33 function create-master-instance { 34 local address="" 35 [[ -n ${1:-} ]] && address="${1}" 36 local internal_address="" 37 [[ -n ${2:-} ]] && internal_address="${2}" 38 39 write-master-env 40 ensure-gci-metadata-files 41 # shellcheck disable=SC2153 # 'MASTER_NAME' is assigned by upstream 42 create-master-instance-internal "${MASTER_NAME}" "${address}" "${internal_address}" 43 } 44 45 function replicate-master-instance() { 46 local existing_master_zone="${1}" 47 local existing_master_name="${2}" 48 local existing_master_replicas="${3}" 49 50 local kube_env 51 kube_env="$(get-metadata "${existing_master_zone}" "${existing_master_name}" kube-env)" 52 # Substitute INITIAL_ETCD_CLUSTER to enable etcd clustering. 53 kube_env="$(echo "${kube_env}" | grep -v "INITIAL_ETCD_CLUSTER")" 54 kube_env="$(echo -e "${kube_env}\nINITIAL_ETCD_CLUSTER: '${existing_master_replicas},${REPLICA_NAME}'")" 55 56 # Substitute INITIAL_ETCD_CLUSTER_STATE 57 kube_env="$(echo "${kube_env}" | grep -v "INITIAL_ETCD_CLUSTER_STATE")" 58 kube_env="$(echo -e "${kube_env}\nINITIAL_ETCD_CLUSTER_STATE: 'existing'")" 59 60 ETCD_CA_KEY="$(echo "${kube_env}" | grep "ETCD_CA_KEY" | sed "s/^.*: '//" | sed "s/'$//")" 61 ETCD_CA_CERT="$(echo "${kube_env}" | grep "ETCD_CA_CERT" | sed "s/^.*: '//" | sed "s/'$//")" 62 create-etcd-certs "${REPLICA_NAME}" "${ETCD_CA_CERT}" "${ETCD_CA_KEY}" 63 64 kube_env="$(echo "${kube_env}" | grep -v "ETCD_PEER_KEY")" 65 kube_env="$(echo -e "${kube_env}\nETCD_PEER_KEY: '${ETCD_PEER_KEY_BASE64}'")" 66 kube_env="$(echo "${kube_env}" | grep -v "ETCD_PEER_CERT")" 67 kube_env="$(echo -e "${kube_env}\nETCD_PEER_CERT: '${ETCD_PEER_CERT_BASE64}'")" 68 69 local master_certs 70 master_certs="$(get-metadata "${existing_master_zone}" "${existing_master_name}" kube-master-certs)" 71 72 ETCD_APISERVER_CA_KEY="$(echo "${master_certs}" | grep "ETCD_APISERVER_CA_KEY" | sed "s/^.*: '//" | sed "s/'$//")" 73 ETCD_APISERVER_CA_CERT="$(echo "${master_certs}" | grep "ETCD_APISERVER_CA_CERT" | sed "s/^.*: '//" | sed "s/'$//")" 74 create-etcd-apiserver-certs "etcd-${REPLICA_NAME}" "${REPLICA_NAME}" "${ETCD_APISERVER_CA_CERT}" "${ETCD_APISERVER_CA_KEY}" 75 76 master_certs="$(echo "${master_certs}" | grep -v "ETCD_APISERVER_SERVER_KEY")" 77 master_certs="$(echo -e "${master_certs}\nETCD_APISERVER_SERVER_KEY: '${ETCD_APISERVER_SERVER_KEY_BASE64}'")" 78 master_certs="$(echo "${master_certs}" | grep -v "ETCD_APISERVER_SERVER_CERT")" 79 master_certs="$(echo -e "${master_certs}\nETCD_APISERVER_SERVER_CERT: '${ETCD_APISERVER_SERVER_CERT_BASE64}'")" 80 master_certs="$(echo "${master_certs}" | grep -v "ETCD_APISERVER_CLIENT_KEY")" 81 master_certs="$(echo -e "${master_certs}\nETCD_APISERVER_CLIENT_KEY: '${ETCD_APISERVER_CLIENT_KEY_BASE64}'")" 82 master_certs="$(echo "${master_certs}" | grep -v "ETCD_APISERVER_CLIENT_CERT")" 83 master_certs="$(echo -e "${master_certs}\nETCD_APISERVER_CLIENT_CERT: '${ETCD_APISERVER_CLIENT_CERT_BASE64}'")" 84 85 echo "${kube_env}" > "${KUBE_TEMP}/master-kube-env.yaml" 86 echo "${master_certs}" > "${KUBE_TEMP}/kube-master-certs.yaml" 87 get-metadata "${existing_master_zone}" "${existing_master_name}" cluster-name > "${KUBE_TEMP}/cluster-name.txt" 88 get-metadata "${existing_master_zone}" "${existing_master_name}" gci-update-strategy > "${KUBE_TEMP}/gci-update.txt" 89 get-metadata "${existing_master_zone}" "${existing_master_name}" cluster-location > "${KUBE_TEMP}/cluster-location.txt" 90 91 create-master-instance-internal "${REPLICA_NAME}" 92 } 93 94 95 # run-gcloud-command runs a given command over ssh with retries. 96 function run-gcloud-command() { 97 local master_name="${1}" 98 local zone="${2}" 99 local command="${3}" 100 101 local retries=5 102 local sleep_sec=10 103 104 local result="" 105 106 for ((i=0; i<retries; i++)); do 107 if result=$(gcloud compute ssh "${master_name}" --project "${PROJECT}" --zone "${zone}" --command "${command}" -- -oConnectTimeout=60 2>&1); then 108 echo "Successfully executed '${command}' on ${master_name}" 109 return 0 110 fi 111 112 sleep "${sleep_sec}" 113 done 114 echo "Failed to execute '${command}' on ${master_name} despite ${retries} attempts" >&2 115 echo "Last attempt failed with: ${result}" >&2 116 return 1 117 } 118 119 120 function create-master-instance-internal() { 121 local gcloud="gcloud" 122 local retries=5 123 local sleep_sec=10 124 if [[ "${MASTER_SIZE##*-}" -ge 64 ]]; then # remove everything up to last dash (inclusive) 125 # Workaround for #55777 126 retries=30 127 sleep_sec=60 128 fi 129 130 local -r master_name="${1}" 131 local -r address="${2:-}" 132 local -r internal_address="${3:-}" 133 134 local preemptible_master="" 135 if [[ "${PREEMPTIBLE_MASTER:-}" == "true" ]]; then 136 preemptible_master="--preemptible --maintenance-policy TERMINATE" 137 fi 138 139 local enable_ip_aliases 140 if [[ "${NODE_IPAM_MODE:-}" == "CloudAllocator" ]]; then 141 enable_ip_aliases=true 142 else 143 enable_ip_aliases=false 144 fi 145 146 local network 147 # shellcheck disable=SC2153 # 'NETWORK' is assigned by upstream 148 network=$(make-gcloud-network-argument \ 149 "${NETWORK_PROJECT}" "${REGION}" "${NETWORK}" "${SUBNETWORK:-}" \ 150 "${address:-}" "${enable_ip_aliases:-}" "${IP_ALIAS_SIZE:-}") 151 152 local metadata="kube-env=${KUBE_TEMP}/master-kube-env.yaml" 153 metadata="${metadata},kubelet-config=${KUBE_TEMP}/master-kubelet-config.yaml" 154 metadata="${metadata},user-data=${KUBE_ROOT}/cluster/gce/gci/master.yaml" 155 metadata="${metadata},configure-sh=${KUBE_ROOT}/cluster/gce/gci/configure.sh" 156 metadata="${metadata},cluster-location=${KUBE_TEMP}/cluster-location.txt" 157 metadata="${metadata},cluster-name=${KUBE_TEMP}/cluster-name.txt" 158 metadata="${metadata},gci-update-strategy=${KUBE_TEMP}/gci-update.txt" 159 metadata="${metadata},kube-master-certs=${KUBE_TEMP}/kube-master-certs.yaml" 160 metadata="${metadata},cluster-location=${KUBE_TEMP}/cluster-location.txt" 161 metadata="${metadata},kube-master-internal-route=${KUBE_ROOT}/cluster/gce/gci/kube-master-internal-route.sh" 162 metadata="${metadata},${MASTER_EXTRA_METADATA}" 163 164 local disk="name=${master_name}-pd" 165 disk="${disk},device-name=master-pd" 166 disk="${disk},mode=rw" 167 disk="${disk},boot=no" 168 disk="${disk},auto-delete=no" 169 170 for ((i=0; i<retries; i++)); do 171 # We expect ZONE to be set and deliberately do not quote preemptible_master 172 # and network 173 # shellcheck disable=SC2153 disable=SC2086 174 if result=$(${gcloud} compute instances create "${master_name}" \ 175 --project "${PROJECT}" \ 176 --zone "${ZONE}" \ 177 --machine-type "${MASTER_SIZE}" \ 178 --image-project="${MASTER_IMAGE_PROJECT}" \ 179 --image "${MASTER_IMAGE}" \ 180 --tags "${MASTER_TAG}" \ 181 --scopes "storage-ro,compute-rw,monitoring,logging-write" \ 182 --metadata-from-file "${metadata}" \ 183 --disk "${disk}" \ 184 --boot-disk-size "${MASTER_ROOT_DISK_SIZE}" \ 185 ${MASTER_MIN_CPU_ARCHITECTURE:+"--min-cpu-platform=${MASTER_MIN_CPU_ARCHITECTURE}"} \ 186 ${preemptible_master} \ 187 ${network} 2>&1); then 188 echo "${result}" >&2 189 190 if [[ -n "${internal_address:-}" ]]; then 191 attach-internal-master-ip "${master_name}" "${ZONE}" "${internal_address}" 192 fi 193 return 0 194 else 195 echo "${result}" >&2 196 if [[ ! "${result}" =~ "try again later" ]]; then 197 echo "Failed to create master instance due to non-retryable error" >&2 198 return 1 199 fi 200 sleep $sleep_sec 201 fi 202 done 203 204 echo "Failed to create master instance despite ${retries} attempts" >&2 205 return 1 206 } 207 208 function get-metadata() { 209 local zone="${1}" 210 local name="${2}" 211 local key="${3}" 212 gcloud compute ssh "${name}" \ 213 --project "${PROJECT}" \ 214 --zone "${zone}" \ 215 --command "curl \"http://metadata.google.internal/computeMetadata/v1/instance/attributes/${key}\" -H \"Metadata-Flavor: Google\"" 2>/dev/null 216 }