├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── dependabot.yml ├── pull_request_template.md ├── release-drafter.yml └── workflows │ ├── check-codegen.yml │ ├── clean-cache.yml │ ├── kustomize-validation.yml │ ├── lint.yml │ ├── publish-chart.yml │ ├── publish-docker.yml │ ├── publish-docs.yml │ ├── release-drafter.yml │ ├── reuse.yml │ ├── size-label.yml │ ├── test-chart.yml │ ├── test-e2e.yml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── Dockerfile ├── LICENSE ├── LICENSES └── Apache-2.0.txt ├── Makefile ├── PROJECT ├── README.md ├── REUSE.toml ├── Tiltfile ├── api └── v1alpha1 │ ├── biossettings_types.go │ ├── biosversion_types.go │ ├── bmc_types.go │ ├── bmcsecret_types.go │ ├── common_types.go │ ├── constants.go │ ├── doc.go │ ├── endpoint_types.go │ ├── groupversion_info.go │ ├── server_types.go │ ├── serverbootconfiguration_types.go │ ├── serverclaim_types.go │ ├── servermaintenance_types.go │ └── zz_generated.deepcopy.go ├── bmc ├── bmc.go ├── mockup.go ├── oem │ ├── dell.go │ ├── hpe.go │ ├── lenovo.go │ └── types.go ├── redfish.go ├── redfish_kube.go └── redfish_local.go ├── cmd ├── manager │ └── main.go ├── metalctl │ ├── app │ │ ├── app.go │ │ ├── console.go │ │ └── move.go │ └── main.go └── metalprobe │ └── main.go ├── cmdutils ├── clients.go ├── move.go ├── move_test.go ├── suite_test.go └── utils.go ├── config ├── certmanager │ ├── certificate-metrics.yaml │ ├── certificate-webhook.yaml │ ├── issuer.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── crd │ ├── bases │ │ ├── metal.ironcore.dev_biossettings.yaml │ │ ├── metal.ironcore.dev_biosversions.yaml │ │ ├── metal.ironcore.dev_bmcs.yaml │ │ ├── metal.ironcore.dev_bmcsecrets.yaml │ │ ├── metal.ironcore.dev_endpoints.yaml │ │ ├── metal.ironcore.dev_serverbootconfigurations.yaml │ │ ├── metal.ironcore.dev_serverclaims.yaml │ │ ├── metal.ironcore.dev_servermaintenances.yaml │ │ └── metal.ironcore.dev_servers.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ └── patches │ │ ├── cainjection_in_bmcs.yaml │ │ ├── cainjection_in_serverclaims.yaml │ │ ├── webhook_in_bmcs.yaml │ │ └── webhook_in_serverclaims.yaml ├── default │ ├── cert_metrics_manager_patch.yaml │ ├── kustomization.yaml │ ├── manager_metrics_patch.yaml │ ├── manager_webhook_patch.yaml │ ├── metrics_service.yaml │ └── webhookcainjection_patch.yaml ├── dev │ ├── delete_manager_auth_proxy_patch.yaml │ ├── kustomization.yaml │ ├── macdb.yaml │ ├── manager_patch.yaml │ └── registry_service.yaml ├── e2e-metrics-validation │ ├── kustomization.yaml │ └── manager_args_patch.yaml ├── manager │ ├── kustomization.yaml │ └── manager.yaml ├── network-policy │ └── allow-webhook-traffic.yaml ├── prometheus │ ├── kustomization.yaml │ ├── monitor.yaml │ └── monitor_tls_patch.yaml ├── rbac │ ├── biossettings_admin_role.yaml │ ├── biossettings_editor_role.yaml │ ├── biossettings_viewer_role.yaml │ ├── biosversion_admin_role.yaml │ ├── biosversion_editor_role.yaml │ ├── biosversion_viewer_role.yaml │ ├── bmc_editor_role.yaml │ ├── bmc_viewer_role.yaml │ ├── bmcsecret_editor_role.yaml │ ├── bmcsecret_viewer_role.yaml │ ├── endpoint_editor_role.yaml │ ├── endpoint_viewer_role.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── metrics_auth_role.yaml │ ├── metrics_auth_role_binding.yaml │ ├── metrics_reader_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ ├── server_editor_role.yaml │ ├── server_viewer_role.yaml │ ├── serverbootconfiguration_editor_role.yaml │ ├── serverbootconfiguration_viewer_role.yaml │ ├── serverclaim_editor_role.yaml │ ├── serverclaim_viewer_role.yaml │ ├── servermaintenance_admin_role.yaml │ ├── servermaintenance_editor_role.yaml │ ├── servermaintenance_viewer_role.yaml │ └── service_account.yaml ├── redfish-mockup │ ├── kustomization.yaml │ ├── redfish_mockup_endpoint.yaml │ └── redfish_mockup_service.yaml ├── samples │ ├── kustomization.yaml │ ├── metal_v1alpha1_biossettings.yaml │ ├── metal_v1alpha1_biosversion.yaml │ ├── metal_v1alpha1_bmc.yaml │ ├── metal_v1alpha1_bmcsecret.yaml │ ├── metal_v1alpha1_endpoint.yaml │ ├── metal_v1alpha1_server.yaml │ ├── metal_v1alpha1_serverbootconfiguration.yaml │ ├── metal_v1alpha1_serverclaim.yaml │ └── metal_v1alpha1_servermaintenance.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ └── service.yaml ├── dist └── chart │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── _helpers.tpl │ ├── certmanager │ │ └── certificate.yaml │ ├── crd │ │ ├── metal.ironcore.dev_biossettings.yaml │ │ ├── metal.ironcore.dev_biosversions.yaml │ │ ├── metal.ironcore.dev_bmcs.yaml │ │ ├── metal.ironcore.dev_bmcsecrets.yaml │ │ ├── metal.ironcore.dev_endpoints.yaml │ │ ├── metal.ironcore.dev_serverbootconfigurations.yaml │ │ ├── metal.ironcore.dev_serverclaims.yaml │ │ ├── metal.ironcore.dev_servermaintenances.yaml │ │ └── metal.ironcore.dev_servers.yaml │ ├── manager │ │ └── manager.yaml │ ├── metrics │ │ └── metrics-service.yaml │ ├── network-policy │ │ └── allow-webhook-traffic.yaml │ ├── prometheus │ │ └── monitor.yaml │ ├── rbac │ │ ├── biossettings_admin_role.yaml │ │ ├── biossettings_editor_role.yaml │ │ ├── biossettings_viewer_role.yaml │ │ ├── biosversion_admin_role.yaml │ │ ├── biosversion_editor_role.yaml │ │ ├── biosversion_viewer_role.yaml │ │ ├── bmc_editor_role.yaml │ │ ├── bmc_viewer_role.yaml │ │ ├── bmcsecret_editor_role.yaml │ │ ├── bmcsecret_viewer_role.yaml │ │ ├── endpoint_editor_role.yaml │ │ ├── endpoint_viewer_role.yaml │ │ ├── leader_election_role.yaml │ │ ├── leader_election_role_binding.yaml │ │ ├── metrics_auth_role.yaml │ │ ├── metrics_auth_role_binding.yaml │ │ ├── metrics_reader_role.yaml │ │ ├── role.yaml │ │ ├── role_binding.yaml │ │ ├── server_editor_role.yaml │ │ ├── server_viewer_role.yaml │ │ ├── serverbootconfiguration_editor_role.yaml │ │ ├── serverbootconfiguration_viewer_role.yaml │ │ ├── serverclaim_editor_role.yaml │ │ ├── serverclaim_viewer_role.yaml │ │ ├── servermaintenance_admin_role.yaml │ │ ├── servermaintenance_editor_role.yaml │ │ ├── servermaintenance_viewer_role.yaml │ │ └── service_account.yaml │ └── webhook │ │ ├── service.yaml │ │ └── webhooks.yaml │ └── values.yaml ├── docs ├── Dockerfile ├── README.md ├── api-reference │ └── api.md ├── architecture.md ├── concepts │ ├── biossettings.md │ ├── biosversion.md │ ├── bmcs.md │ ├── bmcsecrets.md │ ├── bmcsettings.md │ ├── bmcversion.md │ ├── endpoints.md │ ├── serverbootconfigurations.md │ ├── serverclaims.md │ ├── servermaintenance.md │ └── servers.md ├── development │ ├── dev_docs.md │ └── dev_setup.md ├── requirements.txt └── usage │ ├── installation.md │ └── metalctl.md ├── go.mod ├── go.sum ├── hack ├── api-reference │ ├── config.json │ └── template │ │ ├── members.tpl │ │ ├── pkg.tpl │ │ └── type.tpl ├── boilerplate.go.txt ├── dev-mac-prefixes.yaml ├── license-header.txt └── validate-kustomize.sh ├── internal ├── api │ ├── macdb │ │ └── macdb.go │ └── registry │ │ ├── registry.go │ │ └── server.go ├── bmcutils │ └── bmcutils.go ├── console │ ├── console.go │ ├── console_test.go │ └── suite_test.go ├── controller │ ├── biossettings_controller.go │ ├── biossettings_controller_test.go │ ├── biosversion_controller.go │ ├── biosversion_controller_test.go │ ├── bmc_controller.go │ ├── bmc_controller_test.go │ ├── bmcsecret_controller.go │ ├── bmcsecret_controller_test.go │ ├── common_test_helpers.go │ ├── endpoint_controller.go │ ├── endpoint_controller_test.go │ ├── helper.go │ ├── server_controller.go │ ├── server_controller_test.go │ ├── serverbootconfiguration_controller.go │ ├── serverbootconfiguration_controller_test.go │ ├── serverclaim_controller.go │ ├── serverclaim_controller_test.go │ ├── servermaintenance_controller.go │ ├── servermaintenance_controller_test.go │ └── suite_test.go ├── ignition │ └── default.go ├── probe │ ├── agent.go │ ├── agent_test.go │ ├── networking.go │ └── probe_suite_test.go ├── registry │ ├── registry_suite_test.go │ ├── server.go │ └── server_test.go └── webhook │ └── v1alpha1 │ ├── biossettings_webhook.go │ ├── biossettings_webhook_test.go │ ├── biosversion_webhook.go │ ├── biosversion_webhook_test.go │ ├── endpoint_webhook.go │ ├── endpoint_webhook_test.go │ └── webhook_suite_test.go ├── mkdocs.yml ├── scripts └── kind-with-registry.sh └── test ├── e2e ├── e2e_suite_test.go └── e2e_test.go └── utils └── utils.go /.dockerignore: -------------------------------------------------------------------------------- 1 | # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file 2 | # Ignore build and test binaries. 3 | bin/ 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 🐞 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior e.g. provide example action definition. 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Screenshots** 19 | If applicable, add screenshots to help explain your problem. 20 | 21 | **Additional context** 22 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 💡 3 | about: Suggest a new idea for the project. 4 | labels: enhancement 5 | --- 6 | 7 | # Summary 8 | 9 | Brief explanation of the feature. 10 | 11 | ## Basic example 12 | 13 | If the proposal involves a new or changed API, include a basic code example. Omit this section if it's not applicable. 14 | 15 | ## Motivation 16 | 17 | Why are we doing this? What use cases does it support? What is the expected outcome? -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question ❓ 3 | about: Is something unclear? 4 | labels: question 5 | --- 6 | 7 | # Question? -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "gomod" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | # Ignore K8 packages as these are done manually 9 | ignore: 10 | - dependency-name: "k8s.io/api" 11 | - dependency-name: "k8s.io/apiextensions-apiserver" 12 | - dependency-name: "k8s.io/apimachinery" 13 | - dependency-name: "k8s.io/apiserver" 14 | - dependency-name: "k8s.io/client-go" 15 | - dependency-name: "k8s.io/component-base" 16 | - dependency-name: "k8s.io/kube-aggregator" 17 | - dependency-name: "k8s.io/kubectl" 18 | - dependency-name: "sigs.k8s.io/controller-runtime" 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | interval: "weekly" 23 | - package-ecosystem: "docker" 24 | directory: "/" 25 | schedule: 26 | interval: "weekly" 27 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Proposed Changes 2 | 3 | - 4 | - 5 | - 6 | 7 | Fixes # -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION' 2 | tag-template: 'v$RESOLVED_VERSION' 3 | categories: 4 | - title: '⚠️ Breaking' 5 | labels: 6 | - 'breaking' 7 | - title: '🚀 Features' 8 | labels: 9 | - 'feature' 10 | - 'enhancement' 11 | - 'api-change' 12 | - title: '🐛 Bug Fixes' 13 | labels: 14 | - 'fix' 15 | - 'bugfix' 16 | - 'bug' 17 | - title: '🧰 Maintenance' 18 | labels: 19 | - 'chore' 20 | - 'dependencies' 21 | - 'marketing' 22 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 23 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. 24 | version-resolver: 25 | major: 26 | labels: 27 | - 'major' 28 | minor: 29 | labels: 30 | - 'minor' 31 | patch: 32 | labels: 33 | - 'patch' 34 | default: patch 35 | exclude-labels: 36 | - 'skip-changelog' 37 | autolabeler: 38 | - label: 'api-change' 39 | files: 40 | - '/api/*' 41 | - label: 'documentation' 42 | files: 43 | - '*.md' 44 | branch: 45 | - '/docs{0,1}\/.+/' 46 | - label: 'bug' 47 | branch: 48 | - '/fix\/.+/' 49 | title: 50 | - '/fix/i' 51 | - label: 'enhancement' 52 | branch: 53 | - '/feature\/.+/' 54 | body: 55 | - '/JIRA-[0-9]{1,4}/' 56 | - label: 'enhancement' 57 | branch: 58 | - '/enh\/.+/' 59 | - label: 'chore' 60 | branch: 61 | - '/chore\/.+/' 62 | template: | 63 | ## Changes 64 | $CHANGES 65 | -------------------------------------------------------------------------------- /.github/workflows/check-codegen.yml: -------------------------------------------------------------------------------- 1 | name: Check Codegen 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - 'docs/**' 7 | - '**/*.md' 8 | 9 | jobs: 10 | check-codegen: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-go@v5 15 | with: 16 | go-version-file: 'go.mod' 17 | - name: Run make generate 18 | run: make generate 19 | - name: Run make docs 20 | run: make docs 21 | - name: Run make helm 22 | run: make helm 23 | - name: Compare the expected and actual generated/* directories 24 | run: | 25 | if [ "$(git diff | wc -l)" -gt "0" ]; then 26 | echo "Detected uncommitted changes after build. Consider running 'make generate && make docs && make helm'." 27 | echo "See status below:" 28 | git diff 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /.github/workflows/clean-cache.yml: -------------------------------------------------------------------------------- 1 | name: Cleanup caches by a branch 2 | on: 3 | pull_request: 4 | types: 5 | - closed 6 | 7 | jobs: 8 | cleanup: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Check out code 12 | uses: actions/checkout@v4 13 | 14 | - name: Cleanup 15 | run: | 16 | gh extension install actions/gh-actions-cache 17 | 18 | REPO=${{ github.repository }} 19 | BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" 20 | echo "Fetching list of cache key" 21 | cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) 22 | ## Setting this to not fail the workflow while deleting cache keys. 23 | set +e 24 | echo "Deleting caches..." 25 | for cacheKey in $cacheKeysForPR 26 | do 27 | gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm 28 | done 29 | echo "Done" 30 | env: 31 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | -------------------------------------------------------------------------------- /.github/workflows/kustomize-validation.yml: -------------------------------------------------------------------------------- 1 | name: Kustomize Validation 2 | 3 | on: 4 | pull_request: 5 | types: [ assigned, opened, synchronize, reopened ] 6 | paths-ignore: 7 | - 'docs/**' 8 | - '**/*.md' 9 | 10 | jobs: 11 | kustomize-validation: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out code 15 | uses: actions/checkout@v4 16 | - uses: imranismail/setup-kustomize@v2 17 | with: 18 | kustomize-version: '5.0.0' 19 | - run: | 20 | ./hack/validate-kustomize.sh 21 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - 'docs/**' 7 | - '**/*.md' 8 | jobs: 9 | golangci: 10 | name: lint 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-go@v5 15 | with: 16 | go-version-file: 'go.mod' 17 | - name: golangci-lint 18 | uses: golangci/golangci-lint-action@v8 19 | with: 20 | version: v2.1 21 | -------------------------------------------------------------------------------- /.github/workflows/publish-chart.yml: -------------------------------------------------------------------------------- 1 | name: Release Helm Chart 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | push: 8 | branches: 9 | - main 10 | tags: 11 | - 'v*.*.*' 12 | paths-ignore: 13 | - 'docs/**' 14 | - '**/*.md' 15 | pull_request: 16 | branches: 17 | - main 18 | paths-ignore: 19 | - 'docs/**' 20 | - '**/*.md' 21 | types: [labeled, opened, synchronize, reopened] 22 | 23 | jobs: 24 | helm-chart: 25 | runs-on: ubuntu-latest 26 | permissions: 27 | contents: read 28 | packages: write 29 | 30 | if: | 31 | github.event_name == 'push' || 32 | (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ok-to-charts')) || 33 | (github.event_name == 'release' && github.event.action == 'published') 34 | steps: 35 | - name: Checkout code 36 | uses: actions/checkout@v4 37 | 38 | - name: Set up Helm 39 | uses: azure/setup-helm@v4 40 | with: 41 | version: v3.16.2 42 | 43 | - name: Determine chart version 44 | id: chart_version 45 | run: | 46 | if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then 47 | # Use SHA for main branch 48 | CHART_VERSION="0.0.0-$(echo ${{ github.sha }} | cut -c1-7)" 49 | elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 50 | # Use tag version (strip 'v' prefix) 51 | CHART_VERSION="${GITHUB_REF#refs/tags/v}" 52 | else 53 | # Use PR SHA for dry run 54 | CHART_VERSION="0.0.0-$(echo ${{ github.sha }} | cut -c1-7)" 55 | fi 56 | echo "version=$CHART_VERSION" >> $GITHUB_OUTPUT 57 | 58 | - name: Install Kustomize 59 | run: | 60 | curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash 61 | mv kustomize /usr/local/bin 62 | 63 | - name: Prepare CRDs folder 64 | run: | 65 | mkdir -p dist/chart/crds 66 | kustomize build config/default | yq ea 'select(.kind == "CustomResourceDefinition")' > dist/chart/crds/crds.yaml 67 | rm -rf dist/chart/templates/crd 68 | 69 | - name: Package Helm chart 70 | run: | 71 | helm package dist/chart --version ${{ steps.chart_version.outputs.version }} 72 | 73 | - name: Log in to GitHub Container Registry 74 | run: | 75 | echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin 76 | 77 | - name: Push Helm chart to GHCR 78 | run: | 79 | helm push metal-operator-${{ steps.chart_version.outputs.version }}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts -------------------------------------------------------------------------------- /.github/workflows/publish-docker.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker Image 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | push: 8 | branches: 9 | - main 10 | tags: 11 | - v* 12 | paths-ignore: 13 | - 'docs/**' 14 | - '**/*.md' 15 | pull_request: 16 | paths-ignore: 17 | - 'docs/**' 18 | - '**/*.md' 19 | types: [labeled, unlabeled, opened, synchronize, reopened] 20 | 21 | jobs: 22 | buildAndPush: 23 | strategy: 24 | matrix: 25 | image: 26 | - name: metal-operator-controller-manager 27 | target: manager 28 | - name: metalprobe 29 | target: probe 30 | permissions: 31 | contents: read 32 | packages: write 33 | # Condition: Run on push to main, published release, OR PR with 'ok-to-image' label 34 | if: | 35 | github.event_name == 'push' || 36 | (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ok-to-image')) || 37 | (github.event_name == 'release' && github.event.action == 'published') 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v4 41 | - uses: docker/metadata-action@v5 42 | id: meta 43 | with: 44 | images: | 45 | ghcr.io/${{ github.repository_owner }}/${{ matrix.image.name }} 46 | tags: | 47 | type=semver,pattern={{version}} 48 | type=schedule 49 | type=ref,event=branch 50 | type=ref,event=tag 51 | type=ref,event=pr 52 | type=sha 53 | flavor: | 54 | latest=${{ github.ref == 'refs/heads/main' }} 55 | - name: Set up QEMU 56 | uses: docker/setup-qemu-action@v3 57 | with: 58 | platforms: all 59 | # workaround for self-hosted runner 60 | # https://github.com/mumoshu/actions-runner-controller-ci/commit/e91c8c0f6ca82aa7618010c6d2f417aa46c4a4bf 61 | - name: Set up Docker Context for Buildx 62 | id: buildx-context 63 | run: | 64 | docker context create builders 65 | - name: Set up Docker Buildx 66 | timeout-minutes: 5 67 | uses: docker/setup-buildx-action@v3 68 | with: 69 | version: latest 70 | endpoint: builders # self-hosted 71 | - name: Login to GHCR 72 | if: github.event_name != 'pull_request' 73 | uses: docker/login-action@v3 74 | with: 75 | registry: ghcr.io 76 | username: ${{ github.actor }} 77 | password: ${{ secrets.GITHUB_TOKEN }} 78 | - name: Build and push 79 | timeout-minutes: 40 80 | uses: docker/build-push-action@v6 81 | with: 82 | context: . 83 | platforms: linux/amd64,linux/arm64 84 | push: ${{ github.event_name != 'pull_request' }} 85 | tags: ${{ steps.meta.outputs.tags }} 86 | labels: ${{ steps.meta.outputs.labels }} 87 | target: ${{ matrix.image.target }} 88 | -------------------------------------------------------------------------------- /.github/workflows/publish-docs.yml: -------------------------------------------------------------------------------- 1 | name: Publish docs via GitHub Pages 2 | on: 3 | push: 4 | branches: 5 | - main 6 | permissions: 7 | contents: write 8 | jobs: 9 | deploy: 10 | name: Deploy docs 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout main 14 | uses: actions/checkout@v4 15 | - name: Configure Git Credentials 16 | run: | 17 | git config user.name github-actions[bot] 18 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 19 | - uses: actions/setup-python@v5 20 | with: 21 | python-version: 3.x 22 | - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV 23 | - uses: actions/cache@v4 24 | with: 25 | key: mkdocs-material-${{ env.cache_id }} 26 | path: .cache 27 | restore-keys: | 28 | mkdocs-material- 29 | - run: pip install mkdocs-material 30 | - name: Deploy docs 31 | run: mkdocs gh-deploy --force 32 | env: 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request_target: 8 | types: [ opened, reopened, synchronize ] 9 | workflow_dispatch: 10 | 11 | jobs: 12 | update_release_draft: 13 | permissions: 14 | # write permission is required to create a github release 15 | contents: write 16 | # write permission is required for autolabeler 17 | # otherwise, read permission is required at least 18 | pull-requests: write 19 | runs-on: ubuntu-latest 20 | steps: 21 | # Drafts your next Release notes as Pull Requests are merged into "main" 22 | - uses: release-drafter/release-drafter@v6 23 | with: 24 | config-name: release-drafter.yml 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/reuse.yml: -------------------------------------------------------------------------------- 1 | name: REUSE Compliance Check 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | test: 7 | name: reuse 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: REUSE Compliance Check 12 | uses: fsfe/reuse-action@v5 13 | -------------------------------------------------------------------------------- /.github/workflows/size-label.yml: -------------------------------------------------------------------------------- 1 | name: Size Label 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | size-label: 12 | permissions: 13 | contents: read 14 | pull-requests: write 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: size-label 18 | uses: pascalgn/size-label-action@v0.5.5 19 | env: 20 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 21 | -------------------------------------------------------------------------------- /.github/workflows/test-chart.yml: -------------------------------------------------------------------------------- 1 | name: Test Chart 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | pull_request: 8 | paths-ignore: 9 | - 'docs/**' 10 | - '**/*.md' 11 | 12 | jobs: 13 | test-e2e: 14 | name: Run on Ubuntu 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Clone the code 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Go 21 | uses: actions/setup-go@v5 22 | with: 23 | go-version-file: go.mod 24 | 25 | - name: Install Helm 26 | run: | 27 | curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash 28 | 29 | - name: Verify Helm installation 30 | run: helm version 31 | 32 | - name: Lint Helm Chart 33 | run: | 34 | helm lint ./dist/chart 35 | 36 | - name: Install the latest version of kind 37 | run: | 38 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 39 | chmod +x ./kind 40 | sudo mv ./kind /usr/local/bin/kind 41 | 42 | - name: Verify kind installation 43 | run: kind version 44 | 45 | - name: Create kind cluster 46 | run: kind create cluster 47 | 48 | - name: Prepare metal-operator 49 | run: | 50 | go mod download 51 | make docker-build CONTROLLER_IMG=metal-operator:v0.1.0 METALPROBE_IMG=metal-probe:v0.1.0 52 | kind load docker-image metal-operator:v0.1.0 metal-probe:v0.1.0 53 | 54 | - name: Install cert-manager via Helm 55 | run: | 56 | helm repo add jetstack https://charts.jetstack.io 57 | helm repo update 58 | helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true 59 | 60 | - name: Wait for cert-manager to be ready 61 | run: | 62 | kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager 63 | kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-cainjector 64 | kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-webhook 65 | 66 | - name: Install Helm chart for project 67 | run: | 68 | helm install my-release ./dist/chart --create-namespace --namespace metal-operator-system 69 | 70 | - name: Check Helm release status 71 | run: | 72 | helm status my-release --namespace metal-operator-system 73 | -------------------------------------------------------------------------------- /.github/workflows/test-e2e.yml: -------------------------------------------------------------------------------- 1 | name: E2E Tests 2 | 3 | on: 4 | pull_request: 5 | types: [ assigned, opened, synchronize, reopened ] 6 | paths-ignore: 7 | - 'docs/**' 8 | - '**/*.md' 9 | 10 | jobs: 11 | test-e2e: 12 | name: Run on Ubuntu 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Clone the code 16 | uses: actions/checkout@v4 17 | 18 | - name: Setup Go 19 | uses: actions/setup-go@v5 20 | with: 21 | go-version-file: go.mod 22 | 23 | - name: Install the latest version of kind 24 | run: | 25 | curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64 26 | chmod +x ./kind 27 | sudo mv ./kind /usr/local/bin/kind 28 | 29 | - name: Verify kind installation 30 | run: kind version 31 | 32 | - name: Create kind cluster 33 | run: kind create cluster 34 | 35 | - name: Running Test e2e 36 | run: | 37 | go mod tidy 38 | make test-e2e 39 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Code test 2 | 3 | on: 4 | pull_request: 5 | types: [ assigned, opened, synchronize, reopened ] 6 | paths-ignore: 7 | - 'docs/**' 8 | - '**/*.md' 9 | 10 | jobs: 11 | checks: 12 | name: test 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-go@v5 17 | with: 18 | go-version-file: 'go.mod' 19 | - run: make test 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | bin/* 9 | Dockerfile.cross 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # Kubernetes Generated files - skip generated files, except for vendored files 21 | !vendor/**/zz_generated.* 22 | 23 | # editor and IDE paraphernalia 24 | .idea 25 | .vscode 26 | *.swp 27 | *.swo 28 | *~ 29 | .idea/ 30 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | allow-parallel-runners: true 4 | linters: 5 | default: none 6 | enable: 7 | - copyloopvar 8 | - dupl 9 | - errcheck 10 | - ginkgolinter 11 | - goconst 12 | - gocyclo 13 | - govet 14 | - ineffassign 15 | - lll 16 | - misspell 17 | - nakedret 18 | - prealloc 19 | - staticcheck 20 | - unconvert 21 | - unparam 22 | - unused 23 | exclusions: 24 | generated: lax 25 | rules: 26 | - linters: 27 | - lll 28 | path: api/* 29 | - linters: 30 | - dupl 31 | - lll 32 | path: internal/* 33 | paths: 34 | - third_party$ 35 | - builtin$ 36 | - examples$ 37 | formatters: 38 | enable: 39 | - gofmt 40 | - goimports 41 | exclusions: 42 | generated: lax 43 | paths: 44 | - third_party$ 45 | - builtin$ 46 | - examples$ 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM --platform=$BUILDPLATFORM golang:1.24.3 AS builder 3 | ARG TARGETOS 4 | ARG TARGETARCH 5 | 6 | WORKDIR /workspace 7 | # Copy the Go Modules manifests 8 | COPY go.mod go.mod 9 | COPY go.sum go.sum 10 | # cache deps before building and copying source so that we don't need to re-download as much 11 | # and so that source changes don't invalidate our downloaded layer 12 | RUN go mod download 13 | 14 | # Copy the go source 15 | COPY cmd/manager/main.go cmd/manager/main.go 16 | COPY cmd/metalprobe/main.go cmd/metalprobe/main.go 17 | COPY api/ api/ 18 | COPY internal/ internal/ 19 | COPY bmc/ bmc/ 20 | 21 | # Build 22 | # the GOARCH has not a default value to allow the binary be built according to the host where the command 23 | # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO 24 | # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, 25 | # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. 26 | FROM builder AS manager-builder 27 | RUN --mount=type=cache,target=/root/.cache/go-build \ 28 | --mount=type=cache,target=/go/pkg \ 29 | CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/manager/main.go 30 | 31 | FROM builder AS probe-builder 32 | RUN --mount=type=cache,target=/root/.cache/go-build \ 33 | --mount=type=cache,target=/go/pkg \ 34 | CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o metalprobe cmd/metalprobe/main.go 35 | 36 | 37 | # Use distroless as minimal base image to package the manager binary 38 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 39 | FROM gcr.io/distroless/static:nonroot AS manager 40 | LABEL source_repository="https://github.com/ironcore-dev/metal-operator" 41 | WORKDIR / 42 | COPY --from=manager-builder /workspace/manager . 43 | USER 65532:65532 44 | 45 | ENTRYPOINT ["/manager"] 46 | 47 | FROM gcr.io/distroless/static:nonroot AS probe 48 | LABEL source_repository="https://github.com/ironcore-dev/metal-operator" 49 | WORKDIR / 50 | COPY --from=probe-builder /workspace/metalprobe . 51 | USER 65532:65532 52 | 53 | ENTRYPOINT ["/metalprobe"] 54 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | # Code generated by tool. DO NOT EDIT. 2 | # This file is used to track the info used to scaffold your project 3 | # and allow the plugins properly work. 4 | # More info: https://book.kubebuilder.io/reference/project-config.html 5 | domain: ironcore.dev 6 | layout: 7 | - go.kubebuilder.io/v4 8 | plugins: 9 | helm.kubebuilder.io/v1-alpha: {} 10 | projectName: metal-operator 11 | repo: github.com/ironcore-dev/metal-operator 12 | resources: 13 | - api: 14 | crdVersion: v1 15 | controller: true 16 | domain: ironcore.dev 17 | group: metal 18 | kind: Endpoint 19 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 20 | version: v1alpha1 21 | webhooks: 22 | validation: true 23 | webhookVersion: v1 24 | - api: 25 | crdVersion: v1 26 | controller: true 27 | domain: ironcore.dev 28 | group: metal 29 | kind: BMCSecret 30 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 31 | version: v1alpha1 32 | - api: 33 | crdVersion: v1 34 | controller: true 35 | domain: ironcore.dev 36 | group: metal 37 | kind: BMC 38 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 39 | version: v1alpha1 40 | - api: 41 | crdVersion: v1 42 | controller: true 43 | domain: ironcore.dev 44 | group: metal 45 | kind: Server 46 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 47 | version: v1alpha1 48 | - api: 49 | crdVersion: v1 50 | controller: true 51 | domain: ironcore.dev 52 | group: metal 53 | kind: ServerBootConfiguration 54 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 55 | version: v1alpha1 56 | - api: 57 | crdVersion: v1 58 | namespaced: true 59 | controller: true 60 | domain: ironcore.dev 61 | group: metal 62 | kind: ServerClaim 63 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 64 | version: v1alpha1 65 | - api: 66 | crdVersion: v1 67 | namespaced: true 68 | controller: true 69 | domain: ironcore.dev 70 | group: metal 71 | kind: ServerMaintenance 72 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 73 | version: v1alpha1 74 | - api: 75 | crdVersion: v1 76 | controller: true 77 | domain: ironcore.dev 78 | group: metal 79 | kind: BIOSSettings 80 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 81 | version: v1alpha1 82 | - api: 83 | crdVersion: v1 84 | controller: true 85 | domain: ironcore.dev 86 | group: metal 87 | kind: BIOSVersion 88 | path: github.com/ironcore-dev/metal-operator/api/v1alpha1 89 | version: v1alpha1 90 | webhooks: 91 | validation: true 92 | webhookVersion: v1 93 | version: "3" 94 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | SPDX-PackageName = "metal-operator" 3 | SPDX-PackageSupplier = "IronCore authors " 4 | SPDX-PackageDownloadLocation = "https://github.com/ironcore-dev/metal-operator" 5 | 6 | [[annotations]] 7 | path = [ 8 | ".github/**", 9 | ".gitignore", 10 | ".dockerignore", 11 | ".golangci.yml", 12 | "CODEOWNERS", 13 | "Dockerfile", 14 | "Makefile", 15 | "PROJECT", 16 | "config/**", 17 | "dist/**", 18 | "go.mod", 19 | "go.sum", 20 | "mkdocs.yml", 21 | "REUSE.toml", 22 | "hack/**" 23 | ] 24 | precedence = "aggregate" 25 | SPDX-FileCopyrightText = "2024 SAP SE or an SAP affiliate company and IronCore contributors" 26 | SPDX-License-Identifier = "Apache-2.0" 27 | 28 | [[annotations]] 29 | path = [ 30 | "docs/**", 31 | "README.md" 32 | ] 33 | precedence = "aggregate" 34 | SPDX-FileCopyrightText = "2024 SAP SE or an SAP affiliate company and IronCore contributors" 35 | SPDX-License-Identifier = "Apache-2.0" 36 | -------------------------------------------------------------------------------- /api/v1alpha1/bmcsecret_types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package v1alpha1 5 | 6 | import ( 7 | corev1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | const ( 12 | // BMCSecretUsernameKeyName is the secret key name for the username. 13 | BMCSecretUsernameKeyName = "username" 14 | // BMCSecretPasswordKeyName is the secret key name for the password.F 15 | BMCSecretPasswordKeyName = "password" 16 | ) 17 | 18 | //+kubebuilder:object:root=true 19 | //+kubebuilder:subresource:status 20 | //+kubebuilder:resource:scope=Cluster 21 | //+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` 22 | 23 | // BMCSecret is the Schema for the bmcsecrets API 24 | type BMCSecret struct { 25 | metav1.TypeMeta `json:",inline"` 26 | // Standard object's metadata. 27 | // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 28 | // +optional 29 | metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` 30 | 31 | // Immutable, if set to true, ensures that data stored in the Secret cannot 32 | // be updated (only object metadata can be modified). 33 | // If not set to true, the field can be modified at any time. 34 | // Defaulted to nil. 35 | // +optional 36 | Immutable *bool `json:"immutable,omitempty" protobuf:"varint,5,opt,name=immutable"` 37 | 38 | // Data contains the secret data. Each key must consist of alphanumeric 39 | // characters, '-', '_' or '.'. The serialized form of the secret data is a 40 | // base64 encoded string, representing the arbitrary (possibly non-string) 41 | // data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 42 | // +optional 43 | Data map[string][]byte `json:"data,omitempty" protobuf:"bytes,2,rep,name=data"` 44 | 45 | // stringData allows specifying non-binary secret data in string form. 46 | // It is provided as a write-only input field for convenience. 47 | // All keys and values are merged into the data field on write, overwriting any existing values. 48 | // The stringData field is never output when reading from the API. 49 | // +k8s:conversion-gen=false 50 | // +optional 51 | StringData map[string]string `json:"stringData,omitempty" protobuf:"bytes,4,rep,name=stringData"` 52 | 53 | // Used to facilitate programmatic handling of secret data. 54 | // More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types 55 | // +optional 56 | Type corev1.SecretType `json:"type,omitempty" protobuf:"bytes,3,opt,name=type,casttype=SecretType"` 57 | } 58 | 59 | //+kubebuilder:object:root=true 60 | 61 | // BMCSecretList contains a list of BMCSecret 62 | type BMCSecretList struct { 63 | metav1.TypeMeta `json:",inline"` 64 | metav1.ListMeta `json:"metadata,omitempty"` 65 | Items []BMCSecret `json:"items"` 66 | } 67 | 68 | func init() { 69 | SchemeBuilder.Register(&BMCSecret{}, &BMCSecretList{}) 70 | } 71 | -------------------------------------------------------------------------------- /api/v1alpha1/constants.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package v1alpha1 5 | 6 | const ( 7 | // OperationAnnotation indicates which operation should be performed outside the current spec definition flow. 8 | OperationAnnotation = "metal.ironcore.dev/operation" 9 | // OperationAnnotationIgnore skips the reconciliation of a resource if set to true. 10 | OperationAnnotationIgnore = "ignore" 11 | // InstanceTypeAnnotation is used to specify the type of Server. 12 | InstanceTypeAnnotation = "metal.ironcore.dev/instance-type" 13 | ) 14 | -------------------------------------------------------------------------------- /api/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package v1alpha1 contains API Schema definitions for the settings.gardener.cloud API group 5 | // +groupName=metal.ironcore.dev 6 | // +kubebuilder:object:generate=true 7 | package v1alpha1 8 | -------------------------------------------------------------------------------- /api/v1alpha1/endpoint_types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package v1alpha1 5 | 6 | import ( 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | ) 9 | 10 | // EndpointSpec defines the desired state of Endpoint 11 | type EndpointSpec struct { 12 | // MACAddress is the MAC address of the endpoint. 13 | MACAddress string `json:"macAddress"` 14 | // IP is the IP address of the endpoint. 15 | // +kubebuilder:validation:Type=string 16 | // +kubebuilder:validation:Schemaless 17 | IP IP `json:"ip"` 18 | } 19 | 20 | // EndpointStatus defines the observed state of Endpoint 21 | type EndpointStatus struct { 22 | } 23 | 24 | // +kubebuilder:object:root=true 25 | // +kubebuilder:subresource:status 26 | // +kubebuilder:resource:scope=Cluster 27 | // +kubebuilder:printcolumn:name="MACAddress",type=string,JSONPath=`.spec.macAddress` 28 | // +kubebuilder:printcolumn:name="IP",type=string,JSONPath=`.spec.ip` 29 | // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` 30 | 31 | // Endpoint is the Schema for the endpoints API 32 | type Endpoint struct { 33 | metav1.TypeMeta `json:",inline"` 34 | metav1.ObjectMeta `json:"metadata,omitempty"` 35 | 36 | Spec EndpointSpec `json:"spec,omitempty"` 37 | Status EndpointStatus `json:"status,omitempty"` 38 | } 39 | 40 | //+kubebuilder:object:root=true 41 | 42 | // EndpointList contains a list of Endpoint 43 | type EndpointList struct { 44 | metav1.TypeMeta `json:",inline"` 45 | metav1.ListMeta `json:"metadata,omitempty"` 46 | Items []Endpoint `json:"items"` 47 | } 48 | 49 | func init() { 50 | SchemeBuilder.Register(&Endpoint{}, &EndpointList{}) 51 | } 52 | -------------------------------------------------------------------------------- /api/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package v1alpha1 contains API Schema definitions for the metal v1alpha1 API group 5 | // +kubebuilder:object:generate=true 6 | // +groupName=metal.ironcore.dev 7 | package v1alpha1 8 | 9 | import ( 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | "sigs.k8s.io/controller-runtime/pkg/scheme" 12 | ) 13 | 14 | var ( 15 | // GroupVersion is group version used to register these objects 16 | GroupVersion = schema.GroupVersion{Group: "metal.ironcore.dev", Version: "v1alpha1"} 17 | 18 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 19 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 20 | 21 | // AddToScheme adds the types in this group-version to the given scheme. 22 | AddToScheme = SchemeBuilder.AddToScheme 23 | ) 24 | -------------------------------------------------------------------------------- /api/v1alpha1/serverbootconfiguration_types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package v1alpha1 5 | 6 | import ( 7 | v1 "k8s.io/api/core/v1" 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // ServerBootConfigurationSpec defines the desired state of ServerBootConfiguration. 12 | type ServerBootConfigurationSpec struct { 13 | // ServerRef is a reference to the server for which this boot configuration is intended. 14 | ServerRef v1.LocalObjectReference `json:"serverRef"` 15 | 16 | // Image specifies the boot image to be used for the server. 17 | // This field is optional and can be omitted if not specified. 18 | Image string `json:"image,omitempty"` 19 | 20 | // IgnitionSecretRef is a reference to the Kubernetes Secret object that contains 21 | // the ignition configuration for the server. This field is optional and can be omitted if not specified. 22 | IgnitionSecretRef *v1.LocalObjectReference `json:"ignitionSecretRef,omitempty"` 23 | } 24 | 25 | // ServerBootConfigurationState defines the possible states of a ServerBootConfiguration. 26 | type ServerBootConfigurationState string 27 | 28 | const ( 29 | // ServerBootConfigurationStatePending indicates that the boot configuration is pending and not yet ready. 30 | ServerBootConfigurationStatePending ServerBootConfigurationState = "Pending" 31 | 32 | // ServerBootConfigurationStateReady indicates that the boot configuration is ready for use. 33 | ServerBootConfigurationStateReady ServerBootConfigurationState = "Ready" 34 | 35 | // ServerBootConfigurationStateError indicates that there is an error with the boot configuration. 36 | ServerBootConfigurationStateError ServerBootConfigurationState = "Error" 37 | ) 38 | 39 | // ServerBootConfigurationStatus defines the observed state of ServerBootConfiguration. 40 | type ServerBootConfigurationStatus struct { 41 | // State represents the current state of the boot configuration. 42 | State ServerBootConfigurationState `json:"state,omitempty"` 43 | } 44 | 45 | //+kubebuilder:object:root=true 46 | //+kubebuilder:subresource:status 47 | //+kubebuilder:printcolumn:name="ServerRef",type=string,JSONPath=`.spec.serverRef.name` 48 | //+kubebuilder:printcolumn:name="Image",type=string,JSONPath=`.spec.image` 49 | //+kubebuilder:printcolumn:name="IgnitionRef",type=string,JSONPath=`.spec.ignitionSecretRef.name` 50 | //+kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state` 51 | //+kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` 52 | 53 | // ServerBootConfiguration is the Schema for the serverbootconfigurations API 54 | type ServerBootConfiguration struct { 55 | metav1.TypeMeta `json:",inline"` 56 | metav1.ObjectMeta `json:"metadata,omitempty"` 57 | 58 | Spec ServerBootConfigurationSpec `json:"spec,omitempty"` 59 | Status ServerBootConfigurationStatus `json:"status,omitempty"` 60 | } 61 | 62 | //+kubebuilder:object:root=true 63 | 64 | // ServerBootConfigurationList contains a list of ServerBootConfiguration 65 | type ServerBootConfigurationList struct { 66 | metav1.TypeMeta `json:",inline"` 67 | metav1.ListMeta `json:"metadata,omitempty"` 68 | Items []ServerBootConfiguration `json:"items"` 69 | } 70 | 71 | func init() { 72 | SchemeBuilder.Register(&ServerBootConfiguration{}, &ServerBootConfigurationList{}) 73 | } 74 | -------------------------------------------------------------------------------- /bmc/mockup.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package bmc 5 | 6 | import "github.com/stmcginnis/gofish/redfish" 7 | 8 | // RedfishLocalBMC is an implementation of the BMC interface for Redfish. 9 | type RedfishMockUps struct { 10 | BIOSSettingAttr map[string]map[string]any 11 | PendingBIOSSetting map[string]map[string]any 12 | BIOSVersion string 13 | BIOSUpgradingVersion string 14 | BIOSUpgradeTaskIndex int 15 | BIOSUpgradeTaskStatus []redfish.Task 16 | } 17 | 18 | func (r *RedfishMockUps) InitializeDefaults() { 19 | r.BIOSSettingAttr = map[string]map[string]any{ 20 | "abc": {"type": "string", "reboot": false, "value": "bar"}, 21 | "fooreboot": {"type": "integer", "reboot": true, "value": 123}, 22 | } 23 | r.PendingBIOSSetting = map[string]map[string]any{} 24 | r.BIOSVersion = "" 25 | r.BIOSUpgradingVersion = "" 26 | 27 | r.BIOSUpgradeTaskIndex = 0 28 | r.BIOSUpgradeTaskStatus = []redfish.Task{ 29 | { 30 | TaskState: redfish.NewTaskState, 31 | PercentComplete: 0, 32 | }, 33 | { 34 | TaskState: redfish.PendingTaskState, 35 | PercentComplete: 0, 36 | }, 37 | { 38 | TaskState: redfish.StartingTaskState, 39 | PercentComplete: 0, 40 | }, 41 | { 42 | TaskState: redfish.RunningTaskState, 43 | PercentComplete: 10, 44 | }, 45 | { 46 | TaskState: redfish.RunningTaskState, 47 | PercentComplete: 20, 48 | }, 49 | { 50 | TaskState: redfish.RunningTaskState, 51 | PercentComplete: 100, 52 | }, 53 | { 54 | TaskState: redfish.CompletedTaskState, 55 | PercentComplete: 100, 56 | }, 57 | } 58 | } 59 | 60 | func (r *RedfishMockUps) ResetBIOSSettings() { 61 | r.BIOSSettingAttr = map[string]map[string]any{ 62 | "abc": {"type": "string", "reboot": false, "value": "bar"}, 63 | "fooreboot": {"type": "integer", "reboot": true, "value": 123}, 64 | } 65 | r.PendingBIOSSetting = map[string]map[string]any{} 66 | } 67 | 68 | func (r *RedfishMockUps) ResetPendingBIOSSetting() { 69 | r.PendingBIOSSetting = map[string]map[string]any{} 70 | } 71 | 72 | func (r *RedfishMockUps) ResetBIOSVersionUpdate() { 73 | r.ResetBIOSSettings() 74 | r.BIOSUpgradeTaskIndex = 0 75 | r.BIOSUpgradingVersion = "" 76 | r.BIOSVersion = "" 77 | } 78 | 79 | func InitMockUp() { 80 | UnitTestMockUps = &RedfishMockUps{} 81 | UnitTestMockUps.InitializeDefaults() 82 | } 83 | 84 | var UnitTestMockUps *RedfishMockUps 85 | -------------------------------------------------------------------------------- /bmc/oem/dell.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package oem 5 | 6 | import ( 7 | "context" 8 | "encoding/json" 9 | "fmt" 10 | "io" 11 | "net/http" 12 | 13 | "github.com/stmcginnis/gofish" 14 | "github.com/stmcginnis/gofish/redfish" 15 | ) 16 | 17 | type Dell struct { 18 | Service *gofish.Service 19 | } 20 | 21 | func (r *Dell) GetUpdateRequestBody( 22 | parameters *redfish.SimpleUpdateParameters, 23 | ) *SimpleUpdateRequestBody { 24 | RequestBody := &SimpleUpdateRequestBody{} 25 | RequestBody.RedfishOperationApplyTime = redfish.ImmediateOperationApplyTime 26 | RequestBody.ForceUpdate = parameters.ForceUpdate 27 | RequestBody.ImageURI = parameters.ImageURI 28 | RequestBody.Passord = parameters.Passord 29 | RequestBody.Username = parameters.Username 30 | RequestBody.Targets = parameters.Targets 31 | RequestBody.TransferProtocol = parameters.TransferProtocol 32 | 33 | return RequestBody 34 | } 35 | 36 | func (r *Dell) GetUpdateTaskMonitorURI(response *http.Response) (string, error) { 37 | rawBody, err := io.ReadAll(response.Body) 38 | if err != nil { 39 | return "", fmt.Errorf("failed to read the response body %v %v", err, rawBody) 40 | } 41 | 42 | if taskMonitor, ok := response.Header["Location"]; ok && len(rawBody) == 0 { 43 | return taskMonitor[0], nil 44 | } 45 | 46 | return "", fmt.Errorf("unexpected response body %v %v", err, rawBody) 47 | } 48 | 49 | func (r *Dell) GetTaskMonitorDetails(ctx context.Context, taskMonitorResponse *http.Response) (*redfish.Task, error) { 50 | task := &redfish.Task{} 51 | respTaskRawBody, err := io.ReadAll(taskMonitorResponse.Body) 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | err = json.Unmarshal(respTaskRawBody, &task) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | return task, nil 62 | } 63 | -------------------------------------------------------------------------------- /bmc/oem/hpe.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package oem 5 | 6 | import ( 7 | "context" 8 | "encoding/json" 9 | "fmt" 10 | "io" 11 | "net/http" 12 | "strings" 13 | 14 | "github.com/stmcginnis/gofish" 15 | "github.com/stmcginnis/gofish/common" 16 | "github.com/stmcginnis/gofish/redfish" 17 | ) 18 | 19 | type HPE struct { 20 | Service *gofish.Service 21 | } 22 | 23 | func (r *HPE) GetUpdateRequestBody( 24 | parameters *redfish.SimpleUpdateParameters, 25 | ) *SimpleUpdateRequestBody { 26 | RequestBody := &SimpleUpdateRequestBody{} 27 | RequestBody.ForceUpdate = parameters.ForceUpdate 28 | RequestBody.ImageURI = parameters.ImageURI 29 | RequestBody.Passord = parameters.Passord 30 | RequestBody.Username = parameters.Username 31 | RequestBody.Targets = parameters.Targets 32 | RequestBody.TransferProtocol = parameters.TransferProtocol 33 | 34 | return RequestBody 35 | } 36 | 37 | func (r *HPE) GetUpdateTaskMonitorURI(response *http.Response) (string, error) { 38 | rawBody, err := io.ReadAll(response.Body) 39 | if err != nil { 40 | return "", fmt.Errorf("failed to read the response body %v %v", err, rawBody) 41 | } 42 | 43 | // extract tasks ID to monitor it 44 | var tResp struct { 45 | TaskMonitor string 46 | } 47 | err = json.Unmarshal(rawBody, &tResp) 48 | if err != nil { 49 | return tResp.TaskMonitor, fmt.Errorf("failed to Unmarshal taskMonitor URI %v", err) 50 | } 51 | 52 | return tResp.TaskMonitor, nil 53 | } 54 | 55 | func (r *HPE) GetTaskMonitorDetails(ctx context.Context, taskMonitorResponse *http.Response) (*redfish.Task, error) { 56 | task := &redfish.Task{} 57 | respTaskRawBody, err := io.ReadAll(taskMonitorResponse.Body) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | err = json.Unmarshal(respTaskRawBody, &task) 63 | if err != nil { 64 | return nil, err 65 | } 66 | 67 | if task.TaskState == "" && task.ODataID == "" { 68 | // hpe gives error after completion of data, exptract it to verify if success 69 | type errTask struct { 70 | Code string `json:"code"` 71 | Message string `json:"message"` 72 | ExtendedInfo []map[string]string `json:"@Message.ExtendedInfo"` 73 | } 74 | var tTask struct { 75 | Error errTask `json:"error"` 76 | } 77 | err = json.Unmarshal(respTaskRawBody, &tTask) 78 | if err != nil { 79 | return task, 80 | fmt.Errorf( 81 | "unable to extract the completed task details %v. \nResponse body %v", 82 | err, 83 | string(respTaskRawBody)) 84 | } 85 | if strings.Contains(tTask.Error.ExtendedInfo[0]["MessageId"], "Success") { 86 | task.TaskState = redfish.CompletedTaskState 87 | task.PercentComplete = 100 88 | task.TaskStatus = common.OKHealth 89 | return task, nil 90 | } 91 | return task, fmt.Errorf("unable to find the state of the Task %v", string(respTaskRawBody)) 92 | } 93 | 94 | return task, nil 95 | } 96 | -------------------------------------------------------------------------------- /bmc/oem/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package oem 5 | 6 | import "github.com/stmcginnis/gofish/redfish" 7 | 8 | type SimpleUpdateRequestBody struct { 9 | redfish.SimpleUpdateParameters 10 | RedfishOperationApplyTime redfish.OperationApplyTime `json:"@Redfish.OperationApplyTime,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /cmd/metalctl/app/app.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package app 5 | 6 | import ( 7 | "github.com/spf13/cobra" 8 | "k8s.io/apimachinery/pkg/runtime" 9 | 10 | metalv1alphav1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 11 | apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 12 | utilruntime "k8s.io/apimachinery/pkg/util/runtime" 13 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 14 | ) 15 | 16 | const Name string = "metalctl" 17 | 18 | var scheme = runtime.NewScheme() 19 | 20 | func init() { 21 | utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) 22 | utilruntime.Must(clientgoscheme.AddToScheme(scheme)) 23 | utilruntime.Must(metalv1alphav1.AddToScheme(scheme)) 24 | } 25 | 26 | func NewCommand() *cobra.Command { 27 | root := &cobra.Command{ 28 | Use: Name, 29 | Short: "CLI client for metal-operator", 30 | Args: cobra.NoArgs, 31 | } 32 | root.AddCommand(NewMoveCommand()) 33 | root.AddCommand(NewConsoleCommand()) 34 | return root 35 | } 36 | -------------------------------------------------------------------------------- /cmd/metalctl/app/move.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package app 5 | 6 | import ( 7 | "fmt" 8 | "log/slog" 9 | 10 | "github.com/spf13/cobra" 11 | apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 12 | "k8s.io/apimachinery/pkg/runtime/schema" 13 | "k8s.io/client-go/tools/clientcmd" 14 | "sigs.k8s.io/controller-runtime/pkg/client" 15 | 16 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 17 | utils "github.com/ironcore-dev/metal-operator/cmdutils" 18 | ) 19 | 20 | var ( 21 | sourceKubeconfig string 22 | targetKubeconfig string 23 | namespace string 24 | dryRun bool 25 | verbose bool 26 | ) 27 | 28 | func NewMoveCommand() *cobra.Command { 29 | move := &cobra.Command{ 30 | Use: "move", 31 | Short: "Move metal-operator CRs from one cluster to another", 32 | RunE: runMove, 33 | } 34 | move.Flags().StringVar(&sourceKubeconfig, "source-kubeconfig", "", "Kubeconfig pointing to the source cluster") 35 | move.Flags().StringVar(&targetKubeconfig, "target-kubeconfig", "", "Kubeconfig pointing to the target cluster") 36 | move.Flags().StringVar(&namespace, "namespace", "", 37 | "namespace to filter CRs to migrate. Defaults to all namespaces if not specified") 38 | move.Flags().BoolVar(&dryRun, "dry-run", false, "show what would be moved without executing the migration") 39 | move.Flags().BoolVar(&verbose, "verbose", false, "enable verbose logging for detailed output during migration") 40 | _ = move.MarkFlagRequired("source-kubeconfig") 41 | _ = move.MarkFlagRequired("target-kubeconfig") 42 | 43 | if verbose { 44 | slog.SetLogLoggerLevel(slog.LevelDebug) 45 | } 46 | return move 47 | } 48 | 49 | func makeClient(kubeconfig string) (client.Client, error) { 50 | cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 51 | if err != nil { 52 | return nil, fmt.Errorf("failed to load cluster kubeconfig: %w", err) 53 | } 54 | return client.New(cfg, client.Options{Scheme: scheme}) 55 | } 56 | 57 | func makeClients() (utils.Clients, error) { 58 | var clients utils.Clients 59 | var err error 60 | 61 | clients.Source, err = makeClient(sourceKubeconfig) 62 | if err != nil { 63 | return clients, fmt.Errorf("failed to construct a source cluster client: %w", err) 64 | } 65 | clients.Target, err = makeClient(targetKubeconfig) 66 | if err != nil { 67 | return clients, fmt.Errorf("failed to construct a target cluster client: %w", err) 68 | } 69 | return clients, nil 70 | } 71 | 72 | func runMove(cmd *cobra.Command, args []string) error { 73 | clients, err := makeClients() 74 | if err != nil { 75 | return err 76 | } 77 | ctx := cmd.Context() 78 | 79 | crdList := &apiextensionsv1.CustomResourceDefinitionList{} 80 | if err := clients.Source.List(ctx, crdList); err != nil { 81 | return err 82 | } 83 | crsSchema := []schema.GroupVersionKind{} 84 | for _, crd := range crdList.Items { 85 | if crd.Spec.Group == metalv1alpha1.GroupVersion.Group { 86 | crsSchema = append(crsSchema, schema.GroupVersionKind{ 87 | Group: crd.Spec.Group, 88 | Version: crd.Spec.Versions[0].Name, 89 | Kind: crd.Spec.Names.Kind, 90 | }) 91 | } 92 | } 93 | return utils.Move(ctx, clients, crsSchema, namespace, dryRun) 94 | } 95 | -------------------------------------------------------------------------------- /cmd/metalctl/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | 10 | "github.com/ironcore-dev/metal-operator/cmd/metalctl/app" 11 | "sigs.k8s.io/controller-runtime/pkg/manager/signals" 12 | ) 13 | 14 | func main() { 15 | if err := app.NewCommand().ExecuteContext(signals.SetupSignalHandler()); err != nil { 16 | fmt.Fprintln(os.Stderr, err) 17 | os.Exit(1) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /cmd/metalprobe/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "os" 9 | "time" 10 | 11 | "github.com/ironcore-dev/metal-operator/internal/probe" 12 | ctrl "sigs.k8s.io/controller-runtime" 13 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 14 | ) 15 | 16 | var ( 17 | setupLog = ctrl.Log.WithName("setup") 18 | ) 19 | 20 | func main() { 21 | var registryURL string 22 | var serverUUID string 23 | var duration time.Duration 24 | 25 | flag.StringVar(®istryURL, "registry-url", "", "Registry URL where the probe will register itself.") 26 | flag.StringVar(&serverUUID, "server-uuid", "", "Agent UUID to register with the registry.") 27 | flag.DurationVar(&duration, "duration", 5*time.Second, "Duration of time to wait between checks.") 28 | 29 | opts := zap.Options{ 30 | Development: true, 31 | } 32 | opts.BindFlags(flag.CommandLine) 33 | flag.Parse() 34 | 35 | ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) 36 | 37 | if serverUUID == "" { 38 | setupLog.Error(nil, "server uuid is missing") 39 | os.Exit(1) 40 | } 41 | 42 | if registryURL == "" { 43 | setupLog.Error(nil, "registry URL is missing") 44 | os.Exit(1) 45 | } 46 | 47 | ctx := ctrl.SetupSignalHandler() 48 | 49 | setupLog.Info("starting registry agent") 50 | agent := probe.NewAgent(serverUUID, registryURL, duration) 51 | if err := agent.Start(ctx); err != nil { 52 | setupLog.Error(err, "problem running probe agent") 53 | os.Exit(1) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cmdutils/clients.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package cmdutils 5 | 6 | import "sigs.k8s.io/controller-runtime/pkg/client" 7 | 8 | type Clients struct { 9 | Source client.Client 10 | Target client.Client 11 | } 12 | -------------------------------------------------------------------------------- /cmdutils/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package cmdutils 5 | 6 | import ( 7 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 8 | ) 9 | 10 | // transform returns a list of transformed list elements with function f. 11 | func transform[L ~[]E, E any, T any](list L, f func(E) T) []T { 12 | ret := make([]T, len(list)) 13 | for i, elem := range list { 14 | ret[i] = f(elem) 15 | } 16 | return ret 17 | } 18 | 19 | func crName(cr *unstructured.Unstructured) string { 20 | return cr.GetObjectKind().GroupVersionKind().Kind + ":" + cr.GetNamespace() + "/" + cr.GetName() 21 | } 22 | -------------------------------------------------------------------------------- /config/certmanager/certificate-metrics.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a metrics certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | apiVersion: cert-manager.io/v1 4 | kind: Certificate 5 | metadata: 6 | labels: 7 | app.kubernetes.io/name: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | name: metrics-certs # this name should match the one appeared in kustomizeconfig.yaml 10 | namespace: system 11 | spec: 12 | dnsNames: 13 | # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize 14 | # replacements in the config/default/kustomization.yaml file. 15 | - SERVICE_NAME.SERVICE_NAMESPACE.svc 16 | - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local 17 | issuerRef: 18 | kind: Issuer 19 | name: selfsigned-issuer 20 | secretName: metrics-server-cert 21 | -------------------------------------------------------------------------------- /config/certmanager/certificate-webhook.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Certificate 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: metal-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 8 | namespace: system 9 | spec: 10 | # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize 11 | dnsNames: 12 | - SERVICE_NAME.SERVICE_NAMESPACE.svc 13 | - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local 14 | issuerRef: 15 | kind: Issuer 16 | name: selfsigned-issuer 17 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 18 | -------------------------------------------------------------------------------- /config/certmanager/issuer.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. 4 | apiVersion: cert-manager.io/v1 5 | kind: Issuer 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: metal-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | name: selfsigned-issuer 11 | namespace: system 12 | spec: 13 | selfSigned: {} -------------------------------------------------------------------------------- /config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - issuer.yaml 3 | - certificate-metrics.yaml 4 | - certificate-webhook.yaml 5 | 6 | configurations: 7 | - kustomizeconfig.yaml 8 | -------------------------------------------------------------------------------- /config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | -------------------------------------------------------------------------------- /config/crd/bases/metal.ironcore.dev_endpoints.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | controller-gen.kubebuilder.io/version: v0.18.0 7 | name: endpoints.metal.ironcore.dev 8 | spec: 9 | group: metal.ironcore.dev 10 | names: 11 | kind: Endpoint 12 | listKind: EndpointList 13 | plural: endpoints 14 | singular: endpoint 15 | scope: Cluster 16 | versions: 17 | - additionalPrinterColumns: 18 | - jsonPath: .spec.macAddress 19 | name: MACAddress 20 | type: string 21 | - jsonPath: .spec.ip 22 | name: IP 23 | type: string 24 | - jsonPath: .metadata.creationTimestamp 25 | name: Age 26 | type: date 27 | name: v1alpha1 28 | schema: 29 | openAPIV3Schema: 30 | description: Endpoint is the Schema for the endpoints 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: EndpointSpec defines the desired state of Endpoint 51 | properties: 52 | ip: 53 | description: IP is the IP address of the endpoint. 54 | type: string 55 | macAddress: 56 | description: MACAddress is the MAC address of the endpoint. 57 | type: string 58 | required: 59 | - ip 60 | - macAddress 61 | type: object 62 | status: 63 | description: EndpointStatus defines the observed state of Endpoint 64 | type: object 65 | type: object 66 | served: true 67 | storage: true 68 | subresources: 69 | status: {} 70 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/metal.ironcore.dev_endpoints.yaml 6 | - bases/metal.ironcore.dev_bmcsecrets.yaml 7 | - bases/metal.ironcore.dev_bmcs.yaml 8 | - bases/metal.ironcore.dev_servers.yaml 9 | - bases/metal.ironcore.dev_serverbootconfigurations.yaml 10 | - bases/metal.ironcore.dev_serverclaims.yaml 11 | - bases/metal.ironcore.dev_servermaintenances.yaml 12 | - bases/metal.ironcore.dev_biossettings.yaml 13 | - bases/metal.ironcore.dev_biosversions.yaml 14 | #+kubebuilder:scaffold:crdkustomizeresource 15 | 16 | patches: 17 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 18 | # patches here are for enabling the conversion webhook for each CRD 19 | #- path: patches/webhook_in_endpoints.yaml 20 | #- path: patches/webhook_in_bmcsecrets.yaml 21 | - path: patches/webhook_in_bmcs.yaml 22 | #- path: patches/webhook_in_servers.yaml 23 | #- path: patches/webhook_in_serverbootconfigurations.yaml 24 | - path: patches/webhook_in_serverclaims.yaml 25 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 26 | 27 | # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. 28 | # patches here are for enabling the CA injection for each CRD 29 | #- path: patches/cainjection_in_endpoints.yaml 30 | #- path: patches/cainjection_in_bmcsecrets.yaml 31 | #- path: patches/cainjection_in_bmcs.yaml 32 | #- path: patches/cainjection_in_servers.yaml 33 | #- path: patches/cainjection_in_serverbootconfigurations.yaml 34 | #- path: patches/cainjection_in_serverclaims.yaml 35 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 36 | 37 | # [WEBHOOK] To enable webhook, uncomment the following section 38 | # the following config is for teaching kustomize how to do kustomization for CRDs. 39 | 40 | configurations: 41 | - kustomizeconfig.yaml 42 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_bmcs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 7 | name: bmcs.metal.ironcore.dev 8 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_serverclaims.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 7 | name: serverclaims.metal.ironcore.dev 8 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_bmcs.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: bmcs.metal.ironcore.dev 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_serverclaims.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: serverclaims.metal.ironcore.dev 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/default/cert_metrics_manager_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch adds the args, volumes, and ports to allow the manager to use the metrics-server certs. 2 | 3 | # Add the volumeMount for the metrics-server certs 4 | - op: add 5 | path: /spec/template/spec/containers/0/volumeMounts/- 6 | value: 7 | mountPath: /tmp/k8s-metrics-server/metrics-certs 8 | name: metrics-certs 9 | readOnly: true 10 | 11 | # Add the --metrics-cert-path argument for the metrics server 12 | - op: add 13 | path: /spec/template/spec/containers/0/args/- 14 | value: --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs 15 | 16 | # Add the metrics-server certs volume configuration 17 | - op: add 18 | path: /spec/template/spec/volumes/- 19 | value: 20 | name: metrics-certs 21 | secret: 22 | secretName: metrics-server-cert 23 | optional: false 24 | items: 25 | - key: ca.crt 26 | path: ca.crt 27 | - key: tls.crt 28 | path: tls.crt 29 | - key: tls.key 30 | path: tls.key 31 | -------------------------------------------------------------------------------- /config/default/manager_metrics_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch adds the args to allow exposing the metrics endpoint using HTTPS 2 | - op: add 3 | path: /spec/template/spec/containers/0/args/0 4 | value: --metrics-bind-address=:8443 5 | -------------------------------------------------------------------------------- /config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch ensures the webhook certificates are properly mounted in the manager container. 2 | # It configures the necessary arguments, volumes, volume mounts, and container ports. 3 | 4 | # Add the --webhook-cert-path argument for configuring the webhook certificate path 5 | - op: add 6 | path: /spec/template/spec/containers/0/args/- 7 | value: --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs 8 | 9 | # Add the volumeMount for the webhook certificates 10 | - op: add 11 | path: /spec/template/spec/containers/0/volumeMounts/- 12 | value: 13 | mountPath: /tmp/k8s-webhook-server/serving-certs 14 | name: webhook-certs 15 | readOnly: true 16 | 17 | # Add the port configuration for the webhook server 18 | - op: add 19 | path: /spec/template/spec/containers/0/ports/- 20 | value: 21 | containerPort: 9443 22 | name: webhook-server 23 | protocol: TCP 24 | 25 | # Add the volume configuration for the webhook certificates 26 | - op: add 27 | path: /spec/template/spec/volumes/- 28 | value: 29 | name: webhook-certs 30 | secret: 31 | secretName: webhook-server-cert 32 | -------------------------------------------------------------------------------- /config/default/metrics_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | app.kubernetes.io/name: metal-operator 7 | app.kubernetes.io/managed-by: kustomize 8 | name: controller-manager-metrics-service 9 | namespace: system 10 | spec: 11 | ports: 12 | - name: https 13 | port: 8443 14 | protocol: TCP 15 | targetPort: 8443 16 | selector: 17 | control-plane: controller-manager 18 | app.kubernetes.io/name: metal-operator -------------------------------------------------------------------------------- /config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # CERTIFICATE_NAMESPACE and CERTIFICATE_NAME will be substituted by kustomize 3 | #apiVersion: admissionregistration.k8s.io/v1 4 | #kind: MutatingWebhookConfiguration 5 | #metadata: 6 | # labels: 7 | # app.kubernetes.io/name: mutatingwebhookconfiguration 8 | # app.kubernetes.io/instance: mutating-webhook-configuration 9 | # app.kubernetes.io/component: webhook 10 | # app.kubernetes.io/created-by: metal-operator 11 | # app.kubernetes.io/part-of: metal-operator 12 | # app.kubernetes.io/managed-by: kustomize 13 | # name: mutating-webhook-configuration 14 | # annotations: 15 | # cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 16 | --- 17 | apiVersion: admissionregistration.k8s.io/v1 18 | kind: ValidatingWebhookConfiguration 19 | metadata: 20 | labels: 21 | app.kubernetes.io/name: validatingwebhookconfiguration 22 | app.kubernetes.io/instance: validating-webhook-configuration 23 | app.kubernetes.io/component: webhook 24 | app.kubernetes.io/created-by: metal-operator 25 | app.kubernetes.io/part-of: metal-operator 26 | app.kubernetes.io/managed-by: kustomize 27 | name: validating-webhook-configuration 28 | annotations: 29 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME 30 | -------------------------------------------------------------------------------- /config/dev/delete_manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: kube-rbac-proxy 11 | $patch: delete 12 | - name: manager 13 | args: [] 14 | -------------------------------------------------------------------------------- /config/dev/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../default 3 | - ../redfish-mockup 4 | - registry_service.yaml 5 | 6 | patches: 7 | - path: delete_manager_auth_proxy_patch.yaml 8 | - path: manager_patch.yaml 9 | 10 | secretGenerator: 11 | - name: macdb 12 | namespace: metal-operator-system 13 | files: 14 | - macdb.yaml 15 | -------------------------------------------------------------------------------- /config/dev/macdb.yaml: -------------------------------------------------------------------------------- 1 | macPrefixes: 2 | - macPrefix: 23 3 | manufacturer: Foo 4 | protocol: RedfishKube 5 | port: 8000 6 | type: bmc 7 | defaultCredentials: 8 | - username: foo 9 | password: bar 10 | console: 11 | type: ssh 12 | port: 22 13 | -------------------------------------------------------------------------------- /config/dev/manager_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | args: 12 | - --health-probe-bind-address=:8081 13 | - --metrics-bind-address=127.0.0.1:8080 14 | - --leader-elect 15 | - --mac-prefixes-file=/etc/macdb/macdb.yaml 16 | - --probe-image=ghcr.io/ironcore-dev/metalprobe:latest 17 | - --probe-os-image=ghcr.io/ironcore-dev/os-images/gardenlinux:1443.10 18 | - --registry-url=http://127.0.0.1:30000 19 | - --registry-port=30000 20 | - --enforce-first-boot 21 | ports: 22 | - containerPort: 30000 23 | volumeMounts: 24 | - mountPath: /etc/macdb/ 25 | name: macdb 26 | - name: redfish 27 | image: dmtf/redfish-mockup-server:latest 28 | ports: 29 | - containerPort: 8000 30 | securityContext: 31 | runAsNonRoot: false 32 | volumes: 33 | - name: macdb 34 | secret: 35 | defaultMode: 420 36 | secretName: macdb 37 | -------------------------------------------------------------------------------- /config/dev/registry_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: metal-registry 5 | namespace: metal-operator-system 6 | spec: 7 | ports: 8 | - name: registry-server 9 | port: 30000 10 | targetPort: 30000 11 | selector: 12 | control-plane: controller-manager 13 | -------------------------------------------------------------------------------- /config/e2e-metrics-validation/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../default 3 | 4 | patches: 5 | # --registry-url and --probe-os-image are mandatory flags. 6 | # The following patch will add value for above flags 7 | - path: manager_args_patch.yaml 8 | target: 9 | kind: Deployment 10 | -------------------------------------------------------------------------------- /config/e2e-metrics-validation/manager_args_patch.yaml: -------------------------------------------------------------------------------- 1 | # Add the --probe-os-image argument for controller-manager 2 | - op: add 3 | path: /spec/template/spec/containers/0/args/- 4 | value: --probe-os-image=linux 5 | 6 | # Add the --registry-url argument for the controller-manager 7 | - op: add 8 | path: /spec/template/spec/containers/0/args/- 9 | value: --registry-url=http://localhost:30000 -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | -------------------------------------------------------------------------------- /config/network-policy/allow-webhook-traffic.yaml: -------------------------------------------------------------------------------- 1 | # This NetworkPolicy allows ingress traffic to your webhook server running 2 | # as part of the controller-manager from specific namespaces and pods. CR(s) which uses webhooks 3 | # will only work when applied in namespaces labeled with 'webhook: enabled' 4 | apiVersion: networking.k8s.io/v1 5 | kind: NetworkPolicy 6 | metadata: 7 | labels: 8 | app.kubernetes.io/name: metal-operator 9 | app.kubernetes.io/managed-by: kustomize 10 | name: allow-webhook-traffic 11 | namespace: system 12 | spec: 13 | podSelector: 14 | matchLabels: 15 | control-plane: controller-manager 16 | policyTypes: 17 | - Ingress 18 | ingress: 19 | # This allows ingress traffic from any namespace with the label webhook: enabled 20 | - from: 21 | - namespaceSelector: 22 | matchLabels: 23 | webhook: enabled # Only from namespaces with this label 24 | ports: 25 | - port: 443 26 | protocol: TCP 27 | -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | 4 | # [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus 5 | # to securely reference certificates created and managed by cert-manager. 6 | # Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml 7 | # to mount the "metrics-server-cert" secret in the Manager Deployment. 8 | patches: 9 | - path: monitor_tls_patch.yaml 10 | target: 11 | kind: ServiceMonitor 12 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | # Prometheus Monitor Service (Metrics) 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | labels: 6 | control-plane: controller-manager 7 | app.kubernetes.io/name: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | name: controller-manager-metrics-monitor 10 | namespace: system 11 | spec: 12 | endpoints: 13 | - path: /metrics 14 | port: https # Ensure this is the name of the port that exposes HTTPS metrics 15 | scheme: https 16 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 17 | tlsConfig: 18 | # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables 19 | # certificate verification, exposing the system to potential man-in-the-middle attacks. 20 | # For production environments, it is recommended to use cert-manager for automatic TLS certificate management. 21 | # To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml, 22 | # which securely references the certificate from the 'metrics-server-cert' secret. 23 | insecureSkipVerify: true 24 | selector: 25 | matchLabels: 26 | control-plane: controller-manager 27 | app.kubernetes.io/name: metal-operator 28 | 29 | -------------------------------------------------------------------------------- /config/prometheus/monitor_tls_patch.yaml: -------------------------------------------------------------------------------- 1 | # Patch for Prometheus ServiceMonitor to enable secure TLS configuration 2 | # using certificates managed by cert-manager 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | name: controller-manager-metrics-monitor 7 | namespace: system 8 | spec: 9 | endpoints: 10 | - tlsConfig: 11 | insecureSkipVerify: false 12 | ca: 13 | secret: 14 | name: metrics-server-cert 15 | key: ca.crt 16 | cert: 17 | secret: 18 | name: metrics-server-cert 19 | key: tls.crt 20 | keySecret: 21 | name: metrics-server-cert 22 | key: tls.key 23 | -------------------------------------------------------------------------------- /config/rbac/biossettings_admin_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants full permissions ('*') over metal.ironcore.dev. 5 | # This role is intended for users authorized to modify roles and bindings within the cluster, 6 | # enabling them to delegate specific permissions to other users or groups as needed. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: clusterrole 13 | app.kubernetes.io/instance: biossettings-admin-role 14 | app.kubernetes.io/component: rbac 15 | app.kubernetes.io/created-by: metal-operator 16 | app.kubernetes.io/part-of: metal-operator 17 | app.kubernetes.io/managed-by: kustomize 18 | name: biossettings-admin-role 19 | rules: 20 | - apiGroups: 21 | - metal.ironcore.dev 22 | resources: 23 | - biossettings 24 | verbs: 25 | - '*' 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - biossettings/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/biossettings_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 5 | # This role is intended for users who need to manage these resources 6 | # but should not control RBAC or manage permissions for others. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: clusterrole 13 | app.kubernetes.io/instance: biossettings-editor-role 14 | app.kubernetes.io/component: rbac 15 | app.kubernetes.io/created-by: metal-operator 16 | app.kubernetes.io/part-of: metal-operator 17 | app.kubernetes.io/managed-by: kustomize 18 | name: biossettings-editor-role 19 | rules: 20 | - apiGroups: 21 | - metal.ironcore.dev 22 | resources: 23 | - biossettings 24 | verbs: 25 | - create 26 | - delete 27 | - get 28 | - list 29 | - patch 30 | - update 31 | - watch 32 | - apiGroups: 33 | - metal.ironcore.dev 34 | resources: 35 | - biossettings/status 36 | verbs: 37 | - get 38 | -------------------------------------------------------------------------------- /config/rbac/biossettings_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants read-only access to metal.ironcore.dev resources. 5 | # This role is intended for users who need visibility into these resources 6 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: clusterrole 13 | app.kubernetes.io/instance: biossettings-viewer-role 14 | app.kubernetes.io/component: rbac 15 | app.kubernetes.io/created-by: metal-operator 16 | app.kubernetes.io/part-of: metal-operator 17 | app.kubernetes.io/managed-by: kustomize 18 | name: biossettings-viewer-role 19 | rules: 20 | - apiGroups: 21 | - metal.ironcore.dev 22 | resources: 23 | - biossettings 24 | verbs: 25 | - get 26 | - list 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - biossettings/status 32 | verbs: 33 | - get 34 | -------------------------------------------------------------------------------- /config/rbac/biosversion_admin_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants full permissions ('*') over metal.ironcore.dev. 5 | # This role is intended for users authorized to modify roles and bindings within the cluster, 6 | # enabling them to delegate specific permissions to other users or groups as needed. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: biosversion-admin-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - '*' 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - biosversions/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/biosversion_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 5 | # This role is intended for users who need to manage these resources 6 | # but should not control RBAC or manage permissions for others. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: biosversion-editor-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - biosversions/status 32 | verbs: 33 | - get 34 | -------------------------------------------------------------------------------- /config/rbac/biosversion_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants read-only access to metal.ironcore.dev resources. 5 | # This role is intended for users who need visibility into these resources 6 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: biosversion-viewer-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | - apiGroups: 25 | - metal.ironcore.dev 26 | resources: 27 | - biosversions/status 28 | verbs: 29 | - get 30 | -------------------------------------------------------------------------------- /config/rbac/bmc_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit bmcs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: bmc-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: bmc-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - bmcs 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - bmcs/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/bmc_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view bmcs. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: bmc-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: bmc-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - bmcs 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - bmcs/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/bmcsecret_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit bmcsecrets. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: bmcsecret-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: bmcsecret-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - bmcsecrets 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - bmcsecrets/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/bmcsecret_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view bmcsecrets. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: bmcsecret-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: bmcsecret-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - bmcsecrets 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - bmcsecrets/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/endpoint_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit endpoints. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: endpoint-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: endpoint-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - endpoints 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - endpoints/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/endpoint_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view endpoints. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: endpoint-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: endpoint-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - endpoints 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - endpoints/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | # All RBAC will be applied under this service account in 3 | # the deployment namespace. You may comment out this resource 4 | # if your manager will use a service account that exists at 5 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 6 | # subjects if changing service account names. 7 | - service_account.yaml 8 | - role.yaml 9 | - role_binding.yaml 10 | - leader_election_role.yaml 11 | - leader_election_role_binding.yaml 12 | # The following RBAC configurations are used to protect 13 | # the metrics endpoint with authn/authz. These configurations 14 | # ensure that only authorized users and service accounts 15 | # can access the metrics endpoint. Comment the following 16 | # permissions if you want to disable this protection. 17 | # More info: https://book.kubebuilder.io/reference/metrics.html 18 | - metrics_auth_role.yaml 19 | - metrics_auth_role_binding.yaml 20 | - metrics_reader_role.yaml 21 | # For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by 22 | # default, aiding admins in cluster management. Those roles are 23 | # not used by the {{ .ProjectName }} itself. You can comment the following lines 24 | # if you do not want those helpers be installed with your Project. 25 | - biosversion_admin_role.yaml 26 | - biosversion_editor_role.yaml 27 | - biosversion_viewer_role.yaml 28 | - servermaintenance_admin_role.yaml 29 | - servermaintenance_editor_role.yaml 30 | - servermaintenance_viewer_role.yaml 31 | 32 | # For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by 33 | # default, aiding admins in cluster management. Those roles are 34 | # not used by the {{ .ProjectName }} itself. You can comment the following lines 35 | # if you do not want those helpers be installed with your Project. 36 | - biossettings_admin_role.yaml 37 | - biossettings_editor_role.yaml 38 | - biossettings_viewer_role.yaml 39 | 40 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: role 7 | app.kubernetes.io/instance: leader-election-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: leader-election-role 13 | rules: 14 | - apiGroups: 15 | - "" 16 | resources: 17 | - configmaps 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - create 23 | - update 24 | - patch 25 | - delete 26 | - apiGroups: 27 | - coordination.k8s.io 28 | resources: 29 | - leases 30 | verbs: 31 | - get 32 | - list 33 | - watch 34 | - create 35 | - update 36 | - patch 37 | - delete 38 | - apiGroups: 39 | - "" 40 | resources: 41 | - events 42 | verbs: 43 | - create 44 | - patch 45 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: rolebinding 6 | app.kubernetes.io/instance: leader-election-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: metal-operator 9 | app.kubernetes.io/part-of: metal-operator 10 | app.kubernetes.io/managed-by: kustomize 11 | name: leader-election-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: Role 15 | name: leader-election-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/metrics_auth_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-auth-role 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /config/rbac/metrics_auth_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics-auth-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics-auth-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/metrics_reader_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: 7 | - "/metrics" 8 | verbs: 9 | - get 10 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: manager-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - secrets 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - batch 21 | resources: 22 | - jobs 23 | verbs: 24 | - create 25 | - delete 26 | - get 27 | - list 28 | - patch 29 | - update 30 | - watch 31 | - apiGroups: 32 | - metal.ironcore.dev 33 | resources: 34 | - biossettings 35 | - biosversions 36 | - bmcs 37 | - bmcsecrets 38 | - endpoints 39 | - serverbootconfigurations 40 | - serverclaims 41 | - serverconfigurations 42 | - servermaintenances 43 | - servers 44 | verbs: 45 | - create 46 | - delete 47 | - get 48 | - list 49 | - patch 50 | - update 51 | - watch 52 | - apiGroups: 53 | - metal.ironcore.dev 54 | resources: 55 | - biossettings/finalizers 56 | - biosversions/finalizers 57 | - bmcs/finalizers 58 | - bmcsecrets/finalizers 59 | - endpoints/finalizers 60 | - serverbootconfigurations/finalizers 61 | - serverclaims/finalizers 62 | - servermaintenances/finalizers 63 | - servers/finalizers 64 | verbs: 65 | - update 66 | - apiGroups: 67 | - metal.ironcore.dev 68 | resources: 69 | - biossettings/status 70 | - biosversions/status 71 | - bmcs/status 72 | - bmcsecrets/status 73 | - endpoints/status 74 | - serverbootconfigurations/status 75 | - serverclaims/status 76 | - servermaintenances/status 77 | - servers/status 78 | verbs: 79 | - get 80 | - patch 81 | - update 82 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: clusterrolebinding 6 | app.kubernetes.io/instance: manager-rolebinding 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: metal-operator 9 | app.kubernetes.io/part-of: metal-operator 10 | app.kubernetes.io/managed-by: kustomize 11 | name: manager-rolebinding 12 | roleRef: 13 | apiGroup: rbac.authorization.k8s.io 14 | kind: ClusterRole 15 | name: manager-role 16 | subjects: 17 | - kind: ServiceAccount 18 | name: controller-manager 19 | namespace: system 20 | -------------------------------------------------------------------------------- /config/rbac/server_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit servers. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: server-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: server-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - servers 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - servers/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/server_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view servers. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: server-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: server-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - servers 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - servers/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/serverbootconfiguration_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit serverbootconfigurations. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: serverbootconfiguration-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: serverbootconfiguration-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - serverbootconfigurations 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - serverbootconfigurations/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/serverbootconfiguration_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view serverbootconfigurations. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: serverbootconfiguration-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: serverbootconfiguration-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - serverbootconfigurations 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - serverbootconfigurations/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/serverclaim_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit serverclaims. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: serverclaim-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: serverclaim-editor-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - serverclaims 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | - apiGroups: 27 | - metal.ironcore.dev 28 | resources: 29 | - serverclaims/status 30 | verbs: 31 | - get 32 | -------------------------------------------------------------------------------- /config/rbac/serverclaim_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view serverclaims. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: serverclaim-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: metal-operator 10 | app.kubernetes.io/part-of: metal-operator 11 | app.kubernetes.io/managed-by: kustomize 12 | name: serverclaim-viewer-role 13 | rules: 14 | - apiGroups: 15 | - metal.ironcore.dev 16 | resources: 17 | - serverclaims 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - serverclaims/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/servermaintenance_admin_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants full permissions ('*') over metal.ironcore.dev. 5 | # This role is intended for users authorized to modify roles and bindings within the cluster, 6 | # enabling them to delegate specific permissions to other users or groups as needed. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: servermaintenance-admin-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - '*' 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - servermaintenances/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/servermaintenance_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 5 | # This role is intended for users who need to manage these resources 6 | # but should not control RBAC or manage permissions for others. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: servermaintenance-editor-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - servermaintenances/status 32 | verbs: 33 | - get 34 | -------------------------------------------------------------------------------- /config/rbac/servermaintenance_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # This rule is not used by the project metal-operator itself. 2 | # It is provided to allow the cluster admin to help manage permissions for users. 3 | # 4 | # Grants read-only access to metal.ironcore.dev resources. 5 | # This role is intended for users who need visibility into these resources 6 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 7 | 8 | apiVersion: rbac.authorization.k8s.io/v1 9 | kind: ClusterRole 10 | metadata: 11 | labels: 12 | app.kubernetes.io/name: metal-operator 13 | app.kubernetes.io/managed-by: kustomize 14 | name: servermaintenance-viewer-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | - apiGroups: 25 | - metal.ironcore.dev 26 | resources: 27 | - servermaintenances/status 28 | verbs: 29 | - get 30 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: serviceaccount 6 | app.kubernetes.io/instance: controller-manager-sa 7 | app.kubernetes.io/component: rbac 8 | app.kubernetes.io/created-by: metal-operator 9 | app.kubernetes.io/part-of: metal-operator 10 | app.kubernetes.io/managed-by: kustomize 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/redfish-mockup/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - redfish_mockup_endpoint.yaml 3 | - redfish_mockup_service.yaml 4 | -------------------------------------------------------------------------------- /config/redfish-mockup/redfish_mockup_endpoint.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: Endpoint 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: endpoint 6 | app.kubernetes.io/instance: endpoint-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: endpoint-sample 11 | spec: 12 | ip: "127.0.0.1" 13 | macAddress: "23:11:8A:33:CF:EA" 14 | -------------------------------------------------------------------------------- /config/redfish-mockup/redfish_mockup_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redfish 5 | namespace: metal-operator-system 6 | spec: 7 | ports: 8 | - port: 8000 9 | targetPort: 8000 10 | selector: 11 | control-plane: controller-manager 12 | -------------------------------------------------------------------------------- /config/samples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | ## Append samples of your project ## 2 | resources: 3 | - metal_v1alpha1_endpoint.yaml 4 | - metal_v1alpha1_bmcsecret.yaml 5 | - metal_v1alpha1_bmc.yaml 6 | - metal_v1alpha1_server.yaml 7 | - metal_v1alpha1_serverbootconfiguration.yaml 8 | - metal_v1alpha1_serverclaim.yaml 9 | - metal_v1alpha1_servermaintenance.yaml 10 | - metal_v1alpha1_biossettings.yaml 11 | - metal_v1alpha1_biosversion.yaml 12 | #+kubebuilder:scaffold:manifestskustomizesamples 13 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_biossettings.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: BIOSSettings 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: metal-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: biossettings-sample 8 | spec: 9 | serverRef: 10 | name: endpoint-sample-system-0 11 | version: 2.10.2 12 | settings: 13 | PxeDev1EnDis: Enabled 14 | serverMaintenancePolicy: OwnerApproval 15 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_biosversion.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: BIOSVersion 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: metal-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: biosversion-sample 8 | spec: 9 | version: "U59 v2.34 (10/04/2024)" 10 | image: 11 | URI: "https://foo-2.34_10_04_2024.signed.flash" 12 | transferProtocol: "HTTPS" 13 | updatePolicy: Normal 14 | serverRef: 15 | name: endpoint-sample-hpe-system-0 16 | serverMaintenancePolicy: OwnerApproval 17 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_bmc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: BMC 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: bmc 6 | app.kubernetes.io/instance: bmc-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: bmc-sample 11 | spec: 12 | endpointRef: 13 | name: endpoint-sample 14 | bmcSecretRef: 15 | name: bmc-sample 16 | protocol: 17 | name: Redfish 18 | port: 8080 19 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_bmcsecret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: BMCSecret 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: bmcsecret 6 | app.kubernetes.io/instance: bmcsecret-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: bmcsecret-sample 11 | stringData: 12 | username: foo 13 | password: bar 14 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_endpoint.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: Endpoint 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: endpoint 6 | app.kubernetes.io/instance: endpoint-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: endpoint-sample 11 | spec: 12 | ip: "127.0.0.1" 13 | macAddress: "23:11:8A:33:CF:EA" 14 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_server.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: Server 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: server 6 | app.kubernetes.io/instance: server-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: server-sample 11 | spec: 12 | uuid: "12345" 13 | bmcRef: 14 | name: sample-bmc 15 | power: Off 16 | indicatorLED: Blinking 17 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_serverbootconfiguration.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: ServerBootConfiguration 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: serverbootconfiguration 6 | app.kubernetes.io/instance: serverbootconfiguration-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: serverbootconfiguration-sample 11 | spec: 12 | serverRef: 13 | name: server-sample 14 | ignitionSecretRef: 15 | name: my-ignition 16 | image: os-image:latest 17 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_serverclaim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: ServerClaim 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: serverclaim 6 | app.kubernetes.io/instance: serverclaim-sample 7 | app.kubernetes.io/part-of: metal-operator 8 | app.kubernetes.io/managed-by: kustomize 9 | app.kubernetes.io/created-by: metal-operator 10 | name: serverclaim-sample 11 | spec: 12 | serverRef: 13 | name: sample-server 14 | # serverSelector: 15 | # matchLabels: 16 | # az: a1 17 | # cpu: 100 18 | # foo: bar 19 | image: os-image:latest 20 | ignitionSecretRef: 21 | name: my-ignition 22 | power: On 23 | -------------------------------------------------------------------------------- /config/samples/metal_v1alpha1_servermaintenance.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: metal.ironcore.dev/v1alpha1 2 | kind: ServerMaintenance 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: metal-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: servermaintenance-sample 8 | spec: 9 | # TODO(user): Add fields here 10 | -------------------------------------------------------------------------------- /config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting nameReference. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | -------------------------------------------------------------------------------- /config/webhook/manifests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | name: validating-webhook-configuration 6 | webhooks: 7 | - admissionReviewVersions: 8 | - v1 9 | clientConfig: 10 | service: 11 | name: webhook-service 12 | namespace: system 13 | path: /validate-metal-ironcore-dev-v1alpha1-biossettings 14 | failurePolicy: Fail 15 | name: vbiossettings-v1alpha1.kb.io 16 | rules: 17 | - apiGroups: 18 | - metal.ironcore.dev 19 | apiVersions: 20 | - v1alpha1 21 | operations: 22 | - CREATE 23 | - UPDATE 24 | resources: 25 | - biossettings 26 | sideEffects: None 27 | - admissionReviewVersions: 28 | - v1 29 | clientConfig: 30 | service: 31 | name: webhook-service 32 | namespace: system 33 | path: /validate-metal-ironcore-dev-v1alpha1-biosversion 34 | failurePolicy: Fail 35 | name: vbiosversion-v1alpha1.kb.io 36 | rules: 37 | - apiGroups: 38 | - metal.ironcore.dev 39 | apiVersions: 40 | - v1alpha1 41 | operations: 42 | - CREATE 43 | - UPDATE 44 | - DELETE 45 | resources: 46 | - biosversions 47 | sideEffects: None 48 | - admissionReviewVersions: 49 | - v1 50 | clientConfig: 51 | service: 52 | name: webhook-service 53 | namespace: system 54 | path: /validate-metal-ironcore-dev-v1alpha1-endpoint 55 | failurePolicy: Fail 56 | name: vendpoint-v1alpha1.kb.io 57 | rules: 58 | - apiGroups: 59 | - metal.ironcore.dev 60 | apiVersions: 61 | - v1alpha1 62 | operations: 63 | - CREATE 64 | - UPDATE 65 | resources: 66 | - endpoints 67 | sideEffects: None 68 | -------------------------------------------------------------------------------- /config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app.kubernetes.io/name: metal-operator 6 | app.kubernetes.io/managed-by: kustomize 7 | name: webhook-service 8 | namespace: system 9 | spec: 10 | ports: 11 | - port: 443 12 | protocol: TCP 13 | targetPort: 9443 14 | selector: 15 | control-plane: controller-manager 16 | app.kubernetes.io/name: metal-operator 17 | -------------------------------------------------------------------------------- /dist/chart/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building Helm packages. 2 | # Operating system files 3 | .DS_Store 4 | 5 | # Version control directories 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .hg/ 10 | .hgignore 11 | .svn/ 12 | 13 | # Backup and temporary files 14 | *.swp 15 | *.tmp 16 | *.bak 17 | *.orig 18 | *~ 19 | 20 | # IDE and editor-related files 21 | .idea/ 22 | .vscode/ 23 | 24 | # Helm chart artifacts 25 | dist/chart/*.tgz 26 | -------------------------------------------------------------------------------- /dist/chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: metal-operator 3 | description: A Helm chart to distribute the project metal-operator 4 | type: application 5 | version: 0.1.0 6 | appVersion: "0.1.0" 7 | icon: "https://example.com/icon.png" 8 | -------------------------------------------------------------------------------- /dist/chart/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{- define "chart.name" -}} 2 | {{- if .Chart }} 3 | {{- if .Chart.Name }} 4 | {{- .Chart.Name | trunc 63 | trimSuffix "-" }} 5 | {{- else if .Values.nameOverride }} 6 | {{ .Values.nameOverride | trunc 63 | trimSuffix "-" }} 7 | {{- else }} 8 | metal-operator 9 | {{- end }} 10 | {{- else }} 11 | metal-operator 12 | {{- end }} 13 | {{- end }} 14 | 15 | 16 | {{- define "chart.labels" -}} 17 | {{- if .Chart.Version -}} 18 | helm.sh/chart: {{ .Chart.Version | quote }} 19 | {{- end }} 20 | app.kubernetes.io/name: {{ include "chart.name" . }} 21 | app.kubernetes.io/instance: {{ .Release.Name }} 22 | {{- if .Chart.AppVersion }} 23 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 24 | {{- end }} 25 | app.kubernetes.io/managed-by: {{ .Release.Service }} 26 | {{- end }} 27 | 28 | 29 | {{- define "chart.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "chart.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | 35 | {{- define "chart.hasMutatingWebhooks" -}} 36 | {{- $hasMutating := false }} 37 | {{- range . }} 38 | {{- if eq .type "mutating" }} 39 | $hasMutating = true }}{{- end }} 40 | {{- end }} 41 | {{ $hasMutating }}}}{{- end }} 42 | 43 | 44 | {{- define "chart.hasValidatingWebhooks" -}} 45 | {{- $hasValidating := false }} 46 | {{- range . }} 47 | {{- if eq .type "validating" }} 48 | $hasValidating = true }}{{- end }} 49 | {{- end }} 50 | {{ $hasValidating }}}}{{- end }} 51 | -------------------------------------------------------------------------------- /dist/chart/templates/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.certmanager.enable }} 2 | # Self-signed Issuer 3 | apiVersion: cert-manager.io/v1 4 | kind: Issuer 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: selfsigned-issuer 9 | namespace: {{ .Release.Namespace }} 10 | spec: 11 | selfSigned: {} 12 | {{- if .Values.webhook.enable }} 13 | --- 14 | # Certificate for the webhook 15 | apiVersion: cert-manager.io/v1 16 | kind: Certificate 17 | metadata: 18 | annotations: 19 | {{- if .Values.crd.keep }} 20 | "helm.sh/resource-policy": keep 21 | {{- end }} 22 | name: serving-cert 23 | namespace: {{ .Release.Namespace }} 24 | labels: 25 | {{- include "chart.labels" . | nindent 4 }} 26 | spec: 27 | dnsNames: 28 | - metal-operator.{{ .Release.Namespace }}.svc 29 | - metal-operator.{{ .Release.Namespace }}.svc.cluster.local 30 | - metal-operator-webhook-service.{{ .Release.Namespace }}.svc 31 | issuerRef: 32 | kind: Issuer 33 | name: selfsigned-issuer 34 | secretName: webhook-server-cert 35 | {{- end }} 36 | {{- if .Values.metrics.enable }} 37 | --- 38 | # Certificate for the metrics 39 | apiVersion: cert-manager.io/v1 40 | kind: Certificate 41 | metadata: 42 | annotations: 43 | {{- if .Values.crd.keep }} 44 | "helm.sh/resource-policy": keep 45 | {{- end }} 46 | labels: 47 | {{- include "chart.labels" . | nindent 4 }} 48 | name: metrics-certs 49 | namespace: {{ .Release.Namespace }} 50 | spec: 51 | dnsNames: 52 | - metal-operator.{{ .Release.Namespace }}.svc 53 | - metal-operator.{{ .Release.Namespace }}.svc.cluster.local 54 | - metal-operator-metrics-service.{{ .Release.Namespace }}.svc 55 | issuerRef: 56 | kind: Issuer 57 | name: selfsigned-issuer 58 | secretName: metrics-server-cert 59 | {{- end }} 60 | {{- end }} 61 | -------------------------------------------------------------------------------- /dist/chart/templates/crd/metal.ironcore.dev_endpoints.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.crd.enable }} 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | annotations: 9 | {{- if .Values.crd.keep }} 10 | "helm.sh/resource-policy": keep 11 | {{- end }} 12 | controller-gen.kubebuilder.io/version: v0.18.0 13 | name: endpoints.metal.ironcore.dev 14 | spec: 15 | group: metal.ironcore.dev 16 | names: 17 | kind: Endpoint 18 | listKind: EndpointList 19 | plural: endpoints 20 | singular: endpoint 21 | scope: Cluster 22 | versions: 23 | - additionalPrinterColumns: 24 | - jsonPath: .spec.macAddress 25 | name: MACAddress 26 | type: string 27 | - jsonPath: .spec.ip 28 | name: IP 29 | type: string 30 | - jsonPath: .metadata.creationTimestamp 31 | name: Age 32 | type: date 33 | name: v1alpha1 34 | schema: 35 | openAPIV3Schema: 36 | description: Endpoint is the Schema for the endpoints 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: EndpointSpec defines the desired state of Endpoint 57 | properties: 58 | ip: 59 | description: IP is the IP address of the endpoint. 60 | type: string 61 | macAddress: 62 | description: MACAddress is the MAC address of the endpoint. 63 | type: string 64 | required: 65 | - ip 66 | - macAddress 67 | type: object 68 | status: 69 | description: EndpointStatus defines the observed state of Endpoint 70 | type: object 71 | type: object 72 | served: true 73 | storage: true 74 | subresources: 75 | status: {} 76 | {{- end -}} 77 | -------------------------------------------------------------------------------- /dist/chart/templates/metrics/metrics-service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.metrics.enable }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: metal-operator-controller-manager-metrics-service 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | {{- include "chart.labels" . | nindent 4 }} 9 | spec: 10 | ports: 11 | - port: 8443 12 | targetPort: 8443 13 | protocol: TCP 14 | name: https 15 | selector: 16 | control-plane: controller-manager 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /dist/chart/templates/network-policy/allow-webhook-traffic.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.networkPolicy.enable }} 2 | # This NetworkPolicy allows ingress traffic to your webhook server running 3 | # as part of the controller-manager from specific namespaces and pods. CR(s) which uses webhooks 4 | # will only work when applied in namespaces labeled with 'webhook: enabled' 5 | apiVersion: networking.k8s.io/v1 6 | kind: NetworkPolicy 7 | metadata: 8 | labels: 9 | {{- include "chart.labels" . | nindent 4 }} 10 | name: allow-webhook-traffic 11 | namespace: {{ .Release.Namespace }} 12 | spec: 13 | podSelector: 14 | matchLabels: 15 | control-plane: controller-manager 16 | policyTypes: 17 | - Ingress 18 | ingress: 19 | # This allows ingress traffic from any namespace with the label webhook: enabled 20 | - from: 21 | - namespaceSelector: 22 | matchLabels: 23 | webhook: enabled # Only from namespaces with this label 24 | ports: 25 | - port: 443 26 | protocol: TCP 27 | {{- end -}} 28 | -------------------------------------------------------------------------------- /dist/chart/templates/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | # To integrate with Prometheus. 2 | {{- if .Values.prometheus.enable }} 3 | apiVersion: monitoring.coreos.com/v1 4 | kind: ServiceMonitor 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: metal-operator-controller-manager-metrics-monitor 9 | namespace: {{ .Release.Namespace }} 10 | spec: 11 | endpoints: 12 | - path: /metrics 13 | port: https 14 | scheme: https 15 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 16 | tlsConfig: 17 | {{- if .Values.certmanager.enable }} 18 | serverName: metal-operator-controller-manager-metrics-service.{{ .Release.Namespace }}.svc 19 | # Apply secure TLS configuration with cert-manager 20 | insecureSkipVerify: false 21 | ca: 22 | secret: 23 | name: metrics-server-cert 24 | key: ca.crt 25 | cert: 26 | secret: 27 | name: metrics-server-cert 28 | key: tls.crt 29 | keySecret: 30 | name: metrics-server-cert 31 | key: tls.key 32 | {{- else }} 33 | # Development/Test mode (insecure configuration) 34 | insecureSkipVerify: true 35 | {{- end }} 36 | selector: 37 | matchLabels: 38 | control-plane: controller-manager 39 | {{- end }} 40 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biossettings_admin_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants full permissions ('*') over metal.ironcore.dev. 6 | # This role is intended for users authorized to modify roles and bindings within the cluster, 7 | # enabling them to delegate specific permissions to other users or groups as needed. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biossettings-admin-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biossettings 20 | verbs: 21 | - '*' 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - biossettings/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biossettings_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 6 | # This role is intended for users who need to manage these resources 7 | # but should not control RBAC or manage permissions for others. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biossettings-editor-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biossettings 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - biossettings/status 32 | verbs: 33 | - get 34 | {{- end -}} 35 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biossettings_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants read-only access to metal.ironcore.dev resources. 6 | # This role is intended for users who need visibility into these resources 7 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biossettings-viewer-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biossettings 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | - apiGroups: 25 | - metal.ironcore.dev 26 | resources: 27 | - biossettings/status 28 | verbs: 29 | - get 30 | {{- end -}} 31 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biosversion_admin_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants full permissions ('*') over metal.ironcore.dev. 6 | # This role is intended for users authorized to modify roles and bindings within the cluster, 7 | # enabling them to delegate specific permissions to other users or groups as needed. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biosversion-admin-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - '*' 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - biosversions/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biosversion_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 6 | # This role is intended for users who need to manage these resources 7 | # but should not control RBAC or manage permissions for others. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biosversion-editor-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - biosversions/status 32 | verbs: 33 | - get 34 | {{- end -}} 35 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/biosversion_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants read-only access to metal.ironcore.dev resources. 6 | # This role is intended for users who need visibility into these resources 7 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: biosversion-viewer-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - biosversions 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | - apiGroups: 25 | - metal.ironcore.dev 26 | resources: 27 | - biosversions/status 28 | verbs: 29 | - get 30 | {{- end -}} 31 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/bmc_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit bmcs. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: bmc-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - bmcs 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - bmcs/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/bmc_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view bmcs. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: bmc-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - bmcs 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - bmcs/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/bmcsecret_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit bmcsecrets. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: bmcsecret-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - bmcsecrets 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - bmcsecrets/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/bmcsecret_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view bmcsecrets. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: bmcsecret-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - bmcsecrets 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - bmcsecrets/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/endpoint_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit endpoints. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: endpoint-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - endpoints 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - endpoints/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/endpoint_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view endpoints. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: endpoint-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - endpoints 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - endpoints/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions to do leader election. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: Role 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | namespace: {{ .Release.Namespace }} 9 | name: metal-operator-leader-election-role 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - configmaps 15 | verbs: 16 | - get 17 | - list 18 | - watch 19 | - create 20 | - update 21 | - patch 22 | - delete 23 | - apiGroups: 24 | - coordination.k8s.io 25 | resources: 26 | - leases 27 | verbs: 28 | - get 29 | - list 30 | - watch 31 | - create 32 | - update 33 | - patch 34 | - delete 35 | - apiGroups: 36 | - "" 37 | resources: 38 | - events 39 | verbs: 40 | - create 41 | - patch 42 | {{- end -}} 43 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: RoleBinding 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | namespace: {{ .Release.Namespace }} 8 | name: metal-operator-leader-election-rolebinding 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: Role 12 | name: metal-operator-leader-election-role 13 | subjects: 14 | - kind: ServiceAccount 15 | name: {{ .Values.controllerManager.serviceAccountName }} 16 | namespace: {{ .Release.Namespace }} 17 | {{- end -}} 18 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/metrics_auth_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.rbac.enable .Values.metrics.enable }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | name: metal-operator-metrics-auth-role 8 | rules: 9 | - apiGroups: 10 | - authentication.k8s.io 11 | resources: 12 | - tokenreviews 13 | verbs: 14 | - create 15 | - apiGroups: 16 | - authorization.k8s.io 17 | resources: 18 | - subjectaccessreviews 19 | verbs: 20 | - create 21 | {{- end -}} 22 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/metrics_auth_role_binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.rbac.enable .Values.metrics.enable }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | name: metal-operator-metrics-auth-rolebinding 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: metal-operator-metrics-auth-role 12 | subjects: 13 | - kind: ServiceAccount 14 | name: {{ .Values.controllerManager.serviceAccountName }} 15 | namespace: {{ .Release.Namespace }} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/metrics_reader_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.rbac.enable .Values.metrics.enable }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | name: metal-operator-metrics-reader 8 | rules: 9 | - nonResourceURLs: 10 | - "/metrics" 11 | verbs: 12 | - get 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: metal-operator-manager-role 9 | rules: 10 | - apiGroups: 11 | - "" 12 | resources: 13 | - secrets 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - batch 24 | resources: 25 | - jobs 26 | verbs: 27 | - create 28 | - delete 29 | - get 30 | - list 31 | - patch 32 | - update 33 | - watch 34 | - apiGroups: 35 | - metal.ironcore.dev 36 | resources: 37 | - biossettings 38 | - biosversions 39 | - bmcs 40 | - bmcsecrets 41 | - endpoints 42 | - serverbootconfigurations 43 | - serverclaims 44 | - serverconfigurations 45 | - servermaintenances 46 | - servers 47 | verbs: 48 | - create 49 | - delete 50 | - get 51 | - list 52 | - patch 53 | - update 54 | - watch 55 | - apiGroups: 56 | - metal.ironcore.dev 57 | resources: 58 | - biossettings/finalizers 59 | - biosversions/finalizers 60 | - bmcs/finalizers 61 | - bmcsecrets/finalizers 62 | - endpoints/finalizers 63 | - serverbootconfigurations/finalizers 64 | - serverclaims/finalizers 65 | - servermaintenances/finalizers 66 | - servers/finalizers 67 | verbs: 68 | - update 69 | - apiGroups: 70 | - metal.ironcore.dev 71 | resources: 72 | - biossettings/status 73 | - biosversions/status 74 | - bmcs/status 75 | - bmcsecrets/status 76 | - endpoints/status 77 | - serverbootconfigurations/status 78 | - serverclaims/status 79 | - servermaintenances/status 80 | - servers/status 81 | verbs: 82 | - get 83 | - patch 84 | - update 85 | {{- end -}} 86 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | name: metal-operator-manager-rolebinding 8 | roleRef: 9 | apiGroup: rbac.authorization.k8s.io 10 | kind: ClusterRole 11 | name: metal-operator-manager-role 12 | subjects: 13 | - kind: ServiceAccount 14 | name: {{ .Values.controllerManager.serviceAccountName }} 15 | namespace: {{ .Release.Namespace }} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/server_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit servers. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: server-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - servers 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - servers/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/server_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view servers. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: server-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - servers 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - servers/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/serverbootconfiguration_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit serverbootconfigurations. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: serverbootconfiguration-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - serverbootconfigurations 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - serverbootconfigurations/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/serverbootconfiguration_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view serverbootconfigurations. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: serverbootconfiguration-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - serverbootconfigurations 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - serverbootconfigurations/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/serverclaim_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to edit serverclaims. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: serverclaim-editor-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - serverclaims 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - serverclaims/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/serverclaim_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # permissions for end users to view serverclaims. 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | labels: 7 | {{- include "chart.labels" . | nindent 4 }} 8 | name: serverclaim-viewer-role 9 | rules: 10 | - apiGroups: 11 | - metal.ironcore.dev 12 | resources: 13 | - serverclaims 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - metal.ironcore.dev 20 | resources: 21 | - serverclaims/status 22 | verbs: 23 | - get 24 | {{- end -}} 25 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/servermaintenance_admin_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants full permissions ('*') over metal.ironcore.dev. 6 | # This role is intended for users authorized to modify roles and bindings within the cluster, 7 | # enabling them to delegate specific permissions to other users or groups as needed. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: servermaintenance-admin-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - '*' 22 | - apiGroups: 23 | - metal.ironcore.dev 24 | resources: 25 | - servermaintenances/status 26 | verbs: 27 | - get 28 | {{- end -}} 29 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/servermaintenance_editor_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants permissions to create, update, and delete resources within the metal.ironcore.dev. 6 | # This role is intended for users who need to manage these resources 7 | # but should not control RBAC or manage permissions for others. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: servermaintenance-editor-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - create 22 | - delete 23 | - get 24 | - list 25 | - patch 26 | - update 27 | - watch 28 | - apiGroups: 29 | - metal.ironcore.dev 30 | resources: 31 | - servermaintenances/status 32 | verbs: 33 | - get 34 | {{- end -}} 35 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/servermaintenance_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | # This rule is not used by the project metal-operator itself. 3 | # It is provided to allow the cluster admin to help manage permissions for users. 4 | # 5 | # Grants read-only access to metal.ironcore.dev resources. 6 | # This role is intended for users who need visibility into these resources 7 | # without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. 8 | 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRole 11 | metadata: 12 | labels: 13 | {{- include "chart.labels" . | nindent 4 }} 14 | name: servermaintenance-viewer-role 15 | rules: 16 | - apiGroups: 17 | - metal.ironcore.dev 18 | resources: 19 | - servermaintenances 20 | verbs: 21 | - get 22 | - list 23 | - watch 24 | - apiGroups: 25 | - metal.ironcore.dev 26 | resources: 27 | - servermaintenances/status 28 | verbs: 29 | - get 30 | {{- end -}} 31 | -------------------------------------------------------------------------------- /dist/chart/templates/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.enable }} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | labels: 6 | {{- include "chart.labels" . | nindent 4 }} 7 | {{- if and .Values.controllerManager.serviceAccount .Values.controllerManager.serviceAccount.annotations }} 8 | annotations: 9 | {{- range $key, $value := .Values.controllerManager.serviceAccount.annotations }} 10 | {{ $key }}: {{ $value }} 11 | {{- end }} 12 | {{- end }} 13 | name: {{ .Values.controllerManager.serviceAccountName }} 14 | namespace: {{ .Release.Namespace }} 15 | {{- end -}} 16 | -------------------------------------------------------------------------------- /dist/chart/templates/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.webhook.enable }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: metal-operator-webhook-service 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | {{- include "chart.labels" . | nindent 4 }} 9 | spec: 10 | ports: 11 | - port: 443 12 | protocol: TCP 13 | targetPort: 9443 14 | selector: 15 | control-plane: controller-manager 16 | {{- end }} 17 | -------------------------------------------------------------------------------- /dist/chart/templates/webhook/webhooks.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.webhook.enable }} 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: ValidatingWebhookConfiguration 4 | metadata: 5 | name: metal-operator-validating-webhook-configuration 6 | namespace: {{ .Release.Namespace }} 7 | annotations: 8 | {{- if .Values.certmanager.enable }} 9 | cert-manager.io/inject-ca-from: "{{ $.Release.Namespace }}/serving-cert" 10 | {{- end }} 11 | labels: 12 | {{- include "chart.labels" . | nindent 4 }} 13 | webhooks: 14 | - name: vbiossettings-v1alpha1.kb.io 15 | clientConfig: 16 | service: 17 | name: metal-operator-webhook-service 18 | namespace: {{ .Release.Namespace }} 19 | path: /validate-metal-ironcore-dev-v1alpha1-biossettings 20 | failurePolicy: Fail 21 | sideEffects: None 22 | admissionReviewVersions: 23 | - v1 24 | rules: 25 | - operations: 26 | - CREATE 27 | - UPDATE 28 | apiGroups: 29 | - metal.ironcore.dev 30 | apiVersions: 31 | - v1alpha1 32 | resources: 33 | - biossettings 34 | - name: vbiosversion-v1alpha1.kb.io 35 | clientConfig: 36 | service: 37 | name: metal-operator-webhook-service 38 | namespace: {{ .Release.Namespace }} 39 | path: /validate-metal-ironcore-dev-v1alpha1-biosversion 40 | failurePolicy: Fail 41 | sideEffects: None 42 | admissionReviewVersions: 43 | - v1 44 | rules: 45 | - operations: 46 | - CREATE 47 | - UPDATE 48 | - DELETE 49 | apiGroups: 50 | - metal.ironcore.dev 51 | apiVersions: 52 | - v1alpha1 53 | resources: 54 | - biosversions 55 | - name: vendpoint-v1alpha1.kb.io 56 | clientConfig: 57 | service: 58 | name: metal-operator-webhook-service 59 | namespace: {{ .Release.Namespace }} 60 | path: /validate-metal-ironcore-dev-v1alpha1-endpoint 61 | failurePolicy: Fail 62 | sideEffects: None 63 | admissionReviewVersions: 64 | - v1 65 | rules: 66 | - operations: 67 | - CREATE 68 | - UPDATE 69 | apiGroups: 70 | - metal.ironcore.dev 71 | apiVersions: 72 | - v1alpha1 73 | resources: 74 | - endpoints 75 | {{- end }} 76 | -------------------------------------------------------------------------------- /dist/chart/values.yaml: -------------------------------------------------------------------------------- 1 | # [MANAGER]: Manager Deployment Configurations 2 | controllerManager: 3 | replicas: 1 4 | strategy: 5 | type: Recreate 6 | manager: 7 | image: 8 | repository: controller 9 | tag: latest 10 | args: 11 | - "--leader-elect" 12 | - "--metrics-bind-address=:8443" 13 | - "--health-probe-bind-address=:8081" 14 | resources: 15 | limits: 16 | cpu: 300m 17 | memory: 200Mi 18 | requests: 19 | cpu: 300m 20 | memory: 50Mi 21 | livenessProbe: 22 | initialDelaySeconds: 15 23 | periodSeconds: 20 24 | httpGet: 25 | path: /healthz 26 | port: 8081 27 | readinessProbe: 28 | initialDelaySeconds: 5 29 | periodSeconds: 10 30 | httpGet: 31 | path: /readyz 32 | port: 8081 33 | securityContext: 34 | allowPrivilegeEscalation: false 35 | capabilities: 36 | drop: 37 | - "ALL" 38 | podSecurityContext: 39 | runAsNonRoot: true 40 | seccompProfile: 41 | type: RuntimeDefault 42 | terminationGracePeriodSeconds: 10 43 | serviceAccountName: metal-operator-controller-manager 44 | hostNetwork: true 45 | 46 | # [RBAC]: To enable RBAC (Permissions) configurations 47 | rbac: 48 | enable: true 49 | 50 | # [CRDs]: To enable the CRDs 51 | crd: 52 | # This option determines whether the CRDs are included 53 | # in the installation process. 54 | enable: true 55 | 56 | # Enabling this option adds the "helm.sh/resource-policy": keep 57 | # annotation to the CRD, ensuring it remains installed even when 58 | # the Helm release is uninstalled. 59 | # NOTE: Removing the CRDs will also remove all cert-manager CR(s) 60 | # (Certificates, Issuers, ...) due to garbage collection. 61 | keep: true 62 | 63 | # [METRICS]: Set to true to generate manifests for exporting metrics. 64 | # To disable metrics export set false, and ensure that the 65 | # ControllerManager argument "--metrics-bind-address=:8443" is removed. 66 | metrics: 67 | enable: true 68 | 69 | # [WEBHOOKS]: Webhooks configuration 70 | # The following configuration is automatically generated from the manifests 71 | # generated by controller-gen. To update run 'make manifests' and 72 | # the edit command with the '--force' flag 73 | webhook: 74 | enable: true 75 | 76 | # [PROMETHEUS]: To enable a ServiceMonitor to export metrics to Prometheus set true 77 | prometheus: 78 | enable: false 79 | 80 | # [CERT-MANAGER]: To enable cert-manager injection to webhooks set true 81 | certmanager: 82 | enable: true 83 | 84 | # [NETWORK POLICIES]: To enable NetworkPolicies set true 85 | networkPolicy: 86 | enable: false 87 | -------------------------------------------------------------------------------- /docs/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM squidfunk/mkdocs-material:latest 2 | 3 | LABEL project=metal_operator 4 | 5 | WORKDIR /docs 6 | 7 | COPY docs/requirements.txt requirements.txt 8 | RUN pip install --no-cache-dir -r requirements.txt 9 | 10 | EXPOSE 9000 11 | 12 | # Start development server by default 13 | ENTRYPOINT ["mkdocs"] 14 | CMD ["serve", "--dev-addr=0.0.0.0:9000"] 15 | -------------------------------------------------------------------------------- /docs/concepts/biossettings.md: -------------------------------------------------------------------------------- 1 | # BIOSSettings 2 | 3 | `BIOSSettings` represents a BIOS Setting update operation for a physical server (compute system). It updates the bios settings on physical server's BIOS. 4 | 5 | ## Key Points 6 | 7 | - `BIOSSettings` maps a BIOS version and settings as map for a given server. 8 | - Only one `BIOSSettings` can be active per `Server` at a time. 9 | - `BIOSSettings` related changes are applied once the bios version matches with the physical server's bios. 10 | - `BIOSSettings` handles reboots of server (if required) using `ServerMaintenance` resource 11 | - Once`BIOSSettings` moves to `Failed` state, It stays in this state unless Manually moved out of this state. 12 | 13 | ## Workflow 14 | 15 | 1. A separate operator (e.g., `biosSettingsSet`) or user creates a `BIOSSettings` resource referencing a 16 | specific `Server`. 17 | 2. Provided settings are checked against the current BIOS setting. 18 | 3. If settings are same as on the server, the state is moved to `Applied` (even if the version does not match) 19 | 4. If the settings needs update, `BIOSSettings` check the version of BIOS and if required version does not match, it waits for the bios version to reach the spec version. 20 | 5. `BIOSSettings` checks if the required setting update needs physical server reboot. 21 | 6. If reboot is needed and `ServerMaintenance` is not provided already. it requests for one and waits for the `server` to enter `Maintenance` state. 22 | - `policy` used by `ServerMaintenance` is to be provided through Spec `ServerMaintenancePolicyType` in `BIOSSettings` 23 | 7. Setting update process is started and the server is rebooted if required. 24 | 8. `BIOSSettings` verfiy the setting has been applied and trasistions the state to `Applied`. removes the `ServerMaintenance` resource if created by self. 25 | 9. Any further update to the `BIOSSettings` Spec will restart the process. 26 | 10. If the `BIOSSettings` fails to apply the bios setting. The `BIOSSettings` moves to `Failed` state until Manually moved out of this state. 27 | 28 | ## Example 29 | 30 | ```yaml 31 | apiVersion: metal.ironcore.dev/v1alpha1 32 | kind: BIOSSettings 33 | metadata: 34 | name: biossettings-sample 35 | spec: 36 | serverRef: 37 | name: endpoint-sample-system-0 38 | version: 2.10.3 39 | settings: 40 | PxeDev1EnDis: Disable 41 | PxeDev2EnDis: Enabled 42 | OtherSettings: "123" 43 | someother: Disabled 44 | ServerMaintenancePolicy: OwnerApproval 45 | 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/concepts/biosversion.md: -------------------------------------------------------------------------------- 1 | # BIOSVersion 2 | 3 | `BIOSVersion` represents a BIOS Version upgrade operation for a physical server (compute system). It updates the bios Version on physical server's BIOS. 4 | 5 | ## Key Points 6 | 7 | - `BIOSVersion` maps a BIOS version required for a given server's BIOS. 8 | - `BIOSVersion` Spec contains the required details to upgrade the BIOS to required version. 9 | - Only one `BIOSVersion` can be active per `Server` at a time. 10 | - `BIOSVersion` starts the version upgrade of the BIOS using redfish `SimpleUpgrade` API. 11 | - `BIOSVersion` handles reboots of server using `ServerMaintenance` resource. 12 | - Once`BIOSVersion` moves to `Failed` state, It stays in this state unless Manually moved out of this state. 13 | 14 | ## Workflow 15 | 16 | 1. A separate operator (e.g., `biosVersionSet`) or user creates a `BIOSVersion` resource referencing a 17 | specific `Server`. 18 | 2. Provided BIOS Version is checked against the current BIOS version. 19 | 3. If version is same as on the server's BIOS, the state is moved to `Completed`. 20 | 4. If `ServerMaintenance` is not provided already. it requests for one and waits for the `server` to enter `Maintenance` state. 21 | - `policy` used by `ServerMaintenance` is to be provided through Spec `ServerMaintenancePolicy` in `BIOSVersion` 22 | 5. `BIOSVersion` issues the bios upgrade using redfish `SimpleUpgrade` API. and monitors the `upgrade task` created by the API. 23 | 6. the `BIOSVersion` moves to `Failed` state: 24 | - If `SimpleUpgade` is issued but unable to get the task to monitor the progress of bios upgrade 25 | - If the `upgrade task` created by SimpleUpgade fails and does not reach completed state. 26 | - If the bios version requested is lower than that of the current bios version 27 | 7. `BIOSVersion` moves to reboot the server once the `upgrade task` has been completed. 28 | 8. `BIOSVersion` verfiy the bios version post reboot, removes the `ServerMaintenance` resource if created by self. and transistion to `Completed` state 29 | 9. Any further update to the `BIOSVersion` Spec will restart the process. 30 | 31 | ## Example 32 | 33 | ```yaml 34 | apiVersion: metal.ironcore.dev/v1alpha1 35 | kind: BIOSVersion 36 | metadata: 37 | name: biosversion-sample 38 | spec: 39 | version: "U59 v2.34 (10/04/2024)" 40 | image: 41 | URI: "https://foo-2.34_10_04_2024.signed.flash" 42 | transferProtocol: "HTTPS" 43 | updatePolicy: Normal 44 | serverRef: 45 | name: endpoint-sample-hpe-system-0 46 | serverMaintenancePolicy: OwnerApproval 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/concepts/bmcs.md: -------------------------------------------------------------------------------- 1 | # BMCs 2 | 3 | The BMC Custom Resource Definition (CRD) represents a Baseboard Management Controller. 4 | It is designed to manage and monitor the state of BMC devices and the systems (servers) they control. The primary 5 | purpose of the BMC resource is to reconcile the BMC state and detect all systems it manages by creating the 6 | corresponding [`Server`](servers.md) resources. 7 | 8 | ## Example BMC Resource 9 | 10 | Using `endpointRef`: 11 | 12 | ```yaml 13 | apiVersion: metal.ironcore.dev/v1alpha1 14 | kind: BMC 15 | metadata: 16 | name: my-bmc 17 | spec: 18 | endpointRef: 19 | name: my-bmc-endpoint 20 | bmcSecretRef: 21 | name: my-bmc-secret 22 | protocol: 23 | name: Redfish 24 | port: 8000 25 | scheme: http 26 | consoleProtocol: 27 | name: SSH 28 | port: 22 29 | ``` 30 | 31 | Using inline `endpoint`: 32 | 33 | ```yaml 34 | apiVersion: metal.ironcore.dev/v1alpha1 35 | kind: BMC 36 | metadata: 37 | name: my-bmc-inline 38 | spec: 39 | access: 40 | macAddress: "00:1A:2B:3C:4D:5E" 41 | ip: "192.168.100.10" 42 | bmcSecretRef: 43 | name: my-bmc-secret 44 | protocol: 45 | name: Redfish 46 | port: 8000 47 | consoleProtocol: 48 | name: SSH 49 | port: 22 50 | ``` 51 | 52 | ## Usage 53 | 54 | The BMC CRD is essential for managing and monitoring BMC devices. It is used to: 55 | 56 | - **Reconcile BMC State**: Continuously monitor the BMC's status and update its state. 57 | - **Detect Managed Systems**: Identify all systems (servers) managed by the BMC and create corresponding [`Server`](servers.md) resources. 58 | - **Automate Hardware Management**: Enable automated power control, firmware updates, and health monitoring of physical servers through the BMC. 59 | 60 | ## Reconciliation Process 61 | 62 | The `BMCReconciler` is a controller that processes BMC resources to: 63 | 64 | 1. **Access BMC Device**: Uses the `endpointRef` or `endpoint`, along with `bmcSecretRef`, to establish a connection 65 | with the BMC using the specified `protocol`. 66 | 67 | 2. **Retrieve BMC Information**: Gathers details such as manufacturer, model, serial number, firmware version, and 68 | power state. 69 | 70 | 3. **Update BMCStatus**: Populates the `status` field of the BMC resource with the retrieved information. 71 | 72 | 4. **Detect Managed Systems**: Identifies all systems (servers) that the BMC manages. 73 | 74 | 5. **Create Server Resources**: For each detected system, the `BMCReconciler` creates a corresponding [`Server`](servers.md) 75 | resource to represent the physical server. 76 | -------------------------------------------------------------------------------- /docs/concepts/bmcsecrets.md: -------------------------------------------------------------------------------- 1 | # BMCSecrets 2 | 3 | The `BMCSecret` Custom Resource Definition (CRD) is a Kubernetes resource used to store sensitive credentials required 4 | to access a Baseboard Management Controller (BMC). This resource holds the `username` and `password` needed for 5 | authentication with the BMC devices. The `BMCSecret` is utilized by the `BMCReconciler` to construct clients that 6 | interact with BMCs. 7 | 8 | ## Example BMCSecret Resource 9 | 10 | An example of how to define an `BMCSecret` resource: 11 | 12 | ```yaml 13 | apiVersion: v1alpha1 14 | kind: BMCSecret 15 | metadata: 16 | name: my-bmc-secret 17 | stringData: 18 | username: admin 19 | password: supersecretpassword 20 | type: Opaque 21 | ``` 22 | 23 | ## Usage 24 | 25 | The `BMCSecret` resource is essential for securely managing credentials required to access BMC devices. It is used by 26 | the `BMCReconciler` to: 27 | 28 | - **Construct BMC Clients**: Utilize the credentials to authenticate and establish connections with BMC devices. 29 | - **Automate Hardware Management**: Enable automated operations such as power control, firmware updates, and 30 | health monitoring by authenticating with the BMC. 31 | 32 | ## Credential Sources 33 | 34 | - **Endpoint-Based Discovery**: When BMCs are discovered through an [`Endpoint`](endpoints.md) resource and a MAC Prefix Database, 35 | the credentials (`username` and `password`) are derived automatically based on the MAC address prefixes. 36 | - **Manual Configuration**: Users can manually create BMCSecret resources with the required credentials to interact with specific BMCs. 37 | 38 | ## Reconciliation Process 39 | 40 | The `BMCReconciler` uses the `bmcSecretRef` field in the BMC resource's specification to reference the corresponding 41 | `BMCSecret`. It retrieves the credentials from the BMCSecret to authenticate with the BMC device. 42 | -------------------------------------------------------------------------------- /docs/concepts/bmcsettings.md: -------------------------------------------------------------------------------- 1 | # BMCSettings 2 | 3 | `BMCSettings` represents a BMC Setting update operation for a physical server's BMC (compute system). It updates the BMC settings on physical server's BMC. 4 | 5 | ## Key Points 6 | 7 | - `BMCSettings` maps a BMC version and settings as map for a given server. 8 | - Only one `BMCSettings` can be active per `BMC` at a time. 9 | - `BMCSettings` related changes are applied once the BMC version matches with the physical server's BMC version. 10 | - `BMCSettings` handles reboots of BMC 11 | - `BMCSettings` requests for `Maintenance` if `ServerMaintenancePolicy` is set to "OwnerApproval". 12 | - Once`BMCSettings` moves to `Failed` state, It stays in this state unless Manually moved out of this state. 13 | 14 | ## Workflow 15 | 16 | 1. A separate operator (e.g., `bmcSettingsSet`) or user creates a `BMCSettings` resource referencing a specific `BMC` 17 | 2. Provided settings are checked against the current BMC setting. 18 | 3. If settings are same as on the server, the state is moved to `Applied` (even if the version does not match) 19 | 4. If the settings needs update, `BMCSettings` check the version of BMC and if required version does not match, it waits for the BMC version to reach the spec version. 20 | 5. If "OwnerApproval" `ServerMaintenancePolicy` type is requested and `ServerMaintenance` is not provided already. it requests one per `server` managed by `BMC` and waits for all the `server` to enter `Maintenance` state. 21 | 6. Setting update process is started and the physical server's BMC is rebooted if required. 22 | 7. `BMCSettings` verfiy the setting has been applied and trasistions the state to `Applied`. removes all the `ServerMaintenance` resource if created by self. 23 | 8. Any further update to the `BMCSettings` Spec will restart the process. 24 | 9. If the `BMCSettings` fails to apply the bmc setting. The `BMCSettings` moves to `Failed` state until Manually moved out of this state. 25 | 26 | ## Example 27 | 28 | ```yaml 29 | apiVersion: metal.ironcore.dev/v1alpha1 30 | kind: BMCSettings 31 | metadata: 32 | name: bmcsettings-sample 33 | spec: 34 | BMCRef: 35 | name: sample-BMC 36 | version: 2.10.3 37 | settings: 38 | OtherSettings: "123" 39 | someother: Disabled 40 | ServerMaintenancePolicy: OwnerApproval 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/concepts/bmcversion.md: -------------------------------------------------------------------------------- 1 | # BMCVersion 2 | 3 | `BMCVersion` represents a BMC Version upgrade operation for a physical server's Manager. It updates the BMC Version on physical server's BMC. 4 | 5 | ## Key Points 6 | 7 | - `BMCVersion` maps a BMC version required for a given server's BMC. 8 | - `BMCVersion` Spec contains the required details to upgrade the BMC to required version. 9 | - Only one `BMCVersion` can be active per `BMC` at a time. 10 | - `BMCVersion` starts the version upgrade of the BMC using redfish `SimpleUpgrade` API. 11 | - `BMCVersion` handles reboots of BMC. 12 | - `BMCVersion` requests for `Maintenance` if `ServerMaintenancePolicy` is set to "OwnerApproval". 13 | - Once`BMCVersion` moves to `Failed` state, It stays in this state unless Manually moved out of this state. 14 | 15 | ## Workflow 16 | 17 | 1. A separate operator (e.g., `bmcVersionSet`) or user creates a `BMCVersion` resource referencing a specific `BMC`. 18 | 2. Provided settings are checked against the current BMC version. 19 | 3. If version is same as on the server's BMC, the state is moved to `Completed`. 20 | 4. If the version needs upgrade, `BMCVersion` checks the current version of BMC and if required version is lower than the requested, `BMCVersion` moves the state to `Failed` 21 | 5. If "OwnerApproval" `ServerMaintenancePolicy` type is requested and `ServerMaintenance` is not provided already. It requests one per `server` managed by `BMC` and waits for all the `server` to enter `Maintenance` state. 22 | 6. `BMCVersion` issues the BMC upgrade using redfish "SimpleUpgrade" API. and monitors the `upgrade task` created by the API. 23 | 7. `BMCVersion` moves to `Failed` state: 24 | - If `SimpleUpgade` is issued but unable to get the task to monitor the progress of BMC upgrade 25 | - If the `upgrade task` created by SimpleUpgade fails and does not reach completed state. 26 | - If the BMC version requested is lower than that of the current BMC version 27 | 8. `BMCVersion` moves to reboot the BMC once the `upgrade task` has been completed. 28 | 9. `BMCVersion` verfiy the BMC version post reboot, removes the `ServerMaintenance` resource if created by self. and transistion to `Completed` state 29 | 9. Any further update to the `BMCVersion` Spec will restart the process. 30 | 31 | ## Example 32 | 33 | ```yaml 34 | apiVersion: metal.ironcore.dev/v1alpha1 35 | kind: BMCVersion 36 | metadata: 37 | name: biosversion-sample 38 | spec: 39 | version: 2.10.3 40 | image: 41 | URI: "http://foo.com/dell-idrac-bmc-2.10.3.bin" 42 | transferProtocol: "http" 43 | imageSecretRef: 44 | name: sample-secret 45 | forceUpdate: false 46 | BMCRef: 47 | name: BMC-sample 48 | serverMaintenancePolicy: Enforced 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/concepts/serverbootconfigurations.md: -------------------------------------------------------------------------------- 1 | # ServerBootConfigurations 2 | 3 | The `ServerBootConfiguration` Custom Resource Definition (CRD) is a Kubernetes resource used to signal the need to 4 | initiate a boot process for a bare metal server. It serves as an indicator for external components responsible for 5 | configuring network boot environments, such as PXE or HTTPBoot servers. The `ServerBootConfiguration` resource allows 6 | the `metal-operator` to delegate the boot preparation process to third-party operators like the 7 | [`boot-operator`](https://github.com/ironcore-dev/boot-operator) or tools like OpenStack Ironic. 8 | 9 | ## Example ServerBootConfiguration Resource 10 | 11 | ```yaml 12 | apiVersion: metal.ironcore.dev/v1alpha1 13 | kind: ServerBootConfiguration 14 | metadata: 15 | name: my-server-boot-config 16 | namespace: defauilt 17 | spec: 18 | serverRef: 19 | name: my-server 20 | image: my-osimage:latest 21 | ignitionSecretRef: 22 | name: my-ignition-secret 23 | ``` 24 | 25 | ## Integration with Third-Party Components 26 | 27 | The actual preparation of the boot environment is performed by external components, which may include: 28 | - boot-operator: A custom operator that handles boot environment preparation as part of the IronCore project. 29 | - OpenStack Ironic: A service for managing and provisioning bare metal servers. 30 | 31 | These components watch for `ServerBootConfiguration` resources and perform the necessary actions to set up the boot 32 | environment according to the specifications provided. 33 | 34 | ## Why externalizing the boot preparation to a Third-Party? 35 | 36 | **Separation of Concerns**: By abstracting the boot preparation into a separate resource, the `metal-operator` 37 | remains agnostic to the specifics of the boot process, allowing for flexibility in different deployment scenarios. 38 | 39 | **Custom Implementations**: Users can implement their own components to handle the `ServerBootConfiguration`, enabling 40 | integration with various provisioning systems or custom workflows. 41 | 42 | ## Reconciliation Process 43 | 44 | The `ServerReconciler` checks the `ServerBootConfiguration` status before powering on the server. Servers are not 45 | powered on until the boot environment is confirmed to be `ready`. 46 | -------------------------------------------------------------------------------- /docs/concepts/serverclaims.md: -------------------------------------------------------------------------------- 1 | # ServerClaims 2 | 3 | The `ServerClaim` Custom Resource Definition (CRD) is a Kubernetes resource used to claim ownership of a bare metal 4 | [`Server`](servers.md) resource that is in the `Available` state. It allows users to specify the desired 5 | operating system image and ignition configuration for booting the server. The `ServerClaimReconciler` handles the 6 | allocation of servers to claims and manages the lifecycle of the claim and the server. 7 | 8 | ## Example ServerClaim Resource 9 | 10 | Claiming a Specific Server with Ignition Configuration: 11 | 12 | ```yaml 13 | apiVersion: metal.ironcore.dev/v1alpha1 14 | kind: ServerClaim 15 | metadata: 16 | name: my-server-claim 17 | namespace: default 18 | spec: 19 | power: "On" 20 | serverRef: 21 | name: "my-server" 22 | image: "my-osimage:latest" 23 | ignitionSecretRef: 24 | name: "my-ignition-secret" 25 | ``` 26 | 27 | Claiming a Server Using a Selector: 28 | 29 | ```yaml 30 | apiVersion: metal.ironcore.dev/v1alpha1 31 | kind: ServerClaim 32 | metadata: 33 | name: selector-server-claim 34 | namespace: default 35 | spec: 36 | power: "On" 37 | serverSelector: 38 | matchLabels: 39 | hardwareType: gpu-node 40 | location: datacenter-1 41 | image: my-osimage:latest 42 | ignitionSecretRef: 43 | name: my-ignition-secret 44 | ``` 45 | 46 | ## Reconciliation Process 47 | 48 | - [`ServerBootConfiguration`](serverbootconfigurations.md): 49 | - The `ServerClaimReconciler` creates a [`ServerBootConfiguration`](serverbootconfigurations.md) resource under the hood. 50 | - This resource specifies how the server should be booted, including the image and ignition configuration. 51 | 52 | - **State Transitions**: 53 | - Available → Reserved: When a server is successfully claimed. 54 | - Reserved → Cleanup: When the `ServerClaim` is deleted. 55 | - Cleanup → Available: After cleanup tasks are completed. 56 | 57 | - **Cleanup Process**: 58 | - Ensures that servers are sanitized before being made available again. 59 | - Tasks may include wiping disks, resetting BIOS settings, and clearing configurations. 60 | -------------------------------------------------------------------------------- /docs/development/dev_docs.md: -------------------------------------------------------------------------------- 1 | # metal-operator documentation 2 | 3 | ## Local dev setup 4 | 5 | You can run the documentation via: 6 | 7 | ```shell 8 | make startdocs 9 | ``` 10 | 11 | You can remove the `mkdocs` container image by running: 12 | 13 | ```shell 14 | make cleandocs 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/development/dev_setup.md: -------------------------------------------------------------------------------- 1 | # Local Dev Setup 2 | 3 | ## Prerequisites 4 | 5 | - go version v1.22.0+ 6 | - docker version 17.03+. 7 | - kubectl version v1.28.0+. 8 | 9 | ## Overview 10 | 11 | The `metal-operator` is leveraging [envtest](https://book.kubebuilder.io/reference/envtest.html) to conduct and run 12 | unit test suites. Additionally, it is using the [Redfish Mock Server](https://github.com/DMTF/Redfish-Mockup-Server) to 13 | run a local mock Redfish instance to simulate operations performed by various reconcilers. 14 | 15 | ```mermaid 16 | graph TD 17 | A[Kubernetes Controller Runtime Based Reconcilers] -->|Interacts with| B[envtest Kube-apiserver Environment] 18 | A -->|Interacts with| C[Redfish Mock Server] 19 | C -->|Runs as a| D[Docker Container] 20 | ``` 21 | 22 | ### Run the local test suite 23 | 24 | The local test suite can be run via 25 | 26 | ```shell 27 | make test 28 | ``` 29 | 30 | This `Makefile` directive will start under the hood the Redfish mock server, instantiate the `envtest` environment 31 | and run `go test ./...` on the whole project. 32 | 33 | ### Start/Stop Redfish Mock Server 34 | 35 | The Redfish mock server can be started and stopped with the following command 36 | 37 | ```shell 38 | make startbmc 39 | make stopbmc 40 | ``` 41 | 42 | ### Run the local Tilt development environment 43 | 44 | #### Prerequisites 45 | 46 | - [Tilt v0.33.17+](https://docs.tilt.dev/install.html) 47 | - [Kind v0.23.0+](https://kind.sigs.k8s.io/docs/user/quick-start/) 48 | 49 | The local development environment can be started via 50 | 51 | ```shell 52 | make tilt-up 53 | ``` 54 | 55 | This `Makefile` directive will: 56 | - create a local Kind cluster with local registry 57 | - install cert-manager 58 | - install [boot-operator](https://github.com/ironcore-dev/boot-operator) to reconcile the `ServerBootConfiguration` CRD 59 | - start the `metal-operator` controller and Redfish mock server as a sidecar container 60 | - an Endpoint resource is created to point to the Redfish mock server 61 | - this will result in `Server` resources being created and reconciled by the `metal-operator` 62 | 63 | ```shell 64 | ‹kind-metal› kubectl get server 65 | NAME UUID MANUFACTURER POWERSTATE STATE AGE 66 | compute-0-bmc-endpoint-sample 38947555-7742-3448-3784-823347823834 Contoso On Available 3m21s 67 | ``` 68 | 69 | The local development environment can be deleted via 70 | 71 | ```shell 72 | make kind-delete 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # your mkdocs plugins go here 2 | -------------------------------------------------------------------------------- /hack/api-reference/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "hideMemberFields": [ 3 | "TypeMeta" 4 | ], 5 | "hideTypePatterns": [ 6 | "ParseError$", 7 | "List$" 8 | ], 9 | "externalPackages": [ 10 | { 11 | "typeMatchPrefix": "^net/netip", 12 | "docsURLTemplate": "https://pkg.go.dev/net/netip#{{.TypeIdentifier}}" 13 | }, 14 | { 15 | "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/api/resource", 16 | "docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#{{.TypeIdentifier}}" 17 | }, 18 | { 19 | "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/types", 20 | "docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/types#{{.TypeIdentifier}}" 21 | }, 22 | { 23 | "typeMatchPrefix": "^k8s\\.io/(api|apimachinery/pkg/apis)/", 24 | "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}" 25 | } 26 | ], 27 | "typeDisplayNamePrefixOverrides": { 28 | "k8s.io/api/": "Kubernetes ", 29 | "k8s.io/apimachinery/pkg/apis/": "Kubernetes " 30 | }, 31 | "markdownDisabled": false 32 | } 33 | -------------------------------------------------------------------------------- /hack/api-reference/template/members.tpl: -------------------------------------------------------------------------------- 1 | {{ define "members" }} 2 | 3 | {{ range .Members }} 4 | {{ if not (hiddenMember .)}} 5 | 6 | 7 | {{ fieldName . }}
8 | 9 | {{ if linkForType .Type }} 10 | 11 | {{ typeDisplayName .Type }} 12 | 13 | {{ else }} 14 | {{ typeDisplayName .Type }} 15 | {{ end }} 16 | 17 | 18 | 19 | {{ if fieldEmbedded . }} 20 |

21 | (Members of {{ fieldName . }} are embedded into this type.) 22 |

23 | {{ end}} 24 | 25 | {{ if isOptionalMember .}} 26 | (Optional) 27 | {{ end }} 28 | 29 | {{ safe (renderComments .CommentLines) }} 30 | 31 | {{ if and (eq (.Type.Name.Name) "ObjectMeta") }} 32 | Refer to the Kubernetes API documentation for the fields of the 33 | metadata field. 34 | {{ end }} 35 | 36 | {{ if or (eq (fieldName .) "spec") }} 37 |
38 |
39 | 40 | {{ template "members" .Type }} 41 |
42 | {{ end }} 43 | 44 | 45 | {{ end }} 46 | {{ end }} 47 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /hack/api-reference/template/pkg.tpl: -------------------------------------------------------------------------------- 1 | {{ define "packages" }} 2 | 3 | {{ with .packages}} 4 |

Packages:

5 | 12 | {{ end}} 13 | 14 | {{ range .packages }} 15 |

16 | {{- packageDisplayName . -}} 17 |

18 | 19 | {{ with (index .GoPackages 0 )}} 20 | {{ with .DocComments }} 21 |
22 | {{ safe (renderComments .) }} 23 |
24 | {{ end }} 25 | {{ end }} 26 | 27 | Resource Types: 28 | 37 | 38 | {{ range (visibleTypes (sortedTypes .Types))}} 39 | {{ template "type" . }} 40 | {{ end }} 41 |
42 | {{ end }} 43 | 44 |

45 | Generated with gen-crd-api-reference-docs 46 |

47 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /hack/api-reference/template/type.tpl: -------------------------------------------------------------------------------- 1 | {{ define "type" }} 2 | 3 |

4 | {{- .Name.Name }} 5 | {{ if eq .Kind "Alias" }}({{.Underlying}} alias){{ end -}} 6 |

7 | {{ with (typeReferences .) }} 8 |

9 | (Appears on: 10 | {{- $prev := "" -}} 11 | {{- range . -}} 12 | {{- if $prev -}}, {{ end -}} 13 | {{- $prev = . -}} 14 | {{ typeDisplayName . }} 15 | {{- end -}} 16 | ) 17 |

18 | {{ end }} 19 | 20 |
21 | {{ safe (renderComments .CommentLines) }} 22 |
23 | 24 | {{ with (constantsOfType .) }} 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {{- range . -}} 34 | 35 | {{- /* 36 | renderComments implicitly creates a

element, so we 37 | add one to the display name as well to make the contents 38 | of the two cells align evenly. 39 | */ -}} 40 |

41 | 42 | 43 | {{- end -}} 44 | 45 |
ValueDescription

{{ typeDisplayName . }}

{{ safe (renderComments .CommentLines) }}
46 | {{ end }} 47 | 48 | {{ if .Members }} 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {{ if isExportedType . }} 58 | 59 | 62 | 67 | 68 | 69 | 73 | 74 | 75 | {{ end }} 76 | {{ template "members" .}} 77 | 78 |
FieldDescription
60 | apiVersion
61 | string
63 | 64 | {{apiGroup .}} 65 | 66 |
70 | kind
71 | string 72 |
{{.Name.Name}}
79 | {{ end }} 80 | 81 | {{ end }} 82 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /hack/dev-mac-prefixes.yaml: -------------------------------------------------------------------------------- 1 | macPrefixes: 2 | - macPrefix: 23 3 | manufacturer: Foo 4 | protocol: Redfish 5 | port: 8000 6 | type: bmc 7 | defaultCredentials: 8 | - username: foo 9 | password: bar 10 | -------------------------------------------------------------------------------- /hack/license-header.txt: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors 2 | SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /hack/validate-kustomize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | BASEDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 6 | export TERM="xterm-256color" 7 | 8 | bold="$(tput bold)" 9 | red="$(tput setaf 1)" 10 | green="$(tput setaf 2)" 11 | normal="$(tput sgr0)" 12 | 13 | for kustomization in "$BASEDIR"/../config/**/kustomization.yaml; do 14 | path="$(dirname "$kustomization")" 15 | dir="$(realpath --relative-to "$BASEDIR"/.. "$path")" 16 | echo "${bold}Validating $dir${normal}" 17 | if ! kustomize_output="$(kustomize build "$path" 2>&1)"; then 18 | echo "${red}Kustomize build $dir failed:" 19 | echo "$kustomize_output" 20 | exit 1 21 | fi 22 | echo "${green}Successfully validated $dir${normal}" 23 | done 24 | -------------------------------------------------------------------------------- /internal/api/macdb/macdb.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package macdb 5 | 6 | import metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 7 | 8 | // MacPrefixes is a list of MacPrefix 9 | type MacPrefixes struct { 10 | // MacPrefixes is a list of MacPrefix 11 | MacPrefixes []MacPrefix `json:"macPrefixes"` 12 | } 13 | 14 | // Console is a struct that contains the type and port of the console 15 | type Console struct { 16 | // Type is the type of the console 17 | Type string `json:"type"` 18 | // Port is the port of the console 19 | Port int32 `json:"port"` 20 | } 21 | 22 | // MacPrefix is a struct that contains the mac prefix, manufacturer, protocol, protocol scheme, port, type, 23 | // default credentials and console 24 | type MacPrefix struct { 25 | // MacPrefix is the mac prefix 26 | MacPrefix string `json:"macPrefix"` 27 | // Manufacturer is the manufacturer 28 | Manufacturer string `json:"manufacturer"` 29 | // Protocol is the protocol 30 | Protocol string `json:"protocol"` 31 | // ProtocolScheme is the protocol scheme (http, https) 32 | ProtocolScheme metalv1alpha1.ProtocolScheme `json:"protocolScheme,omitempty"` 33 | // Port is the port 34 | Port int32 `json:"port"` 35 | // Type is the type 36 | Type string `json:"type"` 37 | // DefaultCredentials is the default credentials 38 | DefaultCredentials []Credential `json:"defaultCredentials"` 39 | // Console is the console 40 | Console Console `json:"console,omitempty"` 41 | } 42 | 43 | // Credential is a struct that contains the username and password 44 | type Credential struct { 45 | // Username is the username 46 | Username string `json:"username"` 47 | // Password is the password 48 | Password string `json:"password"` 49 | } 50 | -------------------------------------------------------------------------------- /internal/api/registry/registry.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package registry 5 | 6 | // RegistrationPayload represents the payload to send to the `/register` endpoint, 7 | // including the systemUUID and the server details. 8 | type RegistrationPayload struct { 9 | SystemUUID string `json:"systemUUID"` 10 | Data Server `json:"data"` 11 | } 12 | -------------------------------------------------------------------------------- /internal/api/registry/server.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package registry 5 | 6 | // NetworkInterface represents a network interface on a server, 7 | // including its IP and MAC addresses. 8 | type NetworkInterface struct { 9 | Name string `json:"name"` 10 | IPAddress string `json:"ipAddress"` 11 | MACAddress string `json:"macAddress"` 12 | } 13 | 14 | // Server represents a server with a list of network interfaces. 15 | type Server struct { 16 | NetworkInterfaces []NetworkInterface `json:"networkInterfaces,omitempty"` 17 | } 18 | -------------------------------------------------------------------------------- /internal/console/console.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package console 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | 10 | "github.com/ironcore-dev/metal-operator/api/v1alpha1" 11 | "github.com/ironcore-dev/metal-operator/internal/bmcutils" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | ) 14 | 15 | type Config struct { 16 | BMCAddress string 17 | Username string 18 | Password string 19 | } 20 | 21 | func GetConfigForServerName(ctx context.Context, c client.Client, serverName string) (*Config, error) { 22 | server := &v1alpha1.Server{} 23 | if err := c.Get(ctx, client.ObjectKey{Name: serverName}, server); err != nil { 24 | return nil, fmt.Errorf("failed to get server %q: %w", serverName, err) 25 | } 26 | 27 | // Inline BMC configuration 28 | if server.Spec.BMC != nil { 29 | username, password, err := bmcutils.GetBMCCredentialsForBMCSecretName(ctx, c, server.Spec.BMC.BMCSecretRef.Name) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return &Config{ 34 | BMCAddress: server.Spec.BMC.Address, 35 | Username: username, 36 | Password: password, 37 | }, nil 38 | } 39 | 40 | // BMC by reference 41 | if server.Spec.BMCRef != nil { 42 | bmc, err := bmcutils.GetBMCFromBMCName(ctx, c, server.Spec.BMCRef.Name) 43 | if err != nil { 44 | return nil, err 45 | } 46 | username, password, err := bmcutils.GetBMCCredentialsForBMCSecretName(ctx, c, bmc.Spec.BMCSecretRef.Name) 47 | if err != nil { 48 | return nil, err 49 | } 50 | address, err := bmcutils.GetBMCAddressForBMC(ctx, c, bmc) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | return &Config{ 56 | BMCAddress: address, 57 | Username: username, 58 | Password: password, 59 | }, nil 60 | } 61 | 62 | return nil, fmt.Errorf("failed to create configuration for accessing server %s", serverName) 63 | } 64 | -------------------------------------------------------------------------------- /internal/controller/bmcsecret_controller.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controller 5 | 6 | import ( 7 | "context" 8 | 9 | "k8s.io/apimachinery/pkg/runtime" 10 | ctrl "sigs.k8s.io/controller-runtime" 11 | "sigs.k8s.io/controller-runtime/pkg/client" 12 | "sigs.k8s.io/controller-runtime/pkg/log" 13 | 14 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 15 | ) 16 | 17 | // BMCSecretReconciler reconciles a BMCSecret object 18 | type BMCSecretReconciler struct { 19 | client.Client 20 | Scheme *runtime.Scheme 21 | } 22 | 23 | //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=bmcsecrets,verbs=get;list;watch;create;update;patch;delete 24 | //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=bmcsecrets/status,verbs=get;update;patch 25 | //+kubebuilder:rbac:groups=metal.ironcore.dev,resources=bmcsecrets/finalizers,verbs=update 26 | 27 | // Reconcile is part of the main kubernetes reconciliation loop which aims to 28 | // move the current state of the cluster closer to the desired state. 29 | // TODO(user): Modify the Reconcile function to compare the state specified by 30 | // the BMCSecret object against the actual cluster state, and then 31 | // perform operations to make the cluster state reflect the state specified by 32 | // the user. 33 | // 34 | // For more details, check Reconcile and its Result here: 35 | // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.0/pkg/reconcile 36 | func (r *BMCSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 37 | _ = log.FromContext(ctx) 38 | 39 | // TODO(user): your logic here 40 | 41 | return ctrl.Result{}, nil 42 | } 43 | 44 | // SetupWithManager sets up the controller with the Manager. 45 | func (r *BMCSecretReconciler) SetupWithManager(mgr ctrl.Manager) error { 46 | return ctrl.NewControllerManagedBy(mgr). 47 | For(&metalv1alpha1.BMCSecret{}). 48 | Complete(r) 49 | } 50 | -------------------------------------------------------------------------------- /internal/controller/bmcsecret_controller_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controller 5 | 6 | import ( 7 | . "github.com/onsi/ginkgo/v2" 8 | . "github.com/onsi/gomega" 9 | "k8s.io/apimachinery/pkg/api/errors" 10 | "k8s.io/apimachinery/pkg/types" 11 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 12 | 13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 | 15 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 16 | ) 17 | 18 | var _ = Describe("BMCSecret Controller", func() { 19 | Context("When reconciling a resource", func() { 20 | const resourceName = "test-resource" 21 | 22 | typeNamespacedName := types.NamespacedName{ 23 | Name: resourceName, 24 | Namespace: "default", 25 | } 26 | bmcsecret := &metalv1alpha1.BMCSecret{} 27 | 28 | BeforeEach(func(ctx SpecContext) { 29 | By("creating the custom resource for the Kind BMCSecret") 30 | err := k8sClient.Get(ctx, typeNamespacedName, bmcsecret) 31 | if err != nil && errors.IsNotFound(err) { 32 | resource := &metalv1alpha1.BMCSecret{ 33 | ObjectMeta: metav1.ObjectMeta{ 34 | Name: resourceName, 35 | Namespace: "default", 36 | }, 37 | } 38 | Expect(k8sClient.Create(ctx, resource)).To(Succeed()) 39 | } 40 | }) 41 | 42 | AfterEach(func(ctx SpecContext) { 43 | // TODO(user): Cleanup logic after each test, like removing the resource instance. 44 | resource := &metalv1alpha1.BMCSecret{} 45 | err := k8sClient.Get(ctx, typeNamespacedName, resource) 46 | Expect(err).NotTo(HaveOccurred()) 47 | 48 | By("Cleanup the specific resource instance BMCSecret") 49 | Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) 50 | }) 51 | 52 | It("should successfully reconcile the resource", func(ctx SpecContext) { 53 | By("Reconciling the created resource") 54 | controllerReconciler := &BMCSecretReconciler{ 55 | Client: k8sClient, 56 | Scheme: k8sClient.Scheme(), 57 | } 58 | 59 | _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ 60 | NamespacedName: typeNamespacedName, 61 | }) 62 | Expect(err).To(Succeed()) 63 | // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. 64 | // Example: If you expect a certain status condition after reconciliation, verify it here. 65 | }) 66 | }) 67 | }) 68 | -------------------------------------------------------------------------------- /internal/controller/endpoint_controller_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controller 5 | 6 | import ( 7 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | apierrors "k8s.io/apimachinery/pkg/api/errors" 11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | "k8s.io/utils/ptr" 13 | . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" 14 | ) 15 | 16 | var _ = Describe("Endpoints Controller", func() { 17 | ns := SetupTest() 18 | 19 | AfterEach(func(ctx SpecContext) { 20 | DeleteAllMetalResources(ctx, ns.Name) 21 | }) 22 | 23 | It("should successfully create a BMC secret and BMC object from endpoint", func(ctx SpecContext) { 24 | By("Creating an Endpoints object") 25 | endpoint := &metalv1alpha1.Endpoint{ 26 | ObjectMeta: metav1.ObjectMeta{ 27 | GenerateName: "test-endpoint-", 28 | }, 29 | Spec: metalv1alpha1.EndpointSpec{ 30 | // emulator BMC mac address 31 | MACAddress: "23:11:8A:33:CF:EA", 32 | IP: metalv1alpha1.MustParseIP("127.0.0.1"), 33 | }, 34 | } 35 | Expect(k8sClient.Create(ctx, endpoint)).To(Succeed()) 36 | 37 | By("Ensuring that the BMC secret has been created") 38 | bmcSecret := &metalv1alpha1.BMCSecret{ 39 | ObjectMeta: metav1.ObjectMeta{ 40 | Name: endpoint.Name, 41 | }, 42 | } 43 | Eventually(Object(bmcSecret)).Should(SatisfyAll( 44 | HaveField("OwnerReferences", ContainElement(metav1.OwnerReference{ 45 | APIVersion: "metal.ironcore.dev/v1alpha1", 46 | Kind: "Endpoint", 47 | Name: endpoint.Name, 48 | UID: endpoint.UID, 49 | Controller: ptr.To(true), 50 | BlockOwnerDeletion: ptr.To(true), 51 | })), 52 | HaveField("Data", Equal(map[string][]byte{ 53 | metalv1alpha1.BMCSecretUsernameKeyName: []byte("foo"), 54 | metalv1alpha1.BMCSecretPasswordKeyName: []byte("bar"), 55 | })))) 56 | 57 | By("By ensuring that the BMC object has been created") 58 | bmc := &metalv1alpha1.BMC{ 59 | ObjectMeta: metav1.ObjectMeta{ 60 | Name: endpoint.Name, 61 | }, 62 | } 63 | Eventually(Object(bmc)).Should(SatisfyAll( 64 | HaveField("OwnerReferences", ContainElement(metav1.OwnerReference{ 65 | APIVersion: "metal.ironcore.dev/v1alpha1", 66 | Kind: "Endpoint", 67 | Name: endpoint.Name, 68 | UID: endpoint.UID, 69 | Controller: ptr.To(true), 70 | BlockOwnerDeletion: ptr.To(true), 71 | })), 72 | HaveField("Spec.EndpointRef.Name", Equal(endpoint.Name)), 73 | HaveField("Spec.BMCSecretRef.Name", Equal(bmc.Name)), 74 | HaveField("Spec.Protocol", metalv1alpha1.Protocol{ 75 | Name: metalv1alpha1.ProtocolRedfishLocal, 76 | Port: 8000, 77 | }), 78 | HaveField("Spec.ConsoleProtocol", &metalv1alpha1.ConsoleProtocol{ 79 | Name: metalv1alpha1.ConsoleProtocolNameSSH, 80 | Port: 22, 81 | }))) 82 | 83 | By("Removing the endpoint") 84 | Expect(k8sClient.Delete(ctx, endpoint)).To(Succeed()) 85 | 86 | By("Ensuring that all subsequent objects have been removed") 87 | Eventually(Get(endpoint)).Should(Satisfy(apierrors.IsNotFound)) 88 | }) 89 | }) 90 | -------------------------------------------------------------------------------- /internal/controller/helper.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controller 5 | 6 | import ( 7 | "crypto/rand" 8 | "fmt" 9 | "math/big" 10 | 11 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | ) 14 | 15 | const ( 16 | fieldOwner = client.FieldOwner("metal.ironcore.dev/controller-manager") 17 | ) 18 | 19 | // shouldIgnoreReconciliation checks if the object should be ignored during reconciliation. 20 | func shouldIgnoreReconciliation(obj client.Object) bool { 21 | val, found := obj.GetAnnotations()[metalv1alpha1.OperationAnnotation] 22 | if !found { 23 | return false 24 | } 25 | return val == metalv1alpha1.OperationAnnotationIgnore 26 | } 27 | 28 | // GenerateRandomPassword generates a random password of the given length. 29 | func GenerateRandomPassword(length int) ([]byte, error) { 30 | const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 31 | result := make([]byte, length) 32 | for i := 0; i < length; i++ { 33 | n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) 34 | if err != nil { 35 | return nil, fmt.Errorf("failed to generate random password: %w", err) 36 | } 37 | result[i] = letters[n.Int64()] 38 | } 39 | return result, nil 40 | } 41 | -------------------------------------------------------------------------------- /internal/controller/serverbootconfiguration_controller_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controller 5 | 6 | import ( 7 | metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1" 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | v1 "k8s.io/api/core/v1" 11 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 | . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" 13 | ) 14 | 15 | var _ = Describe("ServerBootConfiguration Controller", func() { 16 | ns := SetupTest() 17 | 18 | var server *metalv1alpha1.Server 19 | 20 | BeforeEach(func(ctx SpecContext) { 21 | By("Creating a Server object") 22 | server = &metalv1alpha1.Server{ 23 | ObjectMeta: metav1.ObjectMeta{ 24 | GenerateName: "test-severbootconfig-", 25 | Annotations: map[string]string{ 26 | metalv1alpha1.OperationAnnotation: metalv1alpha1.OperationAnnotationIgnore, 27 | }, 28 | }, 29 | Spec: metalv1alpha1.ServerSpec{}, 30 | } 31 | Expect(k8sClient.Create(ctx, server)).To(Succeed()) 32 | }) 33 | 34 | AfterEach(func(ctx SpecContext) { 35 | DeleteAllMetalResources(ctx, ns.Name) 36 | }) 37 | 38 | It("should successfully add the boot configuration ref to server", func(ctx SpecContext) { 39 | By("By creating a server boot configuration") 40 | config := &metalv1alpha1.ServerBootConfiguration{ 41 | ObjectMeta: metav1.ObjectMeta{ 42 | Namespace: ns.Name, 43 | Name: server.Name, 44 | }, 45 | Spec: metalv1alpha1.ServerBootConfigurationSpec{ 46 | ServerRef: v1.LocalObjectReference{Name: server.Name}, 47 | Image: "foo:latest", 48 | }, 49 | } 50 | Expect(k8sClient.Create(ctx, config)).To(Succeed()) 51 | 52 | Eventually(Object(config)).Should(SatisfyAll( 53 | HaveField("Status.State", metalv1alpha1.ServerBootConfigurationStatePending), 54 | )) 55 | }) 56 | }) 57 | -------------------------------------------------------------------------------- /internal/ignition/default.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package ignition 5 | 6 | import ( 7 | "bytes" 8 | "fmt" 9 | "text/template" 10 | ) 11 | 12 | // Config holds the Docker image and flags. 13 | type Config struct { 14 | Image string 15 | Flags string 16 | SSHPublicKey string 17 | PasswordHash string 18 | } 19 | 20 | // defaultIgnitionTemplate is a Go template for the default Ignition configuration. 21 | var defaultIgnitionTemplate = `variant: fcos 22 | version: "1.3.0" 23 | systemd: 24 | units: 25 | - name: docker-install.service 26 | enabled: true 27 | contents: |- 28 | [Unit] 29 | Description=Install Docker 30 | Before=metalprobe.service 31 | [Service] 32 | Restart=on-failure 33 | RestartSec=20 34 | Type=oneshot 35 | RemainAfterExit=yes 36 | ExecStart=/usr/bin/apt-get update 37 | ExecStart=/usr/bin/apt-get install docker.io docker-cli -y 38 | [Install] 39 | WantedBy=multi-user.target 40 | - name: docker.service 41 | enabled: true 42 | - name: metalprobe.service 43 | enabled: true 44 | contents: |- 45 | [Unit] 46 | Description=Run My Docker Container 47 | [Service] 48 | Restart=on-failure 49 | RestartSec=20 50 | ExecStartPre=-/usr/bin/docker stop metalprobe 51 | ExecStartPre=-/usr/bin/docker rm metalprobe 52 | ExecStartPre=/usr/bin/docker pull {{.Image}} 53 | ExecStart=/usr/bin/docker run --network host --privileged --name metalprobe {{.Image}} {{.Flags}} 54 | ExecStop=/usr/bin/docker stop metalprobe 55 | [Install] 56 | WantedBy=multi-user.target 57 | storage: 58 | files: [] 59 | passwd: 60 | users: 61 | - name: metal 62 | password_hash: {{.PasswordHash}} 63 | groups: [ "wheel" ] 64 | ssh_authorized_keys: [ {{.SSHPublicKey}} ] 65 | ` 66 | 67 | // GenerateDefaultIgnitionData renders the defaultIgnitionTemplate with the given Config. 68 | func GenerateDefaultIgnitionData(config Config) ([]byte, error) { 69 | tmpl, err := template.New("defaultIgnition").Parse(defaultIgnitionTemplate) 70 | if err != nil { 71 | return nil, fmt.Errorf("parsing template failed: %w", err) 72 | } 73 | 74 | var out bytes.Buffer 75 | err = tmpl.Execute(&out, config) 76 | if err != nil { 77 | return nil, fmt.Errorf("executing template failed: %w", err) 78 | } 79 | 80 | return out.Bytes(), nil 81 | } 82 | -------------------------------------------------------------------------------- /internal/probe/agent_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package probe_test 5 | 6 | import ( 7 | "encoding/json" 8 | "fmt" 9 | "net/http" 10 | 11 | "github.com/ironcore-dev/metal-operator/internal/api/registry" 12 | . "github.com/onsi/ginkgo/v2" 13 | . "github.com/onsi/gomega" 14 | ) 15 | 16 | var _ = Describe("ProbeAgent", func() { 17 | It("should ensure the correct endpoints have been registered", func() { 18 | By("performing a GET request to the /systems/{uuid} endpoint") 19 | var resp *http.Response 20 | var err error 21 | Eventually(func(g Gomega) { 22 | resp, err = http.Get(fmt.Sprintf("%s/systems/%s", registryURL, systemUUID)) 23 | g.Expect(resp).NotTo(BeNil()) 24 | g.Expect(err).NotTo(HaveOccurred()) 25 | g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) 26 | }).Should(Succeed()) 27 | 28 | By("ensuring that the endpoints are not empty") 29 | server := ®istry.Server{} 30 | Expect(json.NewDecoder(resp.Body).Decode(server)).NotTo(HaveOccurred()) 31 | Expect(server.NetworkInterfaces).NotTo(BeEmpty()) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /internal/probe/networking.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package probe 5 | 6 | import ( 7 | "net" 8 | "strings" 9 | 10 | "github.com/ironcore-dev/metal-operator/internal/api/registry" 11 | ) 12 | 13 | // IsSLAAC checks if the given IPv6 address is a SLAAC address. 14 | func IsSLAAC(ip string) bool { 15 | return strings.Contains(ip, "ff:fe") 16 | } 17 | 18 | // collectNetworkData collects the IP and MAC addresses of the host's network interfaces, 19 | // ignoring loopback and tunnel (tun) devices. 20 | func collectNetworkData() ([]registry.NetworkInterface, error) { 21 | interfaces, err := net.Interfaces() 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | var networkInterfaces []registry.NetworkInterface 27 | for _, iface := range interfaces { 28 | // Skip loopback, interfaces without a MAC address, tun devices, docker interface 29 | if iface.Flags&net.FlagLoopback != 0 || 30 | iface.HardwareAddr.String() == "" || 31 | strings.HasPrefix(iface.Name, "tun") || 32 | strings.HasPrefix(iface.Name, "docker0") || 33 | iface.Flags&net.FlagUp == 0 { // Filter out interfaces that are down 34 | continue 35 | } 36 | 37 | addrs, err := iface.Addrs() 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | for _, addr := range addrs { 43 | var ip net.IP 44 | switch v := addr.(type) { 45 | case *net.IPNet: 46 | ip = v.IP 47 | case *net.IPAddr: 48 | ip = v.IP 49 | } 50 | 51 | if ip == nil || ip.IsLoopback() { 52 | continue 53 | } 54 | 55 | // Filter out SLAAC addresses 56 | if ip.To4() == nil && IsSLAAC(ip.String()) { 57 | continue 58 | } 59 | 60 | networkInterface := registry.NetworkInterface{ 61 | Name: iface.Name, 62 | IPAddress: ip.String(), 63 | MACAddress: iface.HardwareAddr.String(), 64 | } 65 | networkInterfaces = append(networkInterfaces, networkInterface) 66 | } 67 | } 68 | 69 | return networkInterfaces, nil 70 | } 71 | -------------------------------------------------------------------------------- /internal/probe/probe_suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package probe_test 5 | 6 | import ( 7 | "context" 8 | "net/http" 9 | "testing" 10 | "time" 11 | 12 | "github.com/ironcore-dev/metal-operator/internal/probe" 13 | "github.com/ironcore-dev/metal-operator/internal/registry" 14 | . "github.com/onsi/ginkgo/v2" 15 | . "github.com/onsi/gomega" 16 | logf "sigs.k8s.io/controller-runtime/pkg/log" 17 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 18 | ) 19 | 20 | var ( 21 | probeAgent *probe.Agent 22 | registryServer *registry.Server 23 | 24 | registryAddr = ":30001" 25 | registryURL = "http://localhost:30001" 26 | systemUUID = "1234-5678" 27 | ) 28 | 29 | func TestRegistry(t *testing.T) { 30 | RegisterFailHandler(Fail) 31 | RunSpecs(t, "Registry Suite") 32 | } 33 | 34 | var _ = BeforeSuite(func() { 35 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 36 | 37 | ctx, cancel := context.WithCancel(context.Background()) 38 | DeferCleanup(cancel) 39 | 40 | // Initialize the registry 41 | registryServer = registry.NewServer(registryAddr) 42 | go func() { 43 | defer GinkgoRecover() 44 | Expect(registryServer.Start(ctx)).To(Succeed(), "failed to start registry agent") 45 | }() 46 | 47 | Eventually(func() error { 48 | _, err := http.Get(registryURL) 49 | return err 50 | }).Should(Succeed()) 51 | 52 | // Initialize your probe server 53 | probeAgent = probe.NewAgent(systemUUID, registryURL, 100*time.Millisecond) 54 | go func() { 55 | defer GinkgoRecover() 56 | Expect(probeAgent.Start(ctx)).To(Succeed(), "failed to start probe agent") 57 | }() 58 | }) 59 | -------------------------------------------------------------------------------- /internal/registry/registry_suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package registry_test 5 | 6 | import ( 7 | "context" 8 | "net/http" 9 | "testing" 10 | 11 | "github.com/ironcore-dev/metal-operator/internal/registry" 12 | . "github.com/onsi/ginkgo/v2" 13 | . "github.com/onsi/gomega" 14 | logf "sigs.k8s.io/controller-runtime/pkg/log" 15 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 16 | ) 17 | 18 | var ( 19 | server *registry.Server 20 | testServerURL = "http://localhost:30002" 21 | testServerAddr = ":30002" 22 | ) 23 | 24 | func TestRegistry(t *testing.T) { 25 | RegisterFailHandler(Fail) 26 | RunSpecs(t, "Registry Suite") 27 | } 28 | 29 | var _ = BeforeSuite(func() { 30 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 31 | 32 | ctx, cancel := context.WithCancel(context.Background()) 33 | DeferCleanup(cancel) 34 | 35 | server = registry.NewServer(testServerAddr) 36 | go func() { 37 | defer GinkgoRecover() 38 | Expect(server.Start(ctx)).To(Succeed(), "failed to start registry server") 39 | }() 40 | 41 | Eventually(func() error { 42 | _, err := http.Get(testServerURL) 43 | return err 44 | }).Should(Succeed()) 45 | }) 46 | -------------------------------------------------------------------------------- /internal/registry/server_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package registry_test 5 | 6 | import ( 7 | "bytes" 8 | "encoding/json" 9 | "fmt" 10 | "net/http" 11 | 12 | "github.com/ironcore-dev/metal-operator/internal/api/registry" 13 | . "github.com/onsi/ginkgo/v2" 14 | . "github.com/onsi/gomega" 15 | ) 16 | 17 | var _ = Describe("RegistryServer", func() { 18 | It("should store the system information successfully", func() { 19 | By("registering a system with it's endpoints") 20 | systemRegistrationPayload := registry.RegistrationPayload{ 21 | SystemUUID: "test-uuid", 22 | Data: registry.Server{ 23 | NetworkInterfaces: []registry.NetworkInterface{ 24 | { 25 | Name: "foo", 26 | IPAddress: "1.1.1.1", 27 | MACAddress: "abcd", 28 | }, 29 | }, 30 | }, 31 | } 32 | payload, err := json.Marshal(systemRegistrationPayload) 33 | Expect(err).NotTo(HaveOccurred()) 34 | 35 | By("performing a POST request to the /register endpoint") 36 | response, err := http.Post(fmt.Sprintf("%s/register", testServerURL), "application/json", bytes.NewBuffer(payload)) 37 | Expect(err).NotTo(HaveOccurred()) 38 | Expect(response.StatusCode).To(Equal(http.StatusCreated)) 39 | 40 | By("performing a GET request to the /systems/{uuid} endpoint") 41 | resp, err := http.Get(fmt.Sprintf("%s/systems/%s", testServerURL, systemRegistrationPayload.SystemUUID)) 42 | Expect(err).NotTo(HaveOccurred()) 43 | Expect(resp.StatusCode).To(Equal(http.StatusOK)) 44 | 45 | By("ensuring that the endpoints are correct") 46 | server := ®istry.Server{} 47 | Expect(json.NewDecoder(resp.Body).Decode(server)).NotTo(HaveOccurred()) 48 | Expect(server).To(Equal(®istry.Server{ 49 | NetworkInterfaces: []registry.NetworkInterface{ 50 | { 51 | Name: "foo", 52 | IPAddress: "1.1.1.1", 53 | MACAddress: "abcd", 54 | }, 55 | }, 56 | })) 57 | 58 | By("Ensuring that the server is removed from the registry") 59 | request, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/delete/%s", testServerURL, systemRegistrationPayload.SystemUUID), nil) 60 | Expect(err).NotTo(HaveOccurred()) 61 | c := &http.Client{} 62 | response, err = c.Do(request) 63 | Expect(err).NotTo(HaveOccurred()) 64 | Expect(response.StatusCode).To(Equal(http.StatusOK)) 65 | 66 | By("Ensuring that the server is removed from the registry") 67 | response, err = http.Get(fmt.Sprintf("%s/systems/%s", testServerURL, systemRegistrationPayload.SystemUUID)) 68 | Expect(err).NotTo(HaveOccurred()) 69 | Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: IronCore / Metal Operator 2 | repo_url: https://github.com/ironcore-dev/metal-operator/ 3 | edit_uri: edit/main/docs/ 4 | theme: 5 | icon: 6 | repo: fontawesome/brands/github 7 | features: 8 | - navigation.instant 9 | - navigation.tracking 10 | - navigation.expand 11 | - navigation.indexes 12 | - navigation.top 13 | name: material 14 | logo: https://raw.githubusercontent.com/ironcore-dev/ironcore/main/docs/assets/logo.svg 15 | favicon: https://raw.githubusercontent.com/ironcore-dev/ironcore/main/docs/assets/favicon/favicon.ico 16 | palette: 17 | - media: "(prefers-color-scheme)" 18 | toggle: 19 | icon: material/brightness-auto 20 | name: Switch to light mode 21 | - media: "(prefers-color-scheme: light)" 22 | scheme: default 23 | primary: white 24 | toggle: 25 | icon: material/brightness-7 26 | name: Switch to dark mode 27 | - media: "(prefers-color-scheme: dark)" 28 | scheme: slate 29 | primary: black 30 | toggle: 31 | icon: material/brightness-4 32 | name: Switch to light mode 33 | font: 34 | text: 'Work Sans' 35 | 36 | plugins: 37 | - search 38 | 39 | markdown_extensions: 40 | - pymdownx.highlight 41 | - pymdownx.superfences: 42 | custom_fences: 43 | - name: mermaid 44 | class: mermaid 45 | format: !!python/name:pymdownx.superfences.fence_code_format 46 | - pymdownx.snippets 47 | - codehilite 48 | 49 | nav: 50 | - Home: README.md 51 | - Architecture: architecture.md 52 | - Concepts: 53 | - Endpoints: concepts/endpoints.md 54 | - BMCs: concepts/bmcs.md 55 | - BMCSecrets: concepts/bmcsecrets.md 56 | - Servers: concepts/servers.md 57 | - ServerBootConfigurations: concepts/serverbootconfigurations.md 58 | - ServerClaims: concepts/serverclaims.md 59 | - ServerMaintenance: concepts/servermaintenance.md 60 | - BIOSSettings: concepts/biossettings.md 61 | - BIOSVersion: concepts/biosversion.md 62 | - BMCSettings: concepts/bmcsettings.md 63 | - BMCVersion: concepts/bmcversion.md 64 | - Usage: 65 | - metalctl: usage/metalctl.md 66 | - Development Guide: 67 | - Local Setup: development/dev_setup.md 68 | - Documentation: development/dev_docs.md 69 | - API Reference: api-reference/api.md 70 | 71 | extra: 72 | social: 73 | - icon: fontawesome/brands/github 74 | link: https://github.com/ironcore-dev/metal-operator 75 | -------------------------------------------------------------------------------- /scripts/kind-with-registry.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors 3 | #// SPDX-License-Identifier: Apache-2.0 4 | 5 | set -o errexit 6 | set -o nounset 7 | set -o pipefail 8 | 9 | 10 | REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 11 | KUBECTL=$REPO_ROOT/bin/kubectl 12 | 13 | # desired kind cluster name; default is "metal" 14 | KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-metal}" 15 | 16 | if [[ "$(kind get clusters)" =~ .*"${KIND_CLUSTER_NAME}".* ]]; then 17 | echo "cluster already exists, moving on" 18 | exit 0 19 | fi 20 | 21 | reg_name='kind-registry' 22 | reg_port="${KIND_REGISTRY_PORT:-5000}" 23 | 24 | # create registry container unless it already exists 25 | running="$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" 26 | if [ "${running}" != 'true' ]; then 27 | docker run -d --restart=always -p "127.0.0.1:${reg_port}:5000" --name "${reg_name}" registry:2 28 | fi 29 | 30 | # create a cluster with the local registry enabled in containerd 31 | cat <