diff --git a/README-gcb.md b/README-gcb.md new file mode 100644 index 00000000000..3b3aaea59ac --- /dev/null +++ b/README-gcb.md @@ -0,0 +1,53 @@ +Table of Contents +================= +* [Intro](#intro) +* [Typical Workflows](#typical-workflows) + +# Container Builder Staging and Release + +## Intro + +The Kubernetes release process can now be staged and released on both the GCP +Container Builder (GCB) or on the desktop with the necessary permissions. + +## Typical Workflows + +The typical workflow is very simple and works similar to `anago` in both mock +and `--nomock` variants with a clear division between the two. Stage and +release using either `--nomock` or in the default (mock) mode. + +The hybrid model is also supported +* Stage on GCB +* Release on desktop + +``` +# On GCB, stage a (mock) master branch build from head +$ gcbmgr stage master --build-at-head + +# On GCB, stage a (mock) release-1.9 branch build using test signal +$ gcbmgr stage release-1.9 + +# On GCB, view last 5 jobs +$ gcbmgr +-OR- +$ gcbmgr list + +# View completed staged builds +$ gcbmgr staged + +# Release (from GCB) +$ gcbmgr release master --buildversion= + +# Release (from GCB) +$ gcbmgr release release-1.9 --buildversion= + +# And of course the man page has all the most detailed and up to date info: +$ gcbmgr -man +``` + +Guidance from `gcbmgr staged` instructs you how to release a staged build on +GCB or the desktop. + +NOTE: Releases from GCB are currently unable to send email, so the update + occurs in the form of a new release tracking issue on the + kubernetes/sig-release repo (k8s-release-robot/sig-release for mock runs). diff --git a/README.md b/README.md index 1d908dbf65a..3329f53af62 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,17 @@ on a branch. Without the [--official] flag, a beta would be created. There are two workflows you can choose from: 1. Run through a complete release end to end -2. Create any number of staged (--stage) releases and release from there +2. Create staged (--stage) releases and release from there -First try a staged alpha release: +*NOTE:* Again, the tooling works by default in *mock mode* and runs in *"full +production"* mode using `--nomock`. + +*IMPORTANT:* Staging and release workflows operate exclusively in either mock +or `--nomock` modes. If you stage something in mock mode, it is not available +in `--nomock` mode. Be sure to both stage and release with or without +`--nomock`. + +First try a (mock) staged alpha release: ``` $ anago master --stage ``` @@ -111,14 +119,14 @@ $ anago release-9.9.9 ## Typical Workflows -Stage an official (patch) release on your local disk: +Stage a (mock) official patch release on your local disk: ``` # add --build-at-head to force a build, otherwise rely on find_green_build # in-line to find a build candidate $ anago release-1.8 --stage ``` -Release previously staged official (patch) release from your local disk: +Release previously (mock) staged official patch release from your local disk: ``` # $buildversion will come from the output at the end of the above --stage run # as will this command-line in its entirety diff --git a/anago b/anago index 8af231d1159..7421fc60263 100755 --- a/anago +++ b/anago @@ -30,7 +30,6 @@ PROG=${0##*/} #+ [--security_layer=/path/to/pointer/to/script] #+ [--exclude-suites=" ..."] #+ [--build-at-head] -#+ [--user-at-domain=] #+ [--prebuild] [--buildonly] #+ [--mailto=,] [--gcb] #+ [--tmpdir=] @@ -102,10 +101,6 @@ PROG=${0##*/} #+ A simple $USER check controls who can run in --nomock mode as ACLs #+ restrict who can actually push bits anyway. #+ -#+ --user-at-domain will let you specify an alternate full user@domain.tld. -#+ This should be the address associated with the release GCP project and -#+ the account from which you will be sending mail. -#+ #+ OPTIONS #+ [--stage] - Write all artifacts to #+ gs://$RELEASE_BUCKET/stage for later use @@ -137,9 +132,6 @@ PROG=${0##*/} #+ Users are prompted to remove draft releases, #+ but the action to create them in the first #+ place should be explicit. -#+ [--user-at-domain=] - Specify an (alternate) user@domain.tld -#+ (registered at GCP project and for mailing -#+ release announcements) #+ [--gcb] - Running from GCB #+ [--tmpdir=] - Set an alternate temp dir #+ [--prebuild] - Used during GCB to halt before building @@ -179,7 +171,10 @@ PROG=${0##*/} # If NO ARGUMENTS should return usage, uncomment the following line: usage=${1:-yes} -source $(dirname $(readlink -ne $BASH_SOURCE))/lib/common.sh +# Deal with OSX limitations out the gate for anyone that tries this there +BASE_ROOT=$(dirname $(readlink -e "$BASH_SOURCE" 2>&1)) \ + || BASE_ROOT="$BASH_SOURCE" +source $BASE_ROOT/lib/common.sh source $TOOL_LIB_PATH/gitlib.sh source $TOOL_LIB_PATH/releaselib.sh @@ -199,12 +194,6 @@ RELEASE_BRANCH=${POSITIONAL_ARGV[0]} [[ $RELEASE_BRANCH =~ $BRANCH_REGEX ]] \ || common::exit 1 "Invalid branch name!" -# Backport https://github.com/kubernetes/kubernetes/pull/47939 and remove this -if ((FLAGS_stage)) && \ - ([[ $RELEASE_BRANCH != "master" ]] && ((${BASH_REMATCH[2]}<8))); then - common::exit 1 "--stage only works for 1.8+ releases." -fi - # Check arg conflicts if ((FLAGS_rc)) || ((FLAGS_official)); then if [[ "$RELEASE_BRANCH" == "master" ]]; then @@ -292,7 +281,7 @@ ensure_registry_acls () { fi # Always reset back to $USER - ((FLAGS_gcb)) || logrun $GCLOUD config set account $USER_AT_DOMAIN + ((FLAGS_gcb)) || logrun $GCLOUD config set account $GCP_USER done logrun rm -f $emptyfile @@ -304,16 +293,15 @@ ensure_registry_acls () { # Checks GCP users to ensure they are logged in and accessible # return 1 on failure ensure_gcp_users () { - local userat="$USER_AT_DOMAIN" local user local -a users_to_check - users_to_check+=($G_AUTH_USER $userat) + users_to_check+=($G_AUTH_USER $GCP_USER) for user in ${users_to_check[*]}; do logecho -n "Checking cloud account/auth $user: " - if (logrun gcloud config set account $user && \ - logrun gcloud docker -- version >/dev/null 2>&1); then + if (logrun $GCLOUD config set account $user && \ + logrun $GCLOUD docker -- version >/dev/null 2>&1); then logecho -r "$OK" else logecho -r "$FAILED" @@ -321,22 +309,10 @@ ensure_gcp_users () { logecho "$user is not in the credentialed accounts list!" logecho "Sign in with:" logecho - logecho "$ gcloud auth login $user" + logecho "$ $GCLOUD auth login $user" return 1 fi done - - # Ensure $USER is active to start - # The loop above finishes on $userat - gcloud_auth_list=$($GCLOUD auth list --filter=status:ACTIVE \ - --format="value(account)" 2>/dev/null) - if ! [[ "$gcloud_auth_list" =~ $userat ]]; then - logecho "$userat is not the active gcloud user!" - logecho "Set with:" - logecho - logecho "$ gcloud config set account $userat" - return 1 - fi } ############################################################################### @@ -352,8 +328,9 @@ check_prerequisites () { # We check for docker here as a word which passes for docker-ce and # docker-engine as docker packages are in transiation of deprecating # docker-engine - common::check_packages jq pandoc docker ${PREREQUISITE_PACKAGES[*]} - common::check_pip_packages yq || common::exit 1 "Exiting..." + common::check_packages jq pandoc docker ${PREREQUISITE_PACKAGES[*]} \ + || return 1 + common::check_pip_packages yq || return 1 security_layer::auth_check 2 || return 1 @@ -365,11 +342,6 @@ check_prerequisites () { # to ensure both mock and --nomock runs will work. ensure_registry_acls "${ALL_CONTAINER_REGISTRIES[*]}" || return 1 - # Verify write access to $WRITE_RELEASE_BUCKETS - for rb in ${WRITE_RELEASE_BUCKETS[*]}; do - release::gcs::ensure_release_bucket $rb || return 1 - done - logecho -n "Checking cloud project state: " GCLOUD_PROJECT=$($GCLOUD config get-value project 2>/dev/null) if [[ -z "$GCLOUD_PROJECT" ]]; then @@ -380,6 +352,11 @@ check_prerequisites () { return 1 fi logecho -r "$OK" + + # Verify write access to $WRITE_RELEASE_BUCKETS + for rb in ${WRITE_RELEASE_BUCKETS[*]}; do + release::gcs::ensure_release_bucket $rb || return 1 + done } ############################################################################### @@ -573,6 +550,26 @@ git_tag () { logrun -s git tag -a -m "$commit_string" "${RELEASE_VERSION[$label]}" } +############################################################################## +# Tag/Build a local kube_cross image based on the version in scope +PROGSTEP[local_kube_cross]="TAG/BUILD LOCAL KUBE CROSS" +local_kube_cross () { + local docker_image="gcr.io/google_containers/kube-cross" + local version="$(cat $TREE_ROOT/build/build-image/cross/VERSION)" + local image="$docker_image:$version" + local local_image="$docker_image:local" + + logecho -n "Checking if $image exists locally: " + if logrun -s docker pull $image; then + logecho -n "Tagging docker image $image as $local_image: " + logrun -s docker tag $image $local_image + else + logecho -n "Building docker image $image: " + logrun -s docker build --cache-from $docker_image -t $image \ + -t $local_image $TREE_ROOT/build/build-image/cross/ + fi +} + ############################################################################## # Prepare sources for building for a given label # @param label - The label to process @@ -679,7 +676,10 @@ build_tree () { if ((FLAGS_gcb)); then # make_cross done separately # OUT_DIR works in this context. Woohoo! - logrun -s -v make package-tarballs OUT_DIR=$OUT_DIR-$version || return 1 + # KUBE_DOCKER_IMAGE_TAG needed here due to references deep in + # build/lib/release.sh + logrun -s -v make package-tarballs KUBE_DOCKER_IMAGE_TAG="$version" \ + OUT_DIR=$OUT_DIR-$version || return 1 else # TODO: Ideally we update LOCAL_OUTPUT_ROOT in build/common.sh to be # modifiable. In the meantime just mv the dir after it's done @@ -922,7 +922,7 @@ announce () { local subject local announcement_text=$TMPDIR/$PROG-announce.$$ - ((FLAGS_nomock)) || mailto=$USER_AT_DOMAIN + ((FLAGS_nomock)) || mailto=$GCP_USER mailto=${FLAGS_mailto:-$mailto} if [[ "$arg" == "--branch" ]]; then @@ -952,9 +952,9 @@ announce () { # Due to announcements landing on public mailing lists requiring membership, # post from the invoking user (for now until this is productionized further) # and use reply-to to ensure replies go to the right place. - common::sendmail -h "$mailto" "K8s-Anago<$USER_AT_DOMAIN>" \ + common::sendmail -h "$mailto" "K8s-Anago<$GCP_USER>" \ "K8s-Anago" \ - "$subject" "$USER_AT_DOMAIN" \ + "$subject" "$GCP_USER" \ "$announcement_text" || return 1 fi @@ -1039,9 +1039,13 @@ update_github_release () { # publish binary logecho -n "Uploading binary to github: " - logrun -s $GHCURL -H "Content-Type:application/x-compressed" \ + if $GHCURL -H "Content-Type:application/x-compressed" \ --data-binary @$tarball \ - "${K8S_GITHUB_API/api\./uploads\.}/releases/$release_id/assets?name=${tarball##*/}" + "${K8S_GITHUB_API/api\./uploads\.}/releases/$release_id/assets?name=${tarball##*/}"; then + logecho $OK + else + logecho $FAILED + fi if $draft; then logecho @@ -1053,7 +1057,7 @@ update_github_release () { if ((FLAGS_yes)) || \ common::askyorn -y "Delete draft release (id #$release_id) now"; then logecho -n "Deleting the draft release (id #$release_id): " - logrun $GHCURL -X DELETE $K8S_GITHUB_API/releases/$release_id + $GHCURL -X DELETE $K8S_GITHUB_API/releases/$release_id fi # verify it was deleted @@ -1156,8 +1160,9 @@ get_build_candidate () { fi if [[ -z $BRANCH_POINT ]]; then - if [[ -n $JENKINS_BUILD_VERSION ]]; then - logecho -r "$ATTENTION: Using --buildversion=$JENKINS_BUILD_VERSION" + if [[ -n "$FLAGS_buildversion" ]]; then + logecho -r "$ATTENTION: Using --buildversion=$FLAGS_buildversion" + JENKINS_BUILD_VERSION="$FLAGS_buildversion" else logecho "Asking Jenkins for a good build (this may take some time)..." FLAGS_verbose=1 release::set_build_version \ @@ -1359,6 +1364,100 @@ push_all_artifacts () { fi } +############################################################################## +# Sets major global variables +# RELEASE_GB - space requirements per build +# GCP_USER - The user that drives the entire release +# RELEASE_BUCKET - mock or standard release bucket location +# BUCKET_TYPE - stage or release +# WRITE_RELEASE_BUCKETS - array of writable buckets +# READ_RELEASE_BUCKETS - array of readable buckets for multiple sourcing of +# mock staged builds +# GCRIO_REPO - GCR repo based on mock or --nomock +# ALL_CONTAINER_REGISTRIES - when running mock this array also contains +# google_containers so we can check access in mock +# mode before an actual release occurs +set_globals () { + # Define the placeholder/"role" user for GCB + local gcb_user="gcb@google.com" + + logecho -n "Setting global variables: " + + # Default disk requirements per version - Modified in found_staged_location() + RELEASE_GB="75" + + if ((FLAGS_gcb)); then + # a placeholder that satisfies @google.com conditional below + GCP_USER="$gcb_user" + else + # Nothing should work without this. The entire release workflow depends + # on it whether running from the desktop or GCB + GCP_USER=$($GCLOUD auth list --filter=status:ACTIVE \ + --format="value(account)" 2>/dev/null) + if [[ -z "$GCP_USER" ]]; then + logecho $FAILED + logecho "Unable to set a valid GCP credential!" + return 1 + fi + fi + + RELEASE_BUCKET="kubernetes-release" + if [[ $GCP_USER =~ "@google.com" ]]; then + WRITE_RELEASE_BUCKETS=("$RELEASE_BUCKET") + READ_RELEASE_BUCKETS=("$RELEASE_BUCKET") + fi + + if ((FLAGS_stage)); then + BUCKET_TYPE="stage" + else + BUCKET_TYPE="release" + fi + + if ((FLAGS_nomock)); then + GCRIO_REPO="${FLAGS_gcrio_repo:-google_containers}" + ALL_CONTAINER_REGISTRIES=("$GCRIO_REPO") + else + # GCS buckets cannot contain @ or "google", so for those users, just use + # the "$USER" portion of $GCP_USER/$gcb_user + RELEASE_BUCKET_USER="$RELEASE_BUCKET-${GCP_USER%%@google.com}" + RELEASE_BUCKET_GCB="$RELEASE_BUCKET-${gcb_user%%@google.com}" + RELEASE_BUCKET_USER="${RELEASE_BUCKET_USER/@/-at-}" + RELEASE_BUCKET_GCB="${RELEASE_BUCKET_GCB/@/-at-}" + # GCP also doesn't like anything even remotely looking like a domain name + # in the bucket name so convert . to - + RELEASE_BUCKET_USER="${RELEASE_BUCKET_USER/\./-}" + RELEASE_BUCKET_GCB="${RELEASE_BUCKET_GCB/\./-}" + RELEASE_BUCKET="$RELEASE_BUCKET_USER" + + # All the RELEASE_BUCKETS we could possibly write to + WRITE_RELEASE_BUCKETS+=("$RELEASE_BUCKET_USER") + # All the RELEASE_BUCKETS we could possibly read from (for staging) + READ_RELEASE_BUCKETS+=("$RELEASE_BUCKET_USER") + # If a regular user is running mocks, also look in the GCB mock bucket for + # releases + ((FLAGS_gcb)) || READ_RELEASE_BUCKETS+=("$RELEASE_BUCKET_GCB") + + # Set GCR values + GCRIO_REPO="${FLAGS_gcrio_repo:-kubernetes-release-test}" + [[ $GCP_USER =~ "@google.com" ]] \ + && ALL_CONTAINER_REGISTRIES=("$GCRIO_REPO" "google_containers") + + # This is passed to logrun() where appropriate when we want to mock + # specific activities like pushes + LOGRUN_MOCK="-m" + fi + + # TODO: + # These KUBE_ globals extend beyond the scope of the new release refactored + # tooling so to pass these through as flags will require fixes across + # kubernetes/kubernetes and kubernetes/release which we can do at a later time + export KUBE_DOCKER_REGISTRY="gcr.io/$GCRIO_REPO" + export KUBE_RELEASE_RUN_TESTS=n + export KUBE_SKIP_CONFIRMATIONS=y + + logecho $OK +} + ############################################################################### # MAIN ############################################################################### @@ -1367,61 +1466,6 @@ push_all_artifacts () { : ${FLAGS_rc:=0} : ${FLAGS_official:=0} -# Default disk requirements per version - Modified in found_staged_location() -RELEASE_GB="75" - -# Domain check -if [[ "$FLAGS_user_at_domain" ]]; then - USER_AT_DOMAIN="$FLAGS_user_at_domain" -elif [[ "$HOSTNAME" =~ \.([^\.]+\.[a-z]{2,})$ ]]; then - USER_AT_DOMAIN="$USER@${BASH_REMATCH[1]}" -elif ((FLAGS_gcb)); then - # Just a placeholder that satisfies @google.com conditionals but isn't used - USER_AT_DOMAIN="gcb@google.com" -fi - -if [[ -z $USER_AT_DOMAIN ]]; then - common::exit 1 "$FATAL: Unable to determine your domain." \ - "Use --user-at-domain=user@domain.tld" -fi - -# Set with --buildversion or set it later in release::set_build_version() -JENKINS_BUILD_VERSION=$FLAGS_buildversion - -RELEASE_BUCKET="kubernetes-release" -if [[ $USER_AT_DOMAIN =~ "google.com" ]]; then - WRITE_RELEASE_BUCKETS=("$RELEASE_BUCKET") - READ_RELEASE_BUCKETS=("$RELEASE_BUCKET") -fi - -if ((FLAGS_stage)); then - BUCKET_TYPE="stage" -else - BUCKET_TYPE="release" -fi -if ((FLAGS_nomock)); then - GCRIO_REPO="${FLAGS_gcrio_repo:-google_containers}" - ALL_CONTAINER_REGISTRIES=("$GCRIO_REPO") -else - RELEASE_BUCKET_USER="$RELEASE_BUCKET-$USER" - RELEASE_BUCKET_MOCK="$RELEASE_BUCKET-mock" - # This is passed to logrun() where appropriate when we want to mock - # specific activities like pushes - LOGRUN_MOCK="-m" - # Point to a mock-specific bucket. $USER for desktop runs - if ((FLAGS_gcb)); then - RELEASE_BUCKET=$RELEASE_BUCKET_MOCK - else - RELEASE_BUCKET=$RELEASE_BUCKET_USER - fi - # All the RELEASE_BUCKETS we could possibly write to - WRITE_RELEASE_BUCKETS+=("$RELEASE_BUCKET") - # All the RELEASE_BUCKETS we could possibly read from (for staging) - READ_RELEASE_BUCKETS+=("$RELEASE_BUCKET_USER" "$RELEASE_BUCKET_MOCK") - GCRIO_REPO="${FLAGS_gcrio_repo:-kubernetes-release-test}" - [[ $USER_AT_DOMAIN =~ "google.com" ]] \ - && ALL_CONTAINER_REGISTRIES=("$GCRIO_REPO" "google_containers") -fi BASEDIR=${FLAGS_basedir} if [[ -z "${BASEDIR}" ]]; then # Goobuntu machines have a standard path for "local" disk as the home @@ -1433,14 +1477,6 @@ if [[ -z "${BASEDIR}" ]]; then fi fi -# TODO: -# These KUBE_ globals extend beyond the scope of the new release refactored -# tooling so to pass these through as flags will require fixes across -# kubernetes/kubernetes and kubernetes/release which we can do at a later time -export KUBE_DOCKER_REGISTRY="gcr.io/$GCRIO_REPO" -export KUBE_RELEASE_RUN_TESTS=n -export KUBE_SKIP_CONFIRMATIONS=y - ############################################################################## # Initialize logs ############################################################################## @@ -1454,11 +1490,34 @@ common::logfileinit $LOGFILE 10 # BEGIN script common::timestamp begin +# Point release managers to GCB as the preferred method +if ! ((FLAGS_gcb)); then + logecho $HR + logecho "${TPUT[BOLD]}**** Welcome to the Kubernetes Release Tool, Release" \ + "Manager ****" + logecho + logecho "***************** $PROG has moved to the cloud! *******************${TPUT[OFF]}" + logecho + logecho "* Kubernetes releases have been moved off the desktop" + logecho + logecho "* Desktop $PROG has not been disabled, but running via GCB is the" \ + "preferred method. Usage is similar to $PROG." + logecho + logecho "* https://github.com/kubernetes/release/blob/master/README-gcb.md" \ + "for details on how to get started." + logecho $HR + logecho + logecho -n "Press any key to continue..." + logrun read -n1 + logecho +fi + # Order workflow based on conditions ((FLAGS_stage)) || common::stepindex "gitlib::github_acls" common::stepindex "check_prerequisites" "get_build_candidate" \ "prepare_workspace" "common::disk_space_check" common::stepindex "prepare_tree" +((FLAGS_gcb)) && common::stepindex "local_kube_cross" if ((FLAGS_buildonly)); then ((FLAGS_gcb)) && common::stepindex "make_cross" ((FLAGS_gcb)) || common::stepindex "build_tree" @@ -1474,7 +1533,7 @@ elif ! ((FLAGS_prebuild)); then if ! ((FLAGS_stage)); then common::stepindex "announce" if ((FLAGS_gcb)); then - common::stepindex "gitlib::create_release_issue" + common::stepindex "gitlib::update_release_issue" else common::stepindex "update_github_release" fi @@ -1504,6 +1563,10 @@ if ! ((FLAGS_buildonly)) && ! common::set_cloud_binaries; then common::exit 1 "Exiting..." fi +# Set the majorify of global values +# Moved here b/c now depends on gcloud +set_globals + ((FLAGS_stage)) || common::run_stateful gitlib::github_acls # Simple check to validate who can do actual releases @@ -1635,6 +1698,11 @@ if [[ -z $STAGED_LOCATION ]]; then # Iterate over session release versions for setup, tagging and building for label in ${!RELEASE_VERSION[@]}; do common::run_stateful "prepare_tree $label" RELEASE_VERSION[$label] + # This doesn't have to be done per label, but does need to be inserted + # after an initial prepare_tree(), so just let the statefulness of it + # ignore a second iteration/call. + ((FLAGS_gcb)) \ + && common::run_stateful local_kube_cross # --prebuild for GCB, skip actual builds. Do everything else if ! ((FLAGS_prebuild)); then if ((FLAGS_gcb)); then @@ -1674,7 +1742,7 @@ else # Force complete for these three stages for label in ${!RELEASE_VERSION[@]}; do SKIP_STEPS+=(prepare_tree+$label build_tree+$label) - ((FLAGS_gcb)) && SKIP_STEPS+=(make_cross+$label) + ((FLAGS_gcb)) && SKIP_STEPS+=(local_kube_cross make_cross+$label) done SKIP_STEPS+=(generate_release_notes) for entry in ${SKIP_STEPS[*]}; do @@ -1721,28 +1789,28 @@ if ((FLAGS_stage)); then # clean up here on success # Debatable if this should only happen on GCB if ((FLAGS_gcb)) && ((FLAGS_stage)); then - # Get a list of things to delete - # Everything but the one staged by this run - logecho "Cleaning up old staged builds..." + # Delete everything that's not this build in the vX.Y. namespace # || true to catch non-zero exit when list is empty - $GSUTIL ls -d gs://$RELEASE_BUCKET/$BUCKET_TYPE/${JENKINS_BUILD_VERSION%%-*}* |grep -v $JENKINS_BUILD_VERSION |xargs $GSUTIL -mq rm -r || true + if [[ $JENKINS_BUILD_VERSION =~ (v[0-9]+\.[0-9]+\.) ]]; then + logecho "Cleaning up old staged builds from" \ + "gs://$RELEASE_BUCKET/$BUCKET_TYPE/${BASH_REMATCH[1]}..." + $GSUTIL ls -d gs://$RELEASE_BUCKET/$BUCKET_TYPE/${BASH_REMATCH[1]}* |\ + grep -v $JENKINS_BUILD_VERSION |xargs $GSUTIL -mq rm -r || true + fi fi common::exit 0 fi if [[ -n "$PARENT_BRANCH" ]]; then + # TODO: This needs the gcb create/update release issue treatment common::run_stateful "announce --branch" else common::run_stateful announce # For GCB create/update a release tracking issue if ((FLAGS_gcb)); then - #if search_release_issue $RELEASE_VERSION_PRIME; then - # comment_release_issue - #else - common::run_stateful "gitlib::create_release_issue $RELEASE_VERSION_PRIME" - #fi + common::run_stateful "gitlib::update_release_issue $RELEASE_VERSION_PRIME" else common::run_stateful update_github_release fi diff --git a/build/Dockerfile.k8s-cloud-builder b/build/Dockerfile.k8s-cloud-builder new file mode 100644 index 00000000000..cb674a10eb5 --- /dev/null +++ b/build/Dockerfile.k8s-cloud-builder @@ -0,0 +1,50 @@ +# To rebuild and publish this container run: +# gcloud container builds submit --config update_build_container.yaml . + +FROM ubuntu + +# Install packages +RUN apt-get -q update && apt-get install -qqy apt-transport-https \ + ca-certificates curl git gnupg2 lsb-release python \ + software-properties-common wget python-setuptools python-dev \ + build-essential jq pandoc gettext-base + +# Install Pip packages +RUN easy_install pip +RUN pip install yq + +# Packages required by the make in k8s +# localtime +RUN apt-get -q update && apt-get install -qqy tzdata + +# install net tools +# required by common.sh +RUN apt-get -q update && apt-get install -qqy grep net-tools rsync + +# Install gcloud +RUN echo "deb https://packages.cloud.google.com/apt cloud-sdk-$(lsb_release -cs) main" > /etc/apt/sources.list.d/google-cloud-sdk.list && \ + curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \ + apt-get -q update && \ + apt-get install -qqy google-cloud-sdk + +# Install docker stuff +#--------------------- +# Based on instructions from: +# https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#uninstall-old-versions +RUN \ + apt-get -y update && \ + apt-get install -y \ + linux-image-extra-virtual \ + apt-transport-https \ + ca-certificates \ + curl \ + software-properties-common && \ + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \ + add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable edge" && \ + apt-get -y update + +ARG DOCKER_VERSION=17.09.0~ce-0~ubuntu +RUN apt-get install -y docker-ce=${DOCKER_VERSION} unzip diff --git a/build/build-k8s-cloud-builder-container b/build/build-k8s-cloud-builder-container new file mode 100755 index 00000000000..e37ca0e948d --- /dev/null +++ b/build/build-k8s-cloud-builder-container @@ -0,0 +1 @@ +gcloud container builds submit --config k8s-container.yaml . diff --git a/build/k8s-container.yaml b/build/k8s-container.yaml new file mode 100644 index 00000000000..2614248f70f --- /dev/null +++ b/build/k8s-container.yaml @@ -0,0 +1,8 @@ +# To build and upload a new version of the build container run: +# gcloud container builds submit --config k8s-container.yaml . + +steps: + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-f', 'Dockerfile.k8s-cloud-builder', '-t', 'gcr.io/$PROJECT_ID/k8s-cloud-builder', '.'] + +images: ['gcr.io/$PROJECT_ID/k8s-cloud-builder' ] diff --git a/gcb/release.yaml b/gcb/release.yaml new file mode 100644 index 00000000000..2edb178d944 --- /dev/null +++ b/gcb/release.yaml @@ -0,0 +1,38 @@ +timeout: 14400s + +secrets: +- kmsKeyName: projects/kubernetes-release-test/locations/global/keyRings/anago/cryptoKeys/anago-crypto + secretEnv: + GITHUB_TOKEN: CiQAgPFXnRMc5ZcjM+vEL/4GqevMkjKgWNzwzv9vCQTqLoqzjeoSUQCWqHUkjJaDHICJxKpaJWFzktaSMH9V23XtbqbARYGQumKZYylQQ8kQ5DJPDSjisGoI5c7F+Mgic6iqHY/qmEWRGJo+wwMPqb8BMx9wrotP/A== + +steps: +- name: gcr.io/cloud-builders/git + args: + - "clone" + - "https://github.com/kubernetes/release" + +- name: gcr.io/$PROJECT_ID/k8s-cloud-builder + dir: release + secretEnv: + - GITHUB_TOKEN + args: + - "./anago" + - "${_RELEASE_BRANCH}" + - "${_NOMOCK}" + - "${_OFFICIAL}" + - "${_BUILDVERSION}" + - "--yes" + - "--gcb" + - "--basedir=/workspace" + - "--tmpdir=/workspace/tmp" + +tags: +- ${_GCP_USER_TAG} +- ${_RELEASE_BRANCH} +- ${_BUILD_POINT} +- ${_NOMOCK_TAG} +- ${_OFFICIAL_TAG} +- RELEASE + +options: + machineType: N1_HIGHCPU_32 diff --git a/gcb/stage.yaml b/gcb/stage.yaml new file mode 100644 index 00000000000..ca379db8b95 --- /dev/null +++ b/gcb/stage.yaml @@ -0,0 +1,74 @@ +timeout: 14400s + +secrets: +- kmsKeyName: projects/kubernetes-release-test/locations/global/keyRings/anago/cryptoKeys/anago-crypto + secretEnv: + GITHUB_TOKEN: CiQAgPFXnRMc5ZcjM+vEL/4GqevMkjKgWNzwzv9vCQTqLoqzjeoSUQCWqHUkjJaDHICJxKpaJWFzktaSMH9V23XtbqbARYGQumKZYylQQ8kQ5DJPDSjisGoI5c7F+Mgic6iqHY/qmEWRGJo+wwMPqb8BMx9wrotP/A== + +steps: +- name: gcr.io/cloud-builders/git + args: + - "clone" + - "https://github.com/kubernetes/release" + +- name: gcr.io/$PROJECT_ID/k8s-cloud-builder + dir: release + secretEnv: + - GITHUB_TOKEN + args: + - "./anago" + - "${_RELEASE_BRANCH}" + - "--stage" + - "--prebuild" + - "${_BUILD_AT_HEAD}" + - "${_NOMOCK}" + - "${_OFFICIAL}" + - "${_BUILDVERSION}" + - "--yes" + - "--gcb" + - "--basedir=/workspace" + - "--tmpdir=/workspace/tmp" + +- name: gcr.io/google_containers/kube-cross:local + dir: release + args: + - "./anago" + - "${_RELEASE_BRANCH}" + - "--stage" + - "--buildonly" + - "${_BUILD_AT_HEAD}" + - "${_NOMOCK}" + - "${_OFFICIAL}" + - "${_BUILDVERSION}" + - "--yes" + - "--gcb" + - "--basedir=/workspace" + - "--tmpdir=/workspace/tmp" + +- name: gcr.io/$PROJECT_ID/k8s-cloud-builder + dir: release + secretEnv: + - GITHUB_TOKEN + args: + - "./anago" + - "${_RELEASE_BRANCH}" + - "--stage" + - "${_BUILD_AT_HEAD}" + - "${_NOMOCK}" + - "${_OFFICIAL}" + - "${_BUILDVERSION}" + - "--yes" + - "--gcb" + - "--basedir=/workspace" + - "--tmpdir=/workspace/tmp" + +tags: +- ${_GCP_USER_TAG} +- ${_RELEASE_BRANCH} +- ${_BUILD_POINT} +- ${_NOMOCK_TAG} +- ${_OFFICIAL_TAG} +- STAGE + +options: + machineType: N1_HIGHCPU_32 diff --git a/gcbmgr b/gcbmgr new file mode 100755 index 00000000000..20cf8537cc5 --- /dev/null +++ b/gcbmgr @@ -0,0 +1,460 @@ +#!/bin/bash +# +# Copyright 2017 The Kubernetes Authors All rights reserved. +# +# 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. +# +# Set PROGram name +PROG=${0##*/} +######################################################################## +#+ +#+ NAME +#+ $PROG - Manage Kubernetes Container Release Builds +#+ +#+ SYNOPSIS +#+ Reporting: +#+ $PROG list [STATUS] +#+ $PROG staged +#+ $PROG tail|stream [BUILD_ID] +#+ Staging: +#+ $PROG stage [--buildversion=] +#+ [--build-at-head] [--nomock] [--official] +#+ Releasing: +#+ $PROG release --buildversion= +#+ [--nomock] [--official] +#+ $PROG [--helpshort|--usage|-?] +#+ $PROG [--help|-man] +#+ +#+ DESCRIPTION +#+ Manage Kubernetes/Kubernetes release builds created on Container Builder +#+ on the Google Cloud Platform. +#+ +#+ Releases can only occur from staged builds. The --buildversion arg +#+ works for both staging and releasing. The format of a build version is +#+ vX.Y.Z{-alpha.n|-beta.n}.NN+commit-hash +#+ (Ex. v1.8.8-beta.0.72+cce11c6a185279) +#+ +#+ 'list' shows a columnized output of job associated tags, the job id and +#+ the start time of the job. The tags provide lots of useful info: +#+ +#+ * Who - $USER or GCP USER +#+ * Source commit - HEAD, (result of) find_green_build or --buildversion +#+ * Branch +#+ * Type - STAGE or RELEASE +#+ * Flags - --official and --nomock +#+ +#+ Typical usage: +#+ +#+ # List running jobs +#+ $ $PROG +#+ +#+ # List up to last 5 succeeding jobs +#+ $ $PROG list success +#+ +#+ # "tail"/stream most recent running build +#+ $ $PROG tail +#+ +#+ # Check Staged builds +#+ $ $PROG staged +#+ +#+ # Stage a new master branch release (on passing blocking tests) +#+ $ $PROG master +#+ +#+ # Stage a new master branch release (at head) +#+ $ $PROG master --build-at-head +#+ +#+ # Stage a new release-1.9 branch release (on passing blocking tests) +#+ $ $PROG release-1.9 +#+ +#+ # Stage a new release-1.9 branch release (at head) +#+ $ $PROG release-1.9 +#+ +#+ # Release a previously staged build +#+ $ $PROG release-1.8 --buildversion=v1.8.8-beta.0.72+cce11c6a185279 +#+ +#+ OPTIONS +#+ tail|stream - tail/stream the latest running job to your +#+ console window. You can also specify a +#+ BUILD_ID to stream. +#+ list - List last (up to) 5 jobs. +#+ Default is to list jobs of any status +#+ Or specified by one of WORKING, FAILURE +#+ SUCCESS or CANCELLED (case not important) +#+ staged - Show all staged builds. With --nomock +#+ non-mock staged builds are shown. Without +#+ --nomock, both stage/*-$GCP_USER +#+ & stage/*-gcb builds are shown and +#+ available for release. +#+ --build-at-head - Build directly from head. Do not analyze +#+ test data to pick a candidate. +#+ --nomock - Stage a non-mocked release build to prepare +#+ for an actual release. +#+ --official - For release-* branches, stage an official +#+ X.Y.Z release. Without --official, only the +#+ -beta on the branch is incremented and built. +#+ --buildversion - Release from a previously staged build or +#+ stage a known version. +#+ [--help | -man] - display man page for this script +#+ [--usage | -?] - display in-line usage +#+ +#+ EXAMPLES +#+ $PROG - Default 'list' behavior +#+ $PROG stream - Show the most recent active log +#+ $PROG master --build-at-head +#+ - Build at head on the master branch +#+ $PROG release-1.8 --official +#+ - Analyze test data to find a candidate and +#+ stage an official build for release in mock +#+ mode. +#+ $PROG release-1.8 --official --nomock +#+ - Same as above but stage in non-mock bucket. +#+ +#+ FILES +#+ anago - Main release tool +#+ find_green_build - Test analysis tool +#+ +#+ SEE ALSO +#+ lib/common.sh - base function definitions +#+ lib/github.sh - github specific functions +#+ lib/releaselib.sh - release specific functions +#+ +#+ BUGS/TODO +#+ +######################################################################## +# Deal with OSX limitations out the gate for anyone that tries this there +BASE_ROOT=$(dirname $(readlink -e "$BASH_SOURCE" 2>&1)) \ + || BASE_ROOT="$BASH_SOURCE" +source $BASE_ROOT/lib/common.sh +source $TOOL_LIB_PATH/gitlib.sh +source $TOOL_LIB_PATH/releaselib.sh + +############################################################################### +# FUNCTIONS +############################################################################### +############################################################################### +# common::cleanexit prog-specific override function +# @param exit code +# +common::cleanexit () { + [[ -t 1 ]] && tput cnorm + + common::timestamp end + exit ${1:-0} +} + + +list_staged_builds () { + local bucket + local i + local n + local minor + local staging_buckets + + # Gather last releases + gitlib::last_releases + + logecho + logecho "${TPUT[BOLD]}Last published releases by branch:${TPUT[OFF]}" + for i in $(for n in ${!LAST_RELEASE[*]}; do echo $n; done |sort -h); do + logecho $i: ${LAST_RELEASE[$i]} + done + + for bucket in $BUCKET $USER_BUCKET; do + # Store existing buckets in an array for later use + staging_buckets+=(gs://$bucket/stage) + logecho + logecho "${TPUT[BOLD]}Staged builds on $bucket:${TPUT[OFF]}" + gsutil ls -h gs://$bucket/stage 2>&- + done + + # TODO: Experiment to look at all current versions and then compare + # the related builds in staging to them to only show valid/usable + # staged builds. The below experiment works except that it excludes + # master branch Z+1s until the first Z+1 is published. Still looking + # for a clever, uncomplicated way of displaying this without sending + # people through the gauntlet of trying to figure this out themselves. + # On the plus side, anago does a pretty good job of cleaning up older + # staged builds so the effect here is minimal + #for i in $(for n in ${!LAST_RELEASE[*]}; do echo $n; done |sort -h); do + # [[ ${LAST_RELEASE[$i]} =~ (v[0-9]+\.[0-9]+\.) ]] + # minor=${BASH_REMATCH[1]} + # n=$(echo ${LAST_RELEASE[$i]} | tr -d '[a-z-.]') + # for build in $(gsutil ls -h ${staging_buckets[*]} |fgrep $minor); do + # [[ $build =~ ${VER_REGEX[release]} ]] + # n2=$(echo ${BASH_REMATCH[0]} | tr -d '[a-z-.]') + # ((n2&-) + + # Convert time to local time + time=$(date -d $time +%Y-%b-%d+%R:%S) + echo "$tags" "${status:0:1}" "$id" "$time" + echo + ((counter>=count)) && break + done + } |column -te -c80 +} + +submit_it () { + local substitutions + + # Additional TAG substitutions + substitutions="_OFFICIAL_TAG=$OFFICIAL_TAG,_NOMOCK_TAG=$NOMOCK_TAG" + substitutions+=",_BUILD_POINT=$BUILD_POINT,_GCP_USER_TAG=$GCP_USER_TAG" + + [[ $COMMAND == stage ]] && substitutions+=",_BUILD_AT_HEAD=$BUILD_AT_HEAD" + + # The usual suspects + substitutions+=",_RELEASE_BRANCH=$RELEASE_BRANCH,_OFFICIAL=$OFFICIAL" + substitutions+=",_NOMOCK=$NOMOCK,_BUILDVERSION=$BUILDVERSION" + + if ! JOB_DATA=$($GCLOUD container builds submit --no-source \ + --config=$YAML_FILE --async --disk-size=$DISK_SIZE \ + --substitutions $substitutions 2>&1); then + logecho "$FAILED: Job was not submitted. Details:" + logecho "$JOB_DATA" + exit 1 + fi + + BUILD_ID=$(echo "$JOB_DATA" |awk 'END{print $1}') + [[ "$JOB_DATA" =~ Logs\ are\ available\ at\ \[(https.*)\]\. ]] \ + && BUILD_URL=${BASH_REMATCH[1]} + logecho $HR + logecho "${COMMAND^^} $BUILD_ID submitted sucessfully." + logecho $HR + + logecho + logecho "To view last build:" + logecho "$ $PROG tail" + logecho + logecho "To view this specific build:" + logecho "$ $PROG tail $BUILD_ID" + logecho "-OR-" + logecho "$ $GCLOUD container builds log --stream $BUILD_ID" + logecho "-OR-" + logecho "$BUILD_URL" +} + +release_it () { + if [[ -z $RELEASE_BRANCH ]]; then + logecho "Branch not set. Can't continue" + return 1 + fi + + # Check for mandatory buildversion + if [[ -z $FLAGS_buildversion ]]; then + logecho "--buildversion= required for 'release' jobs." + return 1 + fi + + submit_it +} + +stage_it () { + if [[ -z $RELEASE_BRANCH ]]; then + logecho "Branch not set. Can't continue" + return 1 + fi + + # Get kube_cross version + KUBE_CROSS_VERSION=$(curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/$RELEASE_BRANCH/build/build-image/cross/VERSION) + + [[ -z $KUBE_CROSS_VERSION ]] \ + && common::exit 1 "Unable to set KUBE_CROSS_VERSION. Exiting..." + + # Submit it + submit_it +} + + +############################################################################### +# MAIN +############################################################################### +############################################################################## +# Initialize logs +############################################################################## +# Initialize and save up to 10 (rotated logs) +MYLOG=$TMPDIR/$PROG.log +common::logfileinit $MYLOG 10 +# BEGIN script +common::timestamp begin + +gitlib::repo_state || common::exit 1 "Exiting..." + +# Ensure some prerequisites +if ! common::set_cloud_binaries; then + logecho "Releasing Kubernetes requires gsutil and gcloud. Please download," + logecho "install and authorize through the Google Cloud SDK:" + logecho + logecho "https://developers.google.com/cloud/sdk/" + common::exit 1 "Exiting..." +fi +common::check_packages jq || common::exit 1 "Exiting..." + +logecho + +# Defaults to "list" operation +COMMAND=${POSITIONAL_ARGV[0]:-"list"} +ARG2=${POSITIONAL_ARGV[1]} +PROJECT="kubernetes-release-test" +# Append $PROJECT to GCLOUD +GCLOUD+=" --project $PROJECT" +BUCKET="kubernetes-release" +# disk size must take base image into consideration. +# The amount specified is not what is "free" +DISK_SIZE="150" +GCP_USER=$($GCLOUD auth list --filter=status:ACTIVE --format="value(account)") +# This is used as a tag so convert @ to -at- (for yaml tag field +# where @ is invalid) +# First, for @google.com users strip off the @domain.tld +# If non-google.com, convert @ to -at- +GCP_USER_TAG=${GCP_USER%%@google.com} +GCP_USER_TAG=${GCP_USER_TAG/@/-at-} +# GCP also doesn't like anything even remotely looking like a domain name +# in the bucket name so convert . to - +GCP_USER_TAG=${GCP_USER_TAG/\./-} + +if ((FLAGS_official)); then + OFFICIAL_TAG="official" + OFFICIAL="--$OFFICIAL_TAG" + DISK_SIZE="250" +fi + +if ((FLAGS_build_at_head)); then + BUILD_POINT="HEAD" + BUILD_AT_HEAD="--build-at-head" +fi + +if ((FLAGS_nomock)); then + NOMOCK_TAG="nomock" + NOMOCK="--$NOMOCK_TAG" +else + USER_BUCKET=$BUCKET-$GCP_USER_TAG + BUCKET+="-gcb" +fi + +# BUILD_POINT used in yaml tags field and is one of: +# * HEAD (from --build-at-head) +# * Value of FLAGS_buildversion +# * Defaulting to searching for a build using find_green_build +# +if [[ -n $FLAGS_buildversion ]]; then + BUILD_POINT=$FLAGS_buildversion + BUILDVERSION="--buildversion=${FLAGS_buildversion/+/-}" +else + BUILD_POINT=${BUILD_POINT:-"find_green_build"} +fi + +# TODO: Add a check here that user is allowed to submit jobs to $PROJECT +# Respond with guidance on how to get on board + +case $COMMAND in + list) list_jobs $ARG2 + common::exit 0 + ;; + staged) list_staged_builds + common::exit 0 + ;; + stream|tail) stream_job_log $ARG2 + common::exit 0 + ;; + stage) YAML_FILE="$TOOL_ROOT/gcb/stage.yaml" + RELEASE_BRANCH="$ARG2" + stage_it + ;; + release) if ((FLAGS_nomock)); then + logecho + logecho "$ATTENTION!!" + if ! Askyorn "Are you sure you want to submit an actual release job against the $RELEASE_BRANCH branch"; then + common::exit 1 "Exiting..." + fi + fi + + DISK_SIZE="100" + YAML_FILE="$TOOL_ROOT/gcb/release.yaml" + RELEASE_BRANCH="$ARG2" + release_it + ;; + *) common::exit 1 "Unknown option $COMMAND. Exiting..." + ;; +esac || common::exit 1 "Exiting..." + +# END script +common::timestamp end diff --git a/lib/common.sh b/lib/common.sh index 53c05a7ab41..3a7222d4519 100755 --- a/lib/common.sh +++ b/lib/common.sh @@ -24,9 +24,11 @@ export PROG set -o errtrace -# TODO: -# - Figure out a way to share common bits with other Kubernetes sub repos -# - cleanup / function headers +# OSX not supported. Tell them right away +if [[ $(uname) == "Darwin" ]]; then + echo "OSX is not a supported OS for running these tools. Exiting..." + exit 1 +fi ############################################################################## # COMMON CONSTANTS diff --git a/lib/gitlib.sh b/lib/gitlib.sh index d780b13a1bf..56d2a9b5e0e 100644 --- a/lib/gitlib.sh +++ b/lib/gitlib.sh @@ -20,22 +20,16 @@ ############################################################################### # CONSTANTS ############################################################################### -# TODO: This needs to be pulled into .netrc or some other more secure location -# Any contributor could by accident or on purpose change the yaml or this script -# directly to "set -x" in which case, the TOKEN would be readable in the -# GCB logs -# netrc with git doesn't seem to work, but a combination approach with -# netrc for curl and git remotes with embedded tokens might be an answer -# the files themselves in the container don't need to be encrypted necessarily -# as noone has access to those, but we can't expose this via the env : ${GITHUB_TOKEN:=$FLAGS_github_token} -GHCURL="curl -s --fail --retry 10 -u $GITHUB_TOKEN:x-oauth-basic" +[[ -n $GITHUB_TOKEN ]] && GITHUB_TOKEN_FLAG=("-u" "$GITHUB_TOKEN:x-oauth-basic") +GHCURL="curl -s --fail --retry 10 ${GITHUB_TOKEN_FLAG[*]}" JCURL="curl -g -s --fail --retry 10" K8S_GITHUB_API_ROOT='https://api.github.com/repos' K8S_GITHUB_API="$K8S_GITHUB_API_ROOT/kubernetes/kubernetes" K8S_GITHUB_RAW_ORG='https://raw.githubusercontent.com/kubernetes' -K8S_GITHUB_SEARCHAPI='https://api.github.com/search/issues?per_page=100&q=is:pr%20repo:kubernetes/kubernetes%20' +K8S_GITHUB_SEARCHAPI_ROOT='https://api.github.com/search/issues?per_page=100' +K8S_GITHUB_SEARCHAPI="$K8S_GITHUB_SEARCHAPI_ROOT&q=is:pr%20repo:kubernetes/kubernetes%20" K8S_GITHUB_URL='https://github.com/kubernetes/kubernetes' if ((FLAGS_gcb)); then K8S_GITHUB_AUTH_ROOT="https://git@github.com/" @@ -315,14 +309,16 @@ fi ############################################################################### # Search for a matching release tracking issue -# @param version RELEASE_VERSION_PRIME +# @param version - RELEASE_VERSION_PRIME +# @param repo - org/repo # returns 1 if none found -# prints most recent issue maching +# prints most recent open issue maching gitlib::search_release_issue () { local version=$1 + local repo=$2 local issue - issue=$($GHCURL $K8S_GITHUB_SEARCHAPI_ROOT&q=Release+$version+Tracking+in:title+type:issue+state:open+repo:$RELEASE_TRACKING_REPO | jq -r '.items[] | (.number | tostring)' |sort -n |tail -1) + issue=$($GHCURL "$K8S_GITHUB_SEARCHAPI_ROOT&q=Release+$version+Tracking+in:title+type:issue+state:open+repo:$repo" | jq -r '.items[] | (.number | tostring)' |sort -n |tail -1) [[ -z $issue ]] && return 1 @@ -330,14 +326,14 @@ gitlib::search_release_issue () { } ############################################################################### -# Create a release tracking issue for posting notifications. +# Create/update a release tracking issue for posting notifications. # Mostly for use by --gcb since there's no other email mechanism from which # to send detailed html notifictions. # @param version RELEASE_VERSION_PRIME -PROGSTEP[create_release_issue]="CREATE/UPDATE RELEASE TRACKING ISSUE" -gitlib::create_release_issue () { +PROGSTEP[gitlib::update_release_issue]="CREATE/UPDATE RELEASE TRACKING ISSUE" +gitlib::update_release_issue () { local version=$1 - local assignee="david-mcmahon" + local assignee local milestone local stage local text @@ -353,58 +349,52 @@ gitlib::create_release_issue () { if ((FLAGS_nomock)); then repo="kubernetes/sig-release" - # Let the cc below build the guide - assignee="null" # Would be nice to have a broad distribution list here on par with email # distributions - cc="@kubernetes/sig-release-members" + cc="cc @kubernetes/sig-release-members" else - logecho "No PR created for mock runs..." - return 0 - # Need a real mock repo to update issues in - # Also this might have to be a global if we end up using - # comment_release_issue() and search_release_issue() - repo="david-mcmahon/release" + repo="k8s-release-robot/sig-release" # Force milestone to null on this repo or the curl hangs milestone="null" fi - text="Kubernetes $version has been built and pushed.\n\nThe release notes have been updated in $CHANGELOG_FILE with a pointer to it on github" - - # If the milestone doesn't exist, this will fail. - # May want to check that and only add if there's a valid value to add, Ugh. - issue_number=$($GHCURL $K8S_GITHUB_API_ROOT/$repo/issues --data \ - "{ - \"title\": \"Release $version Tracking\", - \"body\": \"$text\ncc $cc\n\", - \"assignee\": \"$assignee\", - \"milestone\": $milestone, - \"labels\": [ - \"sig-release\", - \"stage/${stage:-stable}\" - ] - }" |jq -r '.number') - - if [[ -n $issue_number ]]; then - logecho "Created issue #$issue_number on github:" - logecho "http://github.com/$repo/issues/$issue_number" + text="Kubernetes $version has been built and pushed.\n\nThe release notes have been updated in $CHANGELOG_FILE with a pointer to it on github." + + # Search for an existing OPEN issue + logecho -n "Searching for an existing release tracking issue: " + if issue_number=$(gitlib::search_release_issue $version $repo); then + logecho "$issue_number" + logecho -n "Updating issue $issue_number: " + # Add a comment + if $GHCURL $K8S_GITHUB_API_ROOT/$repo/issues/$issue_number/comments \ + --data "{ \"body\": \"$text\n$cc\n\" }"; then + logecho $OK + else + logecho $FAILED + return 1 + fi else - logecho "There was a problem creating the release tracking issue" - logecho "This should be done manually." + logecho "NONE" + # Create a new issue + # If the milestone doesn't exist, this will fail. + # May want to check that and only add if there's a valid value to add, Ugh. + issue_number=$($GHCURL $K8S_GITHUB_API_ROOT/$repo/issues --data \ + "{ + \"title\": \"Release $version Tracking\", + \"body\": \"$text\n$cc\n\", + \"milestone\": $milestone, + \"labels\": [ + \"sig/release\", + \"stage/${stage:-stable}\" + ] + }" |jq -r '.number') + + if [[ -n $issue_number ]]; then + logecho "Created issue #$issue_number on github:" + logecho "http://github.com/$repo/issues/$issue_number" + else + logecho "There was a problem creating the release tracking issue" + logecho "This should be done manually." + fi fi } - -############################################################################### -# Create a release tracking issue for posting notifications. -# Mostly for use by --gcb since there's no other email mechanism from which -# to send detailed html notifictions. -gitlib::comment_release_issue () { - local issue=$1 - - $GHCURL $K8S_GITHUB_API_ROOT/$RELEASE_TRACKING_REPO/issues/$issue/comments \ - --data \ - "{ - \"body\": \"$(awk '{printf "%s\\n", $0}' $HOME/look/release-notes.md)\" - }" -} - diff --git a/lib/releaselib.sh b/lib/releaselib.sh index 78a02894627..e454dd988b0 100644 --- a/lib/releaselib.sh +++ b/lib/releaselib.sh @@ -686,7 +686,7 @@ release::gcs::publish_version () { [[ "$version" =~ alpha|beta|rc ]] || type="stable" fi - if ! $GSUTIL ls $release_dir >/dev/null 2>&1 ; then + if ! logrun $GSUTIL ls $release_dir; then logecho "Release files don't exist at $release_dir" return 1 fi @@ -948,8 +948,9 @@ release::docker::release () { done fi - # Always reset back to ${USER_AT_DOMAIN:-$USER@$DOMAIN_NAME} - logrun $GCLOUD config set account "${USER_AT_DOMAIN:-$USER@$DOMAIN_NAME}" + # Always reset back to $GCP_USER + # This is set in push-build.sh and anago + ((FLAGS_gcb)) || logrun $GCLOUD config set account $GCP_USER return $ret } @@ -1007,7 +1008,7 @@ release::docker::release_from_tarfiles () { docker tag $orig_tag $new_tag logecho -n "Pushing $new_tag: " # 'gcloud docker' gives lots of internal_failure's so add retries - logrun -r 5 -s ${docker_push_cmd[@]} push "$new_tag" + logrun -r 5 -s ${docker_push_cmd[@]} push "$new_tag" || return 1 done docker rmi $orig_tag ${new_tags[@]} &>/dev/null || true diff --git a/push-build.sh b/push-build.sh index 65e491788de..cfdbb574aa9 100755 --- a/push-build.sh +++ b/push-build.sh @@ -23,7 +23,7 @@ PROG=${0##*/} #+ #+ SYNOPSIS #+ $PROG [--nomock] [--federation] [--noupdatelatest] [--ci] -#+ [--bucket=] [--domain-name=domain.tld] +#+ [--bucket=] #+ [--private-bucket] #+ $PROG [--helpshort|--usage|-?] #+ $PROG [--help|-man] @@ -54,7 +54,6 @@ PROG=${0##*/} #+ values are kubernetes(default) or federation. #+ [--gcs-suffix=] - Specify a suffix to append to the upload #+ destination on GCS. -#+ [--domain-name=] - Specify an alternate domain.tld #+ [--docker-registry=] - If set, push docker images to specified #+ registry/project #+ [--version-suffix=] - Append suffix to version name if set. @@ -106,7 +105,6 @@ common::timestamp begin # MAIN ############################################################################### RELEASE_BUCKET=${FLAGS_bucket:-"kubernetes-release-dev"} -DOMAIN_NAME=${FLAGS_domain_name:-"google.com"} # Compatibility with incoming global args [[ $KUBE_GCS_UPDATE_LATEST == "n" ]] && FLAGS_noupdatelatest=1 @@ -172,6 +170,12 @@ if ! common::set_cloud_binaries; then common::exit 1 fi +# Nothing should work without this. The entire release workflow depends +# on it whether running from the desktop or GCB +GCP_USER=$($GCLOUD auth list --filter=status:ACTIVE \ + --format="value(account)" 2>/dev/null) +[[ -n "$GCP_USER" ]] || common::exit 1 "Unable to set a valid GCP credential!" + logecho -n "Check/make release bucket $RELEASE_BUCKET: " logrun -s release::gcs::ensure_release_bucket $RELEASE_BUCKET || common::exit 1