diff --git a/.github/workflows/charm-analysis.yaml b/.github/workflows/charm-analysis.yaml index 7c2a732c..75961f9c 100644 --- a/.github/workflows/charm-analysis.yaml +++ b/.github/workflows/charm-analysis.yaml @@ -9,4 +9,5 @@ jobs: uses: canonical/operator-workflows/.github/workflows/test.yaml@main secrets: inherit with: + docs-working-directory: charms self-hosted-runner: false diff --git a/.github/workflows/promote-charms.yaml b/.github/workflows/promote-charms.yaml new file mode 100644 index 00000000..db260ca8 --- /dev/null +++ b/.github/workflows/promote-charms.yaml @@ -0,0 +1,72 @@ +name: Promote charms + +on: + workflow_dispatch: + inputs: + charm: + type: choice + description: 'Charm' + options: + - all + - k8s + - k8s-worker + origin-risk: + type: choice + description: 'Origin Channel' + options: + - edge + - beta + - candidate + destination-risk: + type: choice + description: 'Destination Channel' + options: + - stable + +jobs: + configure-track: + runs-on: ubuntu-latest + outputs: + track: ${{ steps.channel.outputs.track }} + steps: + - name: Determine Channel + id: channel + env: + BRANCH: ${{ github.base_ref || github.ref }} + run: | + BRANCH=${BRANCH#refs/heads/} # strip off refs/heads/ if it exists + if [[ "${BRANCH}" == "main" ]]; then + echo "track=latest" >> "$GITHUB_OUTPUT" + elif [[ "${BRANCH}" =~ "^release-[0-9]+\.[0-9]+$" ]]; then + echo "track=${BRANCH:8}" >> "$GITHUB_OUTPUT" + echo "Promote from $track/${{github.event.inputs.origin-risk}} to $track/${{github.event.inputs.destination-risk}}" + select-charms: + runs-on: ubuntu-latest + outputs: + charms: ${{ steps.charms.outputs.charms }} + steps: + - name: Determine Charms + id: charms + env: + CHOICE: ${{ github.event.inputs.charm }} + run: | + echo "Determines which charms were chosen from $CHOICE" + if [[ "${CHOICE}" == "all" ]]; then + echo "charms=[\"charms/worker\", \"charms/worker/k8s\"]" >> "$GITHUB_OUTPUT" + elif [[ "${CHOICE}" == "k8s" ]]; then + echo "charms=[\"charms/worker/k8s\"]" >> "$GITHUB_OUTPUT" + else + echo "charms=[\"charms/worker\"]" >> "$GITHUB_OUTPUT" + fi + promote-charm: + needs: [configure-track, select-charms] + strategy: + matrix: + charm-directory: ${{ fromJson(needs.select-charms.outputs.charms) }} + uses: canonical/operator-workflows/.github/workflows/promote_charm.yaml@main + with: + origin-channel: ${{needs.configure-track.outputs.track}}/${{ github.event.inputs.origin-risk }} + destination-channel: ${{needs.configure-track.outputs.track}}/${{ github.event.inputs.destination-risk }} + docs-working-directory: ./charms + working-directory: ${{ matrix.charm-directory }} + secrets: inherit diff --git a/.github/workflows/promote_charm.yaml b/.github/workflows/promote_charm.yaml deleted file mode 100644 index 66649de9..00000000 --- a/.github/workflows/promote_charm.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Promote charm - -on: - workflow_dispatch: - inputs: - origin-channel: - type: choice - description: 'Origin Channel' - options: - - latest/edge - destination-channel: - type: choice - description: 'Destination Channel' - options: - - latest/stable - secrets: - CHARMHUB_TOKEN: - required: true - -jobs: - promote-charm: - uses: canonical/operator-workflows/.github/workflows/promote_charm.yaml@main - with: - origin-channel: ${{ github.event.inputs.origin-channel }} - destination-channel: ${{ github.event.inputs.destination-channel }} - secrets: inherit diff --git a/.github/workflows/publish-charms.yaml b/.github/workflows/publish-charms.yaml new file mode 100644 index 00000000..5d53bdac --- /dev/null +++ b/.github/workflows/publish-charms.yaml @@ -0,0 +1,40 @@ +name: Publish Charms to 1.xx/edge + +on: + workflow_dispatch: + push: + branches: + - main + - release-* + +jobs: + configure-channel: + runs-on: ubuntu-latest + outputs: + track: ${{ steps.channel.outputs.track }} + risk: ${{ steps.channel.outputs.risk }} + steps: + - name: Determine Channel + id: channel + env: + BRANCH: ${{ github.base_ref || github.ref }} + run: | + BRANCH=${BRANCH#refs/heads/} # strip off refs/heads/ if it exists + if [[ "${BRANCH}" == "main" ]]; then + echo "track=latest" >> "$GITHUB_OUTPUT" + echo "risk=edge" >> "$GITHUB_OUTPUT" + elif [[ "${BRANCH}" =~ "^release-[0-9]+\.[0-9]+$" ]]; then + echo "track=${BRANCH:8}" >> "$GITHUB_OUTPUT" + echo "risk=beta" >> "$GITHUB_OUTPUT" + fi + publish-to-edge: + needs: [configure-channel] + uses: canonical/operator-workflows/.github/workflows/publish_charm.yaml@main + strategy: + matrix: + charm-directory: ["./charms/worker/", "./charms/worker/k8s/"] + secrets: inherit + with: + channel: ${{needs.configure-channel.outputs.track}}/${{needs.configure-channel.outputs.risk}} + working-directory: ${{ matrix.charm-directory }} + tag-prefix: k8s diff --git a/.github/workflows/publish-k8s-worker.yaml b/.github/workflows/publish-k8s-worker.yaml deleted file mode 100644 index 7e043a78..00000000 --- a/.github/workflows/publish-k8s-worker.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: Publish K8s-worker to edge - -on: - workflow_dispatch: - push: - branches: - - main - -jobs: - publish-to-edge: - uses: canonical/operator-workflows/.github/workflows/publish_charm.yaml@main - secrets: inherit - with: - channel: latest/edge - working-directory: ./charms/worker/ - tag-prefix: k8s-worker \ No newline at end of file diff --git a/.github/workflows/publish-k8s.yaml b/.github/workflows/publish-k8s.yaml deleted file mode 100644 index ada710db..00000000 --- a/.github/workflows/publish-k8s.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: Publish K8s to edge - -on: - workflow_dispatch: - push: - branches: - - main - -jobs: - publish-to-edge: - uses: canonical/operator-workflows/.github/workflows/publish_charm.yaml@main - secrets: inherit - with: - channel: latest/edge - working-directory: ./charms/worker/k8s/ - tag-prefix: k8s \ No newline at end of file diff --git a/docs/releases/stable/create-branch-dialog.png b/docs/releases/stable/create-branch-dialog.png new file mode 100644 index 00000000..728217e9 Binary files /dev/null and b/docs/releases/stable/create-branch-dialog.png differ diff --git a/docs/releases/stable/index.md b/docs/releases/stable/index.md new file mode 100644 index 00000000..416304df --- /dev/null +++ b/docs/releases/stable/index.md @@ -0,0 +1,192 @@ +# Creating a stable release +This document outlines the process for publishing a Canonical Kubernetes stable release. + +## Background + +### Repository Branching +This repositories used by Canonical Kubernetes has a branch scheme to provide a +consistent release experience. Any external or shared repositories are forked +into the `charmed-kubernetes` github organization and have the following branches: + +* `main`: The primary development branch. Merges are made against this branch as they are approved. +* `release_1.xx`: The release branch. New major releases are branched from `main`. +* `release_1.xx`. Bugfix releases have specific commits PR'd to `release_1.xx` from a `bugfix_1.xx_` branch. + +Tags are used to mark releases on the `release_1.xx` branch. + +### Feature Freeze + +In the weeks prior to a stable release the team goes into a feature freeze. At this +time only bugfixes and concentration on resolving any other outstanding issues +will take place for the first week of this freeze. + +The remaining tasks will still be completed at the time of feature freeze giving +Solutions QA a solid base to test from. + +### Conflict resolution + +At the time of the feature freeze, new `release_1.xx` branches are created to match +the default repo branch per the documentation below. During the feature freeze and +Solutions QA period, fixes which need to be applied to address CI or QA failures +(and only those specific fixes) are merged to the respective release branches. + +## Prepare CI + +### $stable++ release + +It may feel early, but part of releasing the next stable version requires +preparing for the release that will follow. This requires opening tracks and +building relevant snaps and charms that will be used in the new `edge` channel. + +Bundle/charm track requests are made by posting to the `charmhub requests` forum +asking for new tracks to be opened for `k8s` and `k8s-worker` charms. For example: + +- https://discourse.charmhub.io/t/request-new-1-30-track-for-all-charmed-k8s-charms-and-bundles/13394 + +ensuring to tag the request with `k8s`, `k8s-worker`, and `canonical-kubernetes` + +## Preparing the release + +### Create release branches for this repo + +* **URL**: https://github.com/canonical/k8s-operator/branches +* **New Branch**: release_1.XX +* **source**: main + +We need to create a `release_1.xx` branch from `main`. +This will be our snapshot from which we test, fix, and subsequently +promote to the new release. + +![Create Branch Dialog](create-branch-dialog.png) + +### Pin snap channel in the release branches + +We need to make sure that the charms have `1.xx/` set as the default snap channel. + +Task: +```sh +git switch release_1.xx +git checkout -b task/snap-risk/release-1.xx/ +# edit the config.options.channel.default = "1.xx/" +edit charms/worker/k8s/charmcraft.yaml +edit charms/worker/charmcraft.yaml +``` + +Where `risk` represents the channel the most stable available risk of the snap. + +For example) `1.30-classic/beta` is the most stable shown below +```sh +⚡ snap info k8s | grep 1.30 + 1.30-classic/stable: -- + 1.30-classic/candidate: -- + 1.30-classic/beta: v1.30.0-beta.0 2024-03-13 (140) 107MB classic + 1.30-classic/edge: ^ +``` + +Commit, and raise a new PR into the `release_1.xx` + +### Pin pip versions of all python dependencies +In order to reproduce charm builds, we should pin the python dependencies of at least +the charm code. The pinning should take place using a specific version of python +in order to ensure compatibility with the base os release. One can use `pyenv` to help +create python environments locally to help freeze the requirements.txt + +| base | python | +| --- | --- | +| ubuntu@20.04 (**focal**) | 3.8 | +| ubuntu@22.04 (**jammy**) | 3.10 | +| ubuntu@24.04 (**noble**) | 3.12 | + +Choose the environment based build-on base in `charms/worker/k8s/charmcraft.yaml` + +In the following example, building on focal yields packages for python 3.8. +```yaml + - build-on: + - name: ubuntu + channel: "20.04" + architectures: [amd64] +``` + +Create a python 3.8 environment, and freeze the libraries. +Then create a PR to merge into the release branch. + +Task: +```sh +pyenv install 3.8 +pyenv virtualenv 3.8 k8s-operator +pyenv activate k8s-operator +git switch release_1.xx +git checkout -b task/pip-pinning/release-1.xx +pip install -r charms/worker/k8s/requirements.txt +pip freeze > charms/worker/k8s/requirements.txt +``` + +### Build charms from the release branches + +Raising a PR, passing the integration tests, and merging into the release +branch should publish the charm to the upstream `1.xx/beta` channel. + +## Internal verification + +### Run **validate-k8s-release-upgrade** job + +**Job**: https://jenkins.canonical.com/k8s-ps5/job/validate-k8s-release-upgrade/ + +This validates the deployment using charms from the `$prev/stable` channel, +then performing an upgrade to `1.xx/beta`. The tests are parameterized to +run on: +* multiple series +* multiple architectures +* multiple clouds (aws/azure/gcp/vsphere) + +### Notify Solutions QA + +At the end of the first week and assuming all major blockers are resolved, the +release is passed over to Solutions QA (SQA) for sign-off. This is done by +[publishing a CI release](https://github.com/charmed-kubernetes/jenkins/releases/new) +with a new `1.xx` tag and informing SQA of that tag. The SQA team will have the +remaining week to test and file bugs so engineering can work towards getting +them resolved prior to stable release. + +### CNCF Conformance + +**Job**: https://jenkins.canonical.com/k8s-ps5/job/conformance-cncf-k8s/ + +Sync `canonical/k8s-conformance` main from upstream. + +- https://github.com/canonical/k8s-conformance + +Confirm passing results, then create a PR against the upstream `k8s-conformance` +repo. + +Next, open an upstream PR: + +- https://github.com/cncf/k8s-conformance/pull/XXXXX + +> **Note**: CNCF requires a sign-off. After confirming results, issue a +`git commit --amend --signoff` on the branch prior to submitting the PR. + +## Performing the release + +### Document release notes + +- Bugfixes +- Enhancements +- Known Limitations/Issues + +### Promote charms to stable +**Job**: https://github.com/canonical/k8s-operator/actions/workflows/promote_charm.yaml + +Run the workflow from a branch, select `release_1.xx`, +* Choose `Charm` - `all` +* Choose `Origin Channel`- `beta` +* Choose `Destination Channel` - `stable` + +![promote charm options](promote-charm.png) + +### Send announcement + +Email announcement to k8s-crew with any relevant information. + + +# Fin \ No newline at end of file diff --git a/docs/releases/stable/promote-charm.png b/docs/releases/stable/promote-charm.png new file mode 100644 index 00000000..1d69696c Binary files /dev/null and b/docs/releases/stable/promote-charm.png differ