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  }