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