k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/hack/lib/etcd.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copyright 2014 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 set of helpers for starting/running etcd for tests
    18  
    19  ETCD_VERSION=${ETCD_VERSION:-3.5.13}
    20  ETCD_HOST=${ETCD_HOST:-127.0.0.1}
    21  ETCD_PORT=${ETCD_PORT:-2379}
    22  # This is intentionally not called ETCD_LOG_LEVEL:
    23  # etcd checks that and compains when it is set in addition
    24  # to the command line argument, even when both have the same value.
    25  ETCD_LOGLEVEL=${ETCD_LOGLEVEL:-warn}
    26  export KUBE_INTEGRATION_ETCD_URL="http://${ETCD_HOST}:${ETCD_PORT}"
    27  
    28  kube::etcd::validate() {
    29    # validate if in path
    30    command -v etcd >/dev/null || {
    31      kube::log::usage "etcd must be in your PATH"
    32      kube::log::info "You can use 'hack/install-etcd.sh' to install a copy in third_party/."
    33      exit 1
    34    }
    35  
    36    # validate etcd port is free
    37    local port_check_command
    38    if command -v ss &> /dev/null && ss -Version | grep 'iproute2' &> /dev/null; then
    39      port_check_command="ss"
    40    elif command -v netstat &>/dev/null; then
    41      port_check_command="netstat"
    42    else
    43      kube::log::usage "unable to identify if etcd is bound to port ${ETCD_PORT}. unable to find ss or netstat utilities."
    44      exit 1
    45    fi
    46    if ${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${ETCD_PORT:?}" >/dev/null 2>&1; then
    47      kube::log::usage "unable to start etcd as port ${ETCD_PORT} is in use. please stop the process listening on this port and retry."
    48      kube::log::usage "$(${port_check_command} -nat | grep "LISTEN" | grep "[\.:]${ETCD_PORT:?}")"
    49      exit 1
    50    fi
    51  
    52    # need set the env of "ETCD_UNSUPPORTED_ARCH" on unstable arch.
    53    arch=$(uname -m)
    54    if [[ $arch =~ arm* ]]; then
    55  	  export ETCD_UNSUPPORTED_ARCH=arm
    56    fi
    57    # validate installed version is at least equal to minimum
    58    version=$(etcd --version | grep Version | head -n 1 | cut -d " " -f 3)
    59    if [[ $(kube::etcd::version "${ETCD_VERSION}") -gt $(kube::etcd::version "${version}") ]]; then
    60     export PATH=${KUBE_ROOT}/third_party/etcd:${PATH}
    61     hash etcd
    62     echo "${PATH}"
    63     version=$(etcd --version | grep Version | head -n 1 | cut -d " " -f 3)
    64     if [[ $(kube::etcd::version "${ETCD_VERSION}") -gt $(kube::etcd::version "${version}") ]]; then
    65      kube::log::usage "etcd version ${ETCD_VERSION} or greater required."
    66      kube::log::info "You can use 'hack/install-etcd.sh' to install a copy in third_party/."
    67      exit 1
    68     fi
    69    fi
    70  }
    71  
    72  kube::etcd::version() {
    73    printf '%s\n' "${@}" | awk -F . '{ printf("%d%03d%03d\n", $1, $2, $3) }'
    74  }
    75  
    76  kube::etcd::start() {
    77    # validate before running
    78    kube::etcd::validate
    79  
    80    # Start etcd
    81    ETCD_DIR=${ETCD_DIR:-$(mktemp -d 2>/dev/null || mktemp -d -t test-etcd.XXXXXX)}
    82    if [[ -d "${ARTIFACTS:-}" ]]; then
    83      ETCD_LOGFILE="${ARTIFACTS}/etcd.$(uname -n).$(id -un).log.DEBUG.$(date +%Y%m%d-%H%M%S).$$"
    84    else
    85      ETCD_LOGFILE=${ETCD_LOGFILE:-"/dev/null"}
    86    fi
    87    kube::log::info "etcd --advertise-client-urls ${KUBE_INTEGRATION_ETCD_URL} --data-dir ${ETCD_DIR} --listen-client-urls http://${ETCD_HOST}:${ETCD_PORT} --log-level=${ETCD_LOGLEVEL} 2> \"${ETCD_LOGFILE}\" >/dev/null"
    88    etcd --advertise-client-urls "${KUBE_INTEGRATION_ETCD_URL}" --data-dir "${ETCD_DIR}" --listen-client-urls "${KUBE_INTEGRATION_ETCD_URL}" --log-level="${ETCD_LOGLEVEL}" 2> "${ETCD_LOGFILE}" >/dev/null &
    89    ETCD_PID=$!
    90  
    91    echo "Waiting for etcd to come up."
    92    kube::util::wait_for_url "${KUBE_INTEGRATION_ETCD_URL}/health" "etcd: " 0.25 80
    93    curl -fs -X POST "${KUBE_INTEGRATION_ETCD_URL}/v3/kv/put" -d '{"key": "X3Rlc3Q=", "value": ""}'
    94  }
    95  
    96  kube::etcd::start_scraping() {
    97    if [[ -d "${ARTIFACTS:-}" ]]; then
    98      ETCD_SCRAPE_DIR="${ARTIFACTS}/etcd-scrapes"
    99    else
   100      ETCD_SCRAPE_DIR=$(mktemp -d -t test.XXXXXX)/etcd-scrapes
   101    fi
   102    kube::log::info "Periodically scraping etcd to ${ETCD_SCRAPE_DIR} ."
   103    mkdir -p "${ETCD_SCRAPE_DIR}"
   104    (
   105      while sleep 30; do
   106        kube::etcd::scrape
   107      done
   108    ) &
   109    ETCD_SCRAPE_PID=$!
   110  }
   111  
   112  kube::etcd::scrape() {
   113      curl -s -S "${KUBE_INTEGRATION_ETCD_URL}/metrics" > "${ETCD_SCRAPE_DIR}/next" && mv "${ETCD_SCRAPE_DIR}/next" "${ETCD_SCRAPE_DIR}/$(date +%s).scrape"
   114  }
   115  
   116  
   117  kube::etcd::stop() {
   118    if [[ -n "${ETCD_SCRAPE_PID:-}" ]] && [[ -n "${ETCD_SCRAPE_DIR:-}" ]] ; then
   119      kill "${ETCD_SCRAPE_PID}" &>/dev/null || :
   120      wait "${ETCD_SCRAPE_PID}" &>/dev/null || :
   121      kube::etcd::scrape || :
   122      (
   123        # shellcheck disable=SC2015
   124        cd "${ETCD_SCRAPE_DIR}"/.. && \
   125        tar czf etcd-scrapes.tgz etcd-scrapes && \
   126        rm -rf etcd-scrapes || :
   127      )
   128    fi
   129    if [[ -n "${ETCD_PID-}" ]]; then
   130      kill "${ETCD_PID}" &>/dev/null || :
   131      wait "${ETCD_PID}" &>/dev/null || :
   132    fi
   133  }
   134  
   135  kube::etcd::clean_etcd_dir() {
   136    if [[ -n "${ETCD_DIR-}" ]]; then
   137      rm -rf "${ETCD_DIR}"
   138    fi
   139  }
   140  
   141  kube::etcd::cleanup() {
   142    kube::etcd::stop
   143    kube::etcd::clean_etcd_dir
   144  }
   145  
   146  kube::etcd::install() {
   147    # Make sure that we will abort if the inner shell fails.
   148    set -o errexit
   149    set -o pipefail
   150    set -o nounset
   151  
   152    # We change directories below, so this subshell is needed.
   153    (
   154      local os
   155      local arch
   156  
   157      os=$(kube::util::host_os)
   158      arch=$(kube::util::host_arch)
   159  
   160      cd "${KUBE_ROOT}/third_party" || return 1
   161      if [[ $(readlink etcd) == etcd-v${ETCD_VERSION}-${os}-* ]]; then
   162        V=3 kube::log::info "etcd v${ETCD_VERSION} is already installed"
   163        return 0 # already installed
   164      fi
   165  
   166      if [[ ${os} == "darwin" ]]; then
   167        download_file="etcd-v${ETCD_VERSION}-${os}-${arch}.zip"
   168        url="https://github.com/etcd-io/etcd/releases/download/v${ETCD_VERSION}/${download_file}"
   169        kube::util::download_file "${url}" "${download_file}"
   170        unzip -o "${download_file}"
   171        ln -fns "etcd-v${ETCD_VERSION}-${os}-${arch}" etcd
   172        rm "${download_file}"
   173      elif [[ ${os} == "linux" ]]; then
   174        url="https://github.com/etcd-io/etcd/releases/download/v${ETCD_VERSION}/etcd-v${ETCD_VERSION}-${os}-${arch}.tar.gz"
   175        download_file="etcd-v${ETCD_VERSION}-${os}-${arch}.tar.gz"
   176        kube::util::download_file "${url}" "${download_file}"
   177        tar xzf "${download_file}"
   178        ln -fns "etcd-v${ETCD_VERSION}-${os}-${arch}" etcd
   179        rm "${download_file}"
   180      else
   181        kube::log::info "${os} is NOT supported."
   182        return 1
   183      fi
   184      V=4 kube::log::info "installed etcd v${ETCD_VERSION}"
   185      return 0 # newly installed
   186    )
   187    # Through the magic of errexit, we will not get here if the above shell
   188    # fails!
   189    PATH="${KUBE_ROOT}/third_party/etcd:${PATH}" # export into current process
   190    export PATH
   191    V=3 kube::log::info "added etcd to PATH: ${KUBE_ROOT}/third_party/etcd"
   192  }