diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..3587c419b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# Copyright 2021 VMware +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# These base images are behind a proxy for rate-limit reasons +# If building locally, you can simply use: +# docker build -t cartographer:dev --build-arg BASE_IMAGE="ubuntu:jammy" --build-arg GOLANG_IMAGE=golang:1.19 . + +ARG BASE_IMAGE=harbor-repo.vmware.com/dockerhub-proxy-cache/library/ubuntu:jammy +ARG GOLANG_IMAGE=harbor-repo.vmware.com/dockerhub-proxy-cache/library/golang:1.19 + +FROM ${BASE_IMAGE} AS ytt + +RUN set -x && \ + apt-get update && \ + apt-get install -y curl=7.81.0-1ubuntu1.14 + +ARG ytt_CHECKSUM=a6729fb8514f10ab58f9ed3b50cd90ef79bf16d1cb29173baa84e1af0bc5ad4f +ARG ytt_VERSION=0.45.3 + +RUN set -eux && \ + url=https://github.com/vmware-tanzu/carvel-ytt/releases/download/v${ytt_VERSION}/ytt-linux-amd64 ; \ + curl -sSL $url -o /usr/local/bin/ytt && \ + echo "${ytt_CHECKSUM} /usr/local/bin/ytt" | sha256sum -c && \ + chmod +x /usr/local/bin/ytt + +FROM ${GOLANG_IMAGE} AS cartographer +WORKDIR /src +COPY go.mod go.sum ./ +RUN go mod download +COPY cmd/ ./cmd/ +COPY pkg/ ./pkg/ +RUN GOOS=linux GOARCH=amd64 go build -o /build/ github.com/vmware-tanzu/cartographer/cmd/cartographer + +FROM gcr.io/paketo-buildpacks/run-jammy-tiny@sha256:35702d19f93e06041db1573b1140742df2182494cc93f646fd57c6d8922dc7a7 +COPY --from=ytt /usr/local/bin/ytt /usr/local/bin/ytt +COPY --from=cartographer /build/cartographer /usr/local/bin/cartographer +ENTRYPOINT [ "cartographer" ] \ No newline at end of file diff --git a/config/manager/deployment.yaml b/config/manager/deployment.yaml index 35eb86493..0f2e727c9 100644 --- a/config/manager/deployment.yaml +++ b/config/manager/deployment.yaml @@ -46,7 +46,7 @@ spec: secretName: cartographer-webhook containers: - name: cartographer-controller - image: ko://github.com/vmware-tanzu/cartographer/cmd/cartographer + image: #@ data.values.controller_image args: - -cert-dir=/cert - -metrics-port=9998 diff --git a/hack/lever_build_request.yaml b/hack/lever_build_request.yaml new file mode 100644 index 000000000..2895340d6 --- /dev/null +++ b/hack/lever_build_request.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 VMware +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#@ load("@ytt:data", "data") +--- +apiVersion: supplychain.cc.build/v1alpha2 +kind: Request +metadata: + name: #@ "cartographer-" + data.values.build_suffix + namespace: default +spec: + artifacts: + images: + - name: #@ data.values.release_image + buildType: kaniko + buildConfig: + kanikoBuildConfig: + dockerfile: Dockerfile + extraArgs: [] + source: + git: + ref: + commit: #@ data.values.commit_ref + branch: unused + url: https://github.com/vmware-tanzu/cartographer.git diff --git a/hack/release.sh b/hack/release.sh index ac4c43f1e..08cd2380b 100755 --- a/hack/release.sh +++ b/hack/release.sh @@ -17,24 +17,41 @@ set -o errexit set -o nounset set -o pipefail -ROOT=$(cd "$(dirname $0)"/.. && pwd) +ROOT=$(cd "$(dirname "$0")"/.. && pwd) readonly ROOT readonly SCRATCH=${SCRATCH:-$(mktemp -d)} -readonly REGISTRY=${REGISTRY:-"$($ROOT/hack/ip.py):5001"} +readonly REGISTRY=${REGISTRY:-"$("$ROOT"/hack/ip.py):5001"} readonly RELEASE_DATE=${RELEASE_DATE:-$(TZ=UTC date +"%Y-%m-%dT%H:%M:%SZ")} -readonly YTT_VERSION=0.42.0 -readonly YTT_CHECKSUM=aa7074d08dc35e588ab0e014f53e98aec0cfed6c3babf8a953c4225007e49ae7 - main() { readonly RELEASE_VERSION=${RELEASE_VERSION:-"v0.0.0-dev"} - readonly PREVIOUS_VERSION=${PREVIOUS_VERSION:-$(git_previous_version $RELEASE_VERSION)} + readonly RELEASE_IMAGE=${RELEASE_IMAGE:-$REGISTRY/cartographer:$RELEASE_VERSION} + readonly PREVIOUS_VERSION=${PREVIOUS_VERSION:-$(git_previous_version "$RELEASE_VERSION")} - show_vars - cd $ROOT + readonly RELEASE_USING_LEVER=${RELEASE_USING_LEVER:-false} + readonly LEVER_COMMIT_REF=${LEVER_COMMIT_REF:-"$(git rev-parse HEAD)"} + readonly LEVER_KUBECONFIG=${LEVER_KUBECONFIG:-""} - download_ytt_to_kodata + show_vars + cd "$ROOT" + + if [[ "$RELEASE_USING_LEVER" == true ]]; then + # Lever build flow + if [[ "$REGISTRY" == "192.168."* ]]; then + echo "REGISTRY must be set to a registry accessible by lever when RELEASE_USING_LEVER is true" + exit 1 + fi + if [[ "$LEVER_KUBECONFIG" == "" ]]; then + echo "LEVER_KUBECONFIG must be set when RELEASE_USING_LEVER is true" + exit 1 + fi + echo "Building using lever" + lever_build_request + else + echo "Building locally" + build_image + fi generate_release create_release_notes } @@ -45,29 +62,71 @@ show_vars() { REGISTRY: $REGISTRY RELEASE_DATE: $RELEASE_DATE RELEASE_VERSION: $RELEASE_VERSION + RELEASE_IMAGE: $RELEASE_IMAGE ROOT: $ROOT SCRATCH: $SCRATCH - YTT_VERSION: $YTT_VERSION + RELEASE_USING_LEVER: $RELEASE_USING_LEVER + LEVER_KUBECONFIG: $LEVER_KUBECONFIG + LEVER_COMMIT_REF: $LEVER_COMMIT_REF " } -download_ytt_to_kodata() { - local url=https://github.com/vmware-tanzu/carvel-ytt/releases/download/v${YTT_VERSION}/ytt-linux-amd64 - local fname=ytt-linux-amd64 - - local dest - dest=$(realpath ./cmd/cartographer/kodata/$fname) +lever_build_request() { + # Lever build request expects LEVER_KUBECONFIG to be the kubeconfig yaml to access the lever cluster + BUILD_SUFFIX="$(git rev-parse HEAD | head -c 6)-$(echo $RANDOM | shasum | head -c 6; echo)" + ytt --ignore-unknown-comments -f ./hack/lever_build_request.yaml \ + --data-value build_suffix="$BUILD_SUFFIX" \ + --data-value commit_ref="$LEVER_COMMIT_REF" \ + --data-value release_image="$RELEASE_IMAGE" \ + | kubectl --kubeconfig <(printf '%s' "${LEVER_KUBECONFIG}") apply -f - + wait_for_lever_build "cartographer-$BUILD_SUFFIX" +} - test -x $dest && echo "${YTT_CHECKSUM} $dest" | sha256sum -c && { - echo "ytt already found in kodata." - return - } +wait_for_lever_build() { + local build_name=$1 + local conditions_json="" + local components_status="-- " + local build_status="-- " + local srp_status="-- " + local ready_status="-- " + + local counter=1 + + echo "Waiting for lever build $build_name to complete..." + # Lever build request has a few build statuses with the final status being the aggregate and the one we wait on + while [[ $ready_status != 'False' && $ready_status != 'True' ]]; do + conditions_json=$(kubectl --kubeconfig <(printf '%s' "${LEVER_KUBECONFIG}") get request/"$build_name" -o jsonpath='{.status.conditions}') + components_status=$(echo "$conditions_json" | jq -r 'map(select(.type == "ComponentsReady"))[0].status') + build_status=$(echo "$conditions_json" | jq -r 'map(select(.type == "BuildReady"))[0].status') + srp_status=$(echo "$conditions_json" | jq -r 'map(select(.type == "SRPResourceSubmitted"))[0].status') + ready_status=$(echo "$conditions_json" | jq -r 'map(select(.type == "Ready"))[0].status') + loading_char=$(printf "%${counter}s") + printf "ComponentsReady: %s; BuildReady: %s; SRPResourceSubmitted: %s; Ready: %s; ${loading_char// /.}\033[0K\r" "$components_status" "$build_status" "$srp_status" "$ready_status" + counter=$((counter + 1)) + if [[ $counter -gt 3 ]]; then + counter=1 + fi + sleep 2 + done + + if [[ $ready_status == 'False' ]]; then + echo "Lever build $build_name failed" + ready_message=$(echo "$conditions_json" | jq 'map(select(.type == "Ready"))[0].message') + echo "Error: $ready_message" + exit 1 + else + # Output here is being parsed by the release pipeline to pass references to package-for-cartographer and catalog + echo "Lever build $build_name succeeded. Image published:" + kubectl --kubeconfig <(printf '%s' "${LEVER_KUBECONFIG}") get request/"$build_name" -o jsonpath='{.status.artifactStatus.images[0].name}' + echo "" + kubectl --kubeconfig <(printf '%s' "${LEVER_KUBECONFIG}") get request/"$build_name" -o jsonpath='{.status.artifactStatus.images[0].image.tag}' + fi +} - pushd "$(mktemp -d)" - curl -sSOL $url - echo "${YTT_CHECKSUM} $fname" | sha256sum -c - install -m 0755 $fname $dest - popd +build_image() { + # Build the image locally using Docker instead of ko + docker build "$ROOT" -t "$RELEASE_IMAGE" --build-arg BASE_IMAGE="ubuntu:jammy" --build-arg GOLANG_IMAGE="golang:1.19" + docker push "$RELEASE_IMAGE" } generate_release() { @@ -75,14 +134,13 @@ generate_release() { ytt --ignore-unknown-comments -f ./config \ -f ./hack/overlays/webhook-configuration.yaml \ -f ./hack/overlays/component-labels.yaml \ - --data-value version=$RELEASE_VERSION | - KO_DOCKER_REPO=$REGISTRY ko resolve -B -f- > \ - ./release/cartographer.yaml + --data-value version="$RELEASE_VERSION" \ + --data-value controller_image="$RELEASE_IMAGE" > ./release/cartographer.yaml } create_release_notes() { local changeset - changeset="$(git_changeset $RELEASE_VERSION $PREVIOUS_VERSION)" + changeset="$(git_changeset "$RELEASE_VERSION" "$PREVIOUS_VERSION")" local assets_checksums assets_checksums=$(checksums ./release) @@ -93,7 +151,7 @@ create_release_notes() { checksums() { local assets_directory=$1 - pushd $assets_directory &>/dev/null + pushd "$assets_directory" &>/dev/null find . -name "*" -type f -exec sha256sum {} + popd &>/dev/null } @@ -102,9 +160,9 @@ git_changeset() { local current_version=$1 local previous_version=$2 - [[ $current_version != v* ]] && current_version=v$current_version - [[ $previous_version != v* ]] && previous_version=v$previous_version - [[ $(git tag -l $current_version) == "" ]] && current_version=HEAD + [[ "$current_version" != v* ]] && current_version="v${current_version}" + [[ "$previous_version" != v* ]] && previous_version="v${previous_version}" + [[ $(git tag -l "$current_version") == "" ]] && current_version=HEAD git -c log.showSignature=false \ log \ @@ -119,12 +177,12 @@ git_previous_version() { local current_version=$1 local version_filter - version_filter=$(printf '^%s$' $current_version) + version_filter=$(printf '^%s$' "$current_version") - [[ $(git tag -l $current_version) == "" ]] && version_filter='.' + [[ $(git tag -l "$current_version") == "" ]] && version_filter='.' git tag --sort=-v:refname -l | - grep -A30 $version_filter | + grep -A30 "$version_filter" | grep -E '^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$' | head -n1 } @@ -171,6 +229,8 @@ Thanks to these contributors who contributed to ! %s ``` ' + # wokeignore:rule=disable + # shellcheck disable=SC2059 printf "$fmt" "$previous_version" "$changeset" "$checksums" } diff --git a/hack/setup.sh b/hack/setup.sh index c3c290d4c..5af1ea026 100755 --- a/hack/setup.sh +++ b/hack/setup.sh @@ -365,7 +365,7 @@ test_runnable_example() { exit 1 else echo "waiting 5 seconds for expected passing test to succeed" - (( counter+1 )) + (( counter+=1 )) fi done @@ -382,7 +382,7 @@ test_runnable_example() { exit 1 else echo "waiting 5 seconds for expected failing test to fail" - (( counter+1 )) + (( counter+=1 )) fi done @@ -403,7 +403,7 @@ test_runnable_example() { exit 1 else echo "waiting 5 seconds for expected passing test to succeed" - (( counter+1 )) + (( counter+=1 )) fi done