├── .github ├── ISSUE_TEMPLATE │ └── file-issues-on-main-kairos-repo.md └── workflows │ ├── lint.yml │ ├── publish.yaml │ └── test.yaml ├── Earthfile ├── LICENSE ├── LocalAI ├── Dockerfile ├── assets │ └── localai.yaml └── run.sh ├── README.md ├── argocd ├── Dockerfile ├── assets │ └── argocd.yaml └── run.sh ├── calico ├── Dockerfile ├── assets │ └── calico.yaml └── run.sh ├── cert-manager ├── Dockerfile └── run.sh ├── coco ├── Dockerfile ├── assets │ ├── containerd-override.conf │ ├── k3s-config.yaml │ ├── k3s-override.conf │ └── plan.yaml └── run.sh ├── earthly.ps1 ├── earthly.sh ├── flux ├── Dockerfile ├── flux-bootstrap.service ├── flux-bootstrap.sh └── run.sh ├── kairos ├── Dockerfile ├── assets │ ├── crd.yaml │ ├── entangle-proxy.yaml │ ├── entangle.yaml │ └── osbuilder.yaml └── run.sh ├── kubevirt ├── Dockerfile ├── assets │ ├── cdi-cr.yaml │ ├── cdi-operator.yaml │ ├── kubevirt-cr.yaml │ └── kubevirt-operator.yaml ├── kubevirt-manager-manifests │ ├── cdi-cr.yaml │ ├── kubevirt-cr.yaml │ ├── kubevirt-manager-bundled.yaml │ ├── kubevirt-manager-deployment.yaml │ ├── kubevirt-manager-ingress.yaml │ ├── kubevirt-manager-ns.yaml │ ├── kubevirt-manager-pc.yaml │ ├── kubevirt-manager-rbac.yaml │ └── kubevirt-manager-service.yaml └── run.sh ├── kyverno ├── Dockerfile ├── assets │ └── kyverno.yaml └── run.sh ├── longhorn ├── Dockerfile ├── assets │ └── longhorn.yaml └── run.sh ├── metallb ├── Dockerfile ├── assets │ ├── addresspool.yaml │ └── metallb.yaml └── run.sh ├── multus ├── Dockerfile ├── manifests.yaml └── run.sh ├── nginx ├── Dockerfile ├── assets │ └── ingress-nginx.yaml └── run.sh ├── openamt ├── Dockerfile └── run.sh ├── renovate.json ├── spinkube ├── Dockerfile └── run.sh ├── system-upgrade-controller ├── Dockerfile ├── assets │ └── system-upgrade-controller.yaml └── run.sh └── tests ├── argocd_test.go ├── calico_test.go ├── cert-manager_test.go ├── go.mod ├── go.sum ├── kairos_test.go ├── kubevirt_test.go ├── kyverno_test.go ├── localai_test.go ├── longhorn_test.go ├── metallb_test.go ├── multus_test.go ├── nginx_test.go ├── suite_test.go └── system-upgrade-controller_test.go /.github/ISSUE_TEMPLATE/file-issues-on-main-kairos-repo.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: File issues on main Kairos repo 3 | about: Tell users to file their issues on the main Kairos repo 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | :warning: All Kairos issues are tracked in our main repo, please file your issue there, thanks! :warning: 11 | 12 | https://github.com/kairos-io/kairos/issues 13 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 14 | with: 15 | fetch-depth: 0 16 | - name: Run Lint checks 17 | run: | 18 | ./earthly.sh +lint 19 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | branches: 8 | - main 9 | 10 | concurrency: 11 | group: ci-publish-${{ github.head_ref || github.ref }}-${{ github.repository }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | images: 16 | runs-on: ubuntu-latest 17 | permissions: 18 | id-token: write 19 | strategy: 20 | matrix: 21 | bundles: 22 | - calico 23 | - cert-manager 24 | - flux 25 | - coco 26 | - kubevirt 27 | - kairos 28 | - longhorn 29 | - kyverno 30 | - metallb 31 | - multus 32 | - nginx 33 | - spinkube 34 | - system-upgrade-controller 35 | - argocd 36 | - "LocalAI" 37 | env: 38 | REGISTRY: quay.io 39 | REGISTRY_USER: ${{ secrets.REGISTRY_USERNAME }} 40 | REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} 41 | steps: 42 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 43 | - uses: docker-practice/actions-setup-docker@master 44 | - uses: earthly/actions-setup@v1 45 | with: 46 | version: "latest" 47 | - run: echo $REGISTRY_PASSWORD | docker login -u $REGISTRY_USER --password-stdin $REGISTRY 48 | - run: earthly --ci --push +build --BUNDLE=${{ matrix.bundles }} 49 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: 9 | group: ci-test-${{ github.head_ref || github.ref }}-${{ github.repository }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | test: 14 | strategy: 15 | matrix: 16 | bundles: 17 | - calico 18 | - cert-manager 19 | - kubevirt 20 | - longhorn 21 | - metallb 22 | - multus 23 | - nginx 24 | - kairos 25 | - kyverno 26 | - system-upgrade-controller 27 | - argocd 28 | - "LocalAI" 29 | - flux 30 | - coco 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 34 | - uses: docker-practice/actions-setup-docker@master 35 | - run: ./earthly.sh --ci --push +test --BUNDLE=${{ matrix.bundles }} 36 | -------------------------------------------------------------------------------- /Earthfile: -------------------------------------------------------------------------------- 1 | VERSION 0.6 2 | FROM alpine 3 | ARG BUNDLE 4 | ARG VERSION="latest" 5 | ARG IMAGE_REPOSITORY=quay.io/kairos/community-bundles 6 | 7 | # renovate: datasource=docker depName=renovate/renovate versioning=docker 8 | ARG RENOVATE_VERSION=37 9 | # renovate: datasource=docker depName=koalaman/shellcheck-alpine versioning=docker 10 | ARG SHELLCHECK_VERSION=v0.9.0 11 | 12 | version: 13 | FROM alpine 14 | RUN apk add git 15 | 16 | COPY . ./ 17 | 18 | RUN echo $(git describe --exact-match --tags || echo "v0.0.0-$(git log --oneline -n 1 | cut -d" " -f1)") > VERSION 19 | 20 | SAVE ARTIFACT VERSION VERSION 21 | 22 | build: 23 | COPY +version/VERSION ./ 24 | ARG VERSION=$(cat VERSION) 25 | FROM DOCKERFILE -f ${BUNDLE}/Dockerfile ./${BUNDLE} 26 | SAVE IMAGE --push $IMAGE_REPOSITORY:${BUNDLE}_${VERSION} 27 | 28 | rootfs: 29 | FROM +build 30 | SAVE ARTIFACT /. rootfs 31 | 32 | test: 33 | FROM quay.io/kairos/core-alpine-opensuse-leap 34 | RUN apk add go 35 | ENV GOPATH=/go 36 | ENV PATH=$PATH:$GOPATH/bin 37 | COPY (+rootfs/rootfs --BUNDLE=$BUNDLE) /bundle 38 | COPY . . 39 | RUN cd tests && \ 40 | go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo && \ 41 | ginkgo --label-filter="${BUNDLE}" -v ./... 42 | 43 | renovate-validate: 44 | ARG RENOVATE_VERSION 45 | FROM renovate/renovate:$RENOVATE_VERSION 46 | WORKDIR /usr/src/app 47 | COPY renovate.json . 48 | RUN renovate-config-validator 49 | 50 | shellcheck-lint: 51 | ARG SHELLCHECK_VERSION 52 | FROM koalaman/shellcheck-alpine:$SHELLCHECK_VERSION 53 | WORKDIR /mnt 54 | COPY . . 55 | RUN find . -name "*.sh" -print | xargs -r -n1 shellcheck 56 | 57 | lint: 58 | BUILD +renovate-validate 59 | BUILD +shellcheck-lint 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LocalAI/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | COPY ./run.sh / 3 | COPY ./assets /assets 4 | -------------------------------------------------------------------------------- /LocalAI/assets/localai.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: localai 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: localai 10 | namespace: localai 11 | spec: 12 | chart: local-ai 13 | repo: https://go-skynet.github.io/helm-charts/ 14 | version: "@VERSION@" 15 | valuesContent: |- 16 | service: 17 | type: "@SERVICETYPE@" 18 | -------------------------------------------------------------------------------- /LocalAI/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | VERSION="3.4.2" 8 | 9 | templ() { 10 | local file="$3" 11 | local value="$2" 12 | local sentinel="$1" 13 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 14 | } 15 | 16 | mkdir -p "${K3S_MANIFEST_DIR}" 17 | 18 | # Set the service type 19 | serviceType=$(kairos-agent config get localai.serviceType | tr -d '\n') 20 | if [[ -z "$serviceType" ]]; then 21 | serviceType="ClusterIP" 22 | fi 23 | templ "SERVICETYPE" "${serviceType}" assets/localai.yaml 24 | 25 | # Set the version of the helm chart 26 | for FILE in assets/*; do 27 | templ "VERSION" "${VERSION}" "${FILE}" 28 | done; 29 | 30 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | kairos-white-column 5bc2fe34 4 |
5 |
6 |

7 | 8 |

Kairos Community Bundles

9 | 10 |
11 | 12 | Welcome to the community-bundles repository! This repository builds and pushes Kairos community bundles that can be consumed by Kairos core or derivative images (such as [provider-kairos](https://github.com/kairos-io/provider-kairos) ) to extend Kairos configurations and settings, and to add cloud-config keywords. 13 | 14 | Please note that these community bundles are not officially supported and are provided on a best-effort basis by the community. 15 | 16 | ## Table of Contents 17 | 18 | - [Table of Contents](#table-of-contents) 19 | - [Usage](#usage) 20 | - [Bundles](#bundles) 21 | - [Calico](#calico) 22 | - [Cert-manager](#cert-manager) 23 | - [Flux](#flux) 24 | - [Kairos](#kairos) 25 | - [Kyverno](#kyverno) 26 | - [Kubevirt](#kubevirt) 27 | - [Longhorn](#longhorn) 28 | - [MetalLB](#metallb) 29 | - [Multus](#multus) 30 | - [Nginx](#nginx) 31 | - [SpinKube](#spinkube) 32 | - [System upgrade controller](#system-upgrade-controller) 33 | - [ArgoCD](#argocd) 34 | - [Development](#development) 35 | 36 | ## Usage 37 | 38 | To use a community bundle, you can load it with the bundles block in the Kairos configuration file, like this: 39 | 40 | ```yaml 41 | bundles: 42 | - targets: 43 | - run://quay.io/kairos/community-bundles: 44 | ``` 45 | 46 | Here is an example of how you might use a community bundle in a Kairos core image: 47 | 48 | ```yaml 49 | #cloud-config 50 | install: 51 | device: "auto" 52 | auto: true 53 | reboot: true 54 | image: "docker:quay.io/kairos/kairos-opensuse:v1.4.0-k3sv1.26.0-k3s1" 55 | 56 | users: 57 | - name: "kairos" 58 | passwd: "kairos" 59 | ssh_authorized_keys: 60 | - ... 61 | 62 | bundles: 63 | - targets: 64 | - run://quay.io/kairos/community-bundles:kubevirt 65 | 66 | k3s: 67 | enabled: true 68 | ``` 69 | 70 | ## Bundles 71 | 72 | ### Calico 73 | 74 | The calico bundle deploys [Project Calico](https://docs.tigera.io/calico/latest/about/). 75 | 76 | To configure the bundle, use the `calico` block: 77 | 78 | ```yaml 79 | #cloud-config 80 | 81 | # Specify the bundle to use 82 | bundles: 83 | - targets: 84 | - run://quay.io/kairos/community-bundles:calico_latest 85 | 86 | # Specify calico settings 87 | calico: 88 | values: 89 | installation: 90 | cni: 91 | type: Calico 92 | calicoNetwork: 93 | bgp: Disabled 94 | ipPools: 95 | - cidr: 10.244.0.0/16 96 | encapsulation: VXLAN 97 | version: 3.25.0 98 | ``` 99 | 100 | Note that specifying `values` and `version` are optional. Specifying `values` allows you to 101 | [customize the Helm Chart](https://docs.tigera.io/calico/latest/getting-started/kubernetes/helm#customize-the-helm-chart). 102 | 103 | ### Cert-manager 104 | 105 | The cert-manager bundle deploys [cert-manager](https://cert-manager.io/docs/installation/). 106 | 107 | The bundle does add a `certManager` block, that allow to change the version (currently only available `v1.11.0`): 108 | 109 | ```yaml 110 | #cloud-config 111 | 112 | # Specify the bundle to use 113 | bundles: 114 | - targets: 115 | - run://quay.io/kairos/community-bundles:cert-manager_latest 116 | 117 | # Specify cert-manager settings 118 | certManager: 119 | version: v1.11.0 120 | ``` 121 | 122 | ### Flux 123 | 124 | This installs [FluxCD](https://fluxcd.io/flux/cmd/flux_bootstrap/) and supports 125 | automatically bootstrapping the cluster. Only one node will do the bootstrap. 126 | It will time out after trying for 30 minutes and it requires `systemd`. 127 | 128 | ```yaml 129 | #cloud-config 130 | 131 | k3s: 132 | enabled: true 133 | 134 | bundles: 135 | - targets: 136 | - run://quay.io/kairos/community-bundles:flux_latest 137 | 138 | # Specify command-line arguments as keys under a key of `bitbucket_server`, 139 | # `git`, `github` or `gitlab` for the provider to boostrap from. An example for 140 | # `github` is shown below. 141 | flux: 142 | env: 143 | # Override default $KUBECONFIG of /etc/rancher/k3s/k3s.yaml if needed 144 | # KUBECONFIG: /home/csagan/.kube/config 145 | GITHUB_TOKEN: abcde1234 146 | github: 147 | owner: csagan 148 | repository: fleet-infra 149 | path: clusters/cosmos 150 | components-extra: image-reflector-controller,image-automation-controller 151 | ``` 152 | 153 | ### Kairos 154 | 155 | The Kairos bundle deploys the [Kairos helm-charts](https://github.com/kairos-io/helm-charts). It installs the `kairos-crds` chart, and allows to enable [entangle-proxy](https://kairos.io/docs/reference/entangle/), [osbuilder](https://kairos.io/docs/advanced/build/), and [entangle](https://kairos.io/docs/reference/entangle/). 156 | 157 | By default the bundle will install only the CRDs, components needs to be explicitly enabled: 158 | 159 | ```yaml 160 | #cloud-config 161 | 162 | # Specify the bundle to use 163 | bundles: 164 | - targets: 165 | - run://quay.io/kairos/community-bundles:kairos_latest 166 | 167 | # Specify kairos bundle setting 168 | kairos: 169 | osbuilder: 170 | enable: true 171 | version: ... #optional 172 | entangle: 173 | enable: true 174 | version: ... #optional 175 | entangleProxy: 176 | enable: true 177 | version: ... #optional 178 | ``` 179 | 180 | ### Kyverno 181 | 182 | The Kyverno bundle deploys [Kyverno](https://kyverno.io/docs/introduction/). 183 | 184 | To configure the bundle, use the `kyverno` block: 185 | 186 | ```yaml 187 | #cloud-config 188 | 189 | # Specify the bundle to use 190 | bundles: 191 | - targets: 192 | - run://quay.io/kairos/community-bundles:kyverno_latest 193 | 194 | # Specify kyverno settings 195 | kyverno: 196 | values: .... 197 | version: ... 198 | ``` 199 | 200 | Note that specifying `values` and `version` are optional. Specifying `values` allows you to 201 | [customize the Helm Chart](https://github.com/kyverno/kyverno/blob/main/charts/kyverno/values.yaml). 202 | 203 | ### Kubevirt 204 | 205 | The Kubevirt bundle deploys [Kubevirt](https://github.com/kubevirt/kubevirt) and optionally [kubevirt-manager](https://kubevirt-manager.io/) 206 | 207 | The bundle does add a `kubevirt` block, that allow to enable `kubevirt-manager`: 208 | 209 | ```yaml 210 | #cloud-config 211 | 212 | # Specify the bundle to use 213 | bundles: 214 | - targets: 215 | - run://quay.io/kairos/community-bundles:kubevirt_latest 216 | 217 | # Specify kubevirt settings 218 | kubevirt: 219 | manager: true 220 | ``` 221 | 222 | ### Longhorn 223 | 224 | The longhorn bundle deploys [Longhorn](https://longhorn.io/docs/). 225 | 226 | To configure the bundle, use the `longhorn` block: 227 | 228 | ```yaml 229 | #cloud-config 230 | 231 | # Specify the bundle to use 232 | bundles: 233 | - targets: 234 | - run://quay.io/kairos/community-bundles:longhorn_latest 235 | 236 | # Specify longhorn settings 237 | longhorn: 238 | values: 239 | defaultSettings: 240 | backupstorePollInterval: 600 241 | version: 1.4.0 242 | ``` 243 | 244 | Note that specifying `values` and `version` are optional. Specifying `values` allows you to 245 | [customize the Helm Chart](https://longhorn.io/docs/latest/advanced-resources/deploy/customizing-default-settings/#using-helm). 246 | 247 | ### MetalLB 248 | 249 | The MetalLB bundle deploys [MetalLB](https://metallb.universe.tf/installation/) in the cluster, available after boostrap. 250 | 251 | The bundle does add a `metallb` block, that allow to set up the MetalLB version and the address pool in the Kairos configuration file: 252 | 253 | ```yaml 254 | #cloud-config 255 | 256 | # Specify the bundle to use 257 | bundles: 258 | - targets: 259 | - run://quay.io/kairos/community-bundles:metallb_latest 260 | 261 | # Specify metallb settings 262 | metallb: 263 | version: 0.13.7 264 | address_pool: 192.168.1.10-192.168.1.20 265 | ``` 266 | 267 | Note, you might want to disable the default LoadBalancer of k3s, a full example can be: 268 | 269 | ```yaml 270 | #cloud-config 271 | 272 | hostname: kairoslab-{{ trunc 4 .MachineID }} 273 | users: 274 | - name: kairos 275 | ssh_authorized_keys: 276 | # Add your github user here! 277 | - github:mudler 278 | 279 | k3s: 280 | enabled: true 281 | args: 282 | - --disable=servicelb 283 | 284 | # Specify the bundle to use 285 | bundles: 286 | - targets: 287 | - run://quay.io/kairos/community-bundles:metallb_latest 288 | 289 | # Specify metallb settings 290 | metallb: 291 | version: 0.13.7 292 | address_pool: 192.168.1.10-192.168.1.20 293 | ``` 294 | 295 | ### Multus 296 | 297 | The Multus bundle deploys [Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni), along with specified [CNI plugins](https://www.cni.dev/plugins/current/). 298 | 299 | The only created resources are the ClusterRole and the associated ClusterRoleBinding. Instead of creating a service account, it sets up a _normal user_ using an [X509 client certificate](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs). This client certificate has a validity of 3650 days by default which can be overwritten by the configuration. 300 | 301 | To configure the bundle, use the `multus` block: 302 | 303 | ```yaml 304 | # Specify the bundle to use 305 | bundles: 306 | - targets: 307 | - run://quay.io/kairos/community-bundles:multus_latest 308 | 309 | # Specify multus settings. Here are the defaults: 310 | multus: 311 | # List of additional CNI plugins to install. May also be a 312 | # whitelist-delimited list. 313 | # See https://www.cni.dev/plugins/current/ for available plugins. 314 | cni_plugins: [] 315 | 316 | # Full path to the directory the plugins will be installed. 317 | cni_bin_dir: /opt/cni/bin 318 | 319 | # Full path to the directory where multus will be installed. 320 | multus_bin_dir: /var/lib/rancher/k3s/data/current/bin 321 | 322 | # Full path to the directory where the configuration files will be written. 323 | cni_conf_dir: /var/lib/rancher/k3s/agent/etc/cni/net.d 324 | 325 | # Full path to the directory containing certificate authority (CA) files. 326 | ca_path: /var/lib/rancher/k3s/server/tls 327 | 328 | # Duration (in days) during which the generated certificate will be valid 329 | # for. 330 | crt_validity: 3650 331 | 332 | # URL of the Kubernetes API 333 | cluster_server: https://127.0.0.1:6443 334 | 335 | # Whether or not to isolate the NetworkAttachmentDefinition resources so that 336 | # the pods referring to them must be in the same namespace. 337 | namespace_isolation: false 338 | 339 | # When namespace isolation is enabled, list of namespaces that are to be 340 | # considered “global” and allow their NetworkAttachmentDefinitions to be 341 | # referred to by pods in other namespaces. May also be a coma-delimited list. 342 | global_namespaces: [] 343 | 344 | # Full path to the CNI configuration wrapped by Multus. If left unset, scan 345 | # the multus.cni_conf_dir directory, sort the filenames alphabetically and 346 | # use the first file result. 347 | primary_config: ~ 348 | ``` 349 | 350 | ### Nginx 351 | 352 | The Nginx bundle deploys [Ingress-Nginx-Controller](https://kubernetes.github.io/ingress-nginx/) in the cluster, available after boostrap. 353 | 354 | The bundle does add a `nginx` block, that allow to set up the nginx version and helm chart [values](https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/values.yaml) in the Kairos configuration file: 355 | 356 | ```yaml 357 | #cloud-config 358 | 359 | # Specify the bundle to use 360 | bundles: 361 | - targets: 362 | - run://quay.io/kairos/community-bundles:nginx_latest 363 | 364 | # Specify nginx settings 365 | nginx: 366 | version: 4.7.3 367 | ``` 368 | 369 | ```yaml 370 | #cloud-config 371 | 372 | # Specify the bundle to use 373 | bundles: 374 | - targets: 375 | - run://quay.io/kairos/community-bundles:nginx_latest 376 | 377 | # Specify nginx settings 378 | nginx: 379 | values: 380 | commonLabels: 381 | myLabel: abc123 382 | ``` 383 | 384 | Note, you might want to disable the default Ingress-Controller of k3s, a full example can be: 385 | 386 | ```yaml 387 | #cloud-config 388 | 389 | hostname: kairoslab-{{ trunc 4 .MachineID }} 390 | users: 391 | - name: kairos 392 | ssh_authorized_keys: 393 | # Add your github user here! 394 | - github:mudler 395 | 396 | k3s: 397 | enabled: true 398 | args: 399 | - --disable=traefik 400 | 401 | # Specify the bundle to use 402 | bundles: 403 | - targets: 404 | - run://quay.io/kairos/community-bundles:nginx_latest 405 | 406 | # Specify nginx settings 407 | nginx: 408 | version: 4.7.3 409 | ``` 410 | 411 | ### SpinKube 412 | 413 | > **WARNING**: This will not work with Kairos distributions that don't use `systemd` (i.e. Alpine). 414 | 415 | The SpinKube bundle deploys [SpinKube](https://spinkube.dev) to a running k3s cluster. 416 | 417 | The bundle has a `spinkube` block that allows you to install `cert-manager`, which is required by SpinKube: 418 | 419 | ```yaml 420 | bundles: 421 | - targets: 422 | - run://quay.io/kairos/community-bundles:spinkube_latest 423 | 424 | spinkube: 425 | installCertManager: true 426 | ``` 427 | 428 | If you don't want to use the bundle's `cert-manager` installation, be sure to check [SpinKube](https://www.spinkube.dev/docs/install/)'s documentation for which version of `cert-manager` to use. 429 | 430 | ### System upgrade controller 431 | 432 | The System upgrade controller bundle deploys [System upgrade controller](https://github.com/rancher/system-upgrade-controller). 433 | 434 | The bundle does add a `suc` block, that allow to change the version: 435 | 436 | ```yaml 437 | #cloud-config 438 | 439 | # Specify the bundle to use 440 | bundles: 441 | - targets: 442 | - run://quay.io/kairos/community-bundles:system-upgrade-controller_latest 443 | 444 | # Specify system-upgrade-controller settings 445 | suc: 446 | version: v0.10.0 447 | ``` 448 | 449 | ### ArgoCD 450 | 451 | The ArgoCD bundle deploys [ArgoCD](https://argo-cd.readthedocs.io/en/stable/). 452 | 453 | To configure the bundle, use the `argocd` block: 454 | 455 | ```yaml 456 | #cloud-config 457 | 458 | # Specify the bundle to use 459 | bundles: 460 | - targets: 461 | - run://quay.io/kairos/community-bundles:argocd_latest 462 | 463 | # Specify argocd settings 464 | argocd: 465 | values: 466 | redis-ha: 467 | enabled: true 468 | controller: 469 | replicas: 1 470 | server: 471 | autoscaling: 472 | enabled: true 473 | minReplicas: 2 474 | version: 7.5.2 475 | ``` 476 | 477 | ## Development 478 | 479 | If you want to build and test a bundle, you can use earthly by running the following commands: 480 | 481 | ``` 482 | # build 483 | ./earthly.sh +build --BUNDLE= 484 | # test 485 | ./earthly.sh +test --BUNDLE= 486 | ``` 487 | 488 | We also provide a version of the `earthly.sh` script for Windows (`earthly.ps1`). 489 | -------------------------------------------------------------------------------- /argocd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | # renovate: datasource=github-releases depName=argoproj/argo-cd 3 | ENV VERSION=2.10.2 4 | ARG TARGETARCH 5 | RUN if [[ "$TARGETARCH" = "amd64" ]]; then \ 6 | export CHECKSUM=a8da9fa1ea7b7072007f535d39526ad0c4a8b8eb58779b48774126335c576187; \ 7 | elif [[ "$TARGETARCH" = "arm64" ]]; then \ 8 | export CHECKSUM=8314c9fda218145344cb0af68ceb8f31338bf11ab4ec315ba553cf6268e17444; \ 9 | fi && \ 10 | echo "CHECKSUM=${CHECKSUM}" > /tmp/checksum_env 11 | RUN source /tmp/checksum_env && echo "CHECKSUM is: ${CHECKSUM}" 12 | ADD "https://github.com/argoproj/argo-cd/releases/download/v${VERSION}/argocd-linux-${TARGETARCH}" /tmp 13 | RUN DOWNLOAD_FILE="/tmp/argocd-linux-${TARGETARCH}" && \ 14 | DOWNLOAD_CHECKSUM=$(sha256sum "${DOWNLOAD_FILE}" | awk '{print $1}') && \ 15 | if [[ ${DOWNLOAD_CHECKSUM} != ${CHECKSUM} ]]; then \ 16 | echo "Checksum does not match"; \ 17 | exit 1; \ 18 | fi 19 | 20 | FROM --platform=$BUILDPLATFORM scratch 21 | ARG TARGETARCH 22 | COPY ./run.sh / 23 | COPY --from=build /tmp/argocd-linux-${TARGETARCH} . 24 | COPY ./assets /assets 25 | -------------------------------------------------------------------------------- /argocd/assets/argocd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: argocd 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: argocd 10 | namespace: argocd 11 | spec: 12 | name: argocd 13 | chart: argo-cd 14 | repo: https://argoproj.github.io/argo-helm 15 | valuesContent: |- 16 | @VALUES@ 17 | version: "@VERSION@" 18 | -------------------------------------------------------------------------------- /argocd/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | BIN=/usr/local/bin/ 7 | 8 | getConfig() { 9 | local key=$1 10 | _value=$(kairos-agent config get "${key} | @json" | tr -d '\n') 11 | # Remove the quotes wrapping the value. 12 | _value=${_value:1:${#_value}-2} 13 | if [ "${_value}" != "null" ]; then 14 | echo "${_value}" 15 | fi 16 | echo 17 | } 18 | 19 | VALUES="{}" 20 | VERSION="7.5.2" # Chart Version 21 | 22 | templ() { 23 | local file="$3" 24 | local value=$2 25 | local sentinel=$1 26 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 27 | } 28 | 29 | readConfig() { 30 | _values=$(getConfig argocd.values) 31 | if [ "$_values" != "" ]; then 32 | VALUES=$_values 33 | fi 34 | _version=$(getConfig argocd.version) 35 | if [ "$_version" != "" ]; then 36 | VERSION=$_version 37 | fi 38 | } 39 | 40 | mkdir -p "${K3S_MANIFEST_DIR}" 41 | mkdir -p $BIN 42 | 43 | readConfig 44 | 45 | # Copy manifests, and template them 46 | for FILE in assets/*; do 47 | templ "VALUES" "${VALUES}" "${FILE}" 48 | templ "VERSION" "${VERSION}" "${FILE}" 49 | done; 50 | 51 | # get system arch 52 | ARCH=$(uname -m) 53 | 54 | if [ "$ARCH" == "x86_64" ]; then 55 | SYSTEM_ARCH="amd64" 56 | else 57 | if [ "$ARCH" == "aarch64" ]; then 58 | SYSTEM_ARCH="arm64" 59 | fi 60 | fi 61 | 62 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 63 | cp argocd-linux-"$SYSTEM_ARCH" $BIN/argocd 64 | sudo chmod +x $BIN/argocd 65 | -------------------------------------------------------------------------------- /calico/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /calico/assets/calico.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: tigera-operator 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: calico 10 | namespace: tigera-operator 11 | spec: 12 | name: calico 13 | chart: tigera-operator 14 | repo: https://docs.tigera.io/calico/charts 15 | valuesContent: |- 16 | @VALUES@ 17 | version: "@VERSION@" 18 | -------------------------------------------------------------------------------- /calico/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | VALUES="{}" 8 | # renovate: depName=tigera-operator repoUrl=https://docs.tigera.io/calico/charts 9 | VERSION="v3.28.2" 10 | 11 | templ() { 12 | local file="$3" 13 | local value="$2" 14 | local sentinel="$1" 15 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 16 | } 17 | 18 | _version=$(kairos-agent config get "calico.version" | tr -d '\n') 19 | if [ "$_version" != "null" ]; then 20 | VERSION=$_version 21 | fi 22 | _values=$(kairos-agent config get "calico.values | @json" | tr -d '\n') 23 | # Remove the quotes wrapping the value. 24 | _values=${_values:1:${#_values}-2} 25 | if [ "$_values" != "null" ]; then 26 | VALUES=$_values 27 | fi 28 | 29 | # Copy manifests, and template them 30 | for FILE in assets/*; do 31 | templ "VALUES" "${VALUES}" "${FILE}" 32 | templ "VERSION" "${VERSION}" "${FILE}" 33 | done; 34 | 35 | mkdir -p "${K3S_MANIFEST_DIR}" 36 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 37 | -------------------------------------------------------------------------------- /cert-manager/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | RUN mkdir /assets 3 | RUN wget https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml -O /assets/cert-manager-v1.11.0.yaml 4 | FROM scratch 5 | COPY ./run.sh / 6 | COPY --from=build /assets /assets 7 | -------------------------------------------------------------------------------- /cert-manager/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | getConfig() { 8 | local l="$1" 9 | key=$(kairos-agent config get "${l}" | tr -d '\n') 10 | if [ "$key" != "null" ]; then 11 | echo "${key}" 12 | fi 13 | echo 14 | } 15 | 16 | VERSION="v1.11.0" 17 | 18 | templ() { 19 | local file="$3" 20 | local value="$2" 21 | local sentinel="$1" 22 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 23 | } 24 | 25 | readConfig() { 26 | _version="$(getConfig 'certManager.version')" 27 | if [ "$_version" != "" ]; then 28 | VERSION=$_version 29 | fi 30 | } 31 | 32 | mkdir -p "${K3S_MANIFEST_DIR}" 33 | 34 | readConfig 35 | 36 | cp -rf "assets/cert-manager-${VERSION}.yaml" "${K3S_MANIFEST_DIR}/cert-manager.yaml" 37 | -------------------------------------------------------------------------------- /coco/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | 3 | # TODO: How do we handle different architectures? 4 | WORKDIR /assets 5 | RUN wget https://github.com/confidential-containers/containerd/releases/download/v1.6.8.1/containerd-1.6.8.1-linux-amd64.tar.gz -O containerd.tar.gz 6 | RUN tar xvf containerd.tar.gz 7 | RUN rm containerd.tar.gz 8 | 9 | RUN wget https://raw.githubusercontent.com/containerd/containerd/release/1.6/containerd.service 10 | 11 | FROM scratch 12 | COPY ./run.sh / 13 | COPY --from=build /assets/ /assets 14 | COPY assets/. /assets 15 | -------------------------------------------------------------------------------- /coco/assets/containerd-override.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | ExecStart= 3 | ExecStart=/usr/local/bin/containerd --config /etc/containerd/config.toml --root /etc/coco/run/ --address /etc/coco/run/containerd.sock 4 | 5 | Environment="PATH=/var/lib/rancher/k3s/data/current/bin:/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin" 6 | -------------------------------------------------------------------------------- /coco/assets/k3s-config.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.k3s.io/installation/configuration#configuration-file 2 | container-runtime-endpoint: /etc/coco/run/containerd.sock 3 | -------------------------------------------------------------------------------- /coco/assets/k3s-override.conf: -------------------------------------------------------------------------------- 1 | [Service] 2 | Environment=K3S_CONFIG_FILE=/etc/coco/k3s-config.yaml 3 | ExecStart= 4 | ExecStart=/usr/bin/k3s server --kubelet-arg cgroup-driver=systemd 5 | 6 | [Unit] 7 | After=containerd.service 8 | -------------------------------------------------------------------------------- /coco/assets/plan.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: custom-script 5 | namespace: system-upgrade 6 | type: Opaque 7 | stringData: 8 | coco-install.sh: | 9 | #!/bin/sh 10 | set -e 11 | 12 | if [ -d "/host/etc/containerd/.sentinel" ]; then 13 | echo "Containerd folder was populated" 14 | exit 0 15 | fi 16 | export COCO_DEPLOY=true 17 | mount --rbind /host/dev /dev 18 | mount --rbind /host/run /run 19 | nsenter -i -m -t 1 -- kairos-agent install-bundle run://@IMAGE@ 20 | exit 0 21 | --- 22 | apiVersion: upgrade.cattle.io/v1 23 | kind: Plan 24 | metadata: 25 | name: coco 26 | namespace: system-upgrade 27 | spec: 28 | concurrency: 1 29 | # This is the version (tag) of the image. 30 | # The version is referred to the kairos version plus the k3s version. 31 | version: "v1.0.0-rc2-k3sv1.23.9-k3s1" 32 | nodeSelector: 33 | matchExpressions: 34 | - { key: kubernetes.io/hostname, operator: Exists } 35 | serviceAccountName: system-upgrade 36 | cordon: false 37 | upgrade: 38 | image: quay.io/kairos/kairos-opensuse-leap 39 | command: 40 | - "/bin/bash" 41 | - "-c" 42 | args: 43 | - bash /host/run/system-upgrade/secrets/custom-script/coco-install.sh 44 | secrets: 45 | - name: custom-script 46 | path: /host/run/system-upgrade/secrets/custom-script 47 | -------------------------------------------------------------------------------- /coco/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | # This script will setup enclave-cc runtime to allow running confidential 6 | # containers on the kairos cluster 7 | # More here: 8 | # https://github.com/confidential-containers/enclave-cc 9 | # https://github.com/confidential-containers/documentation/blob/main/quickstart.md 10 | # 11 | # It works in 2 "modes": 12 | # 1. when kairos first installs, it simply puts the plan.yaml in a place where 13 | # k3s will see it an deploy it as soon as it's up and running. 14 | # 2. when the plan actually runs, it will install this bundle but this time with 15 | # COCO_DEPLOY set to "true". This will run the deployCoco function which puts the 16 | # customized containerd binary in place and makes sure k3s uses that containerd 17 | # (through a socket). Also it copies the containerd configuration generated by 18 | # k3s, to the standard location from which our containerd will read it and to which 19 | # the coco operator will append the `kata` plugin settings. 20 | # (We copy /var/lib/rancher/k3s/agent/etc/containerd/config.toml to /etc/containerd/config.toml) 21 | 22 | getConfig() { 23 | local l=$1 24 | key=$(kairos-agent config get "${l}" | tr -d '\n') 25 | if [ "$key" != "null" ]; then 26 | echo "${key}" 27 | fi 28 | echo 29 | } 30 | 31 | deployCoco() { 32 | mkdir -p /usr/local/bin 33 | cp -f assets/bin/* /usr/local/bin/ 34 | 35 | # Setting an override for k3s service so that we can point to our config 36 | mkdir -p /etc/systemd/system/k3s.service.d 37 | # zz- to run apply override last 38 | 39 | # TODO: This flag: --kubelet-arg cgroup-driver=systemd 40 | # should probalby not be set when in alpine (or other non-systemd systems) 41 | # because maybe k3s decides to not put `SystemdCgroup = true` in the config.toml 42 | # in those cases. 43 | # https://kubernetes.io/docs/setup/production-environment/container-runtimes/#systemd-cgroup-driver 44 | cp assets/k3s-override.conf /etc/systemd/system/k3s.service.d/zz-coco-override.conf 45 | 46 | # NOTE: Make sure the paths we write to are persisted by adding this to the 47 | # kairos config: 48 | # install: 49 | # bind_mounts: 50 | # - /etc/coco 51 | # - /etc/containerd 52 | # Put our k3s config in place 53 | mkdir -p /etc/coco 54 | cp assets/k3s-config.yaml /etc/coco/ 55 | 56 | cp assets/containerd.service /etc/systemd/system/ 57 | mkdir -p /etc/systemd/system/containerd.service.d 58 | cp assets/containerd-override.conf /etc/systemd/system/containerd.service.d/ 59 | 60 | mkdir -p /etc/containerd/ 61 | cp -rf /var/lib/rancher/k3s/agent/etc/containerd/config.toml /etc/containerd/config.toml 62 | 63 | systemctl enable --now containerd.service 64 | 65 | touch /etc/containerd/.sentinel 66 | 67 | # Delete the plan (just in case, though is should not run again) 68 | rm -rf /var/lib/rancher/k3s/server/manifests/plan.yaml 69 | 70 | systemctl daemon-reload # read new definitions 71 | 72 | # NOTE: User should now reboot manually 73 | 74 | 75 | # TODO: 76 | # - In the config.toml generated by k3s, there is a line that point to the shims bin directory: 77 | # 78 | # [plugins."io.containerd.grpc.v1.cri".cni] 79 | # bin_dir = "/var/lib/rancher/k3s/data/599b4f3127975cf230091dd1fbb1c60fb7fa3ce1782b287fd8269855a279a757/bin" 80 | # conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d" 81 | # 82 | # This is where `containerd-shim-runc-v2` is but we should probably be using the 83 | # binary we install in '/usr/local/bin`. 84 | # How do we make use of our binary keeping the rest intact? 85 | } 86 | 87 | 88 | # This is the default functionality of this bundle. It applies a Plan on the cluster 89 | # so that when it starts, it runs the function above to migrate the cluster 90 | # to a "coco" one. The reason for doing this, is that we need to let k3s generate 91 | # the containerd config.json so that we can append our runtimes to it. 92 | # k3s won't generate a config for containerd if we specify "container-runtime-endpoint". 93 | # https://github.com/k3s-io/k3s/blob/85b261096cc494b3795e659b8a5d86fff9251164/pkg/agent/run.go#L113 94 | # 95 | # BUNDLE_TARGET: 96 | # https://github.com/kairos-io/kairos-sdk/commit/7a148fe5bb90c4ed5faceb534d72d6fc9852e8c0#diff-8e10d3eee9260dce2bf6cf7f8147d8052f350fb37c6c3e01c48d04852984b2efR183 97 | installDeployPlan() { 98 | cp assets/plan.yaml /var/lib/rancher/k3s/server/manifests/ 99 | sed -i "s|@IMAGE@|${BUNDLE_TARGET}|g" /var/lib/rancher/k3s/server/manifests/plan.yaml 100 | } 101 | 102 | if [ -n "$COCO_DEPLOY" ]; then 103 | deployCoco 104 | else 105 | installDeployPlan 106 | fi 107 | -------------------------------------------------------------------------------- /earthly.ps1: -------------------------------------------------------------------------------- 1 | docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock --rm -t -v ${pwd}:/workspace -v earthly-tmp:/tmp/earthly:rw earthly/earthly:v0.8.15 --allow-privileged @args -------------------------------------------------------------------------------- /earthly.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock --rm -t -v "$(pwd)":/workspace -v earthly-tmp:/tmp/earthly:rw earthly/earthly:v0.8.15 --allow-privileged "$@" 4 | -------------------------------------------------------------------------------- /flux/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine AS build 2 | # renovate: datasource=github-releases depName=fluxcd/flux2 3 | ENV VERSION=2.1.2 4 | ENV CHECKSUM=61b360b50d6cfc34410730b1cebeb75f5eda2b484e47b9a083412f51ad56de68 5 | 6 | ADD https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_amd64.tar.gz /tmp 7 | RUN DOWNLOAD_FILE="/tmp/flux_${VERSION}_linux_amd64.tar.gz" && \ 8 | DOWNLOAD_CHECKSUM=$(sha256sum "${DOWNLOAD_FILE}" | awk '{print $1}') && \ 9 | if [[ ${DOWNLOAD_CHECKSUM} != ${CHECKSUM} ]]; then \ 10 | echo "Checksum does not match"; \ 11 | exit 1; \ 12 | fi && \ 13 | tar xzf "${DOWNLOAD_FILE}" -C / && \ 14 | rm "${DOWNLOAD_FILE}" 15 | 16 | FROM scratch 17 | COPY --from=build flux . 18 | COPY flux-bootstrap.service . 19 | COPY flux-bootstrap.sh . 20 | COPY run.sh . 21 | -------------------------------------------------------------------------------- /flux/flux-bootstrap.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Bootstrap cluster with Flux 3 | Documentation=https://github.com/kairos-io/community-bundles/blob/main/README.md#flux 4 | After=k3s.service 5 | 6 | [Service] 7 | Type=oneshot 8 | Restart=no 9 | ExecStart=/usr/local/bin/flux-bootstrap.sh 10 | User=root 11 | Group=root 12 | RemainAfterExit=yes 13 | 14 | [Install] 15 | WantedBy=k3s.service 16 | -------------------------------------------------------------------------------- /flux/flux-bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Override with the `flux.env.KUBECONFIG` key if necessary 4 | export KUBECONFIG=/etc/rancher/k3s/k3s.yaml 5 | 6 | # Seconds 7 | short=5 8 | long=900 9 | 10 | configmap=flux-bootstrap 11 | 12 | info () { 13 | echo $'\e[36mINFO\e[0m: ' "$1" 14 | } 15 | 16 | warn() { 17 | echo $'\e[33mWARN\e[0m:' "$1" 18 | } 19 | 20 | error() { 21 | echo $'\e[31mERROR\e[0m:' "$1" 22 | } 23 | 24 | cleanup() { 25 | info "Removing bootstrap configmap" 26 | timeout $short kubectl delete configmap -n default $configmap 27 | } 28 | 29 | # Don't bootstrap if the cluster is already bootstrapped 30 | if flux version &>/dev/null; then 31 | info "Flux is already bootstrapped, exiting..." 32 | exit 0 33 | fi 34 | 35 | # Determine what VCS we need to bootstrap 36 | # Starting in kairos 2.8.15, kairos-agent command returns empty string instead of "null" 37 | for vcs in bitbucket_server git github gitlab; do 38 | # kairos-agent used to return `null` when a key wasn't set, now returns empty. 39 | # we handle both 40 | value=$(kairos-agent config get flux.$vcs 2>/dev/null) 41 | if [[ $value != "null" && -n $value ]]; then 42 | version_control=$vcs 43 | break 44 | fi 45 | done 46 | 47 | if [[ "${version_control}x" == "x" ]]; then 48 | error "Unable to determine what version control provider to use, exiting..." 49 | exit 1 50 | fi 51 | 52 | # Get flux envs and settings for our VCS 53 | mapfile -t envs < <(kairos-agent config get "flux.env" 2>/dev/null) 54 | mapfile -t args < <(kairos-agent config get "flux.$version_control" 2>/dev/null) 55 | declare -a cmdline 56 | 57 | for setting in "${envs[@]}"; do 58 | if [[ $setting != "null" ]] && [[ $setting != "" ]]; then 59 | env=$(echo "$setting" | cut -d: -f1) 60 | value=$(echo "$setting" | sed -n 's/^[^:]*: *//p') 61 | if [[ "${value}x" != "x" ]]; then 62 | export "$env"="$value" 63 | fi 64 | fi 65 | done 66 | 67 | # Set commandline args 68 | for setting in "${args[@]}"; do 69 | if [[ $setting != "null" ]] && [[ $setting != "" ]]; then 70 | arg=$(echo "$setting" | cut -d: -f1) 71 | value=$(echo "$setting" | sed -n 's/^[^:]*: *//p') 72 | if [[ "${value}x" != "x" ]]; then 73 | cmdline+=("--$arg" "$value") 74 | fi 75 | fi 76 | done 77 | 78 | # Try to bootstrap Flux for 30 minutes, sleep 15 seconds between attempts 79 | minutes=30 80 | sleep=15 81 | retry_attempt=1 82 | total_attempts=$(( minutes * 60 / sleep )) 83 | active="false" 84 | 85 | if [[ "${#cmdline[@]}" -eq 0 ]]; then 86 | info "Flux was not configured in cloud-config, not bootstrapping" 87 | exit 0 88 | else 89 | while [[ $retry_attempt -le $total_attempts ]]; do 90 | if [[ "$active" != "true" ]]; then 91 | # Ensure only one host tries to bootstrap, whichever makes the configmap first 92 | if ! timeout $short kubectl version &> /dev/null; then 93 | info "Kubernetes API not ready yet, sleeping" 94 | else 95 | if ! timeout $short kubectl create configmap $configmap --from-literal=hostname="$(hostname)"; then 96 | warn "Unable to create configmap, another node may be active" 97 | fi 98 | 99 | # The configmap exists but we must finally check if the hostname matches 100 | if [[ "$(timeout $short kubectl get configmap -n default $configmap -o jsonpath='{.data.hostname}')" != "$(hostname)" ]]; then 101 | error "Flux bootstrap ConfigMap exists but another node is active, exiting..." 102 | exit 3 103 | fi 104 | 105 | # We must be the active node 106 | active="true" 107 | fi 108 | fi 109 | 110 | if [[ "$active" == "true" ]]; then 111 | if timeout $long flux bootstrap "${version_control/_/-}" "${cmdline[@]}"; then 112 | cleanup 113 | exit 0 114 | fi 115 | fi 116 | 117 | warn "Install attempt $retry_attempt (of $total_attempts) failed, retrying in $sleep seconds" 118 | (( retry_attempt = retry_attempt + 1 )) 119 | sleep $sleep 120 | done 121 | fi 122 | 123 | error "Failed to bootstrap with Flux, timed out ($minutes minutes)" 124 | exit 4 125 | -------------------------------------------------------------------------------- /flux/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | 4 | bin=/usr/local/bin/ 5 | system=/etc/systemd/system/ 6 | 7 | mkdir -p "$bin" 8 | cp flux "$bin" 9 | cp flux-bootstrap.sh "$bin" 10 | cp flux-bootstrap.service "$system" 11 | systemctl enable flux-bootstrap -------------------------------------------------------------------------------- /kairos/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /kairos/assets/crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: kairos 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: kairos-crds 10 | namespace: kairos 11 | spec: 12 | chart: kairos-crds 13 | repo: https://kairos-io.github.io/helm-charts 14 | version: "@VERSION@" 15 | -------------------------------------------------------------------------------- /kairos/assets/entangle-proxy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: entangle 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: entangle 10 | namespace: entangle 11 | spec: 12 | chart: entangle 13 | repo: https://kairos-io.github.io/helm-charts 14 | version: "@VERSION@" 15 | -------------------------------------------------------------------------------- /kairos/assets/entangle.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: entangle 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: entangle 10 | namespace: entangle 11 | spec: 12 | chart: entangle 13 | repo: https://kairos-io.github.io/helm-charts 14 | version: "@VERSION@" 15 | -------------------------------------------------------------------------------- /kairos/assets/osbuilder.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: osbuilder 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: osbuilder 10 | namespace: osbuilder 11 | spec: 12 | chart: osbuilder 13 | repo: https://kairos-io.github.io/helm-charts 14 | version: "@VERSION@" 15 | -------------------------------------------------------------------------------- /kairos/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | getConfig() { 8 | local l=$1 9 | key=$(kairos-agent config get "${l}" | tr -d '\n') 10 | if [ "$key" != "null" ]; then 11 | echo "${key}" 12 | fi 13 | echo 14 | } 15 | 16 | # renovate: depName=entangle repoUrl=https://kairos-io.github.io/helm-charts 17 | ENTANGLE_VERSION="0.2.4" 18 | ENTANGLE_ENABLE="" 19 | # renovate: depName=entangle-proxy repoUrl=https://kairos-io.github.io/helm-charts 20 | ENTANGLEPROXY_VERSION="0.0.5" 21 | ENTANGLEPROXY_ENABLE="" 22 | # renovate: depName=osbuilder repoUrl=https://kairos-io.github.io/helm-charts 23 | OSBUILDER_VERSION="0.6.0" 24 | OSBUILDER_ENABLE="" 25 | 26 | CRDS_VERSION="0.0.13" 27 | 28 | templ() { 29 | local file="$3" 30 | local value="$2" 31 | local sentinel="$1" 32 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 33 | } 34 | 35 | readConfig() { 36 | _version=$(getConfig kairos.crds.version) 37 | if [ "$_version" != "" ]; then 38 | CRDS_VERSION=$_version 39 | fi 40 | _enable=$(getConfig kairos.entangle.enable) 41 | if [ "$_enable" != "" ]; then 42 | ENTANGLE_ENABLE=$_enable 43 | fi 44 | _version=$(getConfig kairos.entangle.version) 45 | if [ "$_version" != "" ]; then 46 | ENTANGLE_VERSION=$_version 47 | fi 48 | _enable=$(getConfig kairos.entangleProxy.enable) 49 | if [ "$_enable" != "" ]; then 50 | ENTANGLEPROXY_ENABLE=$_enable 51 | fi 52 | _version=$(getConfig kairos.entangleProxy.version) 53 | if [ "$_version" != "" ]; then 54 | ENTANGLEPROXY_VERSION=$_version 55 | fi 56 | _enable=$(getConfig kairos.osbuilder.enable) 57 | if [ "$_enable" != "" ]; then 58 | OSBUILDER_ENABLE=$_enable 59 | fi 60 | _version=$(getConfig kairos.osbuilder.version) 61 | if [ "$_version" != "" ]; then 62 | OSBUILDER_VERSION=$_version 63 | fi 64 | } 65 | 66 | mkdir -p "${K3S_MANIFEST_DIR}" 67 | 68 | readConfig 69 | 70 | # Copy manifests, and template them 71 | 72 | templ "VERSION" "${CRDS_VERSION}" assets/crd.yaml 73 | cp -rf assets/crd.yaml "${K3S_MANIFEST_DIR}/kairos-crds.yaml" 74 | 75 | if [ "$ENTANGLE_ENABLE" == "true" ]; then 76 | SRC="assets/entangle.yaml" 77 | FILE=$K3S_MANIFEST_DIR/kairos-entangle.yaml 78 | templ "VERSION" "${ENTANGLE_VERSION}" "${SRC}" 79 | cp -rf "${SRC}" "${FILE}" 80 | fi 81 | 82 | if [ "$ENTANGLEPROXY_ENABLE" == "true" ]; then 83 | SRC="assets/entangle-proxy.yaml" 84 | FILE=$K3S_MANIFEST_DIR/kairos-entangle-proxy.yaml 85 | templ "VERSION" "${ENTANGLEPROXY_VERSION}" "${SRC}" 86 | cp -rf "${SRC}" "${FILE}" 87 | fi 88 | 89 | if [ "$OSBUILDER_ENABLE" == "true" ]; then 90 | SRC="assets/osbuilder.yaml" 91 | FILE="${K3S_MANIFEST_DIR}/kairos-osbuilder.yaml" 92 | templ "VERSION" "${OSBUILDER_VERSION}" "${SRC}" 93 | cp -rf "${SRC}" "${FILE}" 94 | fi 95 | -------------------------------------------------------------------------------- /kubevirt/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | COPY ./kubevirt-manager-manifests /kubevirt-manager-manifests -------------------------------------------------------------------------------- /kubevirt/assets/cdi-cr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cdi.kubevirt.io/v1beta1 2 | kind: CDI 3 | metadata: 4 | name: cdi 5 | spec: 6 | imagePullPolicy: IfNotPresent 7 | infra: 8 | nodeSelector: 9 | kubernetes.io/os: linux 10 | tolerations: 11 | - key: CriticalAddonsOnly 12 | operator: Exists 13 | workload: 14 | nodeSelector: 15 | kubernetes.io/os: linux 16 | -------------------------------------------------------------------------------- /kubevirt/assets/kubevirt-cr.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kubevirt.io/v1 3 | kind: KubeVirt 4 | metadata: 5 | name: kubevirt 6 | namespace: kubevirt 7 | spec: 8 | certificateRotateStrategy: {} 9 | configuration: 10 | developerConfiguration: 11 | featureGates: [] 12 | customizeComponents: {} 13 | imagePullPolicy: IfNotPresent 14 | workloadUpdateStrategy: {} 15 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/cdi-cr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cdi.kubevirt.io/v1beta1 2 | kind: CDI 3 | metadata: 4 | name: cdi 5 | spec: 6 | config: 7 | featureGates: 8 | - HonorWaitForFirstConsumer 9 | imagePullPolicy: IfNotPresent 10 | infra: 11 | nodeSelector: 12 | kubernetes.io/os: linux 13 | tolerations: 14 | - key: CriticalAddonsOnly 15 | operator: Exists 16 | workload: 17 | nodeSelector: 18 | kubernetes.io/os: linux 19 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-cr.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kubevirt.io/v1 3 | kind: KubeVirt 4 | metadata: 5 | name: kubevirt 6 | namespace: kubevirt 7 | spec: 8 | certificateRotateStrategy: {} 9 | configuration: 10 | developerConfiguration: 11 | featureGates: 12 | - ExpandDisks 13 | customizeComponents: {} 14 | imagePullPolicy: IfNotPresent 15 | workloadUpdateStrategy: {} 16 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-bundled.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: kubevirt-manager 6 | labels: 7 | app: kubevirt-manager 8 | kubevirt-manager.io/version: 1.1.2 9 | 10 | --- 11 | apiVersion: v1 12 | kind: ServiceAccount 13 | metadata: 14 | name: kubevirt-manager 15 | namespace: kubevirt-manager 16 | labels: 17 | app: kubevirt-manager 18 | kubevirt-manager.io/version: 1.1.2 19 | 20 | --- 21 | apiVersion: rbac.authorization.k8s.io/v1 22 | kind: ClusterRole 23 | metadata: 24 | name: kubevirt-manager 25 | 26 | rules: 27 | - apiGroups: [""] 28 | resources: ["nodes", "namespaces"] 29 | verbs: ["get", "list"] 30 | - apiGroups: [""] 31 | resources: ["customresourcedefinitions"] 32 | verbs: ["get", "list"] 33 | - apiGroups: [""] 34 | resources: ["persistentvolumeclaims", "persistentvolumes", "services"] 35 | verbs: ["*"] 36 | - apiGroups: ["storage.k8s.io"] 37 | resources: ["storageclasses"] 38 | verbs: ["get", "list"] 39 | - apiGroups: ["apiextensions.k8s.io"] 40 | resources: ["customresourcedefinitions"] 41 | verbs: ["get", "list"] 42 | - apiGroups: ["k8s.cni.cncf.io"] 43 | resources: ["network-attachment-definitions"] 44 | verbs: ["get", "list"] 45 | - apiGroups: ["kubevirt.io"] 46 | resources: ["virtualmachines", "virtualmachineinstances"] 47 | verbs: ["*"] 48 | - apiGroups: ["subresources.kubevirt.io"] 49 | resources: ["*"] 50 | verbs: ["get", "list", "update", "patch"] 51 | - apiGroups: ["instancetype.kubevirt.io"] 52 | resources: ["*"] 53 | verbs: ["*"] 54 | - apiGroups: ["cdi.kubevirt.io"] 55 | resources: ["*"] 56 | verbs: ["*"] 57 | - apiGroups: ["pool.kubevirt.io"] 58 | resources: ["*"] 59 | verbs: ["*"] 60 | - apiGroups: ["scheduling.k8s.io"] 61 | resources: ["priorityclasses"] 62 | verbs: ["get", "list"] 63 | 64 | --- 65 | apiVersion: rbac.authorization.k8s.io/v1 66 | kind: ClusterRoleBinding 67 | metadata: 68 | name: kubevirt-manager 69 | labels: 70 | app: kubevirt-manager 71 | kubevirt-manager.io/version: 1.1.2 72 | roleRef: 73 | apiGroup: rbac.authorization.k8s.io 74 | kind: ClusterRole 75 | name: kubevirt-manager 76 | subjects: 77 | - kind: ServiceAccount 78 | name: kubevirt-manager 79 | namespace: kubevirt-manager 80 | 81 | --- 82 | apiVersion: scheduling.k8s.io/v1 83 | kind: PriorityClass 84 | description: Priority class for VMs which should not be preemtited. 85 | metadata: 86 | name: vm-standard 87 | labels: 88 | app: kubevirt-manager 89 | kubevirt-manager.io/version: 1.1.2 90 | kubevirt-manager.io/managed: "true" 91 | preemptionPolicy: Never 92 | value: 999999999 93 | 94 | --- 95 | apiVersion: scheduling.k8s.io/v1 96 | kind: PriorityClass 97 | description: Priority class for VMs which are allowed to be preemtited. 98 | metadata: 99 | name: vm-preemptible 100 | labels: 101 | app: kubevirt-manager 102 | kubevirt-manager.io/version: 1.1.2 103 | kubevirt-manager.io/managed: "true" 104 | preemptionPolicy: PreemptLowerPriority 105 | value: 1000000 106 | 107 | --- 108 | apiVersion: apps/v1 109 | kind: Deployment 110 | metadata: 111 | name: kubevirt-manager 112 | namespace: kubevirt-manager 113 | labels: 114 | app: kubevirt-manager 115 | kubevirt-manager.io/version: 1.1.2 116 | spec: 117 | selector: 118 | matchLabels: 119 | app: kubevirt-manager 120 | kubevirt-manager.io/version: 1.1.2 121 | replicas: 1 122 | strategy: 123 | type: Recreate 124 | template: 125 | metadata: 126 | labels: 127 | app: kubevirt-manager 128 | kubevirt-manager.io/version: 1.1.2 129 | spec: 130 | containers: 131 | - name: kubevirtmgr 132 | image: kubevirtmanager/kubevirt-manager:1.1.2 133 | imagePullPolicy: IfNotPresent 134 | ports: 135 | - name: http 136 | containerPort: 8080 137 | securityContext: 138 | allowPrivilegeEscalation: false 139 | readOnlyRootFilesystem: true 140 | runAsUser: 10000 141 | runAsGroup: 30000 142 | volumeMounts: 143 | - name: cache-volume 144 | mountPath: /var/cache/nginx 145 | - name: run-volume 146 | mountPath: /var/run 147 | serviceAccountName: kubevirt-manager 148 | restartPolicy: Always 149 | volumes: 150 | - name: cache-volume 151 | emptyDir: {} 152 | - name: run-volume 153 | emptyDir: {} 154 | 155 | --- 156 | apiVersion: v1 157 | kind: Service 158 | metadata: 159 | name: kubevirt-manager 160 | namespace: kubevirt-manager 161 | labels: 162 | app: kubevirt-manager 163 | kubevirt-manager.io/version: 1.1.2 164 | spec: 165 | type: ClusterIP 166 | selector: 167 | app: kubevirt-manager 168 | ports: 169 | - protocol: TCP 170 | port: 8080 171 | targetPort: 8080 -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kubevirt-manager 5 | namespace: kubevirt-manager 6 | labels: 7 | app: kubevirt-manager 8 | kubevirt-manager.io/version: 1.1.2 9 | spec: 10 | selector: 11 | matchLabels: 12 | app: kubevirt-manager 13 | kubevirt-manager.io/version: 1.1.2 14 | replicas: 1 15 | strategy: 16 | type: Recreate 17 | template: 18 | metadata: 19 | labels: 20 | app: kubevirt-manager 21 | kubevirt-manager.io/version: 1.1.2 22 | spec: 23 | containers: 24 | - name: kubevirtmgr 25 | image: kubevirtmanager/kubevirt-manager:1.1.2 26 | imagePullPolicy: IfNotPresent 27 | ports: 28 | - name: http 29 | containerPort: 8080 30 | securityContext: 31 | allowPrivilegeEscalation: false 32 | readOnlyRootFilesystem: true 33 | runAsUser: 10000 34 | runAsGroup: 30000 35 | volumeMounts: 36 | - name: cache-volume 37 | mountPath: /var/cache/nginx 38 | - name: run-volume 39 | mountPath: /var/run 40 | serviceAccountName: kubevirt-manager 41 | restartPolicy: Always 42 | volumes: 43 | - name: cache-volume 44 | emptyDir: {} 45 | - name: run-volume 46 | emptyDir: {} 47 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: kubevirt-manager 5 | namespace: kubevirt-manager 6 | annotations: 7 | nginx.org/location-snippets: | 8 | proxy_set_header Upgrade $http_upgrade; 9 | proxy_set_header Connection $connection_upgrade; 10 | spec: 11 | ingressClassName: my-ingress-class 12 | tls: 13 | - hosts: 14 | - my-host.com 15 | rules: 16 | - host: my-host.com 17 | http: 18 | paths: 19 | - path: / 20 | pathType: Prefix 21 | backend: 22 | service: 23 | name: kubevirt-manager 24 | port: 25 | number: 8080 26 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-ns.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: kubevirt-manager 5 | labels: 6 | app: kubevirt-manager 7 | kubevirt-manager.io/version: 1.1.2 -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-pc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scheduling.k8s.io/v1 2 | kind: PriorityClass 3 | description: Priority class for VMs which should not be preemtited. 4 | metadata: 5 | name: vm-standard 6 | labels: 7 | app: kubevirt-manager 8 | kubevirt-manager.io/version: 1.1.2 9 | kubevirt-manager.io/managed: "true" 10 | preemptionPolicy: Never 11 | value: 999999999 12 | 13 | --- 14 | apiVersion: scheduling.k8s.io/v1 15 | kind: PriorityClass 16 | description: Priority class for VMs which are allowed to be preemtited. 17 | metadata: 18 | name: vm-preemptible 19 | labels: 20 | app: kubevirt-manager 21 | kubevirt-manager.io/version: 1.1.2 22 | kubevirt-manager.io/managed: "true" 23 | preemptionPolicy: PreemptLowerPriority 24 | value: 1000000 25 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kubevirt-manager 5 | namespace: kubevirt-manager 6 | labels: 7 | app: kubevirt-manager 8 | kubevirt-manager.io/version: 1.1.2 9 | 10 | --- 11 | apiVersion: rbac.authorization.k8s.io/v1 12 | kind: ClusterRole 13 | metadata: 14 | name: kubevirt-manager 15 | rules: 16 | - apiGroups: [""] 17 | resources: ["nodes", "namespaces"] 18 | verbs: ["get", "list"] 19 | - apiGroups: [""] 20 | resources: ["customresourcedefinitions"] 21 | verbs: ["get", "list"] 22 | - apiGroups: [""] 23 | resources: ["persistentvolumeclaims", "persistentvolumes", "services"] 24 | verbs: ["*"] 25 | - apiGroups: ["storage.k8s.io"] 26 | resources: ["storageclasses"] 27 | verbs: ["get", "list"] 28 | - apiGroups: ["apiextensions.k8s.io"] 29 | resources: ["customresourcedefinitions"] 30 | verbs: ["get", "list"] 31 | - apiGroups: ["k8s.cni.cncf.io"] 32 | resources: ["network-attachment-definitions"] 33 | verbs: ["get", "list"] 34 | - apiGroups: ["kubevirt.io"] 35 | resources: ["virtualmachines", "virtualmachineinstances"] 36 | verbs: ["*"] 37 | - apiGroups: ["subresources.kubevirt.io"] 38 | resources: ["*"] 39 | verbs: ["get", "list", "update", "patch"] 40 | - apiGroups: ["instancetype.kubevirt.io"] 41 | resources: ["*"] 42 | verbs: ["*"] 43 | - apiGroups: ["cdi.kubevirt.io"] 44 | resources: ["*"] 45 | verbs: ["*"] 46 | - apiGroups: ["pool.kubevirt.io"] 47 | resources: ["*"] 48 | verbs: ["*"] 49 | - apiGroups: ["scheduling.k8s.io"] 50 | resources: ["priorityclasses"] 51 | verbs: ["get", "list"] 52 | 53 | --- 54 | apiVersion: rbac.authorization.k8s.io/v1 55 | kind: ClusterRoleBinding 56 | metadata: 57 | name: kubevirt-manager 58 | labels: 59 | app: kubevirt-manager 60 | kubevirt-manager.io/version: 1.1.1 61 | roleRef: 62 | apiGroup: rbac.authorization.k8s.io 63 | kind: ClusterRole 64 | name: kubevirt-manager 65 | subjects: 66 | - kind: ServiceAccount 67 | name: kubevirt-manager 68 | namespace: kubevirt-manager 69 | -------------------------------------------------------------------------------- /kubevirt/kubevirt-manager-manifests/kubevirt-manager-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: kubevirt-manager 5 | namespace: kubevirt-manager 6 | labels: 7 | app: kubevirt-manager 8 | kubevirt-manager.io/version: 1.1.2 9 | spec: 10 | type: ClusterIP 11 | selector: 12 | app: kubevirt-manager 13 | ports: 14 | - protocol: TCP 15 | port: 8080 16 | targetPort: 8080 -------------------------------------------------------------------------------- /kubevirt/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | getConfig() { 8 | local l=$1 9 | key=$(kairos-agent config get "${l}" | tr -d '\n') 10 | if [ "$key" != "null" ]; then 11 | echo "${key}" 12 | fi 13 | echo 14 | } 15 | 16 | KUBEVIRT_MANAGER="false" 17 | 18 | templ() { 19 | local file="$3" 20 | local value="$2" 21 | local sentinel="$1" 22 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 23 | } 24 | 25 | readConfig() { 26 | _manager=$(getConfig kubevirt.manager) 27 | if [ "$_manager" != "" ]; then 28 | KUBEVIRT_MANAGER=$_manager 29 | fi 30 | } 31 | 32 | mkdir -p "${K3S_MANIFEST_DIR}" 33 | 34 | readConfig 35 | 36 | # Copy manifests from kubevirt 37 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 38 | 39 | if [ "$KUBEVIRT_MANAGER" == "true" ]; then 40 | cp -rf kubevirt-manager-manifests/* "${K3S_MANIFEST_DIR}" 41 | fi 42 | -------------------------------------------------------------------------------- /kyverno/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /kyverno/assets/kyverno.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: kyverno 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: kyverno 10 | namespace: kyverno 11 | spec: 12 | name: kyverno 13 | chart: kyverno 14 | repo: https://kyverno.github.io/kyverno/ 15 | valuesContent: |- 16 | @VALUES@ 17 | version: "@VERSION@" 18 | -------------------------------------------------------------------------------- /kyverno/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | 8 | getConfig() { 9 | local key=$1 10 | _value=$(kairos-agent config get "${key} | @json" | tr -d '\n') 11 | # Remove the quotes wrapping the value. 12 | _value=${_value:1:${#_value}-2} 13 | if [ "${_value}" != "null" ]; then 14 | echo "${_value}" 15 | fi 16 | echo 17 | } 18 | 19 | VALUES="{}" 20 | # renovate: depName=kyverno repoUrl=https://kyverno.github.io/kyverno/ 21 | VERSION="3.2.7" 22 | 23 | templ() { 24 | local file="$3" 25 | local value=$2 26 | local sentinel=$1 27 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 28 | } 29 | 30 | readConfig() { 31 | _values=$(getConfig kyverno.values) 32 | if [ "$_values" != "" ]; then 33 | VALUES=$_values 34 | fi 35 | _version=$(getConfig kyverno.version) 36 | if [ "$_version" != "" ]; then 37 | VERSION=$_version 38 | fi 39 | } 40 | 41 | mkdir -p "${K3S_MANIFEST_DIR}" 42 | 43 | readConfig 44 | 45 | # Copy manifests, and template them 46 | for FILE in assets/*; do 47 | templ "VALUES" "${VALUES}" "${FILE}" 48 | templ "VERSION" "${VERSION}" "${FILE}" 49 | done; 50 | 51 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 52 | -------------------------------------------------------------------------------- /longhorn/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /longhorn/assets/longhorn.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: longhorn-system 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: longhorn 10 | namespace: longhorn-system 11 | spec: 12 | chart: longhorn 13 | repo: https://charts.longhorn.io 14 | valuesContent: |- 15 | @VALUES@ 16 | version: @VERSION@ 17 | -------------------------------------------------------------------------------- /longhorn/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | 8 | getConfig() { 9 | local key=$1 10 | _value=$(kairos-agent config get "${key} | @json" | tr -d '\n') 11 | # Remove the quotes wrapping the value. 12 | _value=${_value:1:${#_value}-2} 13 | if [ "${_value}" != "null" ]; then 14 | echo "${_value}" 15 | fi 16 | echo 17 | } 18 | 19 | VALUES="{}" 20 | # renovate: depName=longhorn repoUrl=https://charts.longhorn.io 21 | VERSION="1.5.3" 22 | 23 | templ() { 24 | local file="$3" 25 | local value=$2 26 | local sentinel=$1 27 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 28 | } 29 | 30 | readConfig() { 31 | _values=$(getConfig longhorn.values) 32 | if [ "$_values" != "" ]; then 33 | VALUES=$_values 34 | fi 35 | _version=$(getConfig longhorn.version) 36 | if [ "$_version" != "" ]; then 37 | VERSION=$_version 38 | fi 39 | } 40 | 41 | mkdir -p "${K3S_MANIFEST_DIR}" 42 | 43 | readConfig 44 | 45 | # Copy manifests, and template them 46 | for FILE in assets/*; do 47 | templ "VALUES" "${VALUES}" "${FILE}" 48 | templ "VERSION" "${VERSION}" "${FILE}" 49 | done; 50 | 51 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 52 | -------------------------------------------------------------------------------- /metallb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /metallb/assets/addresspool.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metallb.io/v1beta1 2 | kind: IPAddressPool 3 | metadata: 4 | name: default 5 | namespace: metallb-system 6 | spec: 7 | addresses: 8 | - @ADDRESS_POOL@ 9 | --- 10 | apiVersion: metallb.io/v1beta1 11 | kind: L2Advertisement 12 | metadata: 13 | name: default 14 | namespace: metallb-system 15 | spec: 16 | ipAddressPools: 17 | - default -------------------------------------------------------------------------------- /metallb/assets/metallb.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: metallb-system 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: metallb 10 | namespace: metallb-system 11 | spec: 12 | chart: metallb 13 | repo: https://metallb.github.io/metallb 14 | version: "@VERSION@" 15 | -------------------------------------------------------------------------------- /metallb/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | getConfig() { 8 | local l=$1 9 | key=$(kairos-agent config get "${l}" | tr -d '\n') 10 | if [ "$key" != "null" ]; then 11 | echo "${key}" 12 | fi 13 | echo 14 | } 15 | 16 | # renovate: depName=metallb repoUrl=https://metallb.github.io/metallb 17 | VERSION="0.14.9" 18 | ADDRESS_POOL="192.168.1.10-192.168.1.20" 19 | 20 | templ() { 21 | local file="$3" 22 | local value="$2" 23 | local sentinel="$1" 24 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 25 | } 26 | 27 | readConfig() { 28 | _version=$(getConfig metallb.version) 29 | if [ "$_version" != "" ]; then 30 | VERSION=$_version 31 | fi 32 | _addresspool=$(getConfig metallb.address_pool) 33 | if [ "$_version" != "" ]; then 34 | ADDRESS_POOL=$_addresspool 35 | fi 36 | } 37 | 38 | mkdir -p "${K3S_MANIFEST_DIR}" 39 | 40 | readConfig 41 | 42 | # Copy manifests, and template them 43 | for FILE in assets/*; do 44 | templ "VERSION" "${VERSION}" "${FILE}" 45 | templ "ADDRESS_POOL" "${ADDRESS_POOL}" "${FILE}" 46 | done; 47 | 48 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 49 | -------------------------------------------------------------------------------- /multus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as builder 2 | 3 | ARG TARGETARCH 4 | 5 | # renovate: datasource=github-releases depName=k8snetworkplumbingwg/multus-cni extractVersion=^v(?.*)$ 6 | ARG MULTUS_VERSION=4.0.2 7 | 8 | # renovate: datasource=github-releases depName=containernetworking/plugins extractVersion=^v(?.*)$ 9 | ARG PLUGINS_VERSION=1.3.0 10 | 11 | WORKDIR /build 12 | 13 | RUN apk add curl && \ 14 | curl -fsSL --remote-name-all \ 15 | https://github.com/k8snetworkplumbingwg/multus-cni/releases/download/v${MULTUS_VERSION}/{checksums.txt,multus-cni_${MULTUS_VERSION}_linux_${TARGETARCH}.tar.gz} \ 16 | https://github.com/containernetworking/plugins/releases/download/v${PLUGINS_VERSION}/cni-plugins-linux-${TARGETARCH}-v${PLUGINS_VERSION}.tgz{.sha256,} && \ 17 | grep ${TARGETARCH} checksums.txt | sha256sum -cs && \ 18 | sha256sum -cs cni-plugins-linux-${TARGETARCH}-v${PLUGINS_VERSION}.tgz.sha256 && \ 19 | tar -xf multus-cni_${MULTUS_VERSION}_linux_${TARGETARCH}.tar.gz --strip-components 1 \ 20 | multus-cni_${MULTUS_VERSION}_linux_${TARGETARCH}/multus && \ 21 | mkdir plugins && \ 22 | tar -xC plugins -f cni-plugins-linux-${TARGETARCH}-v${PLUGINS_VERSION}.tgz 23 | 24 | FROM scratch 25 | 26 | COPY --from=builder /build/multus /multus 27 | COPY --from=builder /build/plugins /plugins 28 | COPY ./manifests.yaml / 29 | COPY ./run.sh / 30 | -------------------------------------------------------------------------------- /multus/manifests.yaml: -------------------------------------------------------------------------------- 1 | # Taken from https://github.com/k8snetworkplumbingwg/multus-cni/blob/v4.0.2/deployments/multus-daemonset.yml 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: network-attachment-definitions.k8s.cni.cncf.io 7 | spec: 8 | group: k8s.cni.cncf.io 9 | scope: Namespaced 10 | names: 11 | plural: network-attachment-definitions 12 | singular: network-attachment-definition 13 | kind: NetworkAttachmentDefinition 14 | shortNames: 15 | - net-attach-def 16 | versions: 17 | - name: v1 18 | served: true 19 | storage: true 20 | schema: 21 | openAPIV3Schema: 22 | description: >- 23 | NetworkAttachmentDefinition is a CRD schema specified by the Network 24 | Plumbing Working Group to express the intent for attaching pods to one or 25 | more logical or physical networks. More information available at: 26 | https://github.com/k8snetworkplumbingwg/multi-net-spec 27 | type: object 28 | properties: 29 | apiVersion: 30 | description: >- 31 | APIVersion defines the versioned schema of this representation of an 32 | object. Servers should convert recognized schemas to the latest 33 | internal value, and may reject unrecognized values. More info: 34 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 35 | type: string 36 | kind: 37 | description: >- 38 | Kind is a string value representing the REST resource this object 39 | represents. Servers may infer this from the endpoint the client 40 | submits requests to. Cannot be updated. In CamelCase. More info: 41 | https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 42 | type: string 43 | metadata: 44 | type: object 45 | spec: 46 | description: >- 47 | NetworkAttachmentDefinition spec defines the desired state of a 48 | network attachment 49 | type: object 50 | properties: 51 | config: 52 | description: >- 53 | NetworkAttachmentDefinition config is a JSON-formatted CNI 54 | configuration 55 | type: string 56 | --- 57 | apiVersion: rbac.authorization.k8s.io/v1 58 | kind: ClusterRole 59 | metadata: 60 | name: multus 61 | rules: 62 | - apiGroups: ["k8s.cni.cncf.io"] 63 | resources: ["*"] 64 | verbs: ["*"] 65 | - apiGroups: [""] 66 | resources: [pods, pods/status] 67 | verbs: [get, update] 68 | - apiGroups: ["", events.k8s.io] 69 | resources: [events] 70 | verbs: [create, patch, update] 71 | --- 72 | apiVersion: rbac.authorization.k8s.io/v1 73 | kind: ClusterRoleBinding 74 | metadata: 75 | name: multus 76 | roleRef: 77 | apiGroup: rbac.authorization.k8s.io 78 | kind: ClusterRole 79 | name: multus 80 | subjects: 81 | - kind: User 82 | name: multus 83 | apiGroup: rbac.authorization.k8s.io 84 | -------------------------------------------------------------------------------- /multus/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests} 6 | CNI_BIN_DIR=/opt/cni/bin 7 | MULTUS_BIN_DIR=/var/lib/rancher/k3s/data/current/bin 8 | CNI_CONF_DIR=/var/lib/rancher/k3s/agent/etc/cni/net.d 9 | CA_PATH=/var/lib/rancher/k3s/server/tls 10 | 11 | getConfig() { 12 | local l=$1 13 | key=$(kairos-agent config get "${l}") 14 | if [[ $key != "null" ]]; then 15 | echo "${key}" 16 | fi 17 | echo 18 | } 19 | 20 | CNI_PLUGINS= 21 | CRT_VALIDITY=3650 22 | NAMESPACE_ISOLATION=false 23 | GLOBAL_NAMESPACES= 24 | PRIMARY_CONFIG= 25 | 26 | readConfig() { 27 | _cni_plugins=$(getConfig multus.cni_plugins[]?) 28 | if [[ $_cni_plugins != "" ]]; then 29 | CNI_PLUGINS=$_cni_plugins 30 | fi 31 | 32 | _crt_validity=$(getConfig multus.crt_validity) 33 | if [[ $_crt_validity != "" ]]; then 34 | CRT_VALIDITY=$_crt_validity 35 | fi 36 | 37 | _namespace_isolation=$(getConfig multus.namespace_isolation) 38 | if [[ $_namespace_isolation != "" ]]; then 39 | NAMESPACE_ISOLATION=$_namespace_isolation 40 | fi 41 | 42 | _global_namespaces=$(getConfig multus.global_namespaces[]?) 43 | if [[ $_global_namespaces != "" ]]; then 44 | GLOBAL_NAMESPACES=${_global_namespaces//[[:space:]]/,} 45 | fi 46 | 47 | _primary_config=$(getConfig multus.primary_config) 48 | if [[ $_primary_config != "" ]]; then 49 | PRIMARY_CONFIG=$_primary_config 50 | else 51 | for config in "${CNI_CONF_DIR}"/*.conflist; do 52 | if [[ $config != "${CNI_CONF_DIR}/00-multus.conflist" ]]; then 53 | PRIMARY_CONFIG=$config 54 | break; 55 | fi 56 | done 57 | fi 58 | } 59 | 60 | createDirectories() { 61 | mkdir -p \ 62 | "${CNI_BIN_DIR}" \ 63 | "${MULTUS_BIN_DIR}" \ 64 | "${K3S_MANIFEST_DIR}" \ 65 | "${CNI_CONF_DIR}/multus.d" 66 | } 67 | 68 | install() { 69 | cp multus "${MULTUS_BIN_DIR}" 70 | } 71 | 72 | installPlugins() { 73 | for plugin in $CNI_PLUGINS; do 74 | cp "plugins/${plugin}" "${CNI_BIN_DIR}" 75 | done 76 | } 77 | 78 | createManifests() { 79 | cp manifests.yaml "${K3S_MANIFEST_DIR}/multus.yaml" 80 | } 81 | 82 | createKubeConfig() { 83 | openssl ecparam -name prime256v1 -genkey -noout -out multus.key 84 | openssl req -new -key multus.key -out multus.csr -subj /CN=multus 85 | openssl x509 -req \ 86 | -in multus.csr \ 87 | -CA "${CA_PATH}/client-ca.crt" \ 88 | -CAkey "${CA_PATH}/client-ca.key" \ 89 | -CAcreateserial \ 90 | -out multus.crt \ 91 | -days "${CRT_VALIDITY}" 92 | 93 | cat > "${CNI_CONF_DIR}/multus.d/multus.kubeconfig" < "${CNI_CONF_DIR}/00-multus.conflist" \ 120 | --arg namespaceIsolation "${NAMESPACE_ISOLATION}" \ 121 | --arg globalNamespaces "${GLOBAL_NAMESPACES}" \ 122 | --arg kubeconfig "${CNI_CONF_DIR}/multus.d/multus.kubeconfig" \ 123 | ' 124 | { 125 | cniVersion: .cniVersion, 126 | name: "multus-cni-network", 127 | plugins: [{ 128 | type: "multus", 129 | capabilities: [.plugins[].capabilities] | add, 130 | namespaceIsolation: ($namespaceIsolation == "true"), 131 | globalNamespaces: $globalNamespaces, 132 | kubeconfig: $kubeconfig, 133 | delegates: [.] 134 | }] 135 | } 136 | ' 137 | 138 | chmod 600 "${CNI_CONF_DIR}/00-multus.conflist" 139 | } 140 | 141 | readConfig 142 | createDirectories 143 | install 144 | installPlugins 145 | createManifests 146 | createKubeConfig 147 | createConfig 148 | -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /nginx/assets/ingress-nginx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ingress-nginx 5 | --- 6 | apiVersion: helm.cattle.io/v1 7 | kind: HelmChart 8 | metadata: 9 | name: ingress-nginx 10 | namespace: ingress-nginx 11 | spec: 12 | repo: https://kubernetes.github.io/ingress-nginx 13 | chart: ingress-nginx 14 | valuesContent: |- 15 | @VALUES@ 16 | version: "@VERSION@" 17 | targetNamespace: ingress-nginx 18 | -------------------------------------------------------------------------------- /nginx/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | VALUES="{}" 8 | # renovate: depName=ingress-nginx repoUrl=https://kubernetes.github.io/ingress-nginx 9 | VERSION="4.11.3" 10 | 11 | templ() { 12 | local file="$3" 13 | local value="$2" 14 | local sentinel="$1" 15 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 16 | } 17 | 18 | _version=$(kairos-agent config get "nginx.version" | tr -d '\n') 19 | if [ "$_version" != "null" ]; then 20 | VERSION=$_version 21 | fi 22 | _values=$(kairos-agent config get "nginx.values | @json" | tr -d '\n') 23 | # Remove the quotes wrapping the value. 24 | _values=${_values:1:${#_values}-2} 25 | if [ "$_values" != "null" ]; then 26 | VALUES=$_values 27 | fi 28 | 29 | templ "VERSION" "${VERSION}" "assets/ingress-nginx.yaml" 30 | templ "VALUES" "${VALUES}" "assets/ingress-nginx.yaml" 31 | 32 | mkdir -p "${K3S_MANIFEST_DIR}" 33 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 34 | -------------------------------------------------------------------------------- /openamt/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/kairos-io/openamt:v0.1.0-beta1 as src 2 | FROM scratch 3 | 4 | COPY --from=src /* / 5 | COPY ./run.sh / 6 | -------------------------------------------------------------------------------- /openamt/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | if [ -n "$(kairos-agent config get amt | head -n1)" ] 6 | then 7 | kairos-agent config get amt | ./agent-provider-amt 8 | fi 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "schedule": [ 5 | "after 11pm every weekday", 6 | "before 7am every weekday", 7 | "every weekend" 8 | ], 9 | "timezone": "Europe/Brussels", 10 | "packageRules": [ 11 | { 12 | "matchUpdateTypes": ["patch"], 13 | "automerge": true 14 | } 15 | ], 16 | "regexManagers": [ 17 | { 18 | "fileMatch": ["^Earthfile$", "Dockerfile$"], 19 | "matchStrings": [ 20 | "#\\s*renovate:\\s*datasource=(?[^\\s]+)\\s+depName=(?[^\\s]+)(\\s+versioning=(?[^\\s]+))?(\\s+extractVersion=(?[^\\n]+))?(\\s+extractVersionTemplate=(?[^\\n]+))?\\n(ARG|ENV)\\s+([^\\s]+)?VERSION=(?[^\\n]+)(\\n(ARG|ENV)\\s+([^\\s]+)?)" 21 | ], 22 | "versioningTemplate": "{{#if versioning}}{{versioning}}{{else}}semver{{/if}}" 23 | }, 24 | { 25 | "fileMatch": ["^earthly\\.(sh|ps1)$"], 26 | "datasourceTemplate": "docker", 27 | "depNameTemplate": "earthly/earthly", 28 | "matchStrings": ["earthly\\/earthly:(?.*?)\\s"], 29 | "versioningTemplate": "semver-coerced" 30 | }, 31 | { 32 | "datasourceTemplate": "helm", 33 | "fileMatch": ["^.+/run\\.sh$"], 34 | "matchStrings": [ 35 | "#\\s*renovate:\\s*depName=(?.*?)(\\s+repoUrl=(?.*?))?\\s([A-Z0-9_]*)VERSION=\"(?.*?)\"\\s" 36 | ] 37 | }, 38 | { 39 | "datasourceTemplate": "helm", 40 | "fileMatch": ["^tests/.+_test\\.go$"], 41 | "matchStrings": [ 42 | "//\\s*renovate:\\s*depName=(?.*?)(\\s+repoUrl=(?.*?))?\\s+.*version: \\\\\"(?.*?)\\\\\"\"" 43 | ] 44 | } 45 | ], 46 | "ignorePaths": [] 47 | } 48 | -------------------------------------------------------------------------------- /spinkube/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 AS builder 2 | 3 | ARG spin_operator_version=0.4.0 4 | ARG kwasm_installer_version=0.17.0 5 | ARG cert_manager_version=1.14.5 6 | 7 | RUN apk update && apk add --no-cache helm 8 | 9 | WORKDIR /assets 10 | 11 | # This follows the SpinKube documentation: 12 | # https://www.spinkube.dev/docs/install/installing-with-helm/ 13 | RUN < kwasm-operator-${kwasm_installer_version}.yaml 24 | 25 | # Spin Operator CRDs 26 | wget -O spin-operator-${spin_operator_version}.crds.yaml https://github.com/spinkube/spin-operator/releases/download/v${spin_operator_version}/spin-operator.crds.yaml 27 | 28 | # Spin Operator Runtime Class 29 | wget -O spin-operator-${spin_operator_version}.runtime-class.yaml https://github.com/spinkube/spin-operator/releases/download/v${spin_operator_version}/spin-operator.runtime-class.yaml 30 | 31 | # Spin Operator Shim Executor 32 | wget -O spin-operator-${spin_operator_version}.shim-executor.yaml https://github.com/spinkube/spin-operator/releases/download/v${spin_operator_version}/spin-operator.shim-executor.yaml 33 | 34 | # Spin Operator (namespace set in run.sh, as is the wait command) 35 | helm template spin-operator \ 36 | --namespace spin-operator \ 37 | --version ${spin_operator_version} \ 38 | oci://ghcr.io/spinkube/charts/spin-operator \ 39 | > spin-operator-${spin_operator_version}.yaml 40 | EOR 41 | 42 | FROM scratch 43 | COPY --from=builder /assets ./assets 44 | COPY run.sh . -------------------------------------------------------------------------------- /spinkube/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This follows the SpinKube documentation: 4 | # https://www.spinkube.dev/docs/install/installing-with-helm/ 5 | 6 | set -ex 7 | 8 | manifest_dir=assets 9 | 10 | spin_operator_version=0.4.0 11 | kwasm_installer_version=0.17.0 12 | cert_manager_version=1.14.5 13 | 14 | _install_cert_manager=$(kairos-agent config get "spinkube.installCertManager" | tr -d '\n') 15 | if [ "$_install_cert_manager" = "true" ]; then 16 | sudo k3s kubectl apply -f "$manifest_dir/cert-manager-$cert_manager_version.yaml" 17 | 18 | # Wait for the various cert-manager resources to be ready before proceeding 19 | sudo k3s kubectl wait --for=condition=available --timeout=300s deployment/cert-manager -n cert-manager 20 | sudo k3s kubectl wait --for=condition=available --timeout=300s deployment/cert-manager-webhook -n cert-manager 21 | sudo k3s kubectl wait --for=condition=available --timeout=300s deployment/cert-manager-cainjector -n cert-manager 22 | fi 23 | 24 | # Check to make sure the kwasm namespace doesn't already exist 25 | if ! sudo k3s kubectl get namespace kwasm > /dev/null 2>&1; then 26 | sudo k3s kubectl create namespace kwasm 27 | fi 28 | 29 | # Check to make sure the spin-operator namespace doesn't already exist 30 | if ! sudo k3s kubectl get namespace spin-operator > /dev/null 2>&1; then 31 | sudo k3s kubectl create namespace spin-operator 32 | fi 33 | 34 | # Install Kwasm Operator 35 | sudo k3s kubectl apply --namespace kwasm -f "$manifest_dir/kwasm-operator-$kwasm_installer_version.yaml" 36 | 37 | # Provision Nodes 38 | sudo k3s kubectl annotate node --all kwasm.sh/kwasm-node=true 39 | 40 | # Install Spin Operator Resources 41 | sudo k3s kubectl apply -f "$manifest_dir/spin-operator-$spin_operator_version.crds.yaml" 42 | sudo k3s kubectl apply -f "$manifest_dir/spin-operator-$spin_operator_version.runtime-class.yaml" 43 | sudo k3s kubectl apply -f "$manifest_dir/spin-operator-$spin_operator_version.shim-executor.yaml" 44 | 45 | # Install Spin Operator 46 | sudo k3s kubectl apply --namespace spin-operator -f "$manifest_dir/spin-operator-$spin_operator_version.yaml" 47 | # Wait for the spin-operator-controller-manager to be ready 48 | sudo k3s kubectl wait --namespace spin-operator --for=condition=available --timeout=300s deployment/spin-operator-controller-manager -------------------------------------------------------------------------------- /system-upgrade-controller/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine as build 2 | FROM scratch 3 | COPY ./run.sh / 4 | COPY ./assets /assets 5 | -------------------------------------------------------------------------------- /system-upgrade-controller/assets/system-upgrade-controller.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: system-upgrade 5 | --- 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | metadata: 9 | name: system-upgrade 10 | namespace: system-upgrade 11 | --- 12 | apiVersion: rbac.authorization.k8s.io/v1 13 | kind: ClusterRoleBinding 14 | metadata: 15 | name: system-upgrade 16 | roleRef: 17 | apiGroup: rbac.authorization.k8s.io 18 | kind: ClusterRole 19 | name: cluster-admin 20 | subjects: 21 | - kind: ServiceAccount 22 | name: system-upgrade 23 | namespace: system-upgrade 24 | --- 25 | apiVersion: v1 26 | data: 27 | SYSTEM_UPGRADE_CONTROLLER_DEBUG: "false" 28 | SYSTEM_UPGRADE_CONTROLLER_THREADS: "2" 29 | SYSTEM_UPGRADE_JOB_ACTIVE_DEADLINE_SECONDS: "900" 30 | SYSTEM_UPGRADE_JOB_BACKOFF_LIMIT: "99" 31 | SYSTEM_UPGRADE_JOB_IMAGE_PULL_POLICY: Always 32 | SYSTEM_UPGRADE_JOB_KUBECTL_IMAGE: rancher/kubectl:v1.21.9 33 | SYSTEM_UPGRADE_JOB_PRIVILEGED: "true" 34 | SYSTEM_UPGRADE_JOB_TTL_SECONDS_AFTER_FINISH: "900" 35 | SYSTEM_UPGRADE_PLAN_POLLING_INTERVAL: 15m 36 | kind: ConfigMap 37 | metadata: 38 | name: default-controller-env 39 | namespace: system-upgrade 40 | --- 41 | apiVersion: apps/v1 42 | kind: Deployment 43 | metadata: 44 | name: system-upgrade-controller 45 | namespace: system-upgrade 46 | spec: 47 | selector: 48 | matchLabels: 49 | upgrade.cattle.io/controller: system-upgrade-controller 50 | template: 51 | metadata: 52 | labels: 53 | upgrade.cattle.io/controller: system-upgrade-controller 54 | spec: 55 | affinity: 56 | nodeAffinity: 57 | requiredDuringSchedulingIgnoredDuringExecution: 58 | nodeSelectorTerms: 59 | - matchExpressions: 60 | - key: node-role.kubernetes.io/master 61 | operator: Exists 62 | containers: 63 | - env: 64 | - name: SYSTEM_UPGRADE_CONTROLLER_NAME 65 | valueFrom: 66 | fieldRef: 67 | fieldPath: metadata.labels['upgrade.cattle.io/controller'] 68 | - name: SYSTEM_UPGRADE_CONTROLLER_NAMESPACE 69 | valueFrom: 70 | fieldRef: 71 | fieldPath: metadata.namespace 72 | envFrom: 73 | - configMapRef: 74 | name: default-controller-env 75 | image: rancher/system-upgrade-controller:@VERSION@ 76 | imagePullPolicy: IfNotPresent 77 | name: system-upgrade-controller 78 | volumeMounts: 79 | - mountPath: /etc/ssl 80 | name: etc-ssl 81 | - mountPath: /etc/pki 82 | name: etc-pki 83 | - mountPath: /etc/ca-certificates 84 | name: etc-ca-certificates 85 | - mountPath: /tmp 86 | name: tmp 87 | serviceAccountName: system-upgrade 88 | tolerations: 89 | - key: CriticalAddonsOnly 90 | operator: Exists 91 | - effect: NoSchedule 92 | key: node-role.kubernetes.io/master 93 | operator: Exists 94 | - effect: NoSchedule 95 | key: node-role.kubernetes.io/controlplane 96 | operator: Exists 97 | - effect: NoSchedule 98 | key: node-role.kubernetes.io/control-plane 99 | operator: Exists 100 | - effect: NoExecute 101 | key: node-role.kubernetes.io/etcd 102 | operator: Exists 103 | volumes: 104 | - hostPath: 105 | path: /etc/ssl 106 | type: Directory 107 | name: etc-ssl 108 | - hostPath: 109 | path: /etc/pki 110 | type: DirectoryOrCreate 111 | name: etc-pki 112 | - hostPath: 113 | path: /etc/ca-certificates 114 | type: DirectoryOrCreate 115 | name: etc-ca-certificates 116 | - emptyDir: {} 117 | name: tmp -------------------------------------------------------------------------------- /system-upgrade-controller/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | K3S_MANIFEST_DIR=${K3S_MANIFEST_DIR:-/var/lib/rancher/k3s/server/manifests/} 6 | 7 | getConfig() { 8 | local l="$1" 9 | key=$(kairos-agent config get "${l}" | tr -d '\n') 10 | if [ "$key" != "null" ]; then 11 | echo "${key}" 12 | fi 13 | echo 14 | } 15 | 16 | VERSION="v0.10.0" 17 | 18 | templ() { 19 | local file="$3" 20 | local value="$2" 21 | local sentinel="$1" 22 | sed -i "s/@${sentinel}@/${value}/g" "${file}" 23 | } 24 | 25 | readConfig() { 26 | _version=$(getConfig suc.version) 27 | if [ "$_version" != "" ]; then 28 | VERSION=$_version 29 | fi 30 | } 31 | 32 | mkdir -p "${K3S_MANIFEST_DIR}" 33 | 34 | readConfig 35 | 36 | # Copy manifests, and template them 37 | for FILE in assets/*; do 38 | templ "VERSION" "${VERSION}" "${FILE}" 39 | done; 40 | 41 | cp -rf assets/* "${K3S_MANIFEST_DIR}" 42 | -------------------------------------------------------------------------------- /tests/argocd_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("argocd test", Label("argocd"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("Deploy argocd with default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "argocd.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(MatchRegexp("version: \".*?\"")) 26 | }) 27 | 28 | It("Specifiy version for argocd", func() { 29 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 30 | argocd: 31 | version: 1`), 0655) 32 | Expect(err).ToNot(HaveOccurred()) 33 | 34 | runBundle() 35 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "argocd.yaml")) 36 | content := string(dat) 37 | Expect(err).ToNot(HaveOccurred()) 38 | Expect(content).To(ContainSubstring("version: \"1\"")) 39 | }) 40 | 41 | It("Deploy argocd with default values", func() { 42 | runBundle() 43 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "argocd.yaml")) 44 | content := string(dat) 45 | Expect(err).ToNot(HaveOccurred()) 46 | Expect(content).To(ContainSubstring("valuesContent: |-\n {}")) 47 | }) 48 | 49 | It("Specifiy installation values for argocd", func() { 50 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 51 | argocd: 52 | values: 53 | installation: 54 | calicoNetwork: 55 | bgp: Disabled 56 | `), 0655) 57 | Expect(err).ToNot(HaveOccurred()) 58 | 59 | runBundle() 60 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "argocd.yaml")) 61 | content := string(dat) 62 | Expect(err).ToNot(HaveOccurred()) 63 | Expect(content).To(ContainSubstring("valuesContent: |-\n {\"installation\":{\"calicoNetwork\":{\"bgp\":\"Disabled\"}}}")) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/calico_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("calico test", Label("calico"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("Deploy calico with default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "calico.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | // renovate: depName=tigera-operator repoUrl=https://docs.tigera.io/calico/charts 26 | Expect(content).To(ContainSubstring("version: \"v3.28.2\"")) 27 | }) 28 | 29 | It("Specifiy major version for calico", func() { 30 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 31 | calico: 32 | version: 1`), 0655) 33 | Expect(err).ToNot(HaveOccurred()) 34 | 35 | runBundle() 36 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "calico.yaml")) 37 | content := string(dat) 38 | Expect(err).ToNot(HaveOccurred()) 39 | Expect(content).To(ContainSubstring("version: \"1\"")) 40 | }) 41 | 42 | It("Specifiy full version for calico", func() { 43 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 44 | calico: 45 | version: 1.2.3`), 0655) 46 | Expect(err).ToNot(HaveOccurred()) 47 | 48 | runBundle() 49 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "calico.yaml")) 50 | content := string(dat) 51 | Expect(err).ToNot(HaveOccurred()) 52 | Expect(content).To(ContainSubstring("version: \"1.2.3\"")) 53 | }) 54 | 55 | It("Deploy calico with default values", func() { 56 | runBundle() 57 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "calico.yaml")) 58 | content := string(dat) 59 | Expect(err).ToNot(HaveOccurred()) 60 | Expect(content).To(ContainSubstring("valuesContent: |-\n {}")) 61 | }) 62 | 63 | It("Specifiy installation values for calico", func() { 64 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 65 | calico: 66 | values: 67 | installation: 68 | calicoNetwork: 69 | bgp: Disabled 70 | `), 0655) 71 | Expect(err).ToNot(HaveOccurred()) 72 | 73 | runBundle() 74 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "calico.yaml")) 75 | content := string(dat) 76 | Expect(err).ToNot(HaveOccurred()) 77 | Expect(content).To(ContainSubstring("valuesContent: |-\n {\"installation\":{\"calicoNetwork\":{\"bgp\":\"Disabled\"}}}")) 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /tests/cert-manager_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("cert-manager test", Label("cert-manager"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("deploys cert-manager operator version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "cert-manager.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(ContainSubstring("clusterissuers.cert-manager.io")) 26 | }) 27 | 28 | It("Specify version for cert-manager", func() { 29 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 30 | certManager: 31 | version: v1.11.0`), 0655) 32 | Expect(err).ToNot(HaveOccurred()) 33 | runBundle() 34 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "cert-manager.yaml")) 35 | content := string(dat) 36 | Expect(err).ToNot(HaveOccurred()) 37 | Expect(content).To(ContainSubstring("clusterissuers.cert-manager.io")) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kairos-io/community-bundles/tests 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/onsi/ginkgo/v2 v2.20.1 7 | github.com/onsi/gomega v1.34.1 8 | gopkg.in/yaml.v3 v3.0.1 9 | ) 10 | 11 | require ( 12 | github.com/go-logr/logr v1.4.2 // indirect 13 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 14 | github.com/google/go-cmp v0.6.0 // indirect 15 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect 16 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 17 | golang.org/x/net v0.28.0 // indirect 18 | golang.org/x/sys v0.23.0 // indirect 19 | golang.org/x/text v0.17.0 // indirect 20 | golang.org/x/tools v0.24.0 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /tests/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 2 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 3 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 4 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 5 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= 6 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 7 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 8 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 9 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 10 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 11 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 12 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 13 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 14 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= 15 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 16 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= 17 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= 18 | github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q= 19 | github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= 20 | github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw= 21 | github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= 22 | github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= 23 | github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= 24 | github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= 25 | github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= 26 | github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 27 | github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 28 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= 29 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 30 | golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= 31 | golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= 32 | golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= 33 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 34 | golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= 35 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 36 | golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= 37 | golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 38 | golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= 39 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 40 | golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= 41 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 42 | golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= 43 | golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= 44 | golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= 45 | golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= 46 | google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= 47 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 48 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 49 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 50 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 51 | -------------------------------------------------------------------------------- /tests/kairos_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("kairos test", Label("kairos"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("Deploy kairos crds with default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kairos-crds.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(ContainSubstring("version: \"0.0.13\"")) 26 | }) 27 | 28 | It("Specifiy version for calico", func() { 29 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 30 | kairos: 31 | crds: 32 | version: "magrathea" 33 | osbuilder: 34 | enable: true 35 | version: "foobar" 36 | entangle: 37 | enable: true 38 | version: "baz" 39 | entangleProxy: 40 | enable: true 41 | version: "42.1.1" 42 | `), 0655) 43 | Expect(err).ToNot(HaveOccurred()) 44 | runBundle() 45 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kairos-crds.yaml")) 46 | content := string(dat) 47 | Expect(err).ToNot(HaveOccurred()) 48 | Expect(content).To(ContainSubstring("version: \"magrathea\"")) 49 | 50 | dat, err = os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kairos-osbuilder.yaml")) 51 | content = string(dat) 52 | Expect(err).ToNot(HaveOccurred()) 53 | Expect(content).To(ContainSubstring("version: \"foobar\""), content) 54 | 55 | dat, err = os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kairos-entangle.yaml")) 56 | content = string(dat) 57 | Expect(err).ToNot(HaveOccurred()) 58 | Expect(content).To(ContainSubstring("version: \"baz\""), content) 59 | 60 | dat, err = os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kairos-entangle-proxy.yaml")) 61 | content = string(dat) 62 | Expect(err).ToNot(HaveOccurred()) 63 | Expect(content).To(ContainSubstring("version: \"42.1.1\""), content) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/kubevirt_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("kubevirt test", Label("kubevirt"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("deploys kubevirt operator version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kubevirt-operator.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(ContainSubstring("quay.io/kubevirt/virt-operator")) 26 | _, err = os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kubevirt-manager-ns.yaml")) 27 | Expect(err).To(HaveOccurred()) 28 | }) 29 | 30 | It("Add manager", func() { 31 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 32 | kubevirt: 33 | manager: true`), 0655) 34 | Expect(err).ToNot(HaveOccurred()) 35 | runBundle() 36 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kubevirt-manager-ns.yaml")) 37 | content := string(dat) 38 | Expect(err).ToNot(HaveOccurred()) 39 | Expect(content).To(ContainSubstring("kubevirt-manager.io/version: 1.1.2")) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /tests/kyverno_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("kyverno test", Label("kyverno"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("Deploy kyverno with default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kyverno.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(MatchRegexp("version: \".*?\"")) 26 | }) 27 | 28 | It("Specifiy version for kyverno", func() { 29 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 30 | kyverno: 31 | version: 1`), 0655) 32 | Expect(err).ToNot(HaveOccurred()) 33 | 34 | runBundle() 35 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kyverno.yaml")) 36 | content := string(dat) 37 | Expect(err).ToNot(HaveOccurred()) 38 | Expect(content).To(ContainSubstring("version: \"1\"")) 39 | }) 40 | 41 | It("Deploy kyverno with default values", func() { 42 | runBundle() 43 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kyverno.yaml")) 44 | content := string(dat) 45 | Expect(err).ToNot(HaveOccurred()) 46 | Expect(content).To(ContainSubstring("valuesContent: |-\n {}")) 47 | }) 48 | 49 | It("Specifiy installation values for kyverno", func() { 50 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 51 | kyverno: 52 | values: 53 | installation: 54 | calicoNetwork: 55 | bgp: Disabled 56 | `), 0655) 57 | Expect(err).ToNot(HaveOccurred()) 58 | 59 | runBundle() 60 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "kyverno.yaml")) 61 | content := string(dat) 62 | Expect(err).ToNot(HaveOccurred()) 63 | Expect(content).To(ContainSubstring("valuesContent: |-\n {\"installation\":{\"calicoNetwork\":{\"bgp\":\"Disabled\"}}}")) 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/localai_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("localai test", Label("LocalAI"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("sets default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "localai.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | // renovate: depName=local-ai repoUrl=https://go-skynet.github.io/helm-charts/ 26 | Expect(content).To(MatchRegexp("version: \".*?\"")) 27 | }) 28 | 29 | It("sets the service type", func() { 30 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 31 | localai: 32 | serviceType: LoadBalancer`), 0655) 33 | Expect(err).ToNot(HaveOccurred()) 34 | 35 | runBundle() 36 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "localai.yaml")) 37 | content := string(dat) 38 | Expect(err).ToNot(HaveOccurred()) 39 | Expect(content).To(ContainSubstring("type: \"LoadBalancer\"")) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /tests/longhorn_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("longhorn test", Label("longhorn"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("Specifiy version for longhorn", func() { 21 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 22 | longhorn: 23 | version: 1`), 0655) 24 | Expect(err).ToNot(HaveOccurred()) 25 | 26 | runBundle() 27 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "longhorn.yaml")) 28 | content := string(dat) 29 | Expect(err).ToNot(HaveOccurred()) 30 | Expect(content).To(ContainSubstring("version: 1")) 31 | }) 32 | 33 | It("Deploy longhorn with default values", func() { 34 | runBundle() 35 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "longhorn.yaml")) 36 | content := string(dat) 37 | Expect(err).ToNot(HaveOccurred()) 38 | Expect(content).To(ContainSubstring("valuesContent: |-\n {}")) 39 | }) 40 | 41 | It("Specifiy installation values for longhorn", func() { 42 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 43 | longhorn: 44 | values: 45 | defaultSettings: 46 | backupstorePollInterval: 600 47 | `), 0655) 48 | Expect(err).ToNot(HaveOccurred()) 49 | 50 | runBundle() 51 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "longhorn.yaml")) 52 | content := string(dat) 53 | Expect(err).ToNot(HaveOccurred()) 54 | Expect(content).To(ContainSubstring("valuesContent: |-\n {\"defaultSettings\":{\"backupstorePollInterval\":600}}")) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /tests/metallb_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("metallb test", Label("metallb"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("sets default version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "metallb.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | // renovate: depName=metallb repoUrl=https://metallb.github.io/metallb 26 | Expect(content).To(MatchRegexp("version: \".*?\"")) 27 | dat, err = os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "addresspool.yaml")) 28 | content = string(dat) 29 | Expect(err).ToNot(HaveOccurred()) 30 | Expect(content).To(ContainSubstring("- 192.168.1.10-192.168.1.20")) 31 | }) 32 | 33 | It("set version", func() { 34 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 35 | metallb: 36 | version: 1`), 0655) 37 | Expect(err).ToNot(HaveOccurred()) 38 | 39 | runBundle() 40 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "metallb.yaml")) 41 | content := string(dat) 42 | Expect(err).ToNot(HaveOccurred()) 43 | Expect(content).To(ContainSubstring("version: \"1\"")) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/multus_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | "gopkg.in/yaml.v3" 11 | ) 12 | 13 | var _ = Describe("multus test", Label("multus"), func() { 14 | 15 | BeforeEach(func() { 16 | prepareBundle() 17 | SH("apk add openssl jq") 18 | SH("mkdir -p /opt/cni/bin") 19 | SH("mkdir -p /var/lib/rancher/k3s/data/current/bin") 20 | SH("mkdir -p /var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d") 21 | SH("mkdir -p /var/lib/rancher/k3s/server/tls") 22 | SH(` 23 | cd /var/lib/rancher/k3s/server/tls/ && 24 | openssl genrsa -out server-ca.key 4096 && 25 | openssl genrsa -out client-ca.key 4096 && 26 | openssl req -x509 -new -nodes -sha256 -days 1 -subj /CN=server-ca -key server-ca.key -out server-ca.crt && 27 | openssl req -x509 -new -nodes -sha256 -days 1 -subj /CN=client-ca -key client-ca.key -out client-ca.crt`) 28 | 29 | err := os.WriteFile("/var/lib/rancher/k3s/agent/etc/cni/net.d/foo.conflist", []byte(`{ 30 | "name": "cbr0", 31 | "cniVersion": "1.0.0", 32 | "plugins": [ 33 | { "type": "portmap", "capabilities": { "portMappings": true } }, 34 | { "type": "bandwidth", "capabilities": { "bandwidth": true } } 35 | ] 36 | }`), 0655) 37 | Expect(err).ToNot(HaveOccurred()) 38 | }) 39 | AfterEach(func() { 40 | cleanBundle() 41 | SH("rm -rfv /opt/cni") 42 | SH("rm -rfv /var/lib/rancher/k3s/data/current/bin") 43 | SH("rm -rfv /var/lib/rancher/k3s/agent/etc/cni") 44 | SH("rm -rfv /var/lib/rancher/k3s/server/tls") 45 | }) 46 | 47 | It("installs multus", func() { 48 | runBundle() 49 | Expect("/var/lib/rancher/k3s/data/current/bin/multus").To(BeARegularFile()) 50 | }) 51 | 52 | It("installs specified plugins", func() { 53 | err := os.WriteFile("/oem/multus.yaml", []byte(`#cloud-config 54 | multus: 55 | cni_plugins: 56 | - portmap 57 | - macvlan`), 0655) 58 | Expect(err).ToNot(HaveOccurred()) 59 | 60 | cfg, _ := SH("kairos-agent config get multus") 61 | fmt.Println(cfg) 62 | runBundle() 63 | Expect("/opt/cni/bin/portmap").To(BeARegularFile()) 64 | Expect("/opt/cni/bin/macvlan").To(BeARegularFile()) 65 | Expect("/opt/cni/bin/dhcp").ToNot(BeARegularFile()) 66 | }) 67 | 68 | It("creates manifests", func() { 69 | runBundle() 70 | dat, err := os.ReadFile("/var/lib/rancher/k3s/server/manifests/multus.yaml") 71 | content := string(dat) 72 | Expect(err).ToNot(HaveOccurred()) 73 | Expect(content).To(MatchRegexp("(?m)^kind: CustomResourceDefinition$")) 74 | Expect(content).To(MatchRegexp("(?m)^kind: ClusterRole$")) 75 | Expect(content).To(MatchRegexp("(?m)^kind: ClusterRoleBinding$")) 76 | }) 77 | 78 | It("creates a kubeconfig", func() { 79 | runBundle() 80 | dat, err := os.ReadFile("/var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d/multus.kubeconfig") 81 | Expect(err).ToNot(HaveOccurred()) 82 | err = yaml.Unmarshal(dat, struct{}{}) 83 | Expect(err).ToNot(HaveOccurred()) 84 | }) 85 | 86 | It("wraps an existing config", func() { 87 | runBundle() 88 | dat, err := os.ReadFile("/var/lib/rancher/k3s/agent/etc/cni/net.d/00-multus.conflist") 89 | Expect(err).ToNot(HaveOccurred()) 90 | 91 | config := &struct { 92 | CniVersion string 93 | Plugins []struct { 94 | Capabilities map[string]bool 95 | Delegates []struct{ Name string } 96 | } 97 | }{} 98 | 99 | json.Unmarshal(dat, &config) 100 | Expect(config.CniVersion).To(Equal("1.0.0")) 101 | Expect(config.Plugins[0].Capabilities).To(Equal(map[string]bool{ 102 | "portMappings": true, 103 | "bandwidth": true, 104 | })) 105 | }) 106 | }) 107 | -------------------------------------------------------------------------------- /tests/nginx_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | const ( 12 | manifestDir = "/var/lib/rancher/k3s/server/manifests" 13 | manifestFile = "ingress-nginx.yaml" 14 | ) 15 | 16 | var _ = Describe("nginx test", Label("nginx"), func() { 17 | 18 | BeforeEach(func() { 19 | prepareBundle() 20 | }) 21 | AfterEach(func() { 22 | cleanBundle() 23 | }) 24 | 25 | It("sets default version", func() { 26 | runBundle() 27 | dat, err := os.ReadFile(filepath.Join(manifestDir, manifestFile)) 28 | content := string(dat) 29 | Expect(err).ToNot(HaveOccurred()) 30 | // renovate: depName=ingress-nginx repoUrl=https://kubernetes.github.io/ingress-nginx 31 | Expect(content).To(ContainSubstring("version: \"4.11.3\"")) 32 | }) 33 | 34 | It("set major version", func() { 35 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 36 | nginx: 37 | version: 1`), 0655) 38 | Expect(err).ToNot(HaveOccurred()) 39 | 40 | runBundle() 41 | dat, err := os.ReadFile(filepath.Join(manifestDir, manifestFile)) 42 | content := string(dat) 43 | Expect(err).ToNot(HaveOccurred()) 44 | Expect(content).To(ContainSubstring("version: \"1\"")) 45 | }) 46 | 47 | It("set full version", func() { 48 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 49 | nginx: 50 | version: 1.2.3`), 0655) 51 | Expect(err).ToNot(HaveOccurred()) 52 | 53 | runBundle() 54 | dat, err := os.ReadFile(filepath.Join(manifestDir, manifestFile)) 55 | content := string(dat) 56 | Expect(err).ToNot(HaveOccurred()) 57 | Expect(content).To(ContainSubstring("version: \"1.2.3\"")) 58 | }) 59 | 60 | It("deploy with default values", func() { 61 | runBundle() 62 | dat, err := os.ReadFile(filepath.Join(manifestDir, manifestFile)) 63 | content := string(dat) 64 | Expect(err).ToNot(HaveOccurred()) 65 | Expect(content).To(ContainSubstring("valuesContent: |-\n {}")) 66 | }) 67 | 68 | It("specifiy values", func() { 69 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 70 | nginx: 71 | values: 72 | commonLabels: 73 | myLabel: abc123`), 0655) 74 | Expect(err).ToNot(HaveOccurred()) 75 | 76 | runBundle() 77 | dat, err := os.ReadFile(filepath.Join(manifestDir, manifestFile)) 78 | content := string(dat) 79 | Expect(err).ToNot(HaveOccurred()) 80 | Expect(content).To(ContainSubstring("valuesContent: |-\n {\"commonLabels\":{\"myLabel\":\"abc123\"}}")) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /tests/suite_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "testing" 8 | 9 | . "github.com/onsi/ginkgo/v2" 10 | . "github.com/onsi/gomega" 11 | ) 12 | 13 | func SH(c string) (string, error) { 14 | cmd := exec.Command("/bin/sh", "-c", c) 15 | cmd.Env = os.Environ() 16 | o, err := cmd.CombinedOutput() 17 | return string(o), err 18 | } 19 | 20 | func TestSuite(t *testing.T) { 21 | RegisterFailHandler(Fail) 22 | RunSpecs(t, "Kubemedia Test Suite") 23 | } 24 | 25 | func runBundle() { 26 | out, err := SH("cd /bundle && ./run.sh") 27 | fmt.Println(out) 28 | ExpectWithOffset(1, err).ToNot(HaveOccurred(), out) 29 | } 30 | 31 | func prepareBundle() { 32 | SH("cp -rf /bundle /bundle.bak") 33 | SH("mkdir /oem") 34 | } 35 | 36 | func cleanBundle() { 37 | SH("rm -rfv /oem") 38 | SH("rm -rfv /var/lib/rancher/k3s/server/manifests/") 39 | SH("rm -rf /bundle") 40 | SH("cp -rf /bundle.bak /bundle") 41 | } 42 | -------------------------------------------------------------------------------- /tests/system-upgrade-controller_test.go: -------------------------------------------------------------------------------- 1 | package bundles_test 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("system-upgrade-controller test", Label("system-upgrade-controller"), func() { 12 | 13 | BeforeEach(func() { 14 | prepareBundle() 15 | }) 16 | AfterEach(func() { 17 | cleanBundle() 18 | }) 19 | 20 | It("deploys default suc operator version", func() { 21 | runBundle() 22 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "system-upgrade-controller.yaml")) 23 | content := string(dat) 24 | Expect(err).ToNot(HaveOccurred()) 25 | Expect(content).To(ContainSubstring("rancher/system-upgrade-controller")) 26 | }) 27 | 28 | It("Specific version", func() { 29 | err := os.WriteFile("/oem/foo.yaml", []byte(`#cloud-config 30 | suc: 31 | version: foobar`), 0655) 32 | Expect(err).ToNot(HaveOccurred()) 33 | runBundle() 34 | dat, err := os.ReadFile(filepath.Join("/var/lib/rancher/k3s/server/manifests", "system-upgrade-controller.yaml")) 35 | content := string(dat) 36 | Expect(err).ToNot(HaveOccurred()) 37 | Expect(content).To(ContainSubstring("rancher/system-upgrade-controller:foobar")) 38 | }) 39 | }) 40 | --------------------------------------------------------------------------------