github.com/Equinix-Metal/virtlet@v1.5.2-0.20210807010419-342346535dc5/build/cmd.sh (about)

     1  #!/bin/bash
     2  set -o errexit
     3  set -o nounset
     4  set -o pipefail
     5  set -o errtrace
     6  
     7  CRIPROXY_DEB_URL="${CRIPROXY_DEB_URL:-https://github.com/Mirantis/criproxy/releases/download/v0.14.0/criproxy-nodeps_0.14.0_amd64.deb}"
     8  VIRTLET_IMAGE_REPO="${VIRTLET_IMAGE_REPO:-ryugu-psie-docker-dev-local.jfrog.io/equinix}"
     9  VIRTLET_SKIP_RSYNC="${VIRTLET_SKIP_RSYNC:-}"
    10  VIRTLET_SKIP_VENDOR="${VIRTLET_SKIP_VENDOR:-false}"
    11  VIRTLET_RSYNC_PORT="${VIRTLET_RSYNC_PORT:-18730}"
    12  VIRTLET_ON_MASTER="${VIRTLET_ON_MASTER:-}"
    13  VIRTLET_MULTI_NODE="${VIRTLET_MULTI_NODE:-}"
    14  # XXX: try to extract the docker socket path from DOCKER_HOST if it's set to unix://...
    15  DOCKER_SOCKET_PATH="${DOCKER_SOCKET_PATH:-/var/run/docker.sock}"
    16  FORCE_UPDATE_IMAGE="${FORCE_UPDATE_IMAGE:-}"
    17  IMAGE_REGEXP_TRANSLATION="${IMAGE_REGEXP_TRANSLATION:-1}"
    18  GH_RELEASE_TEST_USER="ivan4th"
    19  DIND_CRI="${DIND_CRI:-containerd}"
    20  MKDOCS_SERVE_ADDRESS="${MKDOCS_SERVE_ADDRESS:-localhost:8042}"
    21  
    22  # Note that project_dir must not end with slash
    23  project_dir="$(cd "$(dirname "${BASH_SOURCE}")/.." && pwd)"
    24  virtlet_image="${VIRTLET_IMAGE_REPO}/virtlet"
    25  remote_project_dir="/go/src/github.com/Equinix-Metal/virtlet"
    26  build_name="virtlet-build"
    27  tmp_container_name="${build_name}-$(openssl rand -hex 16)"
    28  build_image="${VIRTLET_IMAGE_REPO}/${build_name}:latest"
    29  volume_name=virtlet_src
    30  rsync_git=y
    31  exclude=(
    32      --exclude 'vendor'
    33      --exclude .git
    34      --exclude _output
    35      --exclude '*.png'
    36  )
    37  rsync_pw_file="${project_dir}/_output/rsync.password"
    38  busybox_image=busybox:1.27.2
    39  virtlet_nodes=()
    40  if [[ ${VIRTLET_ON_MASTER} ]]; then
    41    virtlet_nodes+=(kube-master)
    42  fi
    43  if [[ !${VIRTLET_ON_MASTER} || ${VIRTLET_MULTI_NODE} ]]; then
    44    virtlet_nodes+=(kube-node-1)
    45  fi
    46  if [[ ${VIRTLET_MULTI_NODE} ]]; then
    47    virtlet_nodes+=(kube-node-2)
    48  fi
    49  bindata_modtime=1522279343
    50  bindata_out="pkg/tools/bindata.go"
    51  bindata_dir="deploy/data"
    52  bindata_pkg="tools"
    53  ldflags=()
    54  go_package=github.com/Equinix-Metal/virtlet
    55  
    56  function image_tags_filter {
    57      local tag="${1}"
    58      local prefix=".items[0].spec.template.spec."
    59      local suffix="|=map(.image=\"equinix/virtlet:${tag}\")"
    60      echo -n "${prefix}containers${suffix}|${prefix}initContainers${suffix}"
    61  }
    62  
    63  function get_version() {
    64  	inside_git=$(git rev-parse --is-inside-work-tree 2>&1 >/dev/null; echo $?)
    65  	if [ $inside_git != 0 ]; then
    66      echo "Not in GIT repo and VERSION variable is not set."
    67      version='latest'
    68  	else
    69      VERSION_HASH=$(git show --summary | head -1 | awk '{print substr($2,0,8)}')
    70      version="${VERSION_HASH}"
    71    fi
    72    echo "$version" >"${project_dir}/_output/version"
    73    return 0
    74  }
    75  
    76  # from build/common.sh in k8s
    77  function rsync_probe {
    78      # Wait unil rsync is up and running.
    79      local tries=20
    80      while (( ${tries} > 0 )) ; do
    81          if rsync "rsync://k8s@${1}:${2}/" \
    82                   --password-file="${project_dir}/_output/rsyncd.password" \
    83             &> /dev/null ; then
    84              return 0
    85          fi
    86          tries=$(( ${tries} - 1))
    87          sleep 0.1
    88      done
    89  
    90      return 1
    91  }
    92  
    93  function image_exists {
    94      local name="${1}"
    95      # can't use 'docker images -q' due to https://github.com/docker/docker/issues/28895
    96      docker history -q "${name}" >& /dev/null || return 1
    97  }
    98  
    99  function ensure_build_image {
   100      mkdir -p "${project_dir}/_output"
   101      get_version
   102      build_tag="$(cat "${project_dir}/_output/version")"
   103      build_image="${VIRTLET_IMAGE_REPO}/${build_name}:${build_tag}"
   104      docker login ryugu-psie-docker-dev-local.jfrog.io
   105      virtlet_base_image="${VIRTLET_IMAGE_REPO}/virtlet-base:${build_tag}"
   106      build_base_image="${VIRTLET_IMAGE_REPO}/virtlet-build-base:${build_tag}"
   107      echo >&2 "Trying to pull the base image ${virtlet_base_image}..."
   108      if ! docker pull "${virtlet_base_image}"; then
   109          docker build -t "${virtlet_base_image}" \
   110                 -f "${project_dir}/images/Dockerfile.virtlet-base" \
   111                 "${project_dir}/images"
   112          docker push "${virtlet_base_image}"
   113      fi
   114      echo >&2 "Trying to pull the build base image ${build_base_image}..."
   115      if ! docker pull "${build_base_image}"; then
   116          docker build -t "${build_base_image}" \
   117                 --label virtlet_image=build-base \
   118                 --build-arg BASE_TAG=${build_tag} \
   119                 -f "${project_dir}/images/Dockerfile.build-base" "${project_dir}/images"
   120          docker push "${build_base_image}"
   121      fi
   122      tar -C "${project_dir}/images" -c image_skel/ qemu-build.conf Dockerfile.build |
   123          docker build -t "${build_image}" --build-arg BUILD_TAG=${build_tag} \
   124          -f Dockerfile.build -
   125      docker tag "${build_image}" "${VIRTLET_IMAGE_REPO}/${build_name}:latest"
   126      docker push "${build_image}"
   127      docker push "${VIRTLET_IMAGE_REPO}/${build_name}:latest"
   128  }
   129  
   130  function get_rsync_addr {
   131      local container_ip
   132      container_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' virtlet-build)
   133  
   134      # Sometimes we can reach rsync through localhost and a NAT'd port.  Other
   135      # times (when we are running in another docker container on the Jenkins
   136      # machines) we have to talk directly to the container IP.  There is no one
   137      # strategy that works in all cases so we test to figure out which situation we
   138      # are in.
   139      if rsync_probe 127.0.0.1 "${VIRTLET_RSYNC_PORT}"; then
   140          echo "127.0.0.1:${VIRTLET_RSYNC_PORT}" >"${project_dir}/_output/rsync_addr"
   141          return 0
   142      elif rsync_probe "${container_ip}" ${VIRTLET_RSYNC_PORT}; then
   143          echo "${container_ip}:${VIRTLET_RSYNC_PORT}" >"${project_dir}/_output/rsync_addr"
   144          return 0
   145      else
   146          echo "Could not probe the rsync port" >&2
   147      fi
   148  }
   149  
   150  function ensure_build_container {
   151      if ! docker ps --filter=label=virtlet_build | grep -q virtlet-build; then
   152          ensure_build_image
   153          cd "${project_dir}"
   154          # Need to mount docker socket into the container because of
   155          # CRI proxy deployment tests & building the image
   156          # We also pass --tmpfs /tmp because log tailing doesn't work
   157          # on overlayfs. This breaks 'go test' though unless we also
   158          # remount /tmp with exec option (it creates and runs executable files
   159          # under /tmp)
   160          declare -a docker_cert_args=()
   161          if [[ ${DOCKER_CERT_PATH:-} ]]; then
   162             docker_cert_args=(-e DOCKER_CERT_PATH=/docker-cert)
   163          fi
   164          docker run -d --privileged --net=host \
   165                 -l virtlet_build \
   166                 -v "virtlet_src:${remote_project_dir}" \
   167                 -v "virtlet_pkg:/go/pkg" \
   168                 -v /sys/fs/cgroup:/sys/fs/cgroup \
   169                 -v /lib/modules:/lib/modules:ro \
   170                 -v /boot:/boot:ro \
   171                 -v "${DOCKER_SOCKET_PATH}:/var/run/docker.sock" \
   172                 -e DOCKER_MACHINE_NAME="${DOCKER_MACHINE_NAME:-}" \
   173                 -e DOCKER_TLS_VERIFY="${DOCKER_TLS_VERIFY:-}" \
   174                 -e TRAVIS="${TRAVIS:-}" \
   175                 -e TRAVIS_PULL_REQUEST="${TRAVIS_PULL_REQUEST:-}" \
   176                 -e TRAVIS_BRANCH="${TRAVIS_BRANCH:-}" \
   177                 -e CIRCLECI="${CIRCLECI:-}" \
   178                 -e CIRCLE_PULL_REQUEST="${CIRCLE_PULL_REQUEST:-}" \
   179                 -e CIRCLE_BRANCH="${CIRCLE_PULL_REQUEST:-}" \
   180                 -e VIRTLET_ON_MASTER="${VIRTLET_ON_MASTER:-}" \
   181                 -e VIRTLET_MULTI_NODE="${VIRTLET_MULTI_NODE:-}" \
   182                 -e GITHUB_TOKEN="${GITHUB_TOKEN:-}" \
   183                 -e MKDOCS_SERVE_ADDRESS="${MKDOCS_SERVE_ADDRESS:-}" \
   184                 -e VIRTLET_SKIP_VENDOR="${VIRTLET_SKIP_VENDOR:-false}" \
   185                 ${docker_cert_args[@]+"${docker_cert_args[@]}"} \
   186                 --name virtlet-build \
   187                 --tmpfs /tmp \
   188                 "${build_image}" \
   189                 /bin/bash -c "mount /tmp -o remount,exec && sleep Infinity" >/dev/null
   190          if [[ ! ${VIRTLET_SKIP_RSYNC} ]]; then
   191              # from build/common.sh in k8s
   192              mkdir -p "${project_dir}/_output"
   193              dd if=/dev/urandom bs=512 count=1 2>/dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | dd bs=32 count=1 2>/dev/null >"${rsync_pw_file}"
   194              chmod 600 "${rsync_pw_file}"
   195  
   196              docker cp "${rsync_pw_file}" virtlet-build:/rsyncd.password
   197              docker exec -d -i virtlet-build /rsyncd.sh "${VIRTLET_RSYNC_PORT}"
   198              get_rsync_addr
   199          fi
   200          if [[ ${DOCKER_CERT_PATH:-} ]]; then
   201              tar -C "${DOCKER_CERT_PATH}" -c . | docker exec -i virtlet-build /bin/bash -c 'mkdir /docker-cert && tar -C /docker-cert -x'
   202          fi
   203      fi
   204      if [[ ! ${VIRTLET_SKIP_RSYNC} ]]; then
   205          get_rsync_addr
   206          RSYNC_ADDR="$(cat "${project_dir}/_output/rsync_addr")"
   207      fi
   208  }
   209  
   210  function vsh {
   211      ensure_build_container
   212      cd "${project_dir}"
   213      docker exec -it virtlet-build env TERM=xterm bash
   214  }
   215  
   216  function sync_source {
   217      ensure_build_container
   218      cd "${project_dir}"
   219      if [[ ! ${VIRTLET_SKIP_RSYNC} ]]; then
   220          local -a filters=(
   221              --filter '- /_output/'
   222          )
   223          if [[ ${VIRTLET_SKIP_VENDOR:-false} != "true" ]]; then
   224              filters+=(--filter '- /vendor/')
   225          fi
   226          if [[ ! ${rsync_git} ]]; then
   227              filters+=(--filter '- /.git/')
   228          fi
   229          rsync "${filters[@]}" \
   230                --password-file "${project_dir}/_output/rsync.password" \
   231                -a --delete --compress-level=9 \
   232                "${project_dir}/" "rsync://virtlet@${RSYNC_ADDR}/virtlet/"
   233      fi
   234  }
   235  
   236  function vcmd {
   237      sync_source >&2
   238      local t=""
   239      if [[ ${USE_TERM:-} ]]; then
   240          t="t"
   241      fi
   242      docker exec -i"${t}" virtlet-build bash -c "$*"
   243  }
   244  
   245  function vcmd_simple {
   246      local cmd="${1}"
   247      docker exec -i virtlet-build bash -c "${cmd}"
   248  }
   249  
   250  function stop {
   251      docker ps -a -q --filter=label=virtlet_build | while read container_id; do
   252          echo >&2 "Removing container:" "${container_id}"
   253          docker rm -fv "${container_id}"
   254      done
   255  }
   256  
   257  function copy_output {
   258      ensure_build_container
   259      cd "${project_dir}"
   260      vcmd_simple "tar -C '${remote_project_dir}' -cz \$(find . -path '*/_output/*' -type f)" | tar -xvz
   261  }
   262  
   263  function copy_back {
   264      ensure_build_container
   265      cd "${project_dir}"
   266      tar -cz $(find . -path '*/_output/*' -type f | grep -v rsync) | vcmd_simple "tar -C '${remote_project_dir}' -xvz"
   267  }
   268  
   269  function copy_dind_internal {
   270      local virtlet_node="${1}"
   271      if ! docker volume ls -q | grep -q "^kubeadm-dind-${virtlet_node}$"; then
   272          echo "No active or snapshotted kubeadm-dind-cluster" >&2
   273          exit 1
   274      fi
   275      tar -C _output -c . |
   276          docker run -i --rm \
   277                 -v "kubeadm-dind-${virtlet_node}:/dind" \
   278                 --name ${tmp_container_name} \
   279                 "${busybox_image}" \
   280                 /bin/sh -c 'tar -C /dind -xv && chmod ug+s /dind/vmwrapper'
   281  }
   282  
   283  function kvm_ok {
   284      build_tag="$(cat "${project_dir}/_output/version")"
   285      # The check is done inside the virtlet node container because it
   286      # has proper /lib/modules from the docker host. Also, it'll have
   287      # to use the virtlet image later anyway.
   288      # Use kube-master node as all of the DIND nodes in the cluster are similar
   289      if ! docker exec kube-master docker run --privileged --rm -v /lib/modules:/lib/modules "${virtlet_image}:${build_tag}" kvm-ok; then
   290          return 1
   291      fi
   292  }
   293  
   294  function prepare_node {
   295      local node="${1}"
   296      if docker exec "${node}" dpkg-query -W criproxy-nodeps >&/dev/null; then
   297          return 0
   298      fi
   299      ensure_build_container
   300      echo >&2 "Installing CRI proxy package in the node container (${node})..."
   301      if [[ ${DIND_CRI:-} = containerd ]]; then
   302          docker exec "${node}" /bin/bash -c 'echo criproxy-nodeps criproxy/primary_cri select containerd | debconf-set-selections'
   303      fi
   304      docker exec "${node}" /bin/bash -c "curl -sSL '${CRIPROXY_DEB_URL}' >/criproxy.deb && dpkg -i /criproxy.deb && rm /criproxy.deb"
   305  
   306      docker exec "${node}" mount --make-shared /dind
   307      docker exec "${node}" mount --make-shared /dev
   308      docker exec "${node}" mount --make-shared /boot
   309      docker exec "${node}" mount --make-shared /sys/fs/cgroup
   310  
   311      if [[ ${VIRTLET_ON_MASTER} ]]; then
   312          if [[ $(kubectl get node kube-master -o jsonpath='{.spec.taints[?(@.key=="node-role.kubernetes.io/master")]}') ]]; then
   313              kubectl taint nodes kube-master node-role.kubernetes.io/master-
   314          fi
   315      fi
   316      if [[ ${FORCE_UPDATE_IMAGE} ]] || ! docker exec "${node}" docker history -q "${virtlet_image}:latest" >&/dev/null; then
   317          echo >&2 "Propagating Virtlet image to the node container..."
   318          if [[ ${DIND_CRI} = containerd ]]; then
   319            vcmd "docker save '${virtlet_image}:latest' | docker exec -i '${node}' ctr -n k8s.io images import -"
   320          else
   321            vcmd "docker save '${virtlet_image}:latest' | docker exec -i '${node}' docker load"
   322          fi
   323      fi
   324  }
   325  
   326  function prepare_all_nodes {
   327      for node in $(kubectl get nodes -o jsonpath='{.items[?(@.metadata.name!="kube-master")].metadata.name}'); do
   328          prepare_node "${node}"
   329      done
   330  }
   331  
   332  function apply_runtime_label {
   333      local node="${1}"
   334      kubectl label node --overwrite "${node}" extraRuntime=virtlet
   335  }
   336  
   337  function start_dind {
   338      local -a virtlet_config=(--from-literal=image_regexp_translation="${IMAGE_REGEXP_TRANSLATION}")
   339      if ! kvm_ok || [[ ${VIRTLET_DISABLE_KVM:-} ]]; then
   340          virtlet_config+=(--from-literal=disable_kvm=y)
   341      fi
   342      kubectl create configmap -n kube-system virtlet-config "${virtlet_config[@]}"
   343      kubectl create configmap -n kube-system virtlet-image-translations --from-file "${project_dir}/deploy/images.yaml"
   344      start_virtlet
   345  }
   346  
   347  function start_virtlet {
   348      local -a opts=(--dev)
   349      if kubectl version | tail -n1 | grep -q 'v1\.7\.'; then
   350          # apply mount propagation hacks for 1.7
   351          opts+=(--compat)
   352      fi
   353      docker exec virtlet-build "${remote_project_dir}/_output/virtletctl" gen "${opts[@]}" |
   354          kubectl apply -f -
   355  }
   356  
   357  function virtlet_subdir {
   358      local dir="${1:-$(pwd)}"
   359      local prefix="${project_dir}/"
   360      if [[ ${#dir} -lt ${#prefix} || ${dir:0:${#prefix}} != ${prefix} ]]; then
   361          echo >&2 "must be in a project subdir"
   362          exit 1
   363      fi
   364      echo -n "${dir:${#prefix}}"
   365  }
   366  
   367  function clean {
   368      stop
   369      docker volume rm virtlet_src || true
   370      docker volume rm virtlet_pkg || true
   371      docker rmi "${build_image}" || true
   372      # find command may produce zero results
   373      # -exec rm -rf '{}' ';' produces errors when trying to
   374      # enter deleted directories
   375      find . -name _output -type d | while read dir; do
   376          rm -rf "${dir}"
   377      done
   378  }
   379  
   380  function gotest {
   381      # FIXME: exit 1 in $(virtlet_subdir) doesn't cause the script to exit
   382      virtlet_subdir >/dev/null
   383      subdir="$(virtlet_subdir)"
   384      if ! vcmd "cd '${subdir}' && go test $*"; then
   385          vcmd_simple "find . -name 'Test*.out.*' | xargs tar -c -T -" | tar -C "${project_dir}" -x
   386          exit 1
   387      fi
   388  }
   389  
   390  function gobuild {
   391      # FIXME: exit 1 in $(virtlet_subdir) doesn't cause the script to exit
   392      virtlet_subdir >/dev/null
   393      # -gcflags -e removes the limit on error message count, which helps
   394      # with using it for syntax checking
   395      vcmd "cd '$(virtlet_subdir)' && go build -gcflags -e $*"
   396  }
   397  
   398  function build_image_internal {
   399      build_internal
   400      build_tag="$(cat "${project_dir}/_output/version")"
   401      tar -c _output -C "${project_dir}/images" image_skel/ Dockerfile.virtlet |
   402          docker build -t "${virtlet_image}:${build_tag}" --build-arg VIRLET_BASE_TAG=build_tag \
   403            -f Dockerfile.virtlet -
   404      docker push "${virtlet_image}:${build_tag}"
   405      docker tag "${virtlet_image}:${build_tag}" "${virtlet_image}:latest"
   406      docker push "${virtlet_image}:latest"
   407  }
   408  
   409  function install_vendor_internal {
   410      if [ ! -d vendor ]; then
   411          glide install --strip-vendor
   412      fi
   413  }
   414  
   415  function run_tests_internal {
   416      install_vendor_internal
   417      go test -v ./pkg/... ./tests/network/...
   418  }
   419  
   420  function run_integration_internal {
   421      install_vendor_internal
   422      ( cd tests/integration && ./go.test )
   423  }
   424  
   425  function get_ldflags {
   426      # XXX: use kube::version::ldflag (-ldflags -X package.Var=...)
   427      # see also versioning.mk in helm
   428      # https://stackoverflow.com/questions/11354518/golang-application-auto-build-versioning
   429      # see pkg/version/version.go in k8s
   430      # for GoVersion / Compiler / Platform
   431      local vfile="${project_dir}/pkg/version/version.go"
   432      local git_version="$(git describe --tags --abbrev=14 'HEAD^{commit}' | sed "s/-g\([0-9a-f]\{14\}\)$/+\1/")"
   433      local git_commit="$(git rev-parse "HEAD^{commit}")"
   434      local git_tree_state=$([[ $(git status --porcelain) ]] && echo "dirty" || echo "clean")
   435      if [[ ${git_tree_state} == dirty ]]; then
   436          git_version+="-dirty"
   437      fi
   438      local build_date="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
   439      local git_major=""
   440      local git_minor=""
   441      local version_pkg="${go_package}/pkg/version"
   442      local ldflags=(-X "${version_pkg}.gitVersion=${git_version}"
   443                     -X "${version_pkg}.gitCommit=${git_commit}"
   444                     -X "${version_pkg}.gitTreeState=${git_tree_state}"
   445                     -X "${version_pkg}.buildDate=${build_date}")
   446      if [[ ${git_version} =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?([-].*)?([+].*)?$ ]]; then
   447          git_major=${BASH_REMATCH[1]}
   448          git_minor=${BASH_REMATCH[2]}
   449          ldflags+=(-X "${version_pkg}.gitMajor=${git_major}"
   450                    -X "${version_pkg}.gitMinor=${git_minor}")
   451      fi
   452      if [[ ${SET_VIRTLET_IMAGE_TAG:-} ]]; then
   453          ldflags+=(-X "${version_pkg}.imageTag=${SET_VIRTLET_IMAGE_TAG}")
   454      fi
   455      echo "${ldflags[*]}"
   456  }
   457  
   458  function build_internal {
   459      # we don't just always generate the bindata right there because we
   460      # want to keep the source buildable outside this build container.
   461      go-bindata -mode 0644 -o /tmp/bindata.go -modtime "${bindata_modtime}" -pkg "${bindata_pkg}" "${bindata_dir}"
   462      if ! cmp /tmp/bindata.go "${bindata_out}"; then
   463          echo >&2 "${bindata_dir} changed, please re-run ${0} update-bindata"
   464          exit 1
   465      fi
   466      install_vendor_internal
   467      ldflags="$(get_ldflags)"
   468      mkdir -p "${project_dir}/_output"
   469      go build -i -o "${project_dir}/_output/virtlet" -ldflags "${ldflags}" ./cmd/virtlet
   470      go build -i -o "${project_dir}/_output/virtletctl" -ldflags "${ldflags}" ./cmd/virtletctl
   471      GOOS=darwin go build -i -o "${project_dir}/_output/virtletctl.darwin" -ldflags "${ldflags}" ./cmd/virtletctl
   472      go build -i -o "${project_dir}/_output/vmwrapper" ./cmd/vmwrapper
   473      go build -i -o "${project_dir}/_output/flexvolume_driver" ./cmd/flexvolume_driver
   474      go test -i -c -o "${project_dir}/_output/virtlet-e2e-tests" ./tests/e2e
   475      go build -i -o "${project_dir}/_output/virtlet-longevity-tests" -ldflags "${ldflags}" ./cmd/longevity
   476      get_version
   477  }
   478  
   479  function release_description {
   480      local -a tag="${1}"
   481      shift
   482      git tag -l --format='%(contents:body)' "${tag}"
   483      echo
   484      echo "SHA256 sums for the files:"
   485      echo '```'
   486      (cd _output && sha256sum "$@")
   487      echo '```'
   488  }
   489  
   490  function release_internal {
   491      local tag="${1}"
   492      local gh_user="Mirantis"
   493      if [[ ${tag} =~ test ]]; then
   494          gh_user="${GH_RELEASE_TEST_USER}"
   495      fi
   496      local -a opts=(--user "${gh_user}" --repo virtlet --tag "${tag}")
   497      local -a files=(virtletctl virtletctl.darwin)
   498      local description="$(release_description "${tag}" "${files[@]}")"
   499      local pre_release=
   500      if [[ ${tag} =~ -(test|pre).*$ ]]; then
   501          pre_release="--pre-release"
   502      fi
   503      if github-release --quiet delete "${opts[@]}"; then
   504          echo >&2 "Replacing the old Virtlet release"
   505      fi
   506      github-release release "${opts[@]}" \
   507                     --name "$(git tag -l --format='%(contents:subject)' "${tag}")" \
   508                     --description "${description}" \
   509                     ${pre_release}
   510      for filename in "${files[@]}"; do
   511          echo >&2 "Uploading: ${filename}"
   512          github-release upload "${opts[@]}" \
   513                         --name "${filename}" \
   514                         --replace \
   515                         --file "_output/${filename}"
   516      done
   517  }
   518  
   519  function e2e {
   520      ensure_build_container
   521      local cluster_url
   522      cluster_url="$(kubectl config view -o jsonpath='{.clusters[?(@.name=="dind")].cluster.server}')"
   523      docker exec virtlet-build _output/virtlet-e2e-tests -include-unsafe-tests=true -cluster-url "${cluster_url}" "$@"
   524  }
   525  
   526  function update_bindata_internal {
   527      # set fixed modtime to avoid unwanted differences during the checks
   528      # that are done by build/cmd.sh build
   529      go-bindata -mode 0644 -modtime "${bindata_modtime}" -o "${bindata_out}" -pkg "${bindata_pkg}" "${bindata_dir}"
   530  }
   531  
   532  function update_generated_docs_internal {
   533    if [[ ! -f _output/virtletctl ]]; then
   534      echo >&2 "Please run build/cmd.sh build first"
   535    fi
   536    virtletctl gendoc docs/docs/reference
   537    tempfile="$(tempfile)"
   538    _output/virtletctl gendoc --config >"${tempfile}"
   539    sed -i "/<!-- begin -->/,/<!-- end -->/{
   540  //!d
   541  /begin/r ${tempfile}
   542  }" docs/docs/reference/config.md
   543    rm -f "${tempfile}"
   544  }
   545  
   546  function update_generated_internal {
   547    install_vendor_internal
   548    vendor/k8s.io/code-generator/generate-groups.sh all \
   549      github.com/Equinix-Metal/virtlet/pkg/client github.com/Equinix-Metal/virtlet/pkg/api \
   550      virtlet.k8s:v1 \
   551      --go-header-file "build/custom-boilerplate.go.txt"
   552    # fix import url case issues
   553    find pkg/client \
   554         -name '*.go' \
   555         -exec sed -i 's@github\.com/Equinix/virtlet@github\.com/Equinix/virtlet@g' \
   556         '{}' \;
   557  }
   558  
   559  function serve_docs_internal {
   560      (cd docs && mkdocs serve -a "${MKDOCS_SERVE_ADDRESS}")
   561  }
   562  
   563  function build_docs_internal {
   564      site_dir="$(mktemp -d)"
   565      trap 'rm -rf "${site_dir}"' EXIT
   566      # Use strict mode (-s) for mkdocs so that any broken links
   567      # etc. are caught
   568      (cd docs && mkdocs build -s -d "${site_dir}" >&2)
   569      tar -C "${site_dir}" -c .
   570  }
   571  
   572  function build_docs {
   573      cd "${project_dir}"
   574      rm -rf _docs
   575      git clone -b docs . _docs
   576      local docs_hash="$(git ls-tree HEAD -- docs | awk '{print $3}')"
   577      if [[ ! -e _docs/source_hash || ${docs_hash} != $(cat _docs/source_hash) ]]; then
   578          echo >&2 "docs/ directory changed since the last doc build, rebuilding docs"
   579      elif [[ $(git status --porcelain) ]]; then
   580          echo >&2 "Source directory dirty, rebuilding docs"
   581      else
   582          echo >&2 "Docs unchanged, no need to rebuild"
   583          return 0
   584      fi
   585      # clean up _docs except for .git and CNAME
   586      find _docs -name .git -prune -o -type f \! -name CNAME -exec rm -f '{}' \;
   587      vcmd "build/cmd.sh build-docs-internal" | tar -C _docs -xv
   588      echo "${docs_hash}" > _docs/source_hash
   589      (
   590          cd _docs
   591          git add .
   592          git commit -m "Update generated docs [ci skip]"
   593          # this pushes the changes into the local repo (not github!)
   594          git push origin docs
   595      )
   596  }
   597  
   598  function usage {
   599      echo >&2 "Usage:"
   600      echo >&2 "  $0 build"
   601      echo >&2 "  $0 test"
   602      echo >&2 "  $0 copy"
   603      echo >&2 "  $0 copy-dind"
   604      echo >&2 "  $0 start-dind"
   605      echo >&2 "  $0 vsh"
   606      echo >&2 "  $0 stop"
   607      echo >&2 "  $0 clean"
   608      echo >&2 "  $0 update-bindata"
   609      echo >&2 "  $0 update-generated-docs"
   610      echo >&2 "  $0 gotest [TEST_ARGS...]"
   611      echo >&2 "  $0 gobuild [BUILD_ARGS...]"
   612      echo >&2 "  $0 run CMD..."
   613      echo >&2 "  $0 release TAG"
   614      echo >&2 "  $0 serve-docs"
   615      echo >&2 "  $0 build-docs"
   616      echo >&2 "  $0 sync"
   617      exit 1
   618  }
   619  
   620  cmd="${1:-}"
   621  if [[ ! $cmd ]]; then
   622      usage
   623  fi
   624  shift
   625  
   626  case "${cmd}" in
   627      gotest)
   628          gotest "$@"
   629          ;;
   630      gobuild)
   631          rsync_git=
   632          gobuild "$@"
   633          ;;
   634      prepare-vendor)
   635          vcmd "build/cmd.sh install-vendor-internal"
   636          ;;
   637      build)
   638          vcmd "SET_VIRTLET_IMAGE_TAG='${SET_VIRTLET_IMAGE_TAG:-}' build/cmd.sh build-image-internal"
   639          ;;
   640      build-image-internal)
   641          # this is executed inside the container
   642          build_image_internal "$@"
   643          ;;
   644      test)
   645          vcmd 'build/cmd.sh run-tests-internal'
   646          ;;
   647      integration)
   648          vcmd 'build/cmd.sh run-integration-internal'
   649          ;;
   650      install-vendor-internal)
   651          install_vendor_internal
   652          ;;
   653      run-tests-internal)
   654          run_tests_internal
   655          ;;
   656      run-integration-internal)
   657          run_integration_internal
   658          ;;
   659      update-bindata)
   660          vcmd "build/cmd.sh update-bindata-internal"
   661          docker cp "virtlet-build:${remote_project_dir}/pkg/tools/bindata.go" pkg/tools/bindata.go
   662          ;;
   663      update-bindata-internal)
   664          update_bindata_internal
   665          ;;
   666      update-generated)
   667          vcmd "build/cmd.sh update-generated-internal"
   668          docker exec virtlet-build \
   669                 /bin/bash -c \
   670                 "tar -C '${remote_project_dir}' -c $(find pkg/ -name 'zz_generated.*') pkg/client" |
   671              tar -C "${project_dir}" -xv
   672          ;;
   673      update-generated-internal)
   674          update_generated_internal
   675          ;;
   676      update-generated-docs)
   677          vcmd "build/cmd.sh update-generated-docs-internal"
   678          docker exec virtlet-build tar -C "${remote_project_dir}" -c docs/docs/reference/config.md docs/docs/reference/virtletctl.md | tar -C "${project_dir}" -xv
   679          ;;
   680      update-generated-docs-internal)
   681          update_generated_docs_internal
   682          ;;
   683      run)
   684          vcmd "$*"
   685          ;;
   686      vsh)
   687          vsh
   688          ;;
   689      stop)
   690          stop
   691          ;;
   692      clean)
   693          clean
   694          ;;
   695      copy)
   696          copy_output
   697          ;;
   698      copy-back)
   699          copy_back
   700          ;;
   701      copy-dind)
   702          VIRTLET_SKIP_RSYNC=y vcmd "build/cmd.sh copy-dind-internal"
   703          ;;
   704      e2e)
   705          e2e "$@"
   706          ;;
   707      copy-dind-internal)
   708          for virtlet_node in "${virtlet_nodes[@]}"; do
   709              copy_dind_internal "${virtlet_node}"
   710          done
   711          ;;
   712      prepare-all-nodes)
   713          prepare_all_nodes
   714          ;;
   715      start-dind)
   716          for virtlet_node in "${virtlet_nodes[@]}"; do
   717              prepare_node "${virtlet_node}"
   718              apply_runtime_label "${virtlet_node}"
   719          done
   720          start_dind
   721          ;;
   722      start-build-container)
   723          ensure_build_container
   724          ;;
   725      release)
   726          if [[ ! ${1:-} ]]; then
   727              echo >&2 "must specify the tag"
   728              exit 1
   729          fi
   730          ( vcmd "build/cmd.sh release-internal '${1}'" )
   731          ;;
   732      release-internal)
   733          release_internal "$@"
   734          ;;
   735      serve-docs-internal)
   736          serve_docs_internal
   737          ;;
   738      serve-docs)
   739          ( USE_TERM=1 vcmd "build/cmd.sh serve-docs-internal" )
   740          ;;
   741      build-docs-internal)
   742          build_docs_internal
   743          ;;
   744      build-docs)
   745          build_docs
   746          ;;
   747      sync)
   748          sync_source
   749          ;;
   750      *)
   751          usage
   752          ;;
   753  esac
   754  
   755  # TODO: make it possible to run e2e from within the build container, too
   756  # (although we don't need to use that for CircleCI)
   757  # TODO: fix indentation in this file (use 2 spaces)