├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── commit-lint.yaml │ ├── image.yml │ ├── monitor-k8s-versions.yml │ ├── pr-lint.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .releaserc ├── CONTRIBUTING.md ├── DCO ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bin └── kustomization-yaml-fix ├── scripts └── upgrade-k8s.sh └── src └── install-dependencies.sh /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | ## Motivation and Context 5 | 6 | 7 | 8 | 9 | ## How has this been tested? 10 | 11 | ## Types of changes 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 16 | 17 | ## Checklist: 18 | - [ ] My change requires a change to the documentation. 19 | - [ ] I have updated the documentation accordingly. 20 | - [ ] I've read the [CONTRIBUTION](https://github.com/swade1987/flux2-kustomize-template/blob/main/CONTRIBUTING.md) guide 21 | - [ ] I have signed-off my commits with `git commit -s` 22 | -------------------------------------------------------------------------------- /.github/workflows/commit-lint.yaml: -------------------------------------------------------------------------------- 1 | name: commit-lint 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: read 13 | 14 | jobs: 15 | commit-lint: 16 | name: commit-lint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 20 | - uses: wagoid/commitlint-github-action@3d28780bbf0365e29b144e272b2121204d5be5f3 # v6 21 | -------------------------------------------------------------------------------- /.github/workflows/image.yml: -------------------------------------------------------------------------------- 1 | name: image 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | env: 9 | KUBERNETES_VERSION: 1.33.1 10 | 11 | jobs: 12 | build-and-push: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Delete huge unnecessary tools folder 16 | run: rm -rf /opt/hostedtoolcache 17 | 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | 21 | - name: Set up QEMU 22 | uses: docker/setup-qemu-action@v3.3.0 23 | 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v3.8.0 26 | 27 | - name: Login to GCR 28 | uses: docker/login-action@v3.3.0 29 | with: 30 | registry: eu.gcr.io 31 | username: _json_key 32 | password: ${{ secrets.PUBLIC_GCR_JSON_KEY }} 33 | 34 | - name: Extract version from tag 35 | id: version 36 | run: | 37 | # Remove 'v' prefix if present 38 | VERSION=${GITHUB_REF#refs/tags/v} 39 | VERSION=${VERSION#refs/tags/} 40 | echo "VERSION=${VERSION}" >> $GITHUB_ENV 41 | 42 | - name: Build and push 43 | uses: docker/build-push-action@v6.13.0 44 | with: 45 | build-args: | 46 | KUBERNETES_VERSION=${{ env.KUBERNETES_VERSION }} 47 | context: . 48 | push: true 49 | tags: | 50 | eu.gcr.io/swade1987/kubernetes-toolkit:latest 51 | eu.gcr.io/swade1987/kubernetes-toolkit:${{ env.VERSION }} 52 | -------------------------------------------------------------------------------- /.github/workflows/monitor-k8s-versions.yml: -------------------------------------------------------------------------------- 1 | name: Monitor Kubernetes Versions 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' # Run daily at midnight 6 | workflow_dispatch: # Allow manual triggers 7 | 8 | jobs: 9 | check-k8s-version: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | token: ${{ secrets.RELEASE_TOKEN }} 17 | 18 | - name: Setup GitHub CLI 19 | run: | 20 | gh auth login --with-token <<< "${{ secrets.RELEASE_TOKEN }}" 21 | 22 | - name: Check existing PRs 23 | id: check-prs 24 | run: | 25 | EXISTING_PRS=$(gh pr list --json title --jq '.[] | select(.title | contains("upgrading kubernetes to v")) | .title') 26 | if [ -n "$EXISTING_PRS" ]; then 27 | echo "Found existing Kubernetes upgrade PRs:" 28 | echo "$EXISTING_PRS" 29 | echo "Skipping version check until existing PRs are merged" 30 | echo "has_prs=true" >> "$GITHUB_OUTPUT" 31 | exit 0 32 | else 33 | echo "No existing Kubernetes upgrade PRs found" 34 | echo "has_prs=false" >> "$GITHUB_OUTPUT" 35 | fi 36 | 37 | - name: Get current version 38 | if: steps.check-prs.outputs.has_prs == 'false' 39 | id: current 40 | run: | 41 | CURRENT_VERSION=$(grep 'KUBERNETES_VERSION :=' Makefile | awk '{print $3}') 42 | echo "version=${CURRENT_VERSION}" >> "$GITHUB_OUTPUT" 43 | 44 | - name: Get K8s versions 45 | if: steps.check-prs.outputs.has_prs == 'false' 46 | id: versions 47 | run: | 48 | # Get and sort versions 49 | curl -s https://api.github.com/repos/kubernetes/kubernetes/releases | 50 | jq -r '.[].tag_name' | 51 | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | 52 | sed 's/^v//' | 53 | sort -V > $GITHUB_WORKSPACE/k8s_versions.txt 54 | 55 | echo "Available versions:" 56 | cat $GITHUB_WORKSPACE/k8s_versions.txt 57 | 58 | - name: Process versions 59 | if: steps.check-prs.outputs.has_prs == 'false' 60 | id: process 61 | run: | 62 | CURRENT="${{ steps.current.outputs.version }}" 63 | echo "Current version: $CURRENT" 64 | 65 | echo "Reading available versions:" 66 | while IFS= read -r VERSION; do 67 | echo "Checking version: $VERSION" 68 | 69 | if [[ "$VERSION" > "$CURRENT" ]]; then 70 | if [[ "${{ steps.prs.outputs.versions }}" != "none" ]] && \ 71 | echo "${{ steps.prs.outputs.versions }}" | grep -q "^${VERSION}$"; then 72 | echo "Version ${VERSION} already has an open PR" 73 | continue 74 | fi 75 | 76 | echo "version=${VERSION}" >> "$GITHUB_OUTPUT" 77 | echo "Found new version to update to: ${VERSION}" 78 | break 79 | else 80 | echo "Version ${VERSION} is not newer than ${CURRENT}" 81 | fi 82 | done < $GITHUB_WORKSPACE/k8s_versions.txt 83 | 84 | # Clean up temporary file 85 | rm $GITHUB_WORKSPACE/k8s_versions.txt 86 | 87 | - name: Configure Git 88 | if: steps.check-prs.outputs.has_prs == 'false' && steps.process.outputs.version != '' 89 | run: | 90 | git config user.name "Steve Wade" 91 | git config user.email "steven@stevenwade.co.uk" 92 | 93 | - name: Run upgrade script 94 | if: steps.check-prs.outputs.has_prs == 'false' && steps.process.outputs.version != '' 95 | env: 96 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 97 | run: | 98 | chmod +x ./scripts/upgrade-k8s.sh 99 | ./scripts/upgrade-k8s.sh --execute ${{ steps.process.outputs.version }} 100 | -------------------------------------------------------------------------------- /.github/workflows/pr-lint.yml: -------------------------------------------------------------------------------- 1 | name: pr-lint 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: read 13 | 14 | jobs: 15 | lint: 16 | name: pr-lint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | 9 | jobs: 10 | release: 11 | name: release 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: write # to be able to publish a GitHub release 15 | issues: write # to be able to comment on released issues 16 | pull-requests: write # to be able to comment on released pull requests 17 | id-token: write # to enable use of OIDC for npm provenance 18 | steps: 19 | - name: checkout 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 21 | with: 22 | fetch-depth: 0 23 | persist-credentials: false 24 | token: ${{ secrets.RELEASE_TOKEN }} 25 | 26 | - name: setup node.js 27 | uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 28 | with: 29 | node-version: "lts/*" 30 | 31 | - name: release 32 | id: release 33 | uses: cycjimmy/semantic-release-action@v4 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | 6 | env: 7 | KUBERNETES_VERSION: 1.33.1 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Delete huge unnecessary tools folder 14 | run: rm -rf /opt/hostedtoolcache 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | - name: Set up QEMU 18 | uses: docker/setup-qemu-action@v3 19 | - name: Set up Docker Buildx 20 | uses: docker/setup-buildx-action@v3 21 | - name: Login to GCR 22 | uses: docker/login-action@v3 23 | with: 24 | registry: eu.gcr.io 25 | username: _json_key 26 | password: ${{ secrets.PUBLIC_GCR_JSON_KEY }} 27 | - name: Build and push 28 | uses: docker/build-push-action@v3 29 | with: 30 | build-args: | 31 | KUBERNETES_VERSION=${{ env.KUBERNETES_VERSION }} 32 | context: . 33 | push: false 34 | tags: eu.gcr.io/swade1987/kubernetes-toolkit:${{ env.KUBERNETES_VERSION }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /scripts/upgrade-k8s.sh.log 3 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: 2 | - pre-commit 3 | - commit-msg 4 | 5 | repos: 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # SHA for v5.0.0 8 | hooks: 9 | - id: check-merge-conflict 10 | - id: end-of-file-fixer 11 | - id: trailing-whitespace 12 | - repo: https://github.com/compilerla/conventional-pre-commit 13 | rev: 5f9c312d9978fbcee1da97154ba385834eeda799 # SHA for v4.0.0 14 | hooks: 15 | - id: conventional-pre-commit 16 | stages: [commit-msg] 17 | args: [] # optional: list of Conventional Commits types to allow e.g. [feat, fix, ci, chore, test] 18 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/github", 4 | "@semantic-release/commit-analyzer", 5 | "@semantic-release/release-notes-generator", 6 | ], 7 | "branches": [ 8 | { 9 | "name": "main" 10 | }, 11 | { 12 | "name": "next", 13 | "prerelease": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | The repository is [MIT licensed](https://github.com/swade1987/flux2-kustomize-template/blob/main/LICENSE) and 4 | accepts contributions via GitHub pull requests. This document outlines 5 | some of the conventions on to make it easier to get your contribution 6 | accepted. 7 | 8 | We gratefully welcome improvements to issues and documentation as well as to 9 | code. 10 | 11 | ## Certificate of Origin 12 | 13 | By contributing to the repository you agree to the Developer Certificate of 14 | Origin (DCO). This document was created by the Linux Kernel community and is a 15 | simple statement that you, as a contributor, have the legal right to make the 16 | contribution. 17 | 18 | We require all commits to be signed. By signing off with your signature, you 19 | certify that you wrote the patch or otherwise have the right to contribute the 20 | material by the rules of the [DCO](DCO): 21 | 22 | `Signed-off-by: Jane Doe ` 23 | 24 | The signature must contain your real name 25 | (sorry, no pseudonyms or anonymous contributions) 26 | If your `user.name` and `user.email` are configured in your Git config, 27 | you can sign your commit automatically with `git commit -s`. 28 | 29 | ## Acceptance policy 30 | 31 | These things will make a PR more likely to be accepted: 32 | 33 | - a well-described requirement 34 | - sign-off all your commits 35 | - tests for new configuration 36 | - tests for old configuration! 37 | 38 | In general, we will merge a PR once one maintainer has endorsed it. 39 | For substantial changes, more people may become involved, and you might 40 | get asked to resubmit the PR or divide the changes into more than one PR. 41 | 42 | ### Commit Message and Pull Request Requirements: 43 | 44 | This repository enforces the `Conventional Commits` specification for both commit messages and pull request titles. 45 | 46 | All commits and PR titles must follow this format: 47 | type(optional scope): description 48 | 49 | Examples: 50 | - `feat: add new istio validation check` 51 | - `fix(ci): resolve kubeconform pipeline error` 52 | - `docs: update deployment instructions` 53 | - `chore: bump pre-commit hooks version` 54 | 55 | The type must be one of: `build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test` 56 | 57 | For more details on Conventional Commits, see: https://www.conventionalcommits.org/ 58 | 59 | Note: This is enforced automatically via GitHub Actions and pre-commit hooks. 60 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 660 York Street, Suite 102, 6 | San Francisco, CA 94110 USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies of this 9 | license document, but changing it is not allowed. 10 | 11 | 12 | Developer's Certificate of Origin 1.1 13 | 14 | By making a contribution to this project, I certify that: 15 | 16 | (a) The contribution was created in whole or in part by me and I 17 | have the right to submit it under the open source license 18 | indicated in the file; or 19 | 20 | (b) The contribution is based upon previous work that, to the best 21 | of my knowledge, is covered under an appropriate open source 22 | license and I have the right under that license to submit that 23 | work with modifications, whether created in whole or in part 24 | by me, under the same open source license (unless I am 25 | permitted to submit under a different license), as indicated 26 | in the file; or 27 | 28 | (c) The contribution was provided directly to me by some other 29 | person who certified (a), (b) or (c) and I have not modified 30 | it. 31 | 32 | (d) I understand and agree that this project and the contribution 33 | are public and that a record of the contribution (including all 34 | personal information I submit with it, including my sign-off) is 35 | maintained indefinitely and may be redistributed consistent with 36 | this project or the open source license(s) involved. 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21.3 2 | LABEL MAINTAINER="Steven Wade " 3 | 4 | ARG KUBERNETES_VERSION="Unknown" 5 | 6 | # Enable Edge Community Repo 7 | RUN echo "https://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories 8 | 9 | # Install necessary tooling with a specific Buildah version 10 | RUN apk update && apk add --no-cache \ 11 | curl \ 12 | bash \ 13 | execline \ 14 | findutils \ 15 | git \ 16 | make \ 17 | openssh-client && \ 18 | rm -rf /var/cache/apk/* 19 | 20 | # Install Python 3 21 | RUN apk add --update python3 py3-pip 22 | 23 | # Install necessary packages 24 | COPY src/install-dependencies.sh /install-dependencies.sh 25 | RUN /install-dependencies.sh ${KUBERNETES_VERSION} 26 | 27 | # Install /usr/local/bin 28 | COPY bin/* /usr/local/bin/ 29 | 30 | CMD ["/bin/sh"] 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 stevenwadeconsulting 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJNAME := kubernetes-toolkit 2 | KUBERNETES_VERSION := 1.33.1 3 | GOOS ?= $(if $(TARGETOS),$(TARGETOS),linux) 4 | GOARCH ?= $(if $(TARGETARCH),$(TARGETARCH),amd64) 5 | BUILDPLATFORM ?= $(GOOS)/$(GOARCH) 6 | 7 | # ############################################################################################################ 8 | # Local tasks 9 | # ############################################################################################################ 10 | 11 | initialise: 12 | pre-commit --version || brew install pre-commit 13 | pre-commit install --install-hooks 14 | pre-commit run -a 15 | 16 | build: 17 | docker buildx build --build-arg BUILDPLATFORM=$(BUILDPLATFORM) --build-arg TARGETARCH=$(GOARCH) \ 18 | --build-arg KUBERNETES_VERSION=$(KUBERNETES_VERSION) \ 19 | -t local/$(PROJNAME):$(KUBERNETES_VERSION) . 20 | 21 | scan: build 22 | trivy --light -s "UNKNOWN,MEDIUM,HIGH,CRITICAL" --exit-code 1 local/$(PROJNAME):$(KUBERNETES_VERSION) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Toolkit 🛠️ 2 | 3 | [![release](https://github.com/swade1987/kubernetes-toolkit/actions/workflows/release.yml/badge.svg)](https://github.com/swade1987/kubernetes-toolkit/actions/workflows/release.yml) 4 | [![image](https://github.com/swade1987/kubernetes-toolkit/actions/workflows/image.yml/badge.svg)](https://github.com/swade1987/kubernetes-toolkit/actions/workflows/image.yml) 5 | 6 | This container provides a comprehensive suite of tools for Kubernetes. It is designed to be used in CI/CD pipelines and local development environments. 7 | 8 | Images can be found at [https://eu.gcr.io/swade1987/kubernetes-toolkit](https://eu.gcr.io/swade1987/kubernetes-toolkit). 9 | 10 | ## Included Tools/Schemas 11 | 12 | ### Core Kubernetes Tools 13 | - [kubectl](https://kubernetes.io/docs/reference/kubectl/) (version passed as build argument) 14 | - [kustomize](https://github.com/kubernetes-sigs/kustomize) (v5.6.0) 15 | - [Helm v3](https://github.com/helm/helm) (v3.17.1) 16 | - [helm-docs](https://github.com/norwoodj/helm-docs) (v1.14.2) 17 | 18 | ### Validation & Testing 19 | - [kubeconform](https://github.com/yannh/kubeconform) (v0.6.7) 20 | - [conftest](https://github.com/open-policy-agent/conftest) (v0.55.0) 21 | - [pluto](https://github.com/FairwindsOps/pluto) (v5.20.3) 22 | 23 | ### Container Tools 24 | - [trivy](https://github.com/aquasecurity/trivy) (v0.59.0) 25 | 26 | ### GitOps & Service Mesh 27 | - [flux](https://github.com/fluxcd/flux2) (v2.6.1) 28 | - [flux operator](https://github.com/controlplaneio-fluxcd/flux-operator) (v0.21.0) 29 | - [istioctl](https://github.com/istio/istio) (v1.26.1) 30 | 31 | ### Configuration Processing 32 | - [yq](https://github.com/mikefarah/yq) (v4.44.3) 33 | - [jq](https://github.com/stedolan/jq) (v1.7.1) 34 | 35 | ### Development & Linting Tools 36 | - [shellcheck](https://github.com/koalaman/shellcheck) (v0.10.0) 37 | - [jsonlint](https://github.com/zaach/jsonlint) (v1.6.3) 38 | 39 | ### Schema Support 40 | - Kubernetes JSON schemas (version matches kubectl client version) obtained via [k8s-schemas](https://github.com/swade1987/k8s-schemas). 41 | - Flux CRD schemas (matching installed Flux version) 42 | - Flux Operator CRD schemas (matching installed Flux Operator version) 43 | 44 | ## Notes 45 | - All binaries are installed in `/usr/local/bin/` 46 | - Kubernetes schemas are stored in `/tmp/kubernetes-schemas/` 47 | - Flux schemas are stored in `/tmp/flux-schemas/` 48 | - Flux Operator schemas are stored in `/tmp/flux-operator-schemas/` 49 | 50 | ## Features 51 | 52 | - Linting (via CI) using [kubeconform](https://github.com/yannh/kubeconform), [pluto](https://github.com/FairwindsOps/pluto) and [istioctl](https://istio.io/latest/docs/reference/commands/istioctl/). 53 | - Automated with GitHub Actions 54 | - Commits must meet [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 55 | - Automated with GitHub Actions ([commit-lint](https://github.com/conventional-changelog/commitlint/#what-is-commitlint)) 56 | - Pull Request titles must meet [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 57 | - Automated with GitHub Actions ([pr-lint](https://github.com/amannn/action-semantic-pull-request)) 58 | - Commits must be signed with [Developer Certificate of Origin (DCO)](https://developercertificate.org/) 59 | - Automated with GitHub App ([DCO](https://github.com/apps/dco)) 60 | - Automatic [Semantic Releases](https://semantic-release.gitbook.io/) 61 | 62 | ## Getting started 63 | 64 | Before working with the repository it is **mandatory** to execute the following command: 65 | 66 | ``` 67 | make initialise 68 | ``` 69 | 70 | The above command will install the `pre-commit` package and setup pre-commit checks for this repository including [conventional-pre-commit](https://github.com/compilerla/conventional-pre-commit) to make sure your commits match the conventional commit convention. 71 | 72 | ## Contributing to the repository 73 | 74 | To contribute, please read the [contribution guidelines](CONTRIBUTING.md). You may also [report an issue](https://github.com/swade1987/kubernetes-toolkit/issues/new/choose). 75 | -------------------------------------------------------------------------------- /bin/kustomization-yaml-fix: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | DIR="$1" 6 | 7 | function main { 8 | find "$DIR" -name kustomization.yaml -print0 \ 9 | | xargs -P 0 -0I {} dirname {} \ 10 | | xargs -P 0 -I {} sh -c "cd '{}' && kustomize edit fix --vars" 11 | } 12 | 13 | main 14 | -------------------------------------------------------------------------------- /scripts/upgrade-k8s.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################### 4 | # Script Name : upgrade-k8s.sh 5 | # Description : Creates a pull request to upgrade Kubernetes version 6 | # Author : Steve Wade 7 | # Email : steven@stevenwade.co.uk 8 | ############################################################################### 9 | 10 | # Exit on error. Append "|| true" if you expect an error. 11 | set -o errexit 12 | # Exit on error inside any functions or subshells. 13 | set -o errtrace 14 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR 15 | set -o nounset 16 | # Catch error in pipe 17 | set -o pipefail 18 | 19 | # Global constants 20 | readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 21 | readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")" 22 | 23 | # Color definitions 24 | readonly RED='\033[0;31m' 25 | readonly GREEN='\033[0;32m' 26 | readonly YELLOW='\033[1;33m' 27 | readonly NC='\033[0m' # No Color 28 | 29 | ############################################################################### 30 | # Variables 31 | ############################################################################### 32 | VERBOSE=true 33 | DRY_RUN=true 34 | LOG_FILE="${SCRIPT_DIR}/${SCRIPT_NAME}.log" 35 | KUBERNETES_VERSION="" 36 | 37 | ############################################################################### 38 | # Usage help message 39 | ############################################################################### 40 | usage() { 41 | cat < 43 | 44 | Creates a pull request to upgrade Kubernetes version in GitHub Actions and Makefile. 45 | 46 | Options: 47 | -h, --help Show this help message 48 | -e, --execute Execute changes (disabled by default) 49 | -l, --log FILE Log output to specified file 50 | 51 | Example: 52 | ${SCRIPT_NAME} --execute 1.32.0 53 | EOF 54 | } 55 | 56 | ############################################################################### 57 | # Functions 58 | ############################################################################### 59 | 60 | # Logger function 61 | log() { 62 | local level="$1" 63 | shift 64 | local message="$*" 65 | local timestamp 66 | timestamp="$(date +'%Y-%m-%d %H:%M:%S')" 67 | 68 | # Always log to file if LOG_FILE is set 69 | if [[ -n "${LOG_FILE:-}" ]]; then 70 | echo "${timestamp} [${level}] ${message}" >> "${LOG_FILE}" 71 | fi 72 | 73 | # Only output to console if verbose is enabled or if it's an error 74 | if [[ "${VERBOSE}" == "true" ]] || [[ "${level}" == "ERROR" ]]; then 75 | case "${level}" in 76 | ERROR) 77 | echo -e "${RED}${timestamp} [${level}] ${message}${NC}" >&2 78 | ;; 79 | WARN) 80 | echo -e "${YELLOW}${timestamp} [${level}] ${message}${NC}" 81 | ;; 82 | SUCCESS) 83 | echo -e "${GREEN}${timestamp} [${level}] ${message}${NC}" 84 | ;; 85 | *) 86 | echo "${timestamp} [${level}] ${message}" 87 | ;; 88 | esac 89 | fi 90 | } 91 | 92 | # Function to check required commands 93 | check_requirements() { 94 | local failed=false 95 | 96 | for cmd in "$@"; do 97 | if ! command -v "${cmd}" >/dev/null 2>&1; then 98 | log "ERROR" "${cmd} is required but not installed." 99 | failed=true 100 | fi 101 | done 102 | 103 | if [[ "${failed}" == "true" ]]; then 104 | exit 1 105 | fi 106 | } 107 | 108 | # Cleanup function 109 | cleanup() { 110 | log "INFO" "Cleaning up..." 111 | } 112 | 113 | # Validate kubernetes version 114 | validate_version() { 115 | if [[ ! $KUBERNETES_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 116 | log "ERROR" "Invalid Kubernetes version format. Expected format: X.Y.Z" 117 | exit 1 118 | fi 119 | } 120 | 121 | # Show configuration 122 | show_config() { 123 | local whoami=$(whoami) 124 | local branch_name="${whoami}/upgrade-k8s-to-${KUBERNETES_VERSION}" 125 | 126 | log "INFO" "=== Configuration ===" 127 | log "INFO" "Kubernetes Version: ${KUBERNETES_VERSION}" 128 | log "INFO" "Branch Name: ${branch_name}" 129 | log "INFO" "Mode: $([ "$DRY_RUN" = true ] && echo 'DRY RUN' || echo 'EXECUTE')" 130 | log "INFO" "====================" 131 | } 132 | 133 | # Update GitHub Actions workflows 134 | update_github_actions() { 135 | local github_dir=".github/workflows" 136 | 137 | if [[ ! -d "$github_dir" ]]; then 138 | log "ERROR" "GitHub workflows directory not found: $github_dir" 139 | return 1 140 | fi 141 | 142 | log "INFO" "Updating GitHub Actions workflows..." 143 | 144 | find "$github_dir" -type f -name "*.yml" -o -name "*.yaml" | while read -r file; do 145 | if [[ "${DRY_RUN}" == "true" ]]; then 146 | log "INFO" "Would update Kubernetes version in: $file" 147 | else 148 | # Update the version in GitHub Actions workflow files 149 | sed -i.bak -E 's/(KUBERNETES_VERSION: ).*/\1'"${KUBERNETES_VERSION}"'/' "$file" 150 | rm "${file}.bak" 151 | log "SUCCESS" "Updated $file" 152 | fi 153 | done 154 | } 155 | 156 | # Update Makefile 157 | update_makefile() { 158 | if [[ ! -f "Makefile" ]]; then 159 | log "ERROR" "Makefile not found" 160 | return 1 161 | fi 162 | 163 | log "INFO" "Updating Makefile..." 164 | 165 | if [[ "${DRY_RUN}" == "true" ]]; then 166 | log "INFO" "Would update Kubernetes version in Makefile" 167 | else 168 | # Update the version in Makefile 169 | sed -i.bak 's/^KUBERNETES_VERSION := .*/KUBERNETES_VERSION := '"${KUBERNETES_VERSION}"'/' Makefile 170 | rm Makefile.bak 171 | log "SUCCESS" "Updated Makefile" 172 | fi 173 | } 174 | 175 | # Create pull request 176 | create_pull_request() { 177 | if [[ "${DRY_RUN}" == "true" ]]; then 178 | log "INFO" "Would create pull request for version upgrade" 179 | return 0 180 | fi 181 | 182 | local whoami=$(whoami) 183 | local branch_name="${whoami}/upgrade-k8s-to-${KUBERNETES_VERSION}" 184 | local commit_message="feat: upgrading kubernetes to v${KUBERNETES_VERSION}" 185 | 186 | # Create and checkout branch 187 | log "INFO" "Creating and checking out branch..." 188 | git checkout -b "$branch_name" || { log "ERROR" "Failed to create branch"; exit 1; } 189 | 190 | # Commit changes 191 | log "INFO" "Committing changes..." 192 | git add . 193 | git commit -asm "$commit_message" || { log "ERROR" "Failed to commit changes"; exit 1; } 194 | 195 | # Push branch 196 | log "INFO" "Pushing branch..." 197 | git push -u origin "$branch_name" || { log "ERROR" "Failed to push branch"; exit 1; } 198 | 199 | # Create pull request 200 | log "INFO" "Creating pull request..." 201 | gh pr create \ 202 | --title "$commit_message" \ 203 | --body "feat: updating kubernetes version to ${KUBERNETES_VERSION}." \ 204 | --base main \ 205 | --head "$branch_name" || { log "ERROR" "Failed to create PR"; exit 1; } 206 | 207 | log "SUCCESS" "Successfully created pull request for Kubernetes version upgrade" 208 | } 209 | 210 | ############################################################################### 211 | # Main Script 212 | ############################################################################### 213 | 214 | # Parse command line arguments 215 | while [[ $# -gt 0 ]]; do 216 | case "$1" in 217 | -h|--help) 218 | usage 219 | exit 0 220 | ;; 221 | -v|--verbose) 222 | VERBOSE=true 223 | shift 224 | ;; 225 | -e|--execute) 226 | DRY_RUN=false 227 | shift 228 | ;; 229 | -l|--log) 230 | LOG_FILE="$2" 231 | shift 2 232 | ;; 233 | *) 234 | if [[ -z "$KUBERNETES_VERSION" ]]; then 235 | KUBERNETES_VERSION="$1" 236 | else 237 | log "ERROR" "Unexpected argument: $1" 238 | usage 239 | exit 1 240 | fi 241 | shift 242 | ;; 243 | esac 244 | done 245 | 246 | # Check if kubernetes version is provided 247 | if [[ -z "$KUBERNETES_VERSION" ]]; then 248 | log "ERROR" "Kubernetes version is required" 249 | usage 250 | exit 1 251 | fi 252 | 253 | # Ensure cleanup happens on script exit 254 | trap cleanup EXIT 255 | 256 | # Check for required tools 257 | check_requirements "git" "gh" "sed" 258 | 259 | # Main logic 260 | main() { 261 | validate_version 262 | show_config 263 | update_github_actions 264 | update_makefile 265 | create_pull_request 266 | } 267 | 268 | # Run main function 269 | main "$@" 270 | -------------------------------------------------------------------------------- /src/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -uo errexit 4 | 5 | KUBERNETES_VERSION=$1 6 | printf "Downloading kubectl %s\n" "${KUBERNETES_VERSION}" 7 | curl -sL https://dl.k8s.io/release/v"${KUBERNETES_VERSION}"/bin/linux/amd64/kubectl \ 8 | -o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl 9 | kubectl version --client 10 | 11 | KUSTOMIZE=5.6.0 12 | printf "\nDownloading kustomize %s\n" "${KUSTOMIZE}" 13 | curl -sL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE}/kustomize_v${KUSTOMIZE}_linux_amd64.tar.gz | \ 14 | tar xz && mv kustomize /usr/local/bin/kustomize 15 | kustomize version 16 | 17 | HELM_V3=3.17.1 18 | printf "\nDownloading helm %s\n" "${HELM_V3}" 19 | curl -sSL https://get.helm.sh/helm-v${HELM_V3}-linux-amd64.tar.gz | \ 20 | tar xz && mv linux-amd64/helm /usr/local/bin/helmv3 && rm -rf linux-amd64 && ln -s /usr/local/bin/helmv3 /usr/local/bin/helm 21 | helmv3 version 22 | helm version 23 | 24 | KUBECONFORM=0.6.7 25 | printf "\nDownloading kubeconform %s\n" "${KUBECONFORM}" 26 | curl -sL https://github.com/yannh/kubeconform/releases/download/v${KUBECONFORM}/kubeconform-linux-amd64.tar.gz | \ 27 | tar xz && mv kubeconform /usr/local/bin/kubeconform 28 | kubeconform -v 29 | 30 | CONFTEST=0.55.0 31 | printf "\nDownloading conftest %s\n" "${CONFTEST}" 32 | curl -sL https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST}/conftest_${CONFTEST}_Linux_x86_64.tar.gz | \ 33 | tar xz && mv conftest /usr/local/bin/conftest 34 | conftest --version 35 | 36 | FLUX=2.6.1 37 | printf "\nDownloading flux %s\n" "${FLUX}" 38 | curl -sL https://github.com/fluxcd/flux2/releases/download/v${FLUX}/flux_${FLUX}_linux_amd64.tar.gz | \ 39 | tar xz && mv flux /usr/local/bin/flux 40 | rm -rf flux_${FLUX} 41 | flux version --client 42 | 43 | ISTIOCTL=1.26.1 44 | # shellcheck disable=SC2059 45 | printf "\nDownloading istioctl %s\n" "${ISTIOCTL}" 46 | curl -sL https://github.com/istio/istio/releases/download/${ISTIOCTL}/istioctl-${ISTIOCTL}-linux-amd64.tar.gz | \ 47 | tar xz && mv istioctl /usr/local/bin/istioctl 48 | rm -rf istio-${ISTIOCTL} 49 | istioctl version --remote=false 50 | 51 | YQ=v4.44.3 52 | printf "\nDownloading yq %s\n" "${YQ}" 53 | curl -sL https://github.com/mikefarah/yq/releases/download/${YQ}/yq_linux_amd64 \ 54 | -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq 55 | yq --version 56 | 57 | JQ=1.7.1 58 | printf "\nDownloading jq %s\n" "${JQ}" 59 | curl -sL https://github.com/stedolan/jq/releases/download/jq-${JQ}/jq-linux64 \ 60 | -o /usr/local/bin/jq && chmod +x /usr/local/bin/jq 61 | jq --version 62 | 63 | # Install Python 3 and additional libraries 64 | apk add --update --no-cache python3 gcc libxslt-dev libxml2-dev libxml2 libxslt build-base python3-dev nodejs npm 65 | 66 | HELM_DOCS=1.14.2 67 | printf "\nDownloading helm-docs %s\n" "${HELM_DOCS}" 68 | curl -sL https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS}/helm-docs_${HELM_DOCS}_Linux_x86_64.tar.gz | \ 69 | tar xz && mv helm-docs /usr/local/bin/helm-docs 70 | rm -rf helm-docs_${HELM_DOCS}_Linux_x86_64 71 | helm-docs --version 72 | 73 | JSONLINT=1.6.3 74 | printf "\nDownloading jsonlint %s\n" "${JSONLINT}" 75 | npm install jsonlint@${JSONLINT} -g 76 | jsonlint --version || : 77 | 78 | PLUTO=5.20.3 79 | printf "\nDownloading pluto %s\n" "${PLUTO}" 80 | curl -sL https://github.com/FairwindsOps/pluto/releases/download/v${PLUTO}/pluto_${PLUTO}_linux_amd64.tar.gz | \ 81 | tar xz && mv pluto /usr/local/bin/pluto 82 | rm -rf pluto_${PLUTO}_linux_amd64.tar.gz 83 | pluto version 84 | 85 | SHELLCHECK=v0.10.0 86 | printf "\ndownloading shellcheck %s \n" "${SHELLCHECK}" 87 | wget https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK}/shellcheck-${SHELLCHECK}.linux.x86_64.tar.xz -O - | tar xJf - 88 | mv shellcheck-${SHELLCHECK}/shellcheck /usr/local/bin/shellcheck && rm -rf shellcheck-${SHELLCHECK} 89 | shellcheck --version 90 | 91 | TRIVY=0.59.0 92 | printf "\nDownloading trivy %s\n" "${TRIVY}" 93 | curl -sL https://github.com/aquasecurity/trivy/releases/download/v${TRIVY}/trivy_${TRIVY}_Linux-64bit.tar.gz | \ 94 | tar xz && mv trivy /usr/local/bin/trivy 95 | rm -rf trivy_${TRIVY}_Linux-64bit.tar.gz 96 | trivy version 97 | 98 | printf "\nFetching kubernetes json schemas for v%s\n" "${KUBERNETES_VERSION}" 99 | mkdir -p /tmp/kubernetes-schemas/v"${KUBERNETES_VERSION}"-standalone-strict && \ 100 | curl -sL "https://github.com/swade1987/k8s-schemas/releases/download/v${KUBERNETES_VERSION}/kubernetes-json-schema-v${KUBERNETES_VERSION}-standalone-strict.zip" > /tmp/schema.zip && \ 101 | unzip -o /tmp/schema.zip -d /tmp/kubernetes-schemas && \ 102 | rm /tmp/schema.zip 103 | 104 | printf "\nFetching flux json schemas for v%s\n" "${FLUX}" 105 | mkdir -p /tmp/flux-schemas/master-standalone-strict 106 | curl -sL https://github.com/fluxcd/flux2/releases/download/v${FLUX}/crd-schemas.tar.gz | tar zxf - -C /tmp/flux-schemas/master-standalone-strict 107 | 108 | FLUX_OPERATOR=0.21.0 109 | printf "\nFetching flux operator json schemas for v%s\n" "${FLUX_OPERATOR}" 110 | mkdir -p /tmp/flux-operator-schemas/master-standalone-strict 111 | curl -sL https://github.com/controlplaneio-fluxcd/flux-operator/releases/download/v${FLUX_OPERATOR}/crd-schemas.tar.gz | tar zxf - -C /tmp/flux-operator-schemas/master-standalone-strict 112 | --------------------------------------------------------------------------------