From f8018a9a05bbf38c0950fe2ac522e03cdb6102e7 Mon Sep 17 00:00:00 2001 From: Heathcliff Date: Wed, 18 Dec 2024 10:37:06 +0100 Subject: [PATCH] Add scripts for generating manifests Add a script for generating the kubernetes manifest from a template. This allows for adding manifest files for specific release tags to the github releases. To ensure this is automated, add a release workflow as well. To check if the example manifest is up to date, add it to the validate script. Signed-off-by: Heathcliff --- .github/workflows/ci.yaml | 30 +++ .github/workflows/release.yaml | 50 +++++ .gitignore | 5 +- Makefile | 5 + README.md | 13 +- examples/{example-config.yaml => config.yaml} | 0 ...xample-deployment.yaml => deployment.yaml} | 0 hack/manifests.sh | 27 +++ hack/validate.sh | 11 ++ manifests/base/deployment.yaml.template | 172 ++++++++++++++++++ 10 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/release.yaml rename examples/{example-config.yaml => config.yaml} (100%) rename examples/{example-deployment.yaml => deployment.yaml} (100%) create mode 100755 hack/manifests.sh create mode 100644 manifests/base/deployment.yaml.template diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 88310494..4504611d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -19,6 +19,23 @@ on: type: boolean default: false required: false + workflow_call: + inputs: + tag: + description: "Use to set tag, default: rolling" + type: string + default: "rolling" + required: false + dry-run: + description: "Do not push image" + type: boolean + default: false + required: false + latest: + description: "Tag latest" + type: boolean + default: false + required: false push: branches: ["main"] paths: @@ -60,3 +77,16 @@ jobs: dry-run: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' || inputs.dry-run == 'true' }} build-args: "RELEASE_VERSION=${{ inputs.tag == '' && 'rolling' || inputs.tag }}" secrets: inherit + + build-manifests: + uses: heathcliff26/ci/.github/workflows/golang-build.yaml@main + if: ${{ github.event_name != 'pull_request' && github.event_name != 'merge_group' }} + needs: + - validate + with: + release: "${{ github.event_name == 'pull_request' && 'dev' || inputs.tag == '' && 'rolling' || inputs.tag }}" + artifact: "manifests/release/*.yaml" + artifact-name: "manifests" + cmd: "make manifests" + cache: false + secrets: inherit diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..6c5734a7 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,50 @@ +--- +name: Release + +on: + workflow_dispatch: + inputs: + draft: + description: "Create draft release" + type: boolean + default: true + update: + description: "Update existing release" + type: boolean + default: false + tag: + description: "Release tag to use" + type: string + required: true + latest: + description: "Tag container as latest" + type: boolean + default: false + prerelease: + description: "Mark the release as a prerelease" + type: boolean + default: false + +jobs: + build: + uses: ./.github/workflows/ci.yaml + permissions: + contents: read + packages: write + with: + tag: ${{ inputs.tag }} + latest: ${{ inputs.latest }} + secrets: inherit + + release: + uses: heathcliff26/ci/.github/workflows/golang-release.yaml@main + needs: build + permissions: + contents: write + with: + draft: ${{ inputs.draft }} + update: ${{ inputs.update }} + tag: ${{ inputs.tag }} + release-artifacts: "release/*" + artifacts: "{manifests}" + prerelease: ${{ inputs.prerelease }} diff --git a/.gitignore b/.gitignore index 5220d331..2515076f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,11 @@ # Ignore binaries /bin +# Ignore generated manifests +/manifests/release + # Generated go-test coverage reports -coverprofiles/ +/coverprofiles # Ignore files created for testing test-config.yaml diff --git a/Makefile b/Makefile index 5ad4d8e5..3ba27fa2 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ lint: golangci-lint fmt: gofmt -s -w ./cmd ./pkg ./tests +manifests: + hack/manifests.sh + validate: hack/validate.sh @@ -42,5 +45,7 @@ golangci-lint: coverprofile \ lint \ fmt \ + manifests \ validate \ + golangci-lint \ $(NULL) diff --git a/README.md b/README.md index 7840e1bf..c07cae24 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ podman run -d -p 8080:8080 -v fleetlock-data:/data -v /path/to/config.yaml:/conf ## Examples -An example configuration can be found [here](examples/example-config.yaml) +An example configuration can be found [here](examples/config.yaml) ### Zincati configuration @@ -64,14 +64,19 @@ base_url = "http://fleetlock.example.org:8080/" ### Deploying to kubernetes -An example deployment can be found [here](examples/example-deployment.yaml). +An example deployment can be found [here](examples/deployment.yaml). To deploy it to your cluster, run: ``` -kubectl apply -f https://raw.githubusercontent.com/heathcliff26/fleetlock/main/examples/example-deployment.yaml +kubectl apply -f https://raw.githubusercontent.com/heathcliff26/fleetlock/main/examples/deployment.yaml ``` -This will deploy the app to your cluster into the namespace `fleetlock`. You can then access the app under `fleetlock.example.org` +This will deploy the app to your cluster into the namespace `fleetlock`. You can then access the app under `fleetlock.example.org`. + +You should edit the url to a domain of your choosing with +``` +kubectl -n fleetlock edit ingress fleetlock +``` ## Links diff --git a/examples/example-config.yaml b/examples/config.yaml similarity index 100% rename from examples/example-config.yaml rename to examples/config.yaml diff --git a/examples/example-deployment.yaml b/examples/deployment.yaml similarity index 100% rename from examples/example-deployment.yaml rename to examples/deployment.yaml diff --git a/hack/manifests.sh b/hack/manifests.sh new file mode 100755 index 00000000..6fb44381 --- /dev/null +++ b/hack/manifests.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -e + +base_dir="$(dirname "${BASH_SOURCE[0]}" | xargs realpath)/.." + +export REPOSITORY="${REPOSITORY:-ghcr.io/heathcliff26}" +export TAG="${TAG:-latest}" +export FLEETLOCK_NAMESPACE="${FLEETLOCK_NAMESPACE:-fleetlock}" + +output_dir="${base_dir}/manifests/release" + +if [[ "${RELEASE_VERSION}" != "" ]] && [[ "${TAG}" == "latest" ]]; then + TAG="${RELEASE_VERSION}" +fi + +[ ! -d "${output_dir}" ] && mkdir "${output_dir}" + +echo "Creating deployment.yaml" +envsubst < "${base_dir}/manifests/base/deployment.yaml.template" > "${output_dir}/deployment.yaml" + +echo "Wrote manifests to ${output_dir}" + +if [ "${TAG}" == "latest" ]; then + echo "Tag is latest, syncing manifests with examples" + cp "${output_dir}"/*.yaml "${base_dir}/examples/" +fi diff --git a/hack/validate.sh b/hack/validate.sh index 67b06243..a8ec0782 100755 --- a/hack/validate.sh +++ b/hack/validate.sh @@ -12,3 +12,14 @@ if [ $rc -ne 0 ]; then echo "FATAL: Need to run \"make fmt\"" exit 1 fi + +echo "Check if the example manifests are up to date" +export TAG="latest" +export RELEASE_VERSION="" +"${script_dir}/manifests.sh" +rc=0 +git diff-index -I "kubernetesVersion: v1.*" --quiet HEAD -- || rc=1 +if [ $rc -ne 0 ]; then + echo "FATAL: Need to run \"make manifests\" and update the examples with the result" + exit 1 +fi diff --git a/manifests/base/deployment.yaml.template b/manifests/base/deployment.yaml.template new file mode 100644 index 00000000..b651f50a --- /dev/null +++ b/manifests/base/deployment.yaml.template @@ -0,0 +1,172 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: ${FLEETLOCK_NAMESPACE} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: fleetlock-config + namespace: ${FLEETLOCK_NAMESPACE} + labels: + app: fleetlock +data: + config.yaml: | + --- + logLevel: info + storage: + type: kubernetes + groups: + default: + slots: 1 + master: + slots: 1 + worker: + slots: 1 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: fleetlock-leases + namespace: ${FLEETLOCK_NAMESPACE} +rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: fleetlock-leases + namespace: ${FLEETLOCK_NAMESPACE} +subjects: + - kind: ServiceAccount + name: fleetlock +roleRef: + kind: Role + name: fleetlock-leases + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list", "patch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["list"] + - apiGroups: [""] + resources: ["pods/eviction"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} +subjects: + - kind: ServiceAccount + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} +roleRef: + kind: ClusterRole + name: fleetlock + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} + labels: + app: fleetlock +spec: + replicas: 2 + selector: + matchLabels: + app: fleetlock + template: + metadata: + labels: + app: fleetlock + spec: + serviceAccountName: fleetlock + containers: + - name: fleetlock + image: ${REPOSITORY}/fleetlock:${TAG} + args: + - "-c" + - "/config/config.yaml" + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: "/healthz" + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + httpGet: + path: "/healthz" + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - mountPath: /config + name: fleetlock-config + volumes: + - name: fleetlock-config + configMap: + name: fleetlock-config +--- +apiVersion: v1 +kind: Service +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} + labels: + app: fleetlock +spec: + selector: + app: fleetlock + type: ClusterIP + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + name: http +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: fleetlock + namespace: ${FLEETLOCK_NAMESPACE} + labels: + app: fleetlock +spec: + rules: + - host: fleetlock.example.org + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: fleetlock + port: + name: http