├── .github ├── CODEOWNERS ├── codecov.yml ├── mergify.yml ├── settings.yml └── workflows │ ├── ci.yaml │ └── tags.yaml ├── .gitignore ├── LICENSE ├── README.md ├── RELEASING.md ├── contrib └── tag-release.sh └── tinkerbell ├── hegel ├── Chart.yaml ├── templates │ ├── _scheduling.tpl │ ├── deployment.yaml │ ├── role.yaml │ ├── rolebinding.yaml │ ├── service-account.yaml │ └── service.yaml ├── values.schema.json └── values.yaml ├── rufio ├── Chart.yaml ├── crds │ ├── bmc.tinkerbell.org_jobs.yaml │ ├── bmc.tinkerbell.org_machines.yaml │ └── bmc.tinkerbell.org_tasks.yaml ├── templates │ ├── _scheduling.tpl │ ├── deployment.yaml │ ├── leader-election-role-binding.yaml │ ├── leader-election-role.yaml │ ├── role-binding.yaml │ ├── role.yaml │ └── service-account.yaml ├── values.schema.json └── values.yaml ├── smee ├── Chart.yaml ├── templates │ ├── _ports.tpl │ ├── _scheduling.tpl │ ├── deployment.yaml │ ├── role-binding.yaml │ ├── role.yaml │ ├── service-account.yaml │ └── service.yaml ├── values.schema.json └── values.yaml ├── stack ├── Chart.lock ├── Chart.yaml ├── README.md ├── docs │ └── arch.md ├── kubectl.go-template ├── templates │ ├── _scheduling.tpl │ ├── hook.yaml │ ├── init_configmap.yaml │ ├── kubevip.yaml │ ├── nginx-configmap.yaml │ ├── nginx.yaml │ └── nginx_pvc.yaml ├── values.schema.json └── values.yaml └── tink ├── Chart.yaml ├── crds ├── hardware-crd.yaml ├── template-crd.yaml └── workflow-crd.yaml ├── templates ├── tink-controller │ ├── _scheduling.tpl │ ├── deployment.yaml │ ├── leader-election-role.yaml │ ├── leader-election-rolebinding.yaml │ ├── role-binding.yaml │ ├── role.yaml │ └── service-account.yaml └── tink-server │ ├── _scheduling.tpl │ ├── deployment.yaml │ ├── role-binding.yaml │ ├── role.yaml │ ├── service-account.yaml │ └── service.yaml ├── values.schema.json └── values.yaml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | /.github/settings.yml @chrisdoherty4 @jacobweinstock 2 | /.github/CODEOWNERS @chrisdoherty4 @jacobweinstock -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | --- 2 | coverage: 3 | precision: 0 # xx% 4 | round: down # round down 5 | range: 30..40 # red < yellow (this range) < green 6 | 7 | status: 8 | project: 9 | default: 10 | target: auto # automatically calculate coverage target - should increase 11 | threshold: 2% # allow for 2% reduction without failing 12 | patch: 13 | default: 14 | target: auto 15 | changes: false 16 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | queue_rules: 2 | - name: default 3 | queue_conditions: 4 | - base=main 5 | - "#approved-reviews-by>=1" 6 | - "#changes-requested-reviews-by=0" 7 | - "#review-requested=0" 8 | - check-success=DCO 9 | - check-success=validation 10 | - label!=do-not-merge 11 | - label=ready-to-merge 12 | merge_conditions: 13 | # Conditions to get out of the queue (= merged) 14 | - check-success=DCO 15 | - check-success=validation 16 | merge_method: merge 17 | commit_message_template: | 18 | {{ title }} (#{{ number }}) 19 | 20 | {{ body }} 21 | 22 | pull_request_rules: 23 | - name: refactored queue action rule 24 | conditions: [] 25 | actions: 26 | queue: 27 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # Collaborators: give specific users access to this repository. 2 | # See https://docs.github.com/en/rest/reference/repos#add-a-repository-collaborator for available options 3 | collaborators: 4 | # Maintainers, should also be added to the .github/CODEOWNERS file as owners of this settings.yml file. 5 | - username: chrisdoherty4 6 | permission: maintain 7 | - username: jacobweinstock 8 | permission: maintain 9 | # Approvers 10 | - username: displague 11 | permission: push 12 | 13 | # Note: `permission` is only valid on organization-owned repositories. 14 | # The permission to grant the collaborator. Can be one of: 15 | # * `pull` - can pull, but not push to or administer this repository. 16 | # * `push` - can pull and push, but not administer this repository. 17 | # * `admin` - can pull, push and administer this repository. 18 | # * `maintain` - Recommended for project managers who need to manage the repository without access to sensitive or destructive actions. 19 | # * `triage` - Recommended for contributors who need to proactively manage issues and pull requests without write access. 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Validation 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | validation: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v3 12 | 13 | - name: Set up Helm 14 | uses: azure/setup-helm@v3 15 | with: 16 | version: v3.9.4 17 | 18 | - name: Helm lint 19 | # run `helm dependency update tinkerbell/stack`` if this fails 20 | run: helm dependency build tinkerbell/stack/ && helm lint tinkerbell/{smee,hegel,stack,tink} 21 | -------------------------------------------------------------------------------- /.github/workflows/tags.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "v*" 5 | name: Create release 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v2 12 | - name: Generate Release Notes 13 | run: | 14 | release_notes=$(gh api repos/{owner}/{repo}/releases/generate-notes -F tag_name=${{ github.ref }} --jq .body) 15 | echo 'RELEASE_NOTES<> $GITHUB_ENV 16 | echo "${release_notes}" >> $GITHUB_ENV 17 | echo 'EOF' >> $GITHUB_ENV 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | OWNER: ${{ github.repository_owner }} 21 | REPO: ${{ github.event.repository.name }} 22 | 23 | - name: install helm 24 | uses: Azure/setup-helm@v3.3 25 | with: 26 | version: v3.9.4 27 | 28 | - name: create helm chart package 29 | run: ver=${GITHUB_REF_NAME}; helm package tinkerbell/stack --dependency-update --version ${ver:1} 30 | 31 | - name: login to ghcr.io 32 | run: echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ghcr.io/tinkerbell --username ${{ github.actor }} --password-stdin 33 | 34 | - name: publish chart to ghcr.io 35 | run: ver=${GITHUB_REF_NAME}; helm push stack-${ver:1}.tgz oci://ghcr.io/tinkerbell/charts 36 | 37 | - name: Create Release 38 | id: create_release 39 | uses: actions/create-release@v1 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | with: 43 | tag_name: ${{ github.ref }} 44 | release_name: ${{ github.ref }} 45 | body: ${{ env.RELEASE_NOTES }} 46 | draft: false 47 | prerelease: true 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tgz 2 | .vscode/ 3 | Chart.lock 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tinkerbell Helm Charts 2 | 3 | Install the Tinkerbell stack to a Kubernetes cluster using the familiar Helm tool. 4 | 5 | See the [chart README](/tinkerbell/stack/README.md) for configuration details. -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | ## Process 4 | 5 | For version v0.x.y: 6 | 7 | 1. Create the annotated tag 8 | > NOTE: To use your GPG signature when pushing the tag, use `SIGN_TAG=1 ./contrib/tag-release.sh v0.x.y` instead) 9 | - `./contrib/tag-release.sh v0.x.y` 10 | 1. Push the tag to the GitHub repository. This will automatically trigger a [Github Action](https://github.com/tinkerbell/charts/actions) to create a release. 11 | > NOTE: `origin` should be the name of the remote pointing to `github.com/tinkerbell/charts` 12 | - `git push origin v0.x.y` 13 | 1. Review the release on GitHub. 14 | 15 | ### Permissions 16 | 17 | Releasing requires a particular set of permissions. 18 | 19 | - Tag push access to the GitHub repository 20 | -------------------------------------------------------------------------------- /contrib/tag-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | if [ -z "${1-}" ]; then 6 | echo "Must specify new tag" 7 | exit 1 8 | fi 9 | 10 | new_tag=${1-} 11 | [[ $new_tag =~ ^v[0-9]*\.[0-9]*\.[0-9]*$ ]] || ( 12 | echo "Tag must be in the form of vX.Y.Z" 13 | exit 1 14 | ) 15 | 16 | if [[ $(git symbolic-ref HEAD) != refs/heads/main ]] && [[ -z ${ALLOW_NON_MAIN:-} ]]; then 17 | echo "Must be on main branch" >&2 18 | exit 1 19 | fi 20 | if [[ $(git describe --dirty) != $(git describe) ]]; then 21 | echo "Repo must be in a clean state" >&2 22 | exit 1 23 | fi 24 | 25 | git fetch --all 26 | 27 | last_tag=$(git describe --abbrev=0) 28 | last_tag_commit=$(git rev-list -n1 "$last_tag") 29 | last_specific_tag=$(git tag --contains="$last_tag_commit" | grep -E "^v[0-9]*\.[0-9]*\.[0-9]*$" | tail -n 1) 30 | last_specific_tag_commit=$(git rev-list -n1 "$last_specific_tag") 31 | if [[ $last_specific_tag_commit == $(git rev-list -n1 HEAD) ]]; then 32 | echo "No commits since last tag" >&2 33 | exit 1 34 | fi 35 | 36 | if [[ -n ${SIGN_TAG-} ]]; then 37 | git tag -s -m "${new_tag}" "${new_tag}" &>/dev/null && echo "created signed tag ${new_tag}" >&2 && exit 38 | else 39 | git tag -a -m "${new_tag}" "${new_tag}" &>/dev/null && echo "created annotated tag ${new_tag}" >&2 && exit 40 | fi 41 | -------------------------------------------------------------------------------- /tinkerbell/hegel/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: hegel 3 | description: An instance metadata service 4 | icon: https://github.com/tinkerbell/artwork/blob/6f07de53d75cb8932dbc7d14201e038cf3a3b230/Tinkerbell-Icon-Dark.png 5 | 6 | # A chart can be either an 'application' or a 'library' chart. 7 | # 8 | # Application charts are a collection of templates that can be packaged into versioned archives 9 | # to be deployed. 10 | # 11 | # Library charts provide useful utilities or functions for the chart developer. They're included as 12 | # a dependency of application charts to inject those utilities and functions into the rendering 13 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 14 | type: application 15 | 16 | # This is the chart version. This version number should be incremented each time you make changes 17 | # to the chart and its templates, including the app version. 18 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 19 | version: 0.4.1 20 | 21 | # This is the version number of the application being deployed. This version number should be 22 | # incremented each time you make changes to the application. Versions are not expected to 23 | # follow Semantic Versioning. They should reflect the version the application is using. 24 | # It is recommended to use it with quotes. 25 | appVersion: "0.14.2" 26 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $trustedProxies := .Values.trustedProxies }} 3 | {{- $roleType := .Values.rbac.type }} 4 | {{- $nodeSelector := .Values.nodeSelector }} 5 | {{- if .Values.global }} 6 | {{- $trustedProxies = coalesce .Values.trustedProxies .Values.global.trustedProxies }} 7 | {{- $nodeSelector = coalesce .Values.nodeSelector .Values.global.nodeSelector }} 8 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 9 | {{- end }} 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | metadata: 13 | labels: 14 | app: {{ .Values.name }} 15 | name: {{ .Values.name }} 16 | namespace: {{ .Release.Namespace | quote }} 17 | spec: 18 | replicas: {{ .Values.replicas }} 19 | selector: 20 | matchLabels: 21 | app: {{ .Values.name }} 22 | stack: tinkerbell 23 | {{- with .Values.selector }} 24 | {{- toYaml . | nindent 6 }} 25 | {{- end }} 26 | template: 27 | metadata: 28 | labels: 29 | app: {{ .Values.name }} 30 | stack: tinkerbell 31 | {{- with .Values.selector }} 32 | {{- toYaml . | nindent 8 }} 33 | {{- end }} 34 | spec: 35 | containers: 36 | - args: 37 | - --backend=kubernetes 38 | - --http-addr=:{{ .Values.deployment.port }} 39 | {{- if eq $roleType "Role"}} 40 | - --kubernetes-namespace={{ .Release.Namespace }} 41 | {{- end }} 42 | {{- range .Values.args }} 43 | - {{ . }} 44 | {{- end }} 45 | env: 46 | - name: HEGEL_TRUSTED_PROXIES 47 | value: {{ required "missing trustedProxies" ( join "," $trustedProxies | quote ) }} 48 | {{- range $i, $env := .Values.env }} 49 | - name: {{ $env.name | quote }} 50 | value: {{ $env.value | quote }} 51 | {{- end }} 52 | image: {{ .Values.image }} 53 | imagePullPolicy: {{ .Values.imagePullPolicy }} 54 | name: {{ .Values.name }} 55 | ports: 56 | - containerPort: {{ .Values.deployment.port }} 57 | name: {{ .Values.deployment.portName }} 58 | resources: 59 | limits: 60 | cpu: {{ .Values.resources.limits.cpu }} 61 | memory: {{ .Values.resources.limits.memory }} 62 | requests: 63 | cpu: {{ .Values.resources.requests.cpu }} 64 | memory: {{ .Values.resources.requests.memory }} 65 | serviceAccountName: {{ .Values.name }} 66 | {{- with $nodeSelector }} 67 | nodeSelector: 68 | {{ toYaml . | nindent 8 }} 69 | {{- end }} 70 | {{- if .Values.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 71 | tolerations: 72 | {{- include "singleNodeClusterConfig" . | indent 6 }} 73 | affinity: 74 | nodeAffinity: 75 | preferredDuringSchedulingIgnoredDuringExecution: 76 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 77 | {{- end }} 78 | {{- end }} 79 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.name }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | rules: 14 | - apiGroups: ["tinkerbell.org"] 15 | resources: ["hardware", "hardware/status"] 16 | verbs: ["get", "watch", "list"] 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ printf "%sBinding" $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.bindingName }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: {{ $roleType }} 16 | name: {{ .Values.rbac.name }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.name }} 20 | namespace: {{ .Release.Namespace | quote }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.name }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /tinkerbell/hegel/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app: {{ .Values.name }} 7 | name: {{ .Values.name }} 8 | namespace: {{ .Release.Namespace | quote }} 9 | spec: 10 | ports: 11 | - port: {{ .Values.service.port }} 12 | protocol: TCP 13 | targetPort: {{ .Values.deployment.portName }} 14 | selector: 15 | app: {{ .Values.name }} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /tinkerbell/hegel/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "properties": { 5 | "rbac": { 6 | "type": "object", 7 | "properties": { 8 | "type": { 9 | "type": "string", 10 | "enum": ["Role", "ClusterRole"] 11 | }, 12 | "name": { 13 | "type": "string" 14 | }, 15 | "bindingName": { 16 | "type": "string" 17 | } 18 | } 19 | }, 20 | "trustedProxies": { 21 | "type": "array", 22 | "items": { 23 | "type": "string", 24 | "description": "Specifies one or more IPv4/IPv6 addresses expressed using CIDR notation.", 25 | "anyOf": [ 26 | { 27 | "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$" 28 | }, 29 | { 30 | "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" 31 | } 32 | ] 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tinkerbell/hegel/values.yaml: -------------------------------------------------------------------------------- 1 | deploy: true 2 | name: hegel 3 | image: quay.io/tinkerbell/hegel:v0.14.2 4 | imagePullPolicy: IfNotPresent 5 | replicas: 1 6 | service: 7 | port: 50061 8 | deployment: 9 | port: 50061 10 | portName: hegel-http 11 | resources: 12 | limits: 13 | cpu: 500m 14 | memory: 128Mi 15 | requests: 16 | cpu: 10m 17 | memory: 64Mi 18 | rbac: 19 | type: Role # or ClusterRole 20 | name: hegel-role # or hegel-cluster-role 21 | bindingName: hegel-rolebinding # or hegel-cluster-rolebinding 22 | nodeSelector: {} 23 | 24 | # Trusted proxies defines a list of IP or CIDR ranges that are allowed to set the X-Forwarded-For 25 | # header. This typically requires all Pod CIDRs in the cluster. 26 | trustedProxies: [] 27 | 28 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 29 | singleNodeClusterConfig: 30 | controlPlaneTolerationsEnabled: false 31 | nodeAffinityWeight: 1 32 | -------------------------------------------------------------------------------- /tinkerbell/rufio/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: rufio 3 | description: Rufio handles BMC interactions for Tinkerbell 4 | icon: https://github.com/tinkerbell/artwork/blob/6f07de53d75cb8932dbc7d14201e038cf3a3b230/Tinkerbell-Icon-Dark.png 5 | 6 | # A chart can be either an 'application' or a 'library' chart. 7 | # 8 | # Application charts are a collection of templates that can be packaged into versioned archives 9 | # to be deployed. 10 | # 11 | # Library charts provide useful utilities or functions for the chart developer. They're included as 12 | # a dependency of application charts to inject those utilities and functions into the rendering 13 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 14 | type: application 15 | 16 | # This is the chart version. This version number should be incremented each time you make changes 17 | # to the chart and its templates, including the app version. 18 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 19 | version: 0.4.2 20 | 21 | # This is the version number of the application being deployed. This version number should be 22 | # incremented each time you make changes to the application. Versions are not expected to 23 | # follow Semantic Versioning. They should reflect the version the application is using. 24 | # It is recommended to use it with quotes. 25 | appVersion: "0.6.3" 26 | -------------------------------------------------------------------------------- /tinkerbell/rufio/crds/bmc.tinkerbell.org_jobs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.16.4 7 | name: jobs.bmc.tinkerbell.org 8 | spec: 9 | group: bmc.tinkerbell.org 10 | names: 11 | categories: 12 | - tinkerbell 13 | kind: Job 14 | listKind: JobList 15 | plural: jobs 16 | shortNames: 17 | - j 18 | singular: job 19 | scope: Namespaced 20 | versions: 21 | - name: v1alpha1 22 | schema: 23 | openAPIV3Schema: 24 | description: Job is the Schema for the bmcjobs API. 25 | properties: 26 | apiVersion: 27 | description: |- 28 | APIVersion defines the versioned schema of this representation of an object. 29 | Servers should convert recognized schemas to the latest internal value, and 30 | may reject unrecognized values. 31 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 32 | type: string 33 | kind: 34 | description: |- 35 | Kind is a string value representing the REST resource this object represents. 36 | Servers may infer this from the endpoint the client submits requests to. 37 | Cannot be updated. 38 | In CamelCase. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 40 | type: string 41 | metadata: 42 | type: object 43 | spec: 44 | description: JobSpec defines the desired state of Job. 45 | properties: 46 | machineRef: 47 | description: |- 48 | MachineRef represents the Machine resource to execute the job. 49 | All the tasks in the job are executed for the same Machine. 50 | properties: 51 | name: 52 | description: Name of the Machine. 53 | type: string 54 | namespace: 55 | description: Namespace the Machine resides in. 56 | type: string 57 | required: 58 | - name 59 | - namespace 60 | type: object 61 | tasks: 62 | description: |- 63 | Tasks represents a list of baseboard management actions to be executed. 64 | The tasks are executed sequentially. Controller waits for one task to complete before executing the next. 65 | If a single task fails, job execution stops and sets condition Failed. 66 | Condition Completed is set only if all the tasks were successful. 67 | items: 68 | description: |- 69 | Action represents the action to be performed. 70 | A single task can only perform one type of action. 71 | For example either PowerAction or OneTimeBootDeviceAction. 72 | maxProperties: 1 73 | properties: 74 | oneTimeBootDeviceAction: 75 | description: OneTimeBootDeviceAction represents a baseboard 76 | management one time set boot device operation. 77 | properties: 78 | device: 79 | description: |- 80 | Devices represents the boot devices, in order for setting one time boot. 81 | Currently only the first device in the slice is used to set one time boot. 82 | items: 83 | description: BootDevice represents boot device of the 84 | Machine. 85 | type: string 86 | type: array 87 | efiBoot: 88 | description: EFIBoot instructs the machine to use EFI boot. 89 | type: boolean 90 | required: 91 | - device 92 | type: object 93 | powerAction: 94 | description: PowerAction represents a baseboard management power 95 | operation. 96 | enum: 97 | - "on" 98 | - "off" 99 | - soft 100 | - status 101 | - cycle 102 | - reset 103 | type: string 104 | virtualMediaAction: 105 | description: VirtualMediaAction represents a baseboard management 106 | virtual media insert/eject. 107 | properties: 108 | kind: 109 | type: string 110 | mediaURL: 111 | description: |- 112 | mediaURL represents the URL of the image to be inserted into the virtual media, or empty to 113 | eject media. 114 | type: string 115 | required: 116 | - kind 117 | type: object 118 | type: object 119 | minItems: 1 120 | type: array 121 | required: 122 | - machineRef 123 | - tasks 124 | type: object 125 | status: 126 | description: JobStatus defines the observed state of Job. 127 | properties: 128 | completionTime: 129 | description: |- 130 | CompletionTime represents time when the job was completed. 131 | The completion time is only set when the job finishes successfully. 132 | format: date-time 133 | type: string 134 | conditions: 135 | description: Conditions represents the latest available observations 136 | of an object's current state. 137 | items: 138 | properties: 139 | message: 140 | description: Message represents human readable message indicating 141 | details about last transition. 142 | type: string 143 | status: 144 | description: |- 145 | Status is the status of the Job condition. 146 | Can be True or False. 147 | type: string 148 | type: 149 | description: Type of the Job condition. 150 | type: string 151 | required: 152 | - status 153 | - type 154 | type: object 155 | type: array 156 | startTime: 157 | description: StartTime represents time when the Job controller started 158 | processing a job. 159 | format: date-time 160 | type: string 161 | type: object 162 | type: object 163 | served: true 164 | storage: true 165 | subresources: 166 | status: {} 167 | -------------------------------------------------------------------------------- /tinkerbell/rufio/crds/bmc.tinkerbell.org_machines.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.16.4 7 | labels: 8 | clusterctl.cluster.x-k8s.io: "" 9 | clusterctl.cluster.x-k8s.io/move: "" 10 | name: machines.bmc.tinkerbell.org 11 | spec: 12 | group: bmc.tinkerbell.org 13 | names: 14 | categories: 15 | - tinkerbell 16 | kind: Machine 17 | listKind: MachineList 18 | plural: machines 19 | singular: machine 20 | scope: Namespaced 21 | versions: 22 | - name: v1alpha1 23 | schema: 24 | openAPIV3Schema: 25 | description: Machine is the Schema for the machines API. 26 | properties: 27 | apiVersion: 28 | description: |- 29 | APIVersion defines the versioned schema of this representation of an object. 30 | Servers should convert recognized schemas to the latest internal value, and 31 | may reject unrecognized values. 32 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 33 | type: string 34 | kind: 35 | description: |- 36 | Kind is a string value representing the REST resource this object represents. 37 | Servers may infer this from the endpoint the client submits requests to. 38 | Cannot be updated. 39 | In CamelCase. 40 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 41 | type: string 42 | metadata: 43 | type: object 44 | spec: 45 | description: MachineSpec defines desired machine state. 46 | properties: 47 | connection: 48 | description: Connection contains connection data for a Baseboard Management 49 | Controller. 50 | properties: 51 | authSecretRef: 52 | description: |- 53 | AuthSecretRef is the SecretReference that contains authentication information of the Machine. 54 | The Secret must contain username and password keys. This is optional as it is not required when using 55 | the RPC provider. 56 | properties: 57 | name: 58 | description: name is unique within a namespace to reference 59 | a secret resource. 60 | type: string 61 | namespace: 62 | description: namespace defines the space within which the 63 | secret name must be unique. 64 | type: string 65 | type: object 66 | x-kubernetes-map-type: atomic 67 | host: 68 | description: Host is the host IP address or hostname of the Machine. 69 | minLength: 1 70 | type: string 71 | insecureTLS: 72 | description: InsecureTLS specifies trusted TLS connections. 73 | type: boolean 74 | port: 75 | default: 623 76 | description: Port is the port number for connecting with the Machine. 77 | type: integer 78 | providerOptions: 79 | description: ProviderOptions contains provider specific options. 80 | properties: 81 | intelAMT: 82 | description: IntelAMT contains the options to customize the 83 | IntelAMT provider. 84 | properties: 85 | hostScheme: 86 | default: http 87 | description: HostScheme determines whether to use http 88 | or https for intelAMT calls. 89 | enum: 90 | - http 91 | - https 92 | type: string 93 | port: 94 | description: Port that intelAMT will use for calls. 95 | type: integer 96 | type: object 97 | ipmitool: 98 | description: IPMITOOL contains the options to customize the 99 | Ipmitool provider. 100 | properties: 101 | cipherSuite: 102 | description: CipherSuite that ipmitool will use for calls. 103 | type: string 104 | port: 105 | description: Port that ipmitool will use for calls. 106 | type: integer 107 | type: object 108 | preferredOrder: 109 | description: |- 110 | PreferredOrder allows customizing the order that BMC providers are called. 111 | Providers added to this list will be moved to the front of the default order. 112 | Provider names are case insensitive. 113 | The default order is: ipmitool, asrockrack, gofish, intelamt, dell, supermicro, openbmc. 114 | items: 115 | description: ProviderName is the bmclib specific provider 116 | name. Names are case insensitive. 117 | pattern: (?i)^(ipmitool|asrockrack|gofish|IntelAMT|dell|supermicro|openbmc)$ 118 | type: string 119 | type: array 120 | redfish: 121 | description: Redfish contains the options to customize the 122 | Redfish provider. 123 | properties: 124 | port: 125 | description: Port that redfish will use for calls. 126 | type: integer 127 | systemName: 128 | description: |- 129 | SystemName is the name of the system to use for redfish calls. 130 | With redfish implementations that manage multiple systems via a single endpoint, this allows for specifying the system to manage. 131 | type: string 132 | useBasicAuth: 133 | description: UseBasicAuth for redfish calls. The default 134 | is false which means token based auth is used. 135 | type: boolean 136 | type: object 137 | rpc: 138 | description: RPC contains the options to customize the RPC 139 | provider. 140 | properties: 141 | consumerURL: 142 | description: |- 143 | ConsumerURL is the URL where an rpc consumer/listener is running 144 | and to which we will send and receive all notifications. 145 | type: string 146 | experimental: 147 | description: Experimental options. 148 | properties: 149 | customRequestPayload: 150 | description: CustomRequestPayload must be in json. 151 | type: string 152 | dotPath: 153 | description: 'DotPath is the path to the json object 154 | where the bmclib RequestPayload{} struct will be 155 | embedded. For example: object.data.body' 156 | type: string 157 | type: object 158 | hmac: 159 | description: HMAC is the options used to create a HMAC 160 | signature. 161 | properties: 162 | prefixSigDisabled: 163 | description: 'PrefixSigDisabled determines whether 164 | the algorithm will be prefixed to the signature. 165 | Example: sha256=abc123' 166 | type: boolean 167 | secrets: 168 | additionalProperties: 169 | items: 170 | description: |- 171 | SecretReference represents a Secret Reference. It has enough information to retrieve secret 172 | in any namespace 173 | properties: 174 | name: 175 | description: name is unique within a namespace 176 | to reference a secret resource. 177 | type: string 178 | namespace: 179 | description: namespace defines the space within 180 | which the secret name must be unique. 181 | type: string 182 | type: object 183 | x-kubernetes-map-type: atomic 184 | type: array 185 | description: Secrets are a map of algorithms to secrets 186 | used for signing. 187 | type: object 188 | type: object 189 | logNotificationsDisabled: 190 | description: LogNotificationsDisabled determines whether 191 | responses from rpc consumer/listeners will be logged 192 | or not. 193 | type: boolean 194 | request: 195 | description: Request is the options used to create the 196 | rpc HTTP request. 197 | properties: 198 | httpContentType: 199 | description: HTTPContentType is the content type to 200 | use for the rpc request notification. 201 | type: string 202 | httpMethod: 203 | description: HTTPMethod is the HTTP method to use 204 | for the rpc request notification. 205 | type: string 206 | staticHeaders: 207 | additionalProperties: 208 | items: 209 | type: string 210 | type: array 211 | description: StaticHeaders are predefined headers 212 | that will be added to every request. 213 | type: object 214 | timestampFormat: 215 | description: TimestampFormat is the time format for 216 | the timestamp header. 217 | type: string 218 | timestampHeader: 219 | description: 'TimestampHeader is the header name that 220 | should contain the timestamp. Example: X-BMCLIB-Timestamp' 221 | type: string 222 | type: object 223 | signature: 224 | description: Signature is the options used for adding 225 | an HMAC signature to an HTTP request. 226 | properties: 227 | appendAlgoToHeaderDisabled: 228 | description: |- 229 | AppendAlgoToHeaderDisabled decides whether to append the algorithm to the signature header or not. 230 | Example: X-BMCLIB-Signature becomes X-BMCLIB-Signature-256 231 | When set to true, a header will be added for each algorithm. Example: X-BMCLIB-Signature-256 and X-BMCLIB-Signature-512 232 | type: boolean 233 | headerName: 234 | description: 'HeaderName is the header name that should 235 | contain the signature(s). Example: X-BMCLIB-Signature' 236 | type: string 237 | includedPayloadHeaders: 238 | description: |- 239 | IncludedPayloadHeaders are headers whose values will be included in the signature payload. Example: X-BMCLIB-My-Custom-Header 240 | All headers will be deduplicated. 241 | items: 242 | type: string 243 | type: array 244 | type: object 245 | required: 246 | - consumerURL 247 | type: object 248 | type: object 249 | required: 250 | - host 251 | - insecureTLS 252 | type: object 253 | required: 254 | - connection 255 | type: object 256 | status: 257 | description: MachineStatus defines the observed state of Machine. 258 | properties: 259 | conditions: 260 | description: Conditions represents the latest available observations 261 | of an object's current state. 262 | items: 263 | description: MachineCondition defines an observed condition of a 264 | Machine. 265 | properties: 266 | lastUpdateTime: 267 | description: LastUpdateTime of the condition. 268 | format: date-time 269 | type: string 270 | message: 271 | description: Message is a human readable message indicating 272 | with details of the last transition. 273 | type: string 274 | status: 275 | description: Status of the condition. 276 | type: string 277 | type: 278 | description: Type of the Machine condition. 279 | type: string 280 | required: 281 | - status 282 | - type 283 | type: object 284 | type: array 285 | powerState: 286 | description: Power is the current power state of the Machine. 287 | enum: 288 | - "on" 289 | - "off" 290 | - unknown 291 | type: string 292 | type: object 293 | type: object 294 | served: true 295 | storage: true 296 | subresources: 297 | status: {} 298 | -------------------------------------------------------------------------------- /tinkerbell/rufio/crds/bmc.tinkerbell.org_tasks.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.16.4 7 | name: tasks.bmc.tinkerbell.org 8 | spec: 9 | group: bmc.tinkerbell.org 10 | names: 11 | categories: 12 | - tinkerbell 13 | kind: Task 14 | listKind: TaskList 15 | plural: tasks 16 | shortNames: 17 | - t 18 | singular: task 19 | scope: Namespaced 20 | versions: 21 | - name: v1alpha1 22 | schema: 23 | openAPIV3Schema: 24 | description: Task is the Schema for the Task API. 25 | properties: 26 | apiVersion: 27 | description: |- 28 | APIVersion defines the versioned schema of this representation of an object. 29 | Servers should convert recognized schemas to the latest internal value, and 30 | may reject unrecognized values. 31 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 32 | type: string 33 | kind: 34 | description: |- 35 | Kind is a string value representing the REST resource this object represents. 36 | Servers may infer this from the endpoint the client submits requests to. 37 | Cannot be updated. 38 | In CamelCase. 39 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 40 | type: string 41 | metadata: 42 | type: object 43 | spec: 44 | description: TaskSpec defines the desired state of Task. 45 | properties: 46 | connection: 47 | description: Connection represents the Machine connectivity information. 48 | properties: 49 | authSecretRef: 50 | description: |- 51 | AuthSecretRef is the SecretReference that contains authentication information of the Machine. 52 | The Secret must contain username and password keys. This is optional as it is not required when using 53 | the RPC provider. 54 | properties: 55 | name: 56 | description: name is unique within a namespace to reference 57 | a secret resource. 58 | type: string 59 | namespace: 60 | description: namespace defines the space within which the 61 | secret name must be unique. 62 | type: string 63 | type: object 64 | x-kubernetes-map-type: atomic 65 | host: 66 | description: Host is the host IP address or hostname of the Machine. 67 | minLength: 1 68 | type: string 69 | insecureTLS: 70 | description: InsecureTLS specifies trusted TLS connections. 71 | type: boolean 72 | port: 73 | default: 623 74 | description: Port is the port number for connecting with the Machine. 75 | type: integer 76 | providerOptions: 77 | description: ProviderOptions contains provider specific options. 78 | properties: 79 | intelAMT: 80 | description: IntelAMT contains the options to customize the 81 | IntelAMT provider. 82 | properties: 83 | hostScheme: 84 | default: http 85 | description: HostScheme determines whether to use http 86 | or https for intelAMT calls. 87 | enum: 88 | - http 89 | - https 90 | type: string 91 | port: 92 | description: Port that intelAMT will use for calls. 93 | type: integer 94 | type: object 95 | ipmitool: 96 | description: IPMITOOL contains the options to customize the 97 | Ipmitool provider. 98 | properties: 99 | cipherSuite: 100 | description: CipherSuite that ipmitool will use for calls. 101 | type: string 102 | port: 103 | description: Port that ipmitool will use for calls. 104 | type: integer 105 | type: object 106 | preferredOrder: 107 | description: |- 108 | PreferredOrder allows customizing the order that BMC providers are called. 109 | Providers added to this list will be moved to the front of the default order. 110 | Provider names are case insensitive. 111 | The default order is: ipmitool, asrockrack, gofish, intelamt, dell, supermicro, openbmc. 112 | items: 113 | description: ProviderName is the bmclib specific provider 114 | name. Names are case insensitive. 115 | pattern: (?i)^(ipmitool|asrockrack|gofish|IntelAMT|dell|supermicro|openbmc)$ 116 | type: string 117 | type: array 118 | redfish: 119 | description: Redfish contains the options to customize the 120 | Redfish provider. 121 | properties: 122 | port: 123 | description: Port that redfish will use for calls. 124 | type: integer 125 | systemName: 126 | description: |- 127 | SystemName is the name of the system to use for redfish calls. 128 | With redfish implementations that manage multiple systems via a single endpoint, this allows for specifying the system to manage. 129 | type: string 130 | useBasicAuth: 131 | description: UseBasicAuth for redfish calls. The default 132 | is false which means token based auth is used. 133 | type: boolean 134 | type: object 135 | rpc: 136 | description: RPC contains the options to customize the RPC 137 | provider. 138 | properties: 139 | consumerURL: 140 | description: |- 141 | ConsumerURL is the URL where an rpc consumer/listener is running 142 | and to which we will send and receive all notifications. 143 | type: string 144 | experimental: 145 | description: Experimental options. 146 | properties: 147 | customRequestPayload: 148 | description: CustomRequestPayload must be in json. 149 | type: string 150 | dotPath: 151 | description: 'DotPath is the path to the json object 152 | where the bmclib RequestPayload{} struct will be 153 | embedded. For example: object.data.body' 154 | type: string 155 | type: object 156 | hmac: 157 | description: HMAC is the options used to create a HMAC 158 | signature. 159 | properties: 160 | prefixSigDisabled: 161 | description: 'PrefixSigDisabled determines whether 162 | the algorithm will be prefixed to the signature. 163 | Example: sha256=abc123' 164 | type: boolean 165 | secrets: 166 | additionalProperties: 167 | items: 168 | description: |- 169 | SecretReference represents a Secret Reference. It has enough information to retrieve secret 170 | in any namespace 171 | properties: 172 | name: 173 | description: name is unique within a namespace 174 | to reference a secret resource. 175 | type: string 176 | namespace: 177 | description: namespace defines the space within 178 | which the secret name must be unique. 179 | type: string 180 | type: object 181 | x-kubernetes-map-type: atomic 182 | type: array 183 | description: Secrets are a map of algorithms to secrets 184 | used for signing. 185 | type: object 186 | type: object 187 | logNotificationsDisabled: 188 | description: LogNotificationsDisabled determines whether 189 | responses from rpc consumer/listeners will be logged 190 | or not. 191 | type: boolean 192 | request: 193 | description: Request is the options used to create the 194 | rpc HTTP request. 195 | properties: 196 | httpContentType: 197 | description: HTTPContentType is the content type to 198 | use for the rpc request notification. 199 | type: string 200 | httpMethod: 201 | description: HTTPMethod is the HTTP method to use 202 | for the rpc request notification. 203 | type: string 204 | staticHeaders: 205 | additionalProperties: 206 | items: 207 | type: string 208 | type: array 209 | description: StaticHeaders are predefined headers 210 | that will be added to every request. 211 | type: object 212 | timestampFormat: 213 | description: TimestampFormat is the time format for 214 | the timestamp header. 215 | type: string 216 | timestampHeader: 217 | description: 'TimestampHeader is the header name that 218 | should contain the timestamp. Example: X-BMCLIB-Timestamp' 219 | type: string 220 | type: object 221 | signature: 222 | description: Signature is the options used for adding 223 | an HMAC signature to an HTTP request. 224 | properties: 225 | appendAlgoToHeaderDisabled: 226 | description: |- 227 | AppendAlgoToHeaderDisabled decides whether to append the algorithm to the signature header or not. 228 | Example: X-BMCLIB-Signature becomes X-BMCLIB-Signature-256 229 | When set to true, a header will be added for each algorithm. Example: X-BMCLIB-Signature-256 and X-BMCLIB-Signature-512 230 | type: boolean 231 | headerName: 232 | description: 'HeaderName is the header name that should 233 | contain the signature(s). Example: X-BMCLIB-Signature' 234 | type: string 235 | includedPayloadHeaders: 236 | description: |- 237 | IncludedPayloadHeaders are headers whose values will be included in the signature payload. Example: X-BMCLIB-My-Custom-Header 238 | All headers will be deduplicated. 239 | items: 240 | type: string 241 | type: array 242 | type: object 243 | required: 244 | - consumerURL 245 | type: object 246 | type: object 247 | required: 248 | - host 249 | - insecureTLS 250 | type: object 251 | task: 252 | description: Task defines the specific action to be performed. 253 | maxProperties: 1 254 | properties: 255 | oneTimeBootDeviceAction: 256 | description: OneTimeBootDeviceAction represents a baseboard management 257 | one time set boot device operation. 258 | properties: 259 | device: 260 | description: |- 261 | Devices represents the boot devices, in order for setting one time boot. 262 | Currently only the first device in the slice is used to set one time boot. 263 | items: 264 | description: BootDevice represents boot device of the Machine. 265 | type: string 266 | type: array 267 | efiBoot: 268 | description: EFIBoot instructs the machine to use EFI boot. 269 | type: boolean 270 | required: 271 | - device 272 | type: object 273 | powerAction: 274 | description: PowerAction represents a baseboard management power 275 | operation. 276 | enum: 277 | - "on" 278 | - "off" 279 | - soft 280 | - status 281 | - cycle 282 | - reset 283 | type: string 284 | virtualMediaAction: 285 | description: VirtualMediaAction represents a baseboard management 286 | virtual media insert/eject. 287 | properties: 288 | kind: 289 | type: string 290 | mediaURL: 291 | description: |- 292 | mediaURL represents the URL of the image to be inserted into the virtual media, or empty to 293 | eject media. 294 | type: string 295 | required: 296 | - kind 297 | type: object 298 | type: object 299 | required: 300 | - task 301 | type: object 302 | status: 303 | description: TaskStatus defines the observed state of Task. 304 | properties: 305 | completionTime: 306 | description: |- 307 | CompletionTime represents time when the task was completed. 308 | The completion time is only set when the task finishes successfully. 309 | format: date-time 310 | type: string 311 | conditions: 312 | description: Conditions represents the latest available observations 313 | of an object's current state. 314 | items: 315 | properties: 316 | message: 317 | description: Message represents human readable message indicating 318 | details about last transition. 319 | type: string 320 | status: 321 | description: |- 322 | Status is the status of the Task condition. 323 | Can be True or False. 324 | type: string 325 | type: 326 | description: Type of the Task condition. 327 | type: string 328 | required: 329 | - status 330 | - type 331 | type: object 332 | type: array 333 | startTime: 334 | description: StartTime represents time when the Task started processing. 335 | format: date-time 336 | type: string 337 | type: object 338 | type: object 339 | served: true 340 | storage: true 341 | subresources: 342 | status: {} 343 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- $nodeSelector := .Values.nodeSelector }} 4 | {{- if .Values.global }} 5 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 6 | {{- $nodeSelector = coalesce .Values.nodeSelector .Values.global.nodeSelector }} 7 | {{- end }} 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | labels: 12 | app: {{ .Values.name }} 13 | control-plane: controller-manager 14 | name: {{ .Values.name }} 15 | namespace: {{ .Release.Namespace | quote }} 16 | spec: 17 | selector: 18 | matchLabels: 19 | app: {{ .Values.name }} 20 | control-plane: controller-manager 21 | stack: tinkerbell 22 | replicas: 1 23 | template: 24 | metadata: 25 | annotations: 26 | kubectl.kubernetes.io/default-container: manager 27 | labels: 28 | app: {{ .Values.name }} 29 | control-plane: controller-manager 30 | stack: tinkerbell 31 | spec: 32 | {{- if .Values.hostNetwork }} 33 | hostNetwork: true 34 | dnsPolicy: ClusterFirstWithHostNet 35 | {{- end }} 36 | securityContext: 37 | runAsNonRoot: true 38 | containers: 39 | - name: manager 40 | image: {{ .Values.image }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | command: 43 | - /manager 44 | args: 45 | - --leader-elect 46 | {{- if eq $roleType "Role" }} 47 | - -kube-namespace={{ .Release.Namespace }} 48 | {{- end }} 49 | {{- range .Values.additionalArgs }} 50 | - {{ . }} 51 | {{- end }} 52 | securityContext: 53 | allowPrivilegeEscalation: false 54 | livenessProbe: 55 | httpGet: 56 | path: /healthz 57 | port: 8081 58 | initialDelaySeconds: 15 59 | periodSeconds: 20 60 | readinessProbe: 61 | httpGet: 62 | path: /readyz 63 | port: 8081 64 | initialDelaySeconds: 5 65 | periodSeconds: 10 66 | resources: 67 | limits: 68 | cpu: {{ .Values.resources.limits.cpu }} 69 | memory: {{ .Values.resources.limits.memory }} 70 | requests: 71 | cpu: {{ .Values.resources.requests.cpu }} 72 | memory: {{ .Values.resources.requests.memory }} 73 | serviceAccountName: {{ .Values.serviceAccountName }} 74 | terminationGracePeriodSeconds: 10 75 | {{- with $nodeSelector }} 76 | nodeSelector: 77 | {{ toYaml . | nindent 8 }} 78 | {{- end }} 79 | {{- if .Values.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 80 | tolerations: 81 | {{- include "singleNodeClusterConfig" . | indent 6 }} 82 | affinity: 83 | nodeAffinity: 84 | preferredDuringSchedulingIgnoredDuringExecution: 85 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 86 | {{- end }} 87 | {{- end }} 88 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/leader-election-role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ .Values.rufioLeaderElectionRoleBindingName }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: {{ .Values.rufioLeaderElectionRoleName }} 11 | subjects: 12 | - kind: ServiceAccount 13 | name: {{ .Values.serviceAccountName }} 14 | namespace: {{ .Release.Namespace | quote }} 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/leader-election-role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: {{ .Values.rufioLeaderElectionRoleName }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | rules: 8 | - apiGroups: 9 | - "" 10 | resources: 11 | - configmaps 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | - create 17 | - update 18 | - patch 19 | - delete 20 | - apiGroups: 21 | - coordination.k8s.io 22 | resources: 23 | - leases 24 | verbs: 25 | - get 26 | - list 27 | - watch 28 | - create 29 | - update 30 | - patch 31 | - delete 32 | - apiGroups: 33 | - "" 34 | resources: 35 | - events 36 | verbs: 37 | - create 38 | - patch 39 | {{- end }} 40 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ printf "%sBinding" $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.bindingName }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: {{ $roleType }} 16 | name: {{ .Values.rbac.name }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.serviceAccountName }} 20 | namespace: {{ .Release.Namespace | quote }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.name }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | rules: 14 | - apiGroups: [""] 15 | resources: ["secrets"] 16 | verbs: ["get", "list", "watch"] 17 | - apiGroups: ["bmc.tinkerbell.org"] 18 | resources: ["jobs", "jobs/status", "machines", "machines/status", "tasks", "tasks/status"] 19 | verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] 20 | - apiGroups: ["bmc.tinkerbell.org"] 21 | resources: ["jobs/finalizers", "machines/finalizers", "tasks/finalizers"] 22 | verbs: ["update"] 23 | {{- end }} 24 | -------------------------------------------------------------------------------- /tinkerbell/rufio/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.serviceAccountName }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /tinkerbell/rufio/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "properties": { 5 | "rbac": { 6 | "type": "object", 7 | "properties": { 8 | "type": { 9 | "type": "string", 10 | "enum": ["Role", "ClusterRole"] 11 | }, 12 | "name": { 13 | "type": "string" 14 | }, 15 | "bindingName": { 16 | "type": "string" 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tinkerbell/rufio/values.yaml: -------------------------------------------------------------------------------- 1 | deploy: true 2 | name: rufio 3 | image: quay.io/tinkerbell/rufio:v0.6.3 4 | imagePullPolicy: IfNotPresent 5 | resources: 6 | requests: 7 | cpu: 10m 8 | memory: 64Mi 9 | limits: 10 | cpu: 500m 11 | memory: 128Mi 12 | additionalArgs: [] 13 | serviceAccountName: rufio-controller-manager 14 | rufioLeaderElectionRoleName: rufio-leader-election-role 15 | rufioLeaderElectionRoleBindingName: rufio-leader-election-rolebinding 16 | nodeSelector: {} 17 | hostNetwork: false 18 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 19 | singleNodeClusterConfig: 20 | controlPlaneTolerationsEnabled: false 21 | nodeAffinityWeight: 1 22 | 23 | rbac: 24 | type: Role # or ClusterRole 25 | name: rufio-role # or rufio-cluster-role 26 | bindingName: rufio-rolebinding # or rufio-cluster-rolebinding 27 | -------------------------------------------------------------------------------- /tinkerbell/smee/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: smee 3 | description: Smee is the network boot service for Tinkerbell 4 | icon: https://github.com/tinkerbell/artwork/blob/6f07de53d75cb8932dbc7d14201e038cf3a3b230/Tinkerbell-Icon-Dark.png 5 | 6 | # A chart can be either an 'application' or a 'library' chart. 7 | # 8 | # Application charts are a collection of templates that can be packaged into versioned archives 9 | # to be deployed. 10 | # 11 | # Library charts provide useful utilities or functions for the chart developer. They're included as 12 | # a dependency of application charts to inject those utilities and functions into the rendering 13 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 14 | type: application 15 | 16 | # This is the chart version. This version number should be incremented each time you make changes 17 | # to the chart and its templates, including the app version. 18 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 19 | version: 0.6.3 20 | 21 | # This is the version number of the application being deployed. This version number should be 22 | # incremented each time you make changes to the application. Versions are not expected to 23 | # follow Semantic Versioning. They should reflect the version the application is using. 24 | # It is recommended to use it with quotes. 25 | appVersion: "0.15.1" 26 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/_ports.tpl: -------------------------------------------------------------------------------- 1 | {{ define "smee.ports" }} 2 | - {{ .PortKey }}: {{ .http.port }} 3 | name: {{ .http.name }} 4 | protocol: TCP 5 | - {{ .PortKey }}: {{ .syslog.port }} 6 | name: {{ .syslog.name }} 7 | protocol: UDP 8 | - {{ .PortKey }}: {{ .dhcp.port }} 9 | name: {{ .dhcp.name }} 10 | protocol: UDP 11 | - {{ .PortKey }}: {{ .tftp.port }} 12 | name: {{ .tftp.name }} 13 | protocol: UDP 14 | {{- end }} 15 | 16 | {{- define "urlJoiner" }} 17 | {{- if .urlDict.port }} 18 | {{- $host := printf "%v:%v" .urlDict.host .urlDict.port }} 19 | {{- $newDict := set .urlDict "host" $host }} 20 | {{- print (urlJoin $newDict) }} 21 | {{- else }} 22 | {{- print (urlJoin .urlDict) }} 23 | {{- end }} 24 | {{- end }} 25 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $publicIP := .Values.publicIP }} 3 | {{- $trustedProxies := .Values.trustedProxies }} 4 | {{- $roleType := .Values.rbac.type }} 5 | {{- $nodeSelector := .Values.nodeSelector }} 6 | {{- if .Values.global }} 7 | {{- $publicIP = coalesce .Values.publicIP .Values.global.publicIP }} 8 | {{- $trustedProxies = coalesce .Values.trustedProxies .Values.global.trustedProxies }} 9 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 10 | {{- $nodeSelector = coalesce .Values.nodeSelector .Values.global.nodeSelector }} 11 | {{- end }} 12 | {{- $_ := set .Values.dhcp "syslogIp" (default $publicIP .Values.dhcp.syslogIp) }} 13 | {{- $_ := set .Values.dhcp "ipForPacket" (default $publicIP .Values.dhcp.ipForPacket) }} 14 | {{- $_ := set .Values.dhcp "tftpIp" (default $publicIP .Values.dhcp.tftpIp) }} 15 | {{- $_ := set .Values.dhcp.httpIPXE.binaryUrl "host" (default $publicIP .Values.dhcp.httpIPXE.binaryUrl.host) }} 16 | {{- $_ := set .Values.dhcp.httpIPXE.scriptUrl "host" (default $publicIP .Values.dhcp.httpIPXE.scriptUrl.host) }} 17 | {{- $_ := set .Values.http.tinkServer "ip" (default $publicIP .Values.http.tinkServer.ip) }} 18 | {{- $_ := set .Values.http.osieUrl "host" (default $publicIP .Values.http.osieUrl.host) }} 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | labels: 23 | app: {{ .Values.name }} 24 | name: {{ .Values.name }} 25 | namespace: {{ .Release.Namespace | quote }} 26 | spec: 27 | replicas: {{ .Values.replicas }} 28 | selector: 29 | matchLabels: 30 | app: {{ .Values.name }} 31 | stack: tinkerbell 32 | {{- with .Values.selector }} 33 | {{- toYaml . | nindent 6 }} 34 | {{- end }} 35 | strategy: 36 | type: {{ .Values.deployment.strategy.type }} 37 | template: 38 | metadata: 39 | labels: 40 | app: {{ .Values.name }} 41 | stack: tinkerbell 42 | {{- with .Values.selector }} 43 | {{- toYaml . | nindent 8 }} 44 | {{- end }} 45 | spec: 46 | containers: 47 | - image: {{ .Values.image }} 48 | imagePullPolicy: {{ .Values.imagePullPolicy }} 49 | args: 50 | {{- range .Values.additionalArgs }} 51 | - {{ . }} 52 | {{- end }} 53 | env: 54 | - name: SMEE_LOG_LEVEL 55 | value: {{ .Values.logLevel | quote }} 56 | - name: SMEE_DHCP_ADDR 57 | value: {{ printf "%v:%v" .Values.dhcp.ip .Values.dhcp.port | quote }} 58 | - name: SMEE_DHCP_ENABLED 59 | value: {{ .Values.dhcp.enabled | quote }} 60 | - name: SMEE_DHCP_TFTP_PORT 61 | value: {{ .Values.dhcp.tftpPort | quote }} 62 | - name: SMEE_DHCP_HTTP_IPXE_BINARY_PATH 63 | value: {{ .Values.dhcp.httpIPXE.binaryUrl.path | quote }} 64 | - name: SMEE_DHCP_HTTP_IPXE_BINARY_PORT 65 | value: {{ .Values.dhcp.httpIPXE.binaryUrl.port | quote }} 66 | - name: SMEE_DHCP_HTTP_IPXE_BINARY_SCHEME 67 | value: {{ .Values.dhcp.httpIPXE.binaryUrl.scheme | quote }} 68 | - name: SMEE_DHCP_HTTP_IPXE_SCRIPT_PATH 69 | value: {{ .Values.dhcp.httpIPXE.scriptUrl.path | quote }} 70 | - name: SMEE_DHCP_HTTP_IPXE_SCRIPT_PORT 71 | value: {{ .Values.dhcp.httpIPXE.scriptUrl.port | quote }} 72 | - name: SMEE_DHCP_HTTP_IPXE_SCRIPT_SCHEME 73 | value: {{ .Values.dhcp.httpIPXE.scriptUrl.scheme | quote }} 74 | - name: SMEE_DHCP_MODE 75 | value: {{ .Values.dhcp.mode | quote }} 76 | - name: SMEE_EXTRA_KERNEL_ARGS 77 | value: {{ join " " ( append .Values.http.additionalKernelArgs ( printf "tink_worker_image=%s" ( required "missing tinkWorkerImage" .Values.tinkWorkerImage ) ) ) | quote }} 78 | - name: SMEE_HTTP_IPXE_BINARY_ENABLED 79 | value: {{ .Values.http.ipxeBinaryEnabled | quote }} 80 | - name: SMEE_HTTP_IPXE_SCRIPT_ENABLED 81 | value: {{ .Values.http.ipxeScriptEnabled | quote }} 82 | - name: SMEE_HTTP_PORT 83 | value: {{ .Values.http.port | quote }} 84 | - name: SMEE_OSIE_URL 85 | value: {{include "urlJoiner" (dict "urlDict" .Values.http.osieUrl) | quote }} 86 | - name: SMEE_TINK_SERVER 87 | value: {{ printf "%v:%v" .Values.http.tinkServer.ip .Values.http.tinkServer.port | quote }} 88 | - name: SMEE_TINK_SERVER_TLS 89 | value: {{ .Values.http.tinkServer.tls | quote }} 90 | - name: SMEE_TINK_SERVER_INSECURE_TLS 91 | value: {{ .Values.http.tinkServer.insecureTLS | quote }} 92 | - name: SMEE_TRUSTED_PROXIES 93 | value: {{ required "missing trustedProxies" ( join "," $trustedProxies ) | quote }} 94 | - name: SMEE_SYSLOG_ENABLED 95 | value: {{ .Values.syslog.enabled | quote }} 96 | - name: SMEE_IPXE_SCRIPT_PATCH 97 | value: {{ .Values.ipxeScriptPatch | quote }} 98 | - name: SMEE_TFTP_ENABLED 99 | value: {{ .Values.tftp.enabled | quote }} 100 | - name: SMEE_TFTP_TIMEOUT 101 | value: {{ .Values.tftp.timeout | quote }} 102 | - name: SMEE_TFTP_PORT 103 | value: {{ .Values.tftp.port | quote }} 104 | - name: SMEE_SYSLOG_PORT 105 | value: {{ .Values.syslog.port | quote }} 106 | - name: SMEE_HTTP_ADDR 107 | value: {{ .Values.http.ip | quote }} 108 | - name: SMEE_SYSLOG_ADDR 109 | value: {{ .Values.syslog.ip | quote }} 110 | - name: SMEE_TFTP_ADDR 111 | value: {{ .Values.tftp.ip | quote }} 112 | - name: SMEE_DHCP_HTTP_IPXE_BINARY_HOST 113 | value: {{ .Values.dhcp.httpIPXE.binaryUrl.host | quote }} 114 | - name: SMEE_DHCP_HTTP_IPXE_SCRIPT_HOST 115 | value: {{ .Values.dhcp.httpIPXE.scriptUrl.host | quote }} 116 | - name: SMEE_DHCP_SYSLOG_IP 117 | value: {{ .Values.dhcp.syslogIp | quote }} 118 | - name: SMEE_DHCP_TFTP_IP 119 | value: {{ .Values.dhcp.tftpIp | quote }} 120 | - name: SMEE_DHCP_IP_FOR_PACKET 121 | value: {{ .Values.dhcp.ipForPacket | quote }} 122 | - name: SMEE_ISO_ENABLED 123 | value: {{ .Values.iso.enabled | quote }} 124 | - name: SMEE_ISO_URL 125 | value: {{ .Values.iso.url | quote }} 126 | - name: SMEE_ISO_MAGIC_STRING 127 | value: {{ .Values.iso.magicString | quote }} 128 | - name: SMEE_ISO_STATIC_IPAM_ENABLED 129 | value: {{ .Values.iso.staticIPAMEnabled | quote }} 130 | {{- if eq $roleType "Role"}} 131 | - name: SMEE_BACKEND_KUBE_NAMESPACE 132 | value: {{ .Release.Namespace | quote }} 133 | {{- end }} 134 | {{- range .Values.additionalEnv }} 135 | - name: {{ .name | quote }} 136 | value: {{ .value | quote }} 137 | {{- end }} 138 | {{- if not .Values.hostNetwork }} 139 | ports: 140 | {{- include "smee.ports" ( merge ( dict "PortKey" "containerPort" ) .Values ) | indent 12 }} 141 | {{- end }} 142 | name: {{ .Values.name }} 143 | resources: 144 | limits: 145 | cpu: {{ .Values.resources.limits.cpu }} 146 | memory: {{ .Values.resources.limits.memory }} 147 | requests: 148 | cpu: {{ .Values.resources.requests.cpu }} 149 | memory: {{ .Values.resources.requests.memory }} 150 | {{- with .Values.additionalVolumeMounts }} 151 | volumeMounts: 152 | {{- toYaml . | nindent 12 }} 153 | {{- end }} 154 | {{- with .Values.additionalVolumes }} 155 | volumes: 156 | {{- toYaml . | nindent 8 }} 157 | {{- end }} 158 | serviceAccountName: {{ .Values.name }} 159 | {{- if .Values.hostNetwork }} 160 | hostNetwork: true 161 | {{- end }} 162 | {{- with $nodeSelector }} 163 | nodeSelector: 164 | {{ toYaml . | nindent 8 }} 165 | {{- end }} 166 | {{- if or .Values.deployment.tolerations .Values.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 167 | tolerations: 168 | {{- .Values.deployment.tolerations | toYaml | nindent 8 }} 169 | {{- if .Values.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 170 | {{- include "singleNodeClusterConfig" . | indent 6 }} 171 | {{- end }} 172 | {{- end }} 173 | {{- if .Values.deployment.affinity }} 174 | affinity: 175 | {{- .Values.deployment.affinity | toYaml | nindent 8 }} 176 | {{- else if .Values.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 177 | affinity: 178 | nodeAffinity: 179 | preferredDuringSchedulingIgnoredDuringExecution: 180 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 181 | {{- end }} 182 | {{- end }} 183 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ printf "%sBinding" $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.bindingName }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: {{ $roleType }} 16 | name: {{ .Values.rbac.name }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.name }} 20 | namespace: {{ .Release.Namespace | quote }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | {{- $roleType := .Values.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }} 8 | metadata: 9 | name: {{ .Values.rbac.name }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | rules: 14 | - apiGroups: ["tinkerbell.org"] 15 | resources: ["hardware", "hardware/status"] 16 | verbs: ["get", "list", "watch"] 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.name }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /tinkerbell/smee/templates/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.deploy }} 2 | --- 3 | apiVersion: v1 4 | kind: Service 5 | metadata: 6 | labels: 7 | app: {{ .Values.name }} 8 | name: {{ .Values.name }} 9 | namespace: {{ .Release.Namespace | quote }} 10 | spec: 11 | type: ClusterIP 12 | ports: 13 | - name: tftp 14 | port: 69 15 | targetPort: 69 16 | protocol: UDP 17 | - name: http 18 | port: {{ .Values.http.port }} 19 | targetPort: {{ .Values.http.port }} 20 | protocol: TCP 21 | - name: syslog 22 | port: {{ .Values.syslog.port }} 23 | targetPort: {{ .Values.syslog.port }} 24 | protocol: UDP 25 | - name: dhcp 26 | port: 67 27 | targetPort: 67 28 | protocol: UDP 29 | selector: 30 | app: {{ .Values.name }} 31 | {{- end }} 32 | -------------------------------------------------------------------------------- /tinkerbell/smee/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "properties": { 5 | "http": { 6 | "type": "object", 7 | "properties": { 8 | "trustedProxies": { 9 | "type": "array", 10 | "items": { 11 | "type": "string", 12 | "description": "Specifies one or more IPv4/IPv6 addresses expressed using CIDR notation.", 13 | "anyOf": [ 14 | { 15 | "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$" 16 | }, 17 | { 18 | "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" 19 | } 20 | ] 21 | } 22 | } 23 | } 24 | }, 25 | "rbac": { 26 | "type": "object", 27 | "properties": { 28 | "type": { 29 | "type": "string", 30 | "enum": ["Role", "ClusterRole"] 31 | }, 32 | "name": { 33 | "type": "string" 34 | }, 35 | "bindingName": { 36 | "type": "string" 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tinkerbell/smee/values.yaml: -------------------------------------------------------------------------------- 1 | # Toggle deployment of the service. 2 | deploy: true 3 | 4 | # Name of the service used as the deployment name and label selectors. 5 | name: smee 6 | 7 | # The image used to launch the container. 8 | image: quay.io/tinkerbell/smee:v0.15.1 9 | imagePullPolicy: IfNotPresent 10 | 11 | # The number of pods to run. 12 | replicas: 1 13 | 14 | # Resources bounds applied to the container. 15 | resources: 16 | limits: 17 | cpu: 500m 18 | memory: 128Mi 19 | requests: 20 | cpu: 10m 21 | memory: 64Mi 22 | 23 | deployment: 24 | strategy: 25 | type: RollingUpdate 26 | tolerations: [] 27 | affinity: {} 28 | 29 | # The log level for the container. 30 | logLevel: "info" 31 | 32 | # The network mode to launch the smee container. When true, the smee container will use the 33 | # host network. 34 | hostNetwork: false 35 | 36 | # nodeSelector when defined will be constrain Pods to nodes with specific labels 37 | nodeSelector: {} 38 | 39 | # publicIP when defined will be used as the IP in the following locations if they are not defined: 40 | # dhcp.httpIPXE.binaryUrl.host, dhcp.httpIPXE.scriptUrl.host, tinkServer.ip, http.osieUrl.host, dhcp.ipForPacket, dhcp.tftpIp 41 | # This is useful when all Tinkerbell services are running behind the same IP. 42 | publicIP: "" 43 | 44 | # DHCP server configuration. Name is an identifier used across Kubernetes manifests for port 45 | # identification, ip is the IP address to bind to, and port is the port to bind to. 46 | dhcp: 47 | enabled: true 48 | name: smee-dhcp 49 | mode: reservation 50 | ip: 0.0.0.0 51 | port: 67 52 | ipForPacket: "" 53 | tftpIp: "" 54 | tftpPort: 69 55 | syslogIp: "" 56 | httpIPXE: 57 | binaryUrl: # http://:/ipxe 58 | scheme: "http" 59 | host: "" 60 | port: 7171 61 | path: "/ipxe" 62 | scriptUrl: # http://:/auto.ipxe 63 | scheme: "http" 64 | host: "" 65 | port: 7171 66 | path: "/auto.ipxe" 67 | 68 | # TFTP server configuration used to serve iPXE binaries. Name is an identifier used across 69 | # Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the 70 | # port to bind to. 71 | tftp: 72 | enabled: true 73 | name: smee-tftp 74 | ip: 0.0.0.0 75 | port: 69 76 | timeout: 5s 77 | 78 | # HTTP server configuration used to serve iPXE scripts. Name is an identifier used across 79 | # Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the 80 | # port to bind to. 81 | http: 82 | enabled: true 83 | name: smee-http 84 | ip: 0.0.0.0 85 | port: 7171 86 | # Tink Server configuration passed to the Tink Worker to establish a gRPC connection. 87 | tinkServer: 88 | ip: "" 89 | port: 42113 90 | tls: false 91 | insecureTLS: false 92 | osieUrl: 93 | scheme: "http" 94 | host: "" 95 | port: 8080 96 | path: "" 97 | # Additional kernel arguments to pass to the OSIE. (k=v k=v) that are appended to the kernel cmdline in the iPXE script 98 | additionalKernelArgs: [] 99 | # enable iPXE HTTP binary server 100 | ipxeBinaryEnabled: true 101 | # enable iPXE HTTP script server 102 | ipxeScriptEnabled: true 103 | 104 | # ISO settings 105 | iso: 106 | enabled: false 107 | # the string pattern to match for in the source ISO, defaults to the one defined in HookOS 108 | magicString: "" 109 | # enable static IPAM for HookOS 110 | staticIPAMEnabled: false 111 | # an HTTP(S) URL target to an OSIE that is used for patching 112 | url: "" 113 | 114 | # Trusted proxies defines a list of IP or CIDR ranges that are allowed to set the X-Forwarded-For 115 | # header. This typically requires all Pod CIDRs in the cluster. 116 | trustedProxies: [] 117 | 118 | # Syslog server configuration for the smee hosted syslog server. Name is an identifier used across 119 | # Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the 120 | # port to bind to. 121 | syslog: 122 | enabled: true 123 | name: smee-syslog 124 | ip: 0.0.0.0 125 | port: 514 126 | 127 | # The Tink Worker image passed to OSIE as a kernel arg for launching. 128 | tinkWorkerImage: quay.io/tinkerbell/tink-worker:v0.12.1 129 | 130 | # Additional arguments to pass to the smee container. Some arguments are already defined - refer 131 | # to the deployment.yaml template for details. 132 | additionalArgs: [] 133 | 134 | # Additional environment variables to pass to the smee container. Each entry is expected to have a 135 | # name and value key. Some keys are already defined - refer to the deployment.yaml template for 136 | # details. 137 | # 138 | # Example 139 | # - name: MY_ENV_VAR 140 | # value: my-value 141 | additionalEnv: [] 142 | 143 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 144 | singleNodeClusterConfig: 145 | controlPlaneTolerationsEnabled: false 146 | nodeAffinityWeight: 1 147 | 148 | # Additional volumes on the output Deployment definition. 149 | additionalVolumes: [] 150 | # - name: foo 151 | # secret: 152 | # secretName: mysecret 153 | # optional: false 154 | 155 | # Additional volumeMounts on the Smee container 156 | additionalVolumeMounts: [] 157 | # - name: foo 158 | # mountPath: "/etc/foo" 159 | # readOnly: true 160 | 161 | rbac: 162 | type: Role # or ClusterRole 163 | name: smee-role # or smee-cluster-role 164 | bindingName: smee-rolebinding # or smee-cluster-rolebinding 165 | -------------------------------------------------------------------------------- /tinkerbell/stack/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: tink 3 | repository: file://../tink 4 | version: 0.3.2 5 | - name: smee 6 | repository: file://../smee 7 | version: 0.6.3 8 | - name: rufio 9 | repository: file://../rufio 10 | version: 0.4.2 11 | - name: hegel 12 | repository: file://../hegel 13 | version: 0.4.1 14 | digest: sha256:b38111d9a09a79e26aa5e75b7ed7ac484145ea9be694489761f38d635b8120f4 15 | generated: "2025-01-11T11:14:43.348136337-07:00" 16 | -------------------------------------------------------------------------------- /tinkerbell/stack/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: stack 3 | description: A Helm chart for Kubernetes 4 | icon: https://github.com/tinkerbell/artwork/blob/6f07de53d75cb8932dbc7d14201e038cf3a3b230/Tinkerbell-Icon-Dark.png 5 | 6 | # A chart can be either an 'application' or a 'library' chart. 7 | # 8 | # Application charts are a collection of templates that can be packaged into versioned archives 9 | # to be deployed. 10 | # 11 | # Library charts provide useful utilities or functions for the chart developer. They're included as 12 | # a dependency of application charts to inject those utilities and functions into the rendering 13 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 14 | type: application 15 | 16 | # This is the chart version. This version number should be incremented each time you make changes 17 | # to the chart and its templates, including the app version. 18 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 19 | version: 0.6.3 20 | 21 | # This is the version number of the application being deployed. This version number should be 22 | # incremented each time you make changes to the application. Versions are not expected to 23 | # follow Semantic Versioning. They should reflect the version the application is using. 24 | # It is recommended to use it with quotes. 25 | appVersion: "0.6.3" 26 | 27 | dependencies: 28 | - name: tink 29 | version: "0.3.2" 30 | repository: "file://../tink" 31 | - name: smee 32 | version: "0.6.3" 33 | repository: "file://../smee" 34 | - name: rufio 35 | version: "0.4.2" 36 | repository: "file://../rufio" 37 | - name: hegel 38 | version: "0.4.1" 39 | repository: "file://../hegel" 40 | -------------------------------------------------------------------------------- /tinkerbell/stack/README.md: -------------------------------------------------------------------------------- 1 | # Tinkerbell Stack 2 | 3 | This chart installs the full Tinkerbell stack. 4 | 5 | ## TL;DR 6 | 7 | ```bash 8 | helm dependency build stack/ 9 | trusted_proxies=$(kubectl get nodes -o go-template-file=stack/kubectl.go-template) 10 | LB_IP= 11 | helm install stack-release stack/ --create-namespace --namespace tink --wait --set "global.trustedProxies={${trusted_proxies}}" --set "global.publicIP=$LB_IP" 12 | ``` 13 | 14 | ## Introduction 15 | 16 | This chart boootraps a full Tinkerbell stack on a Kubernetes cluster using the Helm package manager. The Tinkerbell stack consists of the following components: 17 | 18 | - [Smee](https://github.com/tinkerbell/smee) 19 | - [Hegel](https://github.com/tinkerbell/hegel) 20 | - [Tink](https://github.com/tinkerbell/tink) 21 | - [Rufio](https://github.com/tinkerbell/rufio) 22 | - [Hook](https://github.com/tinkerbell/hook) 23 | - Reverse proxy server 24 | - DHCP relay agent 25 | 26 | This chart also installs a load balancer ([kube-vip](https://kube-vip.io/)) in order to be able to provide a service type loadBalancer IP for the Nginx server that handles proxying to all the Tinkerbell services and for serving the Hook artifacts. This kube-vip load balancer is the default but can be disabled if another load balancer is preferred. 27 | 28 | ## Design details 29 | 30 | The stack chart does not use an ingress object and controller. This is because most ingress controllers do not support multi-protocol (UDP, TCP, and gRPC in the Tinkerbell case). Smee uses UDP for DHCP, TFTP, and Syslog services. The ingress controllers that do support UDP require a lot of extra configuration, custom resources, etc. The Tinkerbell stack (Hegel and Smee) also needs the source IP or X-ForwardFor enabled to provide the appropriate data to clients. This is not generally available in an ingress controller. As such, the stack chart deploys a very light weight Nginx deployment with a straightforward configuration that accommodates all the Tinkerbell stack services and serving Hook artifacts. As [Gateway API](https://gateway-api.sigs.k8s.io/) (and the implementations of it) matures there is hope that it will be possible to use it to deploy the Tinkerbell stack instead. 31 | 32 | ## Prerequisites 33 | 34 | - Kubernetes 1.23+ 35 | - Kubectl 1.23+ 36 | - Helm 3.9.4+ 37 | 38 | ## Installing the Chart 39 | 40 | Before installing the chart you'll want to customize the IP used for the load balancer (`global.publicIP`). This IP provides ingress for Hegel, Tink, and Smee (TFTP, HTTP, and SYSLOG endpoints as well as unicast DHCP requests). You'll also need to provide the trusted proxies for the Tinkerbell services. The trusted proxies are the IP addresses of the nodes in the cluster. The trusted proxies are used to set the `X-Forwarded-For` header in the Nginx configuration. This is necessary for the Tinkerbell services to get the correct client IP address. The `kubectl.go-template` file is provided to get the IP addresses of the nodes in the cluster. `kubectl get nodes -o go-template-file=stack/kubectl.go-template` 41 | 42 | Now, deploy the chart. 43 | 44 | ```bash 45 | helm dependency build stack/ 46 | trusted_proxies=$(kubectl get nodes -o go-template-file=stack/kubectl.go-template) 47 | helm install stack-release stack/ --create-namespace --namespace tink-system --wait --set "smee.trustedProxies={${trusted_proxies}}" --set "hegel.trustedProxies={${trusted_proxies}}" 48 | ``` 49 | 50 | These commands install the Tinkerbell Stack chart in the `tink-system` namespace with the release name of `stack-release`. 51 | 52 | ## Uninstalling the Chart 53 | 54 | To uninstall/delete the `stack-release` deployment: 55 | 56 | ```bash 57 | helm uninstall stack-release --namespace tink-system 58 | ``` 59 | 60 | ## Upgrading the Chart 61 | 62 | To upgrade the `stack-release` deployment: 63 | 64 | ```bash 65 | helm upgrade stack-release stack/ --namespace tink-system --wait 66 | ``` 67 | 68 | ## Parameters 69 | 70 | ### Stack Service Parameters 71 | 72 | | Name | Description | Value | 73 | | ---- | ----------- | ----- | 74 | | `stack.enabled` | Enable the deployment of the Tinkerbell stack chart | `true` | 75 | | `stack.name` | Name for the stack chart | `tink-stack` | 76 | | `stack.service.type` | Type of service to use for the Tinkerbell stack services. One of the [standard](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) Kubernetes service types. | `LoadBalancer` | 77 | | `stack.selector` | Selector(s) to use for the mapping stack deployment with the service | `app: tink-stack` | 78 | | `stack.loadBalancerIP` | Load balancer IP address to use for the Tinkerbell stack services | `192.168.2.111` | 79 | | `stack.lbClass` | loadBalancerClass to use for in stack service | `kube-vip.io/kube-vip-class` | 80 | | `stack.image` | Image to use for the proxying to Tinkerbell services and serving artifacts | `nginx:1.23.1` | 81 | | `stack.hook.enabled` | Enable the deployment of the Hook artifacts | `true` | 82 | | `stack.hook.name` | Name for the Hook artifacts server | `hook-files` | 83 | | `stack.hook.port` | Port to use for the Hook artifacts server | `8080` | 84 | | `stack.hook.image` | Image to use for downloading the Hook artifacts | `alpine` | 85 | | `stack.hook.downloadURL` | The base URL where all Hook tarballs and checksum.txt file exist for downloading | `https://github.com/tinkerbell/hook/releases/download/latest` | 86 | 87 | ### Load Balancer Parameters (kube-vip) 88 | 89 | | Name | Description | Value | 90 | | ---- | ----------- | ----- | 91 | | `stack.kubevip.enabled` | Enable the deployment of the kube-vip load balancer | `true` | 92 | | `stack.kubevip.name` | Name for the kube-vip load balancer service | `kube-vip` | 93 | | `stack.kubevip.image` | Image to use for the kube-vip load balancer | `ghcr.io/kube-vip/kube-vip:v0.5.0` | 94 | | `stack.kubevip.imagePullPolicy` | Image pull policy to use for kube-vip | `IfNotPresent` | 95 | | `stack.kubevip.roleName` | Role name to use for the kube-vip load service | `kube-vip-role` | 96 | | `stack.kubevip.roleBindingName` | Role binding name to use for the kube-vip load service | `kube-vip-rolebinding` | 97 | | `stack.kubevip.interface` | Interface to use for advertizing the load balancer IP. Leaving it unset to allow Kubevip to auto discover the interface to use. | `""` | 98 | 99 | ### DHCP Relay Parameters 100 | 101 | | Name | Description | Value | 102 | | ---- | ----------- | ----- | 103 | | `stack.relay.name` | Name for the relay service | `dhcp-relay` | 104 | | `stack.relay.enabled` | Enable the deployment of the DHCP relay service | `true` | 105 | | `stack.relay.image` | Image to use for the DHCP relay service | `ghcr.io/jacobweinstock/dhcrelay` | 106 | | `stack.relay.maxHopCount` | Maximum number of hops to allow for DHCP relay | `10` | 107 | | `stack.relay.sourceInterface` | Host/Node interface to use for listening for DHCP broadcast packets | `eno1` | 108 | | `stack.relay.presentGiaddrAction` | Control the handling of incoming DHCPv4 packets which already contain relay agent options | `append` | 109 | 110 | ### Tinkerbell Services Parameters 111 | 112 | All dependent services(Smee, Hegel, Rufio, Tink) can have their values overridden here. The following format is used to accomplish this. 113 | 114 | ```yaml 115 | : 116 | : 117 | : 118 | - : 119 | ``` 120 | 121 | Example: 122 | 123 | ```yaml 124 | hegel: 125 | image: quay.io/tinkerbell/hegel:latest 126 | ``` 127 | 128 | ### Smee Parameters 129 | 130 | | Name | Description | Value | 131 | | ---- | ----------- | ----- | 132 | | `smee.hostNetwork` | Whether to deploy Smee using `hostNetwork` on the pod spec. When `true` Smee will be able to receive DHCP broadcast messages. If `false`, Smee will be behind the load balancer VIP and will need to receive DHCP requests via unicast. | `true` | 133 | 134 | ### JSON Schema 135 | 136 | Helm has the ability to validate a `values.yaml` file via a JSON schema (`values.schema.json`). See the [Helm documentation](https://helm.sh/docs/topics/charts/#schema-files) for more details. Each chart in the Tinkerbell stack has a very basic schema file that is used to validate either RBAC and/or trusted proxies. Each schema file is located next to the `values.yaml` file for each respective chart. 137 | 138 | ### RBAC 139 | 140 | All Tinkerbell services need RBAC permissions to run in a Kubernetes cluster. There are two options for the type of RBAC that can be used. `Role` or `ClusterRole`. Each chart has its own way to toggle between the two. Most of them are located in their `values.yaml` file under `rbac.type`. There is also a global value in the Stack chart that can be used to set the RBAC type for all services. The global value is `global.rbac.type`. The default for all services and for the global value is `Role`. 141 | 142 | ### Persistence 143 | 144 | The only persistence needed for the Tinkerbell stack is if you are downloading HookOS. By default HookOS is downloaded and stored in a local Persistent Volume. If you're cluster has a different storage class you want ot use, can override the default persistent volume claim by setting the `stack.hook.persistence.existingClaim` value. 145 | -------------------------------------------------------------------------------- /tinkerbell/stack/docs/arch.md: -------------------------------------------------------------------------------- 1 | # Stack Architecture 2 | 3 | The following is a high level diagram of the stack architecture. The stack acts as a lightweight ingress. We don't use an existing ingress controller so as to allow users to bring their own and most/all ingresses don't do all the protocols we require (HTTP, TCP, UDP). With this setup all Tinkerbell services (tink server, hegel and smee) can be accessed via a single IP. 4 | 5 | ```shell 6 | ┌───────────┐ 7 | ┌─────────────────┤ service ├──────────────────┐ 8 | │ └───────────┘ │ 9 | │ Port Protocol Backend Flow │ 10 | │ ---- -------- ------------ │ 11 | │ 50061 TCP Nginx -> Hegel │ 12 | │ 42113 TCP Nginx -> Tink Server │ 13 | │ 8080 TCP Nginx │ 14 | │ 7171 TCP Nginx -> Smee │ 15 | │ 69 UDP Nginx -> Smee │ 16 | │ 514 UDP Nginx -> Smee │ 17 | │ 67 UDP DHCP Relay -> Smee │ 18 | └────────────────────────────────────────────────┘ 19 | ┌───────────┐ 20 | ┌──────────────────────────────┤ pod ├───────────────────────────────┐ 21 | │ └───────────┘ │ 22 | │ ┌────────────────────────────────────┐ │ 23 | │ │ init containers │ │ 24 | │ │ │ │ 25 | │ │ ┌──────────────┐ │ │ 26 | │ │ │ │ │ │ 27 | │ │ │ broadcast │ │ │ 28 | │ │ │listener setup│ │ │ 29 | │ │ │ │ │ │ 30 | │ │ │ │ │ │ 31 | │ │ └──────────────┘ │ │ 32 | │ │ │ │ 33 | │ └────────────────────────────────────┘ │ 34 | │ │ 35 | │ ┌────────────────────────────────────┐ │ 36 | │ │ containers │ │ 37 | │ │ │ │ 38 | │ │ ┌──────────────┐ ┌──────────────┐ │ │ 39 | │ │ │ │ │ │ │ │ 40 | │ │ │ │ │ │ │ │ 41 | │ │ │ nginx │ │ dhcp relay │ │ │ 42 | │ │ │ │ │ │ │ │ 43 | │ │ │ │ │ │ │ │ 44 | │ │ └──────────────┘ └──────────────┘ │ │ 45 | │ │ │ │ │ │ 46 | │ └─────────┼─────────────────┼────────┘ │ 47 | │ │ │ │ 48 | │ │ │ │ 49 | └────────────────────────────┼─────────────────┼───────────────────────────┘ 50 | ┌─────────────┼───────────┐ └────┐ 51 | │ │ │ │ 52 | │ │ 7171/TCP │ 53 | 50061/TCP 42113/TCP 69/UDP 67/UDP 54 | │ │ 514/UDP │ 55 | │ │ │ │ 56 | ▼ ▼ ▼ │ 57 | ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 58 | │ │ │ │ │ │ │ 59 | │ │ │ Tink │ │ │ │ 60 | │ Hegel │ │ Server │ │ Smee │◀─┘ 61 | │ │ │ │ │ │ 62 | │ │ │ │ │ │ 63 | └─────────┘ └─────────┘ └─────────┘ 64 | ``` -------------------------------------------------------------------------------- /tinkerbell/stack/kubectl.go-template: -------------------------------------------------------------------------------- 1 | {{- $first := true -}} 2 | {{- range .items -}} 3 | {{- if not $first}},{{else}}{{$first = false}}{{end -}} 4 | {{- .spec.podCIDR -}} 5 | {{- end -}} -------------------------------------------------------------------------------- /tinkerbell/stack/templates/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/stack/templates/hook.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.stack.enabled .Values.stack.hook.enabled }} 2 | --- 3 | apiVersion: v1 4 | kind: ConfigMap 5 | metadata: 6 | name: download-hook 7 | namespace: {{ .Release.Namespace }} 8 | data: 9 | entrypoint.sh: |- 10 | #!/usr/bin/env bash 11 | 12 | set -euo pipefail 13 | 14 | function usage() { 15 | echo "Usage: $0 [OPTION]..." 16 | echo "Script for downloading HookOS artifacts" 17 | echo 18 | echo "Options:" 19 | echo " -u, --url Base URL to the location of the HookOS artifacts (default: https://github.com/tinkerbell/hook/releases/download/latest)" 20 | echo " -a, --arch Architectures to download, one of [x86_64, aarch64, both] (default: both)" 21 | echo " -v, --version The kernel version of the HookOS artifacts to download, one of [5.10, 6.6, both] (default: 6.6)" 22 | echo " -e, --ext The artifact extension types to download, one of [tar.gz, iso, both] (default: both)" 23 | echo " -s, --specific-artifacts List of non-standard artifacts to download" 24 | echo " -o, --output-dir Output directory to store the downloaded artifacts (default: .)" 25 | echo " -h, --help Display this help and exit" 26 | } 27 | 28 | function validate_option() { 29 | local option="$1" 30 | local valid_values="$2" 31 | local value="$3" 32 | 33 | if [[ ! " ${valid_values[@]} " =~ " ${value} " ]]; then 34 | >&2 echo "Invalid value: '$value' for '${option}'. Valid values are: [${valid_values[*]}]" 35 | usage 36 | exit 1 37 | fi 38 | } 39 | 40 | 41 | function get_by_kernel_version() { 42 | # data must be newline separated list of artifacts 43 | local data="$1" 44 | local version="$2" 45 | local artifacts="" 46 | 47 | if [[ "${version}" == "both" ]]; then 48 | artifacts+=$(grep -v "latest-lts" <<< $data)$'\n' 49 | artifacts+=$(grep "latest-lts" <<< "$data") 50 | elif [[ "${version}" == "6.6" ]]; then 51 | artifacts=$(grep "latest-lts" <<< "$data") 52 | elif [[ "${version}" == "5.10" ]]; then 53 | artifacts=$(grep -v "latest-lts" <<< "$data") 54 | fi 55 | 56 | echo "${artifacts}" 57 | } 58 | 59 | function get_by_extension() { 60 | local data="$1" 61 | local ext="$2" 62 | local artifacts="" 63 | 64 | if [[ "${ext}" == "both" ]]; then 65 | artifacts=$(grep ".tar.gz" <<< "$data")$'\n' 66 | artifacts+=$(grep ".iso" <<< "$data") 67 | elif [[ "${ext}" == "tar.gz" ]]; then 68 | artifacts=$(grep ".tar.gz" <<< "$data") 69 | elif [[ "${ext}" == "iso" ]]; then 70 | artifacts=$(grep ".iso" <<< "$data") 71 | fi 72 | 73 | echo "${artifacts}" 74 | } 75 | 76 | function get_by_arch() { 77 | local data="$1" 78 | local arch="$2" 79 | local artifacts="" 80 | 81 | if [[ "${arch}" == "both" ]]; then 82 | artifacts+=$(grep "x86_64" <<< "$data")$'\n' 83 | artifacts+=$(grep "aarch64" <<< "$data") 84 | elif [[ "${arch}" == "x86_64" ]]; then 85 | artifacts=$(grep "x86_64" <<< "$data") 86 | elif [[ "${arch}" == "aarch64" ]]; then 87 | artifacts=$(grep "aarch64" <<< "$data") 88 | fi 89 | 90 | echo "${artifacts}" 91 | } 92 | 93 | function download_artifacts() { 94 | local url="$1" 95 | local artifacts="$2" 96 | local out_dir="$3" 97 | 98 | while IFS= read -r line; do 99 | wget -O "${out_dir}/${line}" "${url}/${line}" 100 | done < <(printf '%s\n' "$artifacts") 101 | } 102 | 103 | function run_checksum512() { 104 | local checksum_data="$1" 105 | local out_dir="$2" 106 | 107 | (cd "${out_dir}" && sha512sum -c <<< "${checksum_data}") 108 | if [ $? -ne 0 ]; then 109 | return 1 110 | fi 111 | return 0 112 | } 113 | 114 | function checksum_format() { 115 | # data is a newline separated list of artifacts 116 | local data="$1" 117 | local raw="$2" 118 | local checksums="" 119 | 120 | while IFS= read -r line; do 121 | checksums+=$(grep "${line}" <<< "${raw}")$'\n' 122 | done < <(printf '%s\n' "$data") 123 | 124 | echo "${checksums}" 125 | } 126 | 127 | # default values 128 | url="https://github.com/tinkerbell/hook/releases/download/latest" 129 | arch="both" 130 | version="6.6" 131 | ext="both" 132 | specific_artifacts=() 133 | output_dir="." 134 | 135 | # valid options 136 | valid_arches=("x86_64" "aarch64" "both") 137 | valid_versions=("5.10" "6.6" "both") 138 | valid_exts=("tar.gz" "iso" "both") 139 | 140 | args=$(getopt -a -o u:a:v:e:s:o:h --long url:,arch:,version:,ext:,specific-artifacts:,output-dir:,help -- "$@") 141 | if [[ $? -gt 0 ]]; then 142 | usage 143 | fi 144 | 145 | eval set -- ${args} 146 | while : 147 | do 148 | case $1 in 149 | -u | --url) 150 | if [[ ! -z $2 ]]; then 151 | url=$2 152 | fi 153 | shift 2 ;; 154 | -a | --arch) 155 | if [[ ! -z $2 ]]; then 156 | validate_option "arch" "${valid_arches[*]}" $2 157 | arch=$2 158 | fi 159 | shift 2 ;; 160 | -v | --version) 161 | if [[ ! -z $2 ]]; then 162 | validate_option "version" "${valid_versions[*]}" $2 163 | version=$2 164 | fi 165 | shift 2 ;; 166 | -e | --ext) 167 | if [[ ! -z $2 ]]; then 168 | validate_option "ext" "${valid_exts[*]}" $2 169 | ext=$2 170 | fi 171 | shift 2 ;; 172 | -s | --specific-artifacts) 173 | if [[ ! -z $2 ]]; then 174 | specific_artifacts=$2 175 | fi 176 | shift 2 ;; 177 | -o | --output-dir) 178 | if [[ ! -z $2 ]]; then 179 | output_dir=$2 180 | fi 181 | shift 2 ;; 182 | -h | --help) 183 | usage 184 | exit 1 185 | shift ;; 186 | # -- means the end of the arguments; drop this, and break out of the while loop 187 | --) shift; break ;; 188 | *) >&2 echo Unsupported option: $1 189 | usage ;; 190 | esac 191 | done 192 | 193 | echo "==> Downloading HookOS artifacts from ${url} for architecture(s): ${arch} and extension(s): ${ext} and version(s): ${version}" 194 | 195 | # 1. Download the checksum file 196 | # 2. Generate a list of artifacts to download based on the options provided 197 | # 3. Run a checksum check for all artifacts to be downloaded. For artifacts that pass (meaning the artifact is already downloaded), do nothing. Make a list of artifacts that need downloaded. 198 | # 4. If all artifacts are already downloaded, sleep and wait for signals. 199 | # 5. Download artifacts that need downloaded. 200 | # 6. Run a checksum check for all downloaded artifacts. 201 | # 7. If all checksums pass, sleep and wait for signals. If any checksum fails, exit with 1. 202 | 203 | function main() { 204 | local checksum_file="${output_dir}/checksum.txt" 205 | 206 | # 1. 207 | echo "==> Downloading checksum file from ${url}" 208 | if ! wget -O "${checksum_file}" ${url}/checksum.txt; then 209 | echo "==> Failed to download checksum file: ${url}/checksum.txt" 210 | return 1 211 | fi 212 | 213 | # 2. 214 | echo "==> Parsing checksum file" 215 | raw_data=$(cat "${checksum_file}") 216 | data=$(cat "${checksum_file}" | awk '{print $2}') 217 | by_kernel=$(get_by_kernel_version "${data}" "${version}") 218 | by_extension=$(get_by_extension "${by_kernel}" "${ext}") 219 | filtered=$(get_by_arch "${by_extension}" "${arch}") 220 | 221 | # 3. 222 | echo "==> Running initial checksum check for all artifacts" 223 | checksums=$(checksum_format "${filtered}" "${raw_data}") 224 | if run_checksum512 "${checksums}" "${output_dir}"; then 225 | cd "${output_dir}" 226 | echo "==> Extracting existing artifacts" 227 | for f in $(ls *.tar.gz | grep -vE "^dtbs"); do echo "==> Extracting ${f}"; tar --no-same-permissions --overwrite -ozxvf "${f}"; done 228 | return 0 229 | fi 230 | 231 | # 5. 232 | echo "==> Downloading artifacts" 233 | download_artifacts "${url}" "${filtered}" "${output_dir}" 234 | checksums=$(checksum_format "${filtered}" "${raw_data}") 235 | echo "==> Running checksum check for all downloaded artifacts" 236 | if ! run_checksum512 "${checksums}" "${output_dir}"; then 237 | echo "==> Checksum failed for some artifacts" 238 | return 1 239 | fi 240 | cd "${output_dir}" 241 | echo "==> Extracting artifacts" 242 | for f in $(ls *.tar.gz | grep -vE "^dtbs"); do echo "==> Extracting ${f}"; tar --no-same-permissions --overwrite -ozxvf "${f}"; done 243 | } 244 | 245 | if ! main; then 246 | exit 1 247 | fi 248 | 249 | echo "==> All artifacts available, waiting for signals..." 250 | sleep infinity & PID=$! 251 | trap "kill $PID" INT TERM 252 | wait $PID 253 | 254 | {{- end }} 255 | -------------------------------------------------------------------------------- /tinkerbell/stack/templates/init_configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.stack.enabled .Values.stack.relay.enabled }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: host-interface-script 6 | data: 7 | host_interface.sh: | 8 | #!/usr/bin/env sh 9 | 10 | # This script allows us to listen and respond to DHCP requests on a host network interface and interact with Smee properly. 11 | # This is used instead of `hostNetwork: true` because the dhcp relay requires clear paths for listening for broadcast traffic 12 | # and sending/receiving unicast traffic to/from Smee. 13 | 14 | set -xeuo pipefail 15 | 16 | function usage() { 17 | echo "Usage: $0 [OPTION]..." 18 | echo "Init script for setting up a network interface to listen and respond to DHCP requests from the Host and move it into a container." 19 | echo 20 | echo "Options:" 21 | echo " -s, --src Source interface for listening and responding to DHCP requests (default: default gateway interface)" 22 | echo " -t, --type Create the interface of type, must be either ipvlan or macvlan (default: macvlan)" 23 | echo " -c, --clean Clean up any interfaces created" 24 | echo " -h, --help Display this help and exit" 25 | } 26 | 27 | function binary_exists() { 28 | command -v "$1" >/dev/null 2>&1 29 | } 30 | 31 | function main() { 32 | local src_interface="$1" 33 | local interface_type="$2" 34 | local interface_mode="$3" 35 | local interface_name="${interface_type}0" 36 | 37 | # Preparation 38 | # Delete existing interfaces in the container 39 | ip link del macvlan0 || true 40 | ip link del ipvlan0 || true 41 | ip link del ipvlan0-wa || true 42 | # Delete existing interfaces in the host namespace 43 | nsenter -t1 -n ip link del macvlan0 || true 44 | nsenter -t1 -n ip link del ipvlan0 || true 45 | nsenter -t1 -n ip link del ipvlan0-wa || true 46 | # Create the interface 47 | nsenter -t1 -n ip link add "${interface_name}" link "${src_interface}" type "${interface_type}" mode "${interface_mode}" || true 48 | # Move the interface into the Pod container 49 | pid=$(echo $$) 50 | nsenter -t1 -n ip link set "${interface_name}" netns ${pid} || nsenter -t1 -n ip link delete "${interface_name}" 51 | # Bring up the interface 52 | ip link set dev "${interface_name}" up 53 | # Set the IP address 54 | ip addr add 127.1.1.1/32 dev "${interface_name}" noprefixroute || true 55 | # Run ipvlan workaround 56 | # There is an issue with ipvlan interfaces. They do not start receiving broadcast packets after creation. 57 | # This is a workaround to get broadcast packets flowing. 58 | # TODO(jacobweinstock): Investigate this deeper and see if this is a kernel bug. 59 | if [[ "${interface_type}" == "ipvlan" ]]; then 60 | nsenter -t1 -n nmap --script broadcast-dhcp-discover 61 | nsenter -t1 -n ip link add "${interface_name}"-wa link "${src_interface}" type "${interface_type}" mode "${interface_mode}" bridge || true 62 | nsenter -t1 -n nmap --script broadcast-dhcp-discover 63 | fi 64 | } 65 | 66 | src_interface=$(nsenter -t1 -n ip route | awk '/default/ {print $5}' | head -n1) 67 | interface_type="macvlan" 68 | interface_mode="bridge" 69 | clean=false 70 | args=$(getopt -a -o s:t:ch --long src:,type:,clean,help -- "$@") 71 | if [[ $? -gt 0 ]]; then 72 | usage 73 | fi 74 | 75 | eval set -- ${args} 76 | while : 77 | do 78 | case $1 in 79 | -s | --src) 80 | if [[ ! -z $2 ]]; then 81 | src_interface=$2 82 | fi 83 | shift 2 ;; 84 | -t | --type) 85 | if [[ "$2" == "ipvlan" ]]; then 86 | interface_type="ipvlan" 87 | interface_mode="l2" 88 | fi 89 | shift 2 ;; 90 | -c | --clean) 91 | clean=true 92 | shift ;; 93 | -h | --help) 94 | usage 95 | exit 1 96 | shift ;; 97 | # -- means the end of the arguments; drop this, and break out of the while loop 98 | --) shift; break ;; 99 | *) >&2 echo Unsupported option: $1 100 | usage ;; 101 | esac 102 | done 103 | 104 | if "${clean}"; then 105 | # Delete existing interfaces in the container 106 | ip link del macvlan0 || true 107 | ip link del ipvlan0 || true 108 | ip link del ipvlan0-wa || true 109 | # Delete existing interfaces in the host namespace 110 | nsenter -t1 -n ip link del macvlan0 || true 111 | nsenter -t1 -n ip link del ipvlan0 || true 112 | nsenter -t1 -n ip link del ipvlan0-wa || true 113 | exit 0 114 | fi 115 | main "${src_interface}" "${interface_type}" "${interface_mode}" 116 | {{- end }} 117 | -------------------------------------------------------------------------------- /tinkerbell/stack/templates/kubevip.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.stack.enabled .Values.stack.kubevip.enabled }} 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: {{ .Values.stack.kubevip.name }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | labels: 8 | app.kubernetes.io/name: {{ .Values.stack.kubevip.name }} 9 | spec: 10 | selector: 11 | matchLabels: 12 | app.kubernetes.io/name: {{ .Values.stack.kubevip.name }} 13 | template: 14 | metadata: 15 | labels: 16 | app.kubernetes.io/name: {{ .Values.stack.kubevip.name }} 17 | spec: 18 | containers: 19 | - args: 20 | - manager 21 | env: 22 | - name: vip_arp 23 | value: "true" 24 | - name: svc_enable 25 | value: "true" 26 | - name: svc_election 27 | value: "true" 28 | - name: enableServicesElection 29 | value: "true" 30 | {{- range .Values.stack.kubevip.additionalEnv }} 31 | - name: {{ .name | quote }} 32 | value: {{ .value | quote }} 33 | {{- end }} 34 | {{- with .Values.stack.kubevip.interface }} 35 | - name: vip_interface 36 | value: {{ . }} 37 | {{- end }} 38 | image: {{ .Values.stack.kubevip.image }} 39 | imagePullPolicy: {{ .Values.stack.kubevip.imagePullPolicy }} 40 | name: {{ .Values.stack.kubevip.name }} 41 | securityContext: 42 | capabilities: 43 | add: 44 | - NET_ADMIN 45 | - NET_RAW 46 | hostNetwork: true 47 | serviceAccountName: {{ .Values.stack.kubevip.name }} 48 | {{- if .Values.stack.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 49 | tolerations: 50 | {{- include "singleNodeClusterConfig" (dict "nodeAffinityWeight" .Values.stack.singleNodeClusterConfig.nodeAffinityWeight) | indent 6 }} 51 | {{- end }} 52 | --- 53 | apiVersion: v1 54 | kind: ServiceAccount 55 | metadata: 56 | name: {{ .Values.stack.kubevip.name }} 57 | namespace: {{ .Release.Namespace | quote }} 58 | --- 59 | apiVersion: rbac.authorization.k8s.io/v1 60 | kind: ClusterRole 61 | metadata: 62 | annotations: 63 | rbac.authorization.kubernetes.io/autoupdate: "true" 64 | name: {{ .Values.stack.kubevip.roleName }} 65 | rules: 66 | - apiGroups: [""] 67 | resources: 68 | - "services" 69 | - "services/status" 70 | - "nodes" 71 | - "endpoints" 72 | verbs: 73 | - "list" 74 | - "get" 75 | - "watch" 76 | - "update" 77 | - apiGroups: 78 | - "coordination.k8s.io" 79 | resources: 80 | - "leases" 81 | verbs: 82 | - "list" 83 | - "get" 84 | - "watch" 85 | - "update" 86 | - "create" 87 | --- 88 | apiVersion: rbac.authorization.k8s.io/v1 89 | kind: ClusterRoleBinding 90 | metadata: 91 | name: {{ .Values.stack.kubevip.roleBindingName }} 92 | roleRef: 93 | apiGroup: rbac.authorization.k8s.io 94 | kind: ClusterRole 95 | name: {{ .Values.stack.kubevip.roleName }} 96 | subjects: 97 | - kind: ServiceAccount 98 | name: {{ .Values.stack.kubevip.name }} 99 | namespace: {{ .Release.Namespace | quote }} 100 | {{- end }} -------------------------------------------------------------------------------- /tinkerbell/stack/templates/nginx-configmap.yaml: -------------------------------------------------------------------------------- 1 | {{ if .Values.stack.enabled -}} 2 | # The NGINX ConfigMap is in a separate file because its checksum is used to trigger updates in 3 | # the deployment. 4 | apiVersion: v1 5 | kind: ConfigMap 6 | metadata: 7 | name: nginx-conf 8 | namespace: {{ .Release.Namespace | quote }} 9 | data: 10 | nginx.conf: | 11 | worker_processes 1; 12 | events { 13 | worker_connections 1024; 14 | } 15 | user root; 16 | 17 | http { 18 | {{- if or (not .Values.smee.hostNetwork) (not .Values.smee.deploy) }} 19 | server { 20 | listen {{ .Values.smee.http.port }}; 21 | location / { 22 | proxy_set_header X-Real-IP $remote_addr; 23 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 24 | resolver $POD_NAMESERVER; 25 | set $smee_dns {{ .Values.smee.name }}.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}.; # needed in Kubernetes for dynamic DNS resolution 26 | 27 | proxy_pass http://$smee_dns:{{ .Values.smee.http.port }}; 28 | } 29 | } 30 | {{- end }} 31 | 32 | server { 33 | listen {{ .Values.hegel.service.port }}; 34 | location / { 35 | proxy_set_header X-Real-IP $remote_addr; 36 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 37 | resolver $POD_NAMESERVER; 38 | set $hegel_dns {{ .Values.hegel.name }}.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}.; # needed in Kubernetes for dynamic DNS resolution 39 | 40 | proxy_pass http://$hegel_dns:{{ .Values.hegel.service.port }}; 41 | } 42 | } 43 | 44 | server { 45 | listen {{ .Values.tink.server.service.port }}; 46 | http2 on; 47 | location / { 48 | proxy_set_header X-Real-IP $remote_addr; 49 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 50 | resolver $POD_NAMESERVER; 51 | set $tink_dns {{ .Values.tink.server.name }}.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}.; # needed in Kubernetes for dynamic DNS resolution 52 | 53 | grpc_pass grpc://$tink_dns:{{ .Values.tink.server.service.port }}; 54 | } 55 | } 56 | 57 | server { 58 | listen {{ .Values.stack.hook.port }}; 59 | location / { 60 | sendfile on; 61 | sendfile_max_chunk 1m; 62 | root /usr/share/nginx/html; 63 | } 64 | } 65 | } 66 | 67 | stream { 68 | log_format logger-json escape=json '{"source": "nginx", "time": $msec, "address": "$remote_addr", "status": $status, "upstream_addr": "$upstream_addr"}'; 69 | 70 | {{- if or (not .Values.smee.hostNetwork) (not .Values.smee.deploy) }} 71 | server { 72 | listen {{ .Values.smee.tftp.port }} udp; 73 | resolver $POD_NAMESERVER; 74 | set $smee_dns {{ .Values.smee.name }}.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}.; # needed in Kubernetes for dynamic DNS resolution 75 | proxy_pass $smee_dns:{{ .Values.smee.tftp.port }}; 76 | access_log /dev/stdout logger-json; 77 | } 78 | server { 79 | listen {{ .Values.smee.syslog.port }} udp; 80 | resolver $POD_NAMESERVER; 81 | set $smee_dns {{ .Values.smee.name }}.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}.; # needed in Kubernetes for dynamic DNS resolution 82 | proxy_pass $smee_dns:{{ .Values.smee.syslog.port }}; 83 | access_log /dev/stdout logger-json; 84 | } 85 | {{- end }} 86 | } 87 | {{- end }} 88 | -------------------------------------------------------------------------------- /tinkerbell/stack/templates/nginx.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.stack.enabled }} 2 | {{- $sourceInterface := .Values.stack.relay.sourceInterface -}} 3 | {{- $ifaceModes := dict "ipvlan" "" "macvlan" "" -}} 4 | {{- $dhcpInterfaceType := .Values.stack.relay.interfaceMode -}} 5 | {{- $nodeSelector := .Values.stack.nodeSelector }} 6 | {{- if not (hasKey $ifaceModes $dhcpInterfaceType) -}} 7 | {{- fail "invalid value at .stack.relay.interfaceMode: valid modes include ipvlan and macvlan" -}} 8 | {{- end -}} 9 | {{- $dhcpInterfaceName := printf "%s0" $dhcpInterfaceType -}} 10 | {{- $listenBroadcast := true -}} 11 | {{- if not (quote .Values.stack.relay.listenBroadcastTraffic | empty) -}} 12 | {{- $listenBroadcast = .Values.stack.relay.listenBroadcastTraffic -}} 13 | {{- end -}} 14 | {{- if not $listenBroadcast -}} 15 | {{- $dhcpInterfaceName = "eth0" -}} 16 | {{- end -}} 17 | {{- if .Values.global }} 18 | {{- $nodeSelector = coalesce .Values.stack.nodeSelector .Values.global.nodeSelector }} 19 | {{- end -}} 20 | {{- $claimName := coalesce .Values.stack.hook.persistence.existingClaim .Values.stack.hook.persistence.localPersistentVolume.name }} 21 | apiVersion: apps/v1 22 | kind: Deployment 23 | metadata: 24 | name: {{ .Values.stack.name}} 25 | namespace: {{ .Release.Namespace | quote }} 26 | spec: 27 | selector: 28 | matchLabels: 29 | {{- with .Values.stack.selector }} 30 | {{- toYaml . | nindent 6 }} 31 | {{- end }} 32 | replicas: 1 33 | strategy: 34 | type: {{ .Values.stack.deployment.strategy.type }} 35 | template: 36 | metadata: 37 | annotations: 38 | checksum/config: {{ include (print $.Template.BasePath "/nginx-configmap.yaml") . | sha256sum }} 39 | labels: 40 | {{- with .Values.stack.selector }} 41 | {{- toYaml . | nindent 8 }} 42 | {{- end }} 43 | spec: 44 | {{- if not .Values.stack.service.enabled }} 45 | hostNetwork: true 46 | dnsPolicy: ClusterFirstWithHostNet 47 | {{- end }} 48 | hostPID: true 49 | containers: 50 | - name: {{ .Values.stack.name }} 51 | image: {{ .Values.stack.image }} 52 | command: ["/bin/bash", "-xeuc"] 53 | args: 54 | - | 55 | export POD_NAMESERVER=$(awk '/nameserver/ {print $2}' /etc/resolv.conf); 56 | [[ $POD_NAMESERVER == *.* ]] || POD_NAMESERVER="[$POD_NAMESERVER]"; 57 | envsubst '$POD_NAMESERVER' \ 58 | /etc/nginx/nginx.conf 60 | exec nginx -g 'daemon off;' 61 | ports: 62 | - containerPort: {{ .Values.hegel.deployment.port }} 63 | protocol: TCP 64 | name: {{ .Values.hegel.deployment.portName }} 65 | - containerPort: {{ .Values.tink.server.deployment.port }} 66 | protocol: TCP 67 | name: {{ .Values.tink.server.deployment.portName }} 68 | - containerPort: {{ .Values.stack.hook.port }} 69 | protocol: TCP 70 | name: hook-http 71 | {{- if and (not .Values.smee.hostNetwork) (.Values.smee.deploy) }} 72 | - containerPort: {{ .Values.smee.http.port }} 73 | protocol: TCP 74 | name: {{ .Values.smee.http.name }} 75 | - containerPort: {{ .Values.smee.tftp.port }} 76 | protocol: UDP 77 | name: {{ .Values.smee.tftp.name }} 78 | - containerPort: {{ .Values.smee.syslog.port }} 79 | protocol: UDP 80 | name: {{ .Values.smee.syslog.name }} 81 | {{- end }} 82 | resources: 83 | limits: 84 | cpu: 500m 85 | memory: 128Mi 86 | requests: 87 | cpu: 10m 88 | memory: 64Mi 89 | volumeMounts: 90 | - mountPath: /tmp 91 | readOnly: true 92 | name: nginx-conf 93 | {{- if .Values.stack.hook.enabled }} 94 | - mountPath: /usr/share/nginx/html 95 | name: hook-artifacts 96 | {{- end }} 97 | {{- if .Values.stack.relay.enabled }} 98 | - name: {{ .Values.stack.relay.name }} 99 | image: {{ .Values.stack.relay.image }} 100 | args: ["-m", "{{ .Values.stack.relay.presentGiaddrAction }}", "-c", "{{ .Values.stack.relay.maxHopCount }}", "-id", "{{ $dhcpInterfaceName }}", "-iu", "eth0", "-U", "eth0", "smee.{{ .Release.Namespace }}.svc.{{ .Values.stack.clusterDomain }}."] 101 | ports: 102 | - containerPort: 67 103 | protocol: UDP 104 | name: dhcp 105 | resources: 106 | limits: 107 | cpu: 500m 108 | memory: 128Mi 109 | requests: 110 | cpu: 10m 111 | memory: 64Mi 112 | securityContext: 113 | capabilities: 114 | add: 115 | - NET_RAW 116 | {{- end }} 117 | {{- if .Values.stack.hook.enabled }} 118 | - name: download-hook 119 | image: {{ .Values.stack.hook.image }} 120 | command: ["/script/entrypoint.sh"] 121 | args: ["--url", "{{ .Values.stack.hook.downloadURL }}", "--output-dir", "/output", "--arch", "{{ .Values.stack.hook.arch }}", "--version", "{{ .Values.stack.hook.kernelVersion }}", "--ext", "{{ .Values.stack.hook.extension }}"] 122 | volumeMounts: 123 | - mountPath: /output 124 | name: hook-artifacts 125 | - mountPath: /script 126 | name: configmap-volume 127 | {{- end }} 128 | volumes: 129 | - name: nginx-conf 130 | configMap: 131 | name: nginx-conf 132 | items: 133 | - key: nginx.conf 134 | path: nginx.conf.template 135 | {{- if and .Values.stack.relay.enabled $listenBroadcast }} 136 | - name: script 137 | configMap: 138 | name: host-interface-script 139 | defaultMode: 0500 140 | {{- end }} 141 | {{- if .Values.stack.hook.enabled }} 142 | - name: hook-artifacts 143 | persistentVolumeClaim: 144 | claimName: {{ $claimName }} 145 | - name: configmap-volume 146 | configMap: 147 | defaultMode: 0700 148 | name: download-hook 149 | {{- end }} 150 | {{- if and .Values.stack.relay.enabled $listenBroadcast }} 151 | initContainers: 152 | - name: relay-broadcast-interface 153 | image: {{ .Values.stack.relay.initImage }} 154 | command: ["/script/host_interface.sh", "-s", "{{ $sourceInterface }}", "-t", "{{ $dhcpInterfaceType }}"] 155 | volumeMounts: 156 | - name: script 157 | mountPath: "/script" 158 | securityContext: 159 | privileged: true 160 | {{- end }} 161 | {{- with $nodeSelector }} 162 | nodeSelector: 163 | {{ toYaml . | nindent 8 }} 164 | {{- end }} 165 | {{- if .Values.stack.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 166 | tolerations: 167 | {{- include "singleNodeClusterConfig" . | indent 6 }} 168 | affinity: 169 | nodeAffinity: 170 | preferredDuringSchedulingIgnoredDuringExecution: 171 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.stack.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 172 | {{- end }} 173 | {{- if .Values.stack.service.enabled }} 174 | --- 175 | apiVersion: v1 176 | kind: Service 177 | metadata: 178 | labels: 179 | app: {{ .Values.stack.name }} 180 | name: {{ .Values.stack.name }} 181 | namespace: {{ .Release.Namespace | quote }} 182 | annotations: 183 | {{- with .Values.stack.service.annotations }} 184 | {{- toYaml . | nindent 4 }} 185 | {{- end }} 186 | spec: 187 | type: {{ .Values.stack.service.type }} 188 | {{- if eq .Values.stack.service.type "LoadBalancer" }} 189 | {{- if .Values.stack.lbClass }} 190 | loadBalancerClass: {{ .Values.stack.lbClass }} 191 | {{- end }} 192 | loadBalancerIP: {{ coalesce .Values.stack.loadBalancerIP .Values.global.publicIP }} 193 | externalTrafficPolicy: Local 194 | {{- end }} 195 | ports: 196 | - name: {{ .Values.hegel.name }} 197 | port: {{ .Values.hegel.deployment.port }} 198 | protocol: TCP 199 | - name: {{ .Values.tink.server.name }} 200 | port: {{ .Values.tink.server.deployment.port }} 201 | protocol: TCP 202 | - name: {{ .Values.stack.hook.name }} 203 | port: {{ .Values.stack.hook.port }} 204 | protocol: TCP 205 | {{- if and (not .Values.smee.hostNetwork) (.Values.smee.deploy) }} 206 | - port: {{ .Values.smee.http.port }} 207 | protocol: TCP 208 | name: {{ .Values.smee.http.name }} 209 | - port: {{ .Values.smee.tftp.port }} 210 | protocol: UDP 211 | name: {{ .Values.smee.tftp.name }} 212 | - port: {{ .Values.smee.syslog.port }} 213 | protocol: UDP 214 | name: {{ .Values.smee.syslog.name }} 215 | {{- end }} 216 | {{- if .Values.stack.relay.enabled }} 217 | - port: 67 218 | protocol: UDP 219 | name: dhcp 220 | {{- end }} 221 | selector: 222 | {{- with .Values.stack.selector }} 223 | {{- toYaml . | nindent 4 }} 224 | {{- end }} 225 | {{- end }} 226 | {{- end }} 227 | -------------------------------------------------------------------------------- /tinkerbell/stack/templates/nginx_pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.stack.enabled .Values.stack.hook.enabled (empty .Values.stack.hook.persistence.existingClaim ) }} 2 | --- 3 | kind: StorageClass 4 | apiVersion: storage.k8s.io/v1 5 | metadata: 6 | name: {{ .Values.stack.hook.persistence.localPersistentVolume.storageClassName }} 7 | namespace: {{ .Release.Namespace }} 8 | provisioner: kubernetes.io/no-provisioner 9 | volumeBindingMode: WaitForFirstConsumer 10 | --- 11 | apiVersion: v1 12 | kind: PersistentVolume 13 | metadata: 14 | name: {{ .Values.stack.hook.persistence.localPersistentVolume.name }} 15 | namespace: {{ .Release.Namespace }} 16 | spec: 17 | capacity: 18 | storage: {{ .Values.stack.hook.persistence.localPersistentVolume.size }} 19 | accessModes: 20 | {{- range .Values.stack.hook.persistence.localPersistentVolume.accessModes }} 21 | - {{ . | quote }} 22 | {{- end }} 23 | persistentVolumeReclaimPolicy: Retain 24 | storageClassName: {{ .Values.stack.hook.persistence.localPersistentVolume.storageClassName }} 25 | local: 26 | path: {{ .Values.stack.hook.persistence.localPersistentVolume.path }} 27 | nodeAffinity: 28 | required: 29 | nodeSelectorTerms: 30 | - matchExpressions: 31 | - key: non-existent-label # this label with DoesNotExist should match all nodes 32 | operator: DoesNotExist 33 | --- 34 | apiVersion: v1 35 | kind: PersistentVolumeClaim 36 | metadata: 37 | name: hook-artifacts 38 | namespace: {{ .Release.Namespace }} 39 | labels: 40 | {{- with .Values.stack.hook.persistence.localPersistentVolume.extraLabels }} 41 | {{- toYaml . | nindent 4 }} 42 | {{- end }} 43 | spec: 44 | accessModes: 45 | {{- range .Values.stack.hook.persistence.localPersistentVolume.accessModes }} 46 | - {{ . | quote }} 47 | {{- end }} 48 | resources: 49 | requests: 50 | storage: {{ .Values.stack.hook.persistence.localPersistentVolume.size | quote }} 51 | storageClassName: {{ .Values.stack.hook.persistence.localPersistentVolume.storageClassName }} 52 | {{- end }} 53 | -------------------------------------------------------------------------------- /tinkerbell/stack/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "global": { 6 | "type": "object", 7 | "properties": { 8 | "publicIP": { 9 | "type": "string" 10 | }, 11 | "rbac": { 12 | "type": "object", 13 | "properties": { 14 | "type": { 15 | "type": "string", 16 | "enum": ["Role", "ClusterRole"] 17 | } 18 | } 19 | }, 20 | "trustedProxies": { 21 | "type": "array", 22 | "items": { 23 | "type": "string", 24 | "description": "Specifies one or more IPv4/IPv6 addresses expressed using CIDR notation.", 25 | "anyOf": [ 26 | { 27 | "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$" 28 | }, 29 | { 30 | "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$" 31 | } 32 | ] 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tinkerbell/stack/values.yaml: -------------------------------------------------------------------------------- 1 | stack: 2 | enabled: true 3 | name: tink-stack 4 | service: 5 | enabled: true 6 | type: LoadBalancer 7 | annotations: {} 8 | selector: 9 | app: tink-stack 10 | nodeSelector: {} 11 | deployment: 12 | strategy: 13 | type: RollingUpdate 14 | # stack needs to resolve DNS names in the cluster (in .svc.clusterDomain) 15 | clusterDomain: cluster.local 16 | # loadBalancerIP will override the global.publicIP value if set 17 | # loadBalancerIP: 192.168.2.112 18 | lbClass: kube-vip.io/kube-vip-class 19 | # Once the Kubernetes Gateway API is more stable, we will use that for all services instead of nginx. 20 | image: nginx:1.27.2 21 | 22 | hook: 23 | enabled: true 24 | name: hook-files 25 | port: 8080 26 | image: bash:5.2.37 27 | # downloadURL only works with the > 0.8.1 Hook release because 28 | # previous Hook versions didn't provide a checksum file. 29 | downloadURL: https://github.com/tinkerbell/hook/releases/download/v0.10.0 30 | arch: both # x86_64, aarch64, both 31 | extension: tar.gz # iso, tar.gz, both 32 | kernelVersion: both # 5.10, 6.6, both 33 | persistence: 34 | # If existingClaim is set, the local persistence volume (localPersistentVolume) objects will NOT be created. 35 | # Use this to point to an existing production grade storage class. 36 | existingClaim: "" 37 | # While local storage is the default, it is not recommended for production use. 38 | localPersistentVolume: 39 | storageClassName: local-storage 40 | # this path must already exist on the node 41 | path: /tmp 42 | name: hook-artifacts 43 | accessModes: 44 | - ReadWriteMany 45 | size: 2Gi 46 | extraLabels: {} 47 | 48 | kubevip: 49 | enabled: true 50 | name: kube-vip 51 | image: ghcr.io/kube-vip/kube-vip:v0.8.7 52 | imagePullPolicy: IfNotPresent 53 | roleName: kube-vip-role 54 | roleBindingName: kube-vip-rolebinding 55 | # Customize the interface KubeVIP advertises on. When unset, KubeVIP will autodetect the interface. 56 | # interface: enp0s8 57 | 58 | # Additional environment variables to pass to the kubevip container. Each entry is expected to have a 59 | # name and value key. Some keys are already defined - refer to the deployment.yaml template for 60 | # details. 61 | # 62 | # Example 63 | # - name: MY_ENV_VAR 64 | # value: my-value 65 | additionalEnv: [] 66 | # Relay allows us to listen and respond to layer broadcast DHCP requests 67 | relay: 68 | name: dhcp-relay 69 | enabled: true 70 | # This image (ghcr.io/jacobweinstock/dhcrelay) is used because the other public dhcprelay images out there (`modem7/dhcprelay`) 71 | # don't respect signals properly when run as PID 1. 72 | image: ghcr.io/jacobweinstock/dhcprelay # dhcprelay is a multiarch-enabled version of dhcrelay 73 | # if `interfaceMode: ipvlan`, then ghcr.io/jacobweinstock/relay-init:v0.1.0 (has nmap and nmap-scripts) is required. Otherwise, alpine can be used. 74 | initImage: ghcr.io/jacobweinstock/relay-init:v0.1.0 75 | maxHopCount: 10 76 | # The presentGiaddrAction pertains to the course of action when the giaddr field appears in the DHCP packet. 77 | # In situations where another DHCP relay agent is already in operation within the environment, 78 | # maintaining option (82) in its received state from the dhcrelay might be essential. 79 | # This behavior can be regulated by configuring the presentGiaddrAction as "forward." 80 | # Additional information is available at: https://linux.die.net/man/8/dhcrelay 81 | presentGiaddrAction: forward 82 | # sourceInterface is the Host/Node interface to use for listening for DHCP broadcast packets. 83 | # When unset, the interface from the default route will be used. 84 | # sourceInterface: eno1 85 | # enable/disable listening for broadcast traffic. Useful when the environment employs DHCP relay agent(s). 86 | # default is true. 87 | listenBroadcastTraffic: true 88 | # interfaceMode determines how we create the interface needed to listen for DHCP broadcast traffic. 89 | # by default macvlan is used. ipvlan is the only other option. 90 | interfaceMode: macvlan 91 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 92 | singleNodeClusterConfig: 93 | controlPlaneTolerationsEnabled: false 94 | nodeAffinityWeight: 1 95 | 96 | # -- Overrides 97 | # The values defined here override those in the individual charts. Some of them require tweaking 98 | # before deployment as they are environment dependent; others are surfaced for convenience. 99 | # 100 | # See individual chart documentation for additional detail. 101 | 102 | smee: 103 | image: quay.io/tinkerbell/smee:v0.15.1 104 | tinkWorkerImage: quay.io/tinkerbell/tink-worker:v0.12.2 105 | 106 | hegel: 107 | image: quay.io/tinkerbell/hegel:v0.14.2 108 | 109 | rufio: 110 | image: quay.io/tinkerbell/rufio:v0.6.3 111 | 112 | tink: 113 | controller: 114 | image: quay.io/tinkerbell/tink-controller:v0.12.2 115 | server: 116 | image: quay.io/tinkerbell/tink:v0.12.2 117 | 118 | # -- Global values 119 | global: 120 | # publicIP is used to set what both smee.publicIP and stack.loadBalancerIP do individually. 121 | publicIP: 192.168.2.113 122 | trustedProxies: [] 123 | rbac: 124 | type: Role 125 | nodeSelector: {} 126 | -------------------------------------------------------------------------------- /tinkerbell/tink/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: tink 3 | description: A Helm chart for Kubernetes 4 | icon: https://github.com/tinkerbell/artwork/blob/6f07de53d75cb8932dbc7d14201e038cf3a3b230/Tinkerbell-Icon-Dark.png 5 | 6 | # A chart can be either an 'application' or a 'library' chart. 7 | # 8 | # Application charts are a collection of templates that can be packaged into versioned archives 9 | # to be deployed. 10 | # 11 | # Library charts provide useful utilities or functions for the chart developer. They're included as 12 | # a dependency of application charts to inject those utilities and functions into the rendering 13 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 14 | type: application 15 | 16 | # This is the chart version. This version number should be incremented each time you make changes 17 | # to the chart and its templates, including the app version. 18 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 19 | version: 0.3.2 20 | 21 | # This is the version number of the application being deployed. This version number should be 22 | # incremented each time you make changes to the application. Versions are not expected to 23 | # follow Semantic Versioning. They should reflect the version the application is using. 24 | # It is recommended to use it with quotes. 25 | appVersion: "0.12.2" 26 | -------------------------------------------------------------------------------- /tinkerbell/tink/crds/hardware-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | annotations: 5 | controller-gen.kubebuilder.io/version: v0.16.3 6 | labels: 7 | clusterctl.cluster.x-k8s.io: "" 8 | clusterctl.cluster.x-k8s.io/move: "" 9 | name: hardware.tinkerbell.org 10 | spec: 11 | group: tinkerbell.org 12 | names: 13 | categories: 14 | - tinkerbell 15 | kind: Hardware 16 | listKind: HardwareList 17 | plural: hardware 18 | shortNames: 19 | - hw 20 | singular: hardware 21 | scope: Namespaced 22 | versions: 23 | - additionalPrinterColumns: 24 | - jsonPath: .status.state 25 | name: State 26 | type: string 27 | name: v1alpha1 28 | schema: 29 | openAPIV3Schema: 30 | description: Hardware is the Schema for the Hardware API. 31 | properties: 32 | apiVersion: 33 | description: |- 34 | APIVersion defines the versioned schema of this representation of an object. 35 | Servers should convert recognized schemas to the latest internal value, and 36 | may reject unrecognized values. 37 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 38 | type: string 39 | kind: 40 | description: |- 41 | Kind is a string value representing the REST resource this object represents. 42 | Servers may infer this from the endpoint the client submits requests to. 43 | Cannot be updated. 44 | In CamelCase. 45 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 46 | type: string 47 | metadata: 48 | type: object 49 | spec: 50 | description: HardwareSpec defines the desired state of Hardware. 51 | properties: 52 | bmcRef: 53 | description: |- 54 | BMCRef contains a relation to a BMC state management type in the same 55 | namespace as the Hardware. This may be used for BMC management by 56 | orchestrators. 57 | properties: 58 | apiGroup: 59 | description: |- 60 | APIGroup is the group for the resource being referenced. 61 | If APIGroup is not specified, the specified Kind must be in the core API group. 62 | For any other third-party types, APIGroup is required. 63 | type: string 64 | kind: 65 | description: Kind is the type of resource being referenced 66 | type: string 67 | name: 68 | description: Name is the name of resource being referenced 69 | type: string 70 | required: 71 | - kind 72 | - name 73 | type: object 74 | x-kubernetes-map-type: atomic 75 | disks: 76 | items: 77 | description: Disk represents a disk device for Tinkerbell Hardware. 78 | properties: 79 | device: 80 | type: string 81 | type: object 82 | type: array 83 | interfaces: 84 | items: 85 | description: Interface represents a network interface configuration for Hardware. 86 | properties: 87 | dhcp: 88 | description: DHCP configuration. 89 | properties: 90 | arch: 91 | type: string 92 | hostname: 93 | type: string 94 | iface_name: 95 | type: string 96 | ip: 97 | description: IP configuration. 98 | properties: 99 | address: 100 | type: string 101 | family: 102 | format: int64 103 | type: integer 104 | gateway: 105 | type: string 106 | netmask: 107 | type: string 108 | type: object 109 | lease_time: 110 | format: int64 111 | type: integer 112 | mac: 113 | pattern: ([0-9a-f]{2}[:]){5}([0-9a-f]{2}) 114 | type: string 115 | name_servers: 116 | items: 117 | type: string 118 | type: array 119 | time_servers: 120 | items: 121 | type: string 122 | type: array 123 | uefi: 124 | type: boolean 125 | vlan_id: 126 | description: validation pattern for VLANDID is a string number between 0-4096 127 | pattern: ^(([0-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))(,[1-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))*)$ 128 | type: string 129 | type: object 130 | disableDhcp: 131 | default: false 132 | description: DisableDHCP disables DHCP for this interface. 133 | type: boolean 134 | netboot: 135 | description: Netboot configuration. 136 | properties: 137 | allowPXE: 138 | type: boolean 139 | allowWorkflow: 140 | type: boolean 141 | ipxe: 142 | description: IPXE configuration. 143 | properties: 144 | contents: 145 | type: string 146 | url: 147 | type: string 148 | type: object 149 | osie: 150 | description: OSIE configuration. 151 | properties: 152 | baseURL: 153 | type: string 154 | initrd: 155 | type: string 156 | kernel: 157 | type: string 158 | type: object 159 | type: object 160 | type: object 161 | type: array 162 | metadata: 163 | properties: 164 | bonding_mode: 165 | format: int64 166 | type: integer 167 | custom: 168 | properties: 169 | preinstalled_operating_system_version: 170 | properties: 171 | distro: 172 | type: string 173 | image_tag: 174 | type: string 175 | os_slug: 176 | type: string 177 | slug: 178 | type: string 179 | version: 180 | type: string 181 | type: object 182 | private_subnets: 183 | items: 184 | type: string 185 | type: array 186 | type: object 187 | facility: 188 | properties: 189 | facility_code: 190 | type: string 191 | plan_slug: 192 | type: string 193 | plan_version_slug: 194 | type: string 195 | type: object 196 | instance: 197 | properties: 198 | allow_pxe: 199 | type: boolean 200 | always_pxe: 201 | type: boolean 202 | crypted_root_password: 203 | type: string 204 | hostname: 205 | type: string 206 | id: 207 | type: string 208 | ips: 209 | items: 210 | properties: 211 | address: 212 | type: string 213 | family: 214 | format: int64 215 | type: integer 216 | gateway: 217 | type: string 218 | management: 219 | type: boolean 220 | netmask: 221 | type: string 222 | public: 223 | type: boolean 224 | type: object 225 | type: array 226 | ipxe_script_url: 227 | type: string 228 | network_ready: 229 | type: boolean 230 | operating_system: 231 | properties: 232 | distro: 233 | type: string 234 | image_tag: 235 | type: string 236 | os_slug: 237 | type: string 238 | slug: 239 | type: string 240 | version: 241 | type: string 242 | type: object 243 | rescue: 244 | type: boolean 245 | ssh_keys: 246 | items: 247 | type: string 248 | type: array 249 | state: 250 | type: string 251 | storage: 252 | properties: 253 | disks: 254 | items: 255 | properties: 256 | device: 257 | type: string 258 | partitions: 259 | items: 260 | properties: 261 | label: 262 | type: string 263 | number: 264 | format: int64 265 | type: integer 266 | size: 267 | format: int64 268 | type: integer 269 | start: 270 | format: int64 271 | type: integer 272 | type_guid: 273 | type: string 274 | type: object 275 | type: array 276 | wipe_table: 277 | type: boolean 278 | type: object 279 | type: array 280 | filesystems: 281 | items: 282 | properties: 283 | mount: 284 | properties: 285 | create: 286 | properties: 287 | force: 288 | type: boolean 289 | options: 290 | items: 291 | type: string 292 | type: array 293 | type: object 294 | device: 295 | type: string 296 | files: 297 | items: 298 | properties: 299 | contents: 300 | type: string 301 | gid: 302 | format: int64 303 | type: integer 304 | mode: 305 | format: int64 306 | type: integer 307 | path: 308 | type: string 309 | uid: 310 | format: int64 311 | type: integer 312 | type: object 313 | type: array 314 | format: 315 | type: string 316 | point: 317 | type: string 318 | type: object 319 | type: object 320 | type: array 321 | raid: 322 | items: 323 | properties: 324 | devices: 325 | items: 326 | type: string 327 | type: array 328 | level: 329 | type: string 330 | name: 331 | type: string 332 | spare: 333 | format: int64 334 | type: integer 335 | type: object 336 | type: array 337 | type: object 338 | tags: 339 | items: 340 | type: string 341 | type: array 342 | userdata: 343 | type: string 344 | type: object 345 | manufacturer: 346 | properties: 347 | id: 348 | type: string 349 | slug: 350 | type: string 351 | type: object 352 | state: 353 | type: string 354 | type: object 355 | resources: 356 | additionalProperties: 357 | anyOf: 358 | - type: integer 359 | - type: string 360 | pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ 361 | x-kubernetes-int-or-string: true 362 | description: |- 363 | Resources represents known resources that are available on a machine. 364 | Resources may be used for scheduling by orchestrators. 365 | type: object 366 | tinkVersion: 367 | format: int64 368 | type: integer 369 | userData: 370 | description: |- 371 | UserData is the user data to configure in the hardware's 372 | metadata 373 | type: string 374 | vendorData: 375 | description: |- 376 | VendorData is the vendor data to configure in the hardware's 377 | metadata 378 | type: string 379 | type: object 380 | status: 381 | description: HardwareStatus defines the observed state of Hardware. 382 | properties: 383 | state: 384 | description: HardwareState represents the hardware state. 385 | type: string 386 | type: object 387 | type: object 388 | served: true 389 | storage: true 390 | subresources: 391 | status: {} 392 | -------------------------------------------------------------------------------- /tinkerbell/tink/crds/template-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | annotations: 5 | controller-gen.kubebuilder.io/version: v0.16.3 6 | name: templates.tinkerbell.org 7 | spec: 8 | group: tinkerbell.org 9 | names: 10 | categories: 11 | - tinkerbell 12 | kind: Template 13 | listKind: TemplateList 14 | plural: templates 15 | shortNames: 16 | - tpl 17 | singular: template 18 | scope: Namespaced 19 | versions: 20 | - additionalPrinterColumns: 21 | - jsonPath: .status.state 22 | name: State 23 | type: string 24 | name: v1alpha1 25 | schema: 26 | openAPIV3Schema: 27 | description: Template is the Schema for the Templates API. 28 | properties: 29 | apiVersion: 30 | description: |- 31 | APIVersion defines the versioned schema of this representation of an object. 32 | Servers should convert recognized schemas to the latest internal value, and 33 | may reject unrecognized values. 34 | More info: 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 represents. 39 | Servers may infer this from the endpoint the client submits requests to. 40 | Cannot be updated. 41 | In CamelCase. 42 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 43 | type: string 44 | metadata: 45 | type: object 46 | spec: 47 | description: TemplateSpec defines the desired state of Template. 48 | properties: 49 | data: 50 | type: string 51 | type: object 52 | status: 53 | description: TemplateStatus defines the observed state of Template. 54 | properties: 55 | state: 56 | description: TemplateState represents the template state. 57 | type: string 58 | type: object 59 | type: object 60 | served: true 61 | storage: true 62 | subresources: 63 | status: {} 64 | -------------------------------------------------------------------------------- /tinkerbell/tink/crds/workflow-crd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | annotations: 5 | controller-gen.kubebuilder.io/version: v0.16.3 6 | name: workflows.tinkerbell.org 7 | spec: 8 | group: tinkerbell.org 9 | names: 10 | categories: 11 | - tinkerbell 12 | kind: Workflow 13 | listKind: WorkflowList 14 | plural: workflows 15 | shortNames: 16 | - wf 17 | singular: workflow 18 | scope: Namespaced 19 | versions: 20 | - additionalPrinterColumns: 21 | - jsonPath: .spec.templateRef 22 | name: Template 23 | type: string 24 | - jsonPath: .status.state 25 | name: State 26 | type: string 27 | - jsonPath: .status.currentAction 28 | name: Current-Action 29 | type: string 30 | - jsonPath: .status.templateRending 31 | name: Template-Rendering 32 | type: string 33 | name: v1alpha1 34 | schema: 35 | openAPIV3Schema: 36 | description: Workflow is the Schema for the Workflows API. 37 | properties: 38 | apiVersion: 39 | description: |- 40 | APIVersion defines the versioned schema of this representation of an object. 41 | Servers should convert recognized schemas to the latest internal value, and 42 | may reject unrecognized values. 43 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources 44 | type: string 45 | kind: 46 | description: |- 47 | Kind is a string value representing the REST resource this object represents. 48 | Servers may infer this from the endpoint the client submits requests to. 49 | Cannot be updated. 50 | In CamelCase. 51 | More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds 52 | type: string 53 | metadata: 54 | type: object 55 | spec: 56 | description: WorkflowSpec defines the desired state of Workflow. 57 | properties: 58 | bootOptions: 59 | description: BootOptions are options that control the booting of Hardware. 60 | properties: 61 | bootMode: 62 | description: BootMode is the type of booting that will be done. 63 | enum: 64 | - netboot 65 | - iso 66 | type: string 67 | isoURL: 68 | description: |- 69 | ISOURL is the URL of the ISO that will be one-time booted. When this field is set, the controller will create a job.bmc.tinkerbell.org object 70 | for getting the associated hardware into a CDROM booting state. 71 | A HardwareRef that contains a spec.BmcRef must be provided. 72 | format: url 73 | type: string 74 | toggleAllowNetboot: 75 | description: |- 76 | ToggleAllowNetboot indicates whether the controller should toggle the field in the associated hardware for allowing PXE booting. 77 | This will be enabled before a Workflow is executed and disabled after the Workflow has completed successfully. 78 | A HardwareRef must be provided. 79 | type: boolean 80 | type: object 81 | hardwareMap: 82 | additionalProperties: 83 | type: string 84 | description: A mapping of template devices to hadware mac addresses. 85 | type: object 86 | hardwareRef: 87 | description: Name of the Hardware associated with this workflow. 88 | type: string 89 | templateRef: 90 | description: Name of the Template associated with this workflow. 91 | type: string 92 | type: object 93 | status: 94 | description: WorkflowStatus defines the observed state of a Workflow. 95 | properties: 96 | bootOptions: 97 | description: BootOptions holds the state of any boot options. 98 | properties: 99 | allowNetboot: 100 | description: AllowNetboot holds the state of the the controller's interactions with the allowPXE field in a Hardware object. 101 | properties: 102 | toggledFalse: 103 | type: boolean 104 | toggledTrue: 105 | type: boolean 106 | type: object 107 | jobs: 108 | additionalProperties: 109 | description: JobStatus holds the state of a specific job.bmc.tinkerbell.org object created. 110 | properties: 111 | complete: 112 | description: Complete indicates whether the created job.bmc.tinkerbell.org has reported its conditions as complete. 113 | type: boolean 114 | existingJobDeleted: 115 | description: |- 116 | ExistingJobDeleted indicates whether any existing job.bmc.tinkerbell.org was deleted. 117 | The name of each job.bmc.tinkerbell.org object created by the controller is the same, so only one can exist at a time. 118 | Using the same name was chosen so that there is only ever 1 job.bmc.tinkerbell.org per Hardware/Machine.bmc.tinkerbell.org. 119 | This makes clean up easier and we dont just orphan jobs every time. 120 | type: boolean 121 | uid: 122 | description: |- 123 | UID is the UID of the job.bmc.tinkerbell.org object associated with this workflow. 124 | This is used to uniquely identify the job.bmc.tinkerbell.org object, as 125 | all objects for a specific Hardware/Machine.bmc.tinkerbell.org are created with the same name. 126 | type: string 127 | type: object 128 | description: Jobs holds the state of any job.bmc.tinkerbell.org objects created. 129 | type: object 130 | type: object 131 | conditions: 132 | description: Conditions are the latest available observations of an object's current state. 133 | items: 134 | description: JobCondition describes current state of a job. 135 | properties: 136 | message: 137 | description: Message is a human readable message indicating details about last transition. 138 | type: string 139 | reason: 140 | description: Reason is a (brief) reason for the condition's last transition. 141 | type: string 142 | status: 143 | description: Status of the condition, one of True, False, Unknown. 144 | type: string 145 | time: 146 | description: Time when the condition was created. 147 | format: date-time 148 | type: string 149 | type: 150 | description: Type of job condition, Complete or Failed. 151 | type: string 152 | required: 153 | - status 154 | - type 155 | type: object 156 | type: array 157 | x-kubernetes-list-type: atomic 158 | currentAction: 159 | description: CurrentAction is the action that is currently in the running state. 160 | type: string 161 | globalTimeout: 162 | description: GlobalTimeout represents the max execution time. 163 | format: int64 164 | type: integer 165 | state: 166 | description: State is the current overall state of the Workflow. 167 | type: string 168 | tasks: 169 | description: Tasks are the tasks to be run by the worker(s). 170 | items: 171 | description: Task represents a series of actions to be completed by a worker. 172 | properties: 173 | actions: 174 | items: 175 | description: Action represents a workflow action. 176 | properties: 177 | command: 178 | items: 179 | type: string 180 | type: array 181 | environment: 182 | additionalProperties: 183 | type: string 184 | type: object 185 | image: 186 | type: string 187 | message: 188 | type: string 189 | name: 190 | type: string 191 | pid: 192 | type: string 193 | seconds: 194 | format: int64 195 | type: integer 196 | startedAt: 197 | format: date-time 198 | type: string 199 | status: 200 | type: string 201 | timeout: 202 | format: int64 203 | type: integer 204 | volumes: 205 | items: 206 | type: string 207 | type: array 208 | type: object 209 | type: array 210 | environment: 211 | additionalProperties: 212 | type: string 213 | type: object 214 | name: 215 | type: string 216 | volumes: 217 | items: 218 | type: string 219 | type: array 220 | worker: 221 | type: string 222 | required: 223 | - actions 224 | - name 225 | - worker 226 | type: object 227 | type: array 228 | templateRending: 229 | description: |- 230 | TemplateRendering indicates whether the template was rendered successfully. 231 | Possible values are "successful" or "failed" or "unknown". 232 | type: string 233 | type: object 234 | type: object 235 | served: true 236 | storage: true 237 | subresources: 238 | status: {} 239 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | {{- $roleType := .Values.controller.rbac.type }} 3 | {{- $nodeSelector := .Values.controller.nodeSelector }} 4 | {{- if .Values.global }} 5 | {{- $roleType = coalesce .Values.global.rbac.type .Values.controller.rbac.type }} 6 | {{- $nodeSelector = coalesce .Values.controller.nodeSelector .Values.global.nodeSelector }} 7 | {{- end }} 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | labels: 12 | app: {{ .Values.controller.name }} 13 | name: {{ .Values.controller.name }} 14 | namespace: {{ .Release.Namespace | quote }} 15 | spec: 16 | replicas: {{ .Values.controller.replicas }} 17 | selector: 18 | matchLabels: 19 | app: {{ .Values.controller.name }} 20 | template: 21 | metadata: 22 | labels: 23 | app: {{ .Values.controller.name }} 24 | spec: 25 | containers: 26 | - image: {{ .Values.controller.image }} 27 | imagePullPolicy: {{ .Values.controller.imagePullPolicy }} 28 | args: 29 | {{- if eq $roleType "Role" }} 30 | - --namespace={{ .Release.Namespace }} 31 | {{- end }} 32 | {{- range .Values.controller.args }} 33 | - {{ . }} 34 | {{- end }} 35 | name: {{ .Values.controller.name }} 36 | resources: 37 | limits: 38 | cpu: {{ .Values.controller.resources.limits.cpu }} 39 | memory: {{ .Values.controller.resources.limits.memory }} 40 | requests: 41 | cpu: {{ .Values.controller.resources.requests.cpu }} 42 | memory: {{ .Values.controller.resources.requests.memory }} 43 | serviceAccountName: {{ .Values.controller.name }} 44 | {{- with $nodeSelector }} 45 | nodeSelector: 46 | {{ toYaml . | nindent 8 }} 47 | {{- end }} 48 | {{- if .Values.controller.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 49 | tolerations: 50 | {{- include "singleNodeClusterConfig" . | indent 6 }} 51 | affinity: 52 | nodeAffinity: 53 | preferredDuringSchedulingIgnoredDuringExecution: 54 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.controller.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 55 | {{- end }} 56 | {{- end }} 57 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/leader-election-role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: {{ .Values.controller.tinkLeaderElectionRoleName }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | rules: 8 | - apiGroups: 9 | - "" 10 | resources: 11 | - configmaps 12 | verbs: 13 | - get 14 | - list 15 | - watch 16 | - create 17 | - update 18 | - patch 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/leader-election-rolebinding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | name: {{ .Values.controller.tinkLeaderElectionRoleBindingName }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: {{ .Values.controller.tinkLeaderElectionRoleName }} 11 | subjects: 12 | - kind: ServiceAccount 13 | name: {{ .Values.controller.name }} 14 | namespace: {{ .Release.Namespace | quote }} 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | {{- $roleType := .Values.controller.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.controller.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }}Binding 8 | metadata: 9 | name: {{ .Values.controller.rbac.bindingName }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: {{ $roleType }} 16 | name: {{ .Values.controller.rbac.name }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.controller.name }} 20 | namespace: {{ .Release.Namespace | quote }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | {{- $roleType := .Values.controller.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.controller.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }} 8 | metadata: 9 | name: {{ .Values.controller.rbac.name }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | rules: 14 | - apiGroups: 15 | - bmc.tinkerbell.org 16 | resources: 17 | - jobs 18 | - jobs/status 19 | verbs: 20 | - create 21 | - delete 22 | - get 23 | - list 24 | - watch 25 | - apiGroups: 26 | - tinkerbell.org 27 | resources: 28 | - hardware 29 | - hardware/status 30 | - templates 31 | - templates/status 32 | verbs: 33 | - get 34 | - list 35 | - patch 36 | - update 37 | - watch 38 | - apiGroups: 39 | - tinkerbell.org 40 | resources: 41 | - workflows 42 | - workflows/status 43 | verbs: 44 | - delete 45 | - get 46 | - list 47 | - patch 48 | - update 49 | - watch 50 | {{- end }} 51 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-controller/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.controller.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.controller.name }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/_scheduling.tpl: -------------------------------------------------------------------------------- 1 | {{- define "singleNodeClusterConfig" }} 2 | - effect: NoSchedule 3 | key: node-role.kubernetes.io/control-plane 4 | {{- end }} 5 | 6 | {{- define "preferWorkerNodes" }} 7 | - weight: {{ .nodeAffinityWeight }} 8 | preference: 9 | matchExpressions: 10 | - key: node-role.kubernetes.io/control-plane 11 | operator: DoesNotExist 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.deploy }} 2 | {{- $roleType := .Values.server.rbac.type }} 3 | {{- $nodeSelector := .Values.server.nodeSelector }} 4 | {{- if .Values.global }} 5 | {{- $roleType = coalesce .Values.global.rbac.type .Values.server.rbac.type }} 6 | {{- $nodeSelector = coalesce .Values.server.nodeSelector .Values.global.nodeSelector }} 7 | {{- end }} 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | labels: 12 | app: {{ .Values.server.name }} 13 | name: {{ .Values.server.name }} 14 | namespace: {{ .Release.Namespace | quote }} 15 | spec: 16 | replicas: {{ .Values.server.replicas }} 17 | selector: 18 | matchLabels: 19 | app: {{ .Values.server.name }} 20 | stack: tinkerbell 21 | {{- with .Values.server.selector }} 22 | {{- toYaml . | nindent 6 }} 23 | {{- end }} 24 | template: 25 | metadata: 26 | labels: 27 | app: {{ .Values.server.name }} 28 | stack: tinkerbell 29 | {{- with .Values.server.selector }} 30 | {{- toYaml . | nindent 8 }} 31 | {{- end }} 32 | spec: 33 | containers: 34 | - args: 35 | - --backend=kubernetes 36 | {{- if eq $roleType "Role"}} 37 | - --kube-namespace={{ .Release.Namespace }} 38 | {{- end }} 39 | {{- range .Values.server.args }} 40 | - {{ . }} 41 | {{- end }} 42 | image: {{ .Values.server.image }} 43 | imagePullPolicy: {{ .Values.server.imagePullPolicy }} 44 | name: server 45 | ports: 46 | - containerPort: {{ .Values.server.deployment.port }} 47 | name: {{ .Values.server.deployment.portName }} 48 | resources: 49 | limits: 50 | cpu: {{ .Values.server.resources.limits.cpu }} 51 | memory: {{ .Values.server.resources.limits.memory }} 52 | requests: 53 | cpu: {{ .Values.server.resources.requests.cpu }} 54 | memory: {{ .Values.server.resources.requests.memory }} 55 | serviceAccountName: {{ .Values.server.name }} 56 | {{- with $nodeSelector }} 57 | nodeSelector: 58 | {{ toYaml . | nindent 8 }} 59 | {{- end }} 60 | {{- if .Values.server.singleNodeClusterConfig.controlPlaneTolerationsEnabled }} 61 | tolerations: 62 | {{- include "singleNodeClusterConfig" . | indent 6 }} 63 | affinity: 64 | nodeAffinity: 65 | preferredDuringSchedulingIgnoredDuringExecution: 66 | {{- include "preferWorkerNodes" (dict "nodeAffinityWeight" .Values.server.singleNodeClusterConfig.nodeAffinityWeight) | indent 10 }} 67 | {{- end }} 68 | {{- end }} 69 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.deploy }} 2 | {{- $roleType := .Values.server.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.server.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ printf "%sBinding" $roleType }} 8 | metadata: 9 | name: {{ .Values.server.rbac.bindingName }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: {{ $roleType }} 16 | name: {{ .Values.server.rbac.name }} 17 | subjects: 18 | - kind: ServiceAccount 19 | name: {{ .Values.server.name }} 20 | namespace: {{ .Release.Namespace | quote }} 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.deploy }} 2 | {{- $roleType := .Values.server.rbac.type }} 3 | {{- if .Values.global }} 4 | {{- $roleType = coalesce .Values.global.rbac.type .Values.server.rbac.type }} 5 | {{- end }} 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: {{ $roleType }} 8 | metadata: 9 | name: {{ .Values.server.rbac.name }} 10 | {{- if eq $roleType "Role" }} 11 | namespace: {{ .Release.Namespace | quote }} 12 | {{- end }} 13 | rules: 14 | - apiGroups: 15 | - tinkerbell.org 16 | resources: 17 | - hardware 18 | - hardware/status 19 | - templates 20 | - templates/status 21 | verbs: 22 | - get 23 | - list 24 | - watch 25 | - apiGroups: 26 | - tinkerbell.org 27 | resources: 28 | - workflows 29 | - workflows/status 30 | verbs: 31 | - get 32 | - list 33 | - patch 34 | - update 35 | - watch 36 | {{- end }} 37 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.deploy }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ .Values.server.name }} 6 | namespace: {{ .Release.Namespace | quote }} 7 | {{- end }} 8 | -------------------------------------------------------------------------------- /tinkerbell/tink/templates/tink-server/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.server.deploy -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app: {{ .Values.server.name }} 7 | name: {{ .Values.server.name }} 8 | namespace: {{ .Release.Namespace | quote }} 9 | spec: 10 | ports: 11 | - port: {{ .Values.server.service.port }} 12 | protocol: TCP 13 | targetPort: {{ .Values.server.deployment.portName }} 14 | selector: 15 | app: {{ .Values.server.name }} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /tinkerbell/tink/values.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "$comment": "This file was generated and then modified.", 5 | "properties": { 6 | "controller": { 7 | "type": "object", 8 | "properties": { 9 | "rbac": { 10 | "type": "object", 11 | "properties": { 12 | "type": { 13 | "type": "string", 14 | "enum": ["Role", "ClusterRole"] 15 | }, 16 | "name": { 17 | "type": "string" 18 | }, 19 | "bindingName": { 20 | "type": "string" 21 | } 22 | } 23 | } 24 | } 25 | }, 26 | "server": { 27 | "type": "object", 28 | "properties": { 29 | "rbac": { 30 | "type": "object", 31 | "properties": { 32 | "type": { 33 | "type": "string", 34 | "enum": ["Role", "ClusterRole"] 35 | }, 36 | "name": { 37 | "type": "string" 38 | }, 39 | "bindingName": { 40 | "type": "string" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tinkerbell/tink/values.yaml: -------------------------------------------------------------------------------- 1 | controller: 2 | deploy: true 3 | name: tink-controller 4 | image: quay.io/tinkerbell/tink-controller:v0.12.2 5 | imagePullPolicy: IfNotPresent 6 | replicas: 1 7 | args: [] 8 | resources: 9 | limits: 10 | cpu: 500m 11 | memory: 128Mi 12 | requests: 13 | cpu: 10m 14 | memory: 64Mi 15 | tinkLeaderElectionRoleName: tink-leader-election-role 16 | tinkLeaderElectionRoleBindingName: tink-leader-election-rolebinding 17 | nodeSelector: {} 18 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 19 | singleNodeClusterConfig: 20 | controlPlaneTolerationsEnabled: false 21 | weight: 1 22 | rbac: 23 | type: Role # or ClusterRole 24 | name: tink-controller-role # or tink-controller-cluster-role 25 | bindingName: tink-controller-rolebinding # or tink-controller-cluster-rolebinding 26 | 27 | server: 28 | deploy: true 29 | name: tink-server 30 | image: quay.io/tinkerbell/tink:v0.12.2 31 | imagePullPolicy: IfNotPresent 32 | replicas: 1 33 | service: 34 | port: 42113 35 | deployment: 36 | port: 42113 37 | portName: tink-grpc 38 | resources: 39 | limits: 40 | cpu: 500m 41 | memory: 128Mi 42 | requests: 43 | cpu: 10m 44 | memory: 64Mi 45 | nodeSelector: {} 46 | # singleNodeClusterConfig to add tolerations for deployments on control plane nodes. This is defaulted to false. 47 | singleNodeClusterConfig: 48 | controlPlaneTolerationsEnabled: false 49 | nodeAffinityWeight: 1 50 | rbac: 51 | type: Role # or ClusterRole 52 | name: tink-server-role # or tink-server-cluster-role 53 | bindingName: tink-server-rolebinding # or tink-server-cluster-rolebinding 54 | --------------------------------------------------------------------------------