k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cluster/gce/gci/configure.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  # Due to the GCE custom metadata size limit, we split the entire script into two
    18  # files configure.sh and configure-helper.sh. The functionality of downloading
    19  # kubernetes configuration, manifests, docker images, and binary files are
    20  # put in configure.sh, which is uploaded via GCE custom metadata.
    21  
    22  set -o errexit
    23  set -o nounset
    24  set -o pipefail
    25  
    26  ### Hardcoded constants
    27  DEFAULT_CNI_VERSION='v1.4.1'
    28  DEFAULT_CNI_HASH='5cff10005288a78b484bbabbaa24669d62a6eedb6cc7c7604b2c1ea14b65e90a1b022c2a2975d7764ec41f24707f6349432e8f11564d03cea0da141195b0602e'
    29  DEFAULT_NPD_VERSION='v0.8.16'
    30  DEFAULT_NPD_HASH_AMD64='6d7c9a8e07d95085ef949373e2019df67b2c717aa3b8043eb7c63ac6a679e7894b0f6efea98354f0059001a35966353220613936ace499ad97b96b7c04f693d8'
    31  DEFAULT_NPD_HASH_ARM64='8c6a61a92e846b2b6c844bac51f34fd90a97fe7109bc3d16520370b944b9a2d1b117c0d1d95464f374354700f4697baaa41265d44e233996b63ef4e5ae450b24'
    32  DEFAULT_CRICTL_VERSION='v1.30.0'
    33  DEFAULT_CRICTL_AMD64_SHA512='2bd1e85ab6abd2ac59e6d1a4ccb316fd08e3b025f8de85a6c8396defb7df5ee4e8daf884c4ad9d6451477ef9754240ec786cc5c5ccf1e9a2f616450f2a98a0d0'
    34  DEFAULT_CRICTL_ARM64_SHA512='bf2d18b781fd4072058862e23e787dd9b1c6c18626bfc5140fbbf34b78b4fca4b3243eff42d28f0a10f1054b4547405a82afae319c9d9975669ef9a7e27a6b42'
    35  DEFAULT_MOUNTER_TAR_SHA='7956fd42523de6b3107ddc3ce0e75233d2fcb78436ff07a1389b6eaac91fb2b1b72a08f7a219eaf96ba1ca4da8d45271002e0d60e0644e796c665f99bb356516'
    36  AUTH_PROVIDER_GCP_HASH_LINUX_AMD64="${AUTH_PROVIDER_GCP_HASH_LINUX_AMD64:-156058e5b3994cba91c23831774033e0d505d6d8b80f43541ef6af91b320fd9dfaabe42ec8a8887b51d87104c2b57e1eb895649d681575ffc80dd9aee8e563db}"
    37  AUTH_PROVIDER_GCP_HASH_LINUX_ARM64="${AUTH_PROVIDER_GCP_HASH_LINUX_ARM64:-1aa3b0bea10a9755231989ffc150cbfa770f1d96932db7535473f7bfeb1108bafdae80202ae738d59495982512e716ff7366d5f414d0e76dd50519f98611f9ab}"
    38  ###
    39  
    40  # Standard curl flags.
    41  CURL_FLAGS='--fail --silent --show-error --retry 5 --retry-delay 3 --connect-timeout 10 --retry-connrefused'
    42  
    43  function set-broken-motd {
    44    cat > /etc/motd <<EOF
    45  Broken (or in progress) Kubernetes node setup! Check the cluster initialization status
    46  using the following commands.
    47  
    48  Master instance:
    49    - sudo systemctl status kube-master-installation
    50    - sudo systemctl status kube-master-configuration
    51  
    52  Node instance:
    53    - sudo systemctl status kube-node-installation
    54    - sudo systemctl status kube-node-configuration
    55  EOF
    56  }
    57  
    58  # A function that fetches a GCE metadata value and echoes it out.
    59  # Args:
    60  #   $1 : URL path after /computeMetadata/v1/ (without heading slash).
    61  #   $2 : An optional default value to echo out if the fetch fails.
    62  #
    63  # NOTE: this function is duplicated in configure-helper.sh, any changes here
    64  # should be duplicated there as well.
    65  function get-metadata-value {
    66    local default="${2:-}"
    67  
    68    local status
    69    # shellcheck disable=SC2086
    70    curl ${CURL_FLAGS} \
    71      -H 'Metadata-Flavor: Google' \
    72      "http://metadata/computeMetadata/v1/${1}" \
    73    || status="$?"
    74    status="${status:-0}"
    75  
    76    if [[ "${status}" -eq 0 || -z "${default}" ]]; then
    77      return "${status}"
    78    else
    79      echo "${default}"
    80    fi
    81  }
    82  
    83  function download-kube-env {
    84    # Fetch kube-env from GCE metadata server.
    85    (
    86      umask 077
    87      local -r tmp_kube_env="/tmp/kube-env.yaml"
    88      # shellcheck disable=SC2086
    89      retry-forever 10 curl ${CURL_FLAGS} \
    90        -H "X-Google-Metadata-Request: True" \
    91        -o "${tmp_kube_env}" \
    92        http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env
    93      # Convert the yaml format file into a shell-style file.
    94      eval "$(python3 -c '''
    95  import pipes,sys,yaml
    96  items = yaml.load(sys.stdin, Loader=yaml.BaseLoader).items()
    97  for k, v in items:
    98      print("readonly {var}={value}".format(var=k, value=pipes.quote(str(v))))
    99  ''' < "${tmp_kube_env}" > "${KUBE_HOME}/kube-env")"
   100      rm -f "${tmp_kube_env}"
   101    )
   102  }
   103  
   104  function download-kubelet-config {
   105    local -r dest="$1"
   106    echo "Downloading Kubelet config file, if it exists"
   107    # Fetch kubelet config file from GCE metadata server.
   108    (
   109      umask 077
   110      local -r tmp_kubelet_config="/tmp/kubelet-config.yaml"
   111      # shellcheck disable=SC2086
   112      retry-forever 10 curl ${CURL_FLAGS} \
   113        -H "X-Google-Metadata-Request: True" \
   114        -o "${tmp_kubelet_config}" \
   115        http://metadata.google.internal/computeMetadata/v1/instance/attributes/kubelet-config
   116      # only write to the final location if curl succeeds
   117      mv "${tmp_kubelet_config}" "${dest}"
   118    )
   119  }
   120  
   121  function download-kube-master-certs {
   122    # Fetch kube-env from GCE metadata server.
   123    (
   124      umask 077
   125      local -r tmp_kube_master_certs="/tmp/kube-master-certs.yaml"
   126      # shellcheck disable=SC2086
   127      retry-forever 10 curl ${CURL_FLAGS} \
   128        -H "X-Google-Metadata-Request: True" \
   129        -o "${tmp_kube_master_certs}" \
   130        http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-master-certs
   131      # Convert the yaml format file into a shell-style file.
   132      eval "$(python3 -c '''
   133  import pipes,sys,yaml
   134  items = yaml.load(sys.stdin, Loader=yaml.BaseLoader).items()
   135  for k, v in items:
   136      print("readonly {var}={value}".format(var=k, value=pipes.quote(str(v))))
   137  ''' < "${tmp_kube_master_certs}" > "${KUBE_HOME}/kube-master-certs")"
   138      rm -f "${tmp_kube_master_certs}"
   139    )
   140  }
   141  
   142  function validate-hash {
   143    local -r file="$1"
   144    local -r expected="$2"
   145  
   146    actual_sha1=$(sha1sum "${file}" | awk '{ print $1 }') || true
   147    actual_sha512=$(sha512sum "${file}" | awk '{ print $1 }') || true
   148    if [[ "${actual_sha1}" != "${expected}" ]] && [[ "${actual_sha512}" != "${expected}" ]]; then
   149      echo "== ${file} corrupted, sha1 ${actual_sha1}/sha512 ${actual_sha512} doesn't match expected ${expected} =="
   150      return 1
   151    fi
   152  }
   153  
   154  # Get default service account credentials of the VM.
   155  GCE_METADATA_INTERNAL="http://metadata.google.internal/computeMetadata/v1/instance"
   156  function get-credentials {
   157    # shellcheck disable=SC2086
   158    curl ${CURL_FLAGS} \
   159      -H "Metadata-Flavor: Google" \
   160      "${GCE_METADATA_INTERNAL}/service-accounts/default/token" \
   161    | python3 -c 'import sys; import json; print(json.loads(sys.stdin.read())["access_token"])'
   162  }
   163  
   164  function valid-storage-scope {
   165    # shellcheck disable=SC2086
   166    curl ${CURL_FLAGS} \
   167      -H "Metadata-Flavor: Google" \
   168      "${GCE_METADATA_INTERNAL}/service-accounts/default/scopes" \
   169    | grep -E "auth/devstorage|auth/cloud-platform"
   170  }
   171  
   172  # Retry a download until we get it. Takes a hash and a set of URLs.
   173  #
   174  # $1 is the sha512/sha1 hash of the URL. Can be "" if the sha512/sha1 hash is unknown.
   175  # $2+ are the URLs to download.
   176  function download-or-bust {
   177    local -r hash="$1"
   178    shift 1
   179  
   180    while true; do
   181      for url in "$@"; do
   182        local file="${url##*/}"
   183        rm -f "${file}"
   184        # if the url belongs to GCS API we should use oauth2_token in the headers if the VM service account has storage scopes
   185        local curl_headers=""
   186  
   187        if [[ "$url" =~ ^https://storage.googleapis.com.* ]] ; then
   188          local canUseCredentials=0
   189  
   190          echo "Getting the scope of service account configured for VM."
   191          if ! valid-storage-scope ; then
   192            canUseCredentials=1
   193            # this behavior is preserved for backward compatibility. We want to fail fast if SA is not available
   194            # and try to download without SA if scope does not exist on SA
   195            echo "No service account or service account without storage scope. Attempt to download without service account token."
   196          fi
   197  
   198          if [[ "${canUseCredentials}" == "0" ]] ; then
   199            echo "Getting the service account access token configured for VM."
   200            local access_token="";
   201            if access_token=$(get-credentials); then
   202              echo "Service account access token is received. Downloading ${url} using this token."
   203            else
   204              echo "Cannot get a service account token. Exiting."
   205              exit 1
   206            fi
   207  
   208            curl_headers=${access_token:+Authorization: Bearer "${access_token}"}
   209          fi
   210        fi
   211        if ! curl ${curl_headers:+-H "${curl_headers}"} -f --ipv4 -Lo "${file}" --connect-timeout 20 --max-time 300 --retry 6 --retry-delay 10 --retry-connrefused "${url}"; then
   212          echo "== Failed to download ${url}. Retrying. =="
   213        elif [[ -n "${hash}" ]] && ! validate-hash "${file}" "${hash}"; then
   214          echo "== Hash validation of ${url} failed. Retrying. =="
   215        else
   216          if [[ -n "${hash}" ]]; then
   217            echo "== Downloaded ${url} (HASH = ${hash}) =="
   218          else
   219            echo "== Downloaded ${url} =="
   220          fi
   221          return
   222        fi
   223      done
   224    done
   225  }
   226  
   227  function is-preloaded {
   228    local -r key=$1
   229    local -r value=$2
   230    grep -qs "${key},${value}" "${KUBE_HOME}/preload_info"
   231  }
   232  
   233  function split-commas {
   234    echo -e "${1//,/'\n'}"
   235  }
   236  
   237  function remount-flexvolume-directory {
   238    local -r flexvolume_plugin_dir=$1
   239    mkdir -p "$flexvolume_plugin_dir"
   240    mount --bind "$flexvolume_plugin_dir" "$flexvolume_plugin_dir"
   241    mount -o remount,exec "$flexvolume_plugin_dir"
   242  }
   243  
   244  function install-gci-mounter-tools {
   245    CONTAINERIZED_MOUNTER_HOME="${KUBE_HOME}/containerized_mounter"
   246    local -r mounter_tar_sha="${DEFAULT_MOUNTER_TAR_SHA}"
   247    if is-preloaded "mounter" "${mounter_tar_sha}"; then
   248      echo "mounter is preloaded."
   249      return
   250    fi
   251  
   252    echo "Downloading gci mounter tools."
   253    mkdir -p "${CONTAINERIZED_MOUNTER_HOME}"
   254    chmod a+x "${CONTAINERIZED_MOUNTER_HOME}"
   255    mkdir -p "${CONTAINERIZED_MOUNTER_HOME}/rootfs"
   256    download-or-bust "${mounter_tar_sha}" "https://storage.googleapis.com/kubernetes-release/gci-mounter/mounter.tar"
   257    cp "${KUBE_HOME}/kubernetes/server/bin/mounter" "${CONTAINERIZED_MOUNTER_HOME}/mounter"
   258    chmod a+x "${CONTAINERIZED_MOUNTER_HOME}/mounter"
   259    mv "${KUBE_HOME}/mounter.tar" /tmp/mounter.tar
   260    tar xf /tmp/mounter.tar -C "${CONTAINERIZED_MOUNTER_HOME}/rootfs"
   261    rm /tmp/mounter.tar
   262    mkdir -p "${CONTAINERIZED_MOUNTER_HOME}/rootfs/var/lib/kubelet"
   263  }
   264  
   265  # Install node problem detector binary.
   266  function install-node-problem-detector {
   267    if [[ -n "${NODE_PROBLEM_DETECTOR_VERSION:-}" ]]; then
   268        local -r npd_version="${NODE_PROBLEM_DETECTOR_VERSION}"
   269        local -r npd_hash="${NODE_PROBLEM_DETECTOR_TAR_HASH}"
   270    else
   271        local -r npd_version="${DEFAULT_NPD_VERSION}"
   272        case "${HOST_PLATFORM}/${HOST_ARCH}" in
   273          linux/amd64)
   274            local -r npd_hash="${DEFAULT_NPD_HASH_AMD64}"
   275            ;;
   276          linux/arm64)
   277            local -r npd_hash="${DEFAULT_NPD_HASH_ARM64}"
   278            ;;
   279          # no other architectures are supported currently.
   280          # Assumption is that this script only runs on linux,
   281          # see cluster/gce/windows/k8s-node-setup.psm1 for windows
   282          # https://github.com/kubernetes/node-problem-detector/releases/
   283          *)
   284            echo "Unrecognized version and platform/arch combination:"
   285            echo "$DEFAULT_NPD_VERSION $HOST_PLATFORM/$HOST_ARCH"
   286            echo "Set NODE_PROBLEM_DETECTOR_VERSION and NODE_PROBLEM_DETECTOR_TAR_HASH to overwrite"
   287            exit 1
   288            ;;
   289        esac
   290    fi
   291    local -r npd_tar="node-problem-detector-${npd_version}-${HOST_PLATFORM}_${HOST_ARCH}.tar.gz"
   292  
   293    if is-preloaded "${npd_tar}" "${npd_hash}"; then
   294      echo "${npd_tar} is preloaded."
   295      return
   296    fi
   297  
   298    if [[ -n "${NODE_PROBLEM_DETECTOR_RELEASE_PATH:-}" ]]; then
   299      echo "Downloading ${npd_tar} from ${NODE_PROBLEM_DETECTOR_RELEASE_PATH}."
   300      local -r download_path="${NODE_PROBLEM_DETECTOR_RELEASE_PATH}/node-problem-detector/${npd_tar}"
   301    else
   302      echo "Downloading ${npd_tar} from github."
   303      local -r download_path="https://github.com/kubernetes/node-problem-detector/releases/download/${npd_version}/${npd_tar}"
   304    fi
   305    download-or-bust "${npd_hash}" "${download_path}"
   306    local -r npd_dir="${KUBE_HOME}/node-problem-detector"
   307    mkdir -p "${npd_dir}"
   308    tar xzf "${KUBE_HOME}/${npd_tar}" -C "${npd_dir}" --overwrite
   309    mv "${npd_dir}/bin"/* "${KUBE_BIN}"
   310    chmod a+x "${KUBE_BIN}/node-problem-detector"
   311    rmdir "${npd_dir}/bin"
   312    rm -f "${KUBE_HOME}/${npd_tar}"
   313  }
   314  
   315  function install-cni-binaries {
   316    local -r cni_version=${CNI_VERSION:-$DEFAULT_CNI_VERSION}
   317    if [[ -n "${CNI_VERSION:-}" ]]; then
   318        local -r cni_hash="${CNI_HASH:-}"
   319    else
   320        local -r cni_hash="${DEFAULT_CNI_HASH}"
   321    fi
   322  
   323    local -r cni_tar="${CNI_TAR_PREFIX}${cni_version}.tgz"
   324    local -r cni_url="${CNI_STORAGE_URL_BASE}/${cni_version}/${cni_tar}"
   325  
   326    if is-preloaded "${cni_tar}" "${cni_hash}"; then
   327      echo "${cni_tar} is preloaded."
   328      return
   329    fi
   330  
   331    echo "Downloading cni binaries"
   332    download-or-bust "${cni_hash}" "${cni_url}"
   333    local -r cni_dir="${KUBE_HOME}/cni"
   334    mkdir -p "${cni_dir}/bin"
   335    tar xzf "${KUBE_HOME}/${cni_tar}" -C "${cni_dir}/bin" --overwrite
   336    mv "${cni_dir}/bin"/* "${KUBE_BIN}"
   337    rmdir "${cni_dir}/bin"
   338    rm -f "${KUBE_HOME}/${cni_tar}"
   339  }
   340  
   341  # Install crictl binary.
   342  # Assumptions: HOST_PLATFORM and HOST_ARCH are specified by calling detect_host_info.
   343  function install-crictl {
   344    if [[ -n "${CRICTL_VERSION:-}" ]]; then
   345      local -r crictl_version="${CRICTL_VERSION}"
   346      local -r crictl_hash="${CRICTL_TAR_HASH}"
   347    else
   348      local -r crictl_version="${DEFAULT_CRICTL_VERSION}"
   349      case "${HOST_PLATFORM}/${HOST_ARCH}" in
   350        linux/amd64)
   351          local -r crictl_hash="${DEFAULT_CRICTL_AMD64_SHA512}"
   352          ;;
   353        linux/arm64)
   354          local -r crictl_hash="${DEFAULT_CRICTL_ARM64_SHA512}"
   355          ;;
   356        *)
   357          echo "Unrecognized version and platform/arch combination:"
   358          echo "$DEFAULT_CRICTL_VERSION $HOST_PLATFORM/$HOST_ARCH"
   359          echo "Set CRICTL_VERSION and CRICTL_TAR_HASH to overwrite"
   360          exit 1
   361      esac
   362    fi
   363    local -r crictl="crictl-${crictl_version}-${HOST_PLATFORM}-${HOST_ARCH}.tar.gz"
   364  
   365    # Create crictl config file.
   366    cat > /etc/crictl.yaml <<EOF
   367  runtime-endpoint: ${CONTAINER_RUNTIME_ENDPOINT:-unix:///run/containerd/containerd.sock}
   368  EOF
   369  
   370    if is-preloaded "${crictl}" "${crictl_hash}"; then
   371      echo "crictl is preloaded"
   372      return
   373    fi
   374  
   375    echo "Downloading crictl"
   376    local -r crictl_path="https://storage.googleapis.com/k8s-artifacts-cri-tools/release/${crictl_version}"
   377    download-or-bust "${crictl_hash}" "${crictl_path}/${crictl}"
   378    tar xf "${crictl}"
   379    mv crictl "${KUBE_BIN}/crictl"
   380    rm -f "${crictl}"
   381  }
   382  
   383  function install-kube-manifests {
   384    # Put kube-system pods manifests in ${KUBE_HOME}/kube-manifests/.
   385    local dst_dir="${KUBE_HOME}/kube-manifests"
   386    mkdir -p "${dst_dir}"
   387    local manifests_tar_urls
   388    while IFS= read -r url; do
   389      manifests_tar_urls+=("$url")
   390    done < <(split-commas "${KUBE_MANIFESTS_TAR_URL}")
   391    local -r manifests_tar="${manifests_tar_urls[0]##*/}"
   392    if [ -n "${KUBE_MANIFESTS_TAR_HASH:-}" ]; then
   393      local -r manifests_tar_hash="${KUBE_MANIFESTS_TAR_HASH}"
   394    else
   395      echo "Downloading k8s manifests hash (not found in env)"
   396      download-or-bust "" "${manifests_tar_urls[@]/.tar.gz/.tar.gz.sha512}"
   397      local -r manifests_tar_hash=$(cat "${manifests_tar}.sha512")
   398    fi
   399  
   400    if is-preloaded "${manifests_tar}" "${manifests_tar_hash}"; then
   401      echo "${manifests_tar} is preloaded."
   402      return
   403    fi
   404  
   405    echo "Downloading k8s manifests tar"
   406    download-or-bust "${manifests_tar_hash}" "${manifests_tar_urls[@]}"
   407    tar xzf "${KUBE_HOME}/${manifests_tar}" -C "${dst_dir}" --overwrite
   408    local -r kube_addon_registry="${KUBE_ADDON_REGISTRY:-registry.k8s.io}"
   409    if [[ "${kube_addon_registry}" != "registry.k8s.io" ]]; then
   410      find "${dst_dir}" \( -name '*.yaml' -or -name '*.yaml.in' \) -print0 | \
   411        xargs -0 sed -ri "s@(image:\s.*)registry.k8s.io@\1${kube_addon_registry}@"
   412      find "${dst_dir}" \( -name '*.manifest' -or -name '*.json' \) -print0 | \
   413        xargs -0 sed -ri "s@(image\":\s+\")registry.k8s.io@\1${kube_addon_registry}@"
   414    fi
   415    cp "${dst_dir}/kubernetes/gci-trusty/gci-configure-helper.sh" "${KUBE_BIN}/configure-helper.sh"
   416    cp "${dst_dir}/kubernetes/gci-trusty/configure-kubeapiserver.sh" "${KUBE_BIN}/configure-kubeapiserver.sh"
   417    if [[ -e "${dst_dir}/kubernetes/gci-trusty/gke-internal-configure-helper.sh" ]]; then
   418      cp "${dst_dir}/kubernetes/gci-trusty/gke-internal-configure-helper.sh" "${KUBE_BIN}/"
   419    fi
   420  
   421    cp "${dst_dir}/kubernetes/gci-trusty/health-monitor.sh" "${KUBE_BIN}/health-monitor.sh"
   422  
   423    rm -f "${KUBE_HOME}/${manifests_tar}"
   424    rm -f "${KUBE_HOME}/${manifests_tar}.sha512"
   425  }
   426  
   427  # A helper function for loading a docker image. It keeps trying up to 5 times.
   428  #
   429  # $1: Full path of the docker image
   430  function try-load-docker-image {
   431    local -r img=$1
   432    echo "Try to load docker image file ${img}"
   433    # Temporarily turn off errexit, because we don't want to exit on first failure.
   434    set +e
   435    local -r max_attempts=5
   436    local -i attempt_num=1
   437  
   438    if [[ "${CONTAINER_RUNTIME_NAME:-}" == "containerd" || "${CONTAINERD_TEST:-}"  == "containerd" ]]; then
   439      load_image_command=${LOAD_IMAGE_COMMAND:-ctr -n=k8s.io images import}
   440      tag_image_command=${TAG_IMAGE_COMMAND:-ctr -n=k8s.io images tag}
   441    else
   442      load_image_command="${LOAD_IMAGE_COMMAND:-}"
   443      tag_image_command="${TAG_IMAGE_COMMAND:-}"
   444    fi
   445  
   446    # Deliberately word split load_image_command
   447    # shellcheck disable=SC2086
   448    until timeout 30 ${load_image_command} "${img}"; do
   449      if [[ "${attempt_num}" == "${max_attempts}" ]]; then
   450        echo "Fail to load docker image file ${img} using ${load_image_command} after ${max_attempts} retries. Exit!!"
   451        exit 1
   452      else
   453        attempt_num=$((attempt_num+1))
   454        sleep 5
   455      fi
   456    done
   457  
   458    if [[ -n "${KUBE_ADDON_REGISTRY:-}" ]]; then
   459      # remove the prefix and suffix from the path to get the container name
   460      container=${img##*/}
   461      container=${container%.tar}
   462      # find the right one for which we will need an additional tag
   463      container=$(ctr -n k8s.io images ls | grep "registry.k8s.io/${container}" | awk '{print $1}' | cut -f 2 -d '/')
   464      ${tag_image_command} "registry.k8s.io/${container}" "${KUBE_ADDON_REGISTRY}/${container}"
   465    fi
   466    # Re-enable errexit.
   467    set -e
   468  }
   469  
   470  # Loads kube-system docker images. It is better to do it before starting kubelet,
   471  # as kubelet will restart docker daemon, which may interfere with loading images.
   472  function load-docker-images {
   473    echo "Start loading kube-system docker images"
   474    local -r img_dir="${KUBE_HOME}/kube-docker-files"
   475    if [[ "${KUBERNETES_MASTER:-}" == "true" ]]; then
   476      try-load-docker-image "${img_dir}/kube-apiserver.tar"
   477      try-load-docker-image "${img_dir}/kube-controller-manager.tar"
   478      try-load-docker-image "${img_dir}/kube-scheduler.tar"
   479    else
   480      try-load-docker-image "${img_dir}/kube-proxy.tar"
   481    fi
   482  }
   483  
   484  # If we are on ubuntu we can try to install containerd
   485  function install-containerd-ubuntu {
   486    # bailout if we are not on ubuntu
   487    if [[ -z "$(command -v lsb_release)" || $(lsb_release -si) != "Ubuntu" ]]; then
   488      echo "Unable to automatically install containerd in non-ubuntu image. Bailing out..."
   489      exit 2
   490    fi
   491  
   492    # Install dependencies, some of these are already installed in the image but
   493    # that's fine since they won't re-install and we can reuse the code below
   494    # for another image someday.
   495    apt-get update
   496    apt-get install -y --no-install-recommends \
   497      apt-transport-https \
   498      ca-certificates \
   499      socat \
   500      curl \
   501      gnupg2 \
   502      software-properties-common \
   503      lsb-release
   504  
   505    release=$(lsb_release -cs)
   506  
   507    # Add the Docker apt-repository (as we install containerd from there)
   508    # shellcheck disable=SC2086
   509    curl ${CURL_FLAGS} \
   510      --location \
   511      "https://download.docker.com/${HOST_PLATFORM}/$(. /etc/os-release; echo "$ID")/gpg" \
   512    | apt-key add -
   513    add-apt-repository \
   514      "deb [arch=${HOST_ARCH}] https://download.docker.com/${HOST_PLATFORM}/$(. /etc/os-release; echo "$ID") \
   515      $release stable"
   516  
   517    # Install containerd from Docker repo
   518    apt-get update && \
   519      apt-get install -y --no-install-recommends containerd
   520    rm -rf /var/lib/apt/lists/*
   521  
   522    # Override to latest versions of containerd and runc
   523    systemctl stop containerd
   524    if [[ -n "${UBUNTU_INSTALL_CONTAINERD_VERSION:-}" ]]; then
   525      # containerd versions have slightly different url(s), so try both
   526      # shellcheck disable=SC2086
   527      ( curl ${CURL_FLAGS} \
   528          --location \
   529          "https://github.com/containerd/containerd/releases/download/${UBUNTU_INSTALL_CONTAINERD_VERSION}/containerd-${UBUNTU_INSTALL_CONTAINERD_VERSION:1}-${HOST_PLATFORM}-${HOST_ARCH}.tar.gz" \
   530        || curl ${CURL_FLAGS} \
   531          --location \
   532          "https://github.com/containerd/containerd/releases/download/${UBUNTU_INSTALL_CONTAINERD_VERSION}/containerd-${UBUNTU_INSTALL_CONTAINERD_VERSION:1}.${HOST_PLATFORM}-${HOST_ARCH}.tar.gz" ) \
   533      | tar --overwrite -xzv -C /usr/
   534    fi
   535    if [[ -n "${UBUNTU_INSTALL_RUNC_VERSION:-}" ]]; then
   536      # shellcheck disable=SC2086
   537      curl ${CURL_FLAGS} \
   538        --location \
   539        "https://github.com/opencontainers/runc/releases/download/${UBUNTU_INSTALL_RUNC_VERSION}/runc.${HOST_ARCH}" --output /usr/sbin/runc \
   540      && chmod 755 /usr/sbin/runc
   541    fi
   542    sudo systemctl start containerd
   543  }
   544  
   545  # If we are on cos we can try to install containerd
   546  function install-containerd-cos {
   547    # bailout if we are not on COS
   548    if [ -e /etc/os-release ] && ! grep -q "ID=cos" /etc/os-release; then
   549      echo "Unable to automatically install containerd in non-cos image. Bailing out..."
   550      exit 2
   551    fi
   552  
   553    # Override to latest versions of containerd and runc
   554    systemctl stop containerd
   555    mkdir -p /home/containerd/
   556    mount --bind /home/containerd /home/containerd
   557    mount -o remount,exec /home/containerd
   558    if [[ -n "${COS_INSTALL_CONTAINERD_VERSION:-}" ]]; then
   559      # containerd versions have slightly different url(s), so try both
   560      # shellcheck disable=SC2086
   561      ( curl ${CURL_FLAGS} \
   562          --location \
   563          "https://github.com/containerd/containerd/releases/download/${COS_INSTALL_CONTAINERD_VERSION}/containerd-${COS_INSTALL_CONTAINERD_VERSION:1}-${HOST_PLATFORM}-${HOST_ARCH}.tar.gz" \
   564        || curl ${CURL_FLAGS} \
   565          --location \
   566          "https://github.com/containerd/containerd/releases/download/${COS_INSTALL_CONTAINERD_VERSION}/containerd-${COS_INSTALL_CONTAINERD_VERSION:1}.${HOST_PLATFORM}-${HOST_ARCH}.tar.gz" ) \
   567      | tar --overwrite -xzv -C /home/containerd/
   568      cp /usr/lib/systemd/system/containerd.service /etc/systemd/system/containerd.service
   569      # fix the path of the new containerd binary
   570      sed -i 's|ExecStart=.*|ExecStart=/home/containerd/bin/containerd|' /etc/systemd/system/containerd.service
   571    fi
   572    if [[ -n "${COS_INSTALL_RUNC_VERSION:-}" ]]; then
   573      # shellcheck disable=SC2086
   574      curl ${CURL_FLAGS} \
   575        --location \
   576        "https://github.com/opencontainers/runc/releases/download/${COS_INSTALL_RUNC_VERSION}/runc.${HOST_ARCH}" --output /home/containerd/bin/runc \
   577      && chmod 755 /home/containerd/bin/runc
   578      # ensure runc gets picked up from the correct location
   579      sed -i "/\[Service\]/a Environment=PATH=/home/containerd/bin:$PATH" /etc/systemd/system/containerd.service
   580    fi
   581    systemctl daemon-reload
   582    sudo systemctl start containerd
   583  }
   584  
   585  function install-auth-provider-gcp {
   586    local -r filename="auth-provider-gcp"
   587    local -r auth_provider_storage_full_path="${AUTH_PROVIDER_GCP_STORAGE_PATH}/${AUTH_PROVIDER_GCP_VERSION}/${HOST_PLATFORM}_${HOST_ARCH}/${filename}"
   588    echo "Downloading auth-provider-gcp ${auth_provider_storage_full_path}" .
   589  
   590    case "${HOST_ARCH}" in
   591      amd64)
   592        local -r auth_provider_gcp_hash="${AUTH_PROVIDER_GCP_HASH_LINUX_AMD64}"
   593        ;;
   594      arm64)
   595        local -r auth_provider_gcp_hash="${AUTH_PROVIDER_GCP_HASH_LINUX_ARM64}"
   596        ;;
   597      *)
   598        echo "Unrecognized version and platform/arch combination: ${HOST_PLATFORM}/${HOST_ARCH}"
   599        exit 1
   600    esac
   601  
   602    download-or-bust "${auth_provider_gcp_hash}" "${auth_provider_storage_full_path}"
   603  
   604    mv "${KUBE_HOME}/${filename}" "${AUTH_PROVIDER_GCP_LINUX_BIN_DIR}"
   605    chmod a+x "${AUTH_PROVIDER_GCP_LINUX_BIN_DIR}/${filename}"
   606  
   607    cat >> "${AUTH_PROVIDER_GCP_LINUX_CONF_FILE}" << EOF
   608  kind: CredentialProviderConfig
   609  apiVersion: kubelet.config.k8s.io/v1
   610  providers:
   611    - name: auth-provider-gcp
   612      apiVersion: credentialprovider.kubelet.k8s.io/v1
   613      matchImages:
   614      - "container.cloud.google.com"
   615      - "gcr.io"
   616      - "*.gcr.io"
   617      - "*.pkg.dev"
   618      args:
   619      - get-credentials
   620      - --v=3
   621      defaultCacheDuration: 1m
   622  EOF
   623  }
   624  
   625  function ensure-containerd-runtime {
   626    # Install containerd/runc if requested
   627    if [[ -n "${UBUNTU_INSTALL_CONTAINERD_VERSION:-}" || -n "${UBUNTU_INSTALL_RUNC_VERSION:-}" ]]; then
   628      log-wrap "InstallContainerdUbuntu" install-containerd-ubuntu
   629    fi
   630    if [[ -n "${COS_INSTALL_CONTAINERD_VERSION:-}" || -n "${COS_INSTALL_RUNC_VERSION:-}" ]]; then
   631      log-wrap "InstallContainerdCOS" install-containerd-cos
   632    fi
   633  
   634    # Fall back to installing distro specific containerd, if not found
   635    if ! command -v containerd >/dev/null 2>&1; then
   636      local linuxrelease="cos"
   637      if [[ -n "$(command -v lsb_release)" ]]; then
   638        linuxrelease=$(lsb_release -si)
   639      fi
   640      case "${linuxrelease}" in
   641        Ubuntu)
   642          log-wrap "InstallContainerdUbuntu" install-containerd-ubuntu
   643          ;;
   644        cos)
   645          log-wrap "InstallContainerdCOS" install-containerd-cos
   646          ;;
   647        *)
   648          echo "Installing containerd for linux release ${linuxrelease} not supported" >&2
   649          exit 2
   650          ;;
   651      esac
   652    fi
   653  
   654    # when custom containerd version is installed sourcing containerd_env.sh will add all tools like ctr to the PATH
   655    if [[ -e "/etc/profile.d/containerd_env.sh" ]]; then
   656     log-wrap 'SourceContainerdEnv' source "/etc/profile.d/containerd_env.sh"
   657    fi
   658  
   659    # Verify presence and print versions of ctr, containerd, runc
   660    if ! command -v ctr >/dev/null 2>&1; then
   661      echo "ERROR ctr not found. Aborting."
   662      exit 2
   663    fi
   664    ctr --version
   665    if ! command -v containerd >/dev/null 2>&1; then
   666      echo "ERROR containerd not found. Aborting."
   667      exit 2
   668    fi
   669    containerd --version
   670    if ! command -v runc >/dev/null 2>&1; then
   671      echo "ERROR runc not found. Aborting."
   672      exit 2
   673    fi
   674    runc --version
   675  }
   676  
   677  function ensure-container-runtime {
   678    case "${CONTAINER_RUNTIME_NAME:-containerd}" in
   679      containerd)
   680        ensure-containerd-runtime
   681        ;;
   682      #TODO: Add crio support
   683      *)
   684        echo "Unsupported container runtime (${CONTAINER_RUNTIME_NAME})." >&2
   685        exit 2
   686        ;;
   687    esac
   688  }
   689  
   690  # Downloads kubernetes binaries and kube-system manifest tarball, unpacks them,
   691  # and places them into suitable directories. Files are placed in /home/kubernetes.
   692  function install-kube-binary-config {
   693    cd "${KUBE_HOME}"
   694    local server_binary_tar_urls
   695    while IFS= read -r url; do
   696      server_binary_tar_urls+=("$url")
   697    done < <(split-commas "${SERVER_BINARY_TAR_URL}")
   698    local -r server_binary_tar="${server_binary_tar_urls[0]##*/}"
   699    if [[ -n "${SERVER_BINARY_TAR_HASH:-}" ]]; then
   700      local -r server_binary_tar_hash="${SERVER_BINARY_TAR_HASH}"
   701    else
   702      echo "Downloading binary release sha512 (not found in env)"
   703      log-wrap "DownloadServerBinarySHA" download-or-bust "" "${server_binary_tar_urls[@]/.tar.gz/.tar.gz.sha512}"
   704      local -r server_binary_tar_hash=$(cat "${server_binary_tar}.sha512")
   705    fi
   706  
   707    if is-preloaded "${server_binary_tar}" "${server_binary_tar_hash}"; then
   708      echo "${server_binary_tar} is preloaded."
   709    else
   710      echo "Downloading binary release tar"
   711      log-wrap "DownloadServerBinary" download-or-bust "${server_binary_tar_hash}" "${server_binary_tar_urls[@]}"
   712      log-wrap "UntarServerBinary" tar xzf "${KUBE_HOME}/${server_binary_tar}" -C "${KUBE_HOME}" --overwrite
   713      # Copy docker_tag and image files to ${KUBE_HOME}/kube-docker-files.
   714      local -r src_dir="${KUBE_HOME}/kubernetes/server/bin"
   715      local dst_dir="${KUBE_HOME}/kube-docker-files"
   716      mkdir -p "${dst_dir}"
   717      cp "${src_dir}/"*.docker_tag "${dst_dir}"
   718      if [[ "${KUBERNETES_MASTER:-}" == "false" ]]; then
   719        cp "${src_dir}/kube-proxy.tar" "${dst_dir}"
   720      else
   721        cp "${src_dir}/kube-apiserver.tar" "${dst_dir}"
   722        cp "${src_dir}/kube-controller-manager.tar" "${dst_dir}"
   723        cp "${src_dir}/kube-scheduler.tar" "${dst_dir}"
   724        cp -r "${KUBE_HOME}/kubernetes/addons" "${dst_dir}"
   725      fi
   726      log-wrap "LoadDockerImages" load-docker-images
   727      mv "${src_dir}/kubelet" "${KUBE_BIN}"
   728      mv "${src_dir}/kubectl" "${KUBE_BIN}"
   729  
   730      # Some older images have LICENSES baked-in as a file. Presumably they will
   731      # have the directory baked-in eventually.
   732      rm -rf "${KUBE_HOME}"/LICENSES
   733      mv "${KUBE_HOME}/kubernetes/LICENSES" "${KUBE_HOME}"
   734      mv "${KUBE_HOME}/kubernetes/kubernetes-src.tar.gz" "${KUBE_HOME}"
   735    fi
   736  
   737    if [[ "${KUBERNETES_MASTER:-}" == "false" ]] && \
   738       [[ "${ENABLE_NODE_PROBLEM_DETECTOR:-}" == "standalone" ]]; then
   739      log-wrap "InstallNodeProblemDetector" install-node-problem-detector
   740    fi
   741  
   742    if [[ "${NETWORK_PROVIDER:-}" == "kubenet" ]] || \
   743       [[ "${NETWORK_PROVIDER:-}" == "cni" ]]; then
   744      log-wrap "InstallCNIBinaries" install-cni-binaries
   745    fi
   746  
   747    # Put kube-system pods manifests in ${KUBE_HOME}/kube-manifests/.
   748    log-wrap "InstallKubeManifests" install-kube-manifests
   749    chmod -R 755 "${KUBE_BIN}"
   750  
   751    # Install gci mounter related artifacts to allow mounting storage volumes in GCI
   752    log-wrap "InstallGCIMounterTools" install-gci-mounter-tools
   753  
   754    # Remount the Flexvolume directory with the "exec" option, if needed.
   755    if [[ "${REMOUNT_VOLUME_PLUGIN_DIR:-}" == "true" && -n "${VOLUME_PLUGIN_DIR:-}" ]]; then
   756      log-wrap "RemountFlexVolume" remount-flexvolume-directory "${VOLUME_PLUGIN_DIR}"
   757    fi
   758  
   759    # When ENABLE_AUTH_PROVIDER_GCP is set, following flags for out-of-tree credential provider for GCP
   760    # are presented to kubelet:
   761    # --image-credential-provider-config=${path-to-config}
   762    # --image-credential-provider-bin-dir=${path-to-auth-provider-binary}
   763    # Also, it is required that DisableKubeletCloudCredentialProviders
   764    # feature gate is set to true for kubelet to use external credential provider.
   765    if [[ "${ENABLE_AUTH_PROVIDER_GCP:-}" == "true" ]]; then
   766      # Install out-of-tree auth-provider-gcp binary to enable kubelet to dynamically
   767      # retrieve credentials for a container image registry.
   768      log-wrap "InstallCredentialProvider" install-auth-provider-gcp
   769    fi
   770    # Install crictl on each node.
   771    log-wrap "InstallCrictl" install-crictl
   772  
   773    # Clean up.
   774    rm -rf "${KUBE_HOME}/kubernetes"
   775    rm -f "${KUBE_HOME}/${server_binary_tar}"
   776    rm -f "${KUBE_HOME}/${server_binary_tar}.sha512"
   777  }
   778  
   779  
   780  # This function detects the platform/arch of the machine where the script runs,
   781  # and sets the HOST_PLATFORM and HOST_ARCH environment variables accordingly.
   782  # Callers can specify HOST_PLATFORM_OVERRIDE and HOST_ARCH_OVERRIDE to skip the detection.
   783  # This function is adapted from the detect_client_info function in cluster/get-kube-binaries.sh
   784  # and kube::util::host_os, kube::util::host_arch functions in hack/lib/util.sh
   785  # This function should be synced with detect_host_info in ./configure-helper.sh
   786  function detect_host_info() {
   787    HOST_PLATFORM=${HOST_PLATFORM_OVERRIDE:-"$(uname -s)"}
   788    case "${HOST_PLATFORM}" in
   789      Linux|linux)
   790        HOST_PLATFORM="linux"
   791        ;;
   792      *)
   793        echo "Unknown, unsupported platform: ${HOST_PLATFORM}." >&2
   794        echo "Supported platform(s): linux." >&2
   795        echo "Bailing out." >&2
   796        exit 2
   797    esac
   798  
   799    HOST_ARCH=${HOST_ARCH_OVERRIDE:-"$(uname -m)"}
   800    case "${HOST_ARCH}" in
   801      x86_64*|i?86_64*|amd64*)
   802        HOST_ARCH="amd64"
   803        ;;
   804      aHOST_arch64*|aarch64*|arm64*)
   805        HOST_ARCH="arm64"
   806        ;;
   807      *)
   808        echo "Unknown, unsupported architecture (${HOST_ARCH})." >&2
   809        echo "Supported architecture(s): amd64 and arm64." >&2
   810        echo "Bailing out." >&2
   811        exit 2
   812        ;;
   813    esac
   814  }
   815  
   816  # Retries a command forever with a delay between retries.
   817  # Args:
   818  #  $1    : delay between retries, in seconds.
   819  #  $2... : the command to run.
   820  function retry-forever {
   821    local -r delay="$1"
   822    shift 1
   823  
   824    until "$@"; do
   825      echo "== $* failed, retrying after ${delay}s"
   826      sleep "${delay}"
   827    done
   828  }
   829  
   830  # Initializes variables used by the log-* functions.
   831  #
   832  # get-metadata-value must be defined before calling this function.
   833  #
   834  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   835  # should be duplicated there as well.
   836  function log-init {
   837    # Used by log-* functions.
   838    LOG_CLUSTER_ID=$(get-metadata-value 'instance/attributes/cluster-uid' 'get-metadata-value-error')
   839    LOG_INSTANCE_NAME=$(hostname)
   840    LOG_BOOT_ID=$(journalctl --list-boots | grep -E '^ *0' | awk '{print $2}')
   841    declare -Ag LOG_START_TIMES
   842    declare -ag LOG_TRAP_STACK
   843  
   844    LOG_STATUS_STARTED='STARTED'
   845    LOG_STATUS_COMPLETED='COMPLETED'
   846    LOG_STATUS_ERROR='ERROR'
   847  }
   848  
   849  # Sets an EXIT trap.
   850  # Args:
   851  #   $1:... : the trap command.
   852  #
   853  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   854  # should be duplicated there as well.
   855  function log-trap-push {
   856    local t="${*:1}"
   857    LOG_TRAP_STACK+=("${t}")
   858    # shellcheck disable=2064
   859    trap "${t}" EXIT
   860  }
   861  
   862  # Removes and restores an EXIT trap.
   863  #
   864  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   865  # should be duplicated there as well.
   866  function log-trap-pop {
   867    # Remove current trap.
   868    unset 'LOG_TRAP_STACK[-1]'
   869  
   870    # Restore previous trap.
   871    if [ ${#LOG_TRAP_STACK[@]} -ne 0 ]; then
   872      local t="${LOG_TRAP_STACK[-1]}"
   873      # shellcheck disable=2064
   874      trap "${t}" EXIT
   875    else
   876      # If no traps in stack, clear.
   877      trap EXIT
   878    fi
   879  }
   880  
   881  # Logs the end of a bootstrap step that errored.
   882  # Args:
   883  #  $1 : bootstrap step name.
   884  #
   885  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   886  # should be duplicated there as well.
   887  function log-error {
   888    local bootstep="$1"
   889  
   890    log-proto "${bootstep}" "${LOG_STATUS_ERROR}" "encountered non-zero exit code"
   891  }
   892  
   893  # Wraps a command with bootstrap logging.
   894  # Args:
   895  #   $1    : bootstrap step name.
   896  #   $2... : the command to run.
   897  #
   898  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   899  # should be duplicated there as well.
   900  function log-wrap {
   901    local bootstep="$1"
   902    local command="${*:2}"
   903  
   904    log-trap-push "log-error ${bootstep}"
   905    log-proto "${bootstep}" "${LOG_STATUS_STARTED}"
   906    $command
   907    log-proto "${bootstep}" "${LOG_STATUS_COMPLETED}"
   908    log-trap-pop
   909  }
   910  
   911  # Logs a bootstrap step start. Prefer log-wrap.
   912  # Args:
   913  #   $1 : bootstrap step name.
   914  #
   915  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   916  # should be duplicated there as well.
   917  function log-start {
   918    local bootstep="$1"
   919  
   920    log-trap-push "log-error ${bootstep}"
   921    log-proto "${bootstep}" "${LOG_STATUS_STARTED}"
   922  }
   923  
   924  # Logs a bootstrap step end. Prefer log-wrap.
   925  # Args:
   926  #   $1 : bootstrap step name.
   927  #
   928  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   929  # should be duplicated there as well.
   930  function log-end {
   931    local bootstep="$1"
   932  
   933    log-proto "${bootstep}" "${LOG_STATUS_COMPLETED}"
   934    log-trap-pop
   935  }
   936  
   937  # Writes a log proto to stdout.
   938  # Args:
   939  #   $1: bootstrap step name.
   940  #   $2: status. Either 'STARTED', 'COMPLETED', or 'ERROR'.
   941  #   $3: optional status reason.
   942  #
   943  # NOTE: this function is duplicated in configure-helper.sh, any changes here
   944  # should be duplicated there as well.
   945  function log-proto {
   946    local bootstep="$1"
   947    local status="$2"
   948    local status_reason="${3:-}"
   949  
   950    # Get current time.
   951    local current_time
   952    current_time="$(date --utc '+%s.%N')"
   953    # ...formatted as UTC RFC 3339.
   954    local timestamp
   955    timestamp="$(date --utc --date="@${current_time}" '+%FT%T.%NZ')"
   956  
   957    # Calculate latency.
   958    local latency='null'
   959    if [ "${status}" == "${LOG_STATUS_STARTED}" ]; then
   960      LOG_START_TIMES["${bootstep}"]="${current_time}"
   961    else
   962      local start_time="${LOG_START_TIMES["${bootstep}"]}"
   963      unset 'LOG_START_TIMES['"${bootstep}"']'
   964  
   965      # Bash cannot do non-integer math, shell out to awk.
   966      latency="$(echo "${current_time} ${start_time}" | awk '{print $1 - $2}')s"
   967  
   968      # The default latency is null which cannot be wrapped as a string so we must
   969      # do it here instead of the printf.
   970      latency="\"${latency}\""
   971    fi
   972  
   973    printf '[cloud.kubernetes.monitoring.proto.SerialportLog] {"cluster_hash":"%s","vm_instance_name":"%s","boot_id":"%s","timestamp":"%s","bootstrap_status":{"step_name":"%s","status":"%s","status_reason":"%s","latency":%s}}\n' \
   974    "${LOG_CLUSTER_ID}" "${LOG_INSTANCE_NAME}" "${LOG_BOOT_ID}" "${timestamp}" "${bootstep}" "${status}" "${status_reason}" "${latency}"
   975  }
   976  
   977  ######### Main Function ##########
   978  log-init
   979  log-start 'ConfigureMain'
   980  echo "Start to install kubernetes files"
   981  log-wrap 'DetectHostInfo' detect_host_info
   982  
   983  # if install fails, message-of-the-day (motd) will warn at login shell
   984  log-wrap 'SetBrokenMotd' set-broken-motd
   985  
   986  KUBE_HOME="/home/kubernetes"
   987  KUBE_BIN="${KUBE_HOME}/bin"
   988  
   989  # download and source kube-env
   990  log-wrap 'DownloadKubeEnv' download-kube-env
   991  log-wrap 'SourceKubeEnv' source "${KUBE_HOME}/kube-env"
   992  
   993  log-wrap 'DownloadKubeletConfig' download-kubelet-config "${KUBE_HOME}/kubelet-config.yaml"
   994  
   995  # master certs
   996  if [[ "${KUBERNETES_MASTER:-}" == "true" ]]; then
   997    log-wrap 'DownloadKubeMasterCerts' download-kube-master-certs
   998  fi
   999  
  1000  # ensure chosen container runtime is present
  1001  log-wrap 'EnsureContainerRuntime' ensure-container-runtime
  1002  
  1003  # binaries and kube-system manifests
  1004  log-wrap 'InstallKubeBinaryConfig' install-kube-binary-config
  1005  
  1006  echo "Done for installing kubernetes files"
  1007  log-end 'ConfigureMain'