k8c.io/api/v3@v3.0.0-20230904060738-b0a93889c0b6/hack/lib.sh (about)

     1  #!/usr/bin/env bash
     2  
     3  # Copyright 2023 The Kubermatic Kubernetes Platform contributors.
     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  # Required for signal propagation to work so
    18  # the cleanup trap gets executed when a script
    19  # receives a SIGINT
    20  set -o monitor
    21  
    22  retry() {
    23    # Works only with bash but doesn't fail on other shells
    24    start_time=$(date +%s)
    25    set +e
    26    actual_retry $@
    27    rc=$?
    28    set -e
    29    elapsed_time=$(($(date +%s) - $start_time))
    30    write_junit "$rc" "$elapsed_time"
    31    return $rc
    32  }
    33  
    34  # We use an extra wrapping to write junit and have a timer
    35  actual_retry() {
    36    retries=$1
    37    shift
    38  
    39    count=0
    40    delay=1
    41    until "$@"; do
    42      rc=$?
    43      count=$((count + 1))
    44      if [ $count -lt "$retries" ]; then
    45        echo "Retry $count/$retries exited $rc, retrying in $delay seconds..." > /dev/stderr
    46        sleep $delay
    47      else
    48        echo "Retry $count/$retries exited $rc, no more retries left." > /dev/stderr
    49        return $rc
    50      fi
    51      delay=$((delay * 2))
    52    done
    53    return 0
    54  }
    55  
    56  echodate() {
    57    # do not use -Is to keep this compatible with macOS
    58    echo "[$(date +%Y-%m-%dT%H:%M:%S%:z)]" "$@"
    59  }
    60  
    61  write_junit() {
    62    # Doesn't make any sense if we don't know a testname
    63    if [ -z "${TEST_NAME:-}" ]; then return; fi
    64    # Only run in CI
    65    if [ -z "${ARTIFACTS:-}" ]; then return; fi
    66  
    67    rc=$1
    68    duration=${2:-0}
    69    errors=0
    70    failure=""
    71    if [ "$rc" -ne 0 ]; then
    72      errors=1
    73      failure='<failure type="Failure">Step failed</failure>'
    74    fi
    75    TEST_CLASS="${TEST_CLASS:-Kubermatic}"
    76    cat << EOF > ${ARTIFACTS}/junit.$(echo $TEST_NAME | sed 's/ /_/g' | tr '[:upper:]' '[:lower:]').xml
    77  <?xml version="1.0" ?>
    78  <testsuites>
    79    <testsuite errors="$errors" failures="$errors" name="$TEST_CLASS" tests="1">
    80      <testcase classname="$TEST_CLASS" name="$TEST_NAME" time="$duration">
    81        $failure
    82      </testcase>
    83    </testsuite>
    84  </testsuites>
    85  EOF
    86  }
    87  
    88  is_containerized() {
    89    # we're inside a Kubernetes pod/container or inside a container launched by containerize()
    90    [ -n "${KUBERNETES_SERVICE_HOST:-}" ] || [ -n "${CONTAINERIZED:-}" ]
    91  }
    92  
    93  containerize() {
    94    local cmd="$1"
    95    local image="${CONTAINERIZE_IMAGE:-quay.io/kubermatic/util:2.3.0}"
    96    local gocache="${CONTAINERIZE_GOCACHE:-/tmp/.gocache}"
    97    local gomodcache="${CONTAINERIZE_GOMODCACHE:-/tmp/.gomodcache}"
    98    local skip="${NO_CONTAINERIZE:-}"
    99  
   100    # short-circuit containerize when in some cases it needs to be avoided
   101    [ -n "$skip" ] && return
   102  
   103    if ! is_containerized; then
   104      echodate "Running $cmd in a Docker container using $image..."
   105      mkdir -p "$gocache"
   106      mkdir -p "$gomodcache"
   107  
   108      exec docker run \
   109        -v "$PWD":/go/src/k8c.io/kubermatic \
   110        -v "$gocache":"$gocache" \
   111        -v "$gomodcache":"$gomodcache" \
   112        -w /go/src/k8c.io/kubermatic \
   113        -e "GOCACHE=$gocache" \
   114        -e "GOMODCACHE=$gomodcache" \
   115        -e "CONTAINERIZED=true" \
   116        -u "$(id -u):$(id -g)" \
   117        --entrypoint="$cmd" \
   118        --rm \
   119        -it \
   120        $image $@
   121  
   122      exit $?
   123    fi
   124  }
   125  
   126  ensure_github_host_pubkey() {
   127    # check whether we already have a known_hosts entry for Github
   128    if ssh-keygen -F github.com > /dev/null 2>&1; then
   129      echo " [*] Github's SSH host key already present" > /dev/stderr
   130    else
   131      local github_rsa_key
   132      # https://help.github.com/en/github/authenticating-to-github/githubs-ssh-key-fingerprints
   133      github_rsa_key="github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
   134  
   135      echo " [*] Adding Github's SSH host key to known hosts" > /dev/stderr
   136      mkdir -p "$HOME/.ssh"
   137      chmod 700 "$HOME/.ssh"
   138      echo "$github_rsa_key" >> "$HOME/.ssh/known_hosts"
   139      chmod 600 "$HOME/.ssh/known_hosts"
   140    fi
   141  }
   142  
   143  # append_trap appends to existing traps, if any. It is needed because Bash replaces existing handlers
   144  # rather than appending: https://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal
   145  # Needing this func is a strong indicator that Bash is not the right language anymore. Also, this
   146  # basically needs unit tests.
   147  append_trap() {
   148    command="$1"
   149    signal="$2"
   150  
   151    # Have existing traps, must append
   152    if [[ "$(trap -p | grep $signal)" ]]; then
   153      existingHandlerName="$(trap -p | grep $signal | awk '{print $3}' | tr -d "'")"
   154  
   155      newHandlerName="${command}_$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13)"
   156      # Need eval to get a random func name
   157      eval "$newHandlerName() { $command; $existingHandlerName; }"
   158      echodate "Appending $command as trap for $signal, existing command $existingHandlerName"
   159      trap $newHandlerName $signal
   160    # First trap
   161    else
   162      echodate "Using $command as trap for $signal"
   163      trap $command $signal
   164    fi
   165  }
   166  
   167  start_docker_daemon_ci() {
   168    # DOCKER_REGISTRY_MIRROR_ADDR is injected via Prow preset;
   169    # start-docker.sh is part of the build image.
   170    DOCKER_REGISTRY_MIRROR="${DOCKER_REGISTRY_MIRROR_ADDR:-}" DOCKER_MTU=1400 start-docker.sh
   171  
   172    # enable the modern buildx plugin
   173    echodate "Enabling dockerx plugin"
   174    docker buildx install
   175  }
   176  
   177  start_docker_daemon() {
   178    if docker stats --no-stream > /dev/null 2>&1; then
   179      echodate "Not starting Docker again, it's already running."
   180      return
   181    fi
   182  
   183    # Start Docker daemon
   184    echodate "Starting Docker"
   185    dockerd > /tmp/docker.log 2>&1 &
   186  
   187    echodate "Started Docker successfully"
   188    append_trap docker_logs EXIT
   189  
   190    # Wait for Docker to start
   191    echodate "Waiting for Docker"
   192    retry 5 docker stats --no-stream
   193    echodate "Docker became ready"
   194  }
   195  
   196  repeat() {
   197    local end=$1
   198    local str="${2:-=}"
   199  
   200    for i in $(seq 1 $end); do
   201      echo -n "${str}"
   202    done
   203  }
   204  
   205  heading() {
   206    local title="$@"
   207    echo "$title"
   208    repeat ${#title} "="
   209    echo
   210  }
   211  
   212  # go_test wraps running `go test` commands. The first argument needs to be file name
   213  # for a junit result file that will be generated if go-junit-report is present and
   214  # $ARTIFACTS is set. The remaining arguments are passed to `go test`.
   215  go_test() {
   216    local junit_name="${1:-}"
   217    shift
   218  
   219    # only run go-junit-report if binary is present and we're in CI / the ARTIFACTS environment is set
   220    if [ -x "$(command -v go-junit-report)" ] && [ ! -z "${ARTIFACTS:-}" ]; then
   221      go test "$@" 2>&1 | go-junit-report -set-exit-code -iocopy -out ${ARTIFACTS}/junit.${junit_name}.xml
   222    else
   223      go test "$@"
   224    fi
   225  }
   226  
   227  # go_test wraps running `go test` commands. The first argument needs to be file name
   228  # for a junit result file that will be generated if go-junit-report is present and
   229  # $ARTIFACTS is set. The remaining arguments are passed to `go test`.
   230  go_test() {
   231    local junit_name="${1:-}"
   232    shift
   233  
   234    # only run go-junit-report if binary is present and we're in CI / the ARTIFACTS environment is set
   235    if [ -x "$(command -v go-junit-report)" ] && [ ! -z "${ARTIFACTS:-}" ]; then
   236      go test "$@" 2>&1 | go-junit-report -set-exit-code -iocopy -out ${ARTIFACTS}/junit.${junit_name}.xml
   237    else
   238      go test "$@"
   239    fi
   240  }