From 09f15182106bc4bb427022e257dbcef58aab123d Mon Sep 17 00:00:00 2001 From: Adam Rozman Date: Fri, 31 Jan 2025 12:39:41 +0200 Subject: [PATCH] move keepalived here from BMO repo This commit: - Moves the project used to build the Metal3 keepalived container from the BMO repository to this repository - Adds support for customizable config file location for the keepalived container - Adds container building github workflow for keepalived - Adds keepalived release workflow - Adds release document for the whole of the utility-images repository These changes were needed for two related reasons. - The community has decided that there is no reason to keep the keepalived files in BMO and they much better fit for the utility-images repository. - There is ongoing work to turn the ironic pod compatible with the K8s pod security option that enforces the use of read only mode for the container file system and the current containers deployed as part of the Ironic pod such as keepalived are not compatible without modification. Note: release workflows and documentation is a new concept for this repository and a bit differ from other Metal3 repos because different projects within the repo get released independently. Signed-off-by: Adam Rozman --- .github/workflows/build-images-action.yml | 12 ++ .github/workflows/keepalived-release.yaml | 138 +++++++++++++++++++ README.md | 18 +++ RELEASING.md | 157 ++++++++++++++++++++++ keepalived/Dockerfile | 16 +++ keepalived/configure-nonroot.sh | 20 +++ keepalived/manage-keepalived.sh | 22 +++ keepalived/sample.keepalived.conf | 20 +++ 8 files changed, 403 insertions(+) create mode 100644 .github/workflows/keepalived-release.yaml create mode 100644 RELEASING.md create mode 100644 keepalived/Dockerfile create mode 100755 keepalived/configure-nonroot.sh create mode 100644 keepalived/manage-keepalived.sh create mode 100644 keepalived/sample.keepalived.conf diff --git a/.github/workflows/build-images-action.yml b/.github/workflows/build-images-action.yml index 4408e8b..dd2e656 100644 --- a/.github/workflows/build-images-action.yml +++ b/.github/workflows/build-images-action.yml @@ -33,3 +33,15 @@ jobs: QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + build_keepalived: + name: Build keepalived container image + if: github.repository == 'metal3-io/utility-images' + uses: metal3-io/project-infra/.github/workflows/container-image-build.yml@main + with: + image-name: 'keepalived' + dockerfile-directory: keepalived + pushImage: true + secrets: + QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} + QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/keepalived-release.yaml b/.github/workflows/keepalived-release.yaml new file mode 100644 index 0000000..33e87f4 --- /dev/null +++ b/.github/workflows/keepalived-release.yaml @@ -0,0 +1,138 @@ +# This code is borrowed from https://github.com/kubernetes-sigs/cluster-api/blob/main/.github/workflows/release.yaml +name: Create Release + +on: + push: + branches: + - main + paths: + - 'keepalived/releasenotes/*.md' + +permissions: {} + +jobs: + push_release_tags: + permissions: + contents: write + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.release-version.outputs.release_version }} + if: github.repository == 'metal3-io/utility-images' + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@bab30c2299617f6615ec02a68b9a40d10bd21366 # tag=v45.0.5 + - name: Get release version + id: release-version + run: | + if [[ ${{ steps.changed-files.outputs.all_changed_files_count }} != 1 ]]; then + echo "1 release notes file should be changed to create a release tag, found ${{ steps.changed-files.outputs.all_changed_files_count }}" + exit 1 + fi + for changed_file in ${{ steps.changed-files.outputs.all_changed_files }}; do + export RELEASE_VERSION=$(echo "${changed_file}" | grep -oP '(?<=/)[^/]+(?=\.md)') + echo "RELEASE_VERSION=${RELEASE_VERSION}" >> ${GITHUB_ENV} + echo "RELEASE_VERSION=${RELEASE_VERSION}" >> ${GITHUB_OUTPUT} + if [[ "${RELEASE_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then + echo "Valid semver: ${RELEASE_VERSION}" + else + echo "Invalid semver: ${RELEASE_VERSION}" + exit 1 + fi + done + - name: Determine the release branch to use + run: | + if [[ ${RELEASE_VERSION} =~ beta ]] || [[ ${RELEASE_VERSION} =~ alpha ]]; then + export RELEASE_BRANCH=main + echo "RELEASE_BRANCH=${RELEASE_BRANCH}" >> ${GITHUB_ENV} + echo "This is a beta or alpha release, will use release branch ${RELEASE_BRANCH}" + else + export RELEASE_BRANCH=release-$(echo ${RELEASE_VERSION} | sed -E 's/^v([0-9]+)\.([0-9]+)\..*$/\1.\2/') + echo "RELEASE_BRANCH=${RELEASE_BRANCH}" >> ${GITHUB_ENV} + echo "This is not a beta or alpha release, will use release branch ${RELEASE_BRANCH}" + fi + - name: Create or checkout release branch + run: | + if git show-ref --verify --quiet "refs/remotes/origin/${RELEASE_BRANCH}"; then + echo "Branch ${RELEASE_BRANCH} already exists" + git checkout "${RELEASE_BRANCH}" + else + git checkout -b "${RELEASE_BRANCH}" + git push origin "${RELEASE_BRANCH}" + echo "Created branch ${RELEASE_BRANCH}" + fi + - name: Validate tag does not already exist + run: | + if [[ -n "$(git tag -l "${RELEASE_VERSION}")" ]]; then + echo "Tag ${RELEASE_VERSION} already exists, exiting" + exit 1 + fi + - name: Create Release Tag + run: | + git config user.name "${GITHUB_ACTOR}" + git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" + git tag -a ${RELEASE_VERSION} -m ${RELEASE_VERSION} + git tag apis/${RELEASE_VERSION} + git tag test/${RELEASE_VERSION} + git tag pkg/hardwareutils/${RELEASE_VERSION} + git push origin ${RELEASE_VERSION} + git push origin apis/${RELEASE_VERSION} + git push origin test/${RELEASE_VERSION} + git push origin pkg/hardwareutils/${RELEASE_VERSION} + echo "Created tags ${RELEASE_VERSION}, apis/${RELEASE_VERSION}, pkg/hardwareutils/${RELEASE_VERSION}, and test/${RELEASE_VERSION}" + release: + name: create draft release + runs-on: ubuntu-latest + needs: push_release_tags + permissions: + contents: write + steps: + - name: Set env + run: echo "RELEASE_TAG=${RELEASE_TAG}" >> ${GITHUB_ENV} + env: + RELEASE_TAG: ${{needs.push_release_tags.outputs.release_tag}} + - name: checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + ref: ${{ env.RELEASE_TAG }} + - name: Calculate go version + run: echo "go_version=$(make go-version)" >> ${GITHUB_ENV} + - name: Set up Go + uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 + with: + go-version: ${{ env.go_version }} + - name: generate release artifacts + run: | + make release + - name: get release notes + run: | + curl -L "https://raw.githubusercontent.com/${{ github.repository }}/main/releasenotes/${{ env.RELEASE_TAG }}.md" \ + -o "${{ env.RELEASE_TAG }}.md" + - name: Release + uses: softprops/action-gh-release@7b4da11513bf3f43f9999e90eabced41ab8bb048 # v2.2.0 + with: + draft: true + files: out/* + body_path: ${{ env.RELEASE_TAG }}.md + tag_name: ${{ env.RELEASE_TAG }} + build_keepalived: + permissions: + contents: read + needs: push_release_tags + name: Build keepalived container image + if: github.repository == 'metal3-io/utility-images' + uses: metal3-io/project-infra/.github/workflows/container-image-build.yml@main + with: + image-name: 'keepalived' + dockerfile-directory: keepalived + pushImage: true + ref: ${{ needs.push_release_tags.outputs.release_tag }} + secrets: + QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }} + QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }} + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/README.md b/README.md index bc1b7ac..60ed287 100644 --- a/README.md +++ b/README.md @@ -74,3 +74,21 @@ FakeIPA simulate the IPA by: a queue of fake agents. - Faking the sync/async commands needed by ironic to inspect, clean and provision a node. + +## Keepalived + +Keepalived container used in Ironic deployments. Keepalived is used to +provide fix IP address for Ironic in such a manner that even after pivoting +operations the IP of Ironic stays persistent. + +[Keeplaived documentation](https://www.keepalived.org/manpage.html) + +Deployment configuration options: + +- `CUSTOM_CONF_DIR` - when specified, the config files will be moved to the + specified directory and the variable substitution will happen there +- `PROVISIONING_IP` - the fix IP provided by keepalived +- `PROVISIONING_INTERFACE` - The name of the interface that will be used + to "host" the fixed IP (keepalived is used in a pod that is attached to + host network, thus the interface names are the same as the interface names + on the host) diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..ba9a4ed --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,157 @@ +# Releasing from from the utility-images repository + +This document details the steps to create a release for a project in the +reporitory. + +## Before making a release + +Things you should check before making a release: + +- Always check if there are project specific release instructions in + the project specific directory. +- Always check if there is a project specific verify-release.sh script in the + project's directory and if present run it and fix all issues highlighted + by the script prior to the release. + +## Permissions + +Creating a release requires repository `write` permissions for: + +- Tag pushing +- Branch creation +- GitHub Release publishing + +These permissions are implicit for the org admins and repository admins. Release +team member gets his/her permissions via `metal3-release-team` membership. This +GitHub team has the required permissions in each repository required to release +BMO. Adding person to the team gives him/her the necessary rights in all +relevant repositories in the organization. Individual persons should not be +given permissions directly. + +## Process + +BMO uses [semantic versioning](https://semver.org). + +- Regular releases: `v0.x.y` +- Beta releases: `v0.x.y-beta.z` +- Release candidate releases: `v0.x.y-rc.z` + +### Repository setup + +Clone the repository: `git clone git@github.com:metal3-io/utility-images` + +or if using existing repository, make sure origin is set to the fork and +upstream is set to `metal3-io`. Verify if your remote is set properly or not +by using following command `git remote -v`. + +- Fetch the remote (`metal3-io`): `git fetch upstream` +This makes sure that all the tags are accessible. + +### Creating Release Notes + +- Switch to the main branch: `git checkout main` + +- Create a new branch for the release notes**: + `git checkout -b release-notes-1.x.x origin/main` + +- Generate the release notes: `RELEASE_TAG=v1.x.x make release-notes` + - Replace `v1.x.x` with the new release tag you're creating. + - This command generates the release notes here + `releasenotes/.md` . + +- Next step is to clean up the release note manually. + - If release is not a beta or release candidate, check for duplicates, + reverts, and incorrect classifications of PRs, and whatever release + creation tagged to be manually checked. + - For any superseded PRs (like same dependency uplifted multiple times, or + commit revertion) that provide no value to the release, move them to + Superseded section. This way the changes are acknowledged to be part of the + release, but not overwhelming the important changes contained by the + release. + +- Commit your changes, push the new branch and create a pull request: + - The commit and PR title should be 🚀 Release v1.x.y: + -`git commit -S -s -m ":rocket: Release v1.x.x"` + -`git push -u origin release-notes-1.x.x` + - Important! The commit should only contain the release notes file, nothing + else, otherwise automation will not work. + +- Ask maintainers and release team members to review your pull request. + +Once PR is merged following GitHub actions are triggered: + +- GitHub action `Create Release` runs following jobs: + - GitHub job `push_release_tags` will create and push the tags. This action + will also create release branch if its missing and release is `rc` or + minor. + - GitHub job `create draft release` creates draft release. Don't publish the + release until release tag is visible in. Running actions are visible on the + [Actions](https://github.com/metal3-io/utility-images/actions) + page, and draft release will be visible on top of the + [Releases](https://github.com/metal3-io/utility-images/releases). + If the release you're making is not a new major release, new minor release, + or a new patch release from the latest release branch, uncheck the box for + latest release. If it is a release candidate (RC) or a beta release, + tick pre-release box. + - GitHub jobs `build_keepalived` build release images with the + release tag, and push them to Quay. Make sure the release tags are visible in + Quay tags pages: + - [keepalived](https://quay.io/repository/metal3-io/keepalived?tab=tags) + If the new release tag is not available for any of the images, check if the + action has failed and retrigger as necessary. + +### Release artifacts + +We need to verify all release artifacts are correctly built or generated by the +release workflow. For a release, we should have the following artifacts: + +There might be a project specific verify-release.sh in the project directory +that might automates the following checks: + +Git tags pushed: + +- Primary release tag: `v0.x.y` + +Container images built and tagged at Quay registry: + +- [keepalived:v0.x.y](https://quay.io/repository/metal3-io/keepalived?tab=tags) + +Files included in the release page: + +- Source code + +### Make the release + +After everything is checked out, hit the `Publish` button your GitHub draft +release! + +## Post-release actions for new release branches + +Some post-release actions are needed if new minor or major branch was created. + +### Branch protection rules + +Branch protection rules need to be applied to the new release branch. Copy the +settings after the previous release branch, with the exception of +`Required tests` selection. Required tests can only be selected after new +keywords are implemented in Jenkins JJB, and project-infra, and have been run at +least once in the PR targeting the branch in question. Branch protection rules +require user to have `admin` permissions in the repository. + +### Update README.md and build badges + +Update `README.md` with release specific information, both on `main` and in the +new `release-0.x` branch as necessary. + +[Prior art](https://github.com/metal3-io/baremetal-operator/pull/1517) + +In the `release-0.x` branch, update the build badges in the `README.md` to point +to correct Jenkins jobs, so the build statuses of the release branch are +visible. + +[Prior art](https://github.com/metal3-io/baremetal-operator/pull/1518) + +## Additional actions outside this repository + +For that, please continue following the instructions provided in +[Metal3 release process](https://github.com/metal3-io/metal3-docs/blob/main/processes/releasing.md) diff --git a/keepalived/Dockerfile b/keepalived/Dockerfile new file mode 100644 index 0000000..f7c752c --- /dev/null +++ b/keepalived/Dockerfile @@ -0,0 +1,16 @@ +# Support FROM override +ARG BASE_IMAGE=ubuntu:22.04 + +FROM $BASE_IMAGE +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get -y update && \ + apt-get -y install keepalived && \ + apt-get -y clean + +COPY sample.keepalived.conf /etc/keepalived/keepalived.conf +COPY manage-keepalived.sh configure-nonroot.sh /bin/ + +RUN /bin/configure-nonroot.sh && rm /bin/configure-nonroot.sh + +CMD ["/bin/bash", "/bin/manage-keepalived.sh"] diff --git a/keepalived/configure-nonroot.sh b/keepalived/configure-nonroot.sh new file mode 100755 index 0000000..6bebd78 --- /dev/null +++ b/keepalived/configure-nonroot.sh @@ -0,0 +1,20 @@ +#!/usr/bin/bash + +set -eux + +# create nonroot image matching the keepalived manifest +NONROOT_USER="nonroot" +NONROOT_GROUP="nonroot" +NONROOT_UID=65532 +NONROOT_GID=65532 + +# run as non-root, allow editing the keepalived.conf during startup +groupadd -g "${NONROOT_GID}" "${NONROOT_GROUP}" +useradd -u "${NONROOT_UID}" -g "${NONROOT_GID}" -m "${NONROOT_USER}" + +mkdir -p /run/keepalived +chown -R root:"${NONROOT_GROUP}" /etc/keepalived /run/keepalived +chmod 2775 /etc/keepalived /run/keepalived +chmod 664 /etc/keepalived/keepalived.conf + +setcap "cap_net_raw,cap_net_broadcast,cap_net_admin=+eip" /usr/sbin/keepalived diff --git a/keepalived/manage-keepalived.sh b/keepalived/manage-keepalived.sh new file mode 100644 index 0000000..4576c30 --- /dev/null +++ b/keepalived/manage-keepalived.sh @@ -0,0 +1,22 @@ +#!/usr/bin/bash + +set -eux +CUSTOM_CONF_DIR="${CUSTOM_CONF_DIR:-/conf}" +CUSTOM_DATA_DIR="${CUSTOM_DATA_DIR:-/data}" +KEEPALIVED_DEFAULT_CONF='/etc/keepalived/keepalived.conf' +KEEPALIVED_CONF_DIR="${CUSTOM_CONF_DIR}/keepalived" +KEEPALIVED_CONF="${KEEPALIVED_CONF_DIR}/keepalived.conf" +KEEPALIVED_DATA_DIR="${CUSTOM_DATA_DIR}/keeplaived" +mkdir -p "${KEEPALIVED_CONF_DIR}" "${KEEPALIVED_DATA_DIR}" +cp "${KEEPALIVED_DEFAULT_CONF}" "${KEEPALIVED_CONF}" + +export assignedIP="${PROVISIONING_IP}/32" +export interface="${PROVISIONING_INTERFACE}" + +sed -i "s~INTERFACE~${interface}~g" "${KEEPALIVED_CONF}" +sed -i "s~CHANGEIP~${assignedIP}~g" "${KEEPALIVED_CONF}" + +exec /usr/sbin/keepalived --dont-fork --log-console \ + --pid="${KEEPALIVED_DATA_DIR}/keepalived.pid" \ + --vrrp_pid="${KEEPALIVED_DATA_DIR}/vrrp.pid" \ + --use-file="${KEEPALIVED_CONF}" diff --git a/keepalived/sample.keepalived.conf b/keepalived/sample.keepalived.conf new file mode 100644 index 0000000..c1c4469 --- /dev/null +++ b/keepalived/sample.keepalived.conf @@ -0,0 +1,20 @@ +! Configuration File for keepalived +global_defs { + notification_email { + sysadmin@example.com + support@example.com + } + notification_email_from lb@example.com + smtp_server localhost + smtp_connect_timeout 30 +} +vrrp_instance VI_1 { + state MASTER + interface INTERFACE + virtual_router_id 1 + priority 101 + advert_int 1 + virtual_ipaddress { + CHANGEIP + } +}