From 1e7c9ba5cb30103d44df937af036f288e3b004ff Mon Sep 17 00:00:00 2001 From: Danny Bessems Date: Thu, 15 Jan 2026 09:58:01 +0000 Subject: [PATCH] Drop initial code --- .gitignore | 5 + .releaserc | 36 ++ CHANGELOG.md | 63 ++ CONTRIBUTING.md | 3 + README.md | 8 +- RELEASENOTES_IM-CNV-v100.md | 67 +++ as-vi-cnv-rig-operator@e1c9e3e68e8.zip | Bin 0 -> 946881 bytes bamboo-specs/bamboo.yaml | 99 ++++ bamboo-specs/prepare/import-variables.yaml | 40 ++ .../prepare/semantic-release-dryrun.yaml | 55 ++ bamboo-specs/release/semantic-release.yaml | 14 + bamboo-specs/validate/ansible-lint.yaml | 22 + bamboo-specs/validate/artifactory-ping.yaml | 10 + bamboo-specs/validate/docs-changesonly.yaml | 75 +++ bamboo-specs/validate/docs-dryrun.yaml | 63 ++ bamboo-specs/validate/docs.yaml | 61 ++ .../rke2-ubuntu-22.04-cloudinit-cp.yaml | 120 ++++ .../rke2-ubuntu-22.04-cloudinit.yaml | 52 ++ .../rke2-ubuntu-24.04-cloudinit-cp.yaml | 120 ++++ .../rke2-ubuntu-24.04-cloudinit.yaml | 52 ++ .../image/ubuntu-22.04-2025-11-25.yaml | 33 ++ .../image/ubuntu-24.04-2025-11-26.yaml | 33 ++ .../templates/rke2-ubuntu-22.04-8fzp2.yaml | 94 +++ .../rke2-ubuntu-22.04-secret-lbbfn.yaml | 18 + .../templates/rke2-ubuntu-22.04-template.yaml | 10 + .../rke2-ubuntu-24.04-secret-3bl5k.yaml | 18 + .../templates/rke2-ubuntu-24.04-template.yaml | 10 + .../templates/rke2-ubuntu-24.04-xrv5n.yaml | 94 +++ .../charts/cluster-templates/.helmignore | 21 + .../charts/cluster-templates/Chart.yaml | 22 + .../charts/cluster-templates/app-readme.md | 105 ++++ .../charts/cluster-templates/questions.yaml | 561 ++++++++++++++++++ .../cluster-templates/templates/NOTES.txt | 6 + .../cluster-templates/templates/_helpers.tpl | 62 ++ .../cluster-templates/templates/cluster.yaml | 438 ++++++++++++++ .../templates/clusterroletemplatebinding.yaml | 11 + .../templates/machinehealthcheck-master.yaml | 33 ++ .../templates/machinehealthcheck-worker.yaml | 25 + .../templates/managedcharts.yaml | 201 +++++++ .../templates/nodeconfig-aws.yaml | 251 ++++++++ .../templates/nodeconfig-azure.yaml | 95 +++ .../templates/nodeconfig-do.yaml | 103 ++++ .../templates/nodeconfig-elemental.yaml | 15 + .../templates/nodeconfig-harvester.yaml | 166 ++++++ .../templates/nodeconfig-vsphere.yaml | 97 +++ .../charts/cluster-templates/values.yaml | 433 ++++++++++++++ .../clusters/tpinf-1345-test-01/fleet.yaml | 13 + .../clusters/tpinf-1345-test-01/gitrepo.yaml | 21 + .../clusters/tpinf-1345-test-01/values.yaml | 365 ++++++++++++ .../.devcontainer/devcontainer.json | 25 + .../.devcontainer/post-install.sh | 23 + deploy/k8s-provisioner/.dockerignore | 11 + .../.github/workflows/lint.yml | 23 + .../.github/workflows/test-e2e.yml | 32 + .../.github/workflows/test.yml | 23 + deploy/k8s-provisioner/.gitignore | 30 + deploy/k8s-provisioner/.golangci.yml | 52 ++ deploy/k8s-provisioner/Dockerfile | 31 + deploy/k8s-provisioner/Makefile | 250 ++++++++ deploy/k8s-provisioner/PROJECT | 29 + deploy/k8s-provisioner/README.md | 135 +++++ .../api/v1alpha1/cluster_types.go | 56 ++ .../api/v1alpha1/groupversion_info.go | 36 ++ .../api/v1alpha1/infra_types.go | 50 ++ .../api/v1alpha1/zz_generated.deepcopy.go | 247 ++++++++ deploy/k8s-provisioner/cmd/main.go | 204 +++++++ .../k8sprovisioner.appstack.io_clusters.yaml | 98 +++ .../k8sprovisioner.appstack.io_infras.yaml | 84 +++ .../config/crd/kustomization.yaml | 17 + .../config/crd/kustomizeconfig.yaml | 19 + .../default/cert_metrics_manager_patch.yaml | 30 + .../config/default/kustomization.yaml | 234 ++++++++ .../config/default/manager_metrics_patch.yaml | 4 + .../config/default/metrics_service.yaml | 18 + .../config/manager/kustomization.yaml | 2 + .../config/manager/manager.yaml | 99 ++++ .../network-policy/allow-metrics-traffic.yaml | 27 + .../config/network-policy/kustomization.yaml | 2 + .../config/prometheus/kustomization.yaml | 11 + .../config/prometheus/monitor.yaml | 27 + .../config/prometheus/monitor_tls_patch.yaml | 19 + .../config/rbac/cluster_admin_role.yaml | 27 + .../config/rbac/cluster_editor_role.yaml | 33 ++ .../config/rbac/cluster_viewer_role.yaml | 29 + .../config/rbac/infra_admin_role.yaml | 27 + .../config/rbac/infra_editor_role.yaml | 33 ++ .../config/rbac/infra_viewer_role.yaml | 29 + .../config/rbac/kustomization.yaml | 31 + .../config/rbac/leader_election_role.yaml | 40 ++ .../rbac/leader_election_role_binding.yaml | 15 + .../config/rbac/metrics_auth_role.yaml | 17 + .../rbac/metrics_auth_role_binding.yaml | 12 + .../config/rbac/metrics_reader_role.yaml | 9 + deploy/k8s-provisioner/config/rbac/role.yaml | 46 ++ .../config/rbac/role_binding.yaml | 15 + .../config/rbac/service_account.yaml | 8 + .../k8sprovisioner_v1alpha1_cluster.yaml | 9 + .../k8sprovisioner_v1alpha1_infra.yaml | 9 + .../config/samples/kustomization.yaml | 5 + deploy/k8s-provisioner/go.mod | 161 +++++ deploy/k8s-provisioner/go.sum | 501 ++++++++++++++++ .../k8s-provisioner/hack/boilerplate.go.txt | 15 + .../internal/controller/cluster_controller.go | 157 +++++ .../controller/cluster_controller_test.go | 84 +++ .../internal/controller/suite_test.go | 116 ++++ .../internal/harvester/factory.go | 229 +++++++ .../k8s-provisioner/internal/helm/client.go | 126 ++++ .../internal/templates/base_values.yaml | 456 ++++++++++++++ .../templates/base_values_vsphere.yaml | 205 +++++++ .../internal/templates/embed.go | 6 + .../test/e2e/e2e_suite_test.go | 92 +++ deploy/k8s-provisioner/test/e2e/e2e_test.go | 337 +++++++++++ .../k8s-provisioner/test/local/cluster.yaml | 22 + .../k8s-provisioner/test/local/cluster2.yaml | 22 + deploy/k8s-provisioner/test/local/infra.yaml | 16 + .../test/local/local-vsphere-tst.yaml | 50 ++ deploy/k8s-provisioner/test/local/local.yaml | 32 + deploy/k8s-provisioner/test/utils/utils.go | 226 +++++++ deploy/rancher/README.md | 31 + deploy/rancher/capi/addon.yaml | 265 +++++++++ deploy/rancher/capi/harvester-addon.yaml | 90 +++ deploy/rancher/capi/helmchart.yaml | 294 +++++++++ deploy/rancher/capi/vcluster-v019.yaml | 255 ++++++++ deploy/rancher/capi/vcluster.yaml | 256 ++++++++ deploy/rancher/fleet/mgmt-dhcp.yaml | 475 +++++++++++++++ deploy/rancher/fleet/mgmt-static.yaml | 493 +++++++++++++++ deploy/rancher/helm/rancher_values_dhcp.yaml | 101 ++++ .../rancher/helm/rancher_values_static.yaml | 117 ++++ deploy/rancher/helm/rke2/Chart.yaml | 7 + .../helm/rke2/templates/rke2_cp_secret.yaml | 69 +++ .../helm/rke2/templates/rke2_cp_vm.yaml | 89 +++ .../rancher/helm/rke2/templates/rke2_lb.yaml | 46 ++ .../rke2/templates/rke2_worker_secret.yaml | 66 +++ .../helm/rke2/templates/rke2_worker_vm.yaml | 74 +++ deploy/rancher/helm/rke2/values.yaml | 92 +++ .../.devcontainer/devcontainer.json | 25 + .../.devcontainer/post-install.sh | 23 + deploy/rig-operator/.dockerignore | 11 + .../rig-operator/.github/workflows/lint.yml | 23 + .../.github/workflows/test-e2e.yml | 32 + .../rig-operator/.github/workflows/test.yml | 23 + deploy/rig-operator/.gitignore | 30 + deploy/rig-operator/.golangci.yml | 52 ++ deploy/rig-operator/Dockerfile | 31 + deploy/rig-operator/Makefile | 250 ++++++++ deploy/rig-operator/PROJECT | 46 ++ deploy/rig-operator/README-DEV.md | 141 +++++ deploy/rig-operator/README.md | 135 +++++ .../api/v1alpha1/clusterblueprint_types.go | 101 ++++ .../api/v1alpha1/groupversion_info.go | 36 ++ .../api/v1alpha1/harvesterblueprint_types.go | 59 ++ .../api/v1alpha1/infrablueprint_types.go | 112 ++++ .../api/v1alpha1/vsphereblueprint_types.go | 67 +++ .../api/v1alpha1/zz_generated.deepcopy.go | 469 +++++++++++++++ deploy/rig-operator/cmd/main.go | 213 +++++++ .../rig.appstack.io_clusterblueprints.yaml | 136 +++++ .../rig.appstack.io_harvesterblueprints.yaml | 82 +++ .../rig.appstack.io_infrablueprints.yaml | 146 +++++ .../rig.appstack.io_vsphereblueprints.yaml | 86 +++ .../config/crd/kustomization.yaml | 19 + .../config/crd/kustomizeconfig.yaml | 19 + .../default/cert_metrics_manager_patch.yaml | 30 + .../config/default/kustomization.yaml | 234 ++++++++ .../config/default/manager_metrics_patch.yaml | 4 + .../config/default/metrics_service.yaml | 18 + .../config/manager/kustomization.yaml | 2 + .../rig-operator/config/manager/manager.yaml | 99 ++++ .../network-policy/allow-metrics-traffic.yaml | 27 + .../config/network-policy/kustomization.yaml | 2 + .../config/prometheus/kustomization.yaml | 11 + .../config/prometheus/monitor.yaml | 27 + .../config/prometheus/monitor_tls_patch.yaml | 19 + .../rbac/clusterblueprint_admin_role.yaml | 27 + .../rbac/clusterblueprint_editor_role.yaml | 33 ++ .../rbac/clusterblueprint_viewer_role.yaml | 29 + .../rbac/harvesterblueprint_admin_role.yaml | 27 + .../rbac/harvesterblueprint_editor_role.yaml | 33 ++ .../rbac/harvesterblueprint_viewer_role.yaml | 29 + .../rbac/infrablueprint_admin_role.yaml | 27 + .../rbac/infrablueprint_editor_role.yaml | 33 ++ .../rbac/infrablueprint_viewer_role.yaml | 29 + .../config/rbac/kustomization.yaml | 37 ++ .../config/rbac/leader_election_role.yaml | 40 ++ .../rbac/leader_election_role_binding.yaml | 15 + .../config/rbac/metrics_auth_role.yaml | 17 + .../rbac/metrics_auth_role_binding.yaml | 12 + .../config/rbac/metrics_reader_role.yaml | 9 + deploy/rig-operator/config/rbac/role.yaml | 54 ++ .../config/rbac/role_binding.yaml | 15 + .../config/rbac/service_account.yaml | 8 + .../rbac/vsphereblueprint_admin_role.yaml | 27 + .../rbac/vsphereblueprint_editor_role.yaml | 33 ++ .../rbac/vsphereblueprint_viewer_role.yaml | 29 + .../config/samples/kustomization.yaml | 7 + .../rig_v1alpha1_clusterblueprint.yaml | 22 + .../rig_v1alpha1_harvesterblueprint.yaml | 14 + ...rig_v1alpha1_infrablueprint_harvester.yaml | 17 + .../rig_v1alpha1_vsphereblueprint.yaml | 9 + .../config/samples/vsphere_stack.yaml | 70 +++ .../docs/blueprint_orchestration.svg | 67 +++ .../rig-operator/docs/controllerflow.mermaid | 29 + deploy/rig-operator/docs/flow-diagram.svg | 67 +++ deploy/rig-operator/docs/uml.mermaid | 121 ++++ deploy/rig-operator/go.mod | 161 +++++ deploy/rig-operator/go.sum | 501 ++++++++++++++++ deploy/rig-operator/hack/boilerplate.go.txt | 15 + .../rig-operator/internal/builder/master.go | 134 +++++ .../controller/clusterblueprint_controller.go | 291 +++++++++ .../clusterblueprint_controller_test.go | 84 +++ .../controller/infrablueprint_controller.go | 128 ++++ .../infrablueprint_controller_test.go | 84 +++ .../internal/controller/suite_test.go | 116 ++++ deploy/rig-operator/internal/helm/client.go | 126 ++++ .../internal/provider/harvester/credential.go | 176 ++++++ .../internal/provider/harvester/manager.go | 126 ++++ .../internal/provider/harvester/strategy.go | 140 +++++ .../internal/provider/interface.go | 16 + .../internal/provider/vsphere/strategy.go | 138 +++++ .../internal/templates/harvester/embed.go | 69 +++ .../internal/templates/harvester/values.yaml | 456 ++++++++++++++ .../internal/templates/vsphere/embed.go | 77 +++ .../internal/templates/vsphere/values.yaml | 202 +++++++ deploy/rig-operator/misc/patch-default-sa | 11 + .../rig-operator/test/e2e/e2e_suite_test.go | 92 +++ deploy/rig-operator/test/e2e/e2e_test.go | 337 +++++++++++ deploy/rig-operator/test/utils/utils.go | 226 +++++++ docs/TEST.md | 9 + docs/_changelog.md | 9 + 228 files changed, 19883 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 .releaserc create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100755 RELEASENOTES_IM-CNV-v100.md create mode 100755 as-vi-cnv-rig-operator@e1c9e3e68e8.zip create mode 100644 bamboo-specs/bamboo.yaml create mode 100644 bamboo-specs/prepare/import-variables.yaml create mode 100644 bamboo-specs/prepare/semantic-release-dryrun.yaml create mode 100644 bamboo-specs/release/semantic-release.yaml create mode 100644 bamboo-specs/validate/ansible-lint.yaml create mode 100644 bamboo-specs/validate/artifactory-ping.yaml create mode 100644 bamboo-specs/validate/docs-changesonly.yaml create mode 100644 bamboo-specs/validate/docs-dryrun.yaml create mode 100644 bamboo-specs/validate/docs.yaml create mode 100644 deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit-cp.yaml create mode 100755 deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit.yaml create mode 100644 deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit-cp.yaml create mode 100755 deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit.yaml create mode 100755 deploy/harvester/image/ubuntu-22.04-2025-11-25.yaml create mode 100755 deploy/harvester/image/ubuntu-24.04-2025-11-26.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-22.04-8fzp2.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-22.04-secret-lbbfn.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-22.04-template.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-24.04-secret-3bl5k.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-24.04-template.yaml create mode 100755 deploy/harvester/templates/rke2-ubuntu-24.04-xrv5n.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/.helmignore create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/Chart.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/app-readme.md create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/questions.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/NOTES.txt create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/_helpers.tpl create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/cluster.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/clusterroletemplatebinding.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-master.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-worker.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/managedcharts.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-aws.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-azure.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-do.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-elemental.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-harvester.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-vsphere.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/values.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/fleet.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/gitrepo.yaml create mode 100644 deploy/iac-cnv/clusters/tpinf-1345-test-01/values.yaml create mode 100644 deploy/k8s-provisioner/.devcontainer/devcontainer.json create mode 100644 deploy/k8s-provisioner/.devcontainer/post-install.sh create mode 100644 deploy/k8s-provisioner/.dockerignore create mode 100644 deploy/k8s-provisioner/.github/workflows/lint.yml create mode 100644 deploy/k8s-provisioner/.github/workflows/test-e2e.yml create mode 100644 deploy/k8s-provisioner/.github/workflows/test.yml create mode 100644 deploy/k8s-provisioner/.gitignore create mode 100644 deploy/k8s-provisioner/.golangci.yml create mode 100644 deploy/k8s-provisioner/Dockerfile create mode 100644 deploy/k8s-provisioner/Makefile create mode 100644 deploy/k8s-provisioner/PROJECT create mode 100644 deploy/k8s-provisioner/README.md create mode 100644 deploy/k8s-provisioner/api/v1alpha1/cluster_types.go create mode 100644 deploy/k8s-provisioner/api/v1alpha1/groupversion_info.go create mode 100644 deploy/k8s-provisioner/api/v1alpha1/infra_types.go create mode 100644 deploy/k8s-provisioner/api/v1alpha1/zz_generated.deepcopy.go create mode 100644 deploy/k8s-provisioner/cmd/main.go create mode 100644 deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_clusters.yaml create mode 100644 deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_infras.yaml create mode 100644 deploy/k8s-provisioner/config/crd/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/crd/kustomizeconfig.yaml create mode 100644 deploy/k8s-provisioner/config/default/cert_metrics_manager_patch.yaml create mode 100644 deploy/k8s-provisioner/config/default/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/default/manager_metrics_patch.yaml create mode 100644 deploy/k8s-provisioner/config/default/metrics_service.yaml create mode 100644 deploy/k8s-provisioner/config/manager/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/manager/manager.yaml create mode 100644 deploy/k8s-provisioner/config/network-policy/allow-metrics-traffic.yaml create mode 100644 deploy/k8s-provisioner/config/network-policy/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/prometheus/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/prometheus/monitor.yaml create mode 100644 deploy/k8s-provisioner/config/prometheus/monitor_tls_patch.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/cluster_admin_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/cluster_editor_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/cluster_viewer_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/infra_admin_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/infra_editor_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/infra_viewer_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/kustomization.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/leader_election_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/leader_election_role_binding.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/metrics_auth_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/metrics_auth_role_binding.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/metrics_reader_role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/role.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/role_binding.yaml create mode 100644 deploy/k8s-provisioner/config/rbac/service_account.yaml create mode 100644 deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_cluster.yaml create mode 100644 deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_infra.yaml create mode 100644 deploy/k8s-provisioner/config/samples/kustomization.yaml create mode 100644 deploy/k8s-provisioner/go.mod create mode 100644 deploy/k8s-provisioner/go.sum create mode 100644 deploy/k8s-provisioner/hack/boilerplate.go.txt create mode 100644 deploy/k8s-provisioner/internal/controller/cluster_controller.go create mode 100644 deploy/k8s-provisioner/internal/controller/cluster_controller_test.go create mode 100644 deploy/k8s-provisioner/internal/controller/suite_test.go create mode 100644 deploy/k8s-provisioner/internal/harvester/factory.go create mode 100644 deploy/k8s-provisioner/internal/helm/client.go create mode 100644 deploy/k8s-provisioner/internal/templates/base_values.yaml create mode 100644 deploy/k8s-provisioner/internal/templates/base_values_vsphere.yaml create mode 100644 deploy/k8s-provisioner/internal/templates/embed.go create mode 100644 deploy/k8s-provisioner/test/e2e/e2e_suite_test.go create mode 100644 deploy/k8s-provisioner/test/e2e/e2e_test.go create mode 100644 deploy/k8s-provisioner/test/local/cluster.yaml create mode 100644 deploy/k8s-provisioner/test/local/cluster2.yaml create mode 100644 deploy/k8s-provisioner/test/local/infra.yaml create mode 100644 deploy/k8s-provisioner/test/local/local-vsphere-tst.yaml create mode 100644 deploy/k8s-provisioner/test/local/local.yaml create mode 100644 deploy/k8s-provisioner/test/utils/utils.go create mode 100644 deploy/rancher/README.md create mode 100644 deploy/rancher/capi/addon.yaml create mode 100644 deploy/rancher/capi/harvester-addon.yaml create mode 100644 deploy/rancher/capi/helmchart.yaml create mode 100644 deploy/rancher/capi/vcluster-v019.yaml create mode 100644 deploy/rancher/capi/vcluster.yaml create mode 100644 deploy/rancher/fleet/mgmt-dhcp.yaml create mode 100644 deploy/rancher/fleet/mgmt-static.yaml create mode 100644 deploy/rancher/helm/rancher_values_dhcp.yaml create mode 100644 deploy/rancher/helm/rancher_values_static.yaml create mode 100644 deploy/rancher/helm/rke2/Chart.yaml create mode 100644 deploy/rancher/helm/rke2/templates/rke2_cp_secret.yaml create mode 100644 deploy/rancher/helm/rke2/templates/rke2_cp_vm.yaml create mode 100644 deploy/rancher/helm/rke2/templates/rke2_lb.yaml create mode 100644 deploy/rancher/helm/rke2/templates/rke2_worker_secret.yaml create mode 100644 deploy/rancher/helm/rke2/templates/rke2_worker_vm.yaml create mode 100644 deploy/rancher/helm/rke2/values.yaml create mode 100644 deploy/rig-operator/.devcontainer/devcontainer.json create mode 100644 deploy/rig-operator/.devcontainer/post-install.sh create mode 100644 deploy/rig-operator/.dockerignore create mode 100644 deploy/rig-operator/.github/workflows/lint.yml create mode 100644 deploy/rig-operator/.github/workflows/test-e2e.yml create mode 100644 deploy/rig-operator/.github/workflows/test.yml create mode 100644 deploy/rig-operator/.gitignore create mode 100644 deploy/rig-operator/.golangci.yml create mode 100644 deploy/rig-operator/Dockerfile create mode 100644 deploy/rig-operator/Makefile create mode 100644 deploy/rig-operator/PROJECT create mode 100644 deploy/rig-operator/README-DEV.md create mode 100644 deploy/rig-operator/README.md create mode 100644 deploy/rig-operator/api/v1alpha1/clusterblueprint_types.go create mode 100644 deploy/rig-operator/api/v1alpha1/groupversion_info.go create mode 100644 deploy/rig-operator/api/v1alpha1/harvesterblueprint_types.go create mode 100644 deploy/rig-operator/api/v1alpha1/infrablueprint_types.go create mode 100644 deploy/rig-operator/api/v1alpha1/vsphereblueprint_types.go create mode 100644 deploy/rig-operator/api/v1alpha1/zz_generated.deepcopy.go create mode 100644 deploy/rig-operator/cmd/main.go create mode 100644 deploy/rig-operator/config/crd/bases/rig.appstack.io_clusterblueprints.yaml create mode 100644 deploy/rig-operator/config/crd/bases/rig.appstack.io_harvesterblueprints.yaml create mode 100644 deploy/rig-operator/config/crd/bases/rig.appstack.io_infrablueprints.yaml create mode 100644 deploy/rig-operator/config/crd/bases/rig.appstack.io_vsphereblueprints.yaml create mode 100644 deploy/rig-operator/config/crd/kustomization.yaml create mode 100644 deploy/rig-operator/config/crd/kustomizeconfig.yaml create mode 100644 deploy/rig-operator/config/default/cert_metrics_manager_patch.yaml create mode 100644 deploy/rig-operator/config/default/kustomization.yaml create mode 100644 deploy/rig-operator/config/default/manager_metrics_patch.yaml create mode 100644 deploy/rig-operator/config/default/metrics_service.yaml create mode 100644 deploy/rig-operator/config/manager/kustomization.yaml create mode 100644 deploy/rig-operator/config/manager/manager.yaml create mode 100644 deploy/rig-operator/config/network-policy/allow-metrics-traffic.yaml create mode 100644 deploy/rig-operator/config/network-policy/kustomization.yaml create mode 100644 deploy/rig-operator/config/prometheus/kustomization.yaml create mode 100644 deploy/rig-operator/config/prometheus/monitor.yaml create mode 100644 deploy/rig-operator/config/prometheus/monitor_tls_patch.yaml create mode 100644 deploy/rig-operator/config/rbac/clusterblueprint_admin_role.yaml create mode 100644 deploy/rig-operator/config/rbac/clusterblueprint_editor_role.yaml create mode 100644 deploy/rig-operator/config/rbac/clusterblueprint_viewer_role.yaml create mode 100644 deploy/rig-operator/config/rbac/harvesterblueprint_admin_role.yaml create mode 100644 deploy/rig-operator/config/rbac/harvesterblueprint_editor_role.yaml create mode 100644 deploy/rig-operator/config/rbac/harvesterblueprint_viewer_role.yaml create mode 100644 deploy/rig-operator/config/rbac/infrablueprint_admin_role.yaml create mode 100644 deploy/rig-operator/config/rbac/infrablueprint_editor_role.yaml create mode 100644 deploy/rig-operator/config/rbac/infrablueprint_viewer_role.yaml create mode 100644 deploy/rig-operator/config/rbac/kustomization.yaml create mode 100644 deploy/rig-operator/config/rbac/leader_election_role.yaml create mode 100644 deploy/rig-operator/config/rbac/leader_election_role_binding.yaml create mode 100644 deploy/rig-operator/config/rbac/metrics_auth_role.yaml create mode 100644 deploy/rig-operator/config/rbac/metrics_auth_role_binding.yaml create mode 100644 deploy/rig-operator/config/rbac/metrics_reader_role.yaml create mode 100644 deploy/rig-operator/config/rbac/role.yaml create mode 100644 deploy/rig-operator/config/rbac/role_binding.yaml create mode 100644 deploy/rig-operator/config/rbac/service_account.yaml create mode 100644 deploy/rig-operator/config/rbac/vsphereblueprint_admin_role.yaml create mode 100644 deploy/rig-operator/config/rbac/vsphereblueprint_editor_role.yaml create mode 100644 deploy/rig-operator/config/rbac/vsphereblueprint_viewer_role.yaml create mode 100644 deploy/rig-operator/config/samples/kustomization.yaml create mode 100644 deploy/rig-operator/config/samples/rig_v1alpha1_clusterblueprint.yaml create mode 100644 deploy/rig-operator/config/samples/rig_v1alpha1_harvesterblueprint.yaml create mode 100644 deploy/rig-operator/config/samples/rig_v1alpha1_infrablueprint_harvester.yaml create mode 100644 deploy/rig-operator/config/samples/rig_v1alpha1_vsphereblueprint.yaml create mode 100644 deploy/rig-operator/config/samples/vsphere_stack.yaml create mode 100644 deploy/rig-operator/docs/blueprint_orchestration.svg create mode 100644 deploy/rig-operator/docs/controllerflow.mermaid create mode 100644 deploy/rig-operator/docs/flow-diagram.svg create mode 100644 deploy/rig-operator/docs/uml.mermaid create mode 100644 deploy/rig-operator/go.mod create mode 100644 deploy/rig-operator/go.sum create mode 100644 deploy/rig-operator/hack/boilerplate.go.txt create mode 100644 deploy/rig-operator/internal/builder/master.go create mode 100644 deploy/rig-operator/internal/controller/clusterblueprint_controller.go create mode 100644 deploy/rig-operator/internal/controller/clusterblueprint_controller_test.go create mode 100644 deploy/rig-operator/internal/controller/infrablueprint_controller.go create mode 100644 deploy/rig-operator/internal/controller/infrablueprint_controller_test.go create mode 100644 deploy/rig-operator/internal/controller/suite_test.go create mode 100644 deploy/rig-operator/internal/helm/client.go create mode 100644 deploy/rig-operator/internal/provider/harvester/credential.go create mode 100644 deploy/rig-operator/internal/provider/harvester/manager.go create mode 100644 deploy/rig-operator/internal/provider/harvester/strategy.go create mode 100644 deploy/rig-operator/internal/provider/interface.go create mode 100644 deploy/rig-operator/internal/provider/vsphere/strategy.go create mode 100644 deploy/rig-operator/internal/templates/harvester/embed.go create mode 100644 deploy/rig-operator/internal/templates/harvester/values.yaml create mode 100644 deploy/rig-operator/internal/templates/vsphere/embed.go create mode 100644 deploy/rig-operator/internal/templates/vsphere/values.yaml create mode 100755 deploy/rig-operator/misc/patch-default-sa create mode 100644 deploy/rig-operator/test/e2e/e2e_suite_test.go create mode 100644 deploy/rig-operator/test/e2e/e2e_test.go create mode 100644 deploy/rig-operator/test/utils/utils.go create mode 100644 docs/TEST.md create mode 100644 docs/_changelog.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0df08ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode +ignore +.version +*.log +*.tmp \ No newline at end of file diff --git a/.releaserc b/.releaserc new file mode 100644 index 0000000..a19b60b --- /dev/null +++ b/.releaserc @@ -0,0 +1,36 @@ +branches: + - name: main + channel: stable + + - name: development + prerelease: rc + channel: beta + + +plugins: + - - "@semantic-release/commit-analyzer" + - releaseRules: + - type: backport + release: patch + + - - "@semantic-release/release-notes-generator" + - presetConfig: + types: + - type: backport + section: Backports + - type: feat + section: Features + - type: fix + section: Bug Fixes + + + - - "@semantic-release/changelog" + - changelogFile: CHANGELOG.md + + - - "@semantic-release/git" + - assets: + - CHANGELOG.md + message: "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + +preset: conventionalcommits +ci: false \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..04514c6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,63 @@ +## [1.0.0-rc.4](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/compare/v1.0.0-rc.3...v1.0.0-rc.4) (2026-01-07) + + +### Features + +* TPINF-871 - README.md and CAPI deployment added. ([792907b](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/792907b901dc9d407429ac00fa4f885864fea628)) +* TPINF-1346 - created RKE2 CloudInit templates for CP nodes ([c04cd9a](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/c04cd9a902e1cbf3b64d0b91573584f87ef3c17e)) +* TPINF-1346 - CronJob to patch default SA in namespaces ([7687bca](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/7687bca1be97ebc3794bf492321ddb6788e57f45)) +* TPINF-1346 - patch default sa to not mount token ([d5b880d](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/d5b880dd53a9f4754ed75f6c654ae9de0542edce)) +* TPINF-871 - FLeet DHCP deployment changed to dhcp ([e02ccc7](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/e02ccc7cbb42af3ed5b8680494ef5609c23ce097)) +* TPINF-871 - Added capi attempts to boot Rancger in Harvester ([9b5d74c](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/9b5d74cf3811fb0e165231d573af070202ae37db)) +* TPINF-871 - Attempt to upgarde vcluster chart to v0.30.1 ([520f23b](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/520f23b863a6eb85a8b5b17f468c05a23c177c14)) +* TPINF-871 - Default namespace commented in LB definition ([29ec3f0](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/29ec3f0377329aa63423029f63ea5a58bff9e2ab)) +* TPINF-871 - Helm chart config split and Fleet update ([618d16f](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/618d16fefccc996660c1b689bf13fcf30bb4c8dc)) +* TPINF-871 - make Helm deployment namespace configurable ([f125160](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/f125160031c538cd39d35dab78471ca61e7f04cd)) +* TPINF-871 - RGS Helm chart updated to RnD environment ([1280bef](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/1280befc775aff54e97a82f8da4f4202d5c534ad)) + +## [1.0.0-rc.3](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/compare/v1.0.0-rc.2...v1.0.0-rc.3) (2025-12-16) + + +### Features + +* TPINF-1093 - Template and cloudinit for Ubuntu 24.04 ([93ca097](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/93ca097226c0c87a2c8c382535f40a2be81b7383)) + +## [1.0.0-rc.2](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/compare/v1.0.0-rc.1...v1.0.0-rc.2) (2025-12-03) + + +### Features + +* TPINF-1093 - Virtualization baselines ([b989a59](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/b989a5954fc97c4d1e7838e7775753ecaba7918f)) + +## 1.0.0-rc.1 (2025-10-08) + + +### Features + +* Inital commit of CI/Docs ([95cc946](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/95cc946ed13fe45a30ed3bdce2a9368124d9e5fc)) + +## 1.0.0-rc.1 (2025-10-08) + + +### Features + +* Inital commit of CI/Docs ([95cc946](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/95cc946ed13fe45a30ed3bdce2a9368124d9e5fc)) + +## 1.0.0-rc.1 (2025-10-08) + + +### Features + +* Inital commit of CI/Docs ([95cc946](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/95cc946ed13fe45a30ed3bdce2a9368124d9e5fc)) + +## 1.0.0-rc.1 (2025-10-07) + + +### Features + +* Semantic RC release with document integration ([f9ea626](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/f9ea6266acf2cabe57b76cfb88ee7a39891bd31d)) + + +### Bug Fixes + +* Dummy commit to trigger semantic-release ([c0b12ed](https://devstash.vanderlande.com/scm/ittp/as-vi-cnv/commit/c0b12ed052eb1baf27b89454c1265857e354899a)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6138a2c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing Guidelines + +[Contribution Wiki](https://devcolla.vanderlande.com/display/ITTP/How+to+contribute) diff --git a/README.md b/README.md index f966f72..cf67d0c 100644 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ - \ No newline at end of file + + + + +# {{ release_version }} - TEST + +TEST123 diff --git a/RELEASENOTES_IM-CNV-v100.md b/RELEASENOTES_IM-CNV-v100.md new file mode 100755 index 0000000..82216ed --- /dev/null +++ b/RELEASENOTES_IM-CNV-v100.md @@ -0,0 +1,67 @@ +# 🚀 Release Notes - IM Cloud Native Virtualization v1.0.0 (im-cnv) + +**Release Date:** 2025-12-01 + +--- + +## 📘 Summary +IM Cloud Native Virtualization v1.0.0 is based on SUSE Virtualization (previously known as Harvester) and offers virtualization as well as container orchestration. + +Within Vanderlande this is the practical successor to Container Platform (CP2/CP3) and VI_IT_VIRTUALIZATION. + +Capabilities of IM-CNV are effectively the same: running any modern Operating System in virtual machines, as well as Kubernetes orchestration of workload clusters enable all of Vanderlande's existing Modules to be run. +There are however, key differences in underlying technology and implementation specifics, which are highlighted below: + +- ### Persistent Storage location (*inside* vs *outside* Kubernetes cluster) + - *CP2/CP3*: Persistent storage (provided through Longhorn) was stored *within* Kubernetes clusters on designated "worker-storage" nodes. + - *IM-CNV*: Respective volumes and replicas (still provided through Longhorn - _though_ seemingly with different `StorageClass` names) are now stored directly on the Hypervisor nodes. + + **There are *no* dedicated storage node pools; cluster nodes can now be reprovisioned _without_ extensive wait periods for replication to finish.** +- ### Services of type `LoadBalancer` managed by different controllers + - *CP2/CP3*: Services of type `LoadBalancer` were managed by **MetalLB**; exposing MetalLB-specific annotations for configuration. + - *IM-CNV*: Services of type `LoadBalancer` are managed by **Harvester's integrated Cloud Controller Manager**. + + **Both load balancers differ in the OSI layers they operate in (MetalLB: Layer 2 and 3, Harvester CMM: Layer 4), however feature parity is maintained for common use cases within Vanderlande.** + ***NOTE:** IP-address pinning is currently not supported through annotations and requires explicit administrator intervention.* +- ### Virtual Machine templating + - *VI_IT_VIRTUALIZATION*: Virtual machine template export & import supported in the format `ova`/`ovf`; virtual machine's disks were stored as `vmdk` files. + - *IM-CNV*: No virtual machine template export & import functionality; virtual machines can be created based on disk images in the formats `qcow2`, `raw`. + + **Harvester includes an addon to connect to a vCenter instance to import virtual machines directly; negating the need to export & import with an intermediate file format.** + + +## 🔗 Related Links +- ~~**Release Bundle**: [Link](#TBD)~~ +- ~~**Changelog**: [Link](#TBD)~~ +- **Jira Release**: [Link](https://devtrack.vanderlande.com/projects/TPINF/versions/144780) +- ~~**SBOM**: [Link](#TBD)~~ +- **Test Results**: [Link](https://devtrack.vanderlande.com/secure/attachment/1179276/VI_IT_VI_IT_CNV-1_0_0.pdf) + +## 🧩 Compatibility Matrix +- Supported Kubernetes Versions: + - **RKE2**: 1.31, 1.32, 1.33 + - **K3S** _(experimental)_: 1.31, 1.32, 1.33 + +- Supported Guest Operating Versions: + - **Suse Linux Enterprise Server**: 15 SP6, 15 SP7 + - **Suse Linux Enterprise Micro**: 6.0, 6.1 + - **Ubuntu**: 22.04, 24.04 + - **RHEL**: 9, 10 + - **Windows**: Windows 11, Windows Server 2025 (up to and including) + +- Bundled Component Versions: + - **Rancher**: v2.12 + - **Longhorn**: v1.9.1 + +## ⚠️ Breaking Changes +Refer to aforementioned key differences to understand how migration to IM-CNV might affect your workloads. + +## 🔄 Migration / Upgrade Steps +_There is no upgrade path from any version of Container Platform; Kubernetes clusters and respective workloads need to be reprovisioned_ + +## 📦 Delivery Artifacts +- **Installation Files:** + - [Installation Manual](https://vanderlande.sharepoint.com/:w:/r/sites/T_Technolo-17-TeamAppStackEdgeComputing/Shared%20Documents/Team%20Application%20Stack/Cloud%20Native%20Virtualization%20Installation%20Manual.docx?d=w143df45494e7454b9c00247ac76c3dc3&csf=1&web=1&e=tnswwo) + - [Operator Manual](https://vanderlande.sharepoint.com/:w:/r/sites/T_Technolo-17-TeamAppStackEdgeComputing/Shared%20Documents/Team%20Application%20Stack/Cloud%20Native%20Virtualization%20Operator%20Manual.docx?d=w5b544952345b40d9ba0e5db01a3f703c&csf=1&web=1&e=XTXc4M) + +--- diff --git a/as-vi-cnv-rig-operator@e1c9e3e68e8.zip b/as-vi-cnv-rig-operator@e1c9e3e68e8.zip new file mode 100755 index 0000000000000000000000000000000000000000..ab19ab705f53eeab7d33dd61428f35d6fec38565 GIT binary patch literal 946881 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

OIb>yHk@#}Ye8)@=y}O` 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

v**Ax=9laaW1JqRJe{|J=KemK z^1e_%PL(>V!<*%&k?~f{8Q9vCh$0cXh6wLGOhrQF@rnBov)s;n=jfh_R zZSmGwHXPVM*VLIRrtYgm{pYOI^M38&#UmcASL{449_Yj;kzJWrGX`l>O4FEz=b9I% zg_r(J`Kd;KcJm9@)7 zz&u9BepADAP}nA}=UMgBT+zDi<%hk8&B8Xfdn?aYrmi=KxYoq-=2o}g{$_N~hHZ{c z(^BcK%d%#h2j=?3!0s zZYPdPdsr&Hwhkw^hIP?@>9ttm?HB0j)og1vjk$W&n_NoM9N!*1vESOMs>!7~tgo)c z`Iv9>WZP2nT;eU@RnIohK+cD2=g4w;Fd7s`7j~L9n)^|B2ktQ|8 zWj(I%f@n)xwVhvHlHqK3eY(4Rne+YBX&;k#ZoF+{=sp1z@>_A|e7|I?tP63bov-E2 zDC#jQb=-ih6P6{<^GuN09SAZ+EgNas1I44yUHInY;EI^z!i7-eV$&-%Z5-or*sP$< znGIJTnWyC6ixMWPl5G^--%YX=G}I6!qe{5q31W}ZoixuhO%SLV}XdtU;{_%wh_wV9BK|fs3d_a^fWT3eXg44yooz(r4EkQGCSqh4x|wN2qX@Vy#)x02Az2*l5UH> zDKZeLC5$V|w}v!A8hEj|^0N}UCSVL8rG;lZ<5WO9F3A)(80)api|oD96j%1%L5VMl zx;~e0rAoDQ5>dn!_KQr>HDR){4V8qp@{oXycFTsn`QmnT z?KN}E&jmN_hhd?JL-mM7ZzJ^X!-Bu%bdyZGE=k(HAX%twUdSLfRIXb1euNIqj>{)sG7>zbbs@mgrqO^LojvsdIO3pgOR17x+XH1CzxX_rqNIa?0h5{LT_r|uizjNS_} z+6UzxrZTV-32DI8e%q;G%Ksjp`GU1z={yU_s(7ykJi3&3!Ay+CGWPb{D4^HA6OJw56kKGPdE@)A4@!p7IPbsnC8uA&bZk0UwQLR$PpKmOnORV$x^ z93Pes zm~PQZl!k=3=IFxs1D4kOn_oxp{^nO<(tyAC)nMYs30U$szveq0Lmm9ZuQ@R!Hn0Ht z^RP0CF{j(M@ti9ofAeelH@~uoAP%B?7Kk_)^g#D8bii0GeZj!Y)tRQ zby+Gvo}w4CK(hyCzB7Z|WW*yNsGRMSzDuA6@iTz|a57N*_Ex8lz}SHp+&R%*eIg%` z(_vf-08%hlwjMC}`paKyzx@@g_S;{Pos*?^^NR*mbDTu^#_b?IP{j1)@zXdIfIy%` zNB{CyRL~SjD|YdKaAD9q#=Attp=w9mjo+mp>Qm6pPEH;sDj{@oxj?0+eFvs}zb69& z-P$h6Gk}C`O|4%iJA-H31rTOWwCB|FDnyA0i|Qi0xiTF;hgwyErCw*SOLzuRS0DH( z{FgMeG{y@8+%tmDRzyoplwu5ky!+)=#`ov7sb9`ue!jrVFlEPdL>?t=sG#ofZh<-3 z{6U0eR^gZxO)CxxI$*4?OOKBKu8o1_1cM`p;t)6|UJLd+1Kms`@gJw`@yVK|#HKex zzcWjIYd&U1Q*ilBkYH-+2nc{xI=gc4j@FjwWtQnn@4=>ZuENnnZoCjIJn9}#&TjdY z8eG5zgk_a(@QNDct626hv2_T?{t9d+Ex zG(#v{ZdC!uF-a#I>MOBCpTi9V$GGm9vMQTNLn6yFJ$~7%cX4)>!;XDF&$*A98oLz> zi6ddd9BsG}pM$(dF_DFvFF#AnSSS}vH%jMs#4<)x-zo@k>z86RDnfm()w>5~L)YJ? z?*O$i(S^W&_4iju{*4>=@<}`jPWS;L1$WhBimviV76OqiKpds;i)id9!C#%=*0|JX zd@*GW=k4Z(@|=`V%c9}Qto8RS;fLA)3IOTo*;Pt`dM zK^1T~Og)tVoVMo|Q5aI2{K2Ni7yi;o|Am^E9W>QS@boa)a*r+tk#yHDR!G%^uQllC1kF>z zn6dns4+eg<%cg0Dxq^dMK44YF%$Z!lP&#;}Sk?1m$(-43GQ5a>7~X4?1E$$`Sw36S zcDX)mMa&89%47iy+PfBk*-{bw36(fCOhX7uDcNzV4f*4jsl`@*k6yP5h;GVJ3nWJU zTy~V z9wp?xitoGp*h?%k>WAppQFXqY2XEGFfs<~)RI&zuSk5(bE9X97{&w=?4&_hHeEb#b z{mr!PEt8)*RbdO(;ag#(g+Pc{#<$NG!vfXy`0>2qE+TdI(pisZM%#|x-EWz$Ghu%L z?3fPyUjUnkwD%8y-2*)S23Y?xF!-cwqQ3xEb48{|dmWsGE>0&`Avt9H2t=Jg@ za70&Onp&`+KDZdk9rfuEfu~eD(yQ8<>u{6nXFu$`p%z!TJhxn#DH)f_C zxh(?OK)8Fv5G5EwPpPpL`ftL>UXh$8n~kVip+`RiI7!%eZZv2z^EE-k2?fAu2V@BP`-5jLa_D0(Rvb?EK$JdPsQ1517l*2N&9XyEy!15gpKWt zKuH0|*HBE9O=&4BnSCn}znLd9kHV#x)p|Cg!r&4rw{9&+!8@xbWNs3xj&P+p;zWqKYM~qN_77eyY`AeG)Eb znc^r{Hxn52IyKExySRDa8Oi4$LE@0S=}!}M2FC;$o+Z2cphL8pO$6taJ)B&?gdvI;`(j#0n?N4q zVhK`F$4nk&66zYm<1pf1#3I2X$A|(J*NQn>H&^$>+|`-=ge6Wvd*tFkS<&9ByegKS zsP5U_PT#fc(1UQ%DbNq&4&z}S;Ee-L*3gNP9+UWze1(}1YI=%lzS(&c2RgJTq`M*T z@f-ozaYDtY+bs?yqc8m!ST^qMP|wl0ZeBH`yY)hVehzo3Fylw#29*{YXf_wWr?wqe zxK-}_;=2#4RB~HXD4{AeVV^sYnxUa5)4eVvdB9|B7!2ZN$+{0d6#qwBFq-ZZ#H zXJHB56M)l@86M5Z)QKU|TdI`MmWMtFKR@sjq8T?wol7HTbF^?bfRvW%Qc!@mw z9}jnptM}0_OnS}o-PX;&UNe}qR;n@rX1DR}N@=bO+n7!@k>9`irO}=jq#ATk9$z8s z#{ITmf3UId*KqxrN^`3Rp&%$PN)&}E7^{XdBtF|o@_DBNwwEcrAXQAdc;**?xIR2)VJ+{v^La#fB~Hr0Ct1uj#-B zBA{bOU|2B|)&)EfsGgvWOhA7P3P3Un)JY=*bD;RumzEDv?4`H?T+dL&?Y7-*0wm@c&EfZU3~+Inx(;XxoJ0GT)P z0M^t5yLANaEz~P9L5=Pf{44Rq(8h8_N0GZEgXNd5X-2vUTeF1|LOilw|hh3Pl5X&*ALR zdjJ9;sNg{h&}Xz9jRj6<_2Mne(cVwh6c6AF!3+oI65f8X;LERGa_$}P@zMiLfQmy- zgc?MH2yyl9MfPEhi1O2-jSSP}4~%x-)i4j>uU>keHywPHBooar6t<9PFjek@Gl0vS z!s3P)-b`Zcr#THrGdO7iCh3*rRADR&LJ{Kw&w&~~-X(xPy$vbD=Dk6PcmhRGhbJR? zQX%DQKxoxU-_fM8A1Kv73xRzTY?WB1nnBAq!BWp`$^ta}MX-iYJ0M7Tt?c>V1iSG~ zuxx)3thw2t4*n}>zH?WTEGan;N~55!lpUk>Uj+L*l=NX(@ze_5JNymtgs@&h+dQ2I zv`;I(3}2imbr-NK?ZbV-Z?0zuG;U=>wzGElARUKs>8W`e^KFY&3FP7w8EgS5KxQ;4 zA!zG8_g;Y}B4A*}QO8Y|Vj#Y!;k?Xb1RxMsArH^L!BE~204Tm(MrBf?EZQ=mF zbHWs40}6f(61{LMrGOrdJ#IYyueEgVOc%=omZ4+FyY`Qtft}P|<@~gWHOR&t_m(Ah z@_jlYwQHCLO_8@*YwDiG_-1R-EO)MVOg|_=O!<ll!(_KMG&tQbkDkGzo=jQgLJ8 zMF=$0{Y<7%?rw=*)Q+?v)`5WermIV=Db+9DGgN9TY~Rf6t&C3nrhbKN`aDwjuObLO zwf8c?@@h0_Y+abT#Pp~Ya9Q^kW$dbzqi(qeu=U2GCie&moFP+Db<$LQCz`NkPRnd9 zgd0Y6m(>kz&8M%$;M_TNxGb#^PFpulHN&Ni?7Fu2d9S=Xb3n?GUOqm~o-NzTY?!34_*pG8H8;OCFY(^a z0}a<)y6lzpb0BF__9R;N2{ep6hqW{dE3XIF`Kd)yPpw&%6|edIXUzWom$O;bKD52r zMeOnvFAT1$*OHQ1QyT83tJQJXgjLbkQQyGj?b5^Ey}+7g_tn$WC)Ty;$E)l4MP(B! zOijnr_~iVG1}>~y*FIB^@BNp%*|rW=&vjFaLapZ#Mh$0CEs`}HY^Y04 z`=^Cx{RTQ)?%UGj9OIg85&nh^4k!C*E-W4{O{ep0s|E+B+!Bucp6uFw)yVwj`p9%v z*4I+`l}8$z7nYYntM6uIS6rB{PnWONGU@u|SZWtj)9wD)rNiEK^{-s&BG#>MeI@@- zeZBY}^!5F3eU12+`ucSIANqRyU-Wf;`2Aa7JO9?#=YP{z>HpMMA3v9`6YhWLYsG)+ z>q~;9H9__SF*V%L$#q5n_OcLlJW_ududx!lyL|MX^B>jD9pLdKN_itdwx-+cw6*x` zh2I~MWkJx3`cAc2nXA8Q#!?eAI4LG28Q6w6pxffl`VrM4y$@rNUzH~YCmcJ7yAjbU z2l?%jgdsH3s1sk1y%uJEC%iZtDRU-j8c;?NId)9XoRlog!skd74~@>}AMDcSktphR zfV+T{-kU!_o+Z1pamEbl(~-s6i;*DG(2WW-ge%qC)Z>F4PSw8p)Fe@gBTuQI$f->F zR4FqTiXpOZT+}HlRAl2%RuuA%RW7CA;+ZKU!B{9VU6*v_W~u%5VQ;A=EP+ct>Vgtz~J<$x)6 z4#tS#QhDr<@d0@ywHnPGK;mF#}V)xtDb+$%qh)uL=> zrbV*m#hrx{};ZxPVM&m>w?$+A>G>iJJjl5 zrCT!z8?%~zr_$+vr_xdXceeevNB=$fUC-6P+Qr04@4pwm9;!&it&2i;pQ}O784*~J zcqPTyVzKc95l4w=70b{8@f03b94~sfpXc*+V@su)7|nu$&q)3F&L$=7A>eatjpog_ zVj;IqUpL6%n(>aJ-DgT_=^g6^+bl>r<=YnpGc&f57$h}{USDxUaxq^?9E^!SN#Zpd zLrMCgL!1Xz^%gu1nT1&|RQ?eLPmJ21{BHTM3bDy@fuo_OWpA)R2|Xj=Z<>sO74PIs zpq5`ic0e}o#&m*Xi$AV}ZkLcJR2>7s%U%luMY~rFx8n&7cZ@%6x(iFN^ZT4|7}r?1 zCzCQ>4plIKn-c+6>^!d^BLm$@Vf!7d$dA}wjX`N@O0T^rv}y2)^SxsHy|P>vb+ zH)|gi64+;TD&>{z>tnNKn3r|O>w72LFBhJnDCmhy>0-8uPrJa3b*U)I_44|eiEvx5 z7!9$>^`O=WGp84JL(2Ij-9SrmE>GzGFm$47UnE+12%ICe$4Jm-dgrooAHE=>f)-_G z_6#vQYHc8Z(AB(=h!5ketaFz?xrRiMyE9XJrlPY@Ggs68bnEal0*@&zt6uh9rGW8j z=E#gol?!ywqSGAe0lwW81>rz|KochkI=|3!lB9L7@XHOr%BE+Q3%D}VZn zj)NlQ^u~FDr1Byp=h@UFDTZPg%cbUyxfa$-0N5j6?osq%8&7v3T1rf(l zZ4d%cxNr+(L>3q)+$xC^5h5&D%w^AnYx^@wr0#>)LMO$e$L9MsfQ$GjA>K%BdrP%u zm4~NlXaG%J<*o&9OAU^%r%R^&IWA03*H72a*Sn*4veN7MR;C8;`s#Lmc-z;#{r$!C z(cs+*nmi}9P@X$WTnxXeA>p}8at0g$%K4e5PfYck9CTwfckOx{hqnE6)( zS=`jOU!_@rpUm#R64BPt*?K?O8vTI(vF882Zvk}ZcB=edxMts>3bg6>4S*8)jU83#eUE5t!Htj2uy^qF$S@r8Pd|UYr?}bnDj_4LdbDUI=~|2ydDd znIRgMSS`N+0l|BQgs4Ms_D7I`cOmk5r<1;&*ejmWgc$^)f_|0Z+6PwfKCx5u+*D5I zqzMw}ka?y)4dPUv$(}$#c^-2^|IHL6XCRjK4trQjKMh{XC=f1oEfHk7Hy>_c5gwOT zAXg`ZBOg#yHwj&g66+?b0BB5K0J#^FtiPh^3u8PX0)F|#>yQ4!Gq^1()33451svv0 z$({SfX%*fh3*V%ppuPYW^>_Gcx`yZ>$oB`gUPgJ>US93`s8TaVHaSe}xgWDl^(6*+ zi5KEJq(iJu$_+fN)N>T~JMiM6c~LkoI}PYR;Zk$U6aSz{c`EA(#^a=XDM4EhkbVVg ziTRLP2GfsAh)cKV!V_8DC#DjNO0|a7w__8gq0F*Lwsvc*N|!` zaUB0e`?CVp>*`XQg>bJ?F&JEj>xO9!^z@jZ(*oP8R6}W;GoGL4rO{0)LxE>DF?I^W z5hLMu1~;77DxpXw+UecIs*mUbla_j=WT1YaKDne2#}b;4ee;rd6qzTb#8;ts6xwat zw2ybg;%I!rgp2ARL=``VTjd$e8f5Y;l$XzmsclPyXr;ujp*`(+_8FtfF0yMFczWQ4 zn0DZ`qc6`5nr<`Kki5){SDZMWVIj}f6ER;PM?fbViV$jclhRpzs!xr)EEMP3a9Iex=RPF~? z4!8IpGV1tXHPPz1_taQ7{Dk#K0uKRkuhTttJHXAGyxS$(Jh)4{-a3He>(&(8%o>@O zbHi)K!_}iPXxXjV?y7#=zvSuMetldoTX&;lvwP-a11yGjoXrVP@%yEEJSgSp(!^ew z4vzAxbP1>?xWA+KaP&mPrumloGOV2$2CY)Ie2=XPd3)v-PF^OYn^SqSjS2fFQPd2( zcgclJ9f|m|23QRmFFKl93`~OhI$~Mvujk>@;_qn4lx~`vDSqD*ZnoK|i|F&6FRZm5 zz<(_N|K8(*@voM@l?mg&+V_V5vw)ld007dzzy60lm%sP@zn&NR?`fDSF$|F3xvL^> zIf7{B=G>-qAnh)rwAL))t2haSUD5EK6<6`? zZ%H+$C-!}vUPx9Vsw04T8+LWgO`r`gthnjPvd1v77k%?5z#HCkpTzWlC)jazZ0MkNgO30scIUUpudAKo5&6X=Q_bmGo8#)G^W`>d zn<&#xLwzZA@%l13VmI7@13cjpaU(AH1gUvh5?FR`^-I&)$)K@C^e|=*^LPz89ZHDP z9!l|@Z}r4Akl=+Dxege35Y1dA*@YQ zo#M|VnRa6`X-TW*jTq`i-fl>>V_te2H}|F?o@=CP4pAbwBs^E-8aS(Ntf}(zOMsPk z-3}U=xl?X5Sd71Qc{{v$Z@DBHI5!X#ELC?BTgI89N{Dl<;r5~>J<5`wC5`xWIgVPV zLZjsSz!={eCljJYOTe8D&@BzVJMx5BYi)PnwVI$d+@cqm%P_J(eLPrCW{_*;l_=sJ z5X{mO)_bAHQm{NOJQW?Daa)AK;~$1bpYg|PUgtH$C2s<-4Uu&5@Nst^qQdOk8K*k7 z32t78`0knB@`4xxtMvVZo7Z_-51SVYX=A6KomcaZphDa%YGYgas|8!^sR^;*RlL0zdNNq7Q*VU8ax$Q1g32N%Y6kFLUk)S1oGTC-%JMQ9e`$A_S ze$scR+8vcVsC0mzw^nh?cJmtlo-0AQ>n~w}Ba!L2l)?g8DSNLaVi1UoOo#K^{E)WO z4kf5@!>j4;{JJ6d^YL{l;`{k@zt|y%rzcY`K6`lni6nOTLeg7qr_+P4YTmO%N@H*v zvL^xFok+c3wVU@0#%`8lT1+p`a~zp@a_p0dh?SnVoy8eeo1Y3{7*#<)rRZ! zq%*>grcxb{*Y5Ko7$0wqvC!rC?;^Lvh@rl(bWMT6S-WT*7uL-Rzfy`q`W?11dag%$ zgRtrK)`nXxj!w7)Vx-00^Z%Gi_4j!Pd&;vY|9hbZexG+3|KAp>tIdBcHfj1RNShtL z`&|v*(%(5?)Cc>=MF~YSd2K~h^EnSlfPfNF7QIL%@gcs;=QbD7tmjN@mVO;~#Qocm z%%v+ugLaL-j(F)0hDP^muKawB;YL^=mSVOj&o5 zWBnXvPNQ|Uq?iSdVP2#mj~QQEWu5+}z549r9giuVY0_v5UBO{jF4x)J3QU%ZKz4I( z6qQV=76}PaM9r!LO4=!NR_jDp6mXzDL4PN%38naLvLxb*fXrzXW7CS)e!DLy#zDcr9gXd2qnXYhjOo9HuC#r+1AMEt`P1LdOxJEB3(8WnI8(1xnqNJ;0 zK5V;VQ@^c8vcMS3Zk|EhAtQR3xS>O$(-VJFpmoB9%mVxBUBx`(bE(iq!TW~pCU4AU zOTg@mMp@9ejn$EXd-$v0QDb;j{e9wHvHR zM|?8nBOu2&eGc8)*J+bfF(Buw27nQqEaWhr*XtH@D z4jmocwWVJS=sATMp~fZ+8&a2wZ)Y|in*hW>6RU=ZOZYb-rqRS2Phbc0@U%6oYjzN> z2)WX+qLf_fAK;ZW_CLJE37cCk*(aA4afu}l3M(YZ!@Sv4j#Lcp0dGQ|cN=}Xi^Z2K4 zS45yCtgl{Z5iyVPYzPijD$=ii?jYRGxj|{WJNM$I2a8!|=$}T6<28M(cLD+cczq9+ zqx*kY_|}I1b=Bu6^;vGv!*{(?flL2Hil|rdXgvC*Gm1GP|y88l)Y1!Xv?xC zT()hk;wsy=Z5yj>+qP}n<|BtI{)o|e|w+X=YHJ}^Ks@wWMt%s7#T4tmB+CN zN3r{tzBc17w0EuQ3){pCp0Y(`Z3+`H*}Ot{%<6;aK$IcDDg|_?zq?%LMnz;z_F8{TS{+`D*3QbM-FyJ0o8HYL13YF0$$xj{`X-NB&2u+SXEO`iA zQrEoqG6&uX&5Ttwsu5?);nIJ=Z>6CoUuWxft0$vtQSIH|Ph*?;_i}`qdKAb8R=jD4 z*%8n+P+0RD10S;n++nW=Vaoj?GBr6WdVG0oF^odn7Jg8Gz)Q zdSD&6T$gFkE9xPnPiO{)Z(r2)!cIb4WRygrUk;m~7HqAX>!!FP=KL@cfR}~f5*scO_28|Lc zDj3CPQ7N3dOJ@rQ9g{C3;w{5SvjuEW(qST(XuJs{e>`?)ejeRJEjH3OAA*f@slB!q z?3EETC)5S4Ha_NA9BE_}ofJ-@e2>v+iKmoW$|o5W1`k; zEOjoUWGm~PxcO79>NRY}IvxSNc-Kmjkr-?Dcs2%usX_rmkNO*~DNvv#R5MyVKche}`#BDx=nGVhCMllvqLl(*VWw zIFJ)0a7ZAb=e?t5aKZYG>B42XI&2%#nBo0CIX~m$#U!wdcEl@B%b#8s1umS+uIFg@ zJNe>1NPc3=NAMOqlu<&=n;tE1mnfLhKB zQ?#dKEGICpav?h~C@D-AYUBll`H?$d8nYnwO91C3LNU~>g`sl_lY_m9pN9t;&hpyT?A$>NigN-9EzDLIM`fbN5U zDB>D1!yK7j7P|S*c+brx;SKNcx@^sj-xR)@WJh#9i zTxC-~ckJH1lS;K(;+#;vk+@ro9k3uj@zuCIb_r>_5!jq_G!GriLh^oWqIa}6JT`G~ zA{;)VUs4Wc)AP15B3&R3G&*=PAv{=#6R4_!C;Y7F)@6q;hxn9~l$Ybe%|~ck=yYR|7!tKILOPfag>H*JHN=?{fNxehM zVVw{0TUEzSjv$zl3j7UTxLub|yUvMUFZ;*VjXk<}{nnLmA6ZM+gHRc)ms@KJkL%B2 z)9d3~+T2X5=IspC1l$iN;BoB_{C}Qc6jwjzJJNhd-lu@)Ho*Kg|l$Dnu@{U!-d!iJ-X2pcZbE@FE_D0`4uIg`?W8s&g3(V@-Z-1hmagpa#KVVvMsA} zR2W%_vQT3af_bX>iz?dU7=rcwa{0#GSXysETAvc-Pf}%5$!`w#x4W1#a0Nd&i8G#@ z+NNi##5+PsbrcUf9d&>fUFxM8w2FgqV&`Amr!B(h;|63Yt{cP&0{vnY;d-*Q(#AjU zLX`YsQ%H6!pe-%j0FdzW1!{gH9ruzF-+fQKOm(h9L76X=PTrVZs5C%0KtO~w<<$x` zu~uxGT5<35$v;Wb6ynWD6v7#J^ehPU#V$n!0mwwf_3){!#zRemUjkgk!7XEQWHC%%d$ztY8Vohy2 z&Vvt?S>UG{!KF<=Nf%i}d}fKqkGy$H9RjUH5mbZLh4@})dgT}XRW*WN$WSwEzTE+* zEFmb~Oxpl+#r4P*Cm)?YvS!yhfH!X~z{^~C0H#LQyBssI15TM0d|iDDDGng6`UfoQ zPJh@9J+PK^ctT**YSGZmDBFXu;aCI4S0R^0XADv|y2TCs_9;u+`JOCmL#UwWSz_Y= z_g3*DnqwAF)edp9>)S?G6jZ4Hte+Qmkmgk&~`sq)y_tB~qC*tBzOt%{m3nx)g` zpAwiy>dr`HB|{bX&e2#fP zU-xhnL+y%&XPjd`Fi0u>xYO<0+b_w)E2S59@n@IJI2<(0FHgJBL@Lbt_DT3{mZIFI0lWB)Q@ zRbmWsHOAys;sbe>FcMZaRKyaw^zhwiJwo_k3XYI&eUOrZbSmlP59~p5&@PhIT>>&m zTHOhxYI6TMW^c4U&wMcT>b+s`9{1t2Jx;(H{t{F}wHSo-6(#>tBla0pe}QeXDzY8+`{Z|?zV`oDfYe#)^>;J4hZZv5F zLhzj;5`XKDGyW}X{pW@LzABA{gN^lHvgA?n^w!_S?e#k-K?kZI{A9qm;f`m>{xJ2E zV*wZj%*vu?pcX_4#%+Yfd<5TDy)kIip5${lQvbDz7E_J^yr)d@yD;ltGUtFW=s`(;m zjy{_lL2oy!4`ABXtY7KXNg@IA8FKWz_)*6p73oY6-KP!P5ei*mYGDY@Yr_wbimRca z=g&~MJ>z;2+ebPuV}9D_ae)h$k}0{!R*5Cpm2P||kRJ>UJjdnswZ<&xmN=8Z2KJL( zMAqH@9$fW|EUirfL)M>SZ1{Y@m4+z1RT7Et+yDZs!;;N|`kvwNlsIm*2LXG9%En%| zs{5}({C`0{KH;Y*hHuMzep{aY|H|^VHV%%|=GNa_q@^W|gV|qpcZyq+0is6;zIsFX zVGl@e<(KLz)+#5kAV%CbP_=?r&!nj_?`(&^rO;x;-*$$>arg0+nIm5eV;rRWgBExj zj8KOY)>YqcMgkM?459m-S{m@C{JyaLQAqtK)1q)JPa)FM*uwW{YzgQ&%N>2UmUM17 zL|vOo--u$|5SBHr)TK>%E4Mskq4L8EUuq@hgh~|+vG1-Y>XSlv3M2q-*qN8sg5zjj z0siBc4{sh1O;7I$)f(CH6my?i@H-ETyav?o>A0@qUgW9C#7z3BNmO|*?L9t?WL96g z;2Sr$xgH_@2BZ;T)4bWuxMFHL!dW80HfKM#WkjX{A}Aar5^sXMCJmf8y3=ECU@_wm zv$XoJr01HN=iH28Pgj#2E*v8ri1JZyd=92Sg7e^p@Fgh8;Rsd;}Eg9}JzlVZr0z$K4Yh9na@SwlZ6ksJV%`H+a|`MX6w8%%X>nL8>nRq?uY5d>kwF6zqRQx*|g; z;NW%}?}+u?tYAvpiZ0Zq*v&72JW zI|cOLm-xFh!9OhbznAz|s$ybkumE~W1 z;w0N8Ge`%sd57ZdcaN}3oLGhg42>L$`Cv~9yMM00x$_{tYA;xnk?GmP0*mf=jU*nW zZx5z7#!$^z6ocu*5YA!P{Y(riqr6HAK)tjq)eCY}B9)HrIYr!T!mmS@0ak?wO%k3^ zX${ap!bL&~f{VzNWA_8FK9>!nQ-qZL8S#VF^kO_<^sn!5-F2jTTs!dF7RERrPEnL% zLyzv5r}~HV!eE4veY3s*pc2=L1l00TKS za|VcJp%L<7KoHx=Oulq=;b3DG1C_Xj@ki418{L_9V9R5e1Wq-SMoXLFa2w-sqeuWK zBx;uPvmqVx8g)4>MV_mBvp>ZeA?hBgbTht>auf+M>E4i#?@}5@)w2ZI5C$u#0_Ih^ zK`{Ii<=d_8dunkLP3KL(#ElG>(vZs&A)+ua5ukRP#X5CK|fAj(*-MO zY?da;3zVuxc-eGnO0_U8qUmSs@k5hBUvve*;>v;Vhu>Dk(^?bT>mlb(Nma?@ zF_dqKnEkFBrp;Op>U(V5LqLi}xgx_<+_wy zb`@$bAz_fx8I9wYKcqJnEJ6$Z6!rSq=mG(mr=$#edr!No_hAcXK!Soz#WK8E!UM59 z#`d36gqv${?cmlN91D_@YtKAF>f@2?oiRjUH2CAA1XW{YF3(J&prFkm zK4$a(x>~%5km^!-eX2B9*#>kJBF7mPoml!o?w}Sx?8p?`K$xkIN#9TPXN#mq?8fj- zXTh~Q>;eOADuMV6;Z)ZF+`c!xtjz7h>QH}CJK7HI^UF}ovljjf( zr(b3nXrG>n%~?{$uN-Qv%8?%njSCOemja9$qz!MH{VL7NhW$nD)|Uf~#aXFVbnt(1 zL<76A#o{-CAT26@@TbV1ElbIUzx>-BmqRt&C-7}#j_(xpKi+YsHkSIv#<4m*(PRgbFl^gE0d>m9$o>&q(n>Okhp}f{va120ItoF^ zg=UO`v{@}InPl1oT}hjG)@((dW9yNt#%*T<%wa@@dSuohvyP#aM4-zN+djg}G(rQf zGII>OI%pO#%zEY+YP4i;v`Duji`ca?VjK{pLrXV_3g};xPP9r8^I*RO;hHcGaO^J? z0TdN;fGVMR#$I3odL)FJUQJ3D`kLI4$3hAAa#8!LJldtT*bki-wkpdh`Ldh*^|o|; zWLJlu9g=F8z$}W&pJybpt#Eh-yFGa?cH7jDj^F@ow*9$w7NU4KMl^qH`K;`Vx_HJf zmff=ke6B2#{WB&2E!7+KeMj$^Z&KzzxxCQ-2R2O1E&m2Jl=OeC(II?X>e@91Sk3(T zwH%Ci9Ks~sQBO)E(@$;)BdlVHsBTKkZjSMB#X0JX-b|Zpl(p&cbXlm_YF;?jmjv{) zSe+22vdH8RVZ-&+MAw!zMV6?r69iZB zm4vy+)&JCOW07tM}#~vCa}bXH5d}eWicH~wE~>jdQu!yi5(u0W~ckFr7BrCj3YCDZ8$-x zu;h1&pps&e;qdU?v`3I>NXdQr^*q3v{&I~l##rpDlCAt#tF8u}Pl5$M93U_#bM(MX z#M*shxzoO3X24#7pQ994E9_KrG(~8@)++EZEwV9t2iobAzG*;@@n&LO@$GKnsb#?_ zI#pohULjAn#t?HK*y;xZ;~2?2^joB+LXAAWNR~$lC9d*|mop~$;uTi@z)CMmU>B(i z#G_9_M+MZz+KN@;9@DDz+GiQYNxmBNqDIO%So-!kpXpP>tTFRzXR=C-j&>iHEA#A=#G0-w_Qzl{HJ1}3q7sji7UGQOfZL~8D# ziSwmfpHubhieEPt% zsox<=wR^nu9JC*W8d66Xwp0jZLmHisg=P-XB{fsVGh)o9GL(g^jUT22!KzD(1P)9n#X&6O=P}hJ(ib(gd7|}xBqLfe5k_(- z+MYezp+F9&$acY{Kj>+wx_C@Zclg7W5J@K4RlMeO-14tw09^000Gjx~wraf7ArjITRGT z%etHcSlwI8j4Go(Gy|6D73tW0G4m6U#X?!n+mRJB>!8LG~Qz$Nkb^#0yuF+@qQdl46<;N7jBv zJMKuk3j{SGiQwHPYHSHII+QnCnsZru&E28s(#f9nm%0sKq6YIjbGm@kdW z-X38OQp1WsH_p#qDHU>{e8PmEi02xDPa42Njt06<(S!k+082n&Bf*o;3sZHQO(Pta zpkg4_=1&yI!UB`+i7_rLO=}yCFenX3t%BMQQhGAYNmst&@;pE+eMh1aOGK@J$pC2o zlwdnQ7I3)qX;2|^`G)juv&pgWIT!20Avu>BVG8IR=LF1OUtl~?CBMP0j0}IQ_bUNf4Bo!W*?QEzUaAZMzx9{ zqxykcJl#x*`l{v@5*(=JMLr)sAHV+uZRKMD@QzGPKcw;mfVV_%Ii&ZC88B7lZ|w9x z(BY7!3=mmie-_T?MSG3y#GNWFh$?N?1c;2OC%sI9{vV5Om&}-#F^bb?T658{NCcUNm}>F~FJ06@EB;_0PcO!S=GtZoBakvE1rbZ{v1*R3H4yfT z8Uz@^HA{0kX3jr%B^^)C|4jv*_!BKwF*-;_4`E(gk;y{$k@@OCIdHlJ;rSnJDiiHxdbvY zVWMQ*z8cnn8nNGtRcE~$UgDokf%x|GBK(`8927kv589qhV|-o#sV+wr7FV{EO5>t% zISF>xbE^qLy~H8*DxeWiafEtcz}|4HlbV{IBL#W?oQ1fJNdL zqS}n!`!XKDjgHZ|e2LUI%}BA`DKyLCooeaE#Rd&OL!in+{ro9ht}9I4r{r2)HG^JW z1>gNm!0+Z~SIoZdkM$sw2PuAUREnj`ZIrb-oe!b&m6Rsk!kmec$Jr1v^7_H23gUb} z;H~0pIuo`1>Su&$iOGjQI~Xr0eSoSJ1j#=uS#GDSPdp|K>*h_n^+j17mEs;C;0IOn zG9)Ux_>-gGV}c$S0Z}asRMssJQXevnpC=Fo-lPyL&DhqP&1UFOW*>!maQXtvlwrwM zwDcmvH<0?>PC-Mh{@@4Rj=?+&6M>{ukiS9bN@60oe$@VmoAJ93<}TX0(TUT_twu#& z{|bC%_wB0v43=As!`01KTGQ)|UP$jADUP*0O=l&d*Wlm;7mpZx0#prTO;;73+!M%o zD8Vf@P^p-rC$V$$!oq9W#y!cpz&*bSw>Bv=1hIf!`B>vJ53UV68)u_IgTmN$J9o59 z8@av3_J*u>$2$Ph>BG6v=jQPI-Do}a9Cihfw6RDG znj9Adxig@2Y>-2oU@HxSPPBSyNO{CfGNAg$(9bwgpru1Q9TUU@j-lwg;YJHnXzN?gz+yE;V~YmpBz>wRO|JS0F*n zf-J`%16DY)rZbSx&&?8hpO|ZJq>yB+p3ZVEi-CzDBzTC%}rnI`Jv%n zqpiZ`+6+lkDu+_|J(m?Ftw+l2gz*pvA~x+&TPT&wJ@RX(YOA~8@OQl%yd+=CB1;V2 z328j3&WZxKLRuJRlxBI;6xb3tjcJy4@%wny)@EkTw~~g}d)Z#6WeaVF8ST{vI@Q&T zPIJe_TkY3fv(qV6w&afJFt65(eH${k*H-fAE57^5xF|2QJbXZ zAY7t9JyGqK_kj2aVZ1@WQhHh6Jz;zplMH$1%M7L$pR=Cc(tF4^eyqU=iA#N;!a~ef zTTikgt4DBC@Tlrhq%Z|g*R`#`X)s&azUuSLh+G0Va}6+YO?m>mKizKn5zH3#4);&A@Y> z_x)H3DGd}wJ5=k3TIzL~u+ff%eSwvR7F8fhDKK~gS6-Ti;(($@b#Hy6-RhtrU0;^k z2}N-K?~^$sii z19(XipruME4H2s6?)SqL3r68|PU29VlyNAZXh2N@7LFw7E9+T0;h-J9)!e3v_taZK z8f$J|W6t{QIEU<^psPe@)u)c)>&c)up;)U$dZ4B2xN6Pt-goZ{z2F_0=-J-kX8C@G?P49J_NlC_rPbJtCLO`8F~o1t-6>4UyNUW=6!Lg?Th3HrAfY{}doFSBcaq0T^7x=MuF6gNQ?*C zU%6a_A0a4CoESgUF$q%;@E;PDL>X{~tM?iTCkb~ zcP(Q~j;ese_i%tch>9d#_&Ozit=*PXJ#k*f^mwmz-Jd5tMcEkJwVi2SzGPWTqc#or ziZ0l}1ZR+Jhm5g=sqIiYl)@9Wh_KSD*aY^Raj#Vc>I~nQ_hF}jmpvm9F7K%NSL=O< zf>su-BG8ICr4+7SR|i9%yG{22Tawpsb#|WCxrY|Mlh`0}<&_G%IS~1ES@sK7qf8E+ zVtY8n{1)jOSw@?o`3x}Z=q}JdCn;ZDymj;Pa? zhI{xSFTs6XLZJez3SiMOr8m}`4PH5qv7PhTQF^-e7x>D+a`RGd-s(rH6Z4(@9-R3v znO*G2>dD(2y++7whZU>K)olJzH7T=r(>fMtD4#Y_xFy$CxRR;QLkXzG@q zrXh;&kTubQb_a}V=07iLvlS+-Md9O@-5hnghBeUMEn3c+Te6+#FZkzgvf(6dh>-`K zVev{+8c(Hh)*qIgv1Elp9N60<`rw%Fb)HbG4QOd_FN&8e=<*xaTuctUpjC|`;(xX; ze+65*`xK?TI%{>Qu>b|ZXKwdMinU{rTGk-Ld6*ey(y2;QpV3nkH&0z!?34z`W=Ryc zXWCl$EEj%Jw+@ONUBX57axM$^eSB7dXLP2~8{^4{dQ+;xS4G?1``bW?Bh6bkZ<}RNJ%o9 zA{A(_e&2M%O00g`S(Ct26eUqpxf7gmvrR}wO6M`=#vuCuWiDSSETm>u3T~Y&swl}* zqUsYRCfwIx0R-4et}u;;Wy!1 zHHLNl(Oo(kzkX6Nc@M(h9|z5LzU$|E8=n} z5%xmSrRoVdmlJZ~SS94Ie^Pkv^Z4FoJ_kPovpEG7@Tc;2yBi;&?*so7a3aIR}!M+H@oo|c7)S-~y9=n-s(qRq)rPa_mA9W)`_o~NMNE@xe)P|g{~ zCiAN^z@cC^D?pNA3ug-oybD!Yx?M@e9bKe=J}iIc7kRIB1U%bn2;gSQrl^MXp@?xK zd7)!6m}-9|aR+_zqIOrJNVIr66P|)$Kxwf8bP#}yO^tb%Qfzo@*#atd{GvccVoMs0 zG4Jc2zJa~HJ#zQQ$j`T{o)5!mg;!AR=fdk-#&%ta=G?E2bwVOtk{65fS55qsn&eQ=OPC7Rk!)x?8;kvK4F>wDi6#kkO7nY@3BGg=Bt?(3 zT>1Nws3bJP^5e)ORw~fR&Q}Buo=M9iH@9+SvgBe3V6cCsTq`J#5S;oYOJ5@U_D8h< z?pwFc3-9S!4eC}-!1|wb-ZhIrmbVEwQFLC{ug{5zr`6kXIw^(1uKR|oV25T!> zyF$I#EUy>e!ET`S=T%D-HYg=U$(OLP6tgBk8{-EXUjDXfc-8T3 zYBE6{@rcM>WDq7P@fsqaz73M8Vb?}pgj z)`SKQ*_@Q~G^_Ml_O!d;xYwu9@~x4OpgHo3ymOTj-BJirBl^)p+{#gW)YH!OgUyqv z&~2~w*!EST=B0M;&guH+ud35G_u*67#SW4nX z%8@>&QN%K#?@23h)>V_h*>Vjw&)So&ERk#dY>+`W8b=VXl422ZKRuL(+NX%^qa+r( zFUw&8YR86o43D_s2yWvUk)S9ZjbjPype4XU%|&#dZi=sb5AhRjn!VI(clD;Bvv@`# zBc28|k;2oeTDMe93rF0ow7VwuiEf;dtPuQ~m7pd$S5}p9$gM>z!S-r(p=kIOhHNVa0MU#t6IbV{|MNRgP(PjHoF? z7zD?2&4JjIUYQ+{uM>U*sUlLqGuVsq{PxGiPxj#)=v$`HEoy?q{8??+5Chz;RN1$O zoOErc7S+Q9;6&#zrQObjN49-;k3CZS9wn`LU_0!zdB_<>_iheI`D-w*P*O>td@T@k z2PhV$oqr{UbB(o?}?z6OGZ4($S zKCE4ClL6S#c0qaB7%cU*Ef;Ctr;*&TcY}9OE*vL0KEa-R#ntS>_kho>di!??uS;UG z;#8%9pi;UPFw+SMH3iWqo)NQQc+A*%8JtY@hUvg`?BCN2o|DS!M`0s9ducYau7SnW zk&3gAIMP`NjBO1TCoA>9^`5m-wlh9~Lrv1;bpv+v+~=|!rKJO)yQ(qPw`HmO?8;Hr z{YnHAiAQlNiO2dVnCJ59r3Y!%M>;qR8v#}K&GO1V!e%SWVp)8z-68paC{4!2Ofa-P z#ON`H+VDu^YYI@{C;a&M<)@lM8g%fXy{ouUT*5h+F8j3hM@X?I!GBo!&W%XjmWWRf zW`Nu#JpD0^I3(KaYX8XW>*Vd&LDS@Tj#C{(macLK%0ly0DlGmxg6XT8~4zLf~pf z`FD40g=&klg0LuFKNIoqF{jhceDa)@Ks9b0v(4*za|-QIdJ2IFp=Pbj%PfiHjN z?gutze(kOdno$U<5$Y2yJwo5SKdgJA3%`FEdF+>^v2~hmKVm?&z`E9tQ&79YjFEz7 zMSsao30N_dT%#iqcs(Qybm0roqj?ASXZn>99+J}W(v&`ylw4^4SpR&L-{j7?Dkx&xU%gany2bxW;f&9Nn_a;)dgeObe9X6E=Ps z#^fdD>;^2}eAb-$ly2`hag}|yLRiQOQL23W!=#%U{DvOYGZ!S2k==c3!!JR{6X4&e zinbd1f^>+lM(WFs{i@492=ye}*C($GkS|r@98aL~`H4agd|UH;Z--{|+c}A>#Ifks z*dxx0HtdrH>&dhkacABRlWA{1sOKqP*SR{ln_~Ca=btG4(+oMX`CIY291Z{g_dlTc z|AK^nhl5F~Yu0Nb2wq33F!A7=(LzJkvq08Je92itp|pOq)c*Ots{7&V>FdTW;$^3b zJ_S9?v?pmBMa1J>g~9sj>nm;9?2Mi=ZI(Y9Bt(9+cX4#BUS&4YMw@3I?JI34#ZL&V z2E|J&@YO2r>dpD49YloudkDC|e5=J-?cJ;MIp>2*?)Yf}1= z;No@vdhLEul~xgl%aJj)viS-JuXx8Y(|C^E0v7TWg1v&ovQn75f@4`C15DH!*8gY% zaiOv3JSHI^AVEgC4Zh+;3)5e@iJbV%WOmHRUs0qwE-jrhZQfG&X+GlVX&4+_+}_9M zYOD|qoC;UO5W1xItD=amCLX8nsMK z#kU$sL;Ti!1=>XB_T+Zy1ZcQ7R%ws)BCR|<}>n&m4B?qlv`&?=v2~ZwIHHgskpmkB|$@N`oATi zz>;(o`dd)KU2Scp=G$cB7Sc|bu)BFMWyLgpRboFEXjF=g%OT%qz-1j8F<)ijhIguP zm{)3)N}%<&)I|o4p$Pl>+3p*A-jb?>vlI)NQgOq(Iv1Z}^oO1^!k7Y~XB0!Z+53kL z%yz#szdsoS_)Q$Q{S@KfZA-lvl2rluBJ z6o(hPw;QhoeX?AAl6guxBvLhdlpA!ad`mbJ&F1x!ymG>`{z_PjS%~44-r(80)@Alc zb#w<0cX5Y~q+8TbRPOEbp$sR!dT>R9UGNwyRb>Wzq~dd! zSCR6wGFrr4I$b+@mS4zb48eB#N}(sI!*Y(J^MhJJLPpCE+Tr5}T9|{vL-PI7X-upZ z(!L=1)VZe(VScX@YpbhZs;xucCW6u`%+9NHG@}*CiDA8Yc?~U3*Z3d>Z=_NV1_652 zVAy~{AdIhBA_kxQ&^zehvQj=n0{Q6<nQL${}$w^^l}fLN0#U>f4>+6D(biySsWa z$==o7!Sgh9!_3vz!Ntw%(a~}sf&`h_g%K-Z{3;v8Q&Mk*?ZSnnUMB_3wmyj=l!=}V zm-{gL%P^u_pdeXjV>1n!+D_9>wyXf z^jgHVBUWW=;-*uwc3D(XfRHeH|GL_ky7@%FTHV$D{OHB(sb2#t4v<#bdVyPz!5tu3-|RzT;-ot^{bPyrpfKn_E4^Ykg*?%VXAiII<0 zP|6S(o$MXQ}92@3L=RoYQiTjun~;#xunjYHlfYMjFjd5B;VWTE^s*&YxlC zDk?Y5?)Rt1*o92l_g1^Zrau@w2NM9j@X=oi?olrqdK+Bt&xc$_-ANd%K(wbjZkJ(b zNhhX#@xw=feHw;^QOk6{%dD0H_jFqOxMq^!AW;0zJ2Qwc_H9x@PYj@TQRM^&B1iM1 zD+iM+2-*IoPD35H?jgU6kNK0r)Q51JjkI=?D4by|X{!v>VEKUV&{7k`H{q{DAy2ym z3fF+N+@+^~vodwLiIDAOoJ1I*pk{5@nX_((I)xBN!;!rU+H+!Vl0IoNy~il~ zQ@O&I=!pr(cjtfT?ZEgCH=n+(`Txzs>i<+r`Pc8x^!k>zX8QF1eVzZR$$WUEc1L}e z&<;Co!5t^N1YYF$S+TVn?rQ=7kvHB~BGHs52KtK>*)lTQxI^%(*+(@WO$L3L7Rgh)_Rmw?SXFTneQ|<1?F}(TGEZ@Os`Z zFFOh((k;!wj981@+VbWJ^n@u2NeA@ge2Y6MAX|=p8W;#js>~P-u#J2auA4aXOIOYs zvBCz(BS?|%Q*X0Kq6zFvw*H`~oYg^;AYR9mORo$XWCcwRW!@ngn)E1U6-tV&WtI#z z@L|jrMmwJmrtt46Lg7sI_Y`NONi-2hIrf6oHkFV}FuO&7xjqNi@a3*xeWnGiM#L#} zsG+WOl9u2S4@NLXguDt`_gA8Amvzz~PM6rQ%?ghK(-NX0r| z7}Ol)g8K$m@&-R1IbC@lX{AU0+?#l2@@dVB#+sJf-oi49apid-apBUGR-P#5v)apU+ErK+P5WMh_pq+eu*Zja zB@;HrWY(TcX=@$IdQQuZL)^XR@TsW+RodF1>HWs7Zm)HgJS&$TYs$VRloz5BoK5Xj z7+)%_jX&w@f=Srm&*>BBA=dZ?;(9`Kl8Ovk^ICqU#1a*F>4t($eukW3p1MuVTnRnv zp7jmYmp7Rd%Q}n4;w?@ktI+iV?FdKC7FA(EeWetvVHn5j1_%O*sNq zsBM0*tSOKCK87o~%^<$M&ava^B!1m^7meCN>EtT708BleNy0Rx-Nk9EjWwJ>#;|_& z@Kb(RQE(9L0Ml?!XexzI(W9quL|65+nP!t;C-x!A zqDp{msjiWdr>%Q?SfdQZAJfU>51Htqm%(o)qG~{&OS94G)B%g0DQFnbEXC-XSX)30 zrs;lqp4Vvh&K^I8?>6ci%$2~N-RprAnmDLx?ajIBtWt|J4#XQ)vHPH|bQ5QTdzi$q z8+TL@QrkQ&TkZrCp8#E}M@r-5LF4I(MQ+44isvBIdn(7ufjZO?s>+d&y)6}dUaHc~ ziT=`C^ftbJ{N4_B)xqg0AO0b1%2W6?{9YH;v8UL#r?C?_wmI*IIBYM022D@m!4%sG z*XXL?qB|CR?XFDakI6g=Z-klX-|JmcGP=vm-6ZQAtZc_mVa^Z3>uWyAOQTGkElqN$3M>-~VL%S-b~j3$6!d`^kD zxuV5wX6HOzaR|?O|Cw&c+$G6Je?P4q{f>Cd|3lFID{7kB+c?=e8{0dW+gR(GTbtPY zJv_gua3-@)M1wXn@&jAPB3$As=^+hFPf_RQEa3&z${~pS_%^+$Pr0F6K77@!04`y+~ zX3k#5T%}@&YCDWEV{?(2Eh4|xOn5~uXgpSWs?5?ZS#3Rcei$i+>5+)40S)HE+Arrf zj%zE8!>)^@J)|iI=4u{mAmcW*1VLuR4p^a5eE_CTSjlLx(i#AEQC2!v=c_SD0%8Xy zj@E0ONwN~iO%j2BHw?-(1P^c5E@sV;%G2oy+){cPVxN|F3yVydEyO-Zr639uqQ1(u703!uHS_7u(41s z61sYJn5S`A36D&a{q-CD&{nfhcmQ`g+oBHHp zoMPF#zBr;4jdcT3pr%9IZhVwwE&_{qjS#%Jv9NK6;86urMa6vjLC~)p*{D|*W6g2z zJ>t9re60r<%L^Q8&7i3M9hFIa&gHm668UtZk&v5w*waUYmcp&v!Do07QNPlBaluF>UxbC{Lk zgvmTaory=-#{m?J)_8teyDn(=X z=8Hig?lV=7o~~Q^2=>xQKp#tGY!25ZV30EnE4|_Ow>`2HR?464c@}RM-YP%K2f|w& z>qC#wiH97u&*PjqePc66Ra{1>SR#LeeC+BYi0$h^FF;gk0oQiY5DJL1CI)N7^)s5L z3HWe8g49r-_OyiFg$f^X$_2b8h03Ibr;rq*v?kR%aGObF?lg)W_-~T-2l33d3cXU@ zAEu9n$m9Y_E@qcI>&gf#0s=O5AKi{dov6r6*#)C;8bU6`gkbrdtZp#QUawk ztEX`oY{0M}Q{ETp+4EnNvR9`l_Q1zL$^Q%NW^B$_cKjAN@qwl(O2E1F@&Xa)<9Goh4rnUGQ2)+@Sp&|h2cAxY!VGcQPG zbn08CX-axY1lJwuYZv|$FH_Ra4E2~fu-Bcv-G6o0Ah9feE9zfUv;Gi|ZD|C7STNI0 zE@oAL*vh1wfmN8%sQlJAxKNock+AwJ@p+G z>Zv!prFCFw-uwE^O*8xc^RezOImnlPpzXiHT*%&Jt(mV&pYf}soa4Va4qtb@qrraw zxjAYRwrdV2HVvu5sqihL@qSkaQi}r; z7dMiHbTd5P9z~#~UEPI#en6ocM%5+;rvysHh>qnKV_ntG+CP>_V&)n4NlG_Y75-*G z?TFElSF&Q+(1T5KNR%!+?$(rgi`&5}%C6~CCG08@R~(8VK|!rD)+}I6tD8nKT-3F& z2xm(ql7?VUk-Za`B};ALmm34{{s)O5pEiR4(cQ55P+i1 zu{In<)PgEyz5NI;g3bo#6F(|^d3PIa4JMbHQP-jhb~Zj<1PYOu z6cnP!UxGcjuMu@rOypLSB!w~#5JrCp5OVBM8c-vXJjin*p`u=@UpSyjgk2JFCG-S! zU8$a7xV2CI&kgS{%8KqubR&9qK$0cZL!%Zk75(0)|AptpiPOJfLHit@B;{`uLhu02a;_Tk!qCZ#3-~`6Ph(kw&XK& zF0T~@R0fjX=bX2r*^2v$U6KU>6o_~2(p;f1i#GJqE~FUSROpH~WHZ5)cwu{Gk-pV0 zStNQSGIkd5 z`|N-C=UbxVCTn4Pp_@;Wi;pgqFDzd$WYoRA2Hppie}|dTzy0XX9uvego2tr1jx3LGcgzQRT}nCSc=u*B(1<@G}vt|gt=|LEX%nun(_i}O@;2xojt9t zE|{zXqL^_v)f$v`tf}3}ZZyl6M$4H=9=OWD>9O0m9T#W^ zay@LQ0O}Smn5V)UX*httvk`1jSjiFd>Mhx;<+U!lXaZ7A#)bf{y)kk7w}EFLw%kY6!HV*Rl%@uQ>h z*bm=COG2Cc^;)8I^l?;7kyC2XIzm1+eN@dF1?1aAN;3n5C#I%qY<|y&wO|cV>TNVB zHJyT8p?8-v7&2#BInI5M0fI2%q)fM940>U&wv&Y!Ct3V%U?I#h>fDNb3?;?{O`xVT z5m3k24MS{wyEsiJ2#+BZy@KXK@0@ZGBSWt}reKEhB7$E%4LSxH6}IXnIhG$|M-;iATmpUcdZ z3y?dNBo{PTq*Y89`jA4#na4fEP@W0qORRUABJMYTbyo~ieaW~n$kLa%HTx8NCc{sX z&1ioH;x*F#*X z8g`Lt6G^kdf6mouL#rXHGOPpV+Ay_ktTTv#zAm$_J`|U}T(3Hwi;U)qBaQfqiJ2AI zxc8$&?`M&-lwwYrgKwQ??M1XGiBVntm}8I01)3K-u-;`29D28!z9=J&7cK>=P9IjRv&OiYGrrEy^#(x7LJU#WyOum>^ zz9_Pdzo=GB?2YW~J^nd458BGh*a96+pX#GKy%6yEoQ3(3%@6CN1$WZwDEHT2a<3&CQ% zrC|H&%!5qAVeafxg%tC_@^5b6U7iY;v}n-q8WcPgr#uA$BR%b2$jyR&t{_Jz$GZ{v zQxrmV4{93(?va`h4(~KDilWznrbPb809v1)8*G!;c49o66PLXYq$EJbvltqwpGItq zgkqioiYFpF?z;(p5CgyabyLoFnh5_MwKU*{em8LQ{Cu-r=*Lz#;N;1Kll?&dG61;w zE*b}pe}ezsXORXp7bLrFRW5ywLBPJyH%LtEpMCpXIxs@;`Z@VEJt2L_8qArjRsd2u zI5hw88`G``#%eH#_cZJLLw9nl7@U_nF^?w^xw)|lTPV98RJAdJzh~eX9uMwZ-*sTF z0i3!Z#bC;f*LyVR4yl(Y1Q=~fsm+{X{j7H^snfmHzQc+UVP26fP7J-*&abL8AUN@n z7hX^ZnV5%=gh62$ClP6Kh&oiJm=HUrlhr`Rl}v4vr(VYQOG)VkRN66hFVP(j91AY6 zD%Bg|>t5nvD4V_M9SMK0d|gn+U?}|4eM5^PQ1nB+IW870vAcNaIVNAaRKhpN%pENB ztxIueyU;zq-lfCE2~0oh+}G}v`fWt0GyjYO6o19x1ZYEcu6;7Gla1p$RE7!iA|SNJ zQDGjkwVdBI1@Uq*9AaW9tc;Jepj@i`>xqjoB`Mt;OtEXEd#RCy%B`81y;(r;kTaju z*cOOoNQ-+!eMH31VM<)yNp@uQu1BObJXDPPTE0xq8|NC>U47`rIjWNOSxreErG*)) zS~-oao!y}x$)xc{;}$wRx)*NWeU^2JNnlN;Yx3VuoEUfMVEG#vr{TCPGL{(Ghf%si z`-1Jd8fmtXKefZ_ZLG6gZqH*79m1w8N59u*R9e99#>QCXuvB{7c7BToYwlrZ#p38g z#o{>Wf>+cD@T4}Ws{v*%Z-i&2F0p;vVCeH{@PO0%-DMtL2fN6s;Ox4t^WfIOR#0=v z6wd9s^r+NNw$TLsD-}oQbU`c9SykH)XgSHV?J^`!Q1$BV?!l`7Q&X+75*gLDCR@X< zgSKkFvjxy=diO_qN9s~!To--an^(Vzx`=RhzHffF$B0WHo9E#p+d{p5E8t6)=_!^i z?xc1(K5J%mXx(6Vo8(gBu%zn6eH=}$3E-U|skg@p!cf@+;oZHwl5F3`ME1Pm-3%D)6_d(_Q zCT1x_hn}Mp?`D_uA0kO>YmMf=Lmywom4^Cxc*ghVt23pv%YAYse&4W};Zfddt5rHC z*)j%k;IMqxz#lwMkZZHNv@gJceN`Q^;stbpn=dwFhKAg&Rj+wj(Y>sBiEcVLe`Ma5t`d-$}jXlBJ z$x|zTt5HgqL5m_4!#Y{E#n}w*7MZ2;n9uCkLj!a|G7c>U_RC*6*xTY3e>jlC)-@#Y!1BimxhfUHapVC`8#SAoOy|=CZ}x;r1SL-&dT?YVfwmcFcAct zavjNCkEZoRZEDwqPv4n%Z40$TqeuB{zGdA@ds7bjnMwQCEioaLbt_IibysKiJ0%>E zD`O%@Vnx-%@3WJ1Al#JhfqXkMY422x2~=icH-uKm0@R(BE+2>+m5H>^JQFD_5t?Wj`yNEglB*%eNa}+>?E(TaHQ_YjPJ!eaxKQ`lA~Af?7SV!y z{hBm~)-5opd9KWI$M3dcLe0|l8t_NRDh))?eVP-QjA{Uh9`HOY+LBYX9y^_~IbOQ) zMe0sz88!Mb6+liTwH9OHG$Xp{t4`M@8?RX=p0YovzKMXp^J05Q=9-+RIYK@6Lk%Du z=NdHyFGW>lOF`I1x#Kk?g((s@`{L=kt^7K64sZCPD&)|;21DuhDj%V(B22_v<_9E= z(8^`fA*#~9Anie=yY%j***o6es&aW<9aOyUy4%#g?>hH&;D(R#QH)ToHTNJ)gP_QO z_PIJH=o>HTC6uCWxE{nKB`;jXqc^F6F>GwMDf)S_D()jElvOpYJ~7%BLG2l0R7vwS zw6^mO5~5^A=x&M*KT|xt(D~ULWu{0ED#**|W84PHqOYdTC`kM}mrEchZ0omlA2p*6 zg^QFeaOg(YwnqInz4}?K5{=m%H`wAGsXP!KRkR4hqrj@tD2QzeSsM`#|o$`kS{31lz<@m@P|3GHYEk6vcVq97ybglBFCZ8}kc=e6{|j6K*=Tt9W{}=8>eC4#WZdxY+utQ)tuA{Nj=fa8tuIjl z9ijZ+FdI^_PX5HvEn#al4>9}|&ug_p4wX{1kLF-WYnQ%aQdjVeM83ozD9_IV84`ll7vz6d6c1)MJg>_wimNZD9A54*uab7A?EoNN68E(ipmYbjIL^ zi*Q>^#2#;yLW|6Z0uRYNZU{}3ub24#+RCI&=5EefpLDPKbP$n zMn9?I!t4C@l~x2`f0mscwkJx_njL7?1`+;@y!N)AoaG+sbv>TW z{{A|oG-Bs(U{_FY!QB;R38^l=Rgh2>>p0a^;M@Bcbfd1$0@NGBCLu7e{XvuwA%(E| zk?QWItsw@Ox@mqtz-%Z3u!FoA8lu}+ zC=;t;a*D<_n2?wKcvsPtcw2z&?Hqj%M>J$|)ot+W6?$@WH19RO$dQClwABDi~Z&{v8 z0zehMd+Ecv3*oNn<=^%txN`wz?9C}iXBHiJJ;IuMN7S4V(CS@L4SDUgdaybgApj*n z47zeL3|{?NS6r6DMuj&wshDsdMk~Fsksp72xK6hZ(9rMgCD?SoV zQQFpb#aa31MDe_fgO)RyZIRNwyaKv10Ag3B{_Z2S@}5asabqOju6+vLHuBXw{sHth ztZSI^d(9)(f-$#}1J&)lb|&SsojW=%b~nu{bdEMv>4%Wb6QQr>}rK}GdVKV8H9 zx6UM_7|ym_3}sYV?>+8bfAy=68`pDB*4TE zXAq_Yk06(@W^Oa_?ewC%v}HIAy-dDv6Hp^Q_qD`?*;0=U1+r0%6RvXmUIgyq3eV0> z>-AaCRI{l_^jY`%Dc;aRZkZ(ro96?8H35W>B3nAZNCxdEG1-rOy&G*WQ9U8p1^~Ay zEh!A+BH41$ybU#8CVUikm*x_=vHxv?b7)!_@y*2maAq@E%VtD*kQNnVMql9 z`WW#%guZ^*x&w8&>AZ%rPP?PGhH!e6N)&gojIv&;$gA_kwp%(|v)FEnAHoJ=y~guN zQ)P!$d-r`%dG_A8X>N!9gz9|j?TMO`$qnEGH__(>={?LdqV~cv*_Y^>TN>Arv&1}w zepVDd0_&AA+xf%h^7(9>Y$a}WT5V}95+iqX<(URS12p-*xYK;hCbXksCCy?6c zl%rAih?kW@no~~1KAeZTE80~RE#Jp`8mtAJD^8OHssRSg!ubQFbZmminNW5@ z2h@Vp4cNhAeT3;z1hpM3j)$0n9UT}Kd=La^3#UQbROXmxUh{-)6X;~T6Dt|Aa!w0zJoN4c)%v{i1YvWB}$s;Fw*55-K|J0qmYtPQHv)0=FF=92iX9adZz4 zkc%}PvbLfYt?xI!82XYLds5QG7}|uRGIcK5I;zh(>2oG8sdDs8c!lPW z`j+i4zWzq8X+vj9MYIKE75#{f9KSaSVlqwnUll&neP@UB&210qFN{(}rj{RStIwbA z=cSjgaPP-y`E|45{9Mq5{b^BQJAx!F7pnImKPLM9Zde6(x!a(&mJ2Ge5sc}8Z@KjWo z9!%urIn>&1R(?ZzNB{F+<w_GqAV+V%IgYqO-8m`(r1Z)4x)-cd1J` zeYL@TDPifaM=`@vQnwYiuSjOPuRAMq%FGb76(S@7#Dpo9T=-ql@y{VaYD97?Ns|#9 zqIYcZ*4rnNm~|rN31AoONAK7@%?B3KCvEmHewR<0x;xh$H5@*iR#&0#qbPH7ho&YB z5t(klqM>g+XkZ?0O&)h#WxE?wuPOdjQNd46I(oNh63?lCn%{LTdwh^rB;+EoYcgKP}IsSF73pECXy4Ti* z!!1ZGsN2(no03ksJEBqb9ci)7kZ-Pxe)H>vaqw2gl0TN5T3%fpo+L|BT&@A!uc*OIeR18j(lDN;vLOSt z&dak4?B>$=k6D3nwY)lL`9YMjs~(x zI7_{{#}Cq5gc*YO_BI>wvbS(mI_odD5bfePB;`z@IdW2&tREoE`-pWBSm zUa;I|mq-JAh;^PN4})n-@_Rvks^0zcNL@i$T2O$4QnRDlZxm;}L+F_6Az&8n^$PdL zRSJ$Hw2VkV38=FA&(O_kcli8Yx)M>5Qcw1*#c&E2jKr|0i+G9Z^|kz#Z2fLwOV-`` zil{-~;LrLk!RgcItjFn8JDIKxF;=GSG89qmIrC#*juF?31Pff4QTn|<9^Oszrs-^J z(COoQX;c08O%|BA9=EUO*cZYA`L12b&3TEgfH1oiDO<_%%!EiA`-vPb%3@4&q+$bWcwD^hFf>RNN)$8DfjpvA5s% z5*magfgwrV5O$HNCOLQ|ecEFH4K$VzeaiMhjjjX&(Krb;`i1mdJI{=GqnC~PjBYii zyP-NBL}*osMl6o7Jq=-^7Re*|KF$(}cS@9pBfky%w%QMjW3!Ktx%+d`Y^Ao{);P18 zLafwf(EExBS4Zu&*7xniYjt=Imx5ymV$H^A2gd$J>0j@ekrjMRRj=i)(%hjHC>v{; z6%sKy@1pQ%ZrZE#j(+{U(rZf77;{2fGm$Th?3p+z}L= z5rMuVNwC;$;V}!VDsqehF3jYLH~x#nWN(^y!w}uQ(Jc6Wn?tZ}EvfEvktxoJd%?_0 z56|V+i8)vkm@+&-=7lK+Nk~RmLT6DV0%eJ!z)AZ&Fj9`VL%4=@iw~=X7E^Bk_@w}S zAxXaf_QFe)*iYY%LouVk;=V^ttN_Z8vK9QK)Wk@2FKVrkxX$q@TA&3HHVj8~u1S#C zR!<=T02c=)w;K{Bzx0WOMbK;M=AlW@=?2)+);vUgu-nUZGtZ9CL6!6UxC^oac{%-LC$p?VNKB=|+I0J*R8N{uQRTtRrq*n*Q4YyIJ%jOVt`}6_Kn2S4Zmjyx*?yE&1@CZc>?6VY&>4k5Q4> zu64qJ-!Ee)Ucx-fnr)=dYyGA_{!keGg_PPi{}&C9FQG)4|Eu5l_fD%ndJfe!+r7W) zMjubm)g>C87n;8>mV#nAyD1E2bt>(uo600m(NDLh`CY+KuKu7Ifs|JUOf8;LQ$D3$d@EqBsz?niJ~sZyLjmY~7#70_e2 zP-)bXQbfAeFwXe!nbEA3TqKBHkWpHcy3MyO=M6@FHtn%OB;Pwl6h!)xbbzXDgwiWc zdIHnRWnc^dyo7CC;%(K+4yrebq}(&1r{n@20#h0RY1^0_5fk~LlXDGI2>ccl0>Q_* z#U3pQJhn14jd46lAA;)(kUir!jP0r1DtI`cxPzhzDZm6HH8;EdWfZ*1qWR$w9)l?( zUC}zi$%I3oK83pGfOE_(O(2?})jh(HoCL}fj*h$D8Y?#p1g3)>JpMXOdvq)M;*DfE z-wf#H%NHj_Te%(M;snSo??j#zxaLXBa|nfY$gxkvR=8(Dp>-2;F%!!zarOw(GvMEj zNwGWJ4TPtuA8K^uQ@*f^2#WOc_|i|;$Dl1SSQ+TR+>dbW@m zLe%?v${@yMNJUES;x>GCBl+>LfgQ0{9hCZUJU@Rl>?O-;W4>)$&?hFf;1DWEf7C3N zhOYenY@TuE`<7fHT)e)g(l(Y{5yL?~XeQ-gd%NAMOKFr+t7#xe4#%%qsuSw`EVS7QzU3^%5@J0|j2^;C_h}1*PbtB%yMtukX8Q3!S-uW2ccjniBK!)YojW+5bm+{x}NOSdH;z?vz#)irieg)iK%a@>1Mzl9auZLxKKt z6El(8g8m0d*=RokjU&gmY|LEFRhkJpcVgavdcjJ{fzO>RV395BkEf`qklb%Ndf%W_ zWL74%%FZ~|FJvI?3@DTB%{>%?_E6otJ^L`!B)Me=QoET{Ef1nok))e}Qutngpy-W3 z$vEs5IdLAr7o<2dR!^jBx4k9d<%&@{3_rMPE(FU*>ToYxCWYF>cN zrK7QOheVAn!2n^$+*3g<96#Wx24tR}Te9pJGpqc?<90?lanm?$WbUt)#jplu*Ui4m z)@V@B1X3gFt&ej{kLQ%S^tM)YgDd97;oNiVP9#mu0RGc`Ld`!<{yvA+{M^_MSKCeA zs-cbcW!wJk_ru|72!L1@-R>Z!Ew}g<)GNoJM9~(Y^WX^)EZ-SxCa;duO4YMV)s!PF zYhEd-di3ek`>PxupL1yaHLNTq`RZ=$44&F~43laAZOoT>#y*X6IET%HTA^SQSbCXS zLYvPEB-7J%cU$Www`~BSspcSHo!)48g-(9wo`Ey$hh7$@p*q0&x*QiQP?LVFz6|5K zEGs*LFNP3cb{d{X>>YTAU@P;?ux{mJuO@jk9nsU&`QW&%0_eE%m{=WQapy>@_BX+3 zp0+=XresMF2r0Oi#pEbogE$&~@y3;ELx*{J03*XVqQMmcMIE}_CrM;~&BG6SYdM#z zdLai~OpC)K5)9Pc?o;78q=8};&QAGxJ&kITFe))pa?cBBufEB%Fn-hDZ7=!hat&Ew z$wEf#OBg;H%Gho3rYZ(~JjSgoON=OZe9&NS>>m>Yw+4u8=vgF|x%=>Ico45a* z{~0!JWn26pqnL7da7sEg5>OqB(DOD0ry*x7$Dmbg3m1^_!D78hT72zqwdi7SE{#ak z`7a4)tW}dad#fHxC7pZd1N~`5|6GvBbWWN$oDW~KF~NGfF^Ed@YT*bL6oZ0Ah-kOx z*uAEL0qZ2@XX7kZjAgj!e4cD(&pKthAXTi4GeXgRxKd@F^$Cd9vbuD2ruHD^L_^B_ znLIII@tODv(VIpXRKrlb?+net$^a_CfF$Vh6y=J|VqHvZ(dWOU{KJMlaX7|0eMRs= ze0kvv#oK=hk!V0%j4~8($R7eX7my!k5`%t_uQ;cJxx|hDJP6qao78vKb+m3lbe=${jafH!dFp zi!UnXhIOgyIsx+QZ4Uk&uLCtC5A?yYU2V<_>-pm{Ag`zGwV*eT(tZGyO1OdHHz|*G zuIdb5Be=CUp~#pyNmH$H&`G5Rs%kH=etM%9ImcWn*+9K*BdX)4A(>wC6$OR>h^9qfSr})t0l?<}` z)}wNsW$5__H$K(ebCDS~*u~#7rm+(~jIX+6@u$S`F>)|qhNZZM)}JT}6FS=j6m6JM#YMAHHO|zaZvUass9~4Xu2? z6+ZvI+Ug2OfW5CD&bzF*elU|rBhit~=j{kz0Dwe)y1W&)T8Q-a^<49xLxs_8eShPYRn^tEw_Ri^y z#l?C@F*R~kqZ6S8Q5R3R?_6A`0)rrIKaXDf%;X_$H?GWn<%uIpHy*0 z)z&jDqjOodR&n=Dp2#S!DO!v(YcEs{MjHFD1{PUU3`Rq4)M?zQvn~I?0Qbik-QwM{ z^VPMHKz!^IQF1BXBh_yB7;67|jHSn%?xTbyc2sXNmkkS;rMt|=)2|E zC)ZPHI28!$WI;)yc$g>?pqJ>gpB!MtpwoozXiOYr4$d<)x^?89047P97Hilrr_Is4 z#neWfLW$*Ctm}~pR%#G>j?%C!^?Fgdrmop!GOQa)B{N3}kr^Q(W;2ytrJZz7&;v!4 z*A1}ASV5IoB*QCv;|P6F9^zt0BxSd2UzGQWD*mDz13^Siq>KkE&-aPhFOhmG_)K>@ zD`jl&!m7sK%%|`r+xx)QYK`m9j892a7v5)zEm6H(@&wMA;SiMz+q#J|QHFgqz6ZL` zHOrIiI~BGuZ7i&@2e_1AP~JsNCx^9TZ{`Q1nb{Kiu#UrEJs5gNdg0p)f3K8dUKNy4E0D)tI|n680vIu7O!jtJ5@f$IshJx7=WgpbeNCqu3qs->rhPVUmL(BiJ_o!C%-qkv1BbI-vdWi&Uye6sVjQwuV1X2_*$grXD9;y7zfyyAh=i8}j^K zcGx(8XS`J$LD%B?3`?T!?DGaRD<$-1w!5g z((h?Cz3`;gR}l$m^bvS)Kz4fThk!m5c3~&EI$2H{aX7Xf1T{l3xI*$+j}~5z(<8!_ z6DY(w%?N*;tR+$+>YLsaEZgZvEU4&zL9a1epkA3LsMM9^#xOujregBo4EW-WVFEX6 z4Z+4>rU&Rmk&X>0hm0obBSx@DxGi4JsAotv ztPA2dtxrxQt|XwB!zk>l6wSkXq$84-(3weQ%}aq8(I??>Q3CM-tU^D4>LJK_&d~@M zwHEj|a8N1uF+rYDSijT}^nYaGF=4@`=tE(M=4<+Qeq6N^QyiMZwW{vcf|AI~T-H>V zobMUz&1Pjvj!-DC6k2zn-igYy;lNul$0{b9$nY>`O(6rpF8{kBVr%3G*{L=Ci%cM>P1OxVfuUX}0YaOfTE@A>z?x&x~%5!Kr-iJ+G+qyCuy-~VDzlfS<9 zuO`ij7qAWDhY@+q?pIubJ*CT}oj>tQPuwmriio^4Z!*P=?#Cqd>7&R8UFE4n*T0M%F&fJlZB*b^lZwDwJ7utM&Nbqnskqe5<)nOta;sZBhUQuH_ z(lCybpc6nuD$|NEVI*iycE%GNk|8%uMqs9Y4W`jLTB{r~$rNszFN85K|7?<1qsFUi z(RWdbKnA>xW<4l7X`M$UIEggHe1G8i_;GK3z6G5DnV&Nw4W;JTn{@Dnlm$nkDH(e` z6d=SreS2JCk@jJbb0M1k!nltzHXm7-L7iPPD$<9{)TfurOfm2v0T{0@ZCAxn1x9{%QPu0B_=?Z6q89)wh;kq;%U^( zb#)CL%gPJzUob*(@~(G`S-AOfxjN2QX&JH|4 zoY0p*h;J-^+h3fpx6IbA##k&#lL(1+Ml}KcQBJfLYa8qr!$U$yn~ZF?rHy zU=onP$k^LolK4A2^se_@5T=r*cxxoy3N2%T1wdv$@wCdUeKzxkD5$7ezz>p@Eu1iQ zr;(4vf$WTN4-a_zu(oyt-pdZeMR zF6&GO6XZb$Q{R?gP$1%6IIcsunxe}Ht>4X0n>SrX?#rr|K@yKhl}RY@D5Puw;}1`D zJ2lNb{nrRZpKH&3(R+ex%k`Ke6EfP6tuib@XFAhT3AHh`6dcWUT_AB>g*NN4WHa*_ zXUo1YYf*v#nA+XHiPvq9Hs}!Q$T!ssn_-r}l#V1sSt-NGzB3x=acA@!^bH!vA@8_> zTP_pEZPJ#QpIS!=oMZe9_PNsm0j#Nxf3Sg88zMkZm$_}+9>+0Nez}Fc;*u+DUL6XB z()WZ&VWB0URRShOD5EzQeeah%mup&!SDn0`z_c(QC+G>GaM@J!47?hty~~+lm)}uv!RR9e_>!`u zrq!-u8$QW^V7qoxQC7tl6-00IzER=esq|j*Iivfa=XuCO>NIrf>@>qS*b(F&CtrT3 zge|0V?b6!AD~HtilZNy=70yhO6ra#Fx>iQL+-pp-UK$tUuWfp@=Bjse_Q(3_j?h8y z!w1V7kufyPz@0l^&K9w(v(cDF;f-7-+WuqS1m9%?+wB@$3E4!@OH*{WshmC`ln>%j zuPnu_Hjp@lZZT(pOvf_sC|3l$F5|r7m*JR?)Zot#%PVZ;ZAL11qlZqhl(d$hE#sY? zJ7U0cNO4U_801=|B_CK7PK|B)FVMo8($nOJSD$xESvJQpDzam1G7ZZ0jcIGoH?o`D ztWPm@g2-E^nA4)CErZ@h&!WJ)Bp5UO^AF;Tq(4yl!@rPM&DX>8-?{j|d-cD2`Txbc z)5i2c4G&kII!FB^<+M<4ZvLG=tCwH6t)5!^8|qa zSzEz_GL-xVds*mbtQ~1gXgtQCc-1sSTaG(vrg;pTldr(V00qXR!Km4fo>fJLde5ZR zU@*0`CSz7MJ^e&4&7m=WXFoQZ)OAxOKCJATyw&jegV=E7>z38v*YEs`wkrF7`CI>n zWSmSKT`i2hq(cq@E7AXF3;+FF|9Q24&^ryO%KRmD^rZ?5lPCqPoX|A| z_T3*ZP{tLJMQ^znG_nvp6Gy9xGEqu#)7;M|ERj?}*K7xk;xvlX@yYbiVKX{CrKjL_ z?ih&ewy0^L(BDh7pe1@wAtV42P2B+`e;FtxP7YxGcsqK$$`C8+L#1GXs&oZP$7-mG zM`sDz84LJD$-+@)6cnOyoTWD18GuNO1+>ZvUz)V%OM+C)XAf9aOd}Pyp2Ruu<{9Br zB}%UVE(wGyxU2q@cdu{YGrP8Bw8$zB%7dW>y2vmftwlmROw^U%Iu?(_tlOWn3lTIJ z!~TrjpdNI76$CB(g%Hj^d^%|LhRA-*67>fLMiQ0|;C$}_NzMQ=SNLV_@Dq2yQCMZz zm1W%JE0FK6^{@V4f@BD(-}<~#T||CBgz3j_lxj@_u6pyQ2ac3YFtFQEF2_bYu%ppV zd&1x3#P$NjH|JW%2aXhfBVhnOuWIfAL8-IMrmqIDSH#lf!tt{M7ROC@p&S=dz5pyT z;*r<^uNCr(R7qCG=X+2BE6DY|C_QZ~^sZp67N$x%Up9jTRvp7zZVgNIsanTKNyrDZ zp@JcV)<#@C>`!1|uOTrYK_MH?-K)#xSxR7P|B8M4c7r5ReSBhCGF9jO9@uH3@7X-y zv%2`fj1<=a2B1M6cDBRzuq<53+B`0KMxxj}g4V0pjDHy|?>Ep=P^bPpGP+zTMJP-BiQMUiI#gej zrn1zKoJOfOs-n;r{n!5UN%5lV32|+p&sai(U-KzM~QuMqrxB|wKFL{yE`!>LBPIW9M*_H_f%5Jq6x7yN@=z35xPh_#p6-HIY|V#((4{Ys6`YulC`(%ok(B2c=?OWP&7 zg~&`WwBC!7u$eS=nvSHKimLocm3W)>Cx3(}Gl^&00}*7`&!@n|(%ad^g|U*dmq&z+ zj7nQ#K_3H$o>)u>YVdE?Kby3Rp!`4f-YUAzB-t92ES6<4Gcz+YGh58eXfd-auviu| zTFlJMlEutyG1Grs)z$y4s;=(3J@YUR^YA^MvsT8A+!47WBLkV9AnqW~o9b(`U>~Mp z*c9RTX+s#;p%x~?N!!=R1X1Q8A8ZZo+2`fKc7z4bL`hDJ$um-rWXW(+bh3Q7Tve7z zy$tv8snx+#jd9`i;;gfr-|+9@w=7 zu+KdK(TxLeU>E*h{h_`UU@AGyKSDZuwi5`Jd*)!An(!Q?g!%dFV**W3W4@GEb>3Gw+l)2vr!L`Ehh|CkvtCRdzi$ba zf%b)+41{2uxRExjjVa7}WM0CJ>`4;@uu-B>8O&m8oRz!n-+3a^{HGNBaBwbfg+kWH zWx>8+&EUr{IfG?&CR@gUl1YLO@Fs3$3-;R4nUMa z?O^sfMgF)QXOJ%Vglr;Vb*rh>LuVE=K0qdHcz%m2IuS z;%pTUhkPB4_j`ccf%*wzoyaVuu1ajNLK!?AL0RZ&b#|qf`(smcKZHb1ALWV9Y05wK z&tLsU@cNS&IUun9{Qm0Uqkja~Klshxjj@024*!g}e|BNgfA4X24z>XQGBb8|{44jJ ziA}Vm2e|Jn;QOl=Z2qyX|M6%4W=+~LGPVJL*UQeHp-bCf-S<_U%})KS-xc7Llnnc4 zD_kjXjFa9TC-Hlz(?%KZ-#oDgu7SlKj8H>te=`v4BaRraX2D)hZD>BaofS*nBdzH?$zW`gw6 zwEUIR7y*f;KamBfBZk?YLSqiztDtV^UO=h<7{rARLTtA7vgfp9{Pr&GD zH6E7}qEj3?;&sJb?${>)L2*nKX1G_uOt{Y2NG9eyxmjquVdBf-((Z2KjemP_E9VpK z@9`JiagYEiAHLn~ur~dtoBhfrUkZbwg#k}w3<5GL#=niNwXKc0ldZ$=xg%1!%VznP zS>=$|lc+_8Cr8Ki1|g_4@P_k(F^9>&NPaX=j|$Z_9O&UF^m^*vo}R>+P9PN&5#%7U zFcV#IfuLN{WYv%^6Xapk>$cK)XUWO_wt8s_J8+s(4F9P6pfUe+f_}ToYJ#qtsHukz|6V&WB>^Wn@Q!Wf&lJX;*29At zN(n3K0B`7U;?YPkom7`;DX{y-+0->7vWit&$70CueFFO{wx?W($s!QSTDzxPQ!4XO zyPs-8Fu4UVe#N!M)DLk5Yk@Xajp@K9c05qT5+c!4Zk+eto$etP(eRf-S`eI9B;lY~gp$7H9@Wo*)SBV44 zL%L`?8K;Rh@8fN?n+FFbM_5KYOmonpmJguE2o74$$xLPLq=ezvU1RkfUK_-#2h#H& zN(OoR*Yqd=o}d6Y=zrkA|G^dia86w(E60DOO6PxJuJkCq`c@(Kv@XZNw6{3XfZm&>&c9qWyRDbAe#qkEhCH>Yv)K?z z3!v3a<7BBay29DdLj`}>3CnxP#BN}>d+}9!-J-b>oI$#91V2^p=Mg)sV7WeU0!JJt zTbo2)^yUQO`?}+s`z5i)-c4$^-F`2EP;0v36V_{7B1r3Y^(3$StHBCX6M6eT2ORyG z@bUjWDL5GD8~zp5lR{bUy8__*0f3MHZ~V<48xeH%jjYXWbRBH1{&*;lWw2eLhY50d zgMNn*i&__86*LbkFrRZEyUd+hM-7GO+;ua*Kh&N#2)xRvj*o}O7u%kj`PoFW4{Gx` zKw*e+%8o!Y&;Yu_m^p>G*^Z!&`p0(`m+RFM?86$_FPiwDXj@N2a;X-H5#&-IQ#5)- zmKLsH#3WMpzIB;$1}V4X!-%=^lHCTI+5ZSQ*?hfvA%iwmBTeUuV!(>FEXp zXuCx<*}`I9MMC`IC~u=bJ!3piw98QRDDjeZC}LgQ=mT;8&gFueeaF(X6g-ao>tdio zyn-C3H-8X5|HB*>ydyM84$3F0ch%+Q>_>D)3X@8ht|x2oi}1&Q>E^jS8JQ_4Ry<^Gy85#&EOwPx6_-{`#p=Y}Ki zsOMV$AS5XPnd zai9p>`0IyRhnZKAh?DJytIDSX6W1f$cJ#wde36-`DVbS)ifYGC0dp!KsjD&2r9NAg_GW(~DwR zd@>8Li3y{}1Fn&t)zq?-<@DB*kxRY=m_ukoI!JVwsoKSRE%~Vot_S~sYBvwieCitC zNC9e-TfQ*6Rf&hrdXKGXNsvjP*W1FN2u0mZ0llJVZXpse#jg8al!Y#^TyE;j_ez>D zGW*=CGfl)^2cn)!qNJ~RY~(9`Iutu)pUGi5c0GvzF%^%RtHDGwo0^455N~6Ig`u|M zET0x8J@G(;A)$U_j;7Uhh`4wR3rdvBVBHQevG0`Mey3!4haz_}KnT?i`RbEGM}(Ix z%?_s~Q+JM4G8=qTs@A(dkYuxaAnM97@UZ&slOHk;WfYF@Kv-)nlJA&_+OaT6?DPe< zLDt36G9UiFs21NT(YJz_cO5bM6NU4rWV#fZ?5CPQlwMd)^RH-eKOz%!rAi*or+n7p zX4eWm-tpFitKfa=SaO-(K2{&^3Ff4G6WU*_)OaJj`@Lq( z|IfGo|1Mou{Yuw!S-+#}yP@`4@o<}T>MzmJcoOTA4I)hWTY={{T}4J;%^JVZ2r>lW zF=EOfYBzq-Ky^7v!E&#s6np%Jw1XO&{=ULv>OhiJqIagCy#UodhV_=aM`5~v!}9#A zEWxY|MGr!TTv!`{Mw$m%OUsMrQ&=}fqQrib;b{N%l6es^gb(}uZ0bGq^>Rw%0%Ghd zH+cj7;bHZ0%q6<=OP=@mbxFPQ3LnTyk2W_P>;vX{Nf)uK32QdC@%Ol>GkF3?dBA9| z-Za55v!K;*-*1+fQI9z4$k*}UxGikLti8=QQvGId`vWFmnsT~uDQNg?spxW6D{R71 z5cW;&p_OqqGy%kPq#jNCGLOfruLK;ljCDQvg(y7T!88IM@w92jVHWCI@U}p})b{{{rK`#o3X6;%xGtoQ)^R32Gf~l`gCleHL(u^St5-PT|)%J_t<` z7qAQ6j6l4(UQ5X?=~uDAqU8EDnCm_p#b)0045l0g{hjX8B&MV)BEQSMS_LaK6l{bm zqiAf;{t1VPtA4RXY~&PsCTQ+n2Rv&lboMk){LWI?)Yo)=N&NVxK}if+orV(Qqb)h4 zf_Rj9uS>15+t3xF$0Fp?eHZ6OE0`Gfh*TNFVIN5JAw}fNev-!epOj6)?elgE*?%p; z&6<<)ld{!~(U=B*p={K*aEmtcx0JDyo`;cNDEoxVlXa#?AUqLg9~gf_kYFCVQ&HAK zT|9>-H&Tq-tet0$?8}dt$Pwq@Rp$Hi3Zn(y=Ipd$Xu529#N}D>ajFrudA9HCy}e@F zH*(!1EM(gQ>6&L=jyUIZw)L-z?Y6$J!(}JY%fm?KTmchpKUurvm8mR`OrGqr~0e}tp--G>M^0pPbuI_NV_~iVY1frW0ZhXeZa`(G@_jj6xibaC3 z1t3lYgCs9m>Rk%Ahd` z5Y+;ekQ?)-zlWpe+P9-dSm;1%XXfw$?SB=<6xw|9<@mhS3TtH=tNhtHHHk`~8PQHT zd~BMF<3!3|Ty^OuZM!r7M%$(U+SdJ*wjBxeU4V1)1f0+FpZR7ltw%vFD zw0&Xo=Bq`w^>~P`&k~7z9|_~3tzBvLJ@6-UbDwI00+`!*-a8`fu79M0WY&}O(8q_O zv~A+<-SZHY>iWqu(2B&wY>iebj4KtuSa;52z~mWY4!ntxq1J_ zuKs<)#b2^^eyl+BcR-ST_JWdlTj^`|aYeoYTU85T>qotfWeTan)~Ln(O>1pUmURF?;tFM-`j!XGfQ6muNiPb*08m z#=~j*h(*^G&JPJYJ8)zj?nt_RuWCqWnnKgMWV^Ve=@lWk6wv~+az{zhbQYFFSHR> z6U

GKqRLds?to-dykIJ%I0+plydmJ_Qe6;M2~dA$*#)HvY2Hw?lr{D&^C%%tyR0 zQt+wqwl-UAp^C(8Lh;72`$WW`TXlIm*?Lt|$p`h?TEBQ=z!fFO%LBVNc1M1ioUN

wLv3n_p6Fz}>7l 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

se5JaDS=ysy&kioJ8MgXkt2!b?ex3=ur2-w~ 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⪻0{uf zISJQLgsV-4Nw7W8@m0@}W*@VGWSmyYX6Ihg01Hau>n!B2BK%z$`;m|A!f4jykVknI zx+n99g|bwah%k{uP72c3f^3$yoMzVr_sF3Y=u=whLS~JLg_{IS!R#_S2jtU@5zMVw{&VpL`3l(X=_s9C{T3>{#OBv@rP>K5lsj&r zPLsEgtz3P?Ns0>iexo_)11=3$QiOx}XkTZ7aaksCp})KU7+NpgGx7)VdSN_JN5R-)B=S?ZEkFA_!AN&TD zpSYQZxd-k?To5?nbWP0Emj%MNxWv~UZp0NXSpFb4ZKHsuawrICVUCNUb@*w}@6VQk zD2N!}TQ5bD8cLpC;NrN*X#MWJ^qL?JIgMW#Li>rVo3UaRN^xc^DL4&v7I?x7c}fGO z(eY%8GD6v@W0vGk6xtuz}KFt&%A3xC*K= zM3#hV^dNuLnd6(ep;73Z_Bks(n5y?_{>035Xb|2B%e(`~ZxzeAP_Z!q$J4u&4BD_y z--eqm?q$f-)7KMi-&Jo^%Rq0%EuL+jZ!RwPFG%{-p@!OXf@y(fW&b+>R+ZJx+&rw3 zhYSsVC09BSLayl>5IVX>us07r){k`Tn={ojQj!5Vek>D?k3`=3YXZB{RIYXWyrsB7 zGe&pow|KNYR=5UUyX{+iQKW9QRu&3pZEvI!) zcJs=`-2B=$wPlVu$c?#P4gkCkCLM^LUD;%;^fUEMr*75?Ht=n5WxgHBijBGY-T2pP zQZ3zxbM+x^6%p!S5`KFDd;*S0uQZD8ZbhPnzl&Yv0!}8!3kjKjRMzPzyzjQdQP!e_7%&~|?+eA>C)9#7${h~C{AOjJzJ)=ER#1zt|1HUH<%6oavEN^^fo1gCs6e@+{VJpVvSrazVHOUuv>+?z&1z$}e z8wbyi#@lC#j)mu852s!E{4jz(ZXjS41n1XItS61{z!NaYk!XlCT;aPkt zBBEaT)Q~Y)i=FlQKDNg{qpCKUCMmQ&*hl&cT4ES91b!{Kj-c;?jYkE$n5TbhH?|w{f!DXA2H-2e9OJdX?sv$p-kVR~1bapjq$Ex3EUuke*%k<#}yB}NBUYOu#=WrH) z%lGp_?}nhSiZ);CfnGQ}^;M>ZK*O&cvP?C1iI2|R$&!El!)*ohvxllvI~!AcuP;kr z>yjqI@<@_sEy8lMKU#{lP*1TT+WsUzPGpo6FAmx6S^EvP*ijEW7+@BD(996|xT0jDkWZ*Ij7vAIe47_$e>G&2 zQ5U-JXmvCx&O)!2gu3m;l`|zXetc^rG01L>^p3S3J}KNI*5c#y&C#6PrVKpAjuH5& zxlGg8U2s5{C9*zsy1DI0>i#U-UFT~y;cr~$9Q3&X5 zi%lmkJwBLBUcR&TW>dbVZ1)_j;+P!A5fQqIy)NqbF!3Q7z zn$qM>uhWM zz{=G+ct!!dAv=KNhKyVD6O9|sOd^SreMqCblIgMqLznfw(-h*MSkF*;Ua;g1y{`3R zk;1PTuWEg!`Z@yZJP(aRptdey%?1=h6-rd5Ap+RMZJa_6c1^?nFLIoj#If`H+5ce z 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�kcM+I^P}e;QZ#k zL)m%esfBRiXAhLmi(OP?jeEzYjP4=(zj})}2q5SB_ysl?ucc*=DOX}Y{zBRXzXo;jgVL<-5jzt0tJaoyIY(e9ocu=h3!=%XAZ_kSl4DSI(*k|w)y#Vuyws{s(D zVMp}4#+syRxgkIQUzSw|^TC@ysOzEnv4tVXvMLGnZ+*T4^7+!{Nct9-LO~Rk+8C;% zKg{Zb$;3CAl6IM9vYa)XI%h*WZMQ^5 z$qN)1-+jdwFeoYaA05wa5(1(G`CMSy((wL6(*Nt3@nu+@%%yNZ?z?4XMYFFVnN9$p zxwO=K4^NdA1w@_V?Uv(8((^&fX7{B^wE+1mLa1vzrIHHJ{iIFuEWLAWyd#aM&oM2t zgr1buu1~sDD!RQ$G7Kwe(d{OYe!5)nfpMq{kX*xZ^ep?d4X7Xvk{drg6KLN}S8i`{Hc`CXfwU z4^9+70->)zwQY_;;y`Va0GHMO{~h+<@32t^2{+V&@6;YB36l8%ZYX$@I30lCzfYg0 ziOwwd0Y;p`LGt53{{LdwN-(ccY5VNrK_1EN$|MkIG>IJ3ac?D?)G z`H356Vz;IcAet~*=msjzBHJnkSF+dxpu)?OArsd@uwT(E5w-`UkTv|Ny6gn= z65KP-fnbAWBqqUmk%I`y`x(+~+OrmU`b5j6NjpwdWoD9)Rcz=A5*ECXNI^en12Qo= z#Kn=1?RxH16QrDVI|~~a@2n^rtekQqPD;1E%|zJdWA+)Q9DyygKODuZedQ%HrTtcm z{8`#}n$!L(o8aKW=-P!JBvNe8N-M!;v;v)w`ReCqpZFQsa~i4H0`z=OnYu_vf;mda zB}viilO?+736jx3!%2{~k^m%sW#I)$?CRCfj5@esN-}xhUNvR&UgvRQ@V~aJ9AP*Y zZz(q5JN+d9W1OnZiTb_eq@Htw^o}ss{9uw0lyQc_VnqC8qji(K?X|;8lx0GHeq++D z49-&hZea`(Q1RDbJJL2k^w*MVnEh-jWURweirey2jERR15D^ zb0~@d3fh{g8H~2KY-qgn&Wx$VUYkI{Pv|hRAYiosKtR90YX0NJ(%;Q=@ynuM9K|GF zvQ;d0$+)X8j%&W%C!qFOIk-1gk1F0sA&6Aa;-xzaLF>BBW+uEyqQE7~B{Yo=oGfho z04cgQgpFcB=t8VY&PYt!Z<`nWV@-MO%IY`}=6$0;$)$8uy8IL#62 z(^7DH?WBjX&c(ezIR>ptdT?nxqfe>L1j&RzEP1@RYkI*QvM2NdHE`{!%+Qv6ScjJZ zlrD*#;Fks$?Ga<6YS7@(_NxVridYQ}gY983uDEkGyyU*hoQkEV^{U#n!X|?SJgx9H zPJ8CNR+a#BQjB6jWjZ($HZvv{*x9?%d;`gkiQtI1 z!i-`UXwo-IVyFuU1RnW*NSx$A#G84_G%l|6v1E#H?WqleA#oAkuf{QS@F`$6khZc9 z8Ywg}?3vP_Z4qUDz5tnV5++4ZJ9J;G zAe9C-g4!R+U#VT03s+z0xMrcGKNIMGuAy*vLAi-Sl_}~qBJAhH_K7@$%;|-4{G_KF zL~*q(1uv)-;vxAgOjD<33y(i{9Iz2*f}Yj?4l8~ zT;BOQ7f1J>1Dw&MdE{fUNEiG_&uEO_G~H1U@6x&()_HVTlMv7^=G)Uuh91;U4g2Ev zowmLdNe{C3tgDaMXEyDx;`r~`H+!JCs%Yg71?~q$&_X!%%tN8>ORnt9Y$|i51=6ii zA(PQr?JVDo@%ITaT}dvleVZ|Hcj|=n5SNL!=x*b_-Sf#~!q$wOD-V_#U~)}a=SZSK zn&!JA17R58;C*abtcHoXbsQGiRaL*ei_18I=T%8te^)0kTC#h;0IH#7Np07X9<+3_ zz2N|hjBG#q#qNlOd^5xTHwA)eyoid_Z0NHn7+sy*mm%e*9!jk?Co1e_c+odu?!Nqk z!E04bafu|noUQi=`@zZE&Fdf9N+)Xc)3oA7lLajXF=6|cr>}QjwSm|Ig3qpSc}D=P zzBHe!GKv)ZqNYyyXlp8^WDAB zKbbnh839m~InzQJn5m`vK&6XanjJ3dKB?T?K9GE@qWnNJF9c_a*|+iowjCMqbZybC zn6rjpnkQC@-l3b;Q@nSWt%3;9iO(!_CTTD#E;2frAh@L9bDc6$c0t*-pVSo>)~-2b zuyl35t*fuv70#nX^;9vTY0$+o^-N~j3!v>rel#N+v zp~Fv9o{AKr0KBbQ0F3MKimYNv|55-5O=lM!kD-+Br$mr$kx!d>oq7g|CX5BNtYIL@ zI5FT`+1wPt58HuFBAer13m<+Nm9IP+_G|g~j&Ebn^3rOkAFPY2=L3WC2K;er2Us-{ zI-Gc$7eKZQ!|~2orv)FB;M>AU@Wb%k?ByEt4nwWF8iOY-RMUTs)HI4!Wo_I}qU~O? zJ@qe&>7mj;m(u)1R?j4C(AkkGn5-nL>f22?xW-@C()E12J(V_fUISn5Xmo%`(HMX< ztH%?L$d8v9u|ug2VuP8kvEkir+259A_CdO&_Ab^4e zkw}MEnsVi-F_Vkvnz!V3e2$m*9+t@YR~v>CoJ!v}+ntOHEBh!Nj#TFrs~#fweK_4- zgEW{E#dg1{pE%sKA!bWrubXz|eA;DB427_AxZzyr@cT6(Q(sGayX{H{?l*SP-)~YN z!jpF#`ZZs@{i(2RiLoBP6#v?3&?WFLF`M!+PhhzA+Zcvmg0ctN1nQb`a=2-PUpR`w z_ZXe$t@pwwnea}yfGJ3#`NJCfMS!YPIVK&rxH{z?LYRwpFnTl?z%fx2x!J(al1ziT z?^Ky$VfBf89;}-KX8qtgjk_4N;gKA2_N0Ry?w2TE(JT>VT5NGs8y%+UL+=u0jyY4~ zvDe=7BeVAU)i#$jt;dA5ogz9kXcqsYcBDMs_iQr^;NnFdkxl8L&xhl`hKJsT0GKG% zALs;Y3#aI5Kdi_`9^bVPC!Q9za3J%WM>}tD9=>V_VSnp7`paaxpC+zKED7C!C0e)( zQyOe;E=q5#zM z5K)zqxPl&Fank5-TSd)7glcw^-ud2%6*OOapmXVj8jOz1kmY`&xEi16$79I}?J;Gfzd)aEjz}86 z|CGdP?YlWwJj_-~oCRi>h~y{z=GrWzBbp4$DAv&{gpRQc39un5KdaQ}hkJBpS^j*} zlOzjwH&@sqH7))>La=#+g$Q+LG%x!4HH;r!82BtWOfz!02mrG$k!+xY!o0r zVN1nRJ0}J>>lz^D1jY9A5lp{hmIgOJ--ZW~;yEDrqreCBGp4!M-Cr}=?gRh)EMg?} zs_@FLe*OCp&S!^G{VGsd#@gJi9yX|unQ$6W^7uR;Mf}w#foA1Y07$9EbK58=fLhN1i&6E0Fz^za~1#2 ztH^4hiee}E+e|ax-+=c1u5Y=W- z^6m2N$PPFon)=DMo_`EVE=*HU*>!8ltyaq8cbr?^=ig^_xK932sSt2J#pN8KSDnOv z6Gm(wET6DZUbC1SitJn(^h*;OsupNz`6AHvf>7Y{hKF(^7K;g}6M&~?_VUT)-E8y) zdFxE6314P+y;Hn&QG(`X_#?;?X-zrz)7V+@`NCA?Q&Y{cQEn}4d)q|TW==zWk%CT8 zd@xTi0V2#SZ$m@}SutTAWb~RB37Z{gK0mDi&%xzvX0dq&#%!ONsOvprMebNlco+(<)<-|fGk_0_Mv=dL-3iB!pHD)nX3VimK#$Y1<(?Cn#1q1=H^{nP zfvp)idggqj*{ID-Hx^B7PJ8{Wnk}t1hM3et46)gF*keXVo3Me@7N7d?JFx|Y_K_}; z+?3SrjcYwmhL|GHLKf=y8oNW)cX`@`snuALBT$VNpn|{C0iIgo{m622^&akznj!&L z1E{>1G$D&>IAeYfsOmX;3mf5HSXAx?LdA8{fKorhH2CeGlH7+;|IG11Urb(MBv6~+ z@0$ZE4ILZu;M?90{dH2B6a{T`>Jw8G>~Cg!<|dIj5`-%DUxjPYeBX?RpYQ(o1fQkZ zee(?;nZkbK?Xc?oY%uxc%y;3JI0%FBksNA^ZA{iKa>=79XOCD*NLLdt0(O5xP96bq zzf)YL?^;GL%IpQ3@M9R62;ElufiEP5GB&h9DgGA|O+V=3~liF?A6NMXZW#kYNFUB`-a~8G%nohM9Pd`=xQ~rcN}w`n}-Kb_ylwu#rR3t znj(LQoP1b@Z5ZXsCGVoPK9)Z$hgmCIv!7lrWWBM@ic^2^EA=UcDj?4bcGrI=H=7Qj zAsiG|ZW5M`jD!zrAZ>u`GiiLPX8ARJo(BSVsi}Zf!ko^=7T=bUVJJz;X!f(M+SzFR zSDNXN1byfzNkBA8;UU`;ikMFZTbjliLhU`lcYP7{hO2QoZte!W3AQy<{X$XY&^i1# z@!;jEbLbOgcXaP~@h9PY>Kc8znTAj)_KbmH90>Ac3C%!+n6EyXUZTLLC%8Lz_^b>eLOQujtOUyTH zsc(hfXYFDowkw_jI2iy_id%ku0o9p~zrzeK7_7)RKSUDqXXH!36i!8Jt7)#Z);tM= z0Pcs0c|({l@XSQX!#B^LL>Z~5yd=qHl^$`VwQzR7@lpzc}g}XsRNB$oEjHcTF-CgUZp4Apgyd{ zJx@CCk7XMvYfCkgrq?D&(2YDr@IZEG9Aa?WHbAtVBaNcxbqnI$g2!*)5rZfJBIz0K zP8T@39-h#M^NTf1(a9=Q`co!w;Qr!at?3S4?mZh729dWjt0T4lik(yF`U)eNnMYI_ z8|vHuDPuR--~DB2ROsQGdMXCLA@MLvY^*)jw;m@#2&lIFO6iK2xH`N&1KtrusBedI zzta?wNE6<+VF%&#d+u-{74KAJAus0@z*l6I#C^^E zK)sr3zEKWb$FnC|>6<~yJz{QSR#O4%7+W3HGvI8y(%TdEe3&3pQGb7+7qCvo^u@5i zfcf;PxhDXSWrK*FEg+3H&3{Ed_okQ8?cZ~MpX7TY>ijHiBSlG_b(pm&;iEFHb7g~% zUtp_u^0(bu2M~~Y(5xcI(NWtmfj?+>IsAeS(0ZpgbS_B{;c3_^EHD7xQt0^t`XO!f zb;25fqi`g!s_LsB`FjPT733_~Kp+nWQ^_%etX$FNQSb7Mud+?8G@}W5x>q6ZVT(9~-4VO{ELvfy=;Fd-^SqOA{7WcSC~ z@|W+=sd{i#{fQ1CzXCTwQ#~BI&+vAXf!L13hg|*IYN_NtET>cNn)p76t5)SWIHXLX ziuRBWI%w3=AEy%sFY*|V(!*RJh#>2jz)~tc7HWsB?9;?Z#dJJ=`O22}<(B5iAMrCF z3CSv-0d{1dh%ZS123+Oxl&Dg%Vi`04v3NrtN#Mz}6(0wb>52=q3W4Fr2>c+TVrl84 zVTT^dD`gI2$719(nT^>`BeHSwSAiQ+;>u;Ce;%e>i_?9M=gaW;D|7~6S`597G&?@* zY@rB8;a`OQ(YObAq@UB^cyzN`jVxnF2{^pl$L9X|hnmsu+1`t`X&l>GLQqV5E4C{i1^Y*4zP*rl2^l zB>+IDPkuTRg`L3GVjgjT16mxb$C8xuT_bUz^2g4F6mmn}*tyi+y`2!Z_w@BMst=*+ zITqGj#`~vkJOZ#0W_!IloLg5RzxfIH^;J1R`=zDAnDn$)mL;M;Bc}~A$vlzXK?Iyq zG|A}CJ`pG)K1&#g2lg_3(n&|M4KfdF2CWJ}Q1G9)|F&SCI&F8Ifb`$*QL7u|5n4Ox zi8qroxCNKOq+mY=W8)?#XNud8x6aKDQZO(#?n^dpFC#Jfi~zQ!^Ef71Y{m+hWB`es zbh&VSz3`?VdoXL~oq}qhDDQJh1b?6BQMV4G2o-7iiKI3m}_X*uczWTx; zU2M7Y@&2{Yhrqh%h|oy-${Z+a#rM}nEO%s7D@>N}9%nw`i{5(PPY$Mi2~?t3|i7kb?}txF{NbF%{+ z@L^;7^4ehp1eTTqaQsem%hEm^wtxC1%ZeQx9$hDa3yh-@jmVh<3EKijG$hc^)stTX z-89wm%G&31D`huN`alu%jg(_&qK$;#7QhkBtfJkb0wMYZ)ouMj*nK!bO#kh#3dKvW zV@CBxs@wAA(yDK^12bmMZx>Y+maNYG4kKr#XKGPtk;$WTez1kqOBwsF4P#1i8!ZoY!lO=|;81cK6#`zt&7gsaYVm==Qh1$)@f2B91Pit{7_chI8lN4* z-WjOL`!AqF;ChEH$mACSxT49&xP`+s`aZvV4bn6q!ro;jJ6LsTh@&R0iRVK7JUzE^aP>}@hql2= zekvI55<&VVર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ʛ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 z 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 literal 0 HcmV?d00001 diff --git a/bamboo-specs/bamboo.yaml b/bamboo-specs/bamboo.yaml new file mode 100644 index 0000000..6dccd67 --- /dev/null +++ b/bamboo-specs/bamboo.yaml @@ -0,0 +1,99 @@ +--- +version: 2 +## Plan properties +plan: + project-key: ITTP + key: ASVICNV + name: AS-VI-Cloud Native Virtualization + +branches: + delete: + after-deleted-days: 2 + after-inactive-days: never + +other: + concurrent-build-plugin: 5 + all-other-apps: + buildExpiryConfig: + duration: 5 + enabled: true + expiryTypeResult: true + maximumBuildsToKeep: 5 + period: days + +## variables used in the jobs +variables: + ## OVA build variables + hostvolume: /data/bamboo/${bamboo.capability.AGENT_ID}/xml-data/build-dir/${bamboo.buildKey} + containerregistry_release: devstore.vanderlande.com:6555 + containerregistry_virtual: devstore.vanderlande.com:6559 + container_agent: ${bamboo.containerregistry_release}/com/vanderlande/conpl/bamboo-agent-extended:1.5.0-linuxbase + container_semrel: ${bamboo.containerregistry_virtual}/com/vanderlande/conpl/bamboo-semantic-release:v23.0.2 + container_mark: kovetskiy/mark:12.2.0 + ## SemRel variables + httpsaccesskey_secret: BAMSCRT@0@0@FyHDe+gBcijblOU8jpGcEEwxpYBWQ0cl2NxEgACy5MidjyRlcZKAS4YXC/nLS8sOXZKHKBF3Siyeh2fdnAjOeg== + ## confluence documentation patch + confluence_url: https://devcolla.vanderlande.com + confluence_username: srv.conpldocs + confluence_password: BAMSCRT@0@0@UxPtDd1NpJ/YoYuImly6ZLqS62SCxPQK5uonPqkfF94= + confluence_space: ITTP + + +stages: + - Prepare: + - import-variables + - semantic-release-dryrun + - Validate: + - docs-dryrun + - Documentation: + - docs-changesonly + +import-variables: !include "prepare/import-variables.yaml" +semantic-release-dryrun: !include "prepare/semantic-release-dryrun.yaml" +docs-dryrun: !include "validate/docs-dryrun.yaml" +docs-changesonly: !include "validate/docs-changesonly.yaml" + +branch-overrides: + - docs-.*: + stages: + - Prepare: + - import-variables + - Documentation: + - docs-dryrun + - docs-changesonly + docs-changesonly: !include "validate/docs-changesonly.yaml" + import-variables: !include "prepare/import-variables.yaml" + docs-dryrun: !include "validate/docs-dryrun.yaml" + + - development: + stages: + - Prepare: + - import-variables + - semantic-release-dryrun + - Validate: + - docs-dryrun + - Release: + - semantic-release + - Documentation: + - docs-changesonly + import-variables: !include "prepare/import-variables.yaml" + semantic-release-dryrun: !include "prepare/semantic-release-dryrun.yaml" + docs-dryrun: !include "validate/docs-dryrun.yaml" + docs-changesonly: !include "validate/docs-changesonly.yaml" + semantic-release: !include "release/semantic-release.yaml" + + - main|^.*.x: + stages: + - Prepare: + - import-variables + - semantic-release-dryrun + - Release: + - semantic-release + - Documentation: + - docs + import-variables: !include "prepare/import-variables.yaml" + semantic-release-dryrun: !include "prepare/semantic-release-dryrun.yaml" + docs: !include "validate/docs.yaml" + semantic-release: !include "release/semantic-release.yaml" + + diff --git a/bamboo-specs/prepare/import-variables.yaml b/bamboo-specs/prepare/import-variables.yaml new file mode 100644 index 0000000..2bbb35b --- /dev/null +++ b/bamboo-specs/prepare/import-variables.yaml @@ -0,0 +1,40 @@ +tasks: + - script: | + #!/bin/bash + set -ex + + case ${bamboo_planRepository_branch} in + main) + USER=${bamboo.release_deployer_username} + PASSWORD=${bamboo.release_deployer_password} + REPOSITORY="nlveg-gen-release-local-01" + ;; + *.x) + USER=${bamboo.release_deployer_username} + PASSWORD=${bamboo.release_deployer_password} + REPOSITORY="nlveg-gen-release-local-01" + ;; + + *) + USER=${bamboo.snapshot_deployer_username} + PASSWORD=${bamboo.snapshot_deployer_password} + REPOSITORY="nlveg-gen-devteam-local-01" + ;; + esac + + + # Inject custom variables into inject-variables source file (inception) + # (Bamboo does not allow proper variable substition operations) + echo -e "\nvmname=conpl_${bamboo.buildNumber}_$(date +"%m-%d-%Y")_$(echo "${bamboo.planRepository.revision}" | head -c7 -z)" >> pipeline.parameters + echo "artifactory_username=${USER}" >> pipeline.parameters + echo "artifactory_password=${PASSWORD}" >> pipeline.parameters + echo "artifactory_repository=${REPOSITORY}" >> pipeline.parameters + echo "var_file=${VAR_FILE}" >> pipeline.parameters + + - inject-variables: + file: pipeline.parameters + scope: RESULT +other: + clean-working-dir: true +requirements: + - AGENT_TYPE: Linux_Base_Agent diff --git a/bamboo-specs/prepare/semantic-release-dryrun.yaml b/bamboo-specs/prepare/semantic-release-dryrun.yaml new file mode 100644 index 0000000..00ccb2c --- /dev/null +++ b/bamboo-specs/prepare/semantic-release-dryrun.yaml @@ -0,0 +1,55 @@ +tasks: + - checkout: + force-clean-build: 'true' + - script: | + #!/bin/bash + set -ex + + docker run --rm --user 555:555 -v ${bamboo.hostvolume}:/code -w /code \ + ${bamboo.container_semrel} \ + npx semantic-release \ + --dry-run --repository-url https://${bamboo.httpsaccesskey_secret}@devstash.vanderlande.com/scm/ittp/as-vi-cnv.git \ + --verifyRelease @semantic-release/exec \ + --verifyReleaseCmd 'echo "${nextRelease.version}" > .version' + + # Function to determine the version tag + get_version_tag() { + if [ -f .version ]; then + echo "$(cat .version)" + else + echo "$(git describe --abbrev=0 --tags | awk '{gsub("^v", ""); print}')" + fi + } + + # Function to determine the commit hash + get_commit_hash() { + echo "$(git log -1 --pretty=format:%h)" + } + + # Get version tag and commit hash + version_tag=$(get_version_tag) + commit_hash=$(get_commit_hash) + override=$(git log -1 --pretty=format:%s | grep -oP '\[docs-override v\K[^\]]+') || true + + # Determine gtag and template_suffix based on branch + if [[ "${bamboo_planRepository_branch}" == "main" || "${bamboo_planRepository_branch}" =~ ^[0-9]+\.[0-9]+\.x$ ]]; then + template_suffix="${version_tag}" + elif [[ "${bamboo_planRepository_branch}" == docs-* && -n $override ]]; then + version_tag="${override}" + template_suffix="${override}" + else + template_suffix="${version_tag}-${commit_hash}" + fi + + # Write to pipeline.parameters + echo -e "\ngtag=${version_tag}" >> pipeline.parameters + echo -e "\ntemplate_suffix=${template_suffix}" >> pipeline.parameters + + - inject-variables: + file: pipeline.parameters + scope: RESULT +other: + clean-working-dir: true +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent \ No newline at end of file diff --git a/bamboo-specs/release/semantic-release.yaml b/bamboo-specs/release/semantic-release.yaml new file mode 100644 index 0000000..66919cf --- /dev/null +++ b/bamboo-specs/release/semantic-release.yaml @@ -0,0 +1,14 @@ +tasks: + - checkout: + force-clean-build: 'true' + - script: | + set -x + docker run --rm --user 555:555 -v ${bamboo.hostvolume}:/code -w /code \ + ${bamboo.container_semrel} \ + npx semantic-release \ + --repository-url https://${bamboo.httpsaccesskey_secret}@devstash.vanderlande.com/scm/ittp/as-vi-cnv.git +other: + clean-working-dir: true +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent diff --git a/bamboo-specs/validate/ansible-lint.yaml b/bamboo-specs/validate/ansible-lint.yaml new file mode 100644 index 0000000..d63169d --- /dev/null +++ b/bamboo-specs/validate/ansible-lint.yaml @@ -0,0 +1,22 @@ +--- +## Molecule deploy and test +tasks: + - script: | + #!/bin/bash + set -ex + + + # Run ansible-lint for the first set of roles (cp/lifecycle) + if ! docker run --rm --volume ${bamboo.hostvolume}:/data \ + --workdir=/data \ + ${bamboo.container_molecule} \ + ansible-lint -c .ansible-lint.yml; then + echo "ERROR: Ansible Lint failed. Check the output for details." + exit 1 # Stop the script immediately + fi + echo "Ansible Lint successful for all ansible/collections/ansible_collections!" +other: + clean-working-dir: true +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent diff --git a/bamboo-specs/validate/artifactory-ping.yaml b/bamboo-specs/validate/artifactory-ping.yaml new file mode 100644 index 0000000..d76a1b6 --- /dev/null +++ b/bamboo-specs/validate/artifactory-ping.yaml @@ -0,0 +1,10 @@ +tasks: + - script: | + #!/bin/bash + set -ex + + docker run --rm ${bamboo.container_jfrog} jfrog rt ping --user ${bamboo.snapshot_deployer_username} --password ${bamboo.snapshot_deployer_password} --url https://devstore.vanderlande.com/artifactory +other: + clean-working-dir: true +requirements: + - AGENT_TYPE: Linux_Base_Agent diff --git a/bamboo-specs/validate/docs-changesonly.yaml b/bamboo-specs/validate/docs-changesonly.yaml new file mode 100644 index 0000000..6bb5b90 --- /dev/null +++ b/bamboo-specs/validate/docs-changesonly.yaml @@ -0,0 +1,75 @@ +tasks: + - checkout: + force-clean-build: 'true' + + - script: | + #!/bin/bash + set -euxo pipefail + + # Ensure there's at least one previous commit + if git rev-parse HEAD~1 >/dev/null 2>&1; then + # Collect changed *.md files under docs/ (ignore deletions) + CHANGED_MD_FILES=$(git diff --name-status HEAD~1 HEAD | \ + awk '$1 != "D" {print $2}' | grep '^docs/.*\.md$' || true) + else + echo "No previous commit to compare against. Skipping update." + exit 0 + fi + + if [[ -z "${CHANGED_MD_FILES}" ]]; then + echo "No relevant markdown files changed under docs/. Skipping Confluence update." + exit 0 + fi + + # Parse minor version from semantic version + MINOR_VERSION=$(echo "${bamboo.inject.gtag}" | grep -Eo "^[0-9]+\.[0-9]+") + + # Inject version numbers into documentation + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" README.md + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" docs/*.md + + # Create temporary folder + mkdir -p ./vi_certs + + # Download latest Vanderlande CA certificates + curl https://pki.vanderlande.com/pki/VanderlandeRootCA.crt -o - | \ + openssl x509 -inform DER -out ./vi_certs/VanderlandeRootCA.crt + curl https://pki.vanderlande.com/pki/VanderlandeSubordinateCA-Internal.crt \ + -o ./vi_certs/VanderlandeSubordinateCA-Internal.crt + + echo "---" + echo "Starting Confluence update for the following files:" + echo "${CHANGED_MD_FILES}" + echo "---" + + # Since -f only accepts one file, we must loop through the list of changed files. + for file in ${CHANGED_MD_FILES} + do + echo "Processing file: ${file}" + + # Run a separate docker command for each file + docker run --rm --name "confluence-docs-update" \ + -v "${bamboo.hostvolume}:/code" \ + -v "${bamboo.hostvolume}/vi_certs:/usr/local/share/ca-certificates" \ + -w /code \ + "${bamboo.container_mark}" \ + /bin/bash -c "\ + update-ca-certificates && \ + mark -u '${bamboo.confluence_username}' \ + -p '${bamboo.confluence_password}' \ + -b '${bamboo.confluence_url}' \ + --ci --changes-only \ + --title-from-h1 \ + --space ${bamboo.confluence_space} \ + --parents 'IT Technology Platform/Team Devcolla'\''s/Application Stack/Harvester Cloud Native Virtualization' \ + -f '${file}'" + echo "Finished processing ${file}." + echo "---" + done + +other: + clean-working-dir: true + +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent \ No newline at end of file diff --git a/bamboo-specs/validate/docs-dryrun.yaml b/bamboo-specs/validate/docs-dryrun.yaml new file mode 100644 index 0000000..055a7e4 --- /dev/null +++ b/bamboo-specs/validate/docs-dryrun.yaml @@ -0,0 +1,63 @@ +tasks: + - checkout: + force-clean-build: 'true' + - script: | + #!/bin/bash + set -x + + # Parse minor version from semantic version + MINOR_VERSION=$(echo "${bamboo.inject.gtag}" | grep -Eo "^[0-9]+\.[0-9]+") + + # Inject version numbers into documentation + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" README.md + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" docs/*.md + + # Create temporary folder + mkdir -p ./vi_certs + + # Download latest Vanderlande certificate authority certificates + curl https://pki.vanderlande.com/pki/VanderlandeRootCA.crt -o - | openssl x509 -inform DER -out ./vi_certs/VanderlandeRootCA.crt + curl https://pki.vanderlande.com/pki/VanderlandeSubordinateCA-Internal.crt -o ./vi_certs/VanderlandeSubordinateCA-Internal.crt + + # Update README markdown file + docker run --rm --name confluence-docs-update \ + -v "${bamboo.hostvolume}:/code" \ + -v "${bamboo.hostvolume}/vi_certs:/usr/local/share/ca-certificates" \ + -w /code \ + "${bamboo.container_mark}" \ + /bin/bash -c "\ + update-ca-certificates && \ + mark \ + -u '${bamboo.confluence_username}' \ + -p '${bamboo.confluence_password}' \ + -b '${bamboo.confluence_url}' \ + --title-from-h1 \ + --space ${bamboo.confluence_space} \ + --parents 'IT Technology Platform/Team Devcolla'\''s/Application Stack/Harvester Cloud Native Virtualization' \ + --dry-run \ + -f './README.md' || exit 1" + + # Update all markdown files in docs/ + docker run --rm --name confluence-docs-update \ + -v "${bamboo.hostvolume}:/code" \ + -v "${bamboo.hostvolume}/vi_certs:/usr/local/share/ca-certificates" \ + -w /code \ + "${bamboo.container_mark}" \ + /bin/bash -c "\ + update-ca-certificates && \ + mark \ + -u '${bamboo.confluence_username}' \ + -p '${bamboo.confluence_password}' \ + -b '${bamboo.confluence_url}' \ + --ci --changes-only \ + --title-from-h1 \ + --space ${bamboo.confluence_space} \ + --parents 'IT Technology Platform/Team Devcolla'\''s/Application Stack/Harvester Cloud Native Virtualization' \ + --dry-run \ + -f './docs/*.md' || exit 1" + +other: + clean-working-dir: true +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent diff --git a/bamboo-specs/validate/docs.yaml b/bamboo-specs/validate/docs.yaml new file mode 100644 index 0000000..2c433c4 --- /dev/null +++ b/bamboo-specs/validate/docs.yaml @@ -0,0 +1,61 @@ +tasks: + - checkout: + force-clean-build: 'true' + - script: | + #!/bin/bash + set -x + + # Parse minor version from semantic version + MINOR_VERSION=$(echo "${bamboo.inject.gtag}" | grep -Eo "^[0-9]+\.[0-9]+") + + # Inject version numbers into documentation + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" README.md + sed -i "s/{{ release_version }}/${bamboo.inject.gtag}/g;s/{{ minor_version }}/${MINOR_VERSION}/g" docs/*.md + + # Create temporary folder + mkdir -p ./vi_certs + + # Download latest Vanderlande certificate authority certificates + curl https://pki.vanderlande.com/pki/VanderlandeRootCA.crt -o - | openssl x509 -inform DER -out ./vi_certs/VanderlandeRootCA.crt + curl https://pki.vanderlande.com/pki/VanderlandeSubordinateCA-Internal.crt -o ./vi_certs/VanderlandeSubordinateCA-Internal.crt + + # Update README markdown file + docker run --rm --name confluence-docs-update \ + -v "${bamboo.hostvolume}:/code" \ + -v "${bamboo.hostvolume}/vi_certs:/usr/local/share/ca-certificates" \ + -w /code \ + "${bamboo.container_mark}" \ + /bin/bash -c "\ + update-ca-certificates && \ + mark \ + -u '${bamboo.confluence_username}' \ + -p '${bamboo.confluence_password}' \ + -b '${bamboo.confluence_url}' \ + --title-from-h1 \ + --space ${bamboo.confluence_space} \ + --parents 'IT Technology Platform/Team Devcolla'\''s/Application Stack/Harvester Cloud Native Virtualization' \ + -f './README.md' || exit 1" + + # Update all markdown files in docs/ + docker run --rm --name confluence-docs-update \ + -v "${bamboo.hostvolume}:/code" \ + -v "${bamboo.hostvolume}/vi_certs:/usr/local/share/ca-certificates" \ + -w /code \ + "${bamboo.container_mark}" \ + /bin/bash -c "\ + update-ca-certificates && \ + mark \ + -u '${bamboo.confluence_username}' \ + -p '${bamboo.confluence_password}' \ + -b '${bamboo.confluence_url}' \ + --ci --changes-only \ + --title-from-h1 \ + --space ${bamboo.confluence_space} \ + --parents 'IT Technology Platform/Team Devcolla'\''s/Application Stack/Harvester Cloud Native Virtualization' \ + -f './docs/*.md' || exit 1" + +other: + clean-working-dir: true +requirements: + - system.docker.executable + - AGENT_TYPE: Linux_Base_Agent diff --git a/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit-cp.yaml b/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit-cp.yaml new file mode 100644 index 0000000..5c35968 --- /dev/null +++ b/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit-cp.yaml @@ -0,0 +1,120 @@ +apiVersion: v1 +data: + cloudInit: | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + + runcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - systemctl enable --now qemu-guest-agent.service + - [sh, '/root/updates.sh'] + + disable_root: true + ssh_pwauth: false + groups: + - etcd + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Jn9gljJAbr9tjxD2$4D4O5YokrpYvYd5lznvtuWRPWWcREo325pEhn5r5vzfIU/1fX6werOG4LlXxNNBOkmbKaabekQ9NQL32IZOiH1 + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + - name: etcd + gecos: ETCD service account + lock_passwd: true + shell: /sbin/nologin + groups: [etcd] + + + write_files: + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + - path: /var/lib/rancher/rke2/server/manifests/disable-sa-automount.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: disable-automount-sa + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: disable-automount-clusterrole + rules: + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list"] + - apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["get", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: disable-automount-binding + subjects: + - kind: ServiceAccount + name: disable-automount-sa + namespace: kube-system + roleRef: + kind: ClusterRole + name: disable-automount-clusterrole + apiGroup: rbac.authorization.k8s.io + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: disable-default-sa-automount + namespace: kube-system + spec: + schedule: "0 0 * * *" + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + spec: + serviceAccountName: disable-automount-sa + containers: + - name: kubectl-patcher + image: alpine/kubectl:1.35.0 + command: + - /bin/sh + - -c + - | + for n in $(kubectl get namespaces -o=jsonpath="{.items[*]['metadata.name']}"); do + echo "Patching default SA in namespace: $n" + kubectl patch serviceaccount default -p '{"automountServiceAccountToken": false}' -n $n + done + restartPolicy: OnFailure +kind: ConfigMap +metadata: + labels: + harvesterhci.io/cloud-init-template: user + name: rke2-ubuntu-22.04-cloudinit-cp + namespace: vanderlande diff --git a/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit.yaml b/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit.yaml new file mode 100755 index 0000000..f8da424 --- /dev/null +++ b/deploy/harvester/cloud-config-templates/rke2-ubuntu-22.04-cloudinit.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +data: + cloudInit: | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + + runcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - systemctl enable --now qemu-guest-agent.service + - [sh, '/root/updates.sh'] + + disable_root: true + ssh_pwauth: false + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Jn9gljJAbr9tjxD2$4D4O5YokrpYvYd5lznvtuWRPWWcREo325pEhn5r5vzfIU/1fX6werOG4LlXxNNBOkmbKaabekQ9NQL32IZOiH1 + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + write_files: + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y +kind: ConfigMap +metadata: + labels: + harvesterhci.io/cloud-init-template: user + name: rke2-ubuntu-22.04-cloudinit + namespace: vanderlande diff --git a/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit-cp.yaml b/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit-cp.yaml new file mode 100644 index 0000000..5243b73 --- /dev/null +++ b/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit-cp.yaml @@ -0,0 +1,120 @@ +apiVersion: v1 +data: + cloudInit: | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + + runcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - systemctl enable --now qemu-guest-agent.service + - [sh, '/root/updates.sh'] + + disable_root: true + ssh_pwauth: false + groups: + - etcd + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Jn9gljJAbr9tjxD2$4D4O5YokrpYvYd5lznvtuWRPWWcREo325pEhn5r5vzfIU/1fX6werOG4LlXxNNBOkmbKaabekQ9NQL32IZOiH1 + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + - name: etcd + gecos: ETCD service account + lock_passwd: true + shell: /sbin/nologin + groups: [etcd] + + write_files: + - path: /root/updates.sh + permissions: '0550' + owner: root:root + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + - path: /var/lib/rancher/rke2/server/manifests/disable-sa-automount.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: disable-automount-sa + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: disable-automount-clusterrole + rules: + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list"] + - apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["get", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: disable-automount-binding + subjects: + - kind: ServiceAccount + name: disable-automount-sa + namespace: kube-system + roleRef: + kind: ClusterRole + name: disable-automount-clusterrole + apiGroup: rbac.authorization.k8s.io + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: disable-default-sa-automount + namespace: kube-system + spec: + schedule: "0 0 * * *" + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + spec: + serviceAccountName: disable-automount-sa + containers: + - name: kubectl-patcher + image: alpine/kubectl:1.35.0 + command: + - /bin/sh + - -c + - | + for n in $(kubectl get namespaces -o=jsonpath="{.items[*]['metadata.name']}"); do + echo "Patching default SA in namespace: $n" + kubectl patch serviceaccount default -p '{"automountServiceAccountToken": false}' -n $n + done + restartPolicy: OnFailure +kind: ConfigMap +metadata: + labels: + harvesterhci.io/cloud-init-template: user + name: rke2-ubuntu-24.04-cloudinit-cp + namespace: vanderlande diff --git a/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit.yaml b/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit.yaml new file mode 100755 index 0000000..971cb6b --- /dev/null +++ b/deploy/harvester/cloud-config-templates/rke2-ubuntu-24.04-cloudinit.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +data: + cloudInit: | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + + runcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - systemctl enable --now qemu-guest-agent.service + - [sh, '/root/updates.sh'] + + disable_root: true + ssh_pwauth: false + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Jn9gljJAbr9tjxD2$4D4O5YokrpYvYd5lznvtuWRPWWcREo325pEhn5r5vzfIU/1fX6werOG4LlXxNNBOkmbKaabekQ9NQL32IZOiH1 + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + write_files: + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y +kind: ConfigMap +metadata: + labels: + harvesterhci.io/cloud-init-template: user + name: rke2-ubuntu-24.04-cloudinit + namespace: vanderlande diff --git a/deploy/harvester/image/ubuntu-22.04-2025-11-25.yaml b/deploy/harvester/image/ubuntu-22.04-2025-11-25.yaml new file mode 100755 index 0000000..112dd43 --- /dev/null +++ b/deploy/harvester/image/ubuntu-22.04-2025-11-25.yaml @@ -0,0 +1,33 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineImage +metadata: + annotations: + harvesterhci.io/storageClassName: harvester-longhorn + finalizers: + - wrangler.cattle.io/vm-image-controller + generateName: ubuntu-22.04- + generation: 1 + labels: + harvesterhci.io/image-type: raw_qcow2 + harvesterhci.io/imageDisplayName: ubuntu-22.04-2025-11-25 + harvesterhci.io/os-release-date: '2025-11-25' + harvesterhci.io/os-type: ubuntu + harvesterhci.io/os-version: '22.04' + name: ubuntu-22.04-7mg64 + namespace: vanderlande + uid: 894bb600-bb7d-4bd3-926f-b91616cd54be +spec: + backend: backingimage + checksum: '' + displayName: ubuntu-22.04-2025-11-25 + pvcName: '' + pvcNamespace: '' + retry: 3 + sourceType: download + storageClassParameters: + migratable: 'true' + numberOfReplicas: '3' + staleReplicaTimeout: '30' + targetStorageClassName: harvester-longhorn + url: >- + https://cloud-images.ubuntu.com/jammy/20251125/jammy-server-cloudimg-amd64.img diff --git a/deploy/harvester/image/ubuntu-24.04-2025-11-26.yaml b/deploy/harvester/image/ubuntu-24.04-2025-11-26.yaml new file mode 100755 index 0000000..b3b5d40 --- /dev/null +++ b/deploy/harvester/image/ubuntu-24.04-2025-11-26.yaml @@ -0,0 +1,33 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineImage +metadata: + annotations: + harvesterhci.io/storageClassName: harvester-longhorn + finalizers: + - wrangler.cattle.io/vm-image-controller + generateName: ubuntu-24.04- + generation: 1 + labels: + harvesterhci.io/image-type: raw_qcow2 + harvesterhci.io/imageDisplayName: ubuntu-24.04-2025-11-26 + harvesterhci.io/os-release-date: '2025-11-26' + harvesterhci.io/os-type: ubuntu + harvesterhci.io/os-version: '24.04' + name: ubuntu-24.04-qhtpc + namespace: vanderlande + uid: 23b60ae3-d5bd-4b10-9587-94e56b39c018 +spec: + backend: backingimage + checksum: '' + displayName: ubuntu-24.04-2025-11-26 + pvcName: '' + pvcNamespace: '' + retry: 3 + sourceType: download + storageClassParameters: + migratable: 'true' + numberOfReplicas: '3' + staleReplicaTimeout: '30' + targetStorageClassName: harvester-longhorn + url: >- + https://cloud-images.ubuntu.com/noble/20251126/noble-server-cloudimg-amd64.img diff --git a/deploy/harvester/templates/rke2-ubuntu-22.04-8fzp2.yaml b/deploy/harvester/templates/rke2-ubuntu-22.04-8fzp2.yaml new file mode 100755 index 0000000..cd9ac88 --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-22.04-8fzp2.yaml @@ -0,0 +1,94 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineTemplateVersion +metadata: + annotations: + template-version.harvesterhci.io/customName: m8HEQq4ebp + generateName: rke2-ubuntu-22.04- + generation: 2 + labels: + template.harvesterhci.io/templateID: rke2-ubuntu-22.04 + name: rke2-ubuntu-22.04-8fzp2 + namespace: vanderlande + ownerReferences: + - apiVersion: harvesterhci.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: VirtualMachineTemplate + name: rke2-ubuntu-22.04 + # UID of the VirtualMachineTemplate to link to + uid: 8358985a-2a3d-4d06-a656-eb5e69d3137d + # UID is of the VirtualMachineTemplateVersion used by the secret + uid: 0c581ffb-8681-4054-a3c1-078a22dc53d8 +spec: + templateId: vanderlande/rke2-ubuntu-22.04 + vm: + metadata: + annotations: + harvesterhci.io/enableCPUAndMemoryHotplug: 'true' + # Image StorageClass name is defined by the image suffix, i.e. ubuntu-22.04-7mg64 -> longhorn-image-7mg64 + harvesterhci.io/volumeClaimTemplates: '[{"metadata":{"name":"-disk-0-q0xip","annotations":{"harvesterhci.io/imageId":"vanderlande/image-7mg64"}},"spec":{"accessModes":["ReadWriteMany"],"resources":{"requests":{"storage":"60Gi"}},"volumeMode":"Block","storageClassName":"longhorn-image-7mg64"}}]' + template-version.harvesterhci.io/customName: m8HEQq4ebp + creationTimestamp: null + labels: + harvesterhci.io/os: ubuntu + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: + harvesterhci.io/sshNames: '["vanderlande/harvester-cnv-node"]' + creationTimestamp: null + spec: + affinity: {} + domain: + cpu: + cores: 1 + maxSockets: 16 + sockets: 4 + threads: 1 + devices: + disks: + - bootOrder: 1 + disk: + bus: virtio + name: disk-0 + - disk: + bus: virtio + name: cloudinitdisk + inputs: + - bus: usb + name: tablet + type: tablet + interfaces: + - bridge: {} + model: virtio + name: default + features: + acpi: + enabled: true + machine: + type: '' + memory: + guest: 8Gi + maxGuest: 32Gi + resources: + limits: + cpu: '16' + memory: 32Gi + evictionStrategy: LiveMigrateIfPossible + networks: + - multus: + networkName: vanderlande/vm-lan + name: default + terminationGracePeriodSeconds: 120 + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: '-disk-0-q0xip' + - cloudInitNoCloud: + networkDataSecretRef: + name: rke2-ubuntu-22.04-lbbfn + secretRef: + name: rke2-ubuntu-22.04-lbbfn + name: cloudinitdisk + diff --git a/deploy/harvester/templates/rke2-ubuntu-22.04-secret-lbbfn.yaml b/deploy/harvester/templates/rke2-ubuntu-22.04-secret-lbbfn.yaml new file mode 100755 index 0000000..0a10d39 --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-22.04-secret-lbbfn.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +data: + # Updated user data should be imported from rke2-ubuntu-22.04-cloudinit and base64 encoded + networkdata: "" + userdata: I2Nsb3VkLWNvbmZpZwpwYWNrYWdlX3VwZGF0ZTogZmFsc2UKcGFja2FnZV91cGdyYWRlOiBmYWxzZQpzbmFwOgogIGNvbW1hbmRzOgogICAgMDogc25hcCByZWZyZXNoIC0taG9sZD1mb3JldmVyCnBhY2thZ2VfcmVib290X2lmX3JlcXVpcmVkOiB0cnVlCnBhY2thZ2VzOgogIC0gcWVtdS1ndWVzdC1hZ2VudAogIC0geXEKICAtIGpxCgpydW5jbWQ6CiAgLSBzeXNjdGwgLXcgbmV0LmlwdjYuY29uZi5hbGwuZGlzYWJsZV9pcHY2PTEKICAtIHN5c3RlbWN0bCBlbmFibGUgLS1ub3cgcWVtdS1ndWVzdC1hZ2VudC5zZXJ2aWNlCiAgLSAtIHNoCiAgICAtIC9yb290L3VwZGF0ZXMuc2gKCmRpc2FibGVfcm9vdDogdHJ1ZQpzc2hfcHdhdXRoOiBmYWxzZQp1c2VyczoKICAtIG5hbWU6IHJhbmNoZXIKICAgIGdlY29zOiBSYW5jaGVyIHNlcnZpY2UgYWNjb3VudAogICAgaGFzaGVkX3Bhc3N3ZDogJDYkSm45Z2xqSkFicjl0anhEMiQ0RDRPNVlva3JwWXZZZDVsem52dHVXUlBXV2NSRW8zMjVwRWhuNXI1dnpmSVUvMWZYNndlck9HNExsWHhOTkJPa21iS2FhYmVrUTlOUUwzMklaT2lIMQogICAgbG9ja19wYXNzd2Q6IGZhbHNlCiAgICBzaGVsbDogL2Jpbi9iYXNoCiAgICBncm91cHM6IFsgdXNlcnMsIHN1ZG8sIGRvY2tlciBdCiAgICBzdWRvOiBBTEw9KEFMTCkKICAgIHNzaF9hdXRob3JpemVkX2tleXM6CiAgICAgIC0gJ3NzaC1lZDI1NTE5CiAgICAgICAgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUV3V25uT1RBdTBMbEFaUmN6UTBaMEt2TmxVZFBoR1FocFppZStuRjFPM3MnCgp3cml0ZV9maWxlczoKICAtIHBhdGg6IC9yb290L3VwZGF0ZXMuc2gKICAgIHBlcm1pc3Npb25zOiAnMDU1MCcKICAgIGNvbnRlbnQ6IHwKICAgICAgIyEvYmluL2Jhc2gKICAgICAgZXhwb3J0IERFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZQogICAgICBhcHQtbWFyayBob2xkIGxpbnV4LWhlYWRlcnMtZ2VuZXJpYwogICAgICBhcHQtbWFyayBob2xkIGxpbnV4LWhlYWRlcnMtdmlydHVhbAogICAgICBhcHQtbWFyayBob2xkIGxpbnV4LWltYWdlLXZpcnR1YWwKICAgICAgYXB0LW1hcmsgaG9sZCBsaW51eC12aXJ0dWFsCiAgICAgIGFwdC1nZXQgdXBkYXRlCiAgICAgIGFwdC1nZXQgdXBncmFkZSAteQogICAgICBhcHQtZ2V0IGF1dG9yZW1vdmUgLXkgICAgCnNzaF9hdXRob3JpemVkX2tleXM6CiAgLSBzc2gtZWQyNTUxOQogICAgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUV3V25uT1RBdTBMbEFaUmN6UTBaMEt2TmxVZFBoR1FocFppZStuRjFPM3MKICAgIEhhcnZlc3RlciBDTlYgTm9kZQo= +kind: Secret +metadata: + labels: + harvesterhci.io/cloud-init-template: harvester + name: rke2-ubuntu-22.04-lbbfn + namespace: vanderlande + ownerReferences: + - apiVersion: harvesterhci.io/v1beta1 + kind: VirtualMachineTemplateVersion + name: rke2-ubuntu-22.04-8fzp2 + # UID of the VirtualMachineTemplateVersion to link to + uid: 0c581ffb-8681-4054-a3c1-078a22dc53d8 +type: secret diff --git a/deploy/harvester/templates/rke2-ubuntu-22.04-template.yaml b/deploy/harvester/templates/rke2-ubuntu-22.04-template.yaml new file mode 100755 index 0000000..ea88dcf --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-22.04-template.yaml @@ -0,0 +1,10 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineTemplate +metadata: + name: rke2-ubuntu-22.04 + namespace: vanderlande + # UID needs to be specified explicitly as it is used in template version. + uid: 8358985a-2a3d-4d06-a656-eb5e69d3137d +spec: + defaultVersionId: vanderlande/rke2-ubuntu-22.04-8fzp2 + diff --git a/deploy/harvester/templates/rke2-ubuntu-24.04-secret-3bl5k.yaml b/deploy/harvester/templates/rke2-ubuntu-24.04-secret-3bl5k.yaml new file mode 100755 index 0000000..89f7d1d --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-24.04-secret-3bl5k.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +data: + networkdata: "" + # Updated user data should be imported from rke2-ubuntu-24.04-cloudinit and base64 encoded + userdata: I2Nsb3VkLWNvbmZpZwpwYWNrYWdlX3VwZGF0ZTogdHJ1ZQpwYWNrYWdlX3VwZ3JhZGU6IGZhbHNlCnNuYXA6CiAgY29tbWFuZHM6CiAgICAwOiBzbmFwIHJlZnJlc2ggLS1ob2xkPWZvcmV2ZXIKcGFja2FnZV9yZWJvb3RfaWZfcmVxdWlyZWQ6IHRydWUKcGFja2FnZXM6CiAgLSBxZW11LWd1ZXN0LWFnZW50CiAgLSB5cQogIC0ganEKCnJ1bmNtZDoKICAtIHN5c2N0bCAtdyBuZXQuaXB2Ni5jb25mLmFsbC5kaXNhYmxlX2lwdjY9MQogIC0gc3lzdGVtY3RsIGVuYWJsZSAtLW5vdyBxZW11LWd1ZXN0LWFnZW50LnNlcnZpY2UKICAtIC0gc2gKICAgIC0gL3Jvb3QvdXBkYXRlcy5zaAoKZGlzYWJsZV9yb290OiB0cnVlCnNzaF9wd2F1dGg6IGZhbHNlCnVzZXJzOgogIC0gbmFtZTogcmFuY2hlcgogICAgZ2Vjb3M6IFJhbmNoZXIgc2VydmljZSBhY2NvdW50CiAgICBoYXNoZWRfcGFzc3dkOiAkNiRKbjlnbGpKQWJyOXRqeEQyJDRENE81WW9rcnBZdllkNWx6bnZ0dVdSUFdXY1JFbzMyNXBFaG41cjV2emZJVS8xZlg2d2VyT0c0TGxYeE5OQk9rbWJLYWFiZWtROU5RTDMySVpPaUgxCiAgICBsb2NrX3Bhc3N3ZDogZmFsc2UKICAgIHNoZWxsOiAvYmluL2Jhc2gKICAgIGdyb3VwczogWyB1c2Vycywgc3VkbywgZG9ja2VyIF0KICAgIHN1ZG86IEFMTD0oQUxMOkFMTCkgQUxMCiAgICBzc2hfYXV0aG9yaXplZF9rZXlzOgogICAgICAtICdzc2gtZWQyNTUxOQogICAgICAgIEFBQUFDM056YUMxbFpESTFOVEU1QUFBQUlFd1dubk9UQXUwTGxBWlJjelEwWjBLdk5sVWRQaEdRaHBaaWUrbkYxTzNzJwoKd3JpdGVfZmlsZXM6CiAgLSBwYXRoOiAvcm9vdC91cGRhdGVzLnNoCiAgICBwZXJtaXNzaW9uczogJzA1NTAnCiAgICBjb250ZW50OiB8CiAgICAgICMhL2Jpbi9iYXNoCiAgICAgIGV4cG9ydCBERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUKICAgICAgYXB0LW1hcmsgaG9sZCBsaW51eC1oZWFkZXJzLWdlbmVyaWMKICAgICAgYXB0LW1hcmsgaG9sZCBsaW51eC1oZWFkZXJzLXZpcnR1YWwKICAgICAgYXB0LW1hcmsgaG9sZCBsaW51eC1pbWFnZS12aXJ0dWFsCiAgICAgIGFwdC1tYXJrIGhvbGQgbGludXgtdmlydHVhbAogICAgICBhcHQtZ2V0IHVwZGF0ZQogICAgICBhcHQtZ2V0IHVwZ3JhZGUgLXkKICAgICAgYXB0LWdldCBhdXRvcmVtb3ZlIC15ICAgIApzc2hfYXV0aG9yaXplZF9rZXlzOgogIC0gc3NoLWVkMjU1MTkKICAgIEFBQUFDM056YUMxbFpESTFOVEU1QUFBQUlFd1dubk9UQXUwTGxBWlJjelEwWjBLdk5sVWRQaEdRaHBaaWUrbkYxTzNzCiAgICBIYXJ2ZXN0ZXIgQ05WIE5vZGUK +kind: Secret +metadata: + labels: + harvesterhci.io/cloud-init-template: harvester + name: rke2-ubuntu-24.04-3bl5k + namespace: vanderlande + ownerReferences: + - apiVersion: harvesterhci.io/v1beta1 + kind: VirtualMachineTemplateVersion + name: rke2-ubuntu-24.04-xrv5n + # UID of the VirtualMachineTemplateVersion to link to + uid: ad96ea4b-3d5a-4de3-adb0-0eb3c99920b2 +type: secret diff --git a/deploy/harvester/templates/rke2-ubuntu-24.04-template.yaml b/deploy/harvester/templates/rke2-ubuntu-24.04-template.yaml new file mode 100755 index 0000000..b66a6e6 --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-24.04-template.yaml @@ -0,0 +1,10 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineTemplate +metadata: + name: rke2-ubuntu-24.04 + namespace: vanderlande + # UID needs to be specified explicitly as it is used in template version and secret. + uid: cf644217-0be1-47f0-8c7f-2594f633da26 +spec: + defaultVersionId: vanderlande/rke2-ubuntu-24.04-xrv5n + diff --git a/deploy/harvester/templates/rke2-ubuntu-24.04-xrv5n.yaml b/deploy/harvester/templates/rke2-ubuntu-24.04-xrv5n.yaml new file mode 100755 index 0000000..06425ce --- /dev/null +++ b/deploy/harvester/templates/rke2-ubuntu-24.04-xrv5n.yaml @@ -0,0 +1,94 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: VirtualMachineTemplateVersion +metadata: + annotations: + template-version.harvesterhci.io/customName: VfNPzXKspc + generateName: rke2-ubuntu-24.04- + generation: 2 + labels: + template.harvesterhci.io/templateID: rke2-ubuntu-24.04 + name: rke2-ubuntu-24.04-xrv5n + namespace: vanderlande + ownerReferences: + - apiVersion: harvesterhci.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: VirtualMachineTemplate + name: rke2-ubuntu-24.04 + # UID of the VirtualMachineTemplate to link to + uid: cf644217-0be1-47f0-8c7f-2594f633da26 + # UID is of the VirtualMachineTemplateVersion used by the secret + uid: ad96ea4b-3d5a-4de3-adb0-0eb3c99920b2 +spec: + templateId: vanderlande/rke2-ubuntu-24.04 + vm: + metadata: + annotations: + harvesterhci.io/enableCPUAndMemoryHotplug: "true" + # Image StorageClass name is defined by the image suffix, i.e. ubuntu-24.04-qhtpc -> longhorn-image-qhtpc + harvesterhci.io/volumeClaimTemplates: '[{"metadata":{"name":"-disk-0-jprp0","annotations":{"harvesterhci.io/imageId":"vanderlande/image-qhtpc"}},"spec":{"accessModes":["ReadWriteMany"],"resources":{"requests":{"storage":"60Gi"}},"volumeMode":"Block","storageClassName":"longhorn-image-qhtpc"}}]' + template-version.harvesterhci.io/customName: VfNPzXKspc + creationTimestamp: null + labels: + harvesterhci.io/os: ubuntu + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: + harvesterhci.io/sshNames: '["vanderlande/harvester-cnv-node"]' + creationTimestamp: null + spec: + affinity: {} + domain: + cpu: + cores: 1 + maxSockets: 16 + sockets: 4 + threads: 1 + devices: + disks: + - bootOrder: 1 + disk: + bus: virtio + name: disk-0 + - disk: + bus: virtio + name: cloudinitdisk + inputs: + - bus: usb + name: tablet + type: tablet + interfaces: + - bridge: {} + model: virtio + name: default + features: + acpi: + enabled: true + machine: + type: "" + memory: + guest: 8Gi + maxGuest: 32Gi + resources: + limits: + cpu: "16" + memory: 32Gi + evictionStrategy: LiveMigrateIfPossible + networks: + - multus: + networkName: vanderlande/vm-lan + name: default + terminationGracePeriodSeconds: 120 + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: -disk-0-jprp0 + - cloudInitNoCloud: + networkDataSecretRef: + name: rke2-ubuntu-24.04-3bl5k + secretRef: + name: rke2-ubuntu-24.04-3bl5k + name: cloudinitdisk + diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/.helmignore b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/.helmignore new file mode 100644 index 0000000..5df8cd4 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/.helmignore @@ -0,0 +1,21 @@ +# HELM IGNORE OPTIONS: +# Patterns to ignore when building Helm packages. +# Supports shell glob matching, relative path matching, and negation (prefixed with !) + +.DS_Store +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +*.swp +*.bak +*.tmp +*.orig +*~ +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/Chart.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/Chart.yaml new file mode 100644 index 0000000..e7f32c9 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: rancher-cluster-templates +version: 0.7.2 +appVersion: 0.7.2 + +type: application +description: Hardened Rancher Cluster Templates by Rancher Government +icon: https://raw.githubusercontent.com/rancherfederal/carbide-docs/main/static/img/carbide-logo.svg + +home: https://github.com/rancherfederal +sources: + - https://github.com/rancherfederal/rancher-cluster-templates + +maintainers: + - name: Rancher Government + email: support@ranchergovernment.com + url: https://ranchergovernment.com + +annotations: + catalog.cattle.io/type: cluster-template + catalog.cattle.io/namespace: fleet-default + classification: UNCLASSIFIED diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/app-readme.md b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/app-readme.md new file mode 100644 index 0000000..9040bd7 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/app-readme.md @@ -0,0 +1,105 @@ +# Rancher Cluster Templates Helm Chart + +| Type | Chart Version | App Version | +| :---------: | :-----------: | :---------: | +| application | `0.7.2` | `0.7.2` | + +⚠️ This project is still in active development. As we continued to develop it, there will be breaking changes. ⚠️ + +## Supported Providers + +### Currently Available + +- AWS Commercial +- AWS GovCloud +- Harvester +- Digital Ocean +- VMWare vSphere +- Custom + +### Pending Validation + +- Microsoft Azure + +## Installing the Chart + +### Helm Install via Repository + +```bash +helm repo add cluster-templates https://rancherfederal.github.io/rancher-cluster-templates +helm upgrade -i cluster cluster-templates/rancher-cluster-templates -n fleet-default -f values.yaml +``` + +## Helm Install via Registry +```bash +helm upgrade -i cluster oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates -n fleet-default -f values.yaml +``` + +## Helm Chart Deployment Status + +```bash +helm status cluster -n fleet-default +``` + +## Uninstalling the Chart + +```bash +helm delete cluster -n fleet-default +``` + +## Chart/Cluster Secrets Management + +### Cloud Credentials + +If you do not have Cloud Credentials already created within the Rancher Manager, you can create them via `kubectl` with the command(s) below. Eventually, we will be moving these options with the Helm Chart! + +#### For AWS Credentials + +```bash +# with long-term credentials (accessKey and secretKey) +kubectl create secret -n cattle-global-data generic aws-creds-sts --from-literal=amazonec2credentialConfig-defaultRegion=$REGION --from-literal=amazonec2credentialConfig-accessKey=$ACCESSKEY --from-literal=amazonec2credentialConfig-secretKey=$SECRETKEY + +kubectl annotate secret -n cattle-global-data aws-creds provisioning.cattle.io/driver=aws +``` + +```bash +# with temporary credentials (accessKey, secretKey, sessionToken) +kubectl create secret -n cattle-global-data generic aws-creds --from-literal=amazonec2credentialConfig-defaultRegion=$REGION --from-literal=amazonec2credentialConfig-accessKey=$ACCESSKEY --from-literal=amazonec2credentialConfig-secretKey=$SECRETKEY --from-literal=amazonec2credentialConfig-sessonToken=$SESSIONTOKEN + +kubectl annotate secret -n cattle-global-data aws-creds provisioning.cattle.io/driver=aws +``` + +#### For Harvester Credentials + +```bash +export CLUSTERID=$(kubectl get clusters.management.cattle.io -o=jsonpath='{range .items[?(@.metadata.labels.provider\.cattle\.io=="harvester")]}{.metadata.name}{"\n"}{end}') + +kubectl create secret -n cattle-global-data generic harvester-creds --from-literal=harvestercredentialConfig-clusterId=$CLUSTERID --from-literal=harvestercredentialConfig-clusterType=imported --from-file=harvestercredentialConfig-kubeconfigContent=harvester.yaml + +kubectl annotate secret -n cattle-global-data harvester-creds provisioning.cattle.io/driver=harvester +``` + +#### For Digital Ocean Credentials + +```bash +kubectl create secret -n cattle-global-data generic digitalocean-creds --from-literal=digitaloceancredentialConfig-accessToken=$TOKEN + +kubectl annotate secret -n cattle-global-data digitalocean-creds provisioning.cattle.io/driver=digitalocean +``` + + +#### For VMWare vSphere Credentials + +```bash +kubectl create secret -n cattle-global-data generic vsphere-creds --from-literal=digitaloceancredentialConfig-accessToken=$TOKEN + +kubectl annotate secret -n cattle-global-data vsphere-creds provisioning.cattle.io/driver=digitalocean +``` + +### Registry Credentials + +If you are configuring an authenticated registry and do not have Registry Credentials created in the Rancher Manager, you can create them via `kubectl` with the command below: + +```bash +kubectl create secret -n fleet-default generic --type kubernetes.io/basic-auth registry-creds --from-literal=username=USERNAME --from-literal=password=PASSWORD +``` diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/questions.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/questions.yaml new file mode 100644 index 0000000..3cf6b5a --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/questions.yaml @@ -0,0 +1,561 @@ +# questions: +# - variable: cluster.name +# default: mycluster +# description: 'Specify the name of the cluster' +# label: 'Cluster Name' +# required: true +# type: string +# group: 'General' +# - variable: cloudCredentialSecretName +# default: +# description: 'CloudCredentialName for provisioning cluster' +# label: 'CloudCredential Name' +# type: cloudcredential +# group: 'General' +# - variable: cloudprovider +# default: custom +# description: 'Specify Infrastructure provider for underlying nodes' +# label: 'Infrastructure Provider' +# type: enum +# required: true +# options: +# - amazonec2 +# - azure +# - digitalocean +# - elemental +# - harvester +# - vsphere +# - custom +# group: 'General' +# - variable: kubernetesVersion +# default: v1.31.5+rke2r1 +# description: 'Specify Kubernetes Version' +# label: 'Kubernetes Version' +# type: enum +# required: true +# options: +# - v1.31.5+rke2r1 +# - v1.30.9+rke2r1 +# - v1.29.13+rke2r1 +# group: 'General' +# - variable: localClusterAuthEndpoint.enabled +# default: false +# label: 'Local Auth Access Endpoint' +# description: 'Enable Local Auth Access Endpoint' +# type: boolean +# group: 'Auth Access Endpoint' +# show_subquestion_if: true +# subquestions: +# - variable: localClusterAuthEndpoint.fqdn +# default: +# description: 'Local Auth Access Endpoint FQDN' +# label: 'Auth Endpoint FQDN' +# type: hostname +# group: 'Auth Access Endpoint' +# - variable: localClusterAuthEndpoint.caCerts +# default: +# label: 'Auth Endpoint Cacerts' +# description: 'Local Auth Access Endpoint CACerts' +# type: multiline +# group: 'Auth Access Endpoint' +# - variable: addons.monitoring.enabled +# default: false +# label: 'Enable Monitoring' +# description: 'Enable Rancher Monitoring' +# type: boolean +# group: 'Monitoring' +# show_subquestion_if: true +# subquestions: +# - variable: monitoring.version +# default: +# label: 'Monitoring Version' +# description: 'Choose chart version of monitoring. If empty latest version will be installed' +# type: string +# group: 'Monitoring' +# - variable: monitoring.values +# default: +# label: 'Monitoring Values' +# description: 'Custom monitoring chart values' +# type: multiline +# group: 'Monitoring' +# - variable: nodepools.0.name +# default: +# description: 'Specify nodepool name' +# type: string +# label: 'Nodepool name' +# required: true +# show_if: cloudprovider=amazonec2 || cloudprovider=vsphere || cloudprovider=azure || cloudprovider=digitalocean || cloudprovider=harvester || cloudprovider=elemental +# group: 'Nodepools' +# - variable: nodepools.0.quantity +# default: 1 +# description: 'Specify node count' +# type: int +# required: true +# show_if: cloudprovider=amazonec2 || cloudprovider=vsphere || cloudprovider=azure || cloudprovider=digitalocean || cloudprovider=harvester || cloudprovider=elemental +# label: 'Node count' +# group: 'Nodepools' +# - variable: nodepools.0.etcd +# default: true +# label: etcd +# type: boolean +# show_if: cloudprovider=amazonec2 || cloudprovider=vsphere || cloudprovider=azure || cloudprovider=digitalocean || cloudprovider=harvester || cloudprovider=elemental +# group: 'Nodepools' +# - variable: nodepools.0.worker +# default: true +# label: worker +# type: boolean +# show_if: cloudprovider=amazonec2 || cloudprovider=vsphere || cloudprovider=azure || cloudprovider=digitalocean || cloudprovider=harvester || cloudprovider=elemental +# group: 'Nodepools' +# - variable: nodepools.0.controlplane +# label: controlplane +# default: true +# type: boolean +# show_if: cloudprovider=amazonec2 || cloudprovider=vsphere || cloudprovider=azure || cloudprovider=digitalocean || cloudprovider=harvester || cloudprovider=elemental +# group: 'Nodepools' +# # amazonec2 +# - variable: nodepools.0.region +# label: 'Region' +# default: us-east-1 +# type: string +# description: 'AWS EC2 Region' +# required: true +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.zone +# label: 'Zone' +# default: a +# type: string +# description: 'AWS EC2 Zone' +# required: true +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.instanceType +# label: 'Instance Type' +# default: t3a.medium +# type: string +# description: 'AWS instance type' +# required: true +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.rootSize +# label: 'Root Disk Size' +# default: 16g +# type: string +# description: 'AWS EC2 root disk size' +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.vpcId +# label: 'VPC/SUBNET' +# default: '' +# type: string +# description: 'AWS EC2 vpc ID' +# required: true +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.iamInstanceProfile +# label: 'Instance Profile Name' +# default: '' +# type: string +# description: 'AWS EC2 Instance Profile Name' +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.ami +# label: 'AMI ID' +# default: '' +# type: string +# description: 'AWS EC2 AMI ID' +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.sshUser +# label: 'SSH Username for AMI' +# default: ubuntu +# type: string +# description: 'AWS EC2 SSH Username for AMI' +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# - variable: nodepools.0.createSecurityGroup +# label: 'Create security group' +# default: true +# type: boolean +# description: 'Whether to create `rancher-node` security group. If false, can provide with existing security group' +# show_if: cloudprovider=amazonec2 +# group: 'Nodepools' +# show_subquestion_if: false +# subquestions: +# - variable: nodepools.0.securityGroups +# label: 'Security groups' +# default: +# type: string +# description: 'Using existing security groups' +# group: 'Nodepools' +# # vsphere +# - variable: nodepools.0.vcenter +# label: 'vSphere IP/hostname' +# default: '' +# type: hostname +# description: 'vSphere IP/hostname for vCenter' +# required: true +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.datacenter +# label: 'Vsphere Datacenter' +# default: '' +# type: hostname +# description: 'vSphere datacenter for virtual machine' +# required: true +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.datastore +# label: 'Vsphere Datastore' +# default: '' +# type: string +# description: 'vSphere datastore for virtual machine' +# required: true +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.datastoreCluster +# label: 'Vsphere DatastoreCluster' +# default: '' +# type: string +# description: 'vSphere datastore cluster for virtual machine' +# required: true +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.diskSize +# label: 'Disk Size' +# default: '20480' +# type: string +# description: 'vSphere size of disk for docker VM (in MB)' +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.memorySize +# label: 'Memory Size' +# default: '2048' +# type: string +# description: 'vSphere size of memory for docker VM (in MB)' +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.network +# label: 'Network' +# default: '' +# type: string +# description: 'vSphere network where the virtual machine will be attached' +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.pool +# label: 'Resource Pool' +# default: '' +# type: string +# description: 'vSphere resource pool for docker VM' +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.sshPort +# label: 'SSH Port' +# default: '22' +# type: string +# description: 'If using a non-B2D image you can specify the ssh port' +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.sshUserGroup +# label: 'SSH User Group' +# default: docker:staff +# type: hostname +# description: "If using a non-B2D image the uploaded keys will need chown'ed, defaults to staff e.g. docker:staff" +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.vappIpallocationpolicy +# label: 'IP allocation policy' +# default: '' +# type: enum +# options: +# - dhcp +# - fixed +# - transient +# - fixedAllocated +# description: "'vSphere vApp IP allocation policy. Supported values are: dhcp, fixed, transient and fixedAllocated'" +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# - variable: nodepools.0.vappIpprotocol +# label: 'IP protocol' +# default: '' +# type: enum +# options: +# - IPv4 +# - IPv6 +# description: "'vSphere vApp IP protocol for this deployment. Supported values are: IPv4 and IPv6'" +# show_if: cloudprovider=vsphere +# group: 'Nodepools' +# # harvester +# - variable: nodepools.0.diskSize +# label: 'Disk Size' +# default: 40 +# type: string +# description: 'Size of virtual hard disk in GB' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.diskBus +# label: 'Disk Bus Type' +# default: string +# type: virtio +# description: 'harvester disk type' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.cpuCount +# label: 'CPUs' +# default: 2 +# type: string +# description: 'number of CPUs for your VM' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.memorySize +# label: 'Memory Size' +# default: 4 +# type: string +# description: 'Memory for VM in GB (available RAM)' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.networkName +# label: 'Network' +# default: default/network-name-1 +# type: string +# description: 'Name of vlan network in harvester' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.imageName +# label: 'Name of Image' +# default: default/image-rand +# type: string +# description: 'Name of image in harvester' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.vmNamespace +# label: 'vm Namespace' +# default: default +# type: string +# description: 'namespace to deploy the VM to' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# - variable: nodepools.0.sshUser +# label: 'SSH User' +# default: ubuntu +# type: string +# description: 'SSH username' +# show_if: cloudprovider=harvester +# group: 'Nodepools' +# # digitalocean +# - variable: nodepools.0.image +# label: 'Image' +# default: ubuntu-20-04-x64 +# type: string +# description: 'Digital Ocean Image' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.backups +# label: 'Backup' +# default: false +# type: boolean +# description: 'enable backups for droplet' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.ipv6 +# label: 'IPv6' +# default: false +# type: boolean +# description: 'enable ipv6 for droplet' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.monitoring +# label: 'Monitoring' +# default: false +# type: boolean +# description: 'enable monitoring for droplet' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.privateNetworking +# label: 'Private Networking' +# default: false +# type: boolean +# description: 'enable private networking for droplet' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.region +# label: 'Region' +# default: sfo3 +# type: string +# description: 'Digital Ocean region' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.size +# label: 'Size' +# default: s-4vcpu-8gb +# type: string +# description: 'Digital Ocean size' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.userdata +# label: 'Userdata' +# default: +# type: multiline +# description: 'File contents for userdata' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.sshPort +# label: 'SSH Port' +# default: 22 +# type: string +# description: 'SSH port' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# - variable: nodepools.0.sshUser +# label: 'SSH User' +# default: root +# type: string +# description: 'SSH username' +# show_if: cloudprovider=digitalocean +# group: 'Nodepools' +# # azure +# - variable: nodepools.0.availabilitySet +# label: 'Availability Set' +# default: docker-machine +# type: string +# description: 'Azure Availability Set to place the virtual machine into' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.diskSize +# label: 'Disk Size' +# default: '' +# type: string +# description: 'Disk size if using managed disk(Gib)' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.dns +# label: 'DNS' +# default: '' +# type: string +# description: 'A unique DNS label for the public IP adddress' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.environment +# label: 'Environment' +# default: AzurePublicCloud +# type: enum +# options: +# - AzurePublicCloud +# - AzureGermanCloud +# - AzureChinaCloud +# - AzureUSGovernmentCloud +# description: 'Azure environment' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.faultDomainCount +# label: 'Fault Domain Count' +# default: '' +# type: string +# description: 'Fault domain count to use for availability set' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.image +# label: 'Image' +# default: canonical:UbuntuServer:18.04-LTS:latest +# type: string +# description: 'Azure virtual machine OS image' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.location +# label: 'Location' +# default: westus +# type: string +# description: 'Azure region to create the virtual machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.managedDisks +# label: 'Managed Disks' +# default: false +# type: boolean +# description: 'Configures VM and availability set for managed disks' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.noPublicIp +# label: 'No Public IP' +# default: false +# type: boolean +# description: 'Do not create a public IP address for the machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.privateIpAddress +# label: 'Private IP Address' +# default: '' +# type: string +# description: 'Specify a static private IP address for the machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.resourceGroup +# label: 'Resource Group' +# default: docker-machine +# type: string +# description: 'Azure Resource Group name (will be created if missing)' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.size +# label: 'Size' +# default: 'Standard_D2_v2' +# type: string +# description: 'Size for Azure Virtual Machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.sshUser +# label: 'SSH Username' +# default: docker-user +# type: string +# description: 'Username for SSH login' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.staticPublicIp +# label: 'Static Public IP' +# default: false +# type: boolean +# description: 'Assign a static public IP address to the machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.storageType +# label: 'Storage Account' +# default: 'Standard_LRS' +# type: string +# description: 'Type of Storage Account to host the OS Disk for the machine' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.subnet +# label: 'Subnet' +# default: docker-machine +# type: string +# description: 'Azure Subnet Name to be used within the Virtual Network' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.subnetPrefix +# label: 'Subnet Prefix' +# default: '192.168.0.0/16' +# type: string +# description: 'Private CIDR block to be used for the new subnet, should comply RFC 1918' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.updateDomainCount +# label: 'Update Domain Count' +# default: '' +# type: string +# description: 'Update domain count to use for availability set' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.usePrivateIp +# label: 'Use Private IP' +# default: false +# type: boolean +# description: 'Azure Subnet Name to be used within the Virtual Network' +# show_if: cloudprovider=azure +# group: 'Nodepools' +# - variable: nodepools.0.vnet +# label: 'Vnet' +# default: 'docker-machine-vnet' +# type: string +# description: 'Azure Virtual Network name to connect the virtual machine (in [resourcegroup:]name format)' +# show_if: cloudprovider=azure +# group: 'Nodepools' diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/NOTES.txt b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/NOTES.txt new file mode 100644 index 0000000..39bdbda --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/NOTES.txt @@ -0,0 +1,6 @@ + +Congratulations! You've successfully deployed a cluster using the Helm Chart for Rancher Cluster Templates by Rancher Government. Please be patient for the cluster to provision and deploy on your infrastructure. + +View the Cluster -> https://{{ .Values.rancher.cattle.url | default "" }}/dashboard/c/_/manager/provisioning.cattle.io.cluster/fleet-default/{{ .Values.cluster.name }} + +View the Docs -> https://github.com/rancherfederal/rancher-cluster-templates diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/_helpers.tpl b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/_helpers.tpl new file mode 100644 index 0000000..a6bc23e --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "rancher-cluster-templates.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "rancher-cluster-templates.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "rancher-cluster-templates.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "rancher-cluster-templates.labels" -}} +helm.sh/chart: {{ include "rancher-cluster-templates.chart" . }} +{{ include "rancher-cluster-templates.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "rancher-cluster-templates.selectorLabels" -}} +app.kubernetes.io/name: {{ include "rancher-cluster-templates.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "rancher-cluster-templates.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "rancher-cluster-templates.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/cluster.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/cluster.yaml new file mode 100644 index 0000000..6755a8d --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/cluster.yaml @@ -0,0 +1,438 @@ +{{- $clustername := .Values.cluster.name -}} +apiVersion: provisioning.cattle.io/v1 +kind: Cluster +metadata: + {{- if .Values.cluster.labels }} + labels: +{{ toYaml .Values.cluster.labels | indent 4 }} + {{- end }} + {{- if .Values.cluster.annotations }} + annotations: +{{ toYaml .Values.cluster.annotations | indent 4 }} + {{- end }} + name: {{ .Values.cluster.name }} + namespace: fleet-default +spec: + {{- if .Values.cluster.config.agentEnvVars }} + agentEnvVars: +{{ toYaml .Values.cluster.config.agentEnvVars | indent 4 }} + {{- end }} + {{- if .Values.cloudCredentialSecretName }} + cloudCredentialSecretName: cattle-global-data:{{ .Values.cloudCredentialSecretName }} + {{- end }} + # clusterAPIConfig: + # clusterAgentDeploymentCustomization: + {{- if .Values.cluster.config.defaultClusterRoleForProjectMembers }} + defaultClusterRoleForProjectMembers: {{ .Values.cluster.config.defaultClusterRoleForProjectMembers }} + {{- end }} + {{- if .Values.cluster.config.defaultPodSecurityAdmissionConfigurationTemplateName }} + defaultPodSecurityAdmissionConfigurationTemplateName: {{ .Values.cluster.config.defaultPodSecurityAdmissionConfigurationTemplateName }} + {{- end }} + {{- if .Values.cluster.config.defaultPodSecurityPolicyTemplateName }} + defaultPodSecurityPolicyTemplateName: {{ .Values.cluster.config.defaultPodSecurityPolicyTemplateName }} + {{- end }} + enableNetworkPolicy: {{ .Values.cluster.config.enableNetworkPolicy }} + # fleetAgentDeploymentCustomization: + {{- if .Values.cluster.config.kubernetesVersion }} + kubernetesVersion: {{ .Values.cluster.config.kubernetesVersion }} + {{- end }} + {{- if eq .Values.cluster.config.localClusterAuthEndpoint.enabled true }} + localClusterAuthEndpoint: + enabled: {{ .Values.cluster.config.localClusterAuthEndpoint.enabled }} + fqdn: {{ .Values.cluster.config.localClusterAuthEndpoint.fqdn }} + caCerts: {{ .Values.cluster.config.localClusterAuthEndpoint.caCerts }} + {{- else }} + localClusterAuthEndpoint: + enabled: false + {{- end }} + # redeploySystemAgentGeneration: + rkeConfig: + {{- with $.Values.cluster.config.chartValues }} + chartValues: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $.Values.cluster.config.additionalManifests }} + additionalManifest: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- if .Values.cluster.config.etcd }} + etcd: + disableSnapshots: {{ .Values.cluster.config.etcd.disableSnapshots }} + snapshotRetention: {{ .Values.cluster.config.etcd.snapshotRetention }} + snapshotScheduleCron: {{ .Values.cluster.config.etcd.snapshotScheduleCron }} + {{- if .Values.cluster.config.etcd.s3 }} + s3: + bucket: {{ .Values.cluster.config.etcd.s3.bucket }} + cloudCredentialName: cattle-global-data:{{ .Values.cluster.config.etcd.s3.cloudCredentialSecretName }} + {{- if .Values.cluster.config.etcd.s3.folder }} + folder: {{ .Values.cluster.config.etcd.s3.folder }} + {{- end }} + region: {{ .Values.cluster.config.etcd.s3.region }} + skipSSLVerify: {{ .Values.cluster.config.etcd.s3.skipSSLVerify }} + endpoint: {{ .Values.cluster.config.etcd.s3.endpoint }} + {{- if .Values.cluster.config.etcd.s3.endpointCA }} + endpointCA: |- +{{ .Values.cluster.config.etcd.s3.endpointCA | indent 10 }} + {{- end }} + {{- end }} + {{- end }} + # etcdSnapshotCreate: + # etcdSnapshotRestore: + # infrastructureRef: + {{- if .Values.cluster.config.globalConfig }} + machineGlobalConfig: + {{- if .Values.cluster.config.globalConfig.cni }} + cni: {{ .Values.cluster.config.globalConfig.cni }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.cluster_cidr }} + cluster-cidr: {{ .Values.cluster.config.globalConfig.cluster_cidr }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.service_cidr }} + service-cidr: {{ .Values.cluster.config.globalConfig.service_cidr }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.docker }} + docker: {{ .Values.cluster.config.globalConfig.docker }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable }} + disable: {{ .Values.cluster.config.globalConfig.disable | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_scheduler }} + disable-scheduler: {{ .Values.cluster.config.globalConfig.disable_scheduler }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_cloud_controller }} + disable-cloud-controller: {{ .Values.cluster.config.globalConfig.disable_cloud_controller }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_kube_proxy }} + disable-kube-proxy: {{ .Values.cluster.config.globalConfig.disable_kube_proxy }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.etcd_expose_metrics }} + etcd-expose-metrics: {{ .Values.cluster.config.globalConfig.etcd_expose_metrics }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.profile }} + profile: {{ .Values.cluster.config.globalConfig.profile }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.selinux }} + selinux: {{ .Values.cluster.config.globalConfig.selinux }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.tls_san }} + tls-san: {{ .Values.cluster.config.globalConfig.tls_san | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.token }} + token: {{ .Values.cluster.config.globalConfig.token }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.systemDefaultRegistry }} + system-default-registry: {{ .Values.cluster.config.globalConfig.systemDefaultRegistry }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.secrets_encryption }} + secrets-encryption: {{ .Values.cluster.config.globalConfig.secrets_encryption }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.write_kubeconfig_mode }} + write-kubeconfig-mode: {{ .Values.cluster.config.globalConfig.write_kubeconfig_mode }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.use_service_account_credentials }} + use-service-account-credentials: {{ .Values.cluster.config.globalConfig.use_service_account_credentials }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.protect_kernel_defaults }} + protect-kernel-defaults: {{ .Values.cluster.config.globalConfig.protect_kernel_defaults }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.cloud_provider_name }} + cloud-provider-name: {{ .Values.cluster.config.globalConfig.cloud_provider_name }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.cloud_provider_config }} + cloud-provider-config: {{ .Values.cluster.config.globalConfig.cloud_provider_config }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.kube_controller_manager_arg }} + kube-controller-manager-arg: {{ .Values.cluster.config.globalConfig.kube_controller_manager_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.kube_scheduler_arg }} + kube-scheduler-arg: {{ .Values.cluster.config.globalConfig.kube_scheduler_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.kube_apiserver_arg }} + kube-apiserver-arg: {{ .Values.cluster.config.globalConfig.kube_apiserver_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.kubelet_proxy_arg }} + kubelet-proxy-arg: {{ .Values.cluster.config.globalConfig.kubelet_proxy_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.kubelet_arg }} + kubelet-arg: {{ .Values.cluster.config.globalConfig.kubelet_arg | toRawJson }} + {{- end }} + {{- end }} + # machinePoolDefaults: + {{- if ne .Values.cloudprovider "custom" }} + machinePools: + {{- if .Values.nodepools }} {{ range $index, $nodepool := .Values.nodepools }} + - name: {{ $nodepool.name }} + quantity: {{ $nodepool.quantity }} + controlPlaneRole: {{ $nodepool.controlplane }} + etcdRole: {{ $nodepool.etcd }} + workerRole: {{ $nodepool.worker }} + {{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 8 }} + {{- end }} + {{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 8 }} + {{- end }} + machineConfigRef: + {{- if eq $.Values.cloudprovider "amazonec2" }} + kind: Amazonec2Config + {{- else if eq $.Values.cloudprovider "vsphere" }} + kind: VmwarevsphereConfig + {{- else if eq $.Values.cloudprovider "harvester" }} + kind: HarvesterConfig + {{- else if eq $.Values.cloudprovider "digitalocean" }} + kind: DigitaloceanConfig + {{- else if eq $.Values.cloudprovider "azure" }} + kind: AzureConfig + {{- else if eq $.Values.cloudprovider "elemental" }} + apiVersion: elemental.cattle.io/v1beta1 + kind: MachineInventorySelectorTemplate + {{- end}} + name: {{ $clustername }}-{{ $nodepool.name }} + displayName: {{ $nodepool.displayName | default $nodepool.name }} + {{- if $nodepool.drainBeforeDelete }} + drainBeforeDelete: {{ $nodepool.drainBeforeDelete }} + {{- end }} + {{- if $nodepool.drainBeforeDeleteTimeout }} + drainBeforeDeleteTimeout: {{ $nodepool.drainBeforeDeleteTimeout }} + {{- end }} + {{- if $nodepool.machineDeploymentLabels }} + machineDeploymentLabels: +{{ toYaml $nodepool.machineDeploymentLabels | indent 8 }} + {{- end }} + {{- if $nodepool.machineDeploymentAnnotations }} + machineDeploymentAnnotations: +{{ toYaml $nodepool.machineDeploymentAnnotations | indent 8 }} + {{- end }} + paused: {{ $nodepool.paused }} + {{- if $nodepool.rollingUpdate }} + rollingUpdate: + maxUnavailable: {{ $nodepool.rollingUpdate.maxUnavailable }} + maxSurge: {{ $nodepool.rollingUpdate.maxSurge }} + {{- end }} + {{- if $nodepool.unhealthyNodeTimeout }} + unhealthyNodeTimeout: {{ $nodepool.unhealthyNodeTimeout }} + {{- end }} + {{- end }} + {{- end }} + {{- if or .Values.cluster.config.controlPlaneConfig .Values.cluster.config.workerConfig}} + machineSelectorConfig: + {{- if .Values.cluster.config.controlPlaneConfig }} + - config: + {{- if .Values.cluster.config.controlPlaneConfig.cni }} + cni: {{ .Values.cluster.config.controlPlaneConfig.cni }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.docker }} + docker: {{ .Values.cluster.config.controlPlaneConfig.docker }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable }} + disable: {{ .Values.cluster.config.globalConfig.disable | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_scheduler }} + disable-scheduler: {{ .Values.cluster.config.globalConfig.disable_scheduler }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_cloud_controller }} + disable-cloud-controller: {{ .Values.cluster.config.globalConfig.disable_cloud_controller }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.disable_kube_proxy }} + disable-kube-proxy: {{ .Values.cluster.config.controlPlaneConfig.disable_kube_proxy }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.etcd_expose_metrics }} + etcd-expose-metrics: {{ .Values.cluster.config.controlPlaneConfig.etcd_expose_metrics }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.profile }} + profile: {{ .Values.cluster.config.controlPlaneConfig.profile }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.selinux }} + selinux: {{ .Values.cluster.config.controlPlaneConfig.selinux }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.tls_san }} + tls-san: {{ .Values.cluster.config.controlPlaneConfig.tls_san | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.token }} + token: {{ .Values.cluster.config.controlPlaneConfig.token }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.systemDefaultRegistry }} + system-default-registry: {{ .Values.cluster.config.controlPlaneConfig.systemDefaultRegistry }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.secrets_encryption }} + secrets-encryption: {{ .Values.cluster.config.controlPlaneConfig.secrets_encryption }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.write_kubeconfig_mode }} + write-kubeconfig-mode: {{ .Values.cluster.config.controlPlaneConfig.write_kubeconfig_mode }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.use_service_account_credentials }} + use-service-account-credentials: {{ .Values.cluster.config.controlPlaneConfig.use_service_account_credentials }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.protect_kernel_defaults }} + protect-kernel-defaults: {{ .Values.cluster.config.controlPlaneConfig.protect_kernel_defaults }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.cloud_provider_name }} + cloud-provider-name: {{ .Values.cluster.config.controlPlaneConfig.cloud_provider_name }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.cloud_provider_config }} + cloud-provider-config: {{ .Values.cluster.config.controlPlaneConfig.cloud_provider_config }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.kube_controller_manager_arg }} + kube-controller-manager-arg: {{ .Values.cluster.config.controlPlaneConfig.kube_controller_manager_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.kube_scheduler_arg }} + kube-scheduler-arg: {{ .Values.cluster.config.controlPlaneConfig.kube_scheduler_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.kube_apiserver_arg }} + kube-apiserver-arg: {{ .Values.cluster.config.controlPlaneConfig.kube_apiserver_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.kubelet_proxy_arg }} + kubelet-proxy-arg: {{ .Values.cluster.config.controlPlaneConfig.kubelet_proxy_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.controlPlaneConfig.kubelet_arg }} + kubelet-arg: {{ .Values.cluster.config.controlPlaneConfig.kubelet_arg | toRawJson }} + {{- end }} + machineLabelSelector: + matchLabels: + node-role.kubernetes.io/control-plane: "true" + {{- end }} + {{- if .Values.cluster.config.workerConfig }} + - config: + {{- if .Values.cluster.config.workerConfig.cni }} + cni: {{ .Values.cluster.config.workerConfig.cni }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.docker }} + docker: {{ .Values.cluster.config.workerConfig.docker }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable }} + disable: {{ .Values.cluster.config.globalConfig.disable | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_scheduler }} + disable-scheduler: {{ .Values.cluster.config.globalConfig.disable_scheduler }} + {{- end }} + {{- if .Values.cluster.config.globalConfig.disable_cloud_controller }} + disable-cloud-controller: {{ .Values.cluster.config.globalConfig.disable_cloud_controller }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.disable_kube_proxy }} + disable-kube-proxy: {{ .Values.cluster.config.workerConfig.disable_kube_proxy }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.etcd_expose_metrics }} + etcd-expose-metrics: {{ .Values.cluster.config.workerConfig.etcd_expose_metrics }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.profile }} + profile: {{ .Values.cluster.config.workerConfig.profile }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.selinux }} + selinux: {{ .Values.cluster.config.workerConfig.selinux }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.tls_san }} + tls-san: {{ .Values.cluster.config.workerConfig.tls_san | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.token }} + token: {{ .Values.cluster.config.workerConfig.token }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.systemDefaultRegistry }} + system-default-registry: {{ .Values.cluster.config.workerConfig.systemDefaultRegistry }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.secrets_encryption }} + secrets-encryption: {{ .Values.cluster.config.workerConfig.secrets_encryption }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.write_kubeconfig_mode }} + write-kubeconfig-mode: {{ .Values.cluster.config.workerConfig.write_kubeconfig_mode }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.use_service_account_credentials }} + use-service-account-credentials: {{ .Values.cluster.config.workerConfig.use_service_account_credentials }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.protect_kernel_defaults }} + protect-kernel-defaults: {{ .Values.cluster.config.workerConfig.protect_kernel_defaults }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.cloud_provider_name }} + cloud-provider-name: {{ .Values.cluster.config.workerConfig.cloud_provider_name }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.cloud_provider_config }} + cloud-provider-config: {{ .Values.cluster.config.workerConfig.cloud_provider_config }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.kube_controller_manager_arg }} + kube-controller-manager-arg: {{ .Values.cluster.config.workerConfig.kube_controller_manager_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.kube_scheduler_arg }} + kube-scheduler-arg: {{ .Values.cluster.config.workerConfig.kube_scheduler_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.kube_apiserver_arg }} + kube-apiserver-arg: {{ .Values.cluster.config.workerConfig.kube_apiserver_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.kubelet_proxy_arg }} + kubelet-proxy-arg: {{ .Values.cluster.config.workerConfig.kubelet_proxy_arg | toRawJson }} + {{- end }} + {{- if .Values.cluster.config.workerConfig.kubelet_arg }} + kubelet-arg: {{ .Values.cluster.config.workerConfig.kubelet_arg | toRawJson }} + {{- end }} + machineLabelSelector: + matchLabels: + rke.cattle.io/worker-role: "true" + {{- end }} + {{- end }} + {{- end }} + # machineSelectorFiles: + # provisionGeneration: + {{- if and .Values.cluster.config.registries (eq .Values.cluster.config.registries.enabled true) }} + registries: + configs: + {{- range .Values.cluster.config.registries.configs }} + {{ .name }}: + authConfigSecretName: {{ .authConfigSecretName }} + caBundle: {{ .caBundle }} + insecureSkipVerify: {{ .insecureSkipVerify }} + tlsSecretName: {{ .tlsSecretName }} + {{- end }} + {{- if .Values.cluster.config.registries.mirrors }} + mirrors: + {{- range .Values.cluster.config.registries.mirrors }} + {{ .name | quote }}: + endpoint: + {{- range .endpoints }} + - {{ . }} + {{- end }} + {{- if .rewrite }} + rewrite: + {{- range $key, $value := .rewrite }} + "{{ $key }}": "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + # rotateCertificates: + # rotateEncryptionKeys: + {{- if .Values.cluster.config.upgradeStrategy }} + upgradeStrategy: + controlPlaneConcurrency: {{ .Values.cluster.config.upgradeStrategy.controlPlaneConcurrency }} + {{- if eq .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.enabled true }} + controlPlaneDrainOptions: + enabled: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.enabled }} + deleteEmptyDirData: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.deleteEmptyDirData }} + disableEviction: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.disableEviction }} + force: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.force }} + gracePeriod: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.gracePeriod }} + ignoreDaemonSets: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.ignoreDaemonSets }} + ignoreErrors: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.ignoreErrors }} + skipWaitForDeleteTimeoutSeconds: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.skipWaitForDeleteTimeoutSeconds }} + timeout: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.timeout }} + {{- else }} + controlPlaneDrainOptions: + enabled: {{ .Values.cluster.config.upgradeStrategy.controlPlaneDrainOptions.enabled }} + {{- end }} + workerConcurrency: {{ .Values.cluster.config.upgradeStrategy.workerConcurrency }} + {{- if eq .Values.cluster.config.upgradeStrategy.workerDrainOptions.enabled true }} + workerDrainOptions: + enabled: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.enabled }} + deleteEmptyDirData: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.deleteEmptyDirData }} + disableEviction: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.disableEviction }} + force: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.force }} + gracePeriod: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.gracePeriod }} + ignoreDaemonSets: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.ignoreDaemonSets }} + ignoreErrors: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.ignoreErrors }} + skipWaitForDeleteTimeoutSeconds: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.skipWaitForDeleteTimeoutSeconds }} + timeout: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.timeout }} + {{- else }} + workerDrainOptions: + enabled: {{ .Values.cluster.config.upgradeStrategy.workerDrainOptions.enabled }} + {{- end }} + {{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/clusterroletemplatebinding.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/clusterroletemplatebinding.yaml new file mode 100644 index 0000000..3708ff0 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/clusterroletemplatebinding.yaml @@ -0,0 +1,11 @@ +{{ $root := . }} +{{- range $index, $member := .Values.clusterMembers }} +apiVersion: management.cattle.io/v3 +clusterName: c-m-{{ trunc 8 (sha256sum (printf "%s/%s" $root.Release.Namespace $root.Values.cluster.name)) }} +kind: ClusterRoleTemplateBinding +metadata: + name: ctrb-{{ trunc 8 (sha256sum (printf "%s/%s" $root.Release.Namespace $member.principalName )) }} + namespace: c-m-{{ trunc 8 (sha256sum (printf "%s/%s" $root.Release.Namespace $root.Values.cluster.name)) }} +roleTemplateName: {{ $member.roleTemplateName }} +userPrincipalName: {{ $member.principalName }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-master.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-master.yaml new file mode 100644 index 0000000..dba7331 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-master.yaml @@ -0,0 +1,33 @@ +{{- $clustername := .Values.cluster.name -}} +{{- range .Values.nodepools }} +{{- if eq .controlplane true }} +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: MachineHealthCheck +metadata: + name: {{ $clustername }}-controlplane-healthcheck + namespace: fleet-default +spec: + clusterName: {{ $clustername }} + selector: + matchLabels: + cluster.x-k8s.io/control-plane: 'true' + cluster.x-k8s.io/cluster-name: {{ $clustername }} +# SAFETY FUSE: + # "40%" prevents a 1-node CP from trying to self-heal (which would kill it). + # If you have 3 nodes, this allows 1 to fail. + maxUnhealthy: 40% + + # TIMEOUTS (v1beta1 uses duration strings like "10m", not integers) + nodeStartupTimeout: 600s + unhealthyConditions: + - type: Ready + status: Unknown + timeout: 300s + - type: Ready + status: "False" + timeout: 300s +{{- end }} +{{- end }} + + diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-worker.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-worker.yaml new file mode 100644 index 0000000..06304e4 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/machinehealthcheck-worker.yaml @@ -0,0 +1,25 @@ +{{- $clustername := .Values.cluster.name -}} +{{- range .Values.nodepools }} +{{- if eq .worker true }} +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: MachineHealthCheck +metadata: + name: {{ $clustername }}-worker-healthcheck + namespace: fleet-default +spec: + clusterName: {{ $clustername }} + selector: + matchLabels: + rke.cattle.io/worker-role: "true" + # USE $ HERE TOO + cluster.x-k8s.io/cluster-name: {{ $clustername }} + maxUnhealthy: 100% + + nodeStartupTimeout: 10m + unhealthyConditions: + - type: Ready + status: "False" + timeout: 300s +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/managedcharts.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/managedcharts.yaml new file mode 100644 index 0000000..592f980 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/managedcharts.yaml @@ -0,0 +1,201 @@ +{{- if .Values.addons.monitoring }} +{{- if .Values.addons.monitoring.enabled }} +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: monitoring-crd-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "rancher-monitoring-crd" + repoName: "rancher-charts" + releaseName: "rancher-monitoring-crd" + version: {{ .Values.addons.monitoring.version }} + {{- if .Values.addons.monitoring.values }} + values: +{{ toYaml .Values.addons.monitoring.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-monitoring-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: monitoring-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "rancher-monitoring" + repoName: "rancher-charts" + releaseName: "rancher-monitoring" + version: {{ .Values.addons.monitoring.version }} + {{- if .Values.addons.monitoring.values }} + values: +{{ toYaml .Values.addons.monitoring.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-monitoring-system" + targets: + - clusterName: {{ .Values.cluster.name }} + diff: + comparePatches: + - apiVersion: admissionregistration.k8s.io/v1beta1 + kind: MutatingWebhookConfiguration + name: rancher-monitoring-admission + jsonPointers: + - /webhooks/0/failurePolicy + - apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + name: rancher-monitoring-admission + jsonPointers: + - /webhooks/0/failurePolicy + - apiVersion: monitoring.coreos.com/v1 + kind: ServiceMonitor + name: rancher-monitoring-kubelet + namespace: kube-system + jsonPointers: + - /spec/endpoints +--- +{{- end }} +{{- end }} +{{- if .Values.addons.logging }} +{{- if .Values.addons.logging.enabled }} +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: logging-crd-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "rancher-logging-crd" + repoName: "rancher-charts" + releaseName: "rancher-logging-crd" + version: {{ .Values.addons.logging.version }} + {{- if .Values.addons.logging.values }} + values: +{{ toYaml .Values.addons.logging.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-logging-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: logging-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "rancher-logging" + repoName: "rancher-charts" + releaseName: "rancher-logging" + version: {{ .Values.addons.logging.version }} + {{- if .Values.addons.logging.values }} + values: +{{ toYaml .Values.addons.logging.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-logging-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +{{- end }} +{{- end }} +{{- if .Values.addons.longhorn }} +{{- if .Values.addons.longhorn.enabled }} +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: longhorn-crd-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "longhorn-crd" + repoName: "rancher-charts" + releaseName: "longhorn-crd" + version: {{ .Values.addons.longhorn.version }} + {{- if .Values.addons.longhorn.values }} + values: +{{ toYaml .Values.addons.longhorn.values | indent 4 }} + {{- end }} + defaultNamespace: "longhorn-system" + targets: + - clusterName: {{ .Values.cluster.name }} + diff: + comparePatches: + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: engineimages.longhorn.io + jsonPointers: + - /status/acceptedNames + - /status/conditions + - /status/storedVersions + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: nodes.longhorn.io + jsonPointers: + - /status/acceptedNames + - /status/conditions + - /status/storedVersions + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: volumes.longhorn.io + jsonPointers: + - /status/acceptedNames + - /status/conditions + - /status/storedVersions +--- +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: longhorn-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "longhorn" + repoName: "rancher-charts" + releaseName: "longhorn" + version: {{ .Values.addons.longhorn.version }} + {{- if .Values.addons.longhorn.values }} + values: +{{ toYaml .Values.addons.longhorn.values | indent 4 }} + {{- end }} + defaultNamespace: "longhorn-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +{{- end }} +{{- end }} +{{- if .Values.addons.neuvector }} +{{- if .Values.addons.neuvector.enabled }} +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: neuvector-crd-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "neuvector-crd" + repoName: "rancher-charts" + releaseName: "neuvector-crd" + version: {{ .Values.addons.neuvector.version }} + {{- if .Values.addons.neuvector.values }} + values: +{{ toYaml .Values.addons.neuvector.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-neuvector-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +apiVersion: management.cattle.io/v3 +kind: ManagedChart +metadata: + name: neuvector-{{ .Values.cluster.name }} + namespace: fleet-default +spec: + chart: "neuvector" + repoName: "rancher-charts" + releaseName: "neuvector" + version: {{ .Values.addons.neuvector.version }} + {{- if .Values.addons.neuvector.values }} + values: +{{ toYaml .Values.addons.neuvector.values | indent 4 }} + {{- end }} + defaultNamespace: "cattle-neuvector-system" + targets: + - clusterName: {{ .Values.cluster.name }} +--- +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-aws.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-aws.yaml new file mode 100644 index 0000000..30c90ea --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-aws.yaml @@ -0,0 +1,251 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "amazonec2" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: Amazonec2Config +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +{{- if $nodepool.accessKey }} +accessKey: {{ $nodepool.accessKey }} +{{- end }} +{{- if $nodepool.ami }} +ami: {{ $nodepool.ami }} +{{- end }} +{{- if $nodepool.blockDurationMinutes }} +blockDurationMinutes: {{ $nodepool.blockDurationMinutes }} +{{- end }} +{{- if $nodepool.deviceName }} +deviceName: {{ $nodepool.deviceName }} +{{- end }} +{{- if $nodepool.encryptEbsVolume }} +encryptEbsVolume: {{ $nodepool.encryptEbsVolume }} +{{- end }} +{{- if $nodepool.endpoint }} +endpoint: {{ $nodepool.endpoint }} +{{- end }} +{{- if $nodepool.httpEndpoint }} +httpEndpoint: {{ $nodepool.httpEndpoint }} +{{- end }} +{{- if $nodepool.httpTokens }} +httpTokens: {{ $nodepool.httpTokens }} +{{- end }} +{{- if $nodepool.iamInstanceProfile }} +iamInstanceProfile: {{ $nodepool.iamInstanceProfile }} +{{- end }} +{{- if $nodepool.insecureTransport }} +insecureTransport: {{ $nodepool.insecureTransport }} +{{- end }} +{{- if $nodepool.instanceType }} +instanceType: {{ $nodepool.instanceType }} +{{- end }} +{{- if $nodepool.keypairName }} +keypairName: {{ $nodepool.keypairName }} +{{- end }} +{{- if $nodepool.kmsKey }} +kmsKey: {{ $nodepool.kmsKey }} +{{- end }} +{{- if $nodepool.monitoring }} +monitoring: {{ $nodepool.monitoring }} +{{- end }} +{{- if $nodepool.openPort}} +openPort: +{{- range $i, $port := $nodepool.openPort }} +- {{ $port | squote }} +{{- end }} +{{- end }} +{{- if $nodepool.privateAddressOnly }} +privateAddressOnly: {{ $nodepool.privateAddressOnly }} +{{- end }} +{{- if $nodepool.region }} +region: {{ $nodepool.region }} +{{- end }} +{{- if $nodepool.requestSpotInstance }} +requestSpotInstance: {{ $nodepool.requestSpotInstance }} +{{- end }} +{{- if $nodepool.retries }} +retries: {{ $nodepool.retries | squote }} +{{- end }} +{{- if $nodepool.rootSize }} +rootSize: {{ $nodepool.rootSize | squote }} +{{- end }} +{{- if $nodepool.secretKey }} +secretKey: {{ $nodepool.secretKey }} +{{- end }} +securityGroup: +{{- if $nodepool.createSecurityGroup }} +- rancher-nodes +{{- else }} +{{ toYaml $nodepool.securityGroups }} +{{- end }} +{{- if $nodepool.securityGroupReadonly }} +securityGroupReadonly: {{ $nodepool.securityGroupReadonly }} +{{- end }} +{{- if $nodepool.sessionToken }} +sessionToken: {{ $nodepool.sessionToken }} +{{- end }} +{{- if $nodepool.spotPrice }} +spotPrice: {{ $nodepool.spotPrice }} +{{- end }} +{{- if $nodepool.sshKeyContents }} +sshKeyContents: {{ $nodepool.sshKeyContents }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.subnetId }} +subnetId: {{ $nodepool.subnetId }} +{{- end }} +{{- if $nodepool.tags }} +tags: {{ $nodepool.tags }} +{{- end }} +{{- if $nodepool.useEbsOptimizedInstance }} +useEbsOptimizedInstance: {{ $nodepool.useEbsOptimizedInstance }} +{{- end }} +{{- if $nodepool.usePrivateAddress }} +usePrivateAddress: {{ $nodepool.usePrivateAddress }} +{{- end }} +{{- if $nodepool.userData }} +userdata: {{- $nodepool.userData | toYaml | indent 1 }} +{{- end }} +{{- if $nodepool.volumeType }} +volumeType: {{ $nodepool.volumeType }} +{{- end }} +{{- if $nodepool.vpcId }} +vpcId: {{ $nodepool.vpcId }} +{{- end }} +{{- if $nodepool.zone }} +zone: {{ $nodepool.zone }} +{{- end }} +--- +{{- end }} +{{ $nodepool := .Values.nodepool }} +{{- if $nodepool }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: Amazonec2Config +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +{{- if $nodepool.accessKey }} +accessKey: {{ $nodepool.accessKey }} +{{- end }} +{{- if $nodepool.ami }} +ami: {{ $nodepool.ami }} +{{- end }} +{{- if $nodepool.blockDurationMinutes }} +blockDurationMinutes: {{ $nodepool.blockDurationMinutes }} +{{- end }} +{{- if $nodepool.deviceName }} +deviceName: {{ $nodepool.deviceName }} +{{- end }} +{{- if $nodepool.encryptEbsVolume }} +encryptEbsVolume: {{ $nodepool.encryptEbsVolume }} +{{- end }} +{{- if $nodepool.endpoint }} +endpoint: {{ $nodepool.endpoint }} +{{- end }} +{{- if $nodepool.httpEndpoint }} +httpEndpoint: {{ $nodepool.httpEndpoint }} +{{- end }} +{{- if $nodepool.httpTokens }} +httpTokens: {{ $nodepool.httpTokens }} +{{- end }} +{{- if $nodepool.iamInstanceProfile }} +iamInstanceProfile: {{ $nodepool.iamInstanceProfile }} +{{- end }} +{{- if $nodepool.insecureTransport }} +insecureTransport: {{ $nodepool.insecureTransport }} +{{- end }} +{{- if $nodepool.instanceType }} +instanceType: {{ $nodepool.instanceType }} +{{- end }} +{{- if $nodepool.keypairName }} +keypairName: {{ $nodepool.keypairName }} +{{- end }} +{{- if $nodepool.kmsKey }} +kmsKey: {{ $nodepool.kmsKey }} +{{- end }} +{{- if $nodepool.monitoring }} +monitoring: {{ $nodepool.monitoring }} +{{- end }} +{{- if $nodepool.openPort}} +openPort: +{{- range $i, $port := $nodepool.openPort }} +- {{ $port | squote }} +{{- end }} +{{- end }} +{{- if $nodepool.privateAddressOnly }} +privateAddressOnly: {{ $nodepool.privateAddressOnly }} +{{- end }} +{{- if $nodepool.region }} +region: {{ $nodepool.region }} +{{- end }} +{{- if $nodepool.requestSpotInstance }} +requestSpotInstance: {{ $nodepool.requestSpotInstance }} +{{- end }} +{{- if $nodepool.retries }} +retries: {{ $nodepool.retries | squote }} +{{- end }} +{{- if $nodepool.rootSize }} +rootSize: {{ $nodepool.rootSize | squote }} +{{- end }} +{{- if $nodepool.secretKey }} +secretKey: {{ $nodepool.secretKey }} +{{- end }} +{{- if $nodepool.createSecurityGroup }} +securityGroup: +- rancher-nodes +{{- else if $nodepool.securityGroups }} +securityGroup: +{{ toYaml $nodepool.securityGroups }} +{{- end }} +{{- if $nodepool.securityGroupReadonly }} +securityGroupReadonly: {{ $nodepool.securityGroupReadonly }} +{{- end }} +{{- if $nodepool.sessionToken }} +sessionToken: {{ $nodepool.sessionToken }} +{{- end }} +{{- if $nodepool.spotPrice }} +spotPrice: {{ $nodepool.spotPrice }} +{{- end }} +{{- if $nodepool.sshKeyContents }} +sshKeyContents: {{ $nodepool.sshKeyContents }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.subnetId }} +subnetId: {{ $nodepool.subnetId }} +{{- end }} +{{- if $nodepool.tags }} +tags: {{ $nodepool.tags }} +{{- end }} +{{- if $nodepool.useEbsOptimizedInstance }} +useEbsOptimizedInstance: {{ $nodepool.useEbsOptimizedInstance }} +{{- end }} +{{- if $nodepool.usePrivateAddress }} +usePrivateAddress: {{ $nodepool.usePrivateAddress }} +{{- end }} +{{- if $nodepool.userData }} +userdata: {{- $nodepool.userData | toYaml | indent 1 }} +{{- end }} +{{- if $nodepool.volumeType }} +volumeType: {{ $nodepool.volumeType }} +{{- end }} +{{- if $nodepool.vpcId }} +vpcId: {{ $nodepool.vpcId }} +{{- end }} +{{- if $nodepool.zone }} +zone: {{ $nodepool.zone }} +{{- end }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-azure.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-azure.yaml new file mode 100644 index 0000000..30d3526 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-azure.yaml @@ -0,0 +1,95 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "azure" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: AzureConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +availabilitySet: {{ $nodepool.availabilitySet }} +clientId: {{ $nodepool.clientId }} +customData: {{ $nodepool.customData }} +diskSize: {{ $nodepool.diskSize }} +dns: {{ $nodepool.dns }} +environment: {{ $nodepool.environment }} +faultDomainCount: {{ $nodepool.faultDomainCount }} +image: {{ $nodepool.image }} +location: {{ $nodepool.location }} +managedDisks: {{ $nodepool.managedDisks }} +noPublicIp: {{ $nodepool.noPublicIp }} +{{- if $nodepool.openPort}} +openPort: +{{- range $i, $port := $nodepool.openPort }} +- {{ $port }} +{{- end }} +{{- end }} +privateIpAddress: {{ $nodepool.privateIpAddress }} +resourceGroup: {{ $nodepool.resourceGroup }} +size: {{ $nodepool.size }} +sshUser: {{ $nodepool.sshUser }} +staticPublicIp: {{ $nodepool.staticPublicIp }} +storageType: {{ $nodepool.storageType }} +subnet: {{ $nodepool.subnet }} +subnetPrefix: {{ $nodepool.subnetPrefix }} +subscriptionId: {{ $nodepool.subscriptionId }} +updateDomainCount: {{ $nodepool.updateDomainCount }} +usePrivateIp: {{ $nodepool.usePrivateIp }} +vnet: {{ $nodepool.vnet }} +--- +{{- end }} +{{ $nodepool := .Values.nodepool }} +{{- if $nodepool }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: AzureConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +availabilitySet: {{ $nodepool.availabilitySet }} +clientId: {{ $nodepool.clientId }} +customData: {{ $nodepool.customData }} +diskSize: {{ $nodepool.diskSize }} +dns: {{ $nodepool.dns }} +environment: {{ $nodepool.environment }} +faultDomainCount: {{ $nodepool.faultDomainCount }} +image: {{ $nodepool.image }} +location: {{ $nodepool.location }} +managedDisks: {{ $nodepool.managedDisks }} +noPublicIp: {{ $nodepool.noPublicIp }} +{{- if $nodepool.openPort}} +openPort: +{{- range $i, $port := $nodepool.openPort }} +- {{ $port }} +{{- end }} +{{- end }} +privateIpAddress: {{ $nodepool.privateIpAddress }} +resourceGroup: {{ $nodepool.resourceGroup }} +size: {{ $nodepool.size }} +sshUser: {{ $nodepool.sshUser }} +staticPublicIp: {{ $nodepool.staticPublicIp }} +storageType: {{ $nodepool.storageType }} +subnet: {{ $nodepool.subnet }} +subnetPrefix: {{ $nodepool.subnetPrefix }} +subscriptionId: {{ $nodepool.subscriptionId }} +updateDomainCount: {{ $nodepool.updateDomainCount }} +usePrivateIp: {{ $nodepool.usePrivateIp }} +vnet: {{ $nodepool.vnet }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-do.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-do.yaml new file mode 100644 index 0000000..5c68eb7 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-do.yaml @@ -0,0 +1,103 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "digitalocean" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: DigitaloceanConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +{{- if $nodepool.accessToken }} +accessToken: {{ $nodepool.accessToken }} +{{- end }} +{{- if $nodepool.backups }} +backups: {{ $nodepool.backups }} +{{- end }} +{{- if $nodepool.image }} +image: {{ $nodepool.image }} +{{- end }} +{{- if $nodepool.ipv6 }} +ipv6: {{ $nodepool.ipv6 }} +{{- end }} +{{- if $nodepool.monitoring }} +monitoring: {{ $nodepool.monitoring }} +{{- end }} +{{- if $nodepool.privateNetworking }} +privateNetworking: {{ $nodepool.privateNetworking }} +{{- end }} +{{- if $nodepool.region }} +region: {{ $nodepool.region }} +{{- end }} +{{- if $nodepool.size }} +size: {{ $nodepool.size }} +{{- end }} +{{- if $nodepool.sshKeyContents }} +sshKeyContents: {{ $nodepool.sshKeyContents }} +{{- end }} +{{- if $nodepool.sshKeyFingerprint }} +sshKeyFingerprint: {{ $nodepool.sshKeyFingerprint }} +{{- end }} +{{- if $nodepool.sshPort }} +sshPort: {{ $nodepool.sshPort | squote }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.tags }} +tags: {{ $nodepool.tags }} +{{- end }} +{{- if $nodepool.userData }} +userdata: {{- $nodepool.userData | toYaml | indent 1 }} +{{- end }} +--- +{{- end }} +{{ $nodepool := .Values.nodepool }} +{{- if $nodepool }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: DigitaloceanConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +{{- if $nodepool.accessToken }} +accessToken: {{ $nodepool.accessToken }} +{{- end }} +{{- if $nodepool.backups }} +backups: {{ $nodepool.backups }} +{{- end }} +{{- if $nodepool.image }} +image: {{ $nodepool.image }} +{{- end }} +{{- if $nodepool.ipv6 }} +ipv6: {{ $nodepool.ipv6 }} +{{- end }} +{{- if $nodepool.monitoring }} +monitoring: {{ $nodepool.monitoring }} +{{- end }} +{{- if $nodepool.privateNetworking }} +privateNetworking: {{ $nodepool.privateNetworking }} +{{- end }} +{{- if $nodepool.region }} +region: {{ $nodepool.region }} +{{- end }} +{{- if $nodepool.size }} +size: {{ $nodepool.size }} +{{- end }} +{{- if $nodepool.sshKeyContents }} +sshKeyContents: {{ $nodepool.sshKeyContents }} +{{- end }} +{{- if $nodepool.sshKeyFingerprint }} +sshKeyFingerprint: {{ $nodepool.sshKeyFingerprint }} +{{- end }} +{{- if $nodepool.sshPort }} +sshPort: {{ $nodepool.sshPort | squote }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.tags }} +tags: {{ $nodepool.tags }} +{{- end }} +{{- if $nodepool.userData }} +userdata: {{- $nodepool.userData | toYaml | indent 1 }} +{{- end }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-elemental.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-elemental.yaml new file mode 100644 index 0000000..81335c8 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-elemental.yaml @@ -0,0 +1,15 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "elemental" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: elemental.cattle.io/v1beta1 +kind: MachineInventorySelectorTemplate +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +spec: + template: + spec: + selector: + {{- toYaml $nodepool.selector | nindent 8 }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-harvester.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-harvester.yaml new file mode 100644 index 0000000..c7a35eb --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-harvester.yaml @@ -0,0 +1,166 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "harvester" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: HarvesterConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +{{- if $nodepool.cloudConfig }} +cloudConfig: {{$nodepool.cloudconfig }} +{{- end }} +{{- if $nodepool.clusterId }} +clusterId: {{ $nodepool.clusterId }} +{{- end }} +{{- if $nodepool.clusterType }} +clusterType: {{ $nodepool.clusterType }} +{{- end }} +{{- if $nodepool.cpuCount }} +cpuCount: {{ $nodepool.cpuCount | squote }} +{{- end }} +{{- if $nodepool.diskBus }} +diskBus: {{ $nodepool.diskBus }} +{{- end }} +{{- if $nodepool.diskInfo }} +diskInfo: {{ $nodepool.diskInfo }} +{{- end }} +{{- if $nodepool.diskSize }} +diskSize: {{ $nodepool.diskSize | squote }} +{{- end }} +{{- if $nodepool.imageName }} +imageName: {{ $nodepool.imageName }} +{{- end }} +{{- if $nodepool.keyPairName }} +keyPairName: {{ $nodepool.keyPairName }} +{{- end }} +{{- if $nodepool.kubeconfigContent }} +kubeconfigContent: {{- $nodepool.kubeconfigContent | toYaml }} +{{- end }} +{{- if $nodepool.memorySize }} +memorySize: {{ $nodepool.memorySize | squote }} +{{- end }} +{{- if $nodepool.networkData }} +networkData: {{- $nodepool.networkData | toYaml | indent 1 }} +{{- end }} +{{- if $nodepool.networkInfo }} +networkInfo: {{ $nodepool.networkInfo }} +{{- end }} +{{- if $nodepool.networkModel }} +networkModel: {{ $nodepool.networkModel }} +{{- end }} +{{- if $nodepool.networkName }} +networkName: {{ $nodepool.networkName }} +{{- end }} +{{- if $nodepool.networkType }} +networkType: {{ $nodepool.networkType }} +{{- end }} +{{- if $nodepool.sshPassword }} +sshPassword: {{ $nodepool.sshPassword }} +{{- end }} +{{- if $nodepool.sshPort }} +sshPort: {{ $nodepool.sshPort | squote }} +{{- end }} +{{- if $nodepool.sshPrivateKeyPath }} +sshPrivateKeyPath: {{ $nodepool.sshPrivateKeyPath }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.userData }} +userData: {{ $nodepool.userData | toYaml }} +{{- end }} +{{- if $nodepool.vmAffinity }} +vmAffinity: {{ $nodepool.vmAffinity}} +{{- end }} +{{- if $nodepool.vmNamespace }} +vmNamespace: {{ $nodepool.vmNamespace }} +{{- end }} +--- +{{- end }} +{{ $nodepool := .Values.nodepool }} +{{- if $nodepool }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: HarvesterConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +{{- if $nodepool.cloudConfig }} +cloudConfig: {{$nodepool.cloudconfig }} +{{- end }} +{{- if $nodepool.clusterId }} +clusterId: {{ $nodepool.clusterId }} +{{- end }} +{{- if $nodepool.clusterType }} +clusterType: {{ $nodepool.clusterType }} +{{- end }} +{{- if $nodepool.cpuCount }} +cpuCount: {{ $nodepool.cpuCount | squote }} +{{- end }} +{{- if $nodepool.diskBus }} +diskBus: {{ $nodepool.diskBus }} +{{- end }} +{{- if $nodepool.diskInfo }} +diskInfo: {{ $nodepool.diskInfo }} +{{- end }} +{{- if $nodepool.diskSize }} +diskSize: {{ $nodepool.diskSize | squote }} +{{- end }} +{{- if $nodepool.imageName }} +imageName: {{ $nodepool.imageName }} +{{- end }} +{{- if $nodepool.keyPairName }} +keyPairName: {{ $nodepool.keyPairName }} +{{- end }} +{{- if $nodepool.kubeconfigContent }} +kubeconfigContent: {{- $nodepool.kubeconfigContent | toYaml }} +{{- end }} +{{- if $nodepool.memorySize }} +memorySize: {{ $nodepool.memorySize | squote }} +{{- end }} +{{- if $nodepool.networkData }} +networkData: {{- $nodepool.networkData | toYaml | indent 1 }} +{{- end }} +{{- if $nodepool.networkInfo }} +networkInfo: {{ $nodepool.networkInfo }} +{{- end }} +{{- if $nodepool.networkModel }} +networkModel: {{ $nodepool.networkModel }} +{{- end }} +{{- if $nodepool.networkName }} +networkName: {{ $nodepool.networkName }} +{{- end }} +{{- if $nodepool.networkType }} +networkType: {{ $nodepool.networkType }} +{{- end }} +{{- if $nodepool.sshPassword }} +sshPassword: {{ $nodepool.sshPassword }} +{{- end }} +{{- if $nodepool.sshPort }} +sshPort: {{ $nodepool.sshPort | squote }} +{{- end }} +{{- if $nodepool.sshPrivateKeyPath }} +sshPrivateKeyPath: {{ $nodepool.sshPrivateKeyPath }} +{{- end }} +{{- if $nodepool.sshUser }} +sshUser: {{ $nodepool.sshUser }} +{{- end }} +{{- if $nodepool.userData }} +userData: {{ $nodepool.userData | toYaml }} +{{- end }} +{{- if $nodepool.vmAffinity }} +vmAffinity: {{ $nodepool.vmAffinity }} +{{- end }} +{{- if $nodepool.vmNamespace }} +vmNamespace: {{ $nodepool.vmNamespace }} +{{- end }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-vsphere.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-vsphere.yaml new file mode 100644 index 0000000..c8f40a6 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/templates/nodeconfig-vsphere.yaml @@ -0,0 +1,97 @@ +{{- $clustername := .Values.cluster.name -}} +{{- if eq .Values.cloudprovider "vsphere" }} +{{- range $index, $nodepool := .Values.nodepools }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: VmwarevsphereConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +{{- if $nodepool.cfgparam }} +cfgparam: {{ $nodepool.cfgparam }} +{{- end }} +cloneFrom: {{ $nodepool.cloneFrom }} +cloudConfig: |- +{{ $nodepool.cloudConfig | indent 2 }} +cloudinit: {{ $nodepool.cloudinit }} +contentLibrary: {{ $nodepool.contentLibrary }} +cpuCount: {{ $nodepool.cpuCount | squote }} +creationType: {{ $nodepool.creationType }} +customAttribute: {{ $nodepool.customAttribute }} +datacenter: {{ $nodepool.datacenter }} +datastore: {{ $nodepool.datastore }} +datastoreCluster: {{ $nodepool.datastoreCluster }} +diskSize: {{ $nodepool.diskSize | squote }} +folder: {{ $nodepool.folder }} +hostsystem: {{ $nodepool.hostsystem }} +memorySize: {{ $nodepool.memorySize | squote }} +network: {{ $nodepool.network }} +pool: {{ $nodepool.pool }} +sshPort: {{ $nodepool.sshPort | squote }} +sshUser: {{ $nodepool.sshUser }} +sshUserGroup: {{ $nodepool.sshUserGroup }} +tag: {{ $nodepool.tag }} +vappIpallocationpolicy: {{ $nodepool.vappIpallocationpolicy }} +vappIpprotocol: {{ $nodepool.vappIpprotocol }} +vappProperty: {{ $nodepool.vappProperty }} +vappTransport: {{ $nodepool.vappTransport }} +vcenter: {{ $nodepool.vcenter }} +vcenterPort: {{ $nodepool.vcenterPort | squote }} +--- +{{- end }} +{{ $nodepool := .Values.nodepool }} +{{- if $nodepool }} +apiVersion: rke-machine-config.cattle.io/v1 +kind: VmwarevsphereConfig +metadata: + name: {{ $clustername }}-{{ $nodepool.name }} + namespace: fleet-default +common: +{{- if $nodepool.labels }} + labels: +{{ toYaml $nodepool.labels | indent 4 }} +{{- end }} +{{- if $nodepool.taints }} + taints: +{{ toYaml $nodepool.taints | indent 4 }} +{{- end }} +{{- if $nodepool.cfgparam }} +cfgparam: {{ $nodepool.cfgparam }} +{{- end }} +cloneFrom: {{ $nodepool.cloneFrom }} +cloudConfig: |- +{{ $nodepool.cloudConfig | indent 2 }} +cloudinit: {{ $nodepool.cloudinit }} +contentLibrary: {{ $nodepool.contentLibrary }} +cpuCount: {{ $nodepool.cpuCount | squote }} +creationType: {{ $nodepool.creationType }} +customAttribute: {{ $nodepool.customAttribute }} +datacenter: {{ $nodepool.datacenter }} +datastore: {{ $nodepool.datastore }} +datastoreCluster: {{ $nodepool.datastoreCluster }} +diskSize: {{ $nodepool.diskSize | squote }} +folder: {{ $nodepool.folder }} +hostsystem: {{ $nodepool.hostsystem }} +memorySize: {{ $nodepool.memorySize | squote }} +network: {{ $nodepool.network }} +pool: {{ $nodepool.pool }} +sshPort: {{ $nodepool.sshPort | squote }} +sshUser: {{ $nodepool.sshUser }} +sshUserGroup: {{ $nodepool.sshUserGroup }} +tag: {{ $nodepool.tag }} +vappIpallocationpolicy: {{ $nodepool.vappIpallocationpolicy }} +vappIpprotocol: {{ $nodepool.vappIpprotocol }} +vappProperty: {{ $nodepool.vappProperty }} +vappTransport: {{ $nodepool.vappTransport }} +vcenter: {{ $nodepool.vcenter }} +vcenterPort: {{ $nodepool.vcenterPort | squote }} +{{- end }} +{{- end }} diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/values.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/values.yaml new file mode 100644 index 0000000..0421ba9 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/charts/cluster-templates/values.yaml @@ -0,0 +1,433 @@ +# amazonec2, azure, digitalocean, harvester, vsphere, custom +cloudprovider: harvester + +# cloud provider credentials +cloudCredentialSecretName: cc-mrklm + +# rancher manager url +rancher: + cattle: + url: rancher-mgmt.product.lan + +# cluster values +cluster: + + name: default-cluster + # labels: + # key: value + config: + kubernetesVersion: v1.33.5+rke2r1 + enableNetworkPolicy: true + localClusterAuthEndpoint: + enabled: false + + # Pod Security Standard (Replaces PSP) + defaultPodSecurityAdmissionConfigurationTemplateName: "rancher-restricted" + + globalConfig: + systemDefaultRegistry: docker.io + cni: canal + docker: false + disable_scheduler: false + disable_cloud_controller: false + disable_kube_proxy: false + etcd_expose_metrics: false + profile: 'cis' + selinux: false + secrets_encryption: true + write_kubeconfig_mode: 0600 + use_service_account_credentials: false + protect_kernel_defaults: true + + kube_apiserver_arg: + - "service-account-extend-token-expiration=false" + - "anonymous-auth=false" + - "enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit,DenyServiceExternalIPs" + - "admission-control-config-file=/etc/rancher/rke2/rke2-admission.yaml" + - "audit-policy-file=/etc/rancher/rke2/audit-policy.yaml" + - "audit-log-path=/var/lib/rancher/rke2/server/logs/audit.log" + - "audit-log-maxage=30" + - "audit-log-maxbackup=10" + - "audit-log-maxsize=100" + + kubelet_arg: + # Strong Ciphers (CIS 4.2.12) + - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + # PID Limit (CIS 4.2.13) + - "pod-max-pids=4096" + # Seccomp Default (CIS 4.2.14) + - "seccomp-default=true" + - "protect-kernel-defaults=true" + - "make-iptables-util-chains=true" + + upgradeStrategy: + controlPlaneConcurrency: 10% + controlPlaneDrainOptions: + enabled: false + workerConcurrency: 10% + workerDrainOptions: + enabled: false + +# node and nodepool(s) values +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + cpuCount: 4 + diskSize: 40 + imageName: vanderlande/image-qhtpc + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + + # --------------------------------------------------------- + # Cloud-Init: Creates the Security Files + # --------------------------------------------------------- + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + - curl + - wget + + bootcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - sysctl -w net.ipv6.conf.default.disable_ipv6=1 + + write_files: + # ---------------------------------------------------------------- + # 1. CNI Permission Fix Script & Cron (CIS 1.1.9 Persistence) + # ---------------------------------------------------------------- + - path: /usr/local/bin/fix-cni-perms.sh + permissions: '0700' + owner: root:root + content: | + #!/bin/bash + # Wait 60s on boot for RKE2 to write files + [ "$1" == "boot" ] && sleep 60 + + # Enforce 600 on CNI files (CIS 1.1.9) + if [ -d /etc/cni/net.d ]; then + find /etc/cni/net.d -type f -exec chmod 600 {} \; + fi + if [ -d /var/lib/cni/networks ]; then + find /var/lib/cni/networks -type f -exec chmod 600 {} \; + fi + + # Every RKE2 service restart can reset CNI file permissions, so we run + # this script on reboot and daily via cron to maintain CIS compliance. + + - path: /etc/cron.d/cis-cni-fix + permissions: '0644' + owner: root:root + content: | + # Run on Reboot (with delay) to fix files created during startup + @reboot root /usr/local/bin/fix-cni-perms.sh boot + # Run once daily at 00:00 to correct any drift + 0 0 * * * root /usr/local/bin/fix-cni-perms.sh + + # ---------------------------------------------------------------- + # 2. RKE2 Admission Config + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/rke2-admission.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: apiserver.config.k8s.io/v1 + kind: AdmissionConfiguration + plugins: + - name: PodSecurity + configuration: + apiVersion: pod-security.admission.config.k8s.io/v1beta1 + kind: PodSecurityConfiguration + defaults: + enforce: "restricted" + enforce-version: "latest" + audit: "restricted" + audit-version: "latest" + warn: "restricted" + warn-version: "latest" + exemptions: + usernames: [] + runtimeClasses: [] + namespaces: [compliance-operator-system,kube-system, cis-operator-system, tigera-operator, calico-system, rke2-ingress-nginx, cattle-system, cattle-fleet-system, longhorn-system, cattle-neuvector-system] + - name: EventRateLimit + configuration: + apiVersion: eventratelimit.admission.k8s.io/v1alpha1 + kind: Configuration + limits: + - type: Server + qps: 5000 + burst: 20000 + + # ---------------------------------------------------------------- + # 3. RKE2 Audit Policy + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/audit-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: audit.k8s.io/v1 + kind: Policy + rules: + - level: None + users: ["system:kube-controller-manager", "system:kube-scheduler", "system:serviceaccount:kube-system:endpoint-controller"] + verbs: ["get", "update"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status"] + - level: None + verbs: ["get"] + resources: + - group: "" + resources: ["nodes", "nodes/status", "pods", "pods/status"] + - level: None + users: ["kube-proxy"] + verbs: ["watch"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status", "configmaps"] + - level: Metadata + resources: + - group: "" + resources: ["secrets", "configmaps"] + - level: RequestResponse + omitStages: + - RequestReceived + + # ---------------------------------------------------------------- + # 4. Static NetworkPolicies + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-network-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: default-deny-ingress + namespace: default + spec: + podSelector: {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-metrics + namespace: kube-public + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-system + namespace: kube-system + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + + # ---------------------------------------------------------------- + # 5. Service Account Hardening + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-config.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: default + automountServiceAccountToken: false + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: kube-system + automountServiceAccountToken: false + + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-cron.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: {name: sa-cleaner, namespace: kube-system} + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: {name: sa-cleaner-role} + rules: + - apiGroups: [""] + resources: ["namespaces", "serviceaccounts"] + verbs: ["get", "list", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: {name: sa-cleaner-binding} + subjects: [{kind: ServiceAccount, name: sa-cleaner, namespace: kube-system}] + roleRef: {kind: ClusterRole, name: sa-cleaner-role, apiGroup: rbac.authorization.k8s.io} + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: sa-cleaner + namespace: kube-system + spec: + schedule: "0 */6 * * *" # Run every 6 hours + jobTemplate: + spec: + template: + spec: + serviceAccountName: sa-cleaner + containers: + - name: cleaner + image: rancher/kubectl:v1.26.0 + command: + - /bin/bash + - -c + - | + # Get all namespaces + for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do + # Check if default SA has automount=true (or null) + automount=$(kubectl get sa default -n $ns -o jsonpath='{.automountServiceAccountToken}') + if [ "$automount" != "false" ]; then + echo "Securing default SA in namespace: $ns" + kubectl patch sa default -n $ns -p '{"automountServiceAccountToken": false}' + fi + done + restartPolicy: OnFailure + + # ---------------------------------------------------------------- + # 6. OS Sysctls Hardening + # ---------------------------------------------------------------- + - path: /etc/sysctl.d/60-rke2-cis.conf + permissions: '0644' + content: | + vm.overcommit_memory=1 + vm.max_map_count=65530 + vm.panic_on_oom=0 + fs.inotify.max_user_watches=1048576 + fs.inotify.max_user_instances=8192 + kernel.panic=10 + kernel.panic_on_oops=1 + net.ipv4.conf.all.rp_filter=1 + net.ipv4.conf.default.rp_filter=1 + net.ipv4.conf.all.accept_source_route=0 + net.ipv4.conf.default.accept_source_route=0 + net.ipv4.conf.all.accept_redirects=0 + net.ipv4.conf.default.accept_redirects=0 + net.ipv4.conf.all.send_redirects=0 + net.ipv4.conf.default.send_redirects=0 + net.ipv4.conf.all.log_martians=1 + net.ipv4.conf.default.log_martians=1 + net.ipv4.icmp_echo_ignore_broadcasts=1 + net.ipv4.icmp_ignore_bogus_error_responses=1 + net.ipv6.conf.all.disable_ipv6=1 + net.ipv6.conf.default.disable_ipv6=1 + fs.protected_hardlinks=1 + fs.protected_symlinks=1 + + # ---------------------------------------------------------------- + # 7. Environment & Setup Scripts + # ---------------------------------------------------------------- + - path: /etc/profile.d/rke2.sh + permissions: '0644' + content: | + export PATH=$PATH:/var/lib/rancher/rke2/bin:/opt/rke2/bin + export KUBECONFIG=/etc/rancher/rke2/rke2.yaml + + + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + - name: etcd + gecos: "etcd user" + shell: /sbin/nologin + system: true + lock_passwd: true + + disable_root: true + ssh_pwauth: true + + runcmd: + - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + - /usr/local/bin/fix-cni-perms.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Cluster ready for Rancher! + + - name: worker-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + cpuCount: 2 + diskSize: 40 + imageName: vanderlande/image-qmx5q + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + +addons: + monitoring: + enabled: false + logging: + enabled: false + longhorn: + enabled: false + neuvector: + enabled: false \ No newline at end of file diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/fleet.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/fleet.yaml new file mode 100644 index 0000000..6a74a12 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/fleet.yaml @@ -0,0 +1,13 @@ +# The namespace on the Management Cluster where the "Cluster" CRD will be created. +# You specified 'fleet-local', which is valid for admin-level operations, +# though 'fleet-default' is also common for downstream clusters. +namespace: fleet-local + +# Reference the external rancher-federal helm chart +helm: + chart: ./charts/cluster-templates + # Replace with the specific version you wish to pin (highly recommended) + releaseName: tpinf-1345-test-01 + version: 0.7.2 + valuesFiles: + - values.yaml diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/gitrepo.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/gitrepo.yaml new file mode 100644 index 0000000..857fa71 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/gitrepo.yaml @@ -0,0 +1,21 @@ +apiVersion: fleet.cattle.io/v1alpha1 +kind: GitRepo +metadata: + labels: + name: tpinf-1345 + namespace: fleet-local + resourceVersion: '27617825' +spec: + branch: TPINF-1345-inv-cis-hardening + clientSecretName: auth-qvn5p + correctDrift: + enabled: true + pollingInterval: 1m0s + repo: https://devstash.vanderlande.com/scm/ittp/as-vi-cnv.git + targets: + - clusterSelector: + matchExpressions: + - key: provider.cattle.io + operator: NotIn + values: + - harvester \ No newline at end of file diff --git a/deploy/iac-cnv/clusters/tpinf-1345-test-01/values.yaml b/deploy/iac-cnv/clusters/tpinf-1345-test-01/values.yaml new file mode 100644 index 0000000..b994c75 --- /dev/null +++ b/deploy/iac-cnv/clusters/tpinf-1345-test-01/values.yaml @@ -0,0 +1,365 @@ + + +# cluster values +cluster: + + name: tpinf-1345-test-01 + # labels: + # key: value + config: + kubernetesVersion: v1.33.5+rke2r1 + +# node and nodepool(s) values +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + cpuCount: 4 + diskSize: 40 + imageName: vanderlande/image-qhtpc + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + + # --------------------------------------------------------- + # Cloud-Init: Creates the Security Files + # --------------------------------------------------------- + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + - curl + - wget + + bootcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - sysctl -w net.ipv6.conf.default.disable_ipv6=1 + + write_files: + # ---------------------------------------------------------------- + # 1. CNI Permission Fix Script & Cron (CIS 1.1.9 Persistence) + # ---------------------------------------------------------------- + - path: /usr/local/bin/fix-cni-perms.sh + permissions: '0700' + owner: root:root + content: | + #!/bin/bash + # Wait 60s on boot for RKE2 to write files + [ "$1" == "boot" ] && sleep 60 + + # Enforce 600 on CNI files (CIS 1.1.9) + if [ -d /etc/cni/net.d ]; then + find /etc/cni/net.d -type f -exec chmod 600 {} \; + fi + if [ -d /var/lib/cni/networks ]; then + find /var/lib/cni/networks -type f -exec chmod 600 {} \; + fi + + # Every RKE2 service restart can reset CNI file permissions, so we run + # this script on reboot and daily via cron to maintain CIS compliance. + + - path: /etc/cron.d/cis-cni-fix + permissions: '0644' + owner: root:root + content: | + # Run on Reboot (with delay) to fix files created during startup + @reboot root /usr/local/bin/fix-cni-perms.sh boot + # Run once daily at 00:00 to correct any drift + 0 0 * * * root /usr/local/bin/fix-cni-perms.sh + + # ---------------------------------------------------------------- + # 2. RKE2 Admission Config + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/rke2-admission.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: apiserver.config.k8s.io/v1 + kind: AdmissionConfiguration + plugins: + - name: PodSecurity + configuration: + apiVersion: pod-security.admission.config.k8s.io/v1beta1 + kind: PodSecurityConfiguration + defaults: + enforce: "restricted" + enforce-version: "latest" + audit: "restricted" + audit-version: "latest" + warn: "restricted" + warn-version: "latest" + exemptions: + usernames: [] + runtimeClasses: [] + namespaces: [compliance-operator-system,kube-system, cis-operator-system, tigera-operator, calico-system, rke2-ingress-nginx, cattle-system, cattle-fleet-system, longhorn-system, cattle-neuvector-system] + - name: EventRateLimit + configuration: + apiVersion: eventratelimit.admission.k8s.io/v1alpha1 + kind: Configuration + limits: + - type: Server + qps: 5000 + burst: 20000 + + # ---------------------------------------------------------------- + # 3. RKE2 Audit Policy + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/audit-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: audit.k8s.io/v1 + kind: Policy + rules: + - level: None + users: ["system:kube-controller-manager", "system:kube-scheduler", "system:serviceaccount:kube-system:endpoint-controller"] + verbs: ["get", "update"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status"] + - level: None + verbs: ["get"] + resources: + - group: "" + resources: ["nodes", "nodes/status", "pods", "pods/status"] + - level: None + users: ["kube-proxy"] + verbs: ["watch"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status", "configmaps"] + - level: Metadata + resources: + - group: "" + resources: ["secrets", "configmaps"] + - level: RequestResponse + omitStages: + - RequestReceived + + # ---------------------------------------------------------------- + # 4. Static NetworkPolicies + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-network-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: default-deny-ingress + namespace: default + spec: + podSelector: {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-metrics + namespace: kube-public + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-system + namespace: kube-system + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + + # ---------------------------------------------------------------- + # 5. Service Account Hardening + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-config.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: default + automountServiceAccountToken: false + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: kube-system + automountServiceAccountToken: false + + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-cron.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: {name: sa-cleaner, namespace: kube-system} + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: {name: sa-cleaner-role} + rules: + - apiGroups: [""] + resources: ["namespaces", "serviceaccounts"] + verbs: ["get", "list", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: {name: sa-cleaner-binding} + subjects: [{kind: ServiceAccount, name: sa-cleaner, namespace: kube-system}] + roleRef: {kind: ClusterRole, name: sa-cleaner-role, apiGroup: rbac.authorization.k8s.io} + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: sa-cleaner + namespace: kube-system + spec: + schedule: "0 */6 * * *" # Run every 6 hours + jobTemplate: + spec: + template: + spec: + serviceAccountName: sa-cleaner + containers: + - name: cleaner + image: rancher/kubectl:v1.26.0 + command: + - /bin/bash + - -c + - | + # Get all namespaces + for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do + # Check if default SA has automount=true (or null) + automount=$(kubectl get sa default -n $ns -o jsonpath='{.automountServiceAccountToken}') + if [ "$automount" != "false" ]; then + echo "Securing default SA in namespace: $ns" + kubectl patch sa default -n $ns -p '{"automountServiceAccountToken": false}' + fi + done + restartPolicy: OnFailure + + # ---------------------------------------------------------------- + # 6. OS Sysctls Hardening + # ---------------------------------------------------------------- + - path: /etc/sysctl.d/60-rke2-cis.conf + permissions: '0644' + content: | + vm.overcommit_memory=1 + vm.max_map_count=65530 + vm.panic_on_oom=0 + fs.inotify.max_user_watches=1048576 + fs.inotify.max_user_instances=8192 + kernel.panic=10 + kernel.panic_on_oops=1 + net.ipv4.conf.all.rp_filter=1 + net.ipv4.conf.default.rp_filter=1 + net.ipv4.conf.all.accept_source_route=0 + net.ipv4.conf.default.accept_source_route=0 + net.ipv4.conf.all.accept_redirects=0 + net.ipv4.conf.default.accept_redirects=0 + net.ipv4.conf.all.send_redirects=0 + net.ipv4.conf.default.send_redirects=0 + net.ipv4.conf.all.log_martians=1 + net.ipv4.conf.default.log_martians=1 + net.ipv4.icmp_echo_ignore_broadcasts=1 + net.ipv4.icmp_ignore_bogus_error_responses=1 + net.ipv6.conf.all.disable_ipv6=1 + net.ipv6.conf.default.disable_ipv6=1 + fs.protected_hardlinks=1 + fs.protected_symlinks=1 + + # ---------------------------------------------------------------- + # 7. Environment & Setup Scripts + # ---------------------------------------------------------------- + - path: /etc/profile.d/rke2.sh + permissions: '0644' + content: | + export PATH=$PATH:/var/lib/rancher/rke2/bin:/opt/rke2/bin + export KUBECONFIG=/etc/rancher/rke2/rke2.yaml + + + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + - name: etcd + gecos: "etcd user" + shell: /sbin/nologin + system: true + lock_passwd: true + + disable_root: true + ssh_pwauth: true + + runcmd: + - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + - /usr/local/bin/fix-cni-perms.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Cluster ready for Rancher! + + - name: worker-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + cpuCount: 2 + diskSize: 40 + imageName: vanderlande/image-qmx5q + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + diff --git a/deploy/k8s-provisioner/.devcontainer/devcontainer.json b/deploy/k8s-provisioner/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a3ab754 --- /dev/null +++ b/deploy/k8s-provisioner/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Kubebuilder DevContainer", + "image": "golang:1.24", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/git:1": {} + }, + + "runArgs": ["--network=host"], + + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "ms-kubernetes-tools.vscode-kubernetes-tools", + "ms-azuretools.vscode-docker" + ] + } + }, + + "onCreateCommand": "bash .devcontainer/post-install.sh" +} + diff --git a/deploy/k8s-provisioner/.devcontainer/post-install.sh b/deploy/k8s-provisioner/.devcontainer/post-install.sh new file mode 100644 index 0000000..67f3e97 --- /dev/null +++ b/deploy/k8s-provisioner/.devcontainer/post-install.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -x + +curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-$(go env GOARCH) +chmod +x ./kind +mv ./kind /usr/local/bin/kind + +curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/$(go env GOARCH) +chmod +x kubebuilder +mv kubebuilder /usr/local/bin/ + +KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt) +curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/$(go env GOARCH)/kubectl" +chmod +x kubectl +mv kubectl /usr/local/bin/kubectl + +docker network create -d=bridge --subnet=172.19.0.0/24 kind + +kind version +kubebuilder version +docker --version +go version +kubectl version --client diff --git a/deploy/k8s-provisioner/.dockerignore b/deploy/k8s-provisioner/.dockerignore new file mode 100644 index 0000000..9af8280 --- /dev/null +++ b/deploy/k8s-provisioner/.dockerignore @@ -0,0 +1,11 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore everything by default and re-include only needed files +** + +# Re-include Go source files (but not *_test.go) +!**/*.go +**/*_test.go + +# Re-include Go module files +!go.mod +!go.sum diff --git a/deploy/k8s-provisioner/.github/workflows/lint.yml b/deploy/k8s-provisioner/.github/workflows/lint.yml new file mode 100644 index 0000000..4838c54 --- /dev/null +++ b/deploy/k8s-provisioner/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Run linter + uses: golangci/golangci-lint-action@v8 + with: + version: v2.5.0 diff --git a/deploy/k8s-provisioner/.github/workflows/test-e2e.yml b/deploy/k8s-provisioner/.github/workflows/test-e2e.yml new file mode 100644 index 0000000..4cdfb30 --- /dev/null +++ b/deploy/k8s-provisioner/.github/workflows/test-e2e.yml @@ -0,0 +1,32 @@ +name: E2E Tests + +on: + push: + pull_request: + +jobs: + test-e2e: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install the latest version of kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-$(go env GOARCH) + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + - name: Verify kind installation + run: kind version + + - name: Running Test e2e + run: | + go mod tidy + make test-e2e diff --git a/deploy/k8s-provisioner/.github/workflows/test.yml b/deploy/k8s-provisioner/.github/workflows/test.yml new file mode 100644 index 0000000..fc2e80d --- /dev/null +++ b/deploy/k8s-provisioner/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + test: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Running Tests + run: | + go mod tidy + make test diff --git a/deploy/k8s-provisioner/.gitignore b/deploy/k8s-provisioner/.gitignore new file mode 100644 index 0000000..9f0f3a1 --- /dev/null +++ b/deploy/k8s-provisioner/.gitignore @@ -0,0 +1,30 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ + +# Kubeconfig might contain secrets +*.kubeconfig diff --git a/deploy/k8s-provisioner/.golangci.yml b/deploy/k8s-provisioner/.golangci.yml new file mode 100644 index 0000000..e5b21b0 --- /dev/null +++ b/deploy/k8s-provisioner/.golangci.yml @@ -0,0 +1,52 @@ +version: "2" +run: + allow-parallel-runners: true +linters: + default: none + enable: + - copyloopvar + - dupl + - errcheck + - ginkgolinter + - goconst + - gocyclo + - govet + - ineffassign + - lll + - misspell + - nakedret + - prealloc + - revive + - staticcheck + - unconvert + - unparam + - unused + settings: + revive: + rules: + - name: comment-spacings + - name: import-shadowing + exclusions: + generated: lax + rules: + - linters: + - lll + path: api/* + - linters: + - dupl + - lll + path: internal/* + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/deploy/k8s-provisioner/Dockerfile b/deploy/k8s-provisioner/Dockerfile new file mode 100644 index 0000000..6466c48 --- /dev/null +++ b/deploy/k8s-provisioner/Dockerfile @@ -0,0 +1,31 @@ +# Build the manager binary +FROM golang:1.24 AS builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the Go source (relies on .dockerignore to filter) +COPY . . + +# Build +# the GOARCH has no default value to allow the binary to be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER 65532:65532 + +ENTRYPOINT ["/manager"] diff --git a/deploy/k8s-provisioner/Makefile b/deploy/k8s-provisioner/Makefile new file mode 100644 index 0000000..ec532ca --- /dev/null +++ b/deploy/k8s-provisioner/Makefile @@ -0,0 +1,250 @@ +# Image URL to use all building/pushing image targets +IMG ?= controller:latest + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk command is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Development + +.PHONY: manifests +manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. + "$(CONTROLLER_GEN)" rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + "$(CONTROLLER_GEN)" object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: manifests generate fmt vet setup-envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell "$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out + +# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'. +# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. +# CertManager is installed by default; skip with: +# - CERT_MANAGER_INSTALL_SKIP=true +KIND_CLUSTER ?= k8s-provisioner-test-e2e + +.PHONY: setup-test-e2e +setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist + @command -v $(KIND) >/dev/null 2>&1 || { \ + echo "Kind is not installed. Please install Kind manually."; \ + exit 1; \ + } + @case "$$($(KIND) get clusters)" in \ + *"$(KIND_CLUSTER)"*) \ + echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \ + *) \ + echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \ + $(KIND) create cluster --name $(KIND_CLUSTER) ;; \ + esac + +.PHONY: test-e2e +test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. + KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v + $(MAKE) cleanup-test-e2e + +.PHONY: cleanup-test-e2e +cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests + @$(KIND) delete cluster --name $(KIND_CLUSTER) + +.PHONY: lint +lint: golangci-lint ## Run golangci-lint linter + "$(GOLANGCI_LINT)" run + +.PHONY: lint-fix +lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes + "$(GOLANGCI_LINT)" run --fix + +.PHONY: lint-config +lint-config: golangci-lint ## Verify golangci-lint linter configuration + "$(GOLANGCI_LINT)" config verify + +##@ Build + +.PHONY: build +build: manifests generate fmt vet ## Build manager binary. + go build -o bin/manager cmd/main.go + +.PHONY: run +run: manifests generate fmt vet ## Run a controller from your host. + go run ./cmd/main.go + +# If you wish to build the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: ## Build docker image with the manager. + $(CONTAINER_TOOL) build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + $(CONTAINER_TOOL) push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/ +# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=> then the export will fail) +# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build and push docker image for the manager for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - $(CONTAINER_TOOL) buildx create --name k8s-provisioner-builder + $(CONTAINER_TOOL) buildx use k8s-provisioner-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm k8s-provisioner-builder + rm Dockerfile.cross + +.PHONY: build-installer +build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. + mkdir -p dist + cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG} + "$(KUSTOMIZE)" build config/default > dist/install.yaml + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \ + if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" apply -f -; else echo "No CRDs to install; skipping."; fi + +.PHONY: uninstall +uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \ + if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -; else echo "No CRDs to delete; skipping."; fi + +.PHONY: deploy +deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG} + "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" apply -f - + +.PHONY: undeploy +undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f - + +##@ Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p "$(LOCALBIN)" + +## Tool Binaries +KUBECTL ?= kubectl +KIND ?= kind +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint + +## Tool Versions +KUSTOMIZE_VERSION ?= v5.7.1 +CONTROLLER_TOOLS_VERSION ?= v0.19.0 + +#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20) +ENVTEST_VERSION ?= $(shell v='$(call gomodver,sigs.k8s.io/controller-runtime)'; \ + [ -n "$$v" ] || { echo "Set ENVTEST_VERSION manually (controller-runtime replace has no tag)" >&2; exit 1; }; \ + printf '%s\n' "$$v" | sed -E 's/^v?([0-9]+)\.([0-9]+).*/release-\1.\2/') + +#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) +ENVTEST_K8S_VERSION ?= $(shell v='$(call gomodver,k8s.io/api)'; \ + [ -n "$$v" ] || { echo "Set ENVTEST_K8S_VERSION manually (k8s.io/api replace has no tag)" >&2; exit 1; }; \ + printf '%s\n' "$$v" | sed -E 's/^v?[0-9]+\.([0-9]+).*/1.\1/') + +GOLANGCI_LINT_VERSION ?= v2.5.0 +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. +$(KUSTOMIZE): $(LOCALBIN) + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. +$(CONTROLLER_GEN): $(LOCALBIN) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) + +.PHONY: setup-envtest +setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory. + @echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..." + @"$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path || { \ + echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \ + exit 1; \ + } + +.PHONY: envtest +envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. +$(ENVTEST): $(LOCALBIN) + $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) + +.PHONY: golangci-lint +golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. +$(GOLANGCI_LINT): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f "$(1)-$(3)" ] && [ "$$(readlink -- "$(1)" 2>/dev/null)" = "$(1)-$(3)" ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +rm -f "$(1)" ;\ +GOBIN="$(LOCALBIN)" go install $${package} ;\ +mv "$(LOCALBIN)/$$(basename "$(1)")" "$(1)-$(3)" ;\ +} ;\ +ln -sf "$$(realpath "$(1)-$(3)")" "$(1)" +endef + +define gomodver +$(shell go list -m -f '{{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}' $(1) 2>/dev/null) +endef diff --git a/deploy/k8s-provisioner/PROJECT b/deploy/k8s-provisioner/PROJECT new file mode 100644 index 0000000..9bc8651 --- /dev/null +++ b/deploy/k8s-provisioner/PROJECT @@ -0,0 +1,29 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html +cliVersion: 4.10.1 +domain: appstack.io +layout: +- go.kubebuilder.io/v4 +projectName: k8s-provisioner +repo: vanderlande.com/appstack/k8s-provisioner +resources: +- api: + crdVersion: v1 + namespaced: true + domain: appstack.io + group: k8sprovisioner + kind: Infra + path: vanderlande.com/appstack/k8s-provisioner/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: appstack.io + group: k8sprovisioner + kind: Cluster + path: vanderlande.com/appstack/k8s-provisioner/api/v1alpha1 + version: v1alpha1 +version: "3" diff --git a/deploy/k8s-provisioner/README.md b/deploy/k8s-provisioner/README.md new file mode 100644 index 0000000..1b242af --- /dev/null +++ b/deploy/k8s-provisioner/README.md @@ -0,0 +1,135 @@ +# k8s-provisioner +// TODO(user): Add simple overview of use/purpose + +## Description +// TODO(user): An in-depth paragraph about your project and overview of use + +## Getting Started + +### Prerequisites +- go version v1.24.6+ +- docker version 17.03+. +- kubectl version v1.11.3+. +- Access to a Kubernetes v1.11.3+ cluster. + +### To Deploy on the cluster +**Build and push your image to the location specified by `IMG`:** + +```sh +make docker-build docker-push IMG=/k8s-provisioner:tag +``` + +**NOTE:** This image ought to be published in the personal registry you specified. +And it is required to have access to pull the image from the working environment. +Make sure you have the proper permission to the registry if the above commands don’t work. + +**Install the CRDs into the cluster:** + +```sh +make install +``` + +**Deploy the Manager to the cluster with the image specified by `IMG`:** + +```sh +make deploy IMG=/k8s-provisioner:tag +``` + +> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin +privileges or be logged in as admin. + +**Create instances of your solution** +You can apply the samples (examples) from the config/sample: + +```sh +kubectl apply -k config/samples/ +``` + +>**NOTE**: Ensure that the samples has default values to test it out. + +### To Uninstall +**Delete the instances (CRs) from the cluster:** + +```sh +kubectl delete -k config/samples/ +``` + +**Delete the APIs(CRDs) from the cluster:** + +```sh +make uninstall +``` + +**UnDeploy the controller from the cluster:** + +```sh +make undeploy +``` + +## Project Distribution + +Following the options to release and provide this solution to the users. + +### By providing a bundle with all YAML files + +1. Build the installer for the image built and published in the registry: + +```sh +make build-installer IMG=/k8s-provisioner:tag +``` + +**NOTE:** The makefile target mentioned above generates an 'install.yaml' +file in the dist directory. This file contains all the resources built +with Kustomize, which are necessary to install this project without its +dependencies. + +2. Using the installer + +Users can just run 'kubectl apply -f ' to install +the project, i.e.: + +```sh +kubectl apply -f https://raw.githubusercontent.com//k8s-provisioner//dist/install.yaml +``` + +### By providing a Helm Chart + +1. Build the chart using the optional helm plugin + +```sh +kubebuilder edit --plugins=helm/v2-alpha +``` + +2. See that a chart was generated under 'dist/chart', and users +can obtain this solution from there. + +**NOTE:** If you change the project, you need to update the Helm Chart +using the same command above to sync the latest changes. Furthermore, +if you create webhooks, you need to use the above command with +the '--force' flag and manually ensure that any custom configuration +previously added to 'dist/chart/values.yaml' or 'dist/chart/manager/manager.yaml' +is manually re-applied afterwards. + +## Contributing +// TODO(user): Add detailed information on how you would like others to contribute to this project + +**NOTE:** Run `make help` for more information on all potential `make` targets + +More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) + +## License + +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/deploy/k8s-provisioner/api/v1alpha1/cluster_types.go b/deploy/k8s-provisioner/api/v1alpha1/cluster_types.go new file mode 100644 index 0000000..fe63d0e --- /dev/null +++ b/deploy/k8s-provisioner/api/v1alpha1/cluster_types.go @@ -0,0 +1,56 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ClusterSpec struct { + InfraRef string `json:"infraRef"` + KubernetesVersion string `json:"kubernetesVersion"` + ControlPlaneHA bool `json:"controlPlaneHA"` + WorkerPools []WorkerPoolRequest `json:"workerPools"` +} + +type WorkerPoolRequest struct { + Name string `json:"name"` + Quantity int `json:"quantity"` + CpuCores int `json:"cpuCores"` + MemoryGB int `json:"memoryGb"` + DiskGB int `json:"diskGb"` +} + +// [NEW] Struct to track the Harvester Identity +type HarvesterAccountStatus struct { + // The ServiceAccount created on Harvester (e.g. "prov-test-cluster-01") + ServiceAccountName string `json:"serviceAccountName,omitempty"` + // The Secret created in this namespace (e.g. "harvesterconfig-test-cluster-01") + SecretRef string `json:"secretRef,omitempty"` + // Expiry for future rotation logic + TokenExpiresAt *metav1.Time `json:"tokenExpiresAt,omitempty"` +} + +type ClusterStatus struct { + Ready bool `json:"ready"` + // +optional + GeneratedAccount *HarvesterAccountStatus `json:"generatedAccount,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type Cluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec ClusterSpec `json:"spec,omitempty"` + Status ClusterStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type ClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Cluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Cluster{}, &ClusterList{}) +} diff --git a/deploy/k8s-provisioner/api/v1alpha1/groupversion_info.go b/deploy/k8s-provisioner/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..c687da4 --- /dev/null +++ b/deploy/k8s-provisioner/api/v1alpha1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the k8sprovisioner v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=k8sprovisioner.appstack.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "k8sprovisioner.appstack.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/deploy/k8s-provisioner/api/v1alpha1/infra_types.go b/deploy/k8s-provisioner/api/v1alpha1/infra_types.go new file mode 100644 index 0000000..c40f37c --- /dev/null +++ b/deploy/k8s-provisioner/api/v1alpha1/infra_types.go @@ -0,0 +1,50 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type InfraSpec struct { + // 1. Rancher/Cloud Settings + // The "Master" credential name in cattle-global-data + // +required + CloudCredentialSecret string `json:"cloudCredentialSecret"` + RancherURL string `json:"rancherUrl"` + // This removes the need for auto-discovery. + HarvesterURL string `json:"harvesterUrl"` + // 2. Environment Defaults + VmNamespace string `json:"vmNamespace"` + ImageName string `json:"imageName"` + NetworkName string `json:"networkName"` + SshUser string `json:"sshUser"` + + // 3. Governance Configs + // +kubebuilder:validation:Optional + RKE2ConfigYAML string `json:"rke2ConfigYaml"` + // +kubebuilder:validation:Optional + UserData string `json:"userData"` +} + +type InfraStatus struct { + Ready bool `json:"ready"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type Infra struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec InfraSpec `json:"spec,omitempty"` + Status InfraStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type InfraList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Infra `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Infra{}, &InfraList{}) +} diff --git a/deploy/k8s-provisioner/api/v1alpha1/zz_generated.deepcopy.go b/deploy/k8s-provisioner/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..a5ea856 --- /dev/null +++ b/deploy/k8s-provisioner/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,247 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Cluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterList) DeepCopyInto(out *ClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Cluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList. +func (in *ClusterList) DeepCopy() *ClusterList { + if in == nil { + return nil + } + out := new(ClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { + *out = *in + if in.WorkerPools != nil { + in, out := &in.WorkerPools, &out.WorkerPools + *out = make([]WorkerPoolRequest, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. +func (in *ClusterSpec) DeepCopy() *ClusterSpec { + if in == nil { + return nil + } + out := new(ClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { + *out = *in + if in.GeneratedAccount != nil { + in, out := &in.GeneratedAccount, &out.GeneratedAccount + *out = new(HarvesterAccountStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. +func (in *ClusterStatus) DeepCopy() *ClusterStatus { + if in == nil { + return nil + } + out := new(ClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HarvesterAccountStatus) DeepCopyInto(out *HarvesterAccountStatus) { + *out = *in + if in.TokenExpiresAt != nil { + in, out := &in.TokenExpiresAt, &out.TokenExpiresAt + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HarvesterAccountStatus. +func (in *HarvesterAccountStatus) DeepCopy() *HarvesterAccountStatus { + if in == nil { + return nil + } + out := new(HarvesterAccountStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Infra) DeepCopyInto(out *Infra) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Infra. +func (in *Infra) DeepCopy() *Infra { + if in == nil { + return nil + } + out := new(Infra) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Infra) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraList) DeepCopyInto(out *InfraList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Infra, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraList. +func (in *InfraList) DeepCopy() *InfraList { + if in == nil { + return nil + } + out := new(InfraList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InfraList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraSpec) DeepCopyInto(out *InfraSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraSpec. +func (in *InfraSpec) DeepCopy() *InfraSpec { + if in == nil { + return nil + } + out := new(InfraSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraStatus) DeepCopyInto(out *InfraStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraStatus. +func (in *InfraStatus) DeepCopy() *InfraStatus { + if in == nil { + return nil + } + out := new(InfraStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkerPoolRequest) DeepCopyInto(out *WorkerPoolRequest) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkerPoolRequest. +func (in *WorkerPoolRequest) DeepCopy() *WorkerPoolRequest { + if in == nil { + return nil + } + out := new(WorkerPoolRequest) + in.DeepCopyInto(out) + return out +} diff --git a/deploy/k8s-provisioner/cmd/main.go b/deploy/k8s-provisioner/cmd/main.go new file mode 100644 index 0000000..e15c17a --- /dev/null +++ b/deploy/k8s-provisioner/cmd/main.go @@ -0,0 +1,204 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + k8sprovisionerv1alpha1 "vanderlande.com/appstack/k8s-provisioner/api/v1alpha1" + "vanderlande.com/appstack/k8s-provisioner/internal/controller" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(k8sprovisionerv1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +// nolint:gocyclo +func main() { + var metricsAddr string + var metricsCertPath, metricsCertName, metricsCertKey string + var webhookCertPath, webhookCertName, webhookCertKey string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.") + flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.") + flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.") + flag.StringVar(&metricsCertPath, "metrics-cert-path", "", + "The directory that contains the metrics server certificate.") + flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") + flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + // Initial webhook TLS options + webhookTLSOpts := tlsOpts + webhookServerOptions := webhook.Options{ + TLSOpts: webhookTLSOpts, + } + + if len(webhookCertPath) > 0 { + setupLog.Info("Initializing webhook certificate watcher using provided certificates", + "webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey) + + webhookServerOptions.CertDir = webhookCertPath + webhookServerOptions.CertName = webhookCertName + webhookServerOptions.KeyName = webhookCertKey + } + + webhookServer := webhook.NewServer(webhookServerOptions) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.4/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.4/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + } + + // If the certificate is not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + // + // TODO(user): If you enable certManager, uncomment the following lines: + // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates + // managed by cert-manager for the metrics server. + // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification. + if len(metricsCertPath) > 0 { + setupLog.Info("Initializing metrics certificate watcher using provided certificates", + "metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey) + + metricsServerOptions.CertDir = metricsCertPath + metricsServerOptions.CertName = metricsCertName + metricsServerOptions.KeyName = metricsCertKey + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "8a5a6d0a.appstack.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err := (&controller.ClusterReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Cluster") + os.Exit(1) + } + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_clusters.yaml b/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_clusters.yaml new file mode 100644 index 0000000..376feda --- /dev/null +++ b/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_clusters.yaml @@ -0,0 +1,98 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: clusters.k8sprovisioner.appstack.io +spec: + group: k8sprovisioner.appstack.io + names: + kind: Cluster + listKind: ClusterList + plural: clusters + singular: cluster + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + controlPlaneHA: + type: boolean + infraRef: + type: string + kubernetesVersion: + type: string + workerPools: + items: + properties: + cpuCores: + type: integer + diskGb: + type: integer + memoryGb: + type: integer + name: + type: string + quantity: + type: integer + required: + - cpuCores + - diskGb + - memoryGb + - name + - quantity + type: object + type: array + required: + - controlPlaneHA + - infraRef + - kubernetesVersion + - workerPools + type: object + status: + properties: + generatedAccount: + description: '[NEW] Struct to track the Harvester Identity' + properties: + secretRef: + description: The Secret created in this namespace (e.g. "harvesterconfig-test-cluster-01") + type: string + serviceAccountName: + description: The ServiceAccount created on Harvester (e.g. "prov-test-cluster-01") + type: string + tokenExpiresAt: + description: Expiry for future rotation logic + format: date-time + type: string + type: object + ready: + type: boolean + required: + - ready + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_infras.yaml b/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_infras.yaml new file mode 100644 index 0000000..2812b73 --- /dev/null +++ b/deploy/k8s-provisioner/config/crd/bases/k8sprovisioner.appstack.io_infras.yaml @@ -0,0 +1,84 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: infras.k8sprovisioner.appstack.io +spec: + group: k8sprovisioner.appstack.io + names: + kind: Infra + listKind: InfraList + plural: infras + singular: infra + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + cloudCredentialSecret: + description: |- + 1. Rancher/Cloud Settings + The "Master" credential name in cattle-global-data + type: string + harvesterUrl: + description: This removes the need for auto-discovery. + type: string + imageName: + type: string + networkName: + type: string + rancherUrl: + type: string + rke2ConfigYaml: + description: 3. Governance Configs + type: string + sshUser: + type: string + userData: + type: string + vmNamespace: + description: 2. Environment Defaults + type: string + required: + - cloudCredentialSecret + - harvesterUrl + - imageName + - networkName + - rancherUrl + - sshUser + - vmNamespace + type: object + status: + properties: + ready: + type: boolean + required: + - ready + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/k8s-provisioner/config/crd/kustomization.yaml b/deploy/k8s-provisioner/config/crd/kustomization.yaml new file mode 100644 index 0000000..c682f6d --- /dev/null +++ b/deploy/k8s-provisioner/config/crd/kustomization.yaml @@ -0,0 +1,17 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/k8sprovisioner.appstack.io_infras.yaml +- bases/k8sprovisioner.appstack.io_clusters.yaml +# +kubebuilder:scaffold:crdkustomizeresource + +patches: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +# +kubebuilder:scaffold:crdkustomizewebhookpatch + +# [WEBHOOK] To enable webhook, uncomment the following section +# the following config is for teaching kustomize how to do kustomization for CRDs. +#configurations: +#- kustomizeconfig.yaml diff --git a/deploy/k8s-provisioner/config/crd/kustomizeconfig.yaml b/deploy/k8s-provisioner/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000..ec5c150 --- /dev/null +++ b/deploy/k8s-provisioner/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/deploy/k8s-provisioner/config/default/cert_metrics_manager_patch.yaml b/deploy/k8s-provisioner/config/default/cert_metrics_manager_patch.yaml new file mode 100644 index 0000000..d975015 --- /dev/null +++ b/deploy/k8s-provisioner/config/default/cert_metrics_manager_patch.yaml @@ -0,0 +1,30 @@ +# This patch adds the args, volumes, and ports to allow the manager to use the metrics-server certs. + +# Add the volumeMount for the metrics-server certs +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + mountPath: /tmp/k8s-metrics-server/metrics-certs + name: metrics-certs + readOnly: true + +# Add the --metrics-cert-path argument for the metrics server +- op: add + path: /spec/template/spec/containers/0/args/- + value: --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs + +# Add the metrics-server certs volume configuration +- op: add + path: /spec/template/spec/volumes/- + value: + name: metrics-certs + secret: + secretName: metrics-server-cert + optional: false + items: + - key: ca.crt + path: ca.crt + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key diff --git a/deploy/k8s-provisioner/config/default/kustomization.yaml b/deploy/k8s-provisioner/config/default/kustomization.yaml new file mode 100644 index 0000000..7c265f7 --- /dev/null +++ b/deploy/k8s-provisioner/config/default/kustomization.yaml @@ -0,0 +1,234 @@ +# Adds namespace to all resources. +namespace: k8s-provisioner-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: k8s-provisioner- + +# Labels to add to all resources and selectors. +#labels: +#- includeSelectors: true +# pairs: +# someName: someValue + +resources: +- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus +# [METRICS] Expose the controller manager metrics service. +- metrics_service.yaml +# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy. +# Only Pod(s) running a namespace labeled with 'metrics: enabled' will be able to gather the metrics. +# Only CR(s) which requires webhooks and are applied on namespaces labeled with 'webhooks: enabled' will +# be able to communicate with the Webhook Server. +#- ../network-policy + +# Uncomment the patches line if you enable Metrics +patches: +# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. +# More info: https://book.kubebuilder.io/reference/metrics +- path: manager_metrics_patch.yaml + target: + kind: Deployment + +# Uncomment the patches line if you enable Metrics and CertManager +# [METRICS-WITH-CERTS] To enable metrics protected with certManager, uncomment the following line. +# This patch will protect the metrics with certManager self-signed certs. +#- path: cert_metrics_manager_patch.yaml +# target: +# kind: Deployment + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- path: manager_webhook_patch.yaml +# target: +# kind: Deployment + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +# Uncomment the following replacements to add the cert-manager CA injection annotations +#replacements: +# - source: # Uncomment the following block to enable certificates for metrics +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.name +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - select: # Uncomment the following to set the Service name for TLS config in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 0 +# create: true + +# - source: +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.namespace +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true +# - select: # Uncomment the following to set the Service namespace for TLS in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have any webhook +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # Name of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - source: +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.namespace # Namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a DefaultingWebhook (--defaulting ) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a ConversionWebhook (--conversion) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionns +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionname diff --git a/deploy/k8s-provisioner/config/default/manager_metrics_patch.yaml b/deploy/k8s-provisioner/config/default/manager_metrics_patch.yaml new file mode 100644 index 0000000..2aaef65 --- /dev/null +++ b/deploy/k8s-provisioner/config/default/manager_metrics_patch.yaml @@ -0,0 +1,4 @@ +# This patch adds the args to allow exposing the metrics endpoint using HTTPS +- op: add + path: /spec/template/spec/containers/0/args/0 + value: --metrics-bind-address=:8443 diff --git a/deploy/k8s-provisioner/config/default/metrics_service.yaml b/deploy/k8s-provisioner/config/default/metrics_service.yaml new file mode 100644 index 0000000..ab1b361 --- /dev/null +++ b/deploy/k8s-provisioner/config/default/metrics_service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: 8443 + selector: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner diff --git a/deploy/k8s-provisioner/config/manager/kustomization.yaml b/deploy/k8s-provisioner/config/manager/kustomization.yaml new file mode 100644 index 0000000..5c5f0b8 --- /dev/null +++ b/deploy/k8s-provisioner/config/manager/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- manager.yaml diff --git a/deploy/k8s-provisioner/config/manager/manager.yaml b/deploy/k8s-provisioner/config/manager/manager.yaml new file mode 100644 index 0000000..6434f87 --- /dev/null +++ b/deploy/k8s-provisioner/config/manager/manager.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + spec: + # TODO(user): Uncomment the following code to configure the nodeAffinity expression + # according to the platforms which are supported by your solution. + # It is considered best practice to support multiple architectures. You can + # build your manager image using the makefile target docker-buildx. + # affinity: + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/arch + # operator: In + # values: + # - amd64 + # - arm64 + # - ppc64le + # - s390x + # - key: kubernetes.io/os + # operator: In + # values: + # - linux + securityContext: + # Projects are configured by default to adhere to the "restricted" Pod Security Standards. + # This ensures that deployments meet the highest security requirements for Kubernetes. + # For more details, see: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + - --health-probe-bind-address=:8081 + image: controller:latest + name: manager + ports: [] + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + volumeMounts: [] + volumes: [] + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/deploy/k8s-provisioner/config/network-policy/allow-metrics-traffic.yaml b/deploy/k8s-provisioner/config/network-policy/allow-metrics-traffic.yaml new file mode 100644 index 0000000..727a884 --- /dev/null +++ b/deploy/k8s-provisioner/config/network-policy/allow-metrics-traffic.yaml @@ -0,0 +1,27 @@ +# This NetworkPolicy allows ingress traffic +# with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those +# namespaces are able to gather data from the metrics endpoint. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: allow-metrics-traffic + namespace: system +spec: + podSelector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + policyTypes: + - Ingress + ingress: + # This allows ingress traffic from any namespace with the label metrics: enabled + - from: + - namespaceSelector: + matchLabels: + metrics: enabled # Only from namespaces with this label + ports: + - port: 8443 + protocol: TCP diff --git a/deploy/k8s-provisioner/config/network-policy/kustomization.yaml b/deploy/k8s-provisioner/config/network-policy/kustomization.yaml new file mode 100644 index 0000000..ec0fb5e --- /dev/null +++ b/deploy/k8s-provisioner/config/network-policy/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- allow-metrics-traffic.yaml diff --git a/deploy/k8s-provisioner/config/prometheus/kustomization.yaml b/deploy/k8s-provisioner/config/prometheus/kustomization.yaml new file mode 100644 index 0000000..fdc5481 --- /dev/null +++ b/deploy/k8s-provisioner/config/prometheus/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- monitor.yaml + +# [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus +# to securely reference certificates created and managed by cert-manager. +# Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml +# to mount the "metrics-server-cert" secret in the Manager Deployment. +#patches: +# - path: monitor_tls_patch.yaml +# target: +# kind: ServiceMonitor diff --git a/deploy/k8s-provisioner/config/prometheus/monitor.yaml b/deploy/k8s-provisioner/config/prometheus/monitor.yaml new file mode 100644 index 0000000..3dc1527 --- /dev/null +++ b/deploy/k8s-provisioner/config/prometheus/monitor.yaml @@ -0,0 +1,27 @@ +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https # Ensure this is the name of the port that exposes HTTPS metrics + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables + # certificate verification, exposing the system to potential man-in-the-middle attacks. + # For production environments, it is recommended to use cert-manager for automatic TLS certificate management. + # To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml, + # which securely references the certificate from the 'metrics-server-cert' secret. + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: k8s-provisioner diff --git a/deploy/k8s-provisioner/config/prometheus/monitor_tls_patch.yaml b/deploy/k8s-provisioner/config/prometheus/monitor_tls_patch.yaml new file mode 100644 index 0000000..5bf84ce --- /dev/null +++ b/deploy/k8s-provisioner/config/prometheus/monitor_tls_patch.yaml @@ -0,0 +1,19 @@ +# Patch for Prometheus ServiceMonitor to enable secure TLS configuration +# using certificates managed by cert-manager +- op: replace + path: /spec/endpoints/0/tlsConfig + value: + # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize + serverName: SERVICE_NAME.SERVICE_NAMESPACE.svc + insecureSkipVerify: false + ca: + secret: + name: metrics-server-cert + key: ca.crt + cert: + secret: + name: metrics-server-cert + key: tls.crt + keySecret: + name: metrics-server-cert + key: tls.key diff --git a/deploy/k8s-provisioner/config/rbac/cluster_admin_role.yaml b/deploy/k8s-provisioner/config/rbac/cluster_admin_role.yaml new file mode 100644 index 0000000..7e4f769 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/cluster_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over k8sprovisioner.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: cluster-admin-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters + verbs: + - '*' +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/cluster_editor_role.yaml b/deploy/k8s-provisioner/config/rbac/cluster_editor_role.yaml new file mode 100644 index 0000000..a16b345 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/cluster_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the k8sprovisioner.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: cluster-editor-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/cluster_viewer_role.yaml b/deploy/k8s-provisioner/config/rbac/cluster_viewer_role.yaml new file mode 100644 index 0000000..b0b5c99 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/cluster_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to k8sprovisioner.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: cluster-viewer-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters + verbs: + - get + - list + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/infra_admin_role.yaml b/deploy/k8s-provisioner/config/rbac/infra_admin_role.yaml new file mode 100644 index 0000000..d6a6abf --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/infra_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over k8sprovisioner.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: infra-admin-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras + verbs: + - '*' +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/infra_editor_role.yaml b/deploy/k8s-provisioner/config/rbac/infra_editor_role.yaml new file mode 100644 index 0000000..fe05dcf --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/infra_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the k8sprovisioner.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: infra-editor-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/infra_viewer_role.yaml b/deploy/k8s-provisioner/config/rbac/infra_viewer_role.yaml new file mode 100644 index 0000000..35205ae --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/infra_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project k8s-provisioner itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to k8sprovisioner.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: infra-viewer-role +rules: +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras + verbs: + - get + - list + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras/status + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/kustomization.yaml b/deploy/k8s-provisioner/config/rbac/kustomization.yaml new file mode 100644 index 0000000..042a61b --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/kustomization.yaml @@ -0,0 +1,31 @@ +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# The following RBAC configurations are used to protect +# the metrics endpoint with authn/authz. These configurations +# ensure that only authorized users and service accounts +# can access the metrics endpoint. Comment the following +# permissions if you want to disable this protection. +# More info: https://book.kubebuilder.io/reference/metrics.html +- metrics_auth_role.yaml +- metrics_auth_role_binding.yaml +- metrics_reader_role.yaml +# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the k8s-provisioner itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. +- cluster_admin_role.yaml +- cluster_editor_role.yaml +- cluster_viewer_role.yaml +- infra_admin_role.yaml +- infra_editor_role.yaml +- infra_viewer_role.yaml + diff --git a/deploy/k8s-provisioner/config/rbac/leader_election_role.yaml b/deploy/k8s-provisioner/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000..1ca283c --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/leader_election_role.yaml @@ -0,0 +1,40 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/deploy/k8s-provisioner/config/rbac/leader_election_role_binding.yaml b/deploy/k8s-provisioner/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..f63b997 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/k8s-provisioner/config/rbac/metrics_auth_role.yaml b/deploy/k8s-provisioner/config/rbac/metrics_auth_role.yaml new file mode 100644 index 0000000..32d2e4e --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/metrics_auth_role.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/deploy/k8s-provisioner/config/rbac/metrics_auth_role_binding.yaml b/deploy/k8s-provisioner/config/rbac/metrics_auth_role_binding.yaml new file mode 100644 index 0000000..e775d67 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/metrics_auth_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metrics-auth-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/k8s-provisioner/config/rbac/metrics_reader_role.yaml b/deploy/k8s-provisioner/config/rbac/metrics_reader_role.yaml new file mode 100644 index 0000000..51a75db --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/metrics_reader_role.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/deploy/k8s-provisioner/config/rbac/role.yaml b/deploy/k8s-provisioner/config/rbac/role.yaml new file mode 100644 index 0000000..f01874d --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/role.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - clusters/status + verbs: + - get + - patch + - update +- apiGroups: + - k8sprovisioner.appstack.io + resources: + - infras + verbs: + - get + - list + - watch diff --git a/deploy/k8s-provisioner/config/rbac/role_binding.yaml b/deploy/k8s-provisioner/config/rbac/role_binding.yaml new file mode 100644 index 0000000..ecac253 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/k8s-provisioner/config/rbac/service_account.yaml b/deploy/k8s-provisioner/config/rbac/service_account.yaml new file mode 100644 index 0000000..9348f71 --- /dev/null +++ b/deploy/k8s-provisioner/config/rbac/service_account.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: controller-manager + namespace: system diff --git a/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_cluster.yaml b/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_cluster.yaml new file mode 100644 index 0000000..59d6599 --- /dev/null +++ b/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_cluster.yaml @@ -0,0 +1,9 @@ +apiVersion: k8sprovisioner.appstack.io/v1alpha1 +kind: Cluster +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: cluster-sample +spec: + # TODO(user): Add fields here diff --git a/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_infra.yaml b/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_infra.yaml new file mode 100644 index 0000000..c24c692 --- /dev/null +++ b/deploy/k8s-provisioner/config/samples/k8sprovisioner_v1alpha1_infra.yaml @@ -0,0 +1,9 @@ +apiVersion: k8sprovisioner.appstack.io/v1alpha1 +kind: Infra +metadata: + labels: + app.kubernetes.io/name: k8s-provisioner + app.kubernetes.io/managed-by: kustomize + name: infra-sample +spec: + # TODO(user): Add fields here diff --git a/deploy/k8s-provisioner/config/samples/kustomization.yaml b/deploy/k8s-provisioner/config/samples/kustomization.yaml new file mode 100644 index 0000000..7a76081 --- /dev/null +++ b/deploy/k8s-provisioner/config/samples/kustomization.yaml @@ -0,0 +1,5 @@ +## Append samples of your project ## +resources: +- k8sprovisioner_v1alpha1_infra.yaml +- k8sprovisioner_v1alpha1_cluster.yaml +# +kubebuilder:scaffold:manifestskustomizesamples diff --git a/deploy/k8s-provisioner/go.mod b/deploy/k8s-provisioner/go.mod new file mode 100644 index 0000000..5c8d398 --- /dev/null +++ b/deploy/k8s-provisioner/go.mod @@ -0,0 +1,161 @@ +module vanderlande.com/appstack/k8s-provisioner + +go 1.25.0 + +require ( + github.com/onsi/ginkgo/v2 v2.27.2 + github.com/onsi/gomega v1.38.2 + gopkg.in/yaml.v3 v3.0.1 + helm.sh/helm/v3 v3.19.4 + k8s.io/api v0.35.0 + k8s.io/apimachinery v0.35.0 + k8s.io/cli-runtime v0.35.0 + k8s.io/client-go v0.35.0 + sigs.k8s.io/controller-runtime v0.22.4 +) + +require ( + cel.dev/expr v0.24.0 // indirect + dario.cat/mergo v1.0.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/Masterminds/squirrel v1.5.4 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/containerd/containerd v1.7.29 // indirect + github.com/containerd/errdefs v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cyphar/filepath-securejoin v0.6.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/evanphx/json-patch v5.9.11+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect + github.com/gosuri/uitable v0.0.4 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rubenv/sql-migrate v1.8.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.38.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.8 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/apiextensions-apiserver v0.34.2 // indirect + k8s.io/apiserver v0.34.2 // indirect + k8s.io/component-base v0.34.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/kubectl v0.34.2 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + oras.land/oras-go/v2 v2.6.0 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/kustomize/api v0.20.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/deploy/k8s-provisioner/go.sum b/deploy/k8s-provisioner/go.sum new file mode 100644 index 0000000..bba3359 --- /dev/null +++ b/deploy/k8s-provisioner/go.sum @@ -0,0 +1,501 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE= +github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= +github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= +github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= +github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM= +github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= +github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= +github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= +github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= +github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= +github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o= +github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI= +go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU= +go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s= +go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk= +go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs= +go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.19.4 h1:E2yFBejmZBczWr5LblhjZbvAOAwVumfBO1AtN3nqI30= +helm.sh/helm/v3 v3.19.4/go.mod h1:PC1rk7PqacpkV4acUFMLStOOis7QM9Jq3DveHBInu4s= +k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= +k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= +k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= +k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= +k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= +k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= +k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= +k8s.io/cli-runtime v0.35.0 h1:PEJtYS/Zr4p20PfZSLCbY6YvaoLrfByd6THQzPworUE= +k8s.io/cli-runtime v0.35.0/go.mod h1:VBRvHzosVAoVdP3XwUQn1Oqkvaa8facnokNkD7jOTMY= +k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= +k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= +k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= +k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/kubectl v0.34.2 h1:+fWGrVlDONMUmmQLDaGkQ9i91oszjjRAa94cr37hzqA= +k8s.io/kubectl v0.34.2/go.mod h1:X2KTOdtZZNrTWmUD4oHApJ836pevSl+zvC5sI6oO2YQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= +oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= +sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I= +sigs.k8s.io/kustomize/api v0.20.1/go.mod h1:t6hUFxO+Ph0VxIk1sKp1WS0dOjbPCtLJ4p8aADLwqjM= +sigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A78= +sigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/deploy/k8s-provisioner/hack/boilerplate.go.txt b/deploy/k8s-provisioner/hack/boilerplate.go.txt new file mode 100644 index 0000000..9786798 --- /dev/null +++ b/deploy/k8s-provisioner/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ \ No newline at end of file diff --git a/deploy/k8s-provisioner/internal/controller/cluster_controller.go b/deploy/k8s-provisioner/internal/controller/cluster_controller.go new file mode 100644 index 0000000..b09ff9a --- /dev/null +++ b/deploy/k8s-provisioner/internal/controller/cluster_controller.go @@ -0,0 +1,157 @@ +package controller + +import ( + "context" + _ "embed" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + k8sprovisionerv1alpha1 "vanderlande.com/appstack/k8s-provisioner/api/v1alpha1" + "vanderlande.com/appstack/k8s-provisioner/internal/harvester" + "vanderlande.com/appstack/k8s-provisioner/internal/helm" + "vanderlande.com/appstack/k8s-provisioner/internal/templates" + + "vanderlande.com/appstack/k8s-provisioner/internal/values" +) + +type ClusterReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// Internal Struct for mapping NodePools to Helm Values +type HelmNodePool struct { + Name string `json:"name"` + DisplayName string `json:"displayName"` + Quantity int `json:"quantity"` + Etcd bool `json:"etcd"` + ControlPlane bool `json:"controlplane"` + Worker bool `json:"worker"` + Paused bool `json:"paused"` + CpuCount int `json:"cpuCount"` + DiskSize int `json:"diskSize"` + ImageName string `json:"imageName"` + MemorySize int `json:"memorySize"` + NetworkName string `json:"networkName"` + SshUser string `json:"sshUser"` + VmNamespace string `json:"vmNamespace"` + UserData string `json:"userData"` +} + +// +kubebuilder:rbac:groups=k8sprovisioner.appstack.io,resources=clusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=k8sprovisioner.appstack.io,resources=clusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=k8sprovisioner.appstack.io,resources=infras,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete + +const clusterFinalizer = "k8sprovisioner.appstack.io/finalizer" + +func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + // Initialize Managers + hvManager := harvester.NewIdentityManager(r.Client, r.Scheme) + + // 1. Fetch Cluster + var cluster k8sprovisionerv1alpha1.Cluster + if err := r.Get(ctx, req.NamespacedName, &cluster); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // 2. Handle Deletion + if !cluster.ObjectMeta.DeletionTimestamp.IsZero() { + if controllerutil.ContainsFinalizer(&cluster, clusterFinalizer) { + l.Info("Processing Cluster Deletion...") + + // A. Uninstall Helm + helmCfg := helm.Config{Namespace: req.Namespace, ReleaseName: req.Name} + if err := helm.Uninstall(helmCfg); err != nil { + return ctrl.Result{}, err + } + + // B. Cleanup Harvester (Using Manager) + hvManager.Cleanup(ctx, &cluster) + + // C. Remove Finalizer + controllerutil.RemoveFinalizer(&cluster, clusterFinalizer) + if err := r.Update(ctx, &cluster); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil + } + + // 3. Add Finalizer + if !controllerutil.ContainsFinalizer(&cluster, clusterFinalizer) { + controllerutil.AddFinalizer(&cluster, clusterFinalizer) + if err := r.Update(ctx, &cluster); err != nil { + return ctrl.Result{}, err + } + } + + // 4. Fetch Infra + var infra k8sprovisionerv1alpha1.Infra + if err := r.Get(ctx, types.NamespacedName{Name: cluster.Spec.InfraRef, Namespace: req.Namespace}, &infra); err != nil { + return ctrl.Result{}, err + } + + // ========================================================= + // 5. SECURE HARVESTER IDENTITY (Simplified) + // ========================================================= + + // The manager handles looking up Rancher creds, minting tokens, + // saving secrets, and updating the Cluster status. + generatedSecretName, err := hvManager.Ensure(ctx, &cluster, &infra) + if err != nil { + return ctrl.Result{}, err + } + + // ========================================================= + // 6. HELM VALUES GENERATION + // ========================================================= + + vb := values.NewBuilder( + &cluster, + &infra, + templates.BaseValuesYAML, + generatedSecretName, + req.Namespace, + ) + + helmValues, err := vb.Build() + if err != nil { + l.Error(err, "Failed to generate helm values") + return ctrl.Result{}, err + } + + chartSpec := vb.GetChartConfig() + + // 7. Trigger Helm Apply + l.Info("Syncing Helm Release", "Release", req.Name) + + helmCfg := helm.Config{ + Namespace: req.Namespace, + ReleaseName: req.Name, + RepoURL: chartSpec.Repo, + ChartName: chartSpec.Name, + Version: chartSpec.Version, + Values: helmValues, + } + + if err := helm.Apply(helmCfg); err != nil { + l.Error(err, "Helm Apply Failed") + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&k8sprovisionerv1alpha1.Cluster{}). + Complete(r) +} diff --git a/deploy/k8s-provisioner/internal/controller/cluster_controller_test.go b/deploy/k8s-provisioner/internal/controller/cluster_controller_test.go new file mode 100644 index 0000000..590275f --- /dev/null +++ b/deploy/k8s-provisioner/internal/controller/cluster_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + k8sprovisionerv1alpha1 "vanderlande.com/appstack/k8s-provisioner/api/v1alpha1" +) + +var _ = Describe("Cluster Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + cluster := &k8sprovisionerv1alpha1.Cluster{} + + BeforeEach(func() { + By("creating the custom resource for the Kind Cluster") + err := k8sClient.Get(ctx, typeNamespacedName, cluster) + if err != nil && errors.IsNotFound(err) { + resource := &k8sprovisionerv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &k8sprovisionerv1alpha1.Cluster{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance Cluster") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &ClusterReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/deploy/k8s-provisioner/internal/controller/suite_test.go b/deploy/k8s-provisioner/internal/controller/suite_test.go new file mode 100644 index 0000000..c02ff88 --- /dev/null +++ b/deploy/k8s-provisioner/internal/controller/suite_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + k8sprovisionerv1alpha1 "vanderlande.com/appstack/k8s-provisioner/api/v1alpha1" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var ( + ctx context.Context + cancel context.CancelFunc + testEnv *envtest.Environment + cfg *rest.Config + k8sClient client.Client +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + ctx, cancel = context.WithCancel(context.TODO()) + + var err error + err = k8sprovisionerv1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + // +kubebuilder:scaffold:scheme + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + // Retrieve the first found binary directory to allow running tests from IDEs + if getFirstFoundEnvTestBinaryDir() != "" { + testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() + } + + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + cancel() + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) + +// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. +// ENVTEST-based tests depend on specific binaries, usually located in paths set by +// controller-runtime. When running tests directly (e.g., via an IDE) without using +// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. +// +// This function streamlines the process by finding the required binaries, similar to +// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are +// properly set up, run 'make setup-envtest' beforehand. +func getFirstFoundEnvTestBinaryDir() string { + basePath := filepath.Join("..", "..", "bin", "k8s") + entries, err := os.ReadDir(basePath) + if err != nil { + logf.Log.Error(err, "Failed to read directory", "path", basePath) + return "" + } + for _, entry := range entries { + if entry.IsDir() { + return filepath.Join(basePath, entry.Name()) + } + } + return "" +} diff --git a/deploy/k8s-provisioner/internal/harvester/factory.go b/deploy/k8s-provisioner/internal/harvester/factory.go new file mode 100644 index 0000000..c50cf80 --- /dev/null +++ b/deploy/k8s-provisioner/internal/harvester/factory.go @@ -0,0 +1,229 @@ +package harvester + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + authenticationv1 "k8s.io/api/authentication/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + k8sprovisionerv1alpha1 "vanderlande.com/appstack/k8s-provisioner/api/v1alpha1" +) + +// TryCleanup performs a "Best Effort" cleanup of Harvester resources. +func TryCleanup(ctx context.Context, k8sClient client.Client, infraRefName, namespace, saName string) { + l := log.FromContext(ctx) + + // 1. Fetch Infra + var infra k8sprovisionerv1alpha1.Infra + if err := k8sClient.Get(ctx, types.NamespacedName{Name: infraRefName, Namespace: namespace}, &infra); err != nil { + l.Info("Cleanup skipped: Infra object not found") + return + } + + vmNamespace := infra.Spec.VmNamespace + if vmNamespace == "" { + vmNamespace = "default" + } + + // 2. Fetch Master Credential + rancherCredName := infra.Spec.CloudCredentialSecret + var rancherSecret corev1.Secret + if err := k8sClient.Get(ctx, types.NamespacedName{Name: rancherCredName, Namespace: "cattle-global-data"}, &rancherSecret); err != nil { + l.Info("Cleanup skipped: Master Credential Secret not found") + return + } + + // 3. Extract Kubeconfig + var kubeBytes []byte + if len(rancherSecret.Data["harvestercredentialConfig-kubeconfigContent"]) > 0 { + kubeBytes = rancherSecret.Data["harvestercredentialConfig-kubeconfigContent"] + } else if len(rancherSecret.Data["credential"]) > 0 { + kubeBytes = rancherSecret.Data["credential"] + } else { + return + } + + // 4. Cleanup + if err := deleteHarvesterResources(ctx, kubeBytes, saName, vmNamespace); err != nil { + l.Error(err, "Failed to cleanup Harvester resources (ignoring)") + } else { + l.Info("Harvester resources deleted successfully") + } +} + +// Internal helper for cleanup +func deleteHarvesterResources(ctx context.Context, masterKubeconfig []byte, serviceAccountName, vmNamespace string) error { + restConfig, err := clientcmd.RESTConfigFromKubeConfig(masterKubeconfig) + if err != nil { + return err + } + hvClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return err + } + + deletePolicy := metav1.DeletePropagationBackground + deleteOpts := metav1.DeleteOptions{PropagationPolicy: &deletePolicy} + + // 1. Delete Global CSI Binding (ClusterRoleBinding) + csiBindingName := fmt.Sprintf("%s-csi-binding", serviceAccountName) + err = hvClient.RbacV1().ClusterRoleBindings().Delete(ctx, csiBindingName, deleteOpts) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + // 2. Delete Cloud Provider Binding (RoleBinding in VM Namespace) + cpBindingName := fmt.Sprintf("%s-cloud-binding", serviceAccountName) + err = hvClient.RbacV1().RoleBindings(vmNamespace).Delete(ctx, cpBindingName, deleteOpts) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + // 3. Delete ServiceAccount (VM Namespace) + err = hvClient.CoreV1().ServiceAccounts(vmNamespace).Delete(ctx, serviceAccountName, deleteOpts) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + return nil +} + +// EnsureCredential mints a dedicated ServiceAccount in the specific VM Namespace +func EnsureCredential(ctx context.Context, masterKubeconfig []byte, clusterName, targetNamespace, vmNamespace, harvesterURL string) (*corev1.Secret, string, time.Time, error) { + + // --- PHASE 1: Connect (Proxy/Master Config) --- + restConfig, err := clientcmd.RESTConfigFromKubeConfig(masterKubeconfig) + if err != nil { + return nil, "", time.Time{}, fmt.Errorf("invalid rancher cloud credential kubeconfig: %w", err) + } + hvClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return nil, "", time.Time{}, err + } + + // --- PHASE 2: Create Identity (SA & Bindings) --- + if vmNamespace == "" { + vmNamespace = "default" + } + saName := fmt.Sprintf("prov-%s", clusterName) + + // A. Create ServiceAccount + sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: saName, Namespace: vmNamespace}} + if _, err := hvClient.CoreV1().ServiceAccounts(vmNamespace).Create(ctx, sa, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { + return nil, "", time.Time{}, err + } + } + + // B. Create RoleBinding (VM Namespace) + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: saName + "-cloud-binding", Namespace: vmNamespace}, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: saName, Namespace: vmNamespace}}, + RoleRef: rbacv1.RoleRef{Kind: "ClusterRole", Name: "harvesterhci.io:cloudprovider", APIGroup: "rbac.authorization.k8s.io"}, + } + if _, err := hvClient.RbacV1().RoleBindings(vmNamespace).Create(ctx, rb, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { /* Ignore */ + } + } + + // C. Create ClusterRoleBinding (Global) + crb := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: saName + "-csi-binding"}, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: saName, Namespace: vmNamespace}}, + RoleRef: rbacv1.RoleRef{Kind: "ClusterRole", Name: "harvesterhci.io:csi-driver", APIGroup: "rbac.authorization.k8s.io"}, + } + if _, err := hvClient.RbacV1().ClusterRoleBindings().Create(ctx, crb, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { /* Ignore */ + } + } + + // D. Mint Token + ttlSeconds := int64(315360000) + tokenRequest, err := hvClient.CoreV1().ServiceAccounts(vmNamespace).CreateToken(ctx, saName, &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ExpirationSeconds: &ttlSeconds}, + }, metav1.CreateOptions{}) + if err != nil { + return nil, "", time.Time{}, fmt.Errorf("failed to mint harvester token: %w", err) + } + expiryTime := time.Now().Add(time.Duration(ttlSeconds) * time.Second) + + // --- PHASE 3: Determine URL & CA --- + + // 1. URL: Use the explicitly provided HarvesterURL + if harvesterURL == "" { + // Fallback to Proxy if user forgot to set it (Safety net) + harvesterURL = restConfig.Host + } + + // 2. CA: Fetch the internal Harvester CA + // (Required because the proxy CA won't match the direct IP/URL) + harvesterCA := restConfig.CAData + + caConfigMap, err := hvClient.CoreV1().ConfigMaps("default").Get(ctx, "kube-root-ca.crt", metav1.GetOptions{}) + if err == nil { + if caStr, ok := caConfigMap.Data["ca.crt"]; ok { + harvesterCA = []byte(caStr) + } + } + + // --- PHASE 4: Construct Kubeconfig --- + caData := base64.StdEncoding.EncodeToString(harvesterCA) + token := tokenRequest.Status.Token + + // Ensure "namespace" aligns vertically with "cluster" and "user" + newKubeconfig := fmt.Sprintf( + `apiVersion: v1 +kind: Config +clusters: +- name: harvester + cluster: + server: %s + certificate-authority-data: %s +users: +- name: provisioner + user: + token: %s +contexts: +- name: default + context: + cluster: harvester + user: provisioner + namespace: %s +current-context: default +`, harvesterURL, caData, token, vmNamespace) + + // --- PHASE 5: Create Secret --- + secretName := fmt.Sprintf("harvesterconfig-%s", clusterName) + + secret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{Kind: "Secret", APIVersion: "v1"}, + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: targetNamespace, + Annotations: map[string]string{ + "v2prov-secret-authorized-for-cluster": clusterName, + "v2prov-authorized-secret-deletes-on-cluster-removal": "true", + }, + Labels: map[string]string{ + "cattle.io/creator": "k8s-provisioner", + }, + }, + Type: "Opaque", + StringData: map[string]string{ + "credential": newKubeconfig, + }, + } + + return secret, saName, expiryTime, nil +} diff --git a/deploy/k8s-provisioner/internal/helm/client.go b/deploy/k8s-provisioner/internal/helm/client.go new file mode 100644 index 0000000..d2df63e --- /dev/null +++ b/deploy/k8s-provisioner/internal/helm/client.go @@ -0,0 +1,126 @@ +package helm + +import ( + "fmt" + "log" + "os" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/registry" // [NEW] Required for OCI + "helm.sh/helm/v3/pkg/storage/driver" + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +type Config struct { + Namespace string + ReleaseName string + RepoURL string + ChartName string + Version string + Values map[string]interface{} +} + +func Apply(cfg Config) error { + settings := cli.New() + + // 1. Initialize Action Config + actionConfig := new(action.Configuration) + getter := genericclioptions.NewConfigFlags(false) + + if err := actionConfig.Init(getter, cfg.Namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil { + return fmt.Errorf("failed to init helm config: %w", err) + } + + // 2. [NEW] Initialize OCI Registry Client + // This tells Helm how to talk to ghcr.io, docker.io, etc. + registryClient, err := registry.NewClient( + registry.ClientOptDebug(true), + registry.ClientOptEnableCache(true), + registry.ClientOptCredentialsFile(settings.RegistryConfig), // Uses ~/.config/helm/registry/config.json + ) + if err != nil { + return fmt.Errorf("failed to init registry client: %w", err) + } + actionConfig.RegistryClient = registryClient + + // 3. Setup Install Action + client := action.NewInstall(actionConfig) + client.Version = cfg.Version + client.Namespace = cfg.Namespace + client.ReleaseName = cfg.ReleaseName + client.CreateNamespace = true + + if cfg.RepoURL != "" { + client.RepoURL = cfg.RepoURL + } + + // 4. Locate Chart (Now supports oci:// because RegistryClient is set) + cp, err := client.ChartPathOptions.LocateChart(cfg.ChartName, settings) + if err != nil { + return fmt.Errorf("failed to locate chart %s: %w", cfg.ChartName, err) + } + + chart, err := loader.Load(cp) + if err != nil { + return fmt.Errorf("failed to load chart: %w", err) + } + + // 5. Install or Upgrade + histClient := action.NewHistory(actionConfig) + histClient.Max = 1 + + if _, err := histClient.Run(cfg.ReleaseName); err == driver.ErrReleaseNotFound { + fmt.Printf("Installing OCI Release %s...\n", cfg.ReleaseName) + _, err := client.Run(chart, cfg.Values) + return err + } else if err != nil { + return err + } + + fmt.Printf("Upgrading OCI Release %s...\n", cfg.ReleaseName) + upgrade := action.NewUpgrade(actionConfig) + upgrade.Version = cfg.Version + upgrade.Namespace = cfg.Namespace + // Important: Upgrade also needs the RegistryClient, but it shares 'actionConfig' + // so it is already set up. + if cfg.RepoURL != "" { + upgrade.RepoURL = cfg.RepoURL + } + _, err = upgrade.Run(cfg.ReleaseName, chart, cfg.Values) + return err +} + +func Uninstall(cfg Config) error { + settings := cli.New() + + // 1. Initialize Action Config (Same as Apply) + actionConfig := new(action.Configuration) + getter := genericclioptions.NewConfigFlags(false) + if err := actionConfig.Init(getter, cfg.Namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil { + return fmt.Errorf("failed to init helm config: %w", err) + } + + // 2. Initialize OCI Registry Client (Crucial for OCI charts) + registryClient, err := registry.NewClient( + registry.ClientOptDebug(true), + registry.ClientOptEnableCache(true), + registry.ClientOptCredentialsFile(settings.RegistryConfig), + ) + if err != nil { + return fmt.Errorf("failed to init registry client: %w", err) + } + actionConfig.RegistryClient = registryClient + + // 3. Run Uninstall + client := action.NewUninstall(actionConfig) + // Don't fail if it's already gone + _, err = client.Run(cfg.ReleaseName) + if err != nil && err != driver.ErrReleaseNotFound { + return fmt.Errorf("failed to uninstall release: %w", err) + } + + fmt.Printf("✅ Uninstalled Release %s\n", cfg.ReleaseName) + return nil +} diff --git a/deploy/k8s-provisioner/internal/templates/base_values.yaml b/deploy/k8s-provisioner/internal/templates/base_values.yaml new file mode 100644 index 0000000..cabfb23 --- /dev/null +++ b/deploy/k8s-provisioner/internal/templates/base_values.yaml @@ -0,0 +1,456 @@ +# ---------------------------------------------------------------- +# BASE TEMPLATE (internal/templates/base_values.yaml) +# ---------------------------------------------------------------- + +_defaults: + helmChart: + repo: "" + name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates" + version: "0.7.2" + controlPlaneProfile: + cpuCores: 4 + memoryGb: 8 + diskGb: 40 + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + - curl + - wget + + bootcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - sysctl -w net.ipv6.conf.default.disable_ipv6=1 + + write_files: + # ---------------------------------------------------------------- + # 1. CNI Permission Fix Script & Cron (CIS 1.1.9 Persistence) + # ---------------------------------------------------------------- + - path: /usr/local/bin/fix-cni-perms.sh + permissions: '0700' + owner: root:root + content: | + #!/bin/bash + # Wait 60s on boot for RKE2 to write files + [ "$1" == "boot" ] && sleep 60 + + # Enforce 600 on CNI files (CIS 1.1.9) + if [ -d /etc/cni/net.d ]; then + find /etc/cni/net.d -type f -exec chmod 600 {} \; + fi + if [ -d /var/lib/cni/networks ]; then + find /var/lib/cni/networks -type f -exec chmod 600 {} \; + fi + + # Every RKE2 service restart can reset CNI file permissions, so we run + # this script on reboot and daily via cron to maintain CIS compliance. + + - path: /etc/cron.d/cis-cni-fix + permissions: '0644' + owner: root:root + content: | + # Run on Reboot (with delay) to fix files created during startup + @reboot root /usr/local/bin/fix-cni-perms.sh boot + # Run once daily at 00:00 to correct any drift + 0 0 * * * root /usr/local/bin/fix-cni-perms.sh + + # ---------------------------------------------------------------- + # 2. RKE2 Admission Config + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/rke2-admission.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: apiserver.config.k8s.io/v1 + kind: AdmissionConfiguration + plugins: + - name: PodSecurity + configuration: + apiVersion: pod-security.admission.config.k8s.io/v1beta1 + kind: PodSecurityConfiguration + defaults: + enforce: "restricted" + enforce-version: "latest" + audit: "restricted" + audit-version: "latest" + warn: "restricted" + warn-version: "latest" + exemptions: + usernames: [] + runtimeClasses: [] + namespaces: [compliance-operator-system,kube-system, cis-operator-system, tigera-operator, calico-system, rke2-ingress-nginx, cattle-system, cattle-fleet-system, longhorn-system, cattle-neuvector-system] + - name: EventRateLimit + configuration: + apiVersion: eventratelimit.admission.k8s.io/v1alpha1 + kind: Configuration + limits: + - type: Server + qps: 5000 + burst: 20000 + + # ---------------------------------------------------------------- + # 3. RKE2 Audit Policy + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/audit-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: audit.k8s.io/v1 + kind: Policy + rules: + - level: None + users: ["system:kube-controller-manager", "system:kube-scheduler", "system:serviceaccount:kube-system:endpoint-controller"] + verbs: ["get", "update"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status"] + - level: None + verbs: ["get"] + resources: + - group: "" + resources: ["nodes", "nodes/status", "pods", "pods/status"] + - level: None + users: ["kube-proxy"] + verbs: ["watch"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status", "configmaps"] + - level: Metadata + resources: + - group: "" + resources: ["secrets", "configmaps"] + - level: RequestResponse + omitStages: + - RequestReceived + + # ---------------------------------------------------------------- + # 4. Static NetworkPolicies + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-network-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: default-deny-ingress + namespace: default + spec: + podSelector: {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-metrics + namespace: kube-public + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-system + namespace: kube-system + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + + # ---------------------------------------------------------------- + # 5. Service Account Hardening + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-config.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: default + automountServiceAccountToken: false + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: kube-system + automountServiceAccountToken: false + + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-cron.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: {name: sa-cleaner, namespace: kube-system} + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: {name: sa-cleaner-role} + rules: + - apiGroups: [""] + resources: ["namespaces", "serviceaccounts"] + verbs: ["get", "list", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: {name: sa-cleaner-binding} + subjects: [{kind: ServiceAccount, name: sa-cleaner, namespace: kube-system}] + roleRef: {kind: ClusterRole, name: sa-cleaner-role, apiGroup: rbac.authorization.k8s.io} + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: sa-cleaner + namespace: kube-system + spec: + schedule: "0 */6 * * *" # Run every 6 hours + jobTemplate: + spec: + template: + spec: + serviceAccountName: sa-cleaner + containers: + - name: cleaner + image: rancher/kubectl:v1.26.0 + command: + - /bin/bash + - -c + - | + # Get all namespaces + for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do + # Check if default SA has automount=true (or null) + automount=$(kubectl get sa default -n $ns -o jsonpath='{.automountServiceAccountToken}') + if [ "$automount" != "false" ]; then + echo "Securing default SA in namespace: $ns" + kubectl patch sa default -n $ns -p '{"automountServiceAccountToken": false}' + fi + done + restartPolicy: OnFailure + + # ---------------------------------------------------------------- + # 6. OS Sysctls Hardening + # ---------------------------------------------------------------- + - path: /etc/sysctl.d/60-rke2-cis.conf + permissions: '0644' + content: | + vm.overcommit_memory=1 + vm.max_map_count=65530 + vm.panic_on_oom=0 + fs.inotify.max_user_watches=1048576 + fs.inotify.max_user_instances=8192 + kernel.panic=10 + kernel.panic_on_oops=1 + net.ipv4.conf.all.rp_filter=1 + net.ipv4.conf.default.rp_filter=1 + net.ipv4.conf.all.accept_source_route=0 + net.ipv4.conf.default.accept_source_route=0 + net.ipv4.conf.all.accept_redirects=0 + net.ipv4.conf.default.accept_redirects=0 + net.ipv4.conf.all.send_redirects=0 + net.ipv4.conf.default.send_redirects=0 + net.ipv4.conf.all.log_martians=1 + net.ipv4.conf.default.log_martians=1 + net.ipv4.icmp_echo_ignore_broadcasts=1 + net.ipv4.icmp_ignore_bogus_error_responses=1 + net.ipv6.conf.all.disable_ipv6=1 + net.ipv6.conf.default.disable_ipv6=1 + fs.protected_hardlinks=1 + fs.protected_symlinks=1 + + # ---------------------------------------------------------------- + # 7. Environment & Setup Scripts + # ---------------------------------------------------------------- + - path: /etc/profile.d/rke2.sh + permissions: '0644' + content: | + export PATH=$PATH:/var/lib/rancher/rke2/bin:/opt/rke2/bin + export KUBECONFIG=/etc/rancher/rke2/rke2.yaml + + + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + - name: etcd + gecos: "etcd user" + shell: /sbin/nologin + system: true + lock_passwd: true + + disable_root: true + ssh_pwauth: true + + runcmd: + - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + - /usr/local/bin/fix-cni-perms.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Node ready for Rancher! + +# amazonec2, azure, digitalocean, harvester, vsphere, custom +cloudprovider: harvester + +# cloud provider credentials +cloudCredentialSecretName: cc-mrklm + +# rancher manager url +rancher: + cattle: + url: rancher-mgmt.product.lan + +# cluster values +cluster: + + name: default-cluster + # labels: + # key: value + config: + kubernetesVersion: v1.33.5+rke2r1 + enableNetworkPolicy: true + localClusterAuthEndpoint: + enabled: false + chartValues: + harvester-cloud-provider: + global: + cattle: + clusterName: default-cluster + + # Pod Security Standard (Replaces PSP) + defaultPodSecurityAdmissionConfigurationTemplateName: "rancher-restricted" + + globalConfig: + systemDefaultRegistry: docker.io + cni: canal + docker: false + disable_scheduler: false + disable_cloud_controller: false + disable_kube_proxy: false + etcd_expose_metrics: false + profile: 'cis' + selinux: false + secrets_encryption: true + write_kubeconfig_mode: 0600 + use_service_account_credentials: false + protect_kernel_defaults: true + cloud_provider_name: harvester + cloud_provider_config: secret://fleet-default:harvesterconfigzswmd + + kube_apiserver_arg: + - "service-account-extend-token-expiration=false" + - "anonymous-auth=false" + - "enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit,DenyServiceExternalIPs" + - "admission-control-config-file=/etc/rancher/rke2/rke2-admission.yaml" + - "audit-policy-file=/etc/rancher/rke2/audit-policy.yaml" + - "audit-log-path=/var/lib/rancher/rke2/server/logs/audit.log" + - "audit-log-maxage=30" + - "audit-log-maxbackup=10" + - "audit-log-maxsize=100" + + kubelet_arg: + # Strong Ciphers (CIS 4.2.12) + - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + # PID Limit (CIS 4.2.13) + - "pod-max-pids=4096" + # Seccomp Default (CIS 4.2.14) + - "seccomp-default=true" + - "protect-kernel-defaults=true" + - "make-iptables-util-chains=true" + + upgradeStrategy: + controlPlaneConcurrency: 10% + controlPlaneDrainOptions: + enabled: false + workerConcurrency: 10% + workerDrainOptions: + enabled: false +addons: + monitoring: + enabled: false + logging: + enabled: false + longhorn: + enabled: false + neuvector: + enabled: false + +# node and nodepool(s) values +# ---------------------------------------------------------------- +# MANUAL TESTING SECTION +# The Operator will DELETE and OVERWRITE this section at runtime. +# These values are only used if you run 'helm install' manually. +# ---------------------------------------------------------------- +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + cpuCount: 4 + diskSize: 40 + imageName: vanderlande/image-qhtpc + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + + - name: worker-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + cpuCount: 2 + diskSize: 40 + imageName: vanderlande/image-qmx5q + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + diff --git a/deploy/k8s-provisioner/internal/templates/base_values_vsphere.yaml b/deploy/k8s-provisioner/internal/templates/base_values_vsphere.yaml new file mode 100644 index 0000000..18f5a37 --- /dev/null +++ b/deploy/k8s-provisioner/internal/templates/base_values_vsphere.yaml @@ -0,0 +1,205 @@ +# ---------------------------------------------------------------- +# BASE TEMPLATE (internal/templates/base_values.yaml) +# ---------------------------------------------------------------- + +_defaults: + helmChart: + repo: "" + name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates" + version: "0.7.2" + controlPlaneProfile: + cpuCores: 4 + memoryGb: 8 + diskGb: 40 + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - yq + - jq + + disable_root: true + ssh_pwauth: false + + write_files: + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + disable_root: true + ssh_pwauth: true + + runcmd: + # - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + + bootcmd: + - sudo bash /root/networking.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Node ready for Rancher! + +# amazonec2, azure, digitalocean, harvester, vsphere, custom +cloudprovider: vsphere + +# cloud provider credentials +cloudCredentialSecretName: cc-lhtl9 + +# rancher manager url +rancher: + cattle: + url: rancher.tst.vanderlande.com + +# cluster values +cluster: + + name: default-cluster-005 + # labels: + # key: value + config: + kubernetesVersion: v1.31.12+rke2r1 + enableNetworkPolicy: true + localClusterAuthEndpoint: + enabled: false + + + # Pod Security Standard (Replaces PSP) + # defaultPodSecurityAdmissionConfigurationTemplateName: "rancher-restricted" + + globalConfig: + systemDefaultRegistry: docker.io + cni: canal + docker: false + disable_scheduler: false + disable_cloud_controller: false + disable_kube_proxy: false + etcd_expose_metrics: false + profile: '' + selinux: false + secrets_encryption: false + write_kubeconfig_mode: 0600 + use_service_account_credentials: false + protect_kernel_defaults: false + cloud_provider_name: '' + + # kube_apiserver_arg: + # - "service-account-extend-token-expiration=false" + # - "anonymous-auth=false" + # - "enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit,DenyServiceExternalIPs" + # - "admission-control-config-file=/etc/rancher/rke2/rke2-admission.yaml" + # - "audit-policy-file=/etc/rancher/rke2/audit-policy.yaml" + # - "audit-log-path=/var/lib/rancher/rke2/server/logs/audit.log" + # - "audit-log-maxage=30" + # - "audit-log-maxbackup=10" + # - "audit-log-maxsize=100" + + # kubelet_arg: + # # Strong Ciphers (CIS 4.2.12) + # - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + # # PID Limit (CIS 4.2.13) + # - "pod-max-pids=4096" + # # Seccomp Default (CIS 4.2.14) + # - "seccomp-default=true" + # - "protect-kernel-defaults=true" + # - "make-iptables-util-chains=true" + + upgradeStrategy: + controlPlaneConcurrency: 10% + controlPlaneDrainOptions: + enabled: false + workerConcurrency: 10% + workerDrainOptions: + enabled: false +addons: + monitoring: + enabled: false + logging: + enabled: false + longhorn: + enabled: true + neuvector: + enabled: false + +# node and nodepool(s) values +# ---------------------------------------------------------------- +# MANUAL TESTING SECTION +# The Operator will DELETE and OVERWRITE this section at runtime. +# These values are only used if you run 'helm install' manually. +# ---------------------------------------------------------------- +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + # VSPHERE SPECIFIC FIELDS + cpuCount: 2 + memorySize: 8192 + diskSize: 40000 + vcenter: "vcenter.vanderlande.com" + datacenter: "NL001" + folder: "ICT Digitalisation - Rancher" + pool: "NL001 Development - Rancher/Resources" + datastoreCluster: "NL001 Development - Rancher SDRS" # Matches your SDRS input + network: + - "nl001.vDS.Distri.Vlan.1542" + # Provisioning Source + creationType: "template" + cloneFrom: "nl001-cp-ubuntu-22.04-amd64-20250327-5.15.0-135-rke2-k3s" + cloudConfig: *userData # Using the anchor from your base file + + - name: worker-storage-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + # VSPHERE SPECIFIC FIELDS + cpuCount: 4 + memorySize: 8192 + diskSize: 100000 + vcenter: "vcenter.vanderlande.com" + datacenter: "NL001" + folder: "ICT Digitalisation - Rancher" + pool: "NL001 Development - Rancher/Resources" + datastoreCluster: "NL001 Development - Rancher SDRS" # Matches your SDRS input + network: + - "nl001.vDS.Distri.Vlan.1542" + # Provisioning Source + creationType: "template" + cloneFrom: "nl001-cp-ubuntu-22.04-amd64-20250327-5.15.0-135-rke2-k3s" + cloudConfig: *userData # Using the anchor from your base file + + + diff --git a/deploy/k8s-provisioner/internal/templates/embed.go b/deploy/k8s-provisioner/internal/templates/embed.go new file mode 100644 index 0000000..745896b --- /dev/null +++ b/deploy/k8s-provisioner/internal/templates/embed.go @@ -0,0 +1,6 @@ +package templates + +import _ "embed" + +//go:embed base_values.yaml +var BaseValuesYAML []byte diff --git a/deploy/k8s-provisioner/test/e2e/e2e_suite_test.go b/deploy/k8s-provisioner/test/e2e/e2e_suite_test.go new file mode 100644 index 0000000..aded9ab --- /dev/null +++ b/deploy/k8s-provisioner/test/e2e/e2e_suite_test.go @@ -0,0 +1,92 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "os" + "os/exec" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "vanderlande.com/appstack/k8s-provisioner/test/utils" +) + +var ( + // Optional Environment Variables: + // - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup. + // These variables are useful if CertManager is already installed, avoiding + // re-installation and conflicts. + skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true" + // isCertManagerAlreadyInstalled will be set true when CertManager CRDs be found on the cluster + isCertManagerAlreadyInstalled = false + + // projectImage is the name of the image which will be build and loaded + // with the code source changes to be tested. + projectImage = "example.com/k8s-provisioner:v0.0.1" +) + +// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated, +// temporary environment to validate project changes with the purpose of being used in CI jobs. +// The default setup requires Kind, builds/loads the Manager Docker image locally, and installs +// CertManager. +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + _, _ = fmt.Fprintf(GinkgoWriter, "Starting k8s-provisioner integration test suite\n") + RunSpecs(t, "e2e suite") +} + +var _ = BeforeSuite(func() { + By("building the manager(Operator) image") + cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectImage)) + _, err := utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image") + + // TODO(user): If you want to change the e2e test vendor from Kind, ensure the image is + // built and available before running the tests. Also, remove the following block. + By("loading the manager(Operator) image on Kind") + err = utils.LoadImageToKindClusterWithName(projectImage) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to load the manager(Operator) image into Kind") + + // The tests-e2e are intended to run on a temporary cluster that is created and destroyed for testing. + // To prevent errors when tests run in environments with CertManager already installed, + // we check for its presence before execution. + // Setup CertManager before the suite if not skipped and if not already installed + if !skipCertManagerInstall { + By("checking if cert manager is installed already") + isCertManagerAlreadyInstalled = utils.IsCertManagerCRDsInstalled() + if !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n") + Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager") + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "WARNING: CertManager is already installed. Skipping installation...\n") + } + } +}) + +var _ = AfterSuite(func() { + // Teardown CertManager after the suite if not skipped and if it was not already installed + if !skipCertManagerInstall && !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n") + utils.UninstallCertManager() + } +}) diff --git a/deploy/k8s-provisioner/test/e2e/e2e_test.go b/deploy/k8s-provisioner/test/e2e/e2e_test.go new file mode 100644 index 0000000..b2d9e17 --- /dev/null +++ b/deploy/k8s-provisioner/test/e2e/e2e_test.go @@ -0,0 +1,337 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "vanderlande.com/appstack/k8s-provisioner/test/utils" +) + +// namespace where the project is deployed in +const namespace = "k8s-provisioner-system" + +// serviceAccountName created for the project +const serviceAccountName = "k8s-provisioner-controller-manager" + +// metricsServiceName is the name of the metrics service of the project +const metricsServiceName = "k8s-provisioner-controller-manager-metrics-service" + +// metricsRoleBindingName is the name of the RBAC that will be created to allow get the metrics data +const metricsRoleBindingName = "k8s-provisioner-metrics-binding" + +var _ = Describe("Manager", Ordered, func() { + var controllerPodName string + + // Before running the tests, set up the environment by creating the namespace, + // enforce the restricted security policy to the namespace, installing CRDs, + // and deploying the controller. + BeforeAll(func() { + By("creating manager namespace") + cmd := exec.Command("kubectl", "create", "ns", namespace) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create namespace") + + By("labeling the namespace to enforce the restricted security policy") + cmd = exec.Command("kubectl", "label", "--overwrite", "ns", namespace, + "pod-security.kubernetes.io/enforce=restricted") + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to label namespace with restricted policy") + + By("installing CRDs") + cmd = exec.Command("make", "install") + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs") + + By("deploying the controller-manager") + cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectImage)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager") + }) + + // After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs, + // and deleting the namespace. + AfterAll(func() { + By("cleaning up the curl pod for metrics") + cmd := exec.Command("kubectl", "delete", "pod", "curl-metrics", "-n", namespace) + _, _ = utils.Run(cmd) + + By("undeploying the controller-manager") + cmd = exec.Command("make", "undeploy") + _, _ = utils.Run(cmd) + + By("uninstalling CRDs") + cmd = exec.Command("make", "uninstall") + _, _ = utils.Run(cmd) + + By("removing manager namespace") + cmd = exec.Command("kubectl", "delete", "ns", namespace) + _, _ = utils.Run(cmd) + }) + + // After each test, check for failures and collect logs, events, + // and pod descriptions for debugging. + AfterEach(func() { + specReport := CurrentSpecReport() + if specReport.Failed() { + By("Fetching controller manager pod logs") + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + controllerLogs, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n %s", controllerLogs) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get Controller logs: %s", err) + } + + By("Fetching Kubernetes events") + cmd = exec.Command("kubectl", "get", "events", "-n", namespace, "--sort-by=.lastTimestamp") + eventsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Kubernetes events:\n%s", eventsOutput) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get Kubernetes events: %s", err) + } + + By("Fetching curl-metrics logs") + cmd = exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + metricsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Metrics logs:\n %s", metricsOutput) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get curl-metrics logs: %s", err) + } + + By("Fetching controller manager pod description") + cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", namespace) + podDescription, err := utils.Run(cmd) + if err == nil { + fmt.Println("Pod description:\n", podDescription) + } else { + fmt.Println("Failed to describe controller pod") + } + } + }) + + SetDefaultEventuallyTimeout(2 * time.Minute) + SetDefaultEventuallyPollingInterval(time.Second) + + Context("Manager", func() { + It("should run successfully", func() { + By("validating that the controller-manager pod is running as expected") + verifyControllerUp := func(g Gomega) { + // Get the name of the controller-manager pod + cmd := exec.Command("kubectl", "get", + "pods", "-l", "control-plane=controller-manager", + "-o", "go-template={{ range .items }}"+ + "{{ if not .metadata.deletionTimestamp }}"+ + "{{ .metadata.name }}"+ + "{{ \"\\n\" }}{{ end }}{{ end }}", + "-n", namespace, + ) + + podOutput, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred(), "Failed to retrieve controller-manager pod information") + podNames := utils.GetNonEmptyLines(podOutput) + g.Expect(podNames).To(HaveLen(1), "expected 1 controller pod running") + controllerPodName = podNames[0] + g.Expect(controllerPodName).To(ContainSubstring("controller-manager")) + + // Validate the pod's status + cmd = exec.Command("kubectl", "get", + "pods", controllerPodName, "-o", "jsonpath={.status.phase}", + "-n", namespace, + ) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Running"), "Incorrect controller-manager pod status") + } + Eventually(verifyControllerUp).Should(Succeed()) + }) + + It("should ensure the metrics endpoint is serving metrics", func() { + By("creating a ClusterRoleBinding for the service account to allow access to metrics") + cmd := exec.Command("kubectl", "create", "clusterrolebinding", metricsRoleBindingName, + "--clusterrole=k8s-provisioner-metrics-reader", + fmt.Sprintf("--serviceaccount=%s:%s", namespace, serviceAccountName), + ) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create ClusterRoleBinding") + + By("validating that the metrics service is available") + cmd = exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Metrics service should exist") + + By("getting the service account token") + token, err := serviceAccountToken() + Expect(err).NotTo(HaveOccurred()) + Expect(token).NotTo(BeEmpty()) + + By("ensuring the controller pod is ready") + verifyControllerPodReady := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pod", controllerPodName, "-n", namespace, + "-o", "jsonpath={.status.conditions[?(@.type=='Ready')].status}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("True"), "Controller pod not ready") + } + Eventually(verifyControllerPodReady, 3*time.Minute, time.Second).Should(Succeed()) + + By("verifying that the controller manager is serving the metrics server") + verifyMetricsServerStarted := func(g Gomega) { + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(ContainSubstring("Serving metrics server"), + "Metrics server not yet started") + } + Eventually(verifyMetricsServerStarted, 3*time.Minute, time.Second).Should(Succeed()) + + // +kubebuilder:scaffold:e2e-metrics-webhooks-readiness + + By("creating the curl-metrics pod to access the metrics endpoint") + cmd = exec.Command("kubectl", "run", "curl-metrics", "--restart=Never", + "--namespace", namespace, + "--image=curlimages/curl:latest", + "--overrides", + fmt.Sprintf(`{ + "spec": { + "containers": [{ + "name": "curl", + "image": "curlimages/curl:latest", + "command": ["/bin/sh", "-c"], + "args": ["curl -v -k -H 'Authorization: Bearer %s' https://%s.%s.svc.cluster.local:8443/metrics"], + "securityContext": { + "readOnlyRootFilesystem": true, + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": ["ALL"] + }, + "runAsNonRoot": true, + "runAsUser": 1000, + "seccompProfile": { + "type": "RuntimeDefault" + } + } + }], + "serviceAccountName": "%s" + } + }`, token, metricsServiceName, namespace, serviceAccountName)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod") + + By("waiting for the curl-metrics pod to complete.") + verifyCurlUp := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pods", "curl-metrics", + "-o", "jsonpath={.status.phase}", + "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Succeeded"), "curl pod in wrong status") + } + Eventually(verifyCurlUp, 5*time.Minute).Should(Succeed()) + + By("getting the metrics by checking curl-metrics logs") + verifyMetricsAvailable := func(g Gomega) { + metricsOutput, err := getMetricsOutput() + g.Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + g.Expect(metricsOutput).NotTo(BeEmpty()) + g.Expect(metricsOutput).To(ContainSubstring("< HTTP/1.1 200 OK")) + } + Eventually(verifyMetricsAvailable, 2*time.Minute).Should(Succeed()) + }) + + // +kubebuilder:scaffold:e2e-webhooks-checks + + // TODO: Customize the e2e test suite with scenarios specific to your project. + // Consider applying sample/CR(s) and check their status and/or verifying + // the reconciliation by using the metrics, i.e.: + // metricsOutput, err := getMetricsOutput() + // Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + // Expect(metricsOutput).To(ContainSubstring( + // fmt.Sprintf(`controller_runtime_reconcile_total{controller="%s",result="success"} 1`, + // strings.ToLower(), + // )) + }) +}) + +// serviceAccountToken returns a token for the specified service account in the given namespace. +// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request +// and parsing the resulting token from the API response. +func serviceAccountToken() (string, error) { + const tokenRequestRawString = `{ + "apiVersion": "authentication.k8s.io/v1", + "kind": "TokenRequest" + }` + + // Temporary file to store the token request + secretName := fmt.Sprintf("%s-token-request", serviceAccountName) + tokenRequestFile := filepath.Join("/tmp", secretName) + err := os.WriteFile(tokenRequestFile, []byte(tokenRequestRawString), os.FileMode(0o644)) + if err != nil { + return "", err + } + + var out string + verifyTokenCreation := func(g Gomega) { + // Execute kubectl command to create the token + cmd := exec.Command("kubectl", "create", "--raw", fmt.Sprintf( + "/api/v1/namespaces/%s/serviceaccounts/%s/token", + namespace, + serviceAccountName, + ), "-f", tokenRequestFile) + + output, err := cmd.CombinedOutput() + g.Expect(err).NotTo(HaveOccurred()) + + // Parse the JSON output to extract the token + var token tokenRequest + err = json.Unmarshal(output, &token) + g.Expect(err).NotTo(HaveOccurred()) + + out = token.Status.Token + } + Eventually(verifyTokenCreation).Should(Succeed()) + + return out, err +} + +// getMetricsOutput retrieves and returns the logs from the curl pod used to access the metrics endpoint. +func getMetricsOutput() (string, error) { + By("getting the curl-metrics logs") + cmd := exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + return utils.Run(cmd) +} + +// tokenRequest is a simplified representation of the Kubernetes TokenRequest API response, +// containing only the token field that we need to extract. +type tokenRequest struct { + Status struct { + Token string `json:"token"` + } `json:"status"` +} diff --git a/deploy/k8s-provisioner/test/local/cluster.yaml b/deploy/k8s-provisioner/test/local/cluster.yaml new file mode 100644 index 0000000..2f69d74 --- /dev/null +++ b/deploy/k8s-provisioner/test/local/cluster.yaml @@ -0,0 +1,22 @@ +apiVersion: k8sprovisioner.appstack.io/v1alpha1 +kind: Cluster +metadata: + name: test-cluster-01 + namespace: fleet-default +spec: + infraRef: "dev-environment-v1" # Must match the Infra name above + # 1. Lifecycle + kubernetesVersion: "v1.33.5+rke2r1" # Overrides the template default + # 2. Topology: Control Plane + # false = 1 Node (Using the Standard 4CPU/8GB from _defaults) + # true = 3 Nodes (Using the Standard 4CPU/8GB from _defaults) + controlPlaneHA: false + # 3. Topology: Workers + # These uses the VM settings (Network, User, etc) from Infra, + # but the Hardware Specs defined below. + workerPools: + - name: "app-workers" + quantity: 1 + cpuCores: 4 # Custom Sizing + memoryGb: 16 # Custom Sizing + diskGb: 60 # Custom Sizing \ No newline at end of file diff --git a/deploy/k8s-provisioner/test/local/cluster2.yaml b/deploy/k8s-provisioner/test/local/cluster2.yaml new file mode 100644 index 0000000..ba48c18 --- /dev/null +++ b/deploy/k8s-provisioner/test/local/cluster2.yaml @@ -0,0 +1,22 @@ +apiVersion: k8sprovisioner.appstack.io/v1alpha1 +kind: Cluster +metadata: + name: test-cluster-02 + namespace: fleet-default +spec: + infraRef: "dev-environment-v1" # Must match the Infra name above + # 1. Lifecycle + kubernetesVersion: "v1.32.10+rke2r1" # Overrides the template default + # 2. Topology: Control Plane + # false = 1 Node (Using the Standard 4CPU/8GB from _defaults) + # true = 3 Nodes (Using the Standard 4CPU/8GB from _defaults) + controlPlaneHA: false + # 3. Topology: Workers + # These uses the VM settings (Network, User, etc) from Infra, + # but the Hardware Specs defined below. + workerPools: + - name: "tech-session-workers" + quantity: 1 + cpuCores: 4 # Custom Sizing + memoryGb: 16 # Custom Sizing + diskGb: 60 # Custom Sizing \ No newline at end of file diff --git a/deploy/k8s-provisioner/test/local/infra.yaml b/deploy/k8s-provisioner/test/local/infra.yaml new file mode 100644 index 0000000..d67288c --- /dev/null +++ b/deploy/k8s-provisioner/test/local/infra.yaml @@ -0,0 +1,16 @@ +apiVersion: k8sprovisioner.appstack.io/v1alpha1 +kind: Infra +metadata: + name: dev-environment-v1 + namespace: fleet-default +spec: + # 1. Integration Credentials + cloudCredentialSecret: "cc-mrklm" # Matches your values.yaml example + rancherUrl: "https://rancher-mgmt.product.lan" + harvesterUrl: "https://172.27.27.190:6443" + + # 2. VM Environment Defaults + vmNamespace: "vanderlande" + imageName: "vanderlande/image-qhtpc" # Default image for this environment + networkName: "vanderlande/vm-lan" + sshUser: "rancher" diff --git a/deploy/k8s-provisioner/test/local/local-vsphere-tst.yaml b/deploy/k8s-provisioner/test/local/local-vsphere-tst.yaml new file mode 100644 index 0000000..970db21 --- /dev/null +++ b/deploy/k8s-provisioner/test/local/local-vsphere-tst.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: Config +clusters: +- name: "local" + cluster: + server: "https://rancher.tst.vanderlande.com/k8s/clusters/local" + certificate-authority-data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFaXpDQ\ + 0EzT2dBd0lCQWdJUUNRN294ZDViK21MU3JpLzNDWHhJVnpBTkJna3Foa2lHOXcwQkFRc0ZBREJoD\ + QpNUXN3Q1FZRFZRUUdFd0pWVXpFVk1CTUdBMVVFQ2hNTVJHbG5hVU5sY25RZ1NXNWpNUmt3RndZR\ + FZRUUxFeEIzDQpkM2N1WkdsbmFXTmxjblF1WTI5dE1TQXdIZ1lEVlFRREV4ZEVhV2RwUTJWeWRDQ\ + khiRzlpWVd3Z1VtOXZkQ0JIDQpNakFlRncweE56RXhNREl4TWpJME1qVmFGdzB5TnpFeE1ESXhNa\ + kkwTWpWYU1GNHhDekFKQmdOVkJBWVRBbFZUDQpNUlV3RXdZRFZRUUtFd3hFYVdkcFEyVnlkQ0JKY\ + m1NeEdUQVhCZ05WQkFzVEVIZDNkeTVrYVdkcFkyVnlkQzVqDQpiMjB4SFRBYkJnTlZCQU1URkZSb\ + 1lYZDBaU0JVVEZNZ1VsTkJJRU5CSUVjeE1JSUJJakFOQmdrcWhraUc5dzBCDQpBUUVGQUFPQ0FRO\ + EFNSUlCQ2dLQ0FRRUF4am5nbVBoVmV0QzBiL296YllKZHpPQlVBMXNNb2c0NzAzMGNBUCtQDQoyM\ + 0FOVU44Z3JYRUNMOE5oREVGNEYxUjl0TDB3WTBtY3pIYVIwYTdsWWFubHh0d1dvMXMydUdubnlEc\ + zZtT0NzDQo2NmV3MnczWUVUcjZUYjE0eGdqcHUxZ0dGdEFlZXdhaWtPOUZ1ZDhoeEdKVFN3bjh4Z\ + U5rZktWV3BEMkw0dkZODQozNkZOZ3hlaWxLNmFFNHlrZ0dBek5sb2tUcDZoTk9MQVlwRHlTZExBU\ + Et6dUpTUTdKQ0VaNk8rU0RLeXdJZFhMDQpvTVRucHh1QktHU0c4OE5XVG8zQ0hDT0dtUUVDaWEye\ + XFkUERqZ0xxbkVpWU5qd1FMOHVNcWo4ck92bE1ndmlCDQpjSEE3eHR5KzcvdVlMTjZaUzdWcTEvR\ + i9sVmhWT2Y1ZWo2alpkbUI4NXN6RmJRSURBUUFCbzRJQlFEQ0NBVHd3DQpIUVlEVlIwT0JCWUVGS\ + 1dNL2pMTTZ3OHMxQm5HQ0xnQUpJaGR3OFczTUI4R0ExVWRJd1FZTUJhQUZFNGlWQ0FZDQpsZWJqY\ + nVZUCt2cTVFdTBHRjQ4NU1BNEdBMVVkRHdFQi93UUVBd0lCaGpBZEJnTlZIU1VFRmpBVUJnZ3JCZ\ + 0VGDQpCUWNEQVFZSUt3WUJCUVVIQXdJd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQTBCZ2dyQ\ + mdFRkJRY0JBUVFvDQpNQ1l3SkFZSUt3WUJCUVVITUFHR0dHaDBkSEE2THk5dlkzTndMbVJwWjJsa\ + lpYSjBMbU52YlRCQ0JnTlZIUjhFDQpPekE1TURlZ05hQXpoakZvZEhSd09pOHZZM0pzTXk1a2FXZ\ + HBZMlZ5ZEM1amIyMHZSR2xuYVVObGNuUkhiRzlpDQpZV3hTYjI5MFJ6SXVZM0pzTUQwR0ExVWRJQ\ + VEyTURRd01nWUVWUjBnQURBcU1DZ0dDQ3NHQVFVRkJ3SUJGaHhvDQpkSFJ3Y3pvdkwzZDNkeTVrY\ + VdkcFkyVnlkQzVqYjIwdlExQlRNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUM2DQprbTBLQTRzV\ + GIyVllwRUJtL3VMMkhML3BaWDlCN0wvaGJKNE5jb0JlN1Y1Nm9DbnQ3YWVJbzhzTWpDUldUQ1daD\ + QpEMWRZMCsyS1pPQzFkS2o4ZDFWWFhBdG5qeXRERHVQUGY2L2lvdzBtWVFUTy9HQWcvTUx5TDZDR\ + G0zRnpEQjhWDQp0c0gvYWVNZ1A2cGdEMVhRcXoraGFEbmZuSlRLQnV4aGNwbngzQWRibGV1ZS9Rb\ + lBmMWhIWWE4TCtSdjhQaTVVDQpoNFY5RndIT2ZwaGRNWE94aTE0T3Ftc2lUYmM1Y09zOS91dWtIK\ + 1lWc3VGZFdUbmE2SVZ3MXFoK3RFdHlIMTZSDQp2bWk3cGtxeVpZVUxPUE1JRTdhdnJsalZWQlp1a\ + Wt3QVJ0WTh0Q1ZWNlBwOWwzVmVhZ0JxYjJmZmdxTkp0M0MwDQpUWU5ZUUkrQlhHMVIxY0FCbG9sZ\ + A0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + +users: +- name: "local" + user: + token: "kubeconfig-u-co2u74xluwwnlqq:r55zjkxnfdzzqstkvmx7cqrzvxvb8x4ks6txr27xpp4fkccvl6fxgr" + + +contexts: +- name: "local" + context: + user: "local" + cluster: "local" + +current-context: "local" diff --git a/deploy/k8s-provisioner/test/local/local.yaml b/deploy/k8s-provisioner/test/local/local.yaml new file mode 100644 index 0000000..2e1c639 --- /dev/null +++ b/deploy/k8s-provisioner/test/local/local.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Config +clusters: +- name: "local" + cluster: + server: "https://rancher-mgmt.product.lan/k8s/clusters/local" + certificate-authority-data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ2VENDQ\ + VdPZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQkdNUnd3R2dZRFZRUUtFeE5rZVc1aGJXbGoKY\ + kdsemRHVnVaWEl0YjNKbk1TWXdKQVlEVlFRRERCMWtlVzVoYldsamJHbHpkR1Z1WlhJdFkyRkFNV\ + GMyTkRFegpPVE0yTVRBZUZ3MHlOVEV4TWpZd05qUXlOREZhRncwek5URXhNalF3TmpReU5ERmFNR\ + Vl4SERBYUJnTlZCQW9UCkUyUjVibUZ0YVdOc2FYTjBaVzVsY2kxdmNtY3hKakFrQmdOVkJBTU1IV\ + 1I1Ym1GdGFXTnNhWE4wWlc1bGNpMWoKWVVBeE56WTBNVE01TXpZeE1Ga3dFd1lIS29aSXpqMENBU\ + VlJS29aSXpqMERBUWNEUWdBRWdWUytveHU0RWpnVQpueCt4VEJUbTVzY0s5dHA4Nk5LS1cvenU2e\ + DZYL0k1L3dTWXVNR1FjWTVKenNNbmlGM1JXQzdSQ2RYYi9yU1d2CkxGb1JwYVgzTEtOQ01FQXdEZ\ + 1lEVlIwUEFRSC9CQVFEQWdLa01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWUQKVlIwT0JCWUVGT\ + 1VkcnZLWkF6bWxFLzZpVTZjQkM1WlByQTR6TUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSVFEYgpNN\ + GQ5THE0TzZsNTNlc1A3bHdsWVVOenpEMzNJSXFCeFc4YTQxeWJkaUFJZ1piK0c1MVdZejFkd1lRc\ + 3lZd1pTClRia0prUk41d2lFTUFsWVZiM3NlTS9rPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t" + +users: +- name: "local" + user: + token: "kubeconfig-user-nlnddg6rkq:q9sfb4486q2v8pvlfvnhcn6s4nb5sbfzkgwvfxdfklmr642hkcb7ng" + + +contexts: +- name: "local" + context: + user: "local" + cluster: "local" + +current-context: "local" diff --git a/deploy/k8s-provisioner/test/utils/utils.go b/deploy/k8s-provisioner/test/utils/utils.go new file mode 100644 index 0000000..495bc7f --- /dev/null +++ b/deploy/k8s-provisioner/test/utils/utils.go @@ -0,0 +1,226 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "strings" + + . "github.com/onsi/ginkgo/v2" // nolint:revive,staticcheck +) + +const ( + certmanagerVersion = "v1.19.1" + certmanagerURLTmpl = "https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml" + + defaultKindBinary = "kind" + defaultKindCluster = "kind" +) + +func warnError(err error) { + _, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) +} + +// Run executes the provided command within this context +func Run(cmd *exec.Cmd) (string, error) { + dir, _ := GetProjectDir() + cmd.Dir = dir + + if err := os.Chdir(cmd.Dir); err != nil { + _, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %q\n", err) + } + + cmd.Env = append(os.Environ(), "GO111MODULE=on") + command := strings.Join(cmd.Args, " ") + _, _ = fmt.Fprintf(GinkgoWriter, "running: %q\n", command) + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), fmt.Errorf("%q failed with error %q: %w", command, string(output), err) + } + + return string(output), nil +} + +// UninstallCertManager uninstalls the cert manager +func UninstallCertManager() { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } + + // Delete leftover leases in kube-system (not cleaned by default) + kubeSystemLeases := []string{ + "cert-manager-cainjector-leader-election", + "cert-manager-controller", + } + for _, lease := range kubeSystemLeases { + cmd = exec.Command("kubectl", "delete", "lease", lease, + "-n", "kube-system", "--ignore-not-found", "--force", "--grace-period=0") + if _, err := Run(cmd); err != nil { + warnError(err) + } + } +} + +// InstallCertManager installs the cert manager bundle. +func InstallCertManager() error { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "apply", "-f", url) + if _, err := Run(cmd); err != nil { + return err + } + // Wait for cert-manager-webhook to be ready, which can take time if cert-manager + // was re-installed after uninstalling on a cluster. + cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook", + "--for", "condition=Available", + "--namespace", "cert-manager", + "--timeout", "5m", + ) + + _, err := Run(cmd) + return err +} + +// IsCertManagerCRDsInstalled checks if any Cert Manager CRDs are installed +// by verifying the existence of key CRDs related to Cert Manager. +func IsCertManagerCRDsInstalled() bool { + // List of common Cert Manager CRDs + certManagerCRDs := []string{ + "certificates.cert-manager.io", + "issuers.cert-manager.io", + "clusterissuers.cert-manager.io", + "certificaterequests.cert-manager.io", + "orders.acme.cert-manager.io", + "challenges.acme.cert-manager.io", + } + + // Execute the kubectl command to get all CRDs + cmd := exec.Command("kubectl", "get", "crds") + output, err := Run(cmd) + if err != nil { + return false + } + + // Check if any of the Cert Manager CRDs are present + crdList := GetNonEmptyLines(output) + for _, crd := range certManagerCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// LoadImageToKindClusterWithName loads a local docker image to the kind cluster +func LoadImageToKindClusterWithName(name string) error { + cluster := defaultKindCluster + if v, ok := os.LookupEnv("KIND_CLUSTER"); ok { + cluster = v + } + kindOptions := []string{"load", "docker-image", name, "--name", cluster} + kindBinary := defaultKindBinary + if v, ok := os.LookupEnv("KIND"); ok { + kindBinary = v + } + cmd := exec.Command(kindBinary, kindOptions...) + _, err := Run(cmd) + return err +} + +// GetNonEmptyLines converts given command output string into individual objects +// according to line breakers, and ignores the empty elements in it. +func GetNonEmptyLines(output string) []string { + var res []string + elements := strings.Split(output, "\n") + for _, element := range elements { + if element != "" { + res = append(res, element) + } + } + + return res +} + +// GetProjectDir will return the directory where the project is +func GetProjectDir() (string, error) { + wd, err := os.Getwd() + if err != nil { + return wd, fmt.Errorf("failed to get current working directory: %w", err) + } + wd = strings.ReplaceAll(wd, "/test/e2e", "") + return wd, nil +} + +// UncommentCode searches for target in the file and remove the comment prefix +// of the target content. The target content may span multiple lines. +func UncommentCode(filename, target, prefix string) error { + // false positive + // nolint:gosec + content, err := os.ReadFile(filename) + if err != nil { + return fmt.Errorf("failed to read file %q: %w", filename, err) + } + strContent := string(content) + + idx := strings.Index(strContent, target) + if idx < 0 { + return fmt.Errorf("unable to find the code %q to be uncomment", target) + } + + out := new(bytes.Buffer) + _, err = out.Write(content[:idx]) + if err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + + scanner := bufio.NewScanner(bytes.NewBufferString(target)) + if !scanner.Scan() { + return nil + } + for { + if _, err = out.WriteString(strings.TrimPrefix(scanner.Text(), prefix)); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + // Avoid writing a newline in case the previous line was the last in target. + if !scanner.Scan() { + break + } + if _, err = out.WriteString("\n"); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + } + + if _, err = out.Write(content[idx+len(target):]); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + + // false positive + // nolint:gosec + if err = os.WriteFile(filename, out.Bytes(), 0644); err != nil { + return fmt.Errorf("failed to write file %q: %w", filename, err) + } + + return nil +} diff --git a/deploy/rancher/README.md b/deploy/rancher/README.md new file mode 100644 index 0000000..7d7d5be --- /dev/null +++ b/deploy/rancher/README.md @@ -0,0 +1,31 @@ +# Rancher deployment overview + +## Prerequisites + +* IP address for LoadBalancer must be from the same subnet as Harvester node IP, i.e. 172.27.27.0/24 for teh LB in current implementation to work. +* Due to environment firewall restrictions _https://get.rke.io_ install source doe not work. All these instances must be replaced with alternative _install.sh_ download location _https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh_. + + + +## Helm chart deployment + +An example Helm chart in the following [folder](./helm/rke2). +Two value files are prepared for DHCP and static IP allocation: +* [rancher_values_dhcp.yaml](./helm/rancher_values_dhcp.yaml) +* [rancher_values_static.yaml](./helm/rancher_values_static.yaml) + + +## Fleet bundle deployment + +2 Fleet bundles were prepared based upon Helm chart: +* [mgmt-dhcp.yaml](./deploy/fleet/mgmt-dhcp.yaml) +* [mgmt-static.yaml](./deploy/fleet/mgmt-static.yaml) + +## CAPI based deployment + +**Notes:** +* Not updated to R&D environment and tested yet! +* There is some compatibility issues with vcluster v0.30 version and Harvester. + +Harvester add-on based [deployment](./capi/addon.yaml). +Helm CRD based [deployment](./capi/helmchart.yaml). diff --git a/deploy/rancher/capi/addon.yaml b/deploy/rancher/capi/addon.yaml new file mode 100644 index 0000000..555e2b6 --- /dev/null +++ b/deploy/rancher/capi/addon.yaml @@ -0,0 +1,265 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: Addon +metadata: + labels: + addon.harvesterhci.io/experimental: "true" + name: rancher-embedded + namespace: rancher-embedded +spec: + chart: vcluster + version: 0.19.0 + enabled: false + repo: https://charts.loft.sh + valuesContent: |- + vm_network_name: "k8s-network" + ssh_keypair: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil" + vm_image_name: "ubuntu-22.04" + vm_default_user: "ubuntu" + harvester_vip: "172.27.27.40" + rancher_url: "rancher-mgmt.product.lan" + harvester_kubeconfig_b64: "YXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnCmNsdXN0ZXJzOgotIG5hbWU6ICJsb2NhbCIKICBjbHVzdGVyOgogICAgc2VydmVyOiAiaHR0cHM6Ly8xNzIuMjcuMjcuMTkwL2s4cy9jbHVzdGVycy9sb2NhbCIKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiAiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSjJWRU5EUVwKICAgICAgVmRQWjBGM1NVSkJaMGxDUVVSQlMwSm5aM0ZvYTJwUFVGRlJSRUZxUWtkTlVuZDNSMmRaUkZaUlVVdEZlRTVyWlZjMWFHSlhiR29LWVwKICAgICAga2RzZW1SSFZuVmFXRWwwWWpOS2JrMVRXWGRLUVZsRVZsRlJSRVJDTVd0bFZ6Vm9ZbGRzYW1KSGJIcGtSMVoxV2xoSmRGa3lSa0ZOVlwKICAgICAgR014VDFSVmR3cFBSR2MxVFZSQlpVWjNNSGxPVkVWM1RVUk5lRTVxU1RSTlZFWmhSbmN3ZWs1VVJYZE5SRVY0VG1wSk5FMVVSbUZOUlwKICAgICAgVmw0U0VSQllVSm5UbFpDUVc5VUNrVXlValZpYlVaMFlWZE9jMkZZVGpCYVZ6VnNZMmt4ZG1OdFkzaEtha0ZyUW1kT1ZrSkJUVTFJVlwKICAgICAgMUkxWW0xR2RHRlhUbk5oV0U0d1dsYzFiR05wTVdvS1dWVkJlRTU2VlRWT1ZFRTBUMFJyZUUxR2EzZEZkMWxJUzI5YVNYcHFNRU5CVVwKICAgICAgVmxKUzI5YVNYcHFNRVJCVVdORVVXZEJSVUZWVlU0eFdtUmxURlY2UmdwTWFtSk1Wbk5TT1ZNMGJTdFRTWE5XWlVOa1JVcHVNVGhRYVwKICAgICAgWHBUYm1jMk5rNXhMMWhHVkZaT2RGRnFMMEl3T1hCR01GTXdUVFpMZDJSbmFHUldWM1Y1Q25vMWJFTmlSVzlVVkRaT1EwMUZRWGRFWlwKICAgICAgMWxFVmxJd1VFRlJTQzlDUVZGRVFXZExhMDFCT0VkQk1WVmtSWGRGUWk5M1VVWk5RVTFDUVdZNGQwaFJXVVFLVmxJd1QwSkNXVVZHU1wKICAgICAgRXd2Um5Ga05GRXJaamhpTlhkTFJtSjJUSEpwVTJrMWRtVnpUVUZ2UjBORGNVZFRUVFE1UWtGTlEwRXdaMEZOUlZWRFNVUk5XZ3BVUlwKICAgICAgWFl6VmpjM04zRjZja2RCTDBjNVdVUmxjMlUwVkdaNllWRlhiVmh3UWxWTE9FRm5XWFZJUVdsRlFXeHZaVEpNTVM5RU9VZE1VRGRXU1wKICAgICAgMU13TWxObUNsUnRRbHBxT1d4WVNVeFBSWEJJZDBkR05tSk1WR3hqUFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0IgoKdXNlcnM6Ci0gbmFtZTogImxvY2FsIgogIHVzZXI6CiAgICB0b2tlbjogImt1YmVjb25maWctdXNlci1remo5OWJubmdmOmd4Nm1kdDVmMjlzZjRsY3R2Zm44Mnp4c3NsOXhydzJtNjg1NDhnOWpsN3psbHR2Nm00dHB6ZiIKCgpjb250ZXh0czoKLSBuYW1lOiAibG9jYWwiCiAgY29udGV4dDoKICAgIHVzZXI6ICJsb2NhbCIKICAgIGNsdXN0ZXI6ICJsb2NhbCIKCmN1cnJlbnQtY29udGV4dDogImxvY2FsIgo=" + + vcluster: + image: rancher/k3s:v1.30.6-k3s1 + sync: + ingresses: + enabled: "true" + + init: + manifestsTemplate: |- + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + spec: + chart: cert-manager + createNamespace: true + version: v1.13.0 + repo: https://charts.jetstack.io + targetNamespace: cert-manager + valuesContent: | + installCRDs: true + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: bootstrap-cluster + spec: + chart: cluster-api-operator + repo: https://kubernetes-sigs.github.io/cluster-api-operator + version: v0.14.0 + valuesContent: | + cert-manager: + enabled: true + bootstrap: rke2 + controlPlane: rke2 + --- + apiVersion: v1 + kind: Namespace + metadata: + name: caphv-system + --- + apiVersion: operator.cluster.x-k8s.io/v1alpha2 + kind: InfrastructureProvider + metadata: + name: harvester + namespace: caphv-system + spec: + version: v0.1.4 + fetchConfig: + url: https://github.com/rancher-sandbox/cluster-api-provider-harvester/releases/download/v0.1.4/components.yaml + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: Cluster + metadata: + labels: + ccm: external + cluster.x-k8s.io/cluster-name: rke2-mgmt + cni: external + csi: external + name: rke2-mgmt + namespace: default + spec: + controlPlaneRef: + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + name: rke2-mgmt-control-plane + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + name: rke2-mgmt-hv + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + metadata: + name: rke2-mgmt-hv + namespace: default + spec: + identitySecret: + name: hv-identity-secret + namespace: default + loadBalancerConfig: + ipamType: dhcp + listeners: + - backendPort: 9345 + name: rke2-server + port: 9345 + protocol: TCP + - backendPort: 443 + name: rke2-ingress + port: 443 + protocol: TCP + server: {{ .Values.harvester_vip }} + targetNamespace: default + --- + apiVersion: v1 + data: + kubeconfig: {{ .Values.harvester_kubeconfig_b64 }} + kind: Secret + metadata: + name: hv-identity-secret + namespace: default + --- + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + metadata: + name: rke2-mgmt-control-plane + namespace: default + spec: + agentConfig: + version: v1.29.6+rke2r1 + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-cp-machine + namespace: default + replicas: 3 + serverConfig: + cni: canal + --- + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + metadata: + name: rke2-mgmt-worker + namespace: default + spec: + template: + spec: + agentConfig: + version: v1.29.6+rke2r1 + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: MachineDeployment + metadata: + name: rke2-mgmt-workers + namespace: default + spec: + clusterName: rke2-mgmt + replicas: 0 + selector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + template: + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + name: rke2-mgmt-worker + namespace: default + clusterName: rke2-mgmt + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-wk-machine + namespace: default + version: v1.29.6+rke2r1 + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-wk-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-cp-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: addons.cluster.x-k8s.io/v1beta1 + kind: ClusterResourceSet + metadata: + labels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + name: rke2-mgmt-rancher-crs-0 + namespace: default + spec: + clusterSelector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + resources: + - kind: Secret + name: rancher-namespace + - kind: Secret + name: rancher-helmchart + - kind: Secret + name: certmanager-helmchart + strategy: Reconcile + --- + apiVersion: v1 + kind: Secret + metadata: + name: certmanager-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: cert-manager\n + \ namespace: default \nspec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n runAsNonRoot: + true\n crds:\n enabled: true\n version: v1.16.1\n repo: https://charts.jetstack.io\n + \ chart: cert-manager\n" + type: addons.cluster.x-k8s.io/resource-set + --- + apiVersion: v1 + kind: Secret + metadata: + name: rancher-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: rancher\n + \ namespace: default \nspec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n hostname: {{ .Values.rancher_url }}\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: |-\n global:\n + \ cattle:\n psp:\n enabled: false\n ingress:\n tls:\n + \ source: rancher\n repo: https://releases.rancher.com/server-charts/stable\n + \ chart: rancher\n version: v2.9.1\n" + type: addons.cluster.x-k8s.io/resource-set diff --git a/deploy/rancher/capi/harvester-addon.yaml b/deploy/rancher/capi/harvester-addon.yaml new file mode 100644 index 0000000..f736c4f --- /dev/null +++ b/deploy/rancher/capi/harvester-addon.yaml @@ -0,0 +1,90 @@ +apiVersion: harvesterhci.io/v1beta1 +kind: Addon +metadata: + labels: + addon.harvesterhci.io/experimental: 'true' + name: temp-vlcuster-fix + namespace: temp-vlcuster-fix +spec: + chart: vcluster + enabled: true + repo: https://charts.loft.sh + valuesContent: |- + serviceCIDR: 10.53.0.0/16 + controlPlane: + distro: + k3s: + resources: + limits: + memory: 16096Mi + cpu: 8000m + enabled: true + imagePullPolicy: IfNotPresent + image: + tag: v1.33.4-k3s1 + repository: rancher/k3s + sync: + toHost: + ingresses: + enabled: true + experimental: + deploy: + vcluster: + manifests: |- + apiVersion: v1 + kind: Namespace + metadata: + name: cattle-system + --- + apiVersion: v1 + kind: Namespace + metadata: + name: cert-manager + labels: + certmanager.k8s.io/disable-validation: "true" + helm: + - chart: + name: cert-manager + repo: https://charts.jetstack.io + version: v1.8.0 + release: + name: cert-manager + namespace: cert-manager + values: |- + installCRDs: true + + - chart: + name: rancher + repo: https://releases.rancher.com/server-charts/latest + version: v2.12.0 + release: + name: rancher + namespace: cattle-system + values: |- + hostname: rancher.product.lan + replicas: 1 + bootstrapPassword: ce6XxaBTv9pHpGln + rancherImage: rancher/rancher + ingress: + tls: + source: rancher + global: + cattle: + psp: + enabled: "false" + extraEnv: + - name: CATTLE_AGENT_IMAGE + value: rancher/rancher-agent:v2.12.0 + version: v0.28.0 +status: + conditions: + - lastUpdateTime: '2025-10-24T13:24:37Z' + status: 'True' + type: Completed + - lastUpdateTime: '2025-10-24T13:24:37Z' + status: 'False' + type: InProgress + - lastUpdateTime: '2025-10-24T13:23:08Z' + status: 'False' + type: OperationFailed + status: AddonDeploySuccessful diff --git a/deploy/rancher/capi/helmchart.yaml b/deploy/rancher/capi/helmchart.yaml new file mode 100644 index 0000000..0072763 --- /dev/null +++ b/deploy/rancher/capi/helmchart.yaml @@ -0,0 +1,294 @@ +apiVersion: helm.cattle.io/v1 +kind: HelmChart +metadata: + name: rancher-embedded +spec: + chart: vcluster + version: 0.30.1 + repo: https://charts.loft.sh + valuesContent: | + # vm_network_name: ${VM_NETWORK} + # ssh_keypair: ${VM_SSH_KEYPAIR} + # vm_image_name: ${VM_IMAGE_NAME} + # vm_default_user: ${VM_DEFAULT_USER} + # harvester_vip: ${HARVESTER_VIP} + # rancher_url: ${RANCHER_URL} + # harvester_kubeconfig_b64: ${HARVESTER_KUBECONFIG_B64} + #external: + + controlPlane: + distro: + k3s: + enabled: true + image: + tag: v1.33.5-k3s1 + statefulSet: + scheduling: + podManagementPolicy: OrderedReady + sync: + fromHost: + ingressClasses: + enabled: true + toHost: + ingresses: + enabled: true + + experimental: + + deploy: + vcluster: + + #vm_network_name: "k8s-network" + #ssh_keypair: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil" + #vm_image_name: "ubuntu-22.04" + #vm_default_user: "ubuntu" + #harvester_vip: "172.27.27.40" + #rancher_url: "rancher-mgmt.product.lan" + #harvester_kubeconfig_b64: "YXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnCmNsdXN0ZXJzOgotIG5hbWU6ICJsb2NhbCIKICBjbHVzdGVyOgogICAgc2VydmVyOiAiaHR0cHM6Ly8xNzIuMjcuMjcuMTkwL2s4cy9jbHVzdGVycy9sb2NhbCIKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiAiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSjJWRU5EUVwKICAgICAgVmRQWjBGM1NVSkJaMGxDUVVSQlMwSm5aM0ZvYTJwUFVGRlJSRUZxUWtkTlVuZDNSMmRaUkZaUlVVdEZlRTVyWlZjMWFHSlhiR29LWVwKICAgICAga2RzZW1SSFZuVmFXRWwwWWpOS2JrMVRXWGRLUVZsRVZsRlJSRVJDTVd0bFZ6Vm9ZbGRzYW1KSGJIcGtSMVoxV2xoSmRGa3lSa0ZOVlwKICAgICAgR014VDFSVmR3cFBSR2MxVFZSQlpVWjNNSGxPVkVWM1RVUk5lRTVxU1RSTlZFWmhSbmN3ZWs1VVJYZE5SRVY0VG1wSk5FMVVSbUZOUlwKICAgICAgVmw0U0VSQllVSm5UbFpDUVc5VUNrVXlValZpYlVaMFlWZE9jMkZZVGpCYVZ6VnNZMmt4ZG1OdFkzaEtha0ZyUW1kT1ZrSkJUVTFJVlwKICAgICAgMUkxWW0xR2RHRlhUbk5oV0U0d1dsYzFiR05wTVdvS1dWVkJlRTU2VlRWT1ZFRTBUMFJyZUUxR2EzZEZkMWxJUzI5YVNYcHFNRU5CVVwKICAgICAgVmxKUzI5YVNYcHFNRVJCVVdORVVXZEJSVUZWVlU0eFdtUmxURlY2UmdwTWFtSk1Wbk5TT1ZNMGJTdFRTWE5XWlVOa1JVcHVNVGhRYVwKICAgICAgWHBUYm1jMk5rNXhMMWhHVkZaT2RGRnFMMEl3T1hCR01GTXdUVFpMZDJSbmFHUldWM1Y1Q25vMWJFTmlSVzlVVkRaT1EwMUZRWGRFWlwKICAgICAgMWxFVmxJd1VFRlJTQzlDUVZGRVFXZExhMDFCT0VkQk1WVmtSWGRGUWk5M1VVWk5RVTFDUVdZNGQwaFJXVVFLVmxJd1QwSkNXVVZHU1wKICAgICAgRXd2Um5Ga05GRXJaamhpTlhkTFJtSjJUSEpwVTJrMWRtVnpUVUZ2UjBORGNVZFRUVFE1UWtGTlEwRXdaMEZOUlZWRFNVUk5XZ3BVUlwKICAgICAgWFl6VmpjM04zRjZja2RCTDBjNVdVUmxjMlUwVkdaNllWRlhiVmh3UWxWTE9FRm5XWFZJUVdsRlFXeHZaVEpNTVM5RU9VZE1VRGRXU1wKICAgICAgMU13TWxObUNsUnRRbHBxT1d4WVNVeFBSWEJJZDBkR05tSk1WR3hqUFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0IgoKdXNlcnM6Ci0gbmFtZTogImxvY2FsIgogIHVzZXI6CiAgICB0b2tlbjogImt1YmVjb25maWctdXNlci1remo5OWJubmdmOmd4Nm1kdDVmMjlzZjRsY3R2Zm44Mnp4c3NsOXhydzJtNjg1NDhnOWpsN3psbHR2Nm00dHB6ZiIKCgpjb250ZXh0czoKLSBuYW1lOiAibG9jYWwiCiAgY29udGV4dDoKICAgIHVzZXI6ICJsb2NhbCIKICAgIGNsdXN0ZXI6ICJsb2NhbCIKCmN1cnJlbnQtY29udGV4dDogImxvY2FsIgo=" + + manifestsTemplate: |- + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + spec: + chart: cert-manager + createNamespace: true + version: v1.13.0 + repo: https://charts.jetstack.io + targetNamespace: cert-manager + valuesContent: | + installCRDs: true + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: bootstrap-cluster + spec: + chart: cluster-api-operator + repo: https://kubernetes-sigs.github.io/cluster-api-operator + version: v0.14.0 + valuesContent: | + cert-manager: + enabled: true + bootstrap: rke2 + controlPlane: rke2 + --- + apiVersion: v1 + kind: Namespace + metadata: + name: caphv-system + --- + apiVersion: operator.cluster.x-k8s.io/v1alpha2 + kind: InfrastructureProvider + metadata: + name: harvester + namespace: caphv-system + spec: + version: v0.1.4 + fetchConfig: + url: https://github.com/rancher-sandbox/cluster-api-provider-harvester/releases/download/v0.1.4/components.yaml + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: Cluster + metadata: + labels: + ccm: external + cluster.x-k8s.io/cluster-name: rke2-mgmt + cni: external + csi: external + name: rke2-mgmt + namespace: default + spec: + controlPlaneRef: + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + name: rke2-mgmt-control-plane + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + name: rke2-mgmt-hv + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + metadata: + name: rke2-mgmt-hv + namespace: default + spec: + identitySecret: + name: hv-identity-secret + namespace: default + loadBalancerConfig: + ipamType: dhcp + listeners: + - backendPort: 9345 + name: rke2-server + port: 9345 + protocol: TCP + - backendPort: 443 + name: rke2-ingress + port: 443 + protocol: TCP + #server: {{ .Values.experimental.deploy.vcluster.harvester_vip }} + server: 172.27.27.40 + targetNamespace: default + --- + apiVersion: v1 + data: + #kubeconfig: {{ .Values.experimental.deploy.vcluster.harvester_kubeconfig_b64 }} + kubeconfig: "YXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnCmNsdXN0ZXJzOgotIG5hbWU6ICJsb2NhbCIKICBjbHVzdGVyOgogICAgc2VydmVyOiAiaHR0cHM6Ly8xNzIuMjcuMjcuMTkwL2s4cy9jbHVzdGVycy9sb2NhbCIKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiAiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSjJWRU5EUVwKICAgICAgVmRQWjBGM1NVSkJaMGxDUVVSQlMwSm5aM0ZvYTJwUFVGRlJSRUZxUWtkTlVuZDNSMmRaUkZaUlVVdEZlRTVyWlZjMWFHSlhiR29LWVwKICAgICAga2RzZW1SSFZuVmFXRWwwWWpOS2JrMVRXWGRLUVZsRVZsRlJSRVJDTVd0bFZ6Vm9ZbGRzYW1KSGJIcGtSMVoxV2xoSmRGa3lSa0ZOVlwKICAgICAgR014VDFSVmR3cFBSR2MxVFZSQlpVWjNNSGxPVkVWM1RVUk5lRTVxU1RSTlZFWmhSbmN3ZWs1VVJYZE5SRVY0VG1wSk5FMVVSbUZOUlwKICAgICAgVmw0U0VSQllVSm5UbFpDUVc5VUNrVXlValZpYlVaMFlWZE9jMkZZVGpCYVZ6VnNZMmt4ZG1OdFkzaEtha0ZyUW1kT1ZrSkJUVTFJVlwKICAgICAgMUkxWW0xR2RHRlhUbk5oV0U0d1dsYzFiR05wTVdvS1dWVkJlRTU2VlRWT1ZFRTBUMFJyZUUxR2EzZEZkMWxJUzI5YVNYcHFNRU5CVVwKICAgICAgVmxKUzI5YVNYcHFNRVJCVVdORVVXZEJSVUZWVlU0eFdtUmxURlY2UmdwTWFtSk1Wbk5TT1ZNMGJTdFRTWE5XWlVOa1JVcHVNVGhRYVwKICAgICAgWHBUYm1jMk5rNXhMMWhHVkZaT2RGRnFMMEl3T1hCR01GTXdUVFpMZDJSbmFHUldWM1Y1Q25vMWJFTmlSVzlVVkRaT1EwMUZRWGRFWlwKICAgICAgMWxFVmxJd1VFRlJTQzlDUVZGRVFXZExhMDFCT0VkQk1WVmtSWGRGUWk5M1VVWk5RVTFDUVdZNGQwaFJXVVFLVmxJd1QwSkNXVVZHU1wKICAgICAgRXd2Um5Ga05GRXJaamhpTlhkTFJtSjJUSEpwVTJrMWRtVnpUVUZ2UjBORGNVZFRUVFE1UWtGTlEwRXdaMEZOUlZWRFNVUk5XZ3BVUlwKICAgICAgWFl6VmpjM04zRjZja2RCTDBjNVdVUmxjMlUwVkdaNllWRlhiVmh3UWxWTE9FRm5XWFZJUVdsRlFXeHZaVEpNTVM5RU9VZE1VRGRXU1wKICAgICAgMU13TWxObUNsUnRRbHBxT1d4WVNVeFBSWEJJZDBkR05tSk1WR3hqUFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0IgoKdXNlcnM6Ci0gbmFtZTogImxvY2FsIgogIHVzZXI6CiAgICB0b2tlbjogImt1YmVjb25maWctdXNlci1remo5OWJubmdmOmd4Nm1kdDVmMjlzZjRsY3R2Zm44Mnp4c3NsOXhydzJtNjg1NDhnOWpsN3psbHR2Nm00dHB6ZiIKCgpjb250ZXh0czoKLSBuYW1lOiAibG9jYWwiCiAgY29udGV4dDoKICAgIHVzZXI6ICJsb2NhbCIKICAgIGNsdXN0ZXI6ICJsb2NhbCIKCmN1cnJlbnQtY29udGV4dDogImxvY2FsIgo=" + kind: Secret + metadata: + name: hv-identity-secret + namespace: default + --- + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + metadata: + name: rke2-mgmt-control-plane + namespace: default + spec: + agentConfig: + version: v1.33.5+rke2r1 + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-cp-machine + namespace: default + replicas: 3 + serverConfig: + cni: canal + --- + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + metadata: + name: rke2-mgmt-worker + namespace: default + spec: + template: + spec: + agentConfig: + version: v1.33.5+rke2r1 + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: MachineDeployment + metadata: + name: rke2-mgmt-workers + namespace: default + spec: + clusterName: rke2-mgmt + replicas: 0 + selector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + template: + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + name: rke2-mgmt-worker + namespace: default + clusterName: rke2-mgmt + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-wk-machine + namespace: default + version: v1.29.6+rke2r1 + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-wk-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + #- {{ .Values.experimental.deploy.vcluster.vm_network_name }} + - k8s-network + #sshKeyPair: default/{{ .Values.experimental.deploy.vcluster.ssh_keypair }} + sshKeyPair: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil" + #sshUser: {{ .Values.experimental.deploy.vcluster.vm_default_user }} + sshUser: ubuntu + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.experimental.deploy.vcluster.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-cp-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + #- {{ .Values.experimental.deploy.vcluster.vm_network_name }} + - k8s-network + #sshKeyPair: default/{{ .Values.experimental.deploy.vcluster.ssh_keypair }} + sshKeyPair: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil" + #sshUser: {{ .Values.experimental.deploy.vcluster.vm_default_user }} + sshUser: ubuntu + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.experimental.deploy.vcluster.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: addons.cluster.x-k8s.io/v1beta1 + kind: ClusterResourceSet + metadata: + labels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + name: rke2-mgmt-rancher-crs-0 + namespace: default + spec: + clusterSelector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + resources: + - kind: Secret + name: rancher-namespace + - kind: Secret + name: rancher-helmchart + - kind: Secret + name: certmanager-helmchart + strategy: Reconcile + --- + apiVersion: v1 + kind: Secret + metadata: + name: certmanager-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: cert-manager\n + \ namespace: default \nspec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n runAsNonRoot: + true\n crds:\n enabled: true\n version: v1.16.1\n repo: https://charts.jetstack.io\n + \ chart: cert-manager\n" + type: addons.cluster.x-k8s.io/resource-set + --- + apiVersion: v1 + kind: Secret + metadata: + name: rancher-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: rancher\n + \ namespace: default \nspec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n #hostname: {{ .Values.experimental.deploy.vcluster.rancher_url }}\n + \ hostname: rancher-mgmt.product.lan\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: |-\n global:\n + \ cattle:\n psp:\n enabled: false\n ingress:\n tls:\n + \ source: rancher\n repo: https://releases.rancher.com/server-charts/latest\n + \ chart: rancher\n version: v2.12.3\n" + type: addons.cluster.x-k8s.io/resource-set diff --git a/deploy/rancher/capi/vcluster-v019.yaml b/deploy/rancher/capi/vcluster-v019.yaml new file mode 100644 index 0000000..c99adff --- /dev/null +++ b/deploy/rancher/capi/vcluster-v019.yaml @@ -0,0 +1,255 @@ +#vm_network_name: "k8s-network" +#ssh_keypair: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil" +#vm_image_name: "ubuntu-22.04" +#vm_default_user: "ubuntu" +#harvester_vip: "172.27.27.40" +#rancher_url: "rancher-mgmt.product.lan" +#harvester_kubeconfig_b64: "YXBpVmVyc2lvbjogdjEKa2luZDogQ29uZmlnCmNsdXN0ZXJzOgotIG5hbWU6ICJsb2NhbCIKICBjbHVzdGVyOgogICAgc2VydmVyOiAiaHR0cHM6Ly8xNzIuMjcuMjcuMTkwL2s4cy9jbHVzdGVycy9sb2NhbCIKICAgIGNlcnRpZmljYXRlLWF1dGhvcml0eS1kYXRhOiAiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSjJWRU5EUVwKICAgICAgVmRQWjBGM1NVSkJaMGxDUVVSQlMwSm5aM0ZvYTJwUFVGRlJSRUZxUWtkTlVuZDNSMmRaUkZaUlVVdEZlRTVyWlZjMWFHSlhiR29LWVwKICAgICAga2RzZW1SSFZuVmFXRWwwWWpOS2JrMVRXWGRLUVZsRVZsRlJSRVJDTVd0bFZ6Vm9ZbGRzYW1KSGJIcGtSMVoxV2xoSmRGa3lSa0ZOVlwKICAgICAgR014VDFSVmR3cFBSR2MxVFZSQlpVWjNNSGxPVkVWM1RVUk5lRTVxU1RSTlZFWmhSbmN3ZWs1VVJYZE5SRVY0VG1wSk5FMVVSbUZOUlwKICAgICAgVmw0U0VSQllVSm5UbFpDUVc5VUNrVXlValZpYlVaMFlWZE9jMkZZVGpCYVZ6VnNZMmt4ZG1OdFkzaEtha0ZyUW1kT1ZrSkJUVTFJVlwKICAgICAgMUkxWW0xR2RHRlhUbk5oV0U0d1dsYzFiR05wTVdvS1dWVkJlRTU2VlRWT1ZFRTBUMFJyZUUxR2EzZEZkMWxJUzI5YVNYcHFNRU5CVVwKICAgICAgVmxKUzI5YVNYcHFNRVJCVVdORVVXZEJSVUZWVlU0eFdtUmxURlY2UmdwTWFtSk1Wbk5TT1ZNMGJTdFRTWE5XWlVOa1JVcHVNVGhRYVwKICAgICAgWHBUYm1jMk5rNXhMMWhHVkZaT2RGRnFMMEl3T1hCR01GTXdUVFpMZDJSbmFHUldWM1Y1Q25vMWJFTmlSVzlVVkRaT1EwMUZRWGRFWlwKICAgICAgMWxFVmxJd1VFRlJTQzlDUVZGRVFXZExhMDFCT0VkQk1WVmtSWGRGUWk5M1VVWk5RVTFDUVdZNGQwaFJXVVFLVmxJd1QwSkNXVVZHU1wKICAgICAgRXd2Um5Ga05GRXJaamhpTlhkTFJtSjJUSEpwVTJrMWRtVnpUVUZ2UjBORGNVZFRUVFE1UWtGTlEwRXdaMEZOUlZWRFNVUk5XZ3BVUlwKICAgICAgWFl6VmpjM04zRjZja2RCTDBjNVdVUmxjMlUwVkdaNllWRlhiVmh3UWxWTE9FRm5XWFZJUVdsRlFXeHZaVEpNTVM5RU9VZE1VRGRXU1wKICAgICAgMU13TWxObUNsUnRRbHBxT1d4WVNVeFBSWEJJZDBkR05tSk1WR3hqUFFvdExTMHRMVVZPUkNCRFJWSlVTVVpKUTBGVVJTMHRMUzB0IgoKdXNlcnM6Ci0gbmFtZTogImxvY2FsIgogIHVzZXI6CiAgICB0b2tlbjogImt1YmVjb25maWctdXNlci1remo5OWJubmdmOmd4Nm1kdDVmMjlzZjRsY3R2Zm44Mnp4c3NsOXhydzJtNjg1NDhnOWpsN3psbHR2Nm00dHB6ZiIKCgpjb250ZXh0czoKLSBuYW1lOiAibG9jYWwiCiAgY29udGV4dDoKICAgIHVzZXI6ICJsb2NhbCIKICAgIGNsdXN0ZXI6ICJsb2NhbCIKCmN1cnJlbnQtY29udGV4dDogImxvY2FsIgo=" + + +vcluster: + image: rancher/k3s:v1.33.5-k3s1 + + +sync: + ingresses: + enabled: true + +init: + manifestsTemplate: |- + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + spec: + chart: cert-manager + createNamespace: true + version: v1.13.0 + repo: https://charts.jetstack.io + targetNamespace: cert-manager + valuesContent: | + installCRDs: true + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: bootstrap-cluster + spec: + chart: cluster-api-operator + repo: https://kubernetes-sigs.github.io/cluster-api-operator + version: v0.14.0 + valuesContent: | + cert-manager: + enabled: true + bootstrap: rke2 + controlPlane: rke2 + --- + apiVersion: v1 + kind: Namespace + metadata: + name: caphv-system + --- + apiVersion: operator.cluster.x-k8s.io/v1alpha2 + kind: InfrastructureProvider + metadata: + name: harvester + namespace: caphv-system + spec: + version: v0.1.4 + fetchConfig: + url: https://github.com/rancher-sandbox/cluster-api-provider-harvester/releases/download/v0.1.4/components.yaml + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: Cluster + metadata: + labels: + ccm: external + cluster.x-k8s.io/cluster-name: rke2-mgmt + cni: external + csi: external + name: rke2-mgmt + namespace: default + spec: + controlPlaneRef: + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + name: rke2-mgmt-control-plane + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + name: rke2-mgmt-hv + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + metadata: + name: rke2-mgmt-hv + namespace: default + spec: + identitySecret: + name: hv-identity-secret + namespace: default + loadBalancerConfig: + ipamType: dhcp + listeners: + - backendPort: 9345 + name: rke2-server + port: 9345 + protocol: TCP + - backendPort: 443 + name: rke2-ingress + port: 443 + protocol: TCP + server: {{ .Values.harvester_vip }} + targetNamespace: default + --- + apiVersion: v1 + data: + kubeconfig: {{ .Values.harvester_kubeconfig_b64 }} + kind: Secret + metadata: + name: hv-identity-secret + namespace: default + --- + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + metadata: + name: rke2-mgmt-control-plane + namespace: default + spec: + agentConfig: + version: v1.33.5+rke2r1 + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-cp-machine + namespace: default + replicas: 3 + serverConfig: + cni: canal + --- + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + metadata: + name: rke2-mgmt-worker + namespace: default + spec: + template: + spec: + agentConfig: + version: v1.33.5+rke2r1 + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: MachineDeployment + metadata: + name: rke2-mgmt-workers + namespace: default + spec: + clusterName: rke2-mgmt + replicas: 0 + selector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + template: + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + name: rke2-mgmt-worker + namespace: default + clusterName: rke2-mgmt + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-wk-machine + namespace: default + version: v1.29.6+rke2r1 + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-wk-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-cp-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: addons.cluster.x-k8s.io/v1beta1 + kind: ClusterResourceSet + metadata: + labels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + name: rke2-mgmt-rancher-crs-0 + namespace: default + spec: + clusterSelector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + resources: + - kind: Secret + name: rancher-namespace + - kind: Secret + name: rancher-helmchart + - kind: Secret + name: certmanager-helmchart + strategy: Reconcile + --- + apiVersion: v1 + kind: Secret + metadata: + name: certmanager-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: cert-manager\n + \ namespace: default \nspec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n runAsNonRoot: + true\n crds:\n enabled: true\n version: v1.16.1\n repo: https://charts.jetstack.io\n + \ chart: cert-manager\n" + type: addons.cluster.x-k8s.io/resource-set + --- + apiVersion: v1 + kind: Secret + metadata: + name: rancher-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: rancher\n + \ namespace: default \nspec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n hostname: {{ .Values.rancher_url }}\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: |-\n global:\n + \ cattle:\n psp:\n enabled: false\n ingress:\n tls:\n + \ source: rancher\n repo: https://releases.rancher.com/server-charts/latest\n + \ chart: rancher\n version: v2.12.3\n" + type: addons.cluster.x-k8s.io/resource-set diff --git a/deploy/rancher/capi/vcluster.yaml b/deploy/rancher/capi/vcluster.yaml new file mode 100644 index 0000000..93755df --- /dev/null +++ b/deploy/rancher/capi/vcluster.yaml @@ -0,0 +1,256 @@ +controlPlane: + distro: + k3s: + enabled: true + image: + tag: v1.33.5-k3s1 + statefulSet: + scheduling: + podManagementPolicy: OrderedReady +experimental: + deploy: + vcluster: + manifestsTemplate: |- + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + spec: + chart: cert-manager + createNamespace: true + version: v1.13.0 + repo: https://charts.jetstack.io + targetNamespace: cert-manager + valuesContent: | + installCRDs: true + --- + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: bootstrap-cluster + spec: + chart: cluster-api-operator + repo: https://kubernetes-sigs.github.io/cluster-api-operator + version: v0.14.0 + valuesContent: | + cert-manager: + enabled: true + bootstrap: rke2 + controlPlane: rke2 + --- + apiVersion: v1 + kind: Namespace + metadata: + name: caphv-system + --- + apiVersion: operator.cluster.x-k8s.io/v1alpha2 + kind: InfrastructureProvider + metadata: + name: harvester + namespace: caphv-system + spec: + version: v0.1.4 + fetchConfig: + url: https://github.com/rancher-sandbox/cluster-api-provider-harvester/releases/download/v0.1.4/components.yaml + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: Cluster + metadata: + labels: + ccm: external + cluster.x-k8s.io/cluster-name: rke2-mgmt + cni: external + csi: external + name: rke2-mgmt + namespace: default + spec: + controlPlaneRef: + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + name: rke2-mgmt-control-plane + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + name: rke2-mgmt-hv + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterCluster + metadata: + name: rke2-mgmt-hv + namespace: default + spec: + identitySecret: + name: hv-identity-secret + namespace: default + loadBalancerConfig: + ipamType: dhcp + listeners: + - backendPort: 9345 + name: rke2-server + port: 9345 + protocol: TCP + - backendPort: 443 + name: rke2-ingress + port: 443 + protocol: TCP + server: {{ .Values.harvester_vip }} + targetNamespace: default + --- + apiVersion: v1 + data: + kubeconfig: {{ .Values.harvester_kubeconfig_b64 }} + kind: Secret + metadata: + name: hv-identity-secret + namespace: default + --- + apiVersion: controlplane.cluster.x-k8s.io/v1alpha1 + kind: RKE2ControlPlane + metadata: + name: rke2-mgmt-control-plane + namespace: default + spec: + agentConfig: + version: v1.33.5+rke2r1 + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-cp-machine + namespace: default + replicas: 3 + serverConfig: + cni: canal + --- + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + metadata: + name: rke2-mgmt-worker + namespace: default + spec: + template: + spec: + agentConfig: + version: v1.33.5+rke2r1 + --- + apiVersion: cluster.x-k8s.io/v1beta1 + kind: MachineDeployment + metadata: + name: rke2-mgmt-workers + namespace: default + spec: + clusterName: rke2-mgmt + replicas: 0 + selector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + template: + spec: + bootstrap: + configRef: + apiVersion: bootstrap.cluster.x-k8s.io/v1alpha1 + kind: RKE2ConfigTemplate + name: rke2-mgmt-worker + namespace: default + clusterName: rke2-mgmt + infrastructureRef: + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + name: rke2-mgmt-wk-machine + namespace: default + version: v1.29.6+rke2r1 + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-wk-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 + kind: HarvesterMachineTemplate + metadata: + name: rke2-mgmt-cp-machine + namespace: default + spec: + template: + spec: + cpu: 2 + memory: 16Gi + networks: + - {{ .Values.vm_network_name }} + sshKeyPair: default/{{ .Values.ssh_keypair }} + sshUser: {{ .Values.vm_default_user }} + volumes: + - bootOrder: 0 + imageName: default/{{ .Values.vm_image_name }} + volumeSize: 40Gi + volumeType: image + --- + apiVersion: addons.cluster.x-k8s.io/v1beta1 + kind: ClusterResourceSet + metadata: + labels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + name: rke2-mgmt-rancher-crs-0 + namespace: default + spec: + clusterSelector: + matchLabels: + cluster.x-k8s.io/cluster-name: rke2-mgmt + resources: + - kind: Secret + name: rancher-namespace + - kind: Secret + name: rancher-helmchart + - kind: Secret + name: certmanager-helmchart + strategy: Reconcile + --- + apiVersion: v1 + kind: Secret + metadata: + name: certmanager-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: cert-manager\n + \ namespace: default \nspec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n runAsNonRoot: + true\n crds:\n enabled: true\n version: v1.16.1\n repo: https://charts.jetstack.io\n + \ chart: cert-manager\n" + type: addons.cluster.x-k8s.io/resource-set + --- + apiVersion: v1 + kind: Secret + metadata: + name: rancher-helmchart + namespace: default + stringData: + data: "apiVersion: helm.cattle.io/v1\nkind: HelmChart\nmetadata:\n name: rancher\n + \ namespace: default \nspec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n hostname: {{ .Values.rancher_url }}\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: |-\n global:\n + \ cattle:\n psp:\n enabled: false\n ingress:\n tls:\n + \ source: rancher\n repo: https://releases.rancher.com/server-charts/latest\n + \ chart: rancher\n version: v2.12.3\n" + type: addons.cluster.x-k8s.io/resource-set +sync: + fromHost: + ingressClasses: + enabled: true + toHost: + ingresses: + enabled: true diff --git a/deploy/rancher/fleet/mgmt-dhcp.yaml b/deploy/rancher/fleet/mgmt-dhcp.yaml new file mode 100644 index 0000000..49da4a8 --- /dev/null +++ b/deploy/rancher/fleet/mgmt-dhcp.yaml @@ -0,0 +1,475 @@ +apiVersion: fleet.cattle.io/v1alpha1 +kind: Bundle +metadata: + name: mgmt-cluster + namespace: fleet-local +spec: + helm: + chart: ./rke2 + # releaseName: rke2-mgmt + values: + cluster_name: rke2-mgmt + control_plane: + cpu_count: 8 + files: + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + namespace: default + spec: + bootstrap: true + targetNamespace: cert-manager + createNamespace: true + valuesContent: |- + securityContext: + runAsNonRoot: true + crds: + enabled: true + version: v1.16.1 + repo: https://charts.jetstack.io + chart: cert-manager + owner: root + path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: rancher + namespace: default + spec: + bootstrap: false + targetNamespace: cattle-system + createNamespace: true + set: + hostname: rancher-mgmt.product.lan + replicas: 3 + bootstrapPassword: admin + valuesContent: |- + global: + cattle: + psp: + enabled: false + ingress: + tls: + source: rancher + repo: https://releases.rancher.com/server-charts/stable + chart: rancher + version: v2.12.3 + owner: root + path: /var/lib/rancher/rke2/server/manifests/rancher.yaml + ipam: dhcp + loadbalancer_gateway: 172.27.27.1 + loadbalancer_subnet: 172.27.27.0/24 + memory_gb: 16 + network: + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + node_count: 3 + vip: 172.27.27.40 + network_name: k8s-network + registry_config: + configs: + rgcrprod.azurecr.us: + auth: + password: test + username: test + rke2_version: v1.33.4+rke2r1 + ssh_pub_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil + system_default_registry: "" + vm: + airgapped_image: false + image: ubuntu-22.04 + qemu_agent_enable: true + qemu_agent_install: true + worker: + node_count: 0 + storage: + class: longhorn-image-99dd5 # StorageClass for image ubuntu-22.04 + valuesFiles: + - values.yaml + + resources: + - content: |2- + helm: + chart: ./rke2 + releaseName: rke2-mgmt + valuesFiles: + - values.yaml + name: fleet.yaml + - content: |- + apiVersion: v2 + name: rke2-cluster + description: RKE2 cluster designed for usage directly on Harvester + + type: application + version: 0.1.1 + appVersion: 0.1.1 + name: rke2/Chart.yaml + - content: "{{- range $i := until (.Values.control_plane.node_count | int) }}\n---\napiVersion: + v1\nkind: Secret\nmetadata:\n name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit\n + \ namespace: {{ $.Values.cluster_namespace }}\nstringData:\n userdata: |\n + \ #cloud-config\n {{- if $.Values.vm.qemu_agent_install }}\n package_update: + true\n packages:\n - qemu-guest-agent\n {{- end }}\n write_files: + \n {{- if $.Values.control_plane.files }}\n{{ $.Values.control_plane.files + | toYaml | indent 4 }}\n {{- end }}\n - path: /etc/rancher/rke2/config.yaml\n + \ owner: root\n content: |\n token: {{ $.Values.shared_token + }}\n {{- if ne $i 0 }}\n server: https://{{ $.Values.control_plane.vip + }}:9345\n {{- end }}\n system-default-registry: {{ $.Values.system_default_registry + }}\n tls-san:\n - {{ $.Values.cluster_name }}-cp-{{ $i }}\n + \ - {{ $.Values.control_plane.vip }}\n secrets-encryption: true\n + \ write-kubeconfig-mode: 0640\n use-service-account-credentials: + true\n {{- if hasKey $.Values \"registry_config\" }}\n - path: /etc/rancher/rke2/registries.yaml\n + \ owner: root\n content: |-\n{{ $.Values.registry_config | toYaml | + indent 8 }}\n {{- end }}\n - path: /etc/hosts\n owner: root\n content: + |\n 127.0.0.1 localhost\n 127.0.0.1 {{$.Values.cluster_name }}-cp-{{ + $i }}\n runcmd:\n {{- if $.Values.vm.qemu_agent_enable }}\n - - systemctl\n + \ - enable\n - '--now'\n - qemu-guest-agent.service\n {{- end + }}\n {{- if not $.Values.vm.airgapped_image }}\n - mkdir -p /var/lib/rancher/rke2-artifacts + && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh\n + \ {{- end}}\n - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} /var/lib/rancher/install.sh\n + \ - systemctl enable rke2-server.service\n - useradd -r -c \"etcd user\" + -s /sbin/nologin -M etcd -U\n - systemctl start rke2-server.service\n ssh_authorized_keys: + \n - {{ $.Values.ssh_pub_key }}\n {{- if ne $.Values.control_plane.ipam + \"dhcp\" }}\n {{- if hasKey $.Values.control_plane \"network\" }}\n networkdata: + |\n{{ index $.Values.control_plane.network $i | indent 4 }}\n {{- end}}\n {{- + else}}\n networkdata: \"\"\n {{- end}}\n{{- end}}" + name: rke2/templates/rke2_cp_secret.yaml + - content: |- + {{- range $i := until (.Values.control_plane.node_count | int) }} + --- + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + namespace: {{ $.Values.cluster_namespace }} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ $.Values.control_plane.node_disk_gb }}Gi + storageClassName: {{ $.Values.storage.class }} + volumeMode: Block + --- + apiVersion: kubevirt.io/v1 + kind: VirtualMachine + metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + # harvesterhci.io/volumeClaimTemplates: | + # [{"metadata":{"name":"{{ $.Values.cluster_name }}-cp-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"{{ $.Values.control_plane.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + # network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-cp-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-cp-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.control_plane.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.control_plane.memory_gb }}Gi + cpu: {{ $.Values.control_plane.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-cp-{{ $i }} + networks: + - name: default + multus: + networkName: default/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + networkDataSecretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + affinity: {} + terminationGracePeriodSeconds: 120 + {{- end }} + name: rke2/templates/rke2_cp_vm.yaml + - content: |- + --- + apiVersion: loadbalancer.harvesterhci.io/v1beta1 + kind: IPPool + metadata: + name: {{ $.Values.cluster_name }}-pool + spec: + ranges: + - gateway: {{ .Values.control_plane.loadbalancer_gateway }} + rangeEnd: {{ .Values.control_plane.vip }} + rangeStart: {{ .Values.control_plane.vip }} + subnet: {{ .Values.control_plane.loadbalancer_subnet }} + selector: {} + --- + apiVersion: loadbalancer.harvesterhci.io/v1beta1 + kind: LoadBalancer + metadata: + name: {{ .Values.cluster_name }}-lb + namespace: default + spec: + healthCheck: + failureThreshold: 2 + port: 6443 + successThreshold: 3 + timeoutSeconds: 5 + periodSeconds: 5 + ipam: pool + ipPool: {{ .Values.cluster_name }}-pool + listeners: + - name: k8s-api + port: 6443 + protocol: TCP + backendPort: 6443 + - name: ingress + port: 443 + protocol: TCP + backendPort: 443 + - name: join + port: 9345 + protocol: TCP + backendPort: 9345 + workloadType: vm + backendServerSelector: + harvesterhci.io/vmName: + {{- range $i := until (.Values.control_plane.node_count | int)}} + - {{ $.Values.cluster_name }}-cp-{{ $i }} + {{- end}} + name: rke2/templates/rke2_lb.yaml + - content: "{{- range $i := until (.Values.worker.node_count | int) }}\n---\napiVersion: + v1\nkind: Secret\nmetadata:\n name: {{ $.Values.cluster_name }}-worker-{{ $i + }}-cloudinit\n namespace: {{ $.Values.cluster_namespace }}\nstringData:\n userdata: + |\n #cloud-config\n {{- if $.Values.vm.qemu_agent_install }}\n package_update: + true\n packages:\n - qemu-guest-agent\n {{- end }}\n write_files: + \n {{- if $.Values.worker.files }}\n{{ $.Values.worker.files | toYaml | indent + 4 }}\n {{- end }}\n - path: /etc/rancher/rke2/config.yaml\n owner: + root\n content: |\n token: {{ $.Values.shared_token }}\n {{- + if ne $i 0 }}\n server: https://{{ $.Values.control_plane.vip }}:9345\n + \ {{- end }}\n system-default-registry: {{ $.Values.system_default_registry + }}\n secrets-encryption: true\n write-kubeconfig-mode: 0640\n + \ use-service-account-credentials: true\n {{- if hasKey $.Values \"registry_config\" + }}\n - path: /etc/rancher/rke2/registries.yaml\n owner: root\n content: + |-\n{{ $.Values.registry_config | toYaml | indent 8 }}\n {{- end }}\n - + path: /etc/hosts\n owner: root\n content: |\n 127.0.0.1 localhost\n + \ 127.0.0.1 {{$.Values.cluster_name }}-worker-{{ $i }}\n runcmd:\n + \ {{- if $.Values.vm.qemu_agent_enable }}\n - - systemctl\n - enable\n + \ - '--now'\n - qemu-guest-agent.service\n {{- end }}\n {{- if + not $.Values.vm.airgapped_image }}\n - mkdir -p /var/lib/rancher/rke2-artifacts + && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh\n + \ {{- end}}\n - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} INSTALL_RKE2_TYPE=\"agent\" + /var/lib/rancher/install.sh\n - systemctl enable rke2-server.service\n - + systemctl start rke2-server.service\n ssh_authorized_keys: \n - {{ $.Values.ssh_pub_key + }}\n {{- if ne $.Values.worker.ipam \"dhcp\" }}\n {{- if hasKey $.Values.worker + \"network\" }}\n networkdata: |\n{{ index $.Values.worker.network $i | indent + 4 }}\n {{- end}}\n {{- else}}\n networkdata: \"\"\n {{- end}}\n{{- end}}" + name: rke2/templates/rke2_worker_secret.yaml + - content: |- + {{- range $i := until (.Values.worker.node_count | int) }} + --- + apiVersion: kubevirt.io/v1 + kind: VirtualMachine + metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + harvesterhci.io/volumeClaimTemplates: | + [{"metadata":{"name":"{{ $.Values.cluster_name }}-worker-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteMany"],"resources":{"requests":{"storage":"{{ $.Values.worker.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-worker-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-worker-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.worker.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.worker.memory_gb }}Gi + cpu: {{ $.Values.worker.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-worker-{{ $i }} + networks: + - name: default + multus: + networkName: default/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-worker-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-worker-{{ $i }}-cloudinit + networkData: "" + affinity: {} + terminationGracePeriodSeconds: 120 + {{- end }} + name: rke2/templates/rke2_worker_vm.yaml + - content: "cluster_name: mycluster\ncluster_namespace: default\n\nshared_token: + insecuretoken\nsystem_default_registry: \"\" #! empty value: use embedded + default\n #! non-empty value: use as regsitry + to source rke2 runtime image from\n #! if your + VM image contains the tarballs for RKE2, it will use those first\nrke2_version: + v1.26.10+rke2r2\n\nssh_pub_key: \"\" #! the public ssh key + to inject onto each node, required if you want to fetch a kubeconfig\n\n# registry_config:\n# + \ configs:\n# \"rgcrprod.azurecr.us\":\n# auth:\n# username: + test\n# password: test\n\nvm:\n image_namespace: default #! + namespace in your harvester cluster containing the vm base image\n image: ubuntu + \ #! name of base vm image to use for your RKE2 nodes\n os: + linux\n distro: ubuntu #! flag used for specific cloud-init + code tied to Ubuntu vs others (netplan)\n uefi_enabled: true\n qemu_agent_install: + true #! flag for installation of the qemu-agent service (Requires internet)\n + \ qemu_agent_enable: true #! flag for enabling the qemu-agent\n airgapped_image: + false #! flag to alert helm that your VM image already has the RKE2 + install script (and does not need to download it)\n\n\nnetwork_name: host\n\ncontrol_plane:\n + \ node_count: 1\n cpu_count: 4\n memory_gb: 8\n node_disk_gb: 40\n loadbalancer_gateway: + 10.10.0.1\n loadbalancer_subnet: 10.10.0.0/24\n files: []\n # files:\n # + - path: /tmp/test\n # owner: root\n # content: |\n # created a file\n\n + \ vip: #! this is the VIP for the Harvester LoadBalancer + object, ensure it is a routable IP\n ipam: dhcp #! this + can be dhcp or static, static requires an equal amount of cloud-init network-data + entries\n\n # network:\n # - | #! ubuntu example\n # network:\n # version: + 2\n # renderer: networkd\n # ethernets:\n # enp1s0:\n # dhcp4: + no\n # addresses: [ \"10.10.0.6/24\" ]\n # gateway4: 10.10.0.1\n + \ # nameservers:\n # addresses: \n # - 10.10.0.1\n\nworker:\n + \ node_count: 1\n cpu_count: 4\n memory_gb: 8\n node_disk_gb: 40\n files: + []\n # files:\n # - path: /tmp/test\n # owner: root\n # content: |\n + \ # created a file\n\n ipam: dhcp #! this can be dhcp + or static, static requires an equal amount of cloud-init network-data entries\n\n + \ # network:\n # - |\n # network:\n # version: 2\n # renderer: + networkd\n # ethernets:\n # enp1s0:\n # dhcp4: no\n # + \ addresses: [ \"10.10.0.20/24\" ]\n # gateway4: 10.10.0.1\n + \ # nameservers:\n # addresses: \n # - 10.10.0.1\n" + name: rke2/values.yaml + - content: "cluster_name: rke2-mgmt\nsystem_default_registry: \"\"\n\nrke2_version: + v1.29.6+rke2r1\n\nvm:\n image: ubuntu\n qemu_agent_install: true \n + \ qemu_agent_enable: true \n airgapped_image: false \nnetwork_name: + lab-workload\nssh_pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDK3vpDMfNKbXTkpOwC77k5xvEpUAcNyJa6pYT17YMbzvHuugSJRiouLElDtpqktto6plkDdrTRXnkDA3aVxUycCl/4IrnCEehlg8LGgFxKASNeXQYL0URIWRDicyJaolg5bFdcu3gYTA0JBtApiebrml6bj9cJGnS8lqRK9wmWIFv5lPICcrZMsw1AIRhghGI5BupUnttD+muHspAiGfjTbiiCvKo3fLmEMQ9pt/46wQuPbzOCVChpJByVG9AKO9IpdkOGgKeuy2y98ZxJIHBAx4B49jDfA8NNfyEBIdgiIvlv6QXgjFbazI5buLYM/RK36kf9JjYNBySZJuA3VMbHnWmWvZYBQUA6ypVMc4Wzvd3hhFmNQn1W+NEHl6v+bCDeo5QIv5dkpIoDgJd8CvWQ42bb2bi7zyO32v2zfaW03eDCeopFAKditMPhjqai0S2W4LRt7dRKEOCvUqPFYqZ99nBk1mmTWG8Gpp7VA/+shn171Yc/wDCwBcEyciqOYNtnW55O3eCiBHsnBcEFKy80zHJ1jckDSluypwBrsooYV5WKS8O+jqGyYfdruJ8oUCPw72b0JHs5AmFCRuhzOU6cZP6Ynghs1SkdVtq722uFjmDUR0X8+hoIZDEWutw6+91YhwnodA3MmGHtInlY+URqdz6TltOMP2X2vSMohnh2zQ==\n\nregistry_config:\n + \ configs:\n \"rgcrprod.azurecr.us\":\n auth:\n username: test\n + \ password: test\n\ncontrol_plane:\n vip: 10.2.0.20 \n loadbalancer_gateway: + 10.2.0.1\n loadbalancer_subnet: 10.2.0.0/24\n \n node_count: 3 \n cpu_count: + 8\n memory_gb: 16\n\n ipam: static\n network:\n - |\n network:\n version: + 2\n renderer: networkd\n ethernets:\n enp1s0:\n dhcp4: + no\n addresses: [ \"10.2.0.21/24\" ]\n gateway4: 10.2.0.1\n + \ nameservers:\n addresses: \n - 10.2.0.1\n - + |\n network:\n version: 2\n renderer: networkd\n ethernets:\n + \ enp1s0:\n dhcp4: no\n addresses: [ \"10.2.0.22/24\" + ]\n gateway4: 10.2.0.1\n nameservers:\n addresses: + \n - 10.2.0.1\n - |\n network:\n version: 2\n renderer: + networkd\n ethernets:\n enp1s0:\n dhcp4: no\n addresses: + [ \"10.2.0.23/24\" ]\n gateway4: 10.2.0.1\n nameservers:\n + \ addresses: \n - 10.2.0.1\n files:\n - path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml\n + \ owner: root\n content: |\n apiVersion: helm.cattle.io/v1\n kind: + HelmChart\n metadata:\n name: cert-manager\n namespace: default + \ \n spec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n + \ runAsNonRoot: true\n crds:\n enabled: true\n + \ version: v1.16.1\n repo: https://charts.jetstack.io\n chart: + cert-manager\n - path: /var/lib/rancher/rke2/server/manifests/rancher.yaml\n + \ owner: root\n content: |\n apiVersion: helm.cattle.io/v1\n kind: + HelmChart\n metadata:\n name: rancher\n namespace: default + \ \n spec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n hostname: rancher.lab.sienarfleet.systems\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: + |-\n global:\n cattle:\n psp:\n enabled: + false\n ingress:\n tls:\n source: rancher\n + \ repo: https://releases.rancher.com/server-charts/stable\n chart: + rancher\n version: v2.10.1\nworker:\n node_count: 0" + name: values.yaml + targetRestrictions: + - clusterName: local + targets: + - clusterName: local + ignore: {} diff --git a/deploy/rancher/fleet/mgmt-static.yaml b/deploy/rancher/fleet/mgmt-static.yaml new file mode 100644 index 0000000..8710084 --- /dev/null +++ b/deploy/rancher/fleet/mgmt-static.yaml @@ -0,0 +1,493 @@ +apiVersion: fleet.cattle.io/v1alpha1 +kind: Bundle +metadata: + name: mgmt-cluster + namespace: fleet-local +spec: + helm: + chart: ./rke2 + # releaseName: rke2-mgmt + values: + cluster_name: rke2-mgmt + control_plane: + cpu_count: 8 + files: + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + namespace: default + spec: + bootstrap: true + targetNamespace: cert-manager + createNamespace: true + valuesContent: |- + securityContext: + runAsNonRoot: true + crds: + enabled: true + version: v1.16.1 + repo: https://charts.jetstack.io + chart: cert-manager + owner: root + path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: rancher + namespace: default + spec: + bootstrap: false + targetNamespace: cattle-system + createNamespace: true + set: + hostname: rancher-mgmt.product.lan + replicas: 3 + bootstrapPassword: admin + valuesContent: |- + global: + cattle: + psp: + enabled: false + ingress: + tls: + source: rancher + repo: https://releases.rancher.com/server-charts/stable + chart: rancher + version: v2.12.3 + owner: root + path: /var/lib/rancher/rke2/server/manifests/rancher.yaml + ipam: static + loadbalancer_gateway: 172.27.27.1 + loadbalancer_subnet: 172.27.27.0/24 + memory_gb: 16 + network: + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.41/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.42/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.43/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + node_count: 3 + vip: 172.27.27.40 + network_name: k8s-network + registry_config: + configs: + rgcrprod.azurecr.us: + auth: + password: test + username: test + rke2_version: v1.33.4+rke2r1 + ssh_pub_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil + system_default_registry: "" + vm: + airgapped_image: false + image: ubuntu-22.04 + qemu_agent_enable: true + qemu_agent_install: true + worker: + node_count: 0 + storage: + class: longhorn-image-99dd5 # StorageClass for image ubuntu-22.04 + valuesFiles: + - values.yaml + + resources: + - content: |2- + helm: + chart: ./rke2 + releaseName: rke2-mgmt + valuesFiles: + - values.yaml + name: fleet.yaml + - content: |- + apiVersion: v2 + name: rke2-cluster + description: RKE2 cluster designed for usage directly on Harvester + + type: application + version: 0.1.1 + appVersion: 0.1.1 + name: rke2/Chart.yaml + - content: "{{- range $i := until (.Values.control_plane.node_count | int) }}\n---\napiVersion: + v1\nkind: Secret\nmetadata:\n name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit\n + \ namespace: {{ $.Values.cluster_namespace }}\nstringData:\n userdata: |\n + \ #cloud-config\n {{- if $.Values.vm.qemu_agent_install }}\n package_update: + true\n packages:\n - qemu-guest-agent\n {{- end }}\n write_files: + \n {{- if $.Values.control_plane.files }}\n{{ $.Values.control_plane.files + | toYaml | indent 4 }}\n {{- end }}\n - path: /etc/rancher/rke2/config.yaml\n + \ owner: root\n content: |\n token: {{ $.Values.shared_token + }}\n {{- if ne $i 0 }}\n server: https://{{ $.Values.control_plane.vip + }}:9345\n {{- end }}\n system-default-registry: {{ $.Values.system_default_registry + }}\n tls-san:\n - {{ $.Values.cluster_name }}-cp-{{ $i }}\n + \ - {{ $.Values.control_plane.vip }}\n secrets-encryption: true\n + \ write-kubeconfig-mode: 0640\n use-service-account-credentials: + true\n {{- if hasKey $.Values \"registry_config\" }}\n - path: /etc/rancher/rke2/registries.yaml\n + \ owner: root\n content: |-\n{{ $.Values.registry_config | toYaml | + indent 8 }}\n {{- end }}\n - path: /etc/hosts\n owner: root\n content: + |\n 127.0.0.1 localhost\n 127.0.0.1 {{$.Values.cluster_name }}-cp-{{ + $i }}\n runcmd:\n {{- if $.Values.vm.qemu_agent_enable }}\n - - systemctl\n + \ - enable\n - '--now'\n - qemu-guest-agent.service\n {{- end + }}\n {{- if not $.Values.vm.airgapped_image }}\n - mkdir -p /var/lib/rancher/rke2-artifacts + && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh\n + \ {{- end}}\n - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} /var/lib/rancher/install.sh\n + \ - systemctl enable rke2-server.service\n - useradd -r -c \"etcd user\" + -s /sbin/nologin -M etcd -U\n - systemctl start rke2-server.service\n ssh_authorized_keys: + \n - {{ $.Values.ssh_pub_key }}\n {{- if ne $.Values.control_plane.ipam + \"dhcp\" }}\n {{- if hasKey $.Values.control_plane \"network\" }}\n networkdata: + |\n{{ index $.Values.control_plane.network $i | indent 4 }}\n {{- end}}\n {{- + else}}\n networkdata: \"\"\n {{- end}}\n{{- end}}" + name: rke2/templates/rke2_cp_secret.yaml + - content: |- + {{- range $i := until (.Values.control_plane.node_count | int) }} + --- + apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + namespace: {{ $.Values.cluster_namespace }} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ $.Values.control_plane.node_disk_gb }}Gi + storageClassName: {{ $.Values.storage.class }} + volumeMode: Block + --- + apiVersion: kubevirt.io/v1 + kind: VirtualMachine + metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + # harvesterhci.io/volumeClaimTemplates: | + # [{"metadata":{"name":"{{ $.Values.cluster_name }}-cp-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"{{ $.Values.control_plane.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + # network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-cp-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-cp-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.control_plane.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.control_plane.memory_gb }}Gi + cpu: {{ $.Values.control_plane.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-cp-{{ $i }} + networks: + - name: default + multus: + networkName: default/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + networkDataSecretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + affinity: {} + terminationGracePeriodSeconds: 120 + {{- end }} + name: rke2/templates/rke2_cp_vm.yaml + - content: |- + --- + apiVersion: loadbalancer.harvesterhci.io/v1beta1 + kind: IPPool + metadata: + name: {{ $.Values.cluster_name }}-pool + spec: + ranges: + - gateway: {{ .Values.control_plane.loadbalancer_gateway }} + rangeEnd: {{ .Values.control_plane.vip }} + rangeStart: {{ .Values.control_plane.vip }} + subnet: {{ .Values.control_plane.loadbalancer_subnet }} + selector: {} + --- + apiVersion: loadbalancer.harvesterhci.io/v1beta1 + kind: LoadBalancer + metadata: + name: {{ .Values.cluster_name }}-lb + namespace: default + spec: + healthCheck: + failureThreshold: 2 + port: 6443 + successThreshold: 3 + timeoutSeconds: 5 + periodSeconds: 5 + ipam: pool + ipPool: {{ .Values.cluster_name }}-pool + listeners: + - name: k8s-api + port: 6443 + protocol: TCP + backendPort: 6443 + - name: ingress + port: 443 + protocol: TCP + backendPort: 443 + - name: join + port: 9345 + protocol: TCP + backendPort: 9345 + workloadType: vm + backendServerSelector: + harvesterhci.io/vmName: + {{- range $i := until (.Values.control_plane.node_count | int)}} + - {{ $.Values.cluster_name }}-cp-{{ $i }} + {{- end}} + name: rke2/templates/rke2_lb.yaml + - content: "{{- range $i := until (.Values.worker.node_count | int) }}\n---\napiVersion: + v1\nkind: Secret\nmetadata:\n name: {{ $.Values.cluster_name }}-worker-{{ $i + }}-cloudinit\n namespace: {{ $.Values.cluster_namespace }}\nstringData:\n userdata: + |\n #cloud-config\n {{- if $.Values.vm.qemu_agent_install }}\n package_update: + true\n packages:\n - qemu-guest-agent\n {{- end }}\n write_files: + \n {{- if $.Values.worker.files }}\n{{ $.Values.worker.files | toYaml | indent + 4 }}\n {{- end }}\n - path: /etc/rancher/rke2/config.yaml\n owner: + root\n content: |\n token: {{ $.Values.shared_token }}\n {{- + if ne $i 0 }}\n server: https://{{ $.Values.control_plane.vip }}:9345\n + \ {{- end }}\n system-default-registry: {{ $.Values.system_default_registry + }}\n secrets-encryption: true\n write-kubeconfig-mode: 0640\n + \ use-service-account-credentials: true\n {{- if hasKey $.Values \"registry_config\" + }}\n - path: /etc/rancher/rke2/registries.yaml\n owner: root\n content: + |-\n{{ $.Values.registry_config | toYaml | indent 8 }}\n {{- end }}\n - + path: /etc/hosts\n owner: root\n content: |\n 127.0.0.1 localhost\n + \ 127.0.0.1 {{$.Values.cluster_name }}-worker-{{ $i }}\n runcmd:\n + \ {{- if $.Values.vm.qemu_agent_enable }}\n - - systemctl\n - enable\n + \ - '--now'\n - qemu-guest-agent.service\n {{- end }}\n {{- if + not $.Values.vm.airgapped_image }}\n - mkdir -p /var/lib/rancher/rke2-artifacts + && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh\n + \ {{- end}}\n - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} INSTALL_RKE2_TYPE=\"agent\" + /var/lib/rancher/install.sh\n - systemctl enable rke2-server.service\n - + systemctl start rke2-server.service\n ssh_authorized_keys: \n - {{ $.Values.ssh_pub_key + }}\n {{- if ne $.Values.worker.ipam \"dhcp\" }}\n {{- if hasKey $.Values.worker + \"network\" }}\n networkdata: |\n{{ index $.Values.worker.network $i | indent + 4 }}\n {{- end}}\n {{- else}}\n networkdata: \"\"\n {{- end}}\n{{- end}}" + name: rke2/templates/rke2_worker_secret.yaml + - content: |- + {{- range $i := until (.Values.worker.node_count | int) }} + --- + apiVersion: kubevirt.io/v1 + kind: VirtualMachine + metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + harvesterhci.io/volumeClaimTemplates: | + [{"metadata":{"name":"{{ $.Values.cluster_name }}-worker-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteMany"],"resources":{"requests":{"storage":"{{ $.Values.worker.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-worker-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs + spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-worker-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.worker.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.worker.memory_gb }}Gi + cpu: {{ $.Values.worker.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-worker-{{ $i }} + networks: + - name: default + multus: + networkName: default/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-worker-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-worker-{{ $i }}-cloudinit + networkData: "" + affinity: {} + terminationGracePeriodSeconds: 120 + {{- end }} + name: rke2/templates/rke2_worker_vm.yaml + - content: "cluster_name: mycluster\ncluster_namespace: default\n\nshared_token: + insecuretoken\nsystem_default_registry: \"\" #! empty value: use embedded + default\n #! non-empty value: use as regsitry + to source rke2 runtime image from\n #! if your + VM image contains the tarballs for RKE2, it will use those first\nrke2_version: + v1.26.10+rke2r2\n\nssh_pub_key: \"\" #! the public ssh key + to inject onto each node, required if you want to fetch a kubeconfig\n\n# registry_config:\n# + \ configs:\n# \"rgcrprod.azurecr.us\":\n# auth:\n# username: + test\n# password: test\n\nvm:\n image_namespace: default #! + namespace in your harvester cluster containing the vm base image\n image: ubuntu + \ #! name of base vm image to use for your RKE2 nodes\n os: + linux\n distro: ubuntu #! flag used for specific cloud-init + code tied to Ubuntu vs others (netplan)\n uefi_enabled: true\n qemu_agent_install: + true #! flag for installation of the qemu-agent service (Requires internet)\n + \ qemu_agent_enable: true #! flag for enabling the qemu-agent\n airgapped_image: + false #! flag to alert helm that your VM image already has the RKE2 + install script (and does not need to download it)\n\n\nnetwork_name: host\n\ncontrol_plane:\n + \ node_count: 1\n cpu_count: 4\n memory_gb: 8\n node_disk_gb: 40\n loadbalancer_gateway: + 10.10.0.1\n loadbalancer_subnet: 10.10.0.0/24\n files: []\n # files:\n # + - path: /tmp/test\n # owner: root\n # content: |\n # created a file\n\n + \ vip: #! this is the VIP for the Harvester LoadBalancer + object, ensure it is a routable IP\n ipam: dhcp #! this + can be dhcp or static, static requires an equal amount of cloud-init network-data + entries\n\n # network:\n # - | #! ubuntu example\n # network:\n # version: + 2\n # renderer: networkd\n # ethernets:\n # enp1s0:\n # dhcp4: + no\n # addresses: [ \"10.10.0.6/24\" ]\n # gateway4: 10.10.0.1\n + \ # nameservers:\n # addresses: \n # - 10.10.0.1\n\nworker:\n + \ node_count: 1\n cpu_count: 4\n memory_gb: 8\n node_disk_gb: 40\n files: + []\n # files:\n # - path: /tmp/test\n # owner: root\n # content: |\n + \ # created a file\n\n ipam: dhcp #! this can be dhcp + or static, static requires an equal amount of cloud-init network-data entries\n\n + \ # network:\n # - |\n # network:\n # version: 2\n # renderer: + networkd\n # ethernets:\n # enp1s0:\n # dhcp4: no\n # + \ addresses: [ \"10.10.0.20/24\" ]\n # gateway4: 10.10.0.1\n + \ # nameservers:\n # addresses: \n # - 10.10.0.1\n" + name: rke2/values.yaml + - content: "cluster_name: rke2-mgmt\nsystem_default_registry: \"\"\n\nrke2_version: + v1.29.6+rke2r1\n\nvm:\n image: ubuntu\n qemu_agent_install: true \n + \ qemu_agent_enable: true \n airgapped_image: false \nnetwork_name: + lab-workload\nssh_pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDK3vpDMfNKbXTkpOwC77k5xvEpUAcNyJa6pYT17YMbzvHuugSJRiouLElDtpqktto6plkDdrTRXnkDA3aVxUycCl/4IrnCEehlg8LGgFxKASNeXQYL0URIWRDicyJaolg5bFdcu3gYTA0JBtApiebrml6bj9cJGnS8lqRK9wmWIFv5lPICcrZMsw1AIRhghGI5BupUnttD+muHspAiGfjTbiiCvKo3fLmEMQ9pt/46wQuPbzOCVChpJByVG9AKO9IpdkOGgKeuy2y98ZxJIHBAx4B49jDfA8NNfyEBIdgiIvlv6QXgjFbazI5buLYM/RK36kf9JjYNBySZJuA3VMbHnWmWvZYBQUA6ypVMc4Wzvd3hhFmNQn1W+NEHl6v+bCDeo5QIv5dkpIoDgJd8CvWQ42bb2bi7zyO32v2zfaW03eDCeopFAKditMPhjqai0S2W4LRt7dRKEOCvUqPFYqZ99nBk1mmTWG8Gpp7VA/+shn171Yc/wDCwBcEyciqOYNtnW55O3eCiBHsnBcEFKy80zHJ1jckDSluypwBrsooYV5WKS8O+jqGyYfdruJ8oUCPw72b0JHs5AmFCRuhzOU6cZP6Ynghs1SkdVtq722uFjmDUR0X8+hoIZDEWutw6+91YhwnodA3MmGHtInlY+URqdz6TltOMP2X2vSMohnh2zQ==\n\nregistry_config:\n + \ configs:\n \"rgcrprod.azurecr.us\":\n auth:\n username: test\n + \ password: test\n\ncontrol_plane:\n vip: 10.2.0.20 \n loadbalancer_gateway: + 10.2.0.1\n loadbalancer_subnet: 10.2.0.0/24\n \n node_count: 3 \n cpu_count: + 8\n memory_gb: 16\n\n ipam: static\n network:\n - |\n network:\n version: + 2\n renderer: networkd\n ethernets:\n enp1s0:\n dhcp4: + no\n addresses: [ \"10.2.0.21/24\" ]\n gateway4: 10.2.0.1\n + \ nameservers:\n addresses: \n - 10.2.0.1\n - + |\n network:\n version: 2\n renderer: networkd\n ethernets:\n + \ enp1s0:\n dhcp4: no\n addresses: [ \"10.2.0.22/24\" + ]\n gateway4: 10.2.0.1\n nameservers:\n addresses: + \n - 10.2.0.1\n - |\n network:\n version: 2\n renderer: + networkd\n ethernets:\n enp1s0:\n dhcp4: no\n addresses: + [ \"10.2.0.23/24\" ]\n gateway4: 10.2.0.1\n nameservers:\n + \ addresses: \n - 10.2.0.1\n files:\n - path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml\n + \ owner: root\n content: |\n apiVersion: helm.cattle.io/v1\n kind: + HelmChart\n metadata:\n name: cert-manager\n namespace: default + \ \n spec:\n bootstrap: true\n targetNamespace: cert-manager\n + \ createNamespace: true\n valuesContent: |-\n securityContext:\n + \ runAsNonRoot: true\n crds:\n enabled: true\n + \ version: v1.16.1\n repo: https://charts.jetstack.io\n chart: + cert-manager\n - path: /var/lib/rancher/rke2/server/manifests/rancher.yaml\n + \ owner: root\n content: |\n apiVersion: helm.cattle.io/v1\n kind: + HelmChart\n metadata:\n name: rancher\n namespace: default + \ \n spec:\n bootstrap: false\n targetNamespace: cattle-system\n + \ createNamespace: true\n set:\n hostname: rancher.lab.sienarfleet.systems\n + \ replicas: 3\n bootstrapPassword: admin\n valuesContent: + |-\n global:\n cattle:\n psp:\n enabled: + false\n ingress:\n tls:\n source: rancher\n + \ repo: https://releases.rancher.com/server-charts/stable\n chart: + rancher\n version: v2.10.1\nworker:\n node_count: 0" + name: values.yaml + targetRestrictions: + - clusterName: local + targets: + - clusterName: local + ignore: {} diff --git a/deploy/rancher/helm/rancher_values_dhcp.yaml b/deploy/rancher/helm/rancher_values_dhcp.yaml new file mode 100644 index 0000000..3eda166 --- /dev/null +++ b/deploy/rancher/helm/rancher_values_dhcp.yaml @@ -0,0 +1,101 @@ +cluster_name: rke2-rancher +cluster_namespace: vanderlande +control_plane: + cpu_count: 4 + files: + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + #namespace: default + spec: + bootstrap: true + targetNamespace: cert-manager + createNamespace: true + valuesContent: |- + securityContext: + runAsNonRoot: true + crds: + enabled: true + version: v1.16.1 + repo: https://charts.jetstack.io + chart: cert-manager + owner: root + path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: rancher + #namespace: default + spec: + bootstrap: false + targetNamespace: cattle-system + createNamespace: true + set: + hostname: rancher-mgmt.product.lan + replicas: 3 + bootstrapPassword: admin + valuesContent: |- + global: + cattle: + psp: + enabled: false + ingress: + tls: + source: rancher + repo: https://releases.rancher.com/server-charts/stable + chart: rancher + version: v2.12.3 + owner: root + path: /var/lib/rancher/rke2/server/manifests/rancher.yaml + ipam: dhcp + loadbalancer_gateway: 172.27.27.1 + loadbalancer_subnet: 172.27.27.0/24 + memory_gb: 12 + network: + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: yes + node_count: 3 + vip: 172.27.27.40 +network_name: vm-lan +registry_config: + configs: + rgcrprod.azurecr.us: + auth: + password: test + username: test +rke2_version: v1.33.4+rke2r1 +ssh_pub_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil +system_default_registry: "" +vm: + airgapped_image: false + image: noble-server-cloudimg-amd64.img + qemu_agent_enable: true + qemu_agent_install: true +worker: + node_count: 0 +storage: + class: longhorn-image-t4n82 # StorageClass for image noble-server-cloudimg-amd64.img \ No newline at end of file diff --git a/deploy/rancher/helm/rancher_values_static.yaml b/deploy/rancher/helm/rancher_values_static.yaml new file mode 100644 index 0000000..874cbc8 --- /dev/null +++ b/deploy/rancher/helm/rancher_values_static.yaml @@ -0,0 +1,117 @@ +cluster_name: rke2-mgmt +cluster_namespace: vanderlande +control_plane: + cpu_count: 4 + files: + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: cert-manager + #namespace: default + spec: + bootstrap: true + targetNamespace: cert-manager + createNamespace: true + valuesContent: |- + securityContext: + runAsNonRoot: true + crds: + enabled: true + version: v1.16.1 + repo: https://charts.jetstack.io + chart: cert-manager + owner: root + path: /var/lib/rancher/rke2/server/manifests/certmanager.yaml + - content: | + apiVersion: helm.cattle.io/v1 + kind: HelmChart + metadata: + name: rancher + #namespace: default + spec: + bootstrap: false + targetNamespace: cattle-system + createNamespace: true + set: + hostname: rancher-mgmt.product.lan + replicas: 3 + bootstrapPassword: admin + valuesContent: |- + global: + cattle: + psp: + enabled: false + ingress: + tls: + source: rancher + repo: https://releases.rancher.com/server-charts/stable + chart: rancher + version: v2.12.3 + owner: root + path: /var/lib/rancher/rke2/server/manifests/rancher.yaml + ipam: static + loadbalancer_gateway: 172.27.27.1 + loadbalancer_subnet: 172.27.27.0/24 + memory_gb: 12 + network: + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.41/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.42/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + - | + network: + version: 2 + renderer: networkd + ethernets: + enp1s0: + dhcp4: no + addresses: [ "172.22.19.43/24" ] + gateway4: 172.22.19.1 + nameservers: + addresses: + - 172.22.19.15 + - 172.22.19.16 + node_count: 3 + vip: 172.27.27.40 +network_name: vm-lan +registry_config: + configs: + rgcrprod.azurecr.us: + auth: + password: test + username: test +rke2_version: v1.33.4+rke2r1 +ssh_pub_key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPyW9YbYPE3efCdHMBgnP8AeVfs5Lw8MBCLhXuteliil +system_default_registry: "" +vm: + airgapped_image: false + image: noble-server-cloudimg-amd64.img + qemu_agent_enable: true + qemu_agent_install: true +worker: + node_count: 0 +storage: + class: longhorn-image-t4n82 # StorageClass for image noble-server-cloudimg-amd64.img \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/Chart.yaml b/deploy/rancher/helm/rke2/Chart.yaml new file mode 100644 index 0000000..3d29afd --- /dev/null +++ b/deploy/rancher/helm/rke2/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: rke2-cluster +description: RKE2 cluster designed for usage directly on Harvester + +type: application +version: 0.1.1 +appVersion: 0.1.1 \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/templates/rke2_cp_secret.yaml b/deploy/rancher/helm/rke2/templates/rke2_cp_secret.yaml new file mode 100644 index 0000000..8649874 --- /dev/null +++ b/deploy/rancher/helm/rke2/templates/rke2_cp_secret.yaml @@ -0,0 +1,69 @@ +{{- range $i := until (.Values.control_plane.node_count | int) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + namespace: {{ $.Values.cluster_namespace }} +stringData: + userdata: | + #cloud-config + {{- if $.Values.vm.qemu_agent_install }} + package_update: true + packages: + - qemu-guest-agent + {{- end }} + write_files: + {{- if $.Values.control_plane.files }} +{{ $.Values.control_plane.files | toYaml | indent 4 }} + {{- end }} + - path: /etc/rancher/rke2/config.yaml + owner: root + content: | + token: {{ $.Values.shared_token }} + {{- if ne $i 0 }} + server: https://{{ $.Values.control_plane.vip }}:9345 + {{- end }} + system-default-registry: {{ $.Values.system_default_registry }} + tls-san: + - {{ $.Values.cluster_name }}-cp-{{ $i }} + - {{ $.Values.control_plane.vip }} + secrets-encryption: true + write-kubeconfig-mode: 0640 + use-service-account-credentials: true + {{- if hasKey $.Values "registry_config" }} + - path: /etc/rancher/rke2/registries.yaml + owner: root + content: |- +{{ $.Values.registry_config | toYaml | indent 8 }} + {{- end }} + - path: /etc/hosts + owner: root + content: | + 127.0.0.1 localhost + 127.0.0.1 {{$.Values.cluster_name }}-cp-{{ $i }} + runcmd: + {{- if $.Values.vm.qemu_agent_enable }} + - - systemctl + - enable + - '--now' + - qemu-guest-agent.service + {{- end }} + {{- if not $.Values.vm.airgapped_image }} + - mkdir -p /var/lib/rancher/rke2-artifacts && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh + {{- end}} + - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} /var/lib/rancher/install.sh + - systemctl enable rke2-server.service + - useradd -r -c "etcd user" -s /sbin/nologin -M etcd -U + - systemctl start rke2-server.service + ssh_authorized_keys: + - {{ $.Values.ssh_pub_key }} + {{- if ne $.Values.control_plane.ipam "dhcp" }} + {{- if hasKey $.Values.control_plane "network" }} + networkdata: | +{{ index $.Values.control_plane.network $i | indent 4 }} + {{- end}} + {{- else}} + networkdata: "" + {{- end}} +{{- end}} \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/templates/rke2_cp_vm.yaml b/deploy/rancher/helm/rke2/templates/rke2_cp_vm.yaml new file mode 100644 index 0000000..0e8bd8d --- /dev/null +++ b/deploy/rancher/helm/rke2/templates/rke2_cp_vm.yaml @@ -0,0 +1,89 @@ +{{- range $i := until (.Values.control_plane.node_count | int) }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + namespace: {{ $.Values.cluster_namespace }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ $.Values.control_plane.node_disk_gb }}Gi + storageClassName: {{ $.Values.storage.class }} + volumeMode: Block +--- +apiVersion: kubevirt.io/v1 +kind: VirtualMachine +metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + # harvesterhci.io/volumeClaimTemplates: | + # [{"metadata":{"name":"{{ $.Values.cluster_name }}-cp-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"{{ $.Values.control_plane.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + # network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-cp-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs +spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-cp-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.control_plane.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.control_plane.memory_gb }}Gi + cpu: {{ $.Values.control_plane.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-cp-{{ $i }} + networks: + - name: default + multus: + networkName: {{ $.Values.cluster_namespace }}/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-cp-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + networkDataSecretRef: + name: {{ $.Values.cluster_name }}-cp-{{ $i }}-cloudinit + affinity: {} + terminationGracePeriodSeconds: 120 +{{- end }} \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/templates/rke2_lb.yaml b/deploy/rancher/helm/rke2/templates/rke2_lb.yaml new file mode 100644 index 0000000..0307ff6 --- /dev/null +++ b/deploy/rancher/helm/rke2/templates/rke2_lb.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: loadbalancer.harvesterhci.io/v1beta1 +kind: IPPool +metadata: + name: {{ $.Values.cluster_name }}-pool +spec: + ranges: + - gateway: {{ .Values.control_plane.loadbalancer_gateway }} + rangeEnd: {{ .Values.control_plane.vip }} + rangeStart: {{ .Values.control_plane.vip }} + subnet: {{ .Values.control_plane.loadbalancer_subnet }} + selector: {} +--- +apiVersion: loadbalancer.harvesterhci.io/v1beta1 +kind: LoadBalancer +metadata: + name: {{ .Values.cluster_name }}-lb + #namespace: default +spec: + healthCheck: + failureThreshold: 2 + port: 6443 + successThreshold: 3 + timeoutSeconds: 5 + periodSeconds: 5 + ipam: pool + ipPool: {{ .Values.cluster_name }}-pool + listeners: + - name: k8s-api + port: 6443 + protocol: TCP + backendPort: 6443 + - name: ingress + port: 443 + protocol: TCP + backendPort: 443 + - name: join + port: 9345 + protocol: TCP + backendPort: 9345 + workloadType: vm + backendServerSelector: + harvesterhci.io/vmName: + {{- range $i := until (.Values.control_plane.node_count | int)}} + - {{ $.Values.cluster_name }}-cp-{{ $i }} + {{- end}} \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/templates/rke2_worker_secret.yaml b/deploy/rancher/helm/rke2/templates/rke2_worker_secret.yaml new file mode 100644 index 0000000..637cf63 --- /dev/null +++ b/deploy/rancher/helm/rke2/templates/rke2_worker_secret.yaml @@ -0,0 +1,66 @@ +{{- range $i := until (.Values.worker.node_count | int) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $.Values.cluster_name }}-worker-{{ $i }}-cloudinit + namespace: {{ $.Values.cluster_namespace }} +stringData: + userdata: | + #cloud-config + {{- if $.Values.vm.qemu_agent_install }} + package_update: true + packages: + - qemu-guest-agent + {{- end }} + write_files: + {{- if $.Values.worker.files }} +{{ $.Values.worker.files | toYaml | indent 4 }} + {{- end }} + - path: /etc/rancher/rke2/config.yaml + owner: root + content: | + token: {{ $.Values.shared_token }} + {{- if ne $i 0 }} + server: https://{{ $.Values.control_plane.vip }}:9345 + {{- end }} + system-default-registry: {{ $.Values.system_default_registry }} + secrets-encryption: true + write-kubeconfig-mode: 0640 + use-service-account-credentials: true + {{- if hasKey $.Values "registry_config" }} + - path: /etc/rancher/rke2/registries.yaml + owner: root + content: |- +{{ $.Values.registry_config | toYaml | indent 8 }} + {{- end }} + - path: /etc/hosts + owner: root + content: | + 127.0.0.1 localhost + 127.0.0.1 {{$.Values.cluster_name }}-worker-{{ $i }} + runcmd: + {{- if $.Values.vm.qemu_agent_enable }} + - - systemctl + - enable + - '--now' + - qemu-guest-agent.service + {{- end }} + {{- if not $.Values.vm.airgapped_image }} + #- mkdir -p /var/lib/rancher/rke2-artifacts && wget https://get.rke2.io -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh + - mkdir -p /var/lib/rancher/rke2-artifacts && wget https://raw.githubusercontent.com/rancher/rke2/refs/heads/master/install.sh -O /var/lib/rancher/install.sh && chmod +x /var/lib/rancher/install.sh + {{- end}} + - INSTALL_RKE2_VERSION={{ $.Values.rke2_version }} INSTALL_RKE2_TYPE="agent" /var/lib/rancher/install.sh + - systemctl enable rke2-server.service + - systemctl start rke2-server.service + ssh_authorized_keys: + - {{ $.Values.ssh_pub_key }} + {{- if ne $.Values.worker.ipam "dhcp" }} + {{- if hasKey $.Values.worker "network" }} + networkdata: | +{{ index $.Values.worker.network $i | indent 4 }} + {{- end}} + {{- else}} + networkdata: "" + {{- end}} +{{- end}} \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/templates/rke2_worker_vm.yaml b/deploy/rancher/helm/rke2/templates/rke2_worker_vm.yaml new file mode 100644 index 0000000..44dd352 --- /dev/null +++ b/deploy/rancher/helm/rke2/templates/rke2_worker_vm.yaml @@ -0,0 +1,74 @@ +{{- range $i := until (.Values.worker.node_count | int) }} +--- +apiVersion: kubevirt.io/v1 +kind: VirtualMachine +metadata: + namespace: {{ $.Values.cluster_namespace }} + annotations: + harvesterhci.io/volumeClaimTemplates: | + [{"metadata":{"name":"{{ $.Values.cluster_name }}-worker-disk-{{ $i }}","annotations":{"harvesterhci.io/imageId":"{{ $.Values.vm.image_namespace }}/{{ $.Values.vm.image }}","helm.app":"rke2"}},"spec":{"accessModes":["ReadWriteMany"],"resources":{"requests":{"storage":"{{ $.Values.worker.node_disk_gb }}Gi"}},"volumeMode":"Block","storageClassName":"{{ $.Values.storage.class }}"}}] + network.harvesterhci.io/ips: '[]' + labels: + harvesterhci.io/creator: harvester + harvesterhci.io/os: {{ $.Values.vm.os }} + name: {{ $.Values.cluster_name }}-worker-{{ $i }} + finalizers: + - harvesterhci.io/VMController.UnsetOwnerOfPVCs +spec: + runStrategy: RerunOnFailure + template: + metadata: + annotations: {} + labels: + harvesterhci.io/vmName: {{ $.Values.cluster_name }}-worker-{{ $i }} + spec: + domain: + machine: + type: '' + cpu: + cores: {{ $.Values.worker.cpu_count }} + sockets: 1 + threads: 1 + devices: + interfaces: + - bridge: {} + model: virtio + name: default + disks: + - name: disk-0 + disk: + bus: virtio + bootOrder: 1 + - name: cloudinitdisk + disk: + bus: virtio + hostDevices: [] + resources: + limits: + memory: {{ $.Values.worker.memory_gb }}Gi + cpu: {{ $.Values.worker.cpu_count }} + features: + acpi: + enabled: {{ $.Values.vm.uefi_enabled }} + firmware: + bootloader: + efi: + secureBoot: false + evictionStrategy: LiveMigrate + hostname: {{ $.Values.cluster_name }}-worker-{{ $i }} + networks: + - name: default + multus: + networkName: {{ $.Values.cluster_namespace }}/{{ $.Values.network_name }} + volumes: + - name: disk-0 + persistentVolumeClaim: + claimName: {{ $.Values.cluster_name }}-worker-disk-{{ $i }} + - name: cloudinitdisk + cloudInitNoCloud: + secretRef: + name: {{ $.Values.cluster_name }}-worker-{{ $i }}-cloudinit + networkData: "" + affinity: {} + terminationGracePeriodSeconds: 120 +{{- end }} \ No newline at end of file diff --git a/deploy/rancher/helm/rke2/values.yaml b/deploy/rancher/helm/rke2/values.yaml new file mode 100644 index 0000000..8704405 --- /dev/null +++ b/deploy/rancher/helm/rke2/values.yaml @@ -0,0 +1,92 @@ +cluster_name: mycluster +cluster_namespace: default + +shared_token: insecuretoken +system_default_registry: "" #! empty value: use embedded default + #! non-empty value: use as regsitry to source rke2 runtime image from + #! if your VM image contains the tarballs for RKE2, it will use those first +rke2_version: v1.26.10+rke2r2 + +ssh_pub_key: "" #! the public ssh key to inject onto each node, required if you want to fetch a kubeconfig + +# registry_config: +# configs: +# "rgcrprod.azurecr.us": +# auth: +# username: test +# password: test + +storage: + class: longhorn + +vm: + image_namespace: default #! namespace in your harvester cluster containing the vm base image + image: ubuntu #! name of base vm image to use for your RKE2 nodes + os: linux + distro: ubuntu #! flag used for specific cloud-init code tied to Ubuntu vs others (netplan) + uefi_enabled: true + qemu_agent_install: true #! flag for installation of the qemu-agent service (Requires internet) + qemu_agent_enable: true #! flag for enabling the qemu-agent + airgapped_image: false #! flag to alert helm that your VM image already has the RKE2 install script (and does not need to download it) + + +network_name: host + +control_plane: + node_count: 1 + cpu_count: 4 + memory_gb: 8 + node_disk_gb: 40 + loadbalancer_gateway: 10.10.0.1 + loadbalancer_subnet: 10.10.0.0/24 + files: [] + # files: + # - path: /tmp/test + # owner: root + # content: | + # created a file + + vip: #! this is the VIP for the Harvester LoadBalancer object, ensure it is a routable IP + ipam: dhcp #! this can be dhcp or static, static requires an equal amount of cloud-init network-data entries + + # network: + # - | #! ubuntu example + # network: + # version: 2 + # renderer: networkd + # ethernets: + # enp1s0: + # dhcp4: no + # addresses: [ "10.10.0.6/24" ] + # gateway4: 10.10.0.1 + # nameservers: + # addresses: + # - 10.10.0.1 + +worker: + node_count: 1 + cpu_count: 4 + memory_gb: 8 + node_disk_gb: 40 + files: [] + # files: + # - path: /tmp/test + # owner: root + # content: | + # created a file + + ipam: dhcp #! this can be dhcp or static, static requires an equal amount of cloud-init network-data entries + + # network: + # - | + # network: + # version: 2 + # renderer: networkd + # ethernets: + # enp1s0: + # dhcp4: no + # addresses: [ "10.10.0.20/24" ] + # gateway4: 10.10.0.1 + # nameservers: + # addresses: + # - 10.10.0.1 diff --git a/deploy/rig-operator/.devcontainer/devcontainer.json b/deploy/rig-operator/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a3ab754 --- /dev/null +++ b/deploy/rig-operator/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "Kubebuilder DevContainer", + "image": "golang:1.24", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/git:1": {} + }, + + "runArgs": ["--network=host"], + + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "ms-kubernetes-tools.vscode-kubernetes-tools", + "ms-azuretools.vscode-docker" + ] + } + }, + + "onCreateCommand": "bash .devcontainer/post-install.sh" +} + diff --git a/deploy/rig-operator/.devcontainer/post-install.sh b/deploy/rig-operator/.devcontainer/post-install.sh new file mode 100644 index 0000000..67f3e97 --- /dev/null +++ b/deploy/rig-operator/.devcontainer/post-install.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -x + +curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-$(go env GOARCH) +chmod +x ./kind +mv ./kind /usr/local/bin/kind + +curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/linux/$(go env GOARCH) +chmod +x kubebuilder +mv kubebuilder /usr/local/bin/ + +KUBECTL_VERSION=$(curl -L -s https://dl.k8s.io/release/stable.txt) +curl -LO "https://dl.k8s.io/release/$KUBECTL_VERSION/bin/linux/$(go env GOARCH)/kubectl" +chmod +x kubectl +mv kubectl /usr/local/bin/kubectl + +docker network create -d=bridge --subnet=172.19.0.0/24 kind + +kind version +kubebuilder version +docker --version +go version +kubectl version --client diff --git a/deploy/rig-operator/.dockerignore b/deploy/rig-operator/.dockerignore new file mode 100644 index 0000000..9af8280 --- /dev/null +++ b/deploy/rig-operator/.dockerignore @@ -0,0 +1,11 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore everything by default and re-include only needed files +** + +# Re-include Go source files (but not *_test.go) +!**/*.go +**/*_test.go + +# Re-include Go module files +!go.mod +!go.sum diff --git a/deploy/rig-operator/.github/workflows/lint.yml b/deploy/rig-operator/.github/workflows/lint.yml new file mode 100644 index 0000000..4838c54 --- /dev/null +++ b/deploy/rig-operator/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Run linter + uses: golangci/golangci-lint-action@v8 + with: + version: v2.5.0 diff --git a/deploy/rig-operator/.github/workflows/test-e2e.yml b/deploy/rig-operator/.github/workflows/test-e2e.yml new file mode 100644 index 0000000..4cdfb30 --- /dev/null +++ b/deploy/rig-operator/.github/workflows/test-e2e.yml @@ -0,0 +1,32 @@ +name: E2E Tests + +on: + push: + pull_request: + +jobs: + test-e2e: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install the latest version of kind + run: | + curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-$(go env GOARCH) + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + - name: Verify kind installation + run: kind version + + - name: Running Test e2e + run: | + go mod tidy + make test-e2e diff --git a/deploy/rig-operator/.github/workflows/test.yml b/deploy/rig-operator/.github/workflows/test.yml new file mode 100644 index 0000000..fc2e80d --- /dev/null +++ b/deploy/rig-operator/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + test: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Running Tests + run: | + go mod tidy + make test diff --git a/deploy/rig-operator/.gitignore b/deploy/rig-operator/.gitignore new file mode 100644 index 0000000..9f0f3a1 --- /dev/null +++ b/deploy/rig-operator/.gitignore @@ -0,0 +1,30 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ + +# Kubeconfig might contain secrets +*.kubeconfig diff --git a/deploy/rig-operator/.golangci.yml b/deploy/rig-operator/.golangci.yml new file mode 100644 index 0000000..e5b21b0 --- /dev/null +++ b/deploy/rig-operator/.golangci.yml @@ -0,0 +1,52 @@ +version: "2" +run: + allow-parallel-runners: true +linters: + default: none + enable: + - copyloopvar + - dupl + - errcheck + - ginkgolinter + - goconst + - gocyclo + - govet + - ineffassign + - lll + - misspell + - nakedret + - prealloc + - revive + - staticcheck + - unconvert + - unparam + - unused + settings: + revive: + rules: + - name: comment-spacings + - name: import-shadowing + exclusions: + generated: lax + rules: + - linters: + - lll + path: api/* + - linters: + - dupl + - lll + path: internal/* + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/deploy/rig-operator/Dockerfile b/deploy/rig-operator/Dockerfile new file mode 100644 index 0000000..6466c48 --- /dev/null +++ b/deploy/rig-operator/Dockerfile @@ -0,0 +1,31 @@ +# Build the manager binary +FROM golang:1.24 AS builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the Go source (relies on .dockerignore to filter) +COPY . . + +# Build +# the GOARCH has no default value to allow the binary to be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER 65532:65532 + +ENTRYPOINT ["/manager"] diff --git a/deploy/rig-operator/Makefile b/deploy/rig-operator/Makefile new file mode 100644 index 0000000..207f05b --- /dev/null +++ b/deploy/rig-operator/Makefile @@ -0,0 +1,250 @@ +# Image URL to use all building/pushing image targets +IMG ?= controller:latest + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# CONTAINER_TOOL defines the container tool to be used for building images. +# Be aware that the target commands are only tested with Docker which is +# scaffolded by default. However, you might want to replace it to use other +# tools. (i.e. podman) +CONTAINER_TOOL ?= docker + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk command is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Development + +.PHONY: manifests +manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. + "$(CONTROLLER_GEN)" rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +.PHONY: generate +generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. + "$(CONTROLLER_GEN)" object:headerFile="hack/boilerplate.go.txt" paths="./..." + +.PHONY: fmt +fmt: ## Run go fmt against code. + go fmt ./... + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: test +test: manifests generate fmt vet setup-envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell "$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out + +# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'. +# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. +# CertManager is installed by default; skip with: +# - CERT_MANAGER_INSTALL_SKIP=true +KIND_CLUSTER ?= deploy-test-e2e + +.PHONY: setup-test-e2e +setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist + @command -v $(KIND) >/dev/null 2>&1 || { \ + echo "Kind is not installed. Please install Kind manually."; \ + exit 1; \ + } + @case "$$($(KIND) get clusters)" in \ + *"$(KIND_CLUSTER)"*) \ + echo "Kind cluster '$(KIND_CLUSTER)' already exists. Skipping creation." ;; \ + *) \ + echo "Creating Kind cluster '$(KIND_CLUSTER)'..."; \ + $(KIND) create cluster --name $(KIND_CLUSTER) ;; \ + esac + +.PHONY: test-e2e +test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. + KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v + $(MAKE) cleanup-test-e2e + +.PHONY: cleanup-test-e2e +cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests + @$(KIND) delete cluster --name $(KIND_CLUSTER) + +.PHONY: lint +lint: golangci-lint ## Run golangci-lint linter + "$(GOLANGCI_LINT)" run + +.PHONY: lint-fix +lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes + "$(GOLANGCI_LINT)" run --fix + +.PHONY: lint-config +lint-config: golangci-lint ## Verify golangci-lint linter configuration + "$(GOLANGCI_LINT)" config verify + +##@ Build + +.PHONY: build +build: manifests generate fmt vet ## Build manager binary. + go build -o bin/manager cmd/main.go + +.PHONY: run +run: manifests generate fmt vet ## Run a controller from your host. + go run ./cmd/main.go + +# If you wish to build the manager image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: ## Build docker image with the manager. + $(CONTAINER_TOOL) build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the manager. + $(CONTAINER_TOOL) push ${IMG} + +# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/ +# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=> then the export will fail) +# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build and push docker image for the manager for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - $(CONTAINER_TOOL) buildx create --name deploy-builder + $(CONTAINER_TOOL) buildx use deploy-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm deploy-builder + rm Dockerfile.cross + +.PHONY: build-installer +build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. + mkdir -p dist + cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG} + "$(KUSTOMIZE)" build config/default > dist/install.yaml + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +.PHONY: install +install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. + @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \ + if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" apply -f -; else echo "No CRDs to install; skipping."; fi + +.PHONY: uninstall +uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + @out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \ + if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -; else echo "No CRDs to delete; skipping."; fi + +.PHONY: deploy +deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG} + "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" apply -f - + +.PHONY: undeploy +undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. + "$(KUSTOMIZE)" build config/default | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f - + +##@ Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p "$(LOCALBIN)" + +## Tool Binaries +KUBECTL ?= kubectl +KIND ?= kind +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest +GOLANGCI_LINT = $(LOCALBIN)/golangci-lint + +## Tool Versions +KUSTOMIZE_VERSION ?= v5.7.1 +CONTROLLER_TOOLS_VERSION ?= v0.19.0 + +#ENVTEST_VERSION is the version of controller-runtime release branch to fetch the envtest setup script (i.e. release-0.20) +ENVTEST_VERSION ?= $(shell v='$(call gomodver,sigs.k8s.io/controller-runtime)'; \ + [ -n "$$v" ] || { echo "Set ENVTEST_VERSION manually (controller-runtime replace has no tag)" >&2; exit 1; }; \ + printf '%s\n' "$$v" | sed -E 's/^v?([0-9]+)\.([0-9]+).*/release-\1.\2/') + +#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31) +ENVTEST_K8S_VERSION ?= $(shell v='$(call gomodver,k8s.io/api)'; \ + [ -n "$$v" ] || { echo "Set ENVTEST_K8S_VERSION manually (k8s.io/api replace has no tag)" >&2; exit 1; }; \ + printf '%s\n' "$$v" | sed -E 's/^v?[0-9]+\.([0-9]+).*/1.\1/') + +GOLANGCI_LINT_VERSION ?= v2.5.0 +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. +$(KUSTOMIZE): $(LOCALBIN) + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. +$(CONTROLLER_GEN): $(LOCALBIN) + $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) + +.PHONY: setup-envtest +setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory. + @echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..." + @"$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path || { \ + echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \ + exit 1; \ + } + +.PHONY: envtest +envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. +$(ENVTEST): $(LOCALBIN) + $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) + +.PHONY: golangci-lint +golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. +$(GOLANGCI_LINT): $(LOCALBIN) + $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION)) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f "$(1)-$(3)" ] && [ "$$(readlink -- "$(1)" 2>/dev/null)" = "$(1)-$(3)" ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +rm -f "$(1)" ;\ +GOBIN="$(LOCALBIN)" go install $${package} ;\ +mv "$(LOCALBIN)/$$(basename "$(1)")" "$(1)-$(3)" ;\ +} ;\ +ln -sf "$$(realpath "$(1)-$(3)")" "$(1)" +endef + +define gomodver +$(shell go list -m -f '{{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}' $(1) 2>/dev/null) +endef diff --git a/deploy/rig-operator/PROJECT b/deploy/rig-operator/PROJECT new file mode 100644 index 0000000..4e9d5df --- /dev/null +++ b/deploy/rig-operator/PROJECT @@ -0,0 +1,46 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html +cliVersion: 4.10.1 +domain: appstack.io +layout: +- go.kubebuilder.io/v4 +projectName: deploy +repo: vanderlande.com/ittp/appstack/rig-operator +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: appstack.io + group: rig + kind: ClusterBlueprint + path: vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: appstack.io + group: rig + kind: InfraBlueprint + path: vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: appstack.io + group: rig + kind: HarvesterBlueprint + path: vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: appstack.io + group: rig + kind: VsphereBlueprint + path: vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1 + version: v1alpha1 +version: "3" diff --git a/deploy/rig-operator/README-DEV.md b/deploy/rig-operator/README-DEV.md new file mode 100644 index 0000000..8e6d63a --- /dev/null +++ b/deploy/rig-operator/README-DEV.md @@ -0,0 +1,141 @@ +# RIG Operator (Resource Infrastructure Gateway) + +**RIG Operator** is a Kubernetes operator designed to decouple **Infrastructure Management** (Quotas, Credentials, Providers) from **Cluster Provisioning** (Kubernetes versions, Node sizing). + +It replaces legacy monolithic provisioners with a **Strategy-Pattern Architecture**, allowing a single operator to manage hybrid fleets (Harvester, vSphere, etc.) using a unified API while strictly enforcing resource quotas. + +--- + +## 🏗 Architecture & Design + +### The Problem +Legacy controllers often mix concerns: +* *Hardcoded Providers:* Adding vSphere requires rewriting the main loop. +* *No Accounting:* Users can provision infinite clusters until the underlying storage fills up. +* *Tight Coupling:* Helm values, RKE2 configs, and VM details are mashed into one huge struct. + +### The RIG Solution +RIG segregates responsibilities into three distinct layers, acting as a **Gatekeeper** and **Router**. + + + +#### 1. The Data Model (Blueprints) +* **`InfraBlueprint` (The Accountant):** Owned by Platform Admins. Defines **Quotas** (CPU/RAM/Disk), **Credentials**, and points to the specific Provider Config. It automatically tracks usage across all child clusters. +* **`ClusterBlueprint` (The Request):** Owned by Users. Defines **What** is needed (e.g., "3 nodes, 4 CPU, 16GB RAM") but not **How** it is provided. +* **`HarvesterBlueprint` / `VsphereBlueprint` (The Tech Specs):** Holds low-level details (Image names, Networks, VM Namespaces). + +#### 2. The Logic Flow +1. **Gatekeeper:** Before doing anything, the Controller checks `Infra.Quota`. If `(Used + Request) > Max`, provisioning is **blocked**. +2. **Router:** The Controller reads `Infra.ProviderRef` and dynamically loads the correct **Strategy** (Harvester vs. vSphere). +3. **Builder:** A generic `MasterBuilder` combines the Strategy's output with a Base Helm Template to generate the final values. + +--- + +## 📂 Project Structure + +| Directory | Role | Description | +| :--- | :--- | :--- | +| `api/v1alpha1` | **The Contract** | Defines the CRDs (`ibp`, `cbp`, `hbp`). | +| `internal/controller` | **The Brain** | `ClusterBlueprint` (Provisioning/Gatekeeping) & `InfraBlueprint` (Accounting). | +| `internal/provider` | **The Interface** | Defines the `Strategy` interface that all clouds must obey. | +| `internal/provider/harvester`| **The Implementation** | Logic specific to Harvester (Identity minting, NodePool mapping). | +| `internal/builder` | **The Assembler** | Merges Strategy output with Helm Templates. Agnostic to the cloud provider. | +| `internal/helm` | **The Tool** | Wrapper around the Helm SDK (OCI supported). | +| `internal/templates` | **The Defaults** | Embedded YAML files containing default values (CPU/RAM, UserData). | + +--- + +## 🚀 Development Workflow + +### Prerequisites +* Go 1.22+ +* Helm v3 (Binary) +* Kubernetes Cluster (or local Kind/Minikube) +* `kubectl` pointing to your dev cluster + +### 1. Common Commands + +**Initial Setup (Download Dependencies):** +```bash +go mod tidy + +``` + +**Update APIs (CRDs):** +*Run this whenever you edit `api/v1alpha1/*.go*` + +```bash +make manifests generate + +``` + +**Run Locally:** +*Runs the controller against your current `~/.kube/config` context.* + +```bash +make install run + +``` + +### 2. Debugging (VS Code / Delve) + +`make run` is great for logs, but if you need to set breakpoints (e.g., to inspect the Helm Values map before it applies), use the debugger. + +**VS Code `launch.json` Configuration:** + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug RIG Operator", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${workspaceFolder}/cmd/main.go", + "args": [], + "env": { + "KUBECONFIG": "${userHome}/.kube/config" + } + } + ] +} + +``` + +1. Select **"Debug RIG Operator"** from the Run menu. +2. Set a breakpoint in `internal/controller/clusterblueprint_controller.go` (e.g., inside the `Reconcile` loop). +3. Apply a generic cluster manifest to trigger the breakpoint. + +--- + +## 🛠 Maintenance Guide + +### "I need to add a new field..." + +| Scenario | Files to Touch | Command to Run | +| --- | --- | --- | +| **Add a field to the API** (e.g., `ProxyURL` to Infra) | `api/v1alpha1/infrablueprint_types.go` | `make manifests generate` | +| **Update Default CPU/RAM** | `internal/templates/harvester/values.yaml` | `make build` (Recompiles embedded file) | +| **Change Harvester UserData logic** | `internal/provider/harvester/strategy.go` | `go test ./...` | +| **Add a new Cloud Provider (e.g. AWS)** | 1. Create `api/.../awsblueprint_types.go`
+ +
2. Create `internal/provider/aws/strategy.go`
+ +
3. Update `controller` switch case. | `make manifests generate` | + +### "The Quota isn't updating!" + +Remember that the **InfraController** is responsible for math. It watches `ClusterBlueprint` events. + +1. Check logs: `kubectl logs -l control-plane=controller-manager` +2. Ensure your Cluster actually points to the correct Infra name (`spec.infraBlueprintRef`). + +--- + +## 📊 Documentation & Diagrams + +Visual flows (Mermaid) are available in the `docs/` folder: + +* `docs/flow-diagram.svg`: High-level Request Flow. +* `docs/controllerflow.mermaid`: Detailed Controller logic. diff --git a/deploy/rig-operator/README.md b/deploy/rig-operator/README.md new file mode 100644 index 0000000..75175c2 --- /dev/null +++ b/deploy/rig-operator/README.md @@ -0,0 +1,135 @@ +# deploy +// TODO(user): Add simple overview of use/purpose + +## Description +// TODO(user): An in-depth paragraph about your project and overview of use + +## Getting Started + +### Prerequisites +- go version v1.24.6+ +- docker version 17.03+. +- kubectl version v1.11.3+. +- Access to a Kubernetes v1.11.3+ cluster. + +### To Deploy on the cluster +**Build and push your image to the location specified by `IMG`:** + +```sh +make docker-build docker-push IMG=/deploy:tag +``` + +**NOTE:** This image ought to be published in the personal registry you specified. +And it is required to have access to pull the image from the working environment. +Make sure you have the proper permission to the registry if the above commands don’t work. + +**Install the CRDs into the cluster:** + +```sh +make install +``` + +**Deploy the Manager to the cluster with the image specified by `IMG`:** + +```sh +make deploy IMG=/deploy:tag +``` + +> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin +privileges or be logged in as admin. + +**Create instances of your solution** +You can apply the samples (examples) from the config/sample: + +```sh +kubectl apply -k config/samples/ +``` + +>**NOTE**: Ensure that the samples has default values to test it out. + +### To Uninstall +**Delete the instances (CRs) from the cluster:** + +```sh +kubectl delete -k config/samples/ +``` + +**Delete the APIs(CRDs) from the cluster:** + +```sh +make uninstall +``` + +**UnDeploy the controller from the cluster:** + +```sh +make undeploy +``` + +## Project Distribution + +Following the options to release and provide this solution to the users. + +### By providing a bundle with all YAML files + +1. Build the installer for the image built and published in the registry: + +```sh +make build-installer IMG=/deploy:tag +``` + +**NOTE:** The makefile target mentioned above generates an 'install.yaml' +file in the dist directory. This file contains all the resources built +with Kustomize, which are necessary to install this project without its +dependencies. + +2. Using the installer + +Users can just run 'kubectl apply -f ' to install +the project, i.e.: + +```sh +kubectl apply -f https://raw.githubusercontent.com//deploy//dist/install.yaml +``` + +### By providing a Helm Chart + +1. Build the chart using the optional helm plugin + +```sh +kubebuilder edit --plugins=helm/v2-alpha +``` + +2. See that a chart was generated under 'dist/chart', and users +can obtain this solution from there. + +**NOTE:** If you change the project, you need to update the Helm Chart +using the same command above to sync the latest changes. Furthermore, +if you create webhooks, you need to use the above command with +the '--force' flag and manually ensure that any custom configuration +previously added to 'dist/chart/values.yaml' or 'dist/chart/manager/manager.yaml' +is manually re-applied afterwards. + +## Contributing +// TODO(user): Add detailed information on how you would like others to contribute to this project + +**NOTE:** Run `make help` for more information on all potential `make` targets + +More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) + +## License + +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/deploy/rig-operator/api/v1alpha1/clusterblueprint_types.go b/deploy/rig-operator/api/v1alpha1/clusterblueprint_types.go new file mode 100644 index 0000000..5aa5e59 --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/clusterblueprint_types.go @@ -0,0 +1,101 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GenericPoolReq defines a request for a set of nodes with specific sizing. +// This is provider-agnostic. +type GenericPoolReq struct { + // Name is the identifier for this node pool (e.g. "workers-gpu"). + // +required + Name string `json:"name"` + + // Quantity is the number of nodes desired. + // +required + // +kubebuilder:validation:Minimum=0 + Quantity int `json:"quantity"` + + // CpuCores is the number of vCPUs per node. + // +required + // +kubebuilder:validation:Minimum=1 + CpuCores int `json:"cpuCores"` + + // MemoryGB is the amount of RAM per node in Gigabytes. + // +required + // +kubebuilder:validation:Minimum=1 + MemoryGB int `json:"memoryGb"` + + // DiskGB is the root disk size per node in Gigabytes. + // +required + // +kubebuilder:validation:Minimum=10 + DiskGB int `json:"diskGb"` +} + +// ClusterBlueprintSpec defines the desired state of ClusterBlueprint +type ClusterBlueprintSpec struct { + // InfraBlueprintRef points to the InfraBlueprint (IBP) that manages + // the quotas and provider details for this cluster. + // +required + InfraBlueprintRef string `json:"infraBlueprintRef"` + + // KubernetesVersion is the target RKE2/K3s version (e.g., v1.28.0+rke2r1). + // +required + KubernetesVersion string `json:"kubernetesVersion"` + + // ControlPlaneHA determines if we provision 3 CP nodes (true) or 1 (false). + // +optional + ControlPlaneHA bool `json:"controlPlaneHA"` + + // WorkerPools is the list of worker node groups to provision. + // +optional + WorkerPools []GenericPoolReq `json:"workerPools,omitempty"` +} + +// IdentityStatus tracks the generated cloud provider identity +type IdentityStatus struct { + // SecretRef is the name of the generated secret used by this cluster. + SecretRef string `json:"secretRef,omitempty"` + + // ServiceAccount is the name of the SA created on the provider (if applicable). + ServiceAccount string `json:"serviceAccount,omitempty"` +} + +// ClusterBlueprintStatus defines the observed state of ClusterBlueprint +type ClusterBlueprintStatus struct { + // Ready indicates if the Helm Chart has been successfully applied. + Ready bool `json:"ready"` + + // Identity tracks the cloud credentials generated for this cluster. + // +optional + Identity *IdentityStatus `json:"identity,omitempty"` + + // Phase can be "Pending", "Provisioning", "Deployed", or "Failed" + // +optional + Phase string `json:"phase,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName=cbp +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase" +// +kubebuilder:printcolumn:name="K8s Version",type="string",JSONPath=".spec.kubernetesVersion" +// +kubebuilder:printcolumn:name="Infra",type="string",JSONPath=".spec.infraBlueprintRef" +type ClusterBlueprint struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ClusterBlueprintSpec `json:"spec,omitempty"` + Status ClusterBlueprintStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type ClusterBlueprintList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterBlueprint `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ClusterBlueprint{}, &ClusterBlueprintList{}) +} diff --git a/deploy/rig-operator/api/v1alpha1/groupversion_info.go b/deploy/rig-operator/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..c90c93a --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the rig v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=rig.appstack.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "rig.appstack.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/deploy/rig-operator/api/v1alpha1/harvesterblueprint_types.go b/deploy/rig-operator/api/v1alpha1/harvesterblueprint_types.go new file mode 100644 index 0000000..99e6bc1 --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/harvesterblueprint_types.go @@ -0,0 +1,59 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// HarvesterBlueprintSpec defines the desired state of HarvesterBlueprint +type HarvesterBlueprintSpec struct { + // HarvesterURL is the endpoint of the Harvester cluster (e.g. https://10.x.x.x:6443). + // This replaces the need for auto-discovery. + // +required + HarvesterURL string `json:"harvesterUrl"` + + // VmNamespace is the namespace in Harvester where VMs will be created. + // +required + VmNamespace string `json:"vmNamespace"` + + // ImageName is the specific image name in Harvester to clone (e.g. image-abcde). + // +required + ImageName string `json:"imageName"` + + // NetworkName is the VM Network to attach to the nodes. + // +required + NetworkName string `json:"networkName"` + + // SshUser is the username to configure on the VM (e.g. ubuntu, rancher). + // +required + SshUser string `json:"sshUser"` +} + +// HarvesterBlueprintStatus defines the observed state of HarvesterBlueprint +type HarvesterBlueprintStatus struct { + // Ready indicates the configuration is valid (optional future use) + Ready bool `json:"ready,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName=hbp +type HarvesterBlueprint struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HarvesterBlueprintSpec `json:"spec,omitempty"` + Status HarvesterBlueprintStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// HarvesterBlueprintList contains a list of HarvesterBlueprint +type HarvesterBlueprintList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HarvesterBlueprint `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HarvesterBlueprint{}, &HarvesterBlueprintList{}) +} diff --git a/deploy/rig-operator/api/v1alpha1/infrablueprint_types.go b/deploy/rig-operator/api/v1alpha1/infrablueprint_types.go new file mode 100644 index 0000000..de4d48f --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/infrablueprint_types.go @@ -0,0 +1,112 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// InfraQuota defines the resource limits for this infrastructure account +type InfraQuota struct { + // MaxCPU is the total number of cores allowed across all clusters + // +optional + MaxCPU int `json:"maxCpu,omitempty"` + + // MaxMemoryGB is the total RAM (in GB) allowed across all clusters + // +optional + MaxMemoryGB int `json:"maxMemoryGb,omitempty"` + + // MaxDiskGB is the total Storage (in GB) allowed across all clusters + // +optional + MaxDiskGB int `json:"maxDiskGb,omitempty"` +} + +// InfraQuotaStatus tracks current usage +type InfraQuotaStatus struct { + // UsedCPU is the sum of cores currently provisioned + UsedCPU int `json:"usedCpu"` + + // UsedMemoryGB is the sum of RAM currently provisioned + UsedMemoryGB int `json:"usedMemoryGb"` + + // UsedDiskGB tracks storage consumption + UsedDiskGB int `json:"usedDiskGb"` +} + +// ProviderRef points to the specific provider configuration (HBP or VBP) +type ProviderRef struct { + // Kind is the type of resource being referenced (e.g., HarvesterBlueprint) + // +required + Kind string `json:"kind"` + + // Name is the name of resource being referenced + // +required + Name string `json:"name"` + + // APIGroup defaults to rig.appstack.io if not specified + // +optional + APIGroup string `json:"apiGroup,omitempty"` +} + +// InfraBlueprintSpec defines the desired state of InfraBlueprint +type InfraBlueprintSpec struct { + // RancherURL is the public URL of the Rancher Manager (e.g. https://rancher.example.com) + // This is injected into the Helm Chart to register the cluster. + // +required + RancherURL string `json:"rancherUrl"` + + // CloudCredentialSecret is the name of the Secret containing the + // master cloud credentials (e.g., kubeconfig or username/password). + // +required + CloudCredentialSecret string `json:"cloudCredentialSecret"` + + // ProviderRef points to the technical configuration (HarvesterBlueprint/VsphereBlueprint). + // +required + ProviderRef ProviderRef `json:"providerRef"` + + // Quota defines the maximum resources allocatable by this Infra. + // +optional + Quota InfraQuota `json:"quota,omitempty"` + + // UserData is the default cloud-init user data for all clusters in this Infra. + // +optional + UserData string `json:"userData,omitempty"` +} + +// InfraBlueprintStatus defines the observed state of InfraBlueprint +type InfraBlueprintStatus struct { + // Ready indicates the provider connection is verified + Ready bool `json:"ready,omitempty"` + + // Usage tracks the current resource consumption + Usage InfraQuotaStatus `json:"usage,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName=ibp +// +kubebuilder:printcolumn:name="Ready",type="boolean",JSONPath=".status.ready" +// +kubebuilder:printcolumn:name="MaxCPU",type="integer",JSONPath=".spec.quota.maxCpu" +// +kubebuilder:printcolumn:name="UsedCPU",type="integer",JSONPath=".status.usage.usedCpu" +// +kubebuilder:printcolumn:name="MaxMem(GB)",type="integer",JSONPath=".spec.quota.maxMemoryGb" +// +kubebuilder:printcolumn:name="UsedMem(GB)",type="integer",JSONPath=".status.usage.usedMemoryGb" +// +kubebuilder:printcolumn:name="MaxDisk(GB)",type="integer",JSONPath=".spec.quota.maxDiskGb" +// +kubebuilder:printcolumn:name="UsedDisk(GB)",type="integer",JSONPath=".status.usage.usedDiskGb" +type InfraBlueprint struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec InfraBlueprintSpec `json:"spec,omitempty"` + Status InfraBlueprintStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// InfraBlueprintList contains a list of InfraBlueprint +type InfraBlueprintList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []InfraBlueprint `json:"items"` +} + +func init() { + SchemeBuilder.Register(&InfraBlueprint{}, &InfraBlueprintList{}) +} diff --git a/deploy/rig-operator/api/v1alpha1/vsphereblueprint_types.go b/deploy/rig-operator/api/v1alpha1/vsphereblueprint_types.go new file mode 100644 index 0000000..1b268c3 --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/vsphereblueprint_types.go @@ -0,0 +1,67 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VsphereBlueprintSpec defines the desired state of VsphereBlueprint +type VsphereBlueprintSpec struct { + // vCenter address (e.g. vcenter.example.com) + // +required + VCenter string `json:"vCenter"` + + // Datacenter name (e.g. NL001) + // +required + Datacenter string `json:"datacenter"` + + // Folder path where VMs will be organized (e.g. "ICT Digitalisation - Rancher") + // +required + Folder string `json:"folder"` + + // ResourcePool path (e.g. "NL001 Development - Rancher/Resources") + // +required + ResourcePool string `json:"resourcePool"` + + // DatastoreCluster or Datastore name (e.g. "NL001 Development - Rancher SDRS") + // +required + Datastore string `json:"datastore"` + + // Network name to attach to (e.g. "nl001.vDS.Distri.Vlan.1542") + // +required + Network string `json:"network"` + + // Template is the VM template name to clone from + // +required + Template string `json:"template"` +} + +// VsphereBlueprintStatus defines the observed state +type VsphereBlueprintStatus struct { + Ready bool `json:"ready,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:shortName=vbp + +// VsphereBlueprint is the Schema for the vsphereblueprints API +type VsphereBlueprint struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VsphereBlueprintSpec `json:"spec,omitempty"` + Status VsphereBlueprintStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// VsphereBlueprintList contains a list of VsphereBlueprint +type VsphereBlueprintList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VsphereBlueprint `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VsphereBlueprint{}, &VsphereBlueprintList{}) +} diff --git a/deploy/rig-operator/api/v1alpha1/zz_generated.deepcopy.go b/deploy/rig-operator/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..1f79af9 --- /dev/null +++ b/deploy/rig-operator/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,469 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBlueprint) DeepCopyInto(out *ClusterBlueprint) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBlueprint. +func (in *ClusterBlueprint) DeepCopy() *ClusterBlueprint { + if in == nil { + return nil + } + out := new(ClusterBlueprint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterBlueprint) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBlueprintList) DeepCopyInto(out *ClusterBlueprintList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterBlueprint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBlueprintList. +func (in *ClusterBlueprintList) DeepCopy() *ClusterBlueprintList { + if in == nil { + return nil + } + out := new(ClusterBlueprintList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterBlueprintList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBlueprintSpec) DeepCopyInto(out *ClusterBlueprintSpec) { + *out = *in + if in.WorkerPools != nil { + in, out := &in.WorkerPools, &out.WorkerPools + *out = make([]GenericPoolReq, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBlueprintSpec. +func (in *ClusterBlueprintSpec) DeepCopy() *ClusterBlueprintSpec { + if in == nil { + return nil + } + out := new(ClusterBlueprintSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBlueprintStatus) DeepCopyInto(out *ClusterBlueprintStatus) { + *out = *in + if in.Identity != nil { + in, out := &in.Identity, &out.Identity + *out = new(IdentityStatus) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBlueprintStatus. +func (in *ClusterBlueprintStatus) DeepCopy() *ClusterBlueprintStatus { + if in == nil { + return nil + } + out := new(ClusterBlueprintStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GenericPoolReq) DeepCopyInto(out *GenericPoolReq) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPoolReq. +func (in *GenericPoolReq) DeepCopy() *GenericPoolReq { + if in == nil { + return nil + } + out := new(GenericPoolReq) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HarvesterBlueprint) DeepCopyInto(out *HarvesterBlueprint) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HarvesterBlueprint. +func (in *HarvesterBlueprint) DeepCopy() *HarvesterBlueprint { + if in == nil { + return nil + } + out := new(HarvesterBlueprint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HarvesterBlueprint) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HarvesterBlueprintList) DeepCopyInto(out *HarvesterBlueprintList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HarvesterBlueprint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HarvesterBlueprintList. +func (in *HarvesterBlueprintList) DeepCopy() *HarvesterBlueprintList { + if in == nil { + return nil + } + out := new(HarvesterBlueprintList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HarvesterBlueprintList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HarvesterBlueprintSpec) DeepCopyInto(out *HarvesterBlueprintSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HarvesterBlueprintSpec. +func (in *HarvesterBlueprintSpec) DeepCopy() *HarvesterBlueprintSpec { + if in == nil { + return nil + } + out := new(HarvesterBlueprintSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HarvesterBlueprintStatus) DeepCopyInto(out *HarvesterBlueprintStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HarvesterBlueprintStatus. +func (in *HarvesterBlueprintStatus) DeepCopy() *HarvesterBlueprintStatus { + if in == nil { + return nil + } + out := new(HarvesterBlueprintStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IdentityStatus) DeepCopyInto(out *IdentityStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IdentityStatus. +func (in *IdentityStatus) DeepCopy() *IdentityStatus { + if in == nil { + return nil + } + out := new(IdentityStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraBlueprint) DeepCopyInto(out *InfraBlueprint) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraBlueprint. +func (in *InfraBlueprint) DeepCopy() *InfraBlueprint { + if in == nil { + return nil + } + out := new(InfraBlueprint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InfraBlueprint) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraBlueprintList) DeepCopyInto(out *InfraBlueprintList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]InfraBlueprint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraBlueprintList. +func (in *InfraBlueprintList) DeepCopy() *InfraBlueprintList { + if in == nil { + return nil + } + out := new(InfraBlueprintList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InfraBlueprintList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraBlueprintSpec) DeepCopyInto(out *InfraBlueprintSpec) { + *out = *in + out.ProviderRef = in.ProviderRef + out.Quota = in.Quota +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraBlueprintSpec. +func (in *InfraBlueprintSpec) DeepCopy() *InfraBlueprintSpec { + if in == nil { + return nil + } + out := new(InfraBlueprintSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraBlueprintStatus) DeepCopyInto(out *InfraBlueprintStatus) { + *out = *in + out.Usage = in.Usage +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraBlueprintStatus. +func (in *InfraBlueprintStatus) DeepCopy() *InfraBlueprintStatus { + if in == nil { + return nil + } + out := new(InfraBlueprintStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraQuota) DeepCopyInto(out *InfraQuota) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraQuota. +func (in *InfraQuota) DeepCopy() *InfraQuota { + if in == nil { + return nil + } + out := new(InfraQuota) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InfraQuotaStatus) DeepCopyInto(out *InfraQuotaStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfraQuotaStatus. +func (in *InfraQuotaStatus) DeepCopy() *InfraQuotaStatus { + if in == nil { + return nil + } + out := new(InfraQuotaStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProviderRef) DeepCopyInto(out *ProviderRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderRef. +func (in *ProviderRef) DeepCopy() *ProviderRef { + if in == nil { + return nil + } + out := new(ProviderRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VsphereBlueprint) DeepCopyInto(out *VsphereBlueprint) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VsphereBlueprint. +func (in *VsphereBlueprint) DeepCopy() *VsphereBlueprint { + if in == nil { + return nil + } + out := new(VsphereBlueprint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VsphereBlueprint) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VsphereBlueprintList) DeepCopyInto(out *VsphereBlueprintList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VsphereBlueprint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VsphereBlueprintList. +func (in *VsphereBlueprintList) DeepCopy() *VsphereBlueprintList { + if in == nil { + return nil + } + out := new(VsphereBlueprintList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VsphereBlueprintList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VsphereBlueprintSpec) DeepCopyInto(out *VsphereBlueprintSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VsphereBlueprintSpec. +func (in *VsphereBlueprintSpec) DeepCopy() *VsphereBlueprintSpec { + if in == nil { + return nil + } + out := new(VsphereBlueprintSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VsphereBlueprintStatus) DeepCopyInto(out *VsphereBlueprintStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VsphereBlueprintStatus. +func (in *VsphereBlueprintStatus) DeepCopy() *VsphereBlueprintStatus { + if in == nil { + return nil + } + out := new(VsphereBlueprintStatus) + in.DeepCopyInto(out) + return out +} diff --git a/deploy/rig-operator/cmd/main.go b/deploy/rig-operator/cmd/main.go new file mode 100644 index 0000000..aceb7e9 --- /dev/null +++ b/deploy/rig-operator/cmd/main.go @@ -0,0 +1,213 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + rigv1alpha1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + "vanderlande.com/ittp/appstack/rig-operator/internal/controller" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(rigv1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +// nolint:gocyclo +func main() { + var metricsAddr string + var metricsCertPath, metricsCertName, metricsCertKey string + var webhookCertPath, webhookCertName, webhookCertKey string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.") + flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.") + flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.") + flag.StringVar(&metricsCertPath, "metrics-cert-path", "", + "The directory that contains the metrics server certificate.") + flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") + flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + // Initial webhook TLS options + webhookTLSOpts := tlsOpts + webhookServerOptions := webhook.Options{ + TLSOpts: webhookTLSOpts, + } + + if len(webhookCertPath) > 0 { + setupLog.Info("Initializing webhook certificate watcher using provided certificates", + "webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey) + + webhookServerOptions.CertDir = webhookCertPath + webhookServerOptions.CertName = webhookCertName + webhookServerOptions.KeyName = webhookCertKey + } + + webhookServer := webhook.NewServer(webhookServerOptions) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.4/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.22.4/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + } + + // If the certificate is not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + // + // TODO(user): If you enable certManager, uncomment the following lines: + // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates + // managed by cert-manager for the metrics server. + // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification. + if len(metricsCertPath) > 0 { + setupLog.Info("Initializing metrics certificate watcher using provided certificates", + "metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey) + + metricsServerOptions.CertDir = metricsCertPath + metricsServerOptions.CertName = metricsCertName + metricsServerOptions.KeyName = metricsCertKey + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "47b7cef0.appstack.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err := (&controller.ClusterBlueprintReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + // [IMPORTANT] Add this line to enable event broadcasting + Recorder: mgr.GetEventRecorderFor("rig-operator"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ClusterBlueprint") + os.Exit(1) + } + if err := (&controller.InfraBlueprintReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "InfraBlueprint") + os.Exit(1) + } + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/deploy/rig-operator/config/crd/bases/rig.appstack.io_clusterblueprints.yaml b/deploy/rig-operator/config/crd/bases/rig.appstack.io_clusterblueprints.yaml new file mode 100644 index 0000000..c9b0b3c --- /dev/null +++ b/deploy/rig-operator/config/crd/bases/rig.appstack.io_clusterblueprints.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: clusterblueprints.rig.appstack.io +spec: + group: rig.appstack.io + names: + kind: ClusterBlueprint + listKind: ClusterBlueprintList + plural: clusterblueprints + shortNames: + - cbp + singular: clusterblueprint + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + - jsonPath: .spec.kubernetesVersion + name: K8s Version + type: string + - jsonPath: .spec.infraBlueprintRef + name: Infra + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ClusterBlueprintSpec defines the desired state of ClusterBlueprint + properties: + controlPlaneHA: + description: ControlPlaneHA determines if we provision 3 CP nodes + (true) or 1 (false). + type: boolean + infraBlueprintRef: + description: |- + InfraBlueprintRef points to the InfraBlueprint (IBP) that manages + the quotas and provider details for this cluster. + type: string + kubernetesVersion: + description: KubernetesVersion is the target RKE2/K3s version (e.g., + v1.28.0+rke2r1). + type: string + workerPools: + description: WorkerPools is the list of worker node groups to provision. + items: + description: |- + GenericPoolReq defines a request for a set of nodes with specific sizing. + This is provider-agnostic. + properties: + cpuCores: + description: CpuCores is the number of vCPUs per node. + minimum: 1 + type: integer + diskGb: + description: DiskGB is the root disk size per node in Gigabytes. + minimum: 10 + type: integer + memoryGb: + description: MemoryGB is the amount of RAM per node in Gigabytes. + minimum: 1 + type: integer + name: + description: Name is the identifier for this node pool (e.g. + "workers-gpu"). + type: string + quantity: + description: Quantity is the number of nodes desired. + minimum: 0 + type: integer + required: + - cpuCores + - diskGb + - memoryGb + - name + - quantity + type: object + type: array + required: + - infraBlueprintRef + - kubernetesVersion + type: object + status: + description: ClusterBlueprintStatus defines the observed state of ClusterBlueprint + properties: + identity: + description: Identity tracks the cloud credentials generated for this + cluster. + properties: + secretRef: + description: SecretRef is the name of the generated secret used + by this cluster. + type: string + serviceAccount: + description: ServiceAccount is the name of the SA created on the + provider (if applicable). + type: string + type: object + phase: + description: Phase can be "Pending", "Provisioning", "Deployed", or + "Failed" + type: string + ready: + description: Ready indicates if the Helm Chart has been successfully + applied. + type: boolean + required: + - ready + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/rig-operator/config/crd/bases/rig.appstack.io_harvesterblueprints.yaml b/deploy/rig-operator/config/crd/bases/rig.appstack.io_harvesterblueprints.yaml new file mode 100644 index 0000000..cac7ea4 --- /dev/null +++ b/deploy/rig-operator/config/crd/bases/rig.appstack.io_harvesterblueprints.yaml @@ -0,0 +1,82 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: harvesterblueprints.rig.appstack.io +spec: + group: rig.appstack.io + names: + kind: HarvesterBlueprint + listKind: HarvesterBlueprintList + plural: harvesterblueprints + shortNames: + - hbp + singular: harvesterblueprint + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: HarvesterBlueprintSpec defines the desired state of HarvesterBlueprint + properties: + harvesterUrl: + description: |- + HarvesterURL is the endpoint of the Harvester cluster (e.g. https://10.x.x.x:6443). + This replaces the need for auto-discovery. + type: string + imageName: + description: ImageName is the specific image name in Harvester to + clone (e.g. image-abcde). + type: string + networkName: + description: NetworkName is the VM Network to attach to the nodes. + type: string + sshUser: + description: SshUser is the username to configure on the VM (e.g. + ubuntu, rancher). + type: string + vmNamespace: + description: VmNamespace is the namespace in Harvester where VMs will + be created. + type: string + required: + - harvesterUrl + - imageName + - networkName + - sshUser + - vmNamespace + type: object + status: + description: HarvesterBlueprintStatus defines the observed state of HarvesterBlueprint + properties: + ready: + description: Ready indicates the configuration is valid (optional + future use) + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/rig-operator/config/crd/bases/rig.appstack.io_infrablueprints.yaml b/deploy/rig-operator/config/crd/bases/rig.appstack.io_infrablueprints.yaml new file mode 100644 index 0000000..20f7d8e --- /dev/null +++ b/deploy/rig-operator/config/crd/bases/rig.appstack.io_infrablueprints.yaml @@ -0,0 +1,146 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: infrablueprints.rig.appstack.io +spec: + group: rig.appstack.io + names: + kind: InfraBlueprint + listKind: InfraBlueprintList + plural: infrablueprints + shortNames: + - ibp + singular: infrablueprint + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.ready + name: Ready + type: boolean + - jsonPath: .spec.quota.maxCpu + name: MaxCPU + type: integer + - jsonPath: .status.usage.usedCpu + name: UsedCPU + type: integer + - jsonPath: .spec.quota.maxMemoryGb + name: MaxMem(GB) + type: integer + - jsonPath: .status.usage.usedMemoryGb + name: UsedMem(GB) + type: integer + - jsonPath: .spec.quota.maxDiskGb + name: MaxDisk(GB) + type: integer + - jsonPath: .status.usage.usedDiskGb + name: UsedDisk(GB) + type: integer + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: InfraBlueprintSpec defines the desired state of InfraBlueprint + properties: + cloudCredentialSecret: + description: |- + CloudCredentialSecret is the name of the Secret containing the + master cloud credentials (e.g., kubeconfig or username/password). + type: string + providerRef: + description: ProviderRef points to the technical configuration (HarvesterBlueprint/VsphereBlueprint). + properties: + apiGroup: + description: APIGroup defaults to rig.appstack.io if not specified + type: string + kind: + description: Kind is the type of resource being referenced (e.g., + HarvesterBlueprint) + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + quota: + description: Quota defines the maximum resources allocatable by this + Infra. + properties: + maxCpu: + description: MaxCPU is the total number of cores allowed across + all clusters + type: integer + maxDiskGb: + description: MaxDiskGB is the total Storage (in GB) allowed across + all clusters + type: integer + maxMemoryGb: + description: MaxMemoryGB is the total RAM (in GB) allowed across + all clusters + type: integer + type: object + rancherUrl: + description: |- + RancherURL is the public URL of the Rancher Manager (e.g. https://rancher.example.com) + This is injected into the Helm Chart to register the cluster. + type: string + userData: + description: UserData is the default cloud-init user data for all + clusters in this Infra. + type: string + required: + - cloudCredentialSecret + - providerRef + - rancherUrl + type: object + status: + description: InfraBlueprintStatus defines the observed state of InfraBlueprint + properties: + ready: + description: Ready indicates the provider connection is verified + type: boolean + usage: + description: Usage tracks the current resource consumption + properties: + usedCpu: + description: UsedCPU is the sum of cores currently provisioned + type: integer + usedDiskGb: + description: UsedDiskGB tracks storage consumption + type: integer + usedMemoryGb: + description: UsedMemoryGB is the sum of RAM currently provisioned + type: integer + required: + - usedCpu + - usedDiskGb + - usedMemoryGb + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/rig-operator/config/crd/bases/rig.appstack.io_vsphereblueprints.yaml b/deploy/rig-operator/config/crd/bases/rig.appstack.io_vsphereblueprints.yaml new file mode 100644 index 0000000..84cfe79 --- /dev/null +++ b/deploy/rig-operator/config/crd/bases/rig.appstack.io_vsphereblueprints.yaml @@ -0,0 +1,86 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: vsphereblueprints.rig.appstack.io +spec: + group: rig.appstack.io + names: + kind: VsphereBlueprint + listKind: VsphereBlueprintList + plural: vsphereblueprints + shortNames: + - vbp + singular: vsphereblueprint + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: VsphereBlueprint is the Schema for the vsphereblueprints API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: VsphereBlueprintSpec defines the desired state of VsphereBlueprint + properties: + datacenter: + description: Datacenter name (e.g. NL001) + type: string + datastore: + description: DatastoreCluster or Datastore name (e.g. "NL001 Development + - Rancher SDRS") + type: string + folder: + description: Folder path where VMs will be organized (e.g. "ICT Digitalisation + - Rancher") + type: string + network: + description: Network name to attach to (e.g. "nl001.vDS.Distri.Vlan.1542") + type: string + resourcePool: + description: ResourcePool path (e.g. "NL001 Development - Rancher/Resources") + type: string + template: + description: Template is the VM template name to clone from + type: string + vCenter: + description: vCenter address (e.g. vcenter.example.com) + type: string + required: + - datacenter + - datastore + - folder + - network + - resourcePool + - template + - vCenter + type: object + status: + description: VsphereBlueprintStatus defines the observed state + properties: + ready: + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/rig-operator/config/crd/kustomization.yaml b/deploy/rig-operator/config/crd/kustomization.yaml new file mode 100644 index 0000000..fae5f90 --- /dev/null +++ b/deploy/rig-operator/config/crd/kustomization.yaml @@ -0,0 +1,19 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/rig.appstack.io_clusterblueprints.yaml +- bases/rig.appstack.io_infrablueprints.yaml +- bases/rig.appstack.io_harvesterblueprints.yaml +- bases/rig.appstack.io_vsphereblueprints.yaml +# +kubebuilder:scaffold:crdkustomizeresource + +patches: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +# +kubebuilder:scaffold:crdkustomizewebhookpatch + +# [WEBHOOK] To enable webhook, uncomment the following section +# the following config is for teaching kustomize how to do kustomization for CRDs. +#configurations: +#- kustomizeconfig.yaml diff --git a/deploy/rig-operator/config/crd/kustomizeconfig.yaml b/deploy/rig-operator/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000..ec5c150 --- /dev/null +++ b/deploy/rig-operator/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/deploy/rig-operator/config/default/cert_metrics_manager_patch.yaml b/deploy/rig-operator/config/default/cert_metrics_manager_patch.yaml new file mode 100644 index 0000000..d975015 --- /dev/null +++ b/deploy/rig-operator/config/default/cert_metrics_manager_patch.yaml @@ -0,0 +1,30 @@ +# This patch adds the args, volumes, and ports to allow the manager to use the metrics-server certs. + +# Add the volumeMount for the metrics-server certs +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + mountPath: /tmp/k8s-metrics-server/metrics-certs + name: metrics-certs + readOnly: true + +# Add the --metrics-cert-path argument for the metrics server +- op: add + path: /spec/template/spec/containers/0/args/- + value: --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs + +# Add the metrics-server certs volume configuration +- op: add + path: /spec/template/spec/volumes/- + value: + name: metrics-certs + secret: + secretName: metrics-server-cert + optional: false + items: + - key: ca.crt + path: ca.crt + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key diff --git a/deploy/rig-operator/config/default/kustomization.yaml b/deploy/rig-operator/config/default/kustomization.yaml new file mode 100644 index 0000000..bb35f39 --- /dev/null +++ b/deploy/rig-operator/config/default/kustomization.yaml @@ -0,0 +1,234 @@ +# Adds namespace to all resources. +namespace: deploy-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: deploy- + +# Labels to add to all resources and selectors. +#labels: +#- includeSelectors: true +# pairs: +# someName: someValue + +resources: +- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus +# [METRICS] Expose the controller manager metrics service. +- metrics_service.yaml +# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy. +# Only Pod(s) running a namespace labeled with 'metrics: enabled' will be able to gather the metrics. +# Only CR(s) which requires webhooks and are applied on namespaces labeled with 'webhooks: enabled' will +# be able to communicate with the Webhook Server. +#- ../network-policy + +# Uncomment the patches line if you enable Metrics +patches: +# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443. +# More info: https://book.kubebuilder.io/reference/metrics +- path: manager_metrics_patch.yaml + target: + kind: Deployment + +# Uncomment the patches line if you enable Metrics and CertManager +# [METRICS-WITH-CERTS] To enable metrics protected with certManager, uncomment the following line. +# This patch will protect the metrics with certManager self-signed certs. +#- path: cert_metrics_manager_patch.yaml +# target: +# kind: Deployment + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- path: manager_webhook_patch.yaml +# target: +# kind: Deployment + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +# Uncomment the following replacements to add the cert-manager CA injection annotations +#replacements: +# - source: # Uncomment the following block to enable certificates for metrics +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.name +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - select: # Uncomment the following to set the Service name for TLS config in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 0 +# create: true + +# - source: +# kind: Service +# version: v1 +# name: controller-manager-metrics-service +# fieldPath: metadata.namespace +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: metrics-certs +# fieldPaths: +# - spec.dnsNames.0 +# - spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true +# - select: # Uncomment the following to set the Service namespace for TLS in Prometheus ServiceMonitor +# kind: ServiceMonitor +# group: monitoring.coreos.com +# version: v1 +# name: controller-manager-metrics-monitor +# fieldPaths: +# - spec.endpoints.0.tlsConfig.serverName +# options: +# delimiter: '.' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have any webhook +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # Name of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 0 +# create: true +# - source: +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.namespace # Namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert # This name should match the one in certificate.yaml +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a DefaultingWebhook (--defaulting ) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true + +# - source: # Uncomment the following block if you have a ConversionWebhook (--conversion) +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.namespace # Namespace of the certificate CR +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionns +# - source: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# name: serving-cert +# fieldPath: .metadata.name +# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD. +# +kubebuilder:scaffold:crdkustomizecainjectionname diff --git a/deploy/rig-operator/config/default/manager_metrics_patch.yaml b/deploy/rig-operator/config/default/manager_metrics_patch.yaml new file mode 100644 index 0000000..2aaef65 --- /dev/null +++ b/deploy/rig-operator/config/default/manager_metrics_patch.yaml @@ -0,0 +1,4 @@ +# This patch adds the args to allow exposing the metrics endpoint using HTTPS +- op: add + path: /spec/template/spec/containers/0/args/0 + value: --metrics-bind-address=:8443 diff --git a/deploy/rig-operator/config/default/metrics_service.yaml b/deploy/rig-operator/config/default/metrics_service.yaml new file mode 100644 index 0000000..1c552fd --- /dev/null +++ b/deploy/rig-operator/config/default/metrics_service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: 8443 + selector: + control-plane: controller-manager + app.kubernetes.io/name: deploy diff --git a/deploy/rig-operator/config/manager/kustomization.yaml b/deploy/rig-operator/config/manager/kustomization.yaml new file mode 100644 index 0000000..5c5f0b8 --- /dev/null +++ b/deploy/rig-operator/config/manager/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- manager.yaml diff --git a/deploy/rig-operator/config/manager/manager.yaml b/deploy/rig-operator/config/manager/manager.yaml new file mode 100644 index 0000000..56c7047 --- /dev/null +++ b/deploy/rig-operator/config/manager/manager.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + spec: + # TODO(user): Uncomment the following code to configure the nodeAffinity expression + # according to the platforms which are supported by your solution. + # It is considered best practice to support multiple architectures. You can + # build your manager image using the makefile target docker-buildx. + # affinity: + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/arch + # operator: In + # values: + # - amd64 + # - arm64 + # - ppc64le + # - s390x + # - key: kubernetes.io/os + # operator: In + # values: + # - linux + securityContext: + # Projects are configured by default to adhere to the "restricted" Pod Security Standards. + # This ensures that deployments meet the highest security requirements for Kubernetes. + # For more details, see: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + - --health-probe-bind-address=:8081 + image: controller:latest + name: manager + ports: [] + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + # TODO(user): Configure the resources accordingly based on the project requirements. + # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + volumeMounts: [] + volumes: [] + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 diff --git a/deploy/rig-operator/config/network-policy/allow-metrics-traffic.yaml b/deploy/rig-operator/config/network-policy/allow-metrics-traffic.yaml new file mode 100644 index 0000000..ca4e31d --- /dev/null +++ b/deploy/rig-operator/config/network-policy/allow-metrics-traffic.yaml @@ -0,0 +1,27 @@ +# This NetworkPolicy allows ingress traffic +# with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those +# namespaces are able to gather data from the metrics endpoint. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: allow-metrics-traffic + namespace: system +spec: + podSelector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + policyTypes: + - Ingress + ingress: + # This allows ingress traffic from any namespace with the label metrics: enabled + - from: + - namespaceSelector: + matchLabels: + metrics: enabled # Only from namespaces with this label + ports: + - port: 8443 + protocol: TCP diff --git a/deploy/rig-operator/config/network-policy/kustomization.yaml b/deploy/rig-operator/config/network-policy/kustomization.yaml new file mode 100644 index 0000000..ec0fb5e --- /dev/null +++ b/deploy/rig-operator/config/network-policy/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- allow-metrics-traffic.yaml diff --git a/deploy/rig-operator/config/prometheus/kustomization.yaml b/deploy/rig-operator/config/prometheus/kustomization.yaml new file mode 100644 index 0000000..fdc5481 --- /dev/null +++ b/deploy/rig-operator/config/prometheus/kustomization.yaml @@ -0,0 +1,11 @@ +resources: +- monitor.yaml + +# [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus +# to securely reference certificates created and managed by cert-manager. +# Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml +# to mount the "metrics-server-cert" secret in the Manager Deployment. +#patches: +# - path: monitor_tls_patch.yaml +# target: +# kind: ServiceMonitor diff --git a/deploy/rig-operator/config/prometheus/monitor.yaml b/deploy/rig-operator/config/prometheus/monitor.yaml new file mode 100644 index 0000000..16f5f6b --- /dev/null +++ b/deploy/rig-operator/config/prometheus/monitor.yaml @@ -0,0 +1,27 @@ +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https # Ensure this is the name of the port that exposes HTTPS metrics + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + # TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables + # certificate verification, exposing the system to potential man-in-the-middle attacks. + # For production environments, it is recommended to use cert-manager for automatic TLS certificate management. + # To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml, + # which securely references the certificate from the 'metrics-server-cert' secret. + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager + app.kubernetes.io/name: deploy diff --git a/deploy/rig-operator/config/prometheus/monitor_tls_patch.yaml b/deploy/rig-operator/config/prometheus/monitor_tls_patch.yaml new file mode 100644 index 0000000..5bf84ce --- /dev/null +++ b/deploy/rig-operator/config/prometheus/monitor_tls_patch.yaml @@ -0,0 +1,19 @@ +# Patch for Prometheus ServiceMonitor to enable secure TLS configuration +# using certificates managed by cert-manager +- op: replace + path: /spec/endpoints/0/tlsConfig + value: + # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize + serverName: SERVICE_NAME.SERVICE_NAMESPACE.svc + insecureSkipVerify: false + ca: + secret: + name: metrics-server-cert + key: ca.crt + cert: + secret: + name: metrics-server-cert + key: tls.crt + keySecret: + name: metrics-server-cert + key: tls.key diff --git a/deploy/rig-operator/config/rbac/clusterblueprint_admin_role.yaml b/deploy/rig-operator/config/rbac/clusterblueprint_admin_role.yaml new file mode 100644 index 0000000..342a000 --- /dev/null +++ b/deploy/rig-operator/config/rbac/clusterblueprint_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over rig.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: clusterblueprint-admin-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints + verbs: + - '*' +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/clusterblueprint_editor_role.yaml b/deploy/rig-operator/config/rbac/clusterblueprint_editor_role.yaml new file mode 100644 index 0000000..cc08280 --- /dev/null +++ b/deploy/rig-operator/config/rbac/clusterblueprint_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the rig.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: clusterblueprint-editor-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/clusterblueprint_viewer_role.yaml b/deploy/rig-operator/config/rbac/clusterblueprint_viewer_role.yaml new file mode 100644 index 0000000..f9298a7 --- /dev/null +++ b/deploy/rig-operator/config/rbac/clusterblueprint_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to rig.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: clusterblueprint-viewer-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints + verbs: + - get + - list + - watch +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/harvesterblueprint_admin_role.yaml b/deploy/rig-operator/config/rbac/harvesterblueprint_admin_role.yaml new file mode 100644 index 0000000..0b951cd --- /dev/null +++ b/deploy/rig-operator/config/rbac/harvesterblueprint_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over rig.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: harvesterblueprint-admin-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints + verbs: + - '*' +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/harvesterblueprint_editor_role.yaml b/deploy/rig-operator/config/rbac/harvesterblueprint_editor_role.yaml new file mode 100644 index 0000000..f8ab0a7 --- /dev/null +++ b/deploy/rig-operator/config/rbac/harvesterblueprint_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the rig.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: harvesterblueprint-editor-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/harvesterblueprint_viewer_role.yaml b/deploy/rig-operator/config/rbac/harvesterblueprint_viewer_role.yaml new file mode 100644 index 0000000..5ea0b10 --- /dev/null +++ b/deploy/rig-operator/config/rbac/harvesterblueprint_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to rig.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: harvesterblueprint-viewer-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints + verbs: + - get + - list + - watch +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/infrablueprint_admin_role.yaml b/deploy/rig-operator/config/rbac/infrablueprint_admin_role.yaml new file mode 100644 index 0000000..26e7ff0 --- /dev/null +++ b/deploy/rig-operator/config/rbac/infrablueprint_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over rig.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: infrablueprint-admin-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints + verbs: + - '*' +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/infrablueprint_editor_role.yaml b/deploy/rig-operator/config/rbac/infrablueprint_editor_role.yaml new file mode 100644 index 0000000..2c08135 --- /dev/null +++ b/deploy/rig-operator/config/rbac/infrablueprint_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the rig.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: infrablueprint-editor-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/infrablueprint_viewer_role.yaml b/deploy/rig-operator/config/rbac/infrablueprint_viewer_role.yaml new file mode 100644 index 0000000..68d9170 --- /dev/null +++ b/deploy/rig-operator/config/rbac/infrablueprint_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to rig.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: infrablueprint-viewer-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints + verbs: + - get + - list + - watch +- apiGroups: + - rig.appstack.io + resources: + - infrablueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/kustomization.yaml b/deploy/rig-operator/config/rbac/kustomization.yaml new file mode 100644 index 0000000..9579950 --- /dev/null +++ b/deploy/rig-operator/config/rbac/kustomization.yaml @@ -0,0 +1,37 @@ +resources: +# All RBAC will be applied under this service account in +# the deployment namespace. You may comment out this resource +# if your manager will use a service account that exists at +# runtime. Be sure to update RoleBinding and ClusterRoleBinding +# subjects if changing service account names. +- service_account.yaml +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# The following RBAC configurations are used to protect +# the metrics endpoint with authn/authz. These configurations +# ensure that only authorized users and service accounts +# can access the metrics endpoint. Comment the following +# permissions if you want to disable this protection. +# More info: https://book.kubebuilder.io/reference/metrics.html +- metrics_auth_role.yaml +- metrics_auth_role_binding.yaml +- metrics_reader_role.yaml +# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by +# default, aiding admins in cluster management. Those roles are +# not used by the deploy itself. You can comment the following lines +# if you do not want those helpers be installed with your Project. +- vsphereblueprint_admin_role.yaml +- vsphereblueprint_editor_role.yaml +- vsphereblueprint_viewer_role.yaml +- harvesterblueprint_admin_role.yaml +- harvesterblueprint_editor_role.yaml +- harvesterblueprint_viewer_role.yaml +- infrablueprint_admin_role.yaml +- infrablueprint_editor_role.yaml +- infrablueprint_viewer_role.yaml +- clusterblueprint_admin_role.yaml +- clusterblueprint_editor_role.yaml +- clusterblueprint_viewer_role.yaml + diff --git a/deploy/rig-operator/config/rbac/leader_election_role.yaml b/deploy/rig-operator/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000..e0bc9f3 --- /dev/null +++ b/deploy/rig-operator/config/rbac/leader_election_role.yaml @@ -0,0 +1,40 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/deploy/rig-operator/config/rbac/leader_election_role_binding.yaml b/deploy/rig-operator/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..93ad1f9 --- /dev/null +++ b/deploy/rig-operator/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/rig-operator/config/rbac/metrics_auth_role.yaml b/deploy/rig-operator/config/rbac/metrics_auth_role.yaml new file mode 100644 index 0000000..32d2e4e --- /dev/null +++ b/deploy/rig-operator/config/rbac/metrics_auth_role.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/deploy/rig-operator/config/rbac/metrics_auth_role_binding.yaml b/deploy/rig-operator/config/rbac/metrics_auth_role_binding.yaml new file mode 100644 index 0000000..e775d67 --- /dev/null +++ b/deploy/rig-operator/config/rbac/metrics_auth_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metrics-auth-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/rig-operator/config/rbac/metrics_reader_role.yaml b/deploy/rig-operator/config/rbac/metrics_reader_role.yaml new file mode 100644 index 0000000..51a75db --- /dev/null +++ b/deploy/rig-operator/config/rbac/metrics_reader_role.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/role.yaml b/deploy/rig-operator/config/rbac/role.yaml new file mode 100644 index 0000000..c130b15 --- /dev/null +++ b/deploy/rig-operator/config/rbac/role.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints + - infrablueprints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints/finalizers + verbs: + - update +- apiGroups: + - rig.appstack.io + resources: + - clusterblueprints/status + - infrablueprints/status + verbs: + - get + - patch + - update +- apiGroups: + - rig.appstack.io + resources: + - harvesterblueprints + verbs: + - get + - list + - watch diff --git a/deploy/rig-operator/config/rbac/role_binding.yaml b/deploy/rig-operator/config/rbac/role_binding.yaml new file mode 100644 index 0000000..d3d78c7 --- /dev/null +++ b/deploy/rig-operator/config/rbac/role_binding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/deploy/rig-operator/config/rbac/service_account.yaml b/deploy/rig-operator/config/rbac/service_account.yaml new file mode 100644 index 0000000..9b43ffd --- /dev/null +++ b/deploy/rig-operator/config/rbac/service_account.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: controller-manager + namespace: system diff --git a/deploy/rig-operator/config/rbac/vsphereblueprint_admin_role.yaml b/deploy/rig-operator/config/rbac/vsphereblueprint_admin_role.yaml new file mode 100644 index 0000000..f7162ad --- /dev/null +++ b/deploy/rig-operator/config/rbac/vsphereblueprint_admin_role.yaml @@ -0,0 +1,27 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants full permissions ('*') over rig.appstack.io. +# This role is intended for users authorized to modify roles and bindings within the cluster, +# enabling them to delegate specific permissions to other users or groups as needed. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: vsphereblueprint-admin-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints + verbs: + - '*' +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/vsphereblueprint_editor_role.yaml b/deploy/rig-operator/config/rbac/vsphereblueprint_editor_role.yaml new file mode 100644 index 0000000..5ab66ac --- /dev/null +++ b/deploy/rig-operator/config/rbac/vsphereblueprint_editor_role.yaml @@ -0,0 +1,33 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants permissions to create, update, and delete resources within the rig.appstack.io. +# This role is intended for users who need to manage these resources +# but should not control RBAC or manage permissions for others. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: vsphereblueprint-editor-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/rbac/vsphereblueprint_viewer_role.yaml b/deploy/rig-operator/config/rbac/vsphereblueprint_viewer_role.yaml new file mode 100644 index 0000000..dec03a8 --- /dev/null +++ b/deploy/rig-operator/config/rbac/vsphereblueprint_viewer_role.yaml @@ -0,0 +1,29 @@ +# This rule is not used by the project deploy itself. +# It is provided to allow the cluster admin to help manage permissions for users. +# +# Grants read-only access to rig.appstack.io resources. +# This role is intended for users who need visibility into these resources +# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing. + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: vsphereblueprint-viewer-role +rules: +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints + verbs: + - get + - list + - watch +- apiGroups: + - rig.appstack.io + resources: + - vsphereblueprints/status + verbs: + - get diff --git a/deploy/rig-operator/config/samples/kustomization.yaml b/deploy/rig-operator/config/samples/kustomization.yaml new file mode 100644 index 0000000..9f41c13 --- /dev/null +++ b/deploy/rig-operator/config/samples/kustomization.yaml @@ -0,0 +1,7 @@ +## Append samples of your project ## +resources: +- rig_v1alpha1_clusterblueprint.yaml +- rig_v1alpha1_infrablueprint.yaml +- rig_v1alpha1_harvesterblueprint.yaml +- rig_v1alpha1_vsphereblueprint.yaml +# +kubebuilder:scaffold:manifestskustomizesamples diff --git a/deploy/rig-operator/config/samples/rig_v1alpha1_clusterblueprint.yaml b/deploy/rig-operator/config/samples/rig_v1alpha1_clusterblueprint.yaml new file mode 100644 index 0000000..f9f85b4 --- /dev/null +++ b/deploy/rig-operator/config/samples/rig_v1alpha1_clusterblueprint.yaml @@ -0,0 +1,22 @@ +apiVersion: rig.appstack.io/v1alpha1 +kind: ClusterBlueprint +metadata: + name: test-cluster-01 + namespace: fleet-default +spec: + # Points to the InfraBlueprint (which links to Harvester + Quotas) + infraBlueprintRef: "dev-environment-v1" + + # 1. Lifecycle + kubernetesVersion: "v1.33.5+rke2r1" + + # 2. Topology: Control Plane (1 Node) + controlPlaneHA: false + + # 3. Topology: Workers + workerPools: + - name: "app-workers" + quantity: 1 + cpuCores: 4 + memoryGb: 16 + diskGb: 60 \ No newline at end of file diff --git a/deploy/rig-operator/config/samples/rig_v1alpha1_harvesterblueprint.yaml b/deploy/rig-operator/config/samples/rig_v1alpha1_harvesterblueprint.yaml new file mode 100644 index 0000000..dc63beb --- /dev/null +++ b/deploy/rig-operator/config/samples/rig_v1alpha1_harvesterblueprint.yaml @@ -0,0 +1,14 @@ +apiVersion: rig.appstack.io/v1alpha1 +kind: HarvesterBlueprint +metadata: + name: dev-harvester-config + namespace: fleet-default +spec: + # [MOVED] Technical connection details live here now + harvesterUrl: "https://172.27.27.190:6443" + + # [MOVED] VM Template details + vmNamespace: "vanderlande" + imageName: "vanderlande/image-qhtpc" + networkName: "vanderlande/vm-lan" + sshUser: "rancher" \ No newline at end of file diff --git a/deploy/rig-operator/config/samples/rig_v1alpha1_infrablueprint_harvester.yaml b/deploy/rig-operator/config/samples/rig_v1alpha1_infrablueprint_harvester.yaml new file mode 100644 index 0000000..6fd5d8a --- /dev/null +++ b/deploy/rig-operator/config/samples/rig_v1alpha1_infrablueprint_harvester.yaml @@ -0,0 +1,17 @@ +apiVersion: rig.appstack.io/v1alpha1 +kind: InfraBlueprint +metadata: + name: dev-environment-v1 + namespace: fleet-default +spec: + cloudCredentialSecret: "cc-mrklm" + # [NEW] Added Rancher URL + rancherUrl: "https://rancher-mgmt.product.lan" + + providerRef: + kind: HarvesterBlueprint + name: dev-harvester-config + quota: + maxCpu: 100 + maxMemoryGb: 256 + maxDiskGb: 3000 \ No newline at end of file diff --git a/deploy/rig-operator/config/samples/rig_v1alpha1_vsphereblueprint.yaml b/deploy/rig-operator/config/samples/rig_v1alpha1_vsphereblueprint.yaml new file mode 100644 index 0000000..986fd85 --- /dev/null +++ b/deploy/rig-operator/config/samples/rig_v1alpha1_vsphereblueprint.yaml @@ -0,0 +1,9 @@ +apiVersion: rig.appstack.io/v1alpha1 +kind: VsphereBlueprint +metadata: + labels: + app.kubernetes.io/name: deploy + app.kubernetes.io/managed-by: kustomize + name: vsphereblueprint-sample +spec: + # TODO(user): Add fields here diff --git a/deploy/rig-operator/config/samples/vsphere_stack.yaml b/deploy/rig-operator/config/samples/vsphere_stack.yaml new file mode 100644 index 0000000..2146cf7 --- /dev/null +++ b/deploy/rig-operator/config/samples/vsphere_stack.yaml @@ -0,0 +1,70 @@ +# --------------------------------------------------------- +# 1. Technical Configuration (The Location) +# --------------------------------------------------------- +apiVersion: rig.appstack.io/v1alpha1 +kind: VsphereBlueprint +metadata: + name: dev-vsphere-config + namespace: fleet-default +spec: + vCenter: "vcenter.vanderlande.com" + datacenter: "NL001" + folder: "ICT Digitalisation - Rancher" + resourcePool: "NL001 Development - Rancher/Resources" + datastore: "NL001 Development - Rancher SDRS" + network: "nl001.vDS.Distri.Vlan.1542" + template: "nl001-cp-ubuntu-22.04-amd64-20250327-5.15.0-135-rke2-k3s" + +--- +# --------------------------------------------------------- +# 2. Infra Manager (The Accountant & Identity) +# --------------------------------------------------------- +apiVersion: rig.appstack.io/v1alpha1 +kind: InfraBlueprint +metadata: + name: dev-vsphere-infra + namespace: fleet-default +spec: + # Credentials (Must exist in Rancher/Kubernetes) + cloudCredentialSecret: "cc-lhtl9" + rancherUrl: "https://rancher.tst.vanderlande.com" + + # Point to the vSphere Configuration above + providerRef: + kind: VsphereBlueprint + name: dev-vsphere-config + + # Budget Limits for this Environment + quota: + maxCpu: 50 # Total vCPUs allowed + maxMemoryGb: 128 # Total RAM allowed + maxDiskGb: 5000 # Total Disk allowed + +--- +# --------------------------------------------------------- +# 3. Cluster Request (The User Goal) +# --------------------------------------------------------- +apiVersion: rig.appstack.io/v1alpha1 +kind: ClusterBlueprint +metadata: + name: test-vsphere-cluster-01 + namespace: fleet-default +spec: + # Link to the vSphere Infra defined above + infraBlueprintRef: "dev-vsphere-infra" + + # Lifecycle + kubernetesVersion: "v1.31.12+rke2r1" + + # Topology: Control Plane (1 Node) + # Uses default sizing from values.yaml (2 CPU / 8 GB) + controlPlaneHA: false + + # Topology: Workers + # These sizes (GB) will be converted to MB automatically by your Strategy + workerPools: + - name: "app-workers" + quantity: 2 + cpuCores: 4 + memoryGb: 8 # Strategy converts to 8192 MB + diskGb: 100 # Strategy converts to 102400 MB \ No newline at end of file diff --git a/deploy/rig-operator/docs/blueprint_orchestration.svg b/deploy/rig-operator/docs/blueprint_orchestration.svg new file mode 100644 index 0000000..a4d2388 --- /dev/null +++ b/deploy/rig-operator/docs/blueprint_orchestration.svg @@ -0,0 +1,67 @@ +

API_Blueprints

Controller_Layer

Generation_Layer

Unsupported markdown: list
Unsupported markdown: list
Unsupported markdown: list
Unsupported markdown: list

Injected Dependency

Implements

Implements

Reads config to map data

Reads config to map data

watches
reads & checks quota
configures & calls

«Kind: ClusterBlueprint, Short: cbp»

ClusterBlueprint

Description: Generic cluster request

---

+spec.infraBlueprintRef : string

+spec.kubernetesVersion : string

+spec.workerPools : List<GenericPoolReq>

«Kind: InfraBlueprint, Short: ibp»

InfraBlueprint

Description: Manages quotas and provider ref

---

+spec.quotaLimits : ResourceList

+status.quotaUsed : ResourceList

+spec.providerRef : TypedLocalObjectReference

«Kind: VsphereBlueprint, Short: vbp»

VsphereBlueprint

Description: Concrete vSphere details

---

+spec.vcenterURL : string

+spec.datacenterID : string

+spec.networkIDs : List<string>

«Kind: HarvesterBlueprint, Short: hbp»

HarvesterBlueprint

Description: Concrete Harvester details

---

+spec.harvesterURL : string

+spec.vmNamespace : string

+spec.imageName : string

«Kind: AzureBlueprint, Short: abp»

AzureBlueprint

Description: Future Azure details

RIGController

Description: The brain. Watches CBPs, checks IBP quotas.

---

+Reconcile(request)

MasterValuesBuilder

Description: Knows generic Helm structure.

---

-strategy : ProviderStrategy

+BuildHelmValues(cbp, ibp) : Map

«Interface»

ProviderStrategy

Description: Contract for isolated provider logic.

---

+GenerateNodePools(genericPools, providerBP) : List<Any>

+GetGlobalOverrides(providerBP) : Map

+PerformPreFlight(ctx, providerBP) : Error

VsphereStrategy

Description: Specialist VBP to Helm translation.

---

+GenerateNodePools(...)

HarvesterStrategy

Description: Specialist HBP to Helm translation.

---

+GenerateNodePools(...)

+PerformPreFlight(...)

The providerRef is polymorphic.\nIt points to ANY ProviderBlueprint Kind\n(vbp, hbp, or abp).

Unsupported markdown: list
\ No newline at end of file diff --git a/deploy/rig-operator/docs/controllerflow.mermaid b/deploy/rig-operator/docs/controllerflow.mermaid new file mode 100644 index 0000000..059a0f0 --- /dev/null +++ b/deploy/rig-operator/docs/controllerflow.mermaid @@ -0,0 +1,29 @@ +sequenceDiagram + participant User + participant Controller + participant InfraBP as InfraBlueprint + participant ProviderBP as Harvester/Vsphere BP + participant Strategy + participant Builder as MasterBuilder + participant Helm + + User->>Controller: Create ClusterBlueprint + Controller->>InfraBP: 1. Get Infra & Quota + InfraBP-->>Controller: ProviderRef (Kind="HarvesterBlueprint") + + note over Controller: Dynamic Switching Logic + + alt Kind is Harvester + Controller->>ProviderBP: 2. Get Harvester Config + Controller->>Strategy: 3. Init HarvesterStrategy + else Kind is Vsphere + Controller->>ProviderBP: 2. Get Vsphere Config + Controller->>Strategy: 3. Init VsphereStrategy + end + + Controller->>Builder: 4. Build(Strategy) + Builder->>Strategy: GenerateNodePools() + Strategy-->>Builder: [Pool A, Pool B] + Builder-->>Controller: map[values] + + Controller->>Helm: 5. Apply(values) \ No newline at end of file diff --git a/deploy/rig-operator/docs/flow-diagram.svg b/deploy/rig-operator/docs/flow-diagram.svg new file mode 100644 index 0000000..9653009 --- /dev/null +++ b/deploy/rig-operator/docs/flow-diagram.svg @@ -0,0 +1,67 @@ +HelmMasterBuilderStrategyHarvester/Vsphere BPInfraBlueprintControllerUserHelmMasterBuilderStrategyHarvester/Vsphere BPInfraBlueprintControllerUserDynamic Switching Logicalt[Kind is Harvester][Kind is Vsphere]Create ClusterBlueprint1. Get Infra & QuotaProviderRef (Kind="HarvesterBlueprint")2. Get Harvester Config3. Init HarvesterStrategy2. Get Vsphere Config3. Init VsphereStrategy4. Build(Strategy)GenerateNodePools()[Pool A, Pool B]map[values]5. Apply(values) \ No newline at end of file diff --git a/deploy/rig-operator/docs/uml.mermaid b/deploy/rig-operator/docs/uml.mermaid new file mode 100644 index 0000000..fb7a202 --- /dev/null +++ b/deploy/rig-operator/docs/uml.mermaid @@ -0,0 +1,121 @@ +classDiagram + direction TB + + %% ========================================== + %% PACKAGE: K8s API Definitions (Blueprints) + %% ========================================== + namespace API_Blueprints { + class ClusterBlueprint { + <> + Description: Generic cluster request + --- + +spec.infraBlueprintRef : string + +spec.kubernetesVersion : string + +spec.workerPools : List~GenericPoolReq~ + } + + class InfraBlueprint { + <> + Description: Manages quotas and provider ref + --- + +spec.quotaLimits : ResourceList + +status.quotaUsed : ResourceList + +spec.providerRef : TypedLocalObjectReference + } + + class VsphereBlueprint { + <> + Description: Concrete vSphere details + --- + +spec.vcenterURL : string + +spec.datacenterID : string + +spec.networkIDs : List~string~ + } + + class HarvesterBlueprint { + <> + Description: Concrete Harvester details + --- + +spec.harvesterURL : string + +spec.vmNamespace : string + +spec.imageName : string + } + + class AzureBlueprint { + <> + Description: Future Azure details + } + } + + %% Relationships between Blueprints + ClusterBlueprint --> InfraBlueprint : 1. References by Name + note for InfraBlueprint "The providerRef is polymorphic.\nIt points to ANY ProviderBlueprint Kind\n(vbp, hbp, or abp)." + InfraBlueprint ..> VsphereBlueprint : 2. Dynamically references Kind=vbp + InfraBlueprint ..> HarvesterBlueprint : 2. Dynamically references Kind=hbp + InfraBlueprint ..> AzureBlueprint : 2. Dynamically references Kind=abp + + + %% ========================================== + %% PACKAGE: Controller (Orchestration) + %% ========================================== + namespace Controller_Layer { + class RIGController { + Description: The brain. Watches CBPs, checks IBP quotas. + --- + +Reconcile(request) + } + } + + RIGController "watches" --> ClusterBlueprint + RIGController "reads & checks quota" --> InfraBlueprint + + + %% ========================================== + %% PACKAGE: Builders & Strategies (Generation) + %% ========================================== + namespace Generation_Layer { + class MasterValuesBuilder { + Description: Knows generic Helm structure. + --- + -strategy : ProviderStrategy + +BuildHelmValues(cbp, ibp) Map + } + + class ProviderStrategy { + <> + Description: Contract for isolated provider logic. + --- + +GenerateNodePools(genericPools, providerBP) List~Any~ + +GetGlobalOverrides(providerBP) Map + +PerformPreFlight(ctx, providerBP) Error + } + + class VsphereStrategy { + Description: Specialist VBP to Helm translation. + --- + +GenerateNodePools(...) + } + + class HarvesterStrategy { + Description: Specialist HBP to Helm translation. + --- + +GenerateNodePools(...) + +PerformPreFlight(...) + } + } + + %% Controller orchestrates builders + note for RIGController "1. Reads IBP.providerRef.Kind\n2. Instantiates correct Strategy (e.g. VsphereStrategy)\n3. Injects Strategy into MasterBuilder\n4. Calls MasterBuilder.Build()" + + RIGController "configures & calls" --> MasterValuesBuilder + + %% Master Builder uses the interface + MasterValuesBuilder o--> ProviderStrategy : Injected Dependency + + %% Realization of strategies + ProviderStrategy <|.. VsphereStrategy : Implements + ProviderStrategy <|.. HarvesterStrategy : Implements + + %% Strategies read their specific blueprints + VsphereStrategy ..> VsphereBlueprint : Reads config to map data + HarvesterStrategy ..> HarvesterBlueprint : Reads config to map data \ No newline at end of file diff --git a/deploy/rig-operator/go.mod b/deploy/rig-operator/go.mod new file mode 100644 index 0000000..098c729 --- /dev/null +++ b/deploy/rig-operator/go.mod @@ -0,0 +1,161 @@ +module vanderlande.com/ittp/appstack/rig-operator + +go 1.25.0 + +require ( + github.com/onsi/ginkgo/v2 v2.27.2 + github.com/onsi/gomega v1.38.2 + gopkg.in/yaml.v3 v3.0.1 + helm.sh/helm/v3 v3.19.4 + k8s.io/api v0.35.0 + k8s.io/apimachinery v0.35.0 + k8s.io/cli-runtime v0.35.0 + k8s.io/client-go v0.35.0 + sigs.k8s.io/controller-runtime v0.22.4 +) + +require ( + cel.dev/expr v0.24.0 // indirect + dario.cat/mergo v1.0.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/Masterminds/squirrel v1.5.4 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/containerd/containerd v1.7.29 // indirect + github.com/containerd/errdefs v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cyphar/filepath-securejoin v0.6.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/evanphx/json-patch v5.9.11+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-gorp/gorp/v3 v3.1.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect + github.com/gosuri/uitable v0.0.4 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.62.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rubenv/sql-migrate v1.8.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.38.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/grpc v1.72.1 // indirect + google.golang.org/protobuf v1.36.8 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/apiextensions-apiserver v0.34.2 // indirect + k8s.io/apiserver v0.34.2 // indirect + k8s.io/component-base v0.34.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/kubectl v0.34.2 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + oras.land/oras-go/v2 v2.6.0 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/kustomize/api v0.20.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/deploy/rig-operator/go.sum b/deploy/rig-operator/go.sum new file mode 100644 index 0000000..bba3359 --- /dev/null +++ b/deploy/rig-operator/go.sum @@ -0,0 +1,501 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= +github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE= +github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= +github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= +github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE= +github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM= +github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= +github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= +github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= +github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= +github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= +github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o= +github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI= +go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU= +go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s= +go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk= +go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs= +go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.19.4 h1:E2yFBejmZBczWr5LblhjZbvAOAwVumfBO1AtN3nqI30= +helm.sh/helm/v3 v3.19.4/go.mod h1:PC1rk7PqacpkV4acUFMLStOOis7QM9Jq3DveHBInu4s= +k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= +k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= +k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= +k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= +k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= +k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= +k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= +k8s.io/cli-runtime v0.35.0 h1:PEJtYS/Zr4p20PfZSLCbY6YvaoLrfByd6THQzPworUE= +k8s.io/cli-runtime v0.35.0/go.mod h1:VBRvHzosVAoVdP3XwUQn1Oqkvaa8facnokNkD7jOTMY= +k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= +k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= +k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= +k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/kubectl v0.34.2 h1:+fWGrVlDONMUmmQLDaGkQ9i91oszjjRAa94cr37hzqA= +k8s.io/kubectl v0.34.2/go.mod h1:X2KTOdtZZNrTWmUD4oHApJ836pevSl+zvC5sI6oO2YQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= +oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= +sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I= +sigs.k8s.io/kustomize/api v0.20.1/go.mod h1:t6hUFxO+Ph0VxIk1sKp1WS0dOjbPCtLJ4p8aADLwqjM= +sigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A78= +sigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/deploy/rig-operator/hack/boilerplate.go.txt b/deploy/rig-operator/hack/boilerplate.go.txt new file mode 100644 index 0000000..9786798 --- /dev/null +++ b/deploy/rig-operator/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ \ No newline at end of file diff --git a/deploy/rig-operator/internal/builder/master.go b/deploy/rig-operator/internal/builder/master.go new file mode 100644 index 0000000..fbb2e2d --- /dev/null +++ b/deploy/rig-operator/internal/builder/master.go @@ -0,0 +1,134 @@ +package builder + +import ( + "context" + "encoding/json" + "fmt" + + "gopkg.in/yaml.v3" + + "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + "vanderlande.com/ittp/appstack/rig-operator/internal/provider" +) + +// ChartConfig holds the helm settings extracted from the YAML _defaults +// The Controller needs this to know WHICH chart to fetch. +type ChartConfig struct { + Repo string + Name string + Version string +} + +type MasterBuilder struct { + strategy provider.Strategy + baseTemplate []byte + chartConfig ChartConfig +} + +func NewMasterBuilder(strategy provider.Strategy, baseTemplate []byte) *MasterBuilder { + b := &MasterBuilder{ + strategy: strategy, + baseTemplate: baseTemplate, + // Safe defaults + chartConfig: ChartConfig{ + Name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates", + }, + } + return b +} + +// GetChartConfig returns the chart details found in the template. +func (b *MasterBuilder) GetChartConfig() ChartConfig { + return b.chartConfig +} + +// Build orchestrates the values generation process +func (b *MasterBuilder) Build(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) { + values := make(map[string]interface{}) + if err := yaml.Unmarshal(b.baseTemplate, &values); err != nil { + return nil, fmt.Errorf("failed to unmarshal base template: %w", err) + } + + // 1. Extract Chart Config from _defaults (Legacy Logic Ported) + // We do this so the Controller knows what version to install. + if defaults, ok := values["_defaults"].(map[string]interface{}); ok { + if chartCfg, ok := defaults["helmChart"].(map[string]interface{}); ok { + if v, ok := chartCfg["repo"].(string); ok { + b.chartConfig.Repo = v + } + if v, ok := chartCfg["name"].(string); ok { + b.chartConfig.Name = v + } + if v, ok := chartCfg["version"].(string); ok { + b.chartConfig.Version = v + } + } + } + + // 2. Generate Node Pools (Delegated to Strategy) + // [DIFFERENCE]: We don't loop here. The Strategy knows how to map CBP -> Provider NodePools. + nodePools, err := b.strategy.GenerateNodePools(ctx, cbp) + if err != nil { + return nil, fmt.Errorf("strategy failed to generate node pools: %w", err) + } + + // 3. Get Global Overrides (Delegated to Strategy) + // [DIFFERENCE]: We don't hardcode "cloud_provider_name" here. The Strategy returns it. + overrides, err := b.strategy.GetGlobalOverrides(ctx, cbp, credentialSecret) + if err != nil { + return nil, fmt.Errorf("strategy failed to get global overrides: %w", err) + } + + // 4. Inject Logic into the Helm Structure + if clusterMap, ok := values["cluster"].(map[string]interface{}); ok { + clusterMap["name"] = cbp.Name + + if configMap, ok := clusterMap["config"].(map[string]interface{}); ok { + configMap["kubernetesVersion"] = cbp.Spec.KubernetesVersion + + // Ensure globalConfig exists + if _, ok := configMap["globalConfig"]; !ok { + configMap["globalConfig"] = make(map[string]interface{}) + } + globalConfig := configMap["globalConfig"].(map[string]interface{}) + + // Inject Overrides + for k, v := range overrides { + // A. Handle specific Global Config keys + if k == "cloud_provider_name" || k == "cloud_provider_config" { + globalConfig[k] = v + continue + } + + // B. Handle Chart Values (CCM/CSI Addons) + if k == "chartValues" { + if existingChartVals, ok := configMap["chartValues"].(map[string]interface{}); ok { + if newChartVals, ok := v.(map[string]interface{}); ok { + for ck, cv := range newChartVals { + existingChartVals[ck] = cv + } + } + } else { + configMap["chartValues"] = v + } + continue + } + + // C. Default: Inject at Root level + values[k] = v + } + } + } + + // 5. Inject Node Pools + // We marshal/unmarshal to ensure JSON tags from the Strategy structs are respected + tempJSON, _ := json.Marshal(nodePools) + var cleanNodePools interface{} + _ = json.Unmarshal(tempJSON, &cleanNodePools) + values["nodepools"] = cleanNodePools + + // 6. Cleanup internal keys + delete(values, "_defaults") + + return values, nil +} diff --git a/deploy/rig-operator/internal/controller/clusterblueprint_controller.go b/deploy/rig-operator/internal/controller/clusterblueprint_controller.go new file mode 100644 index 0000000..d507c64 --- /dev/null +++ b/deploy/rig-operator/internal/controller/clusterblueprint_controller.go @@ -0,0 +1,291 @@ +package controller + +import ( + "context" + "fmt" + "time" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + rigv1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + "vanderlande.com/ittp/appstack/rig-operator/internal/builder" + "vanderlande.com/ittp/appstack/rig-operator/internal/helm" + "vanderlande.com/ittp/appstack/rig-operator/internal/provider" + "vanderlande.com/ittp/appstack/rig-operator/internal/provider/harvester" + harvesterTemplate "vanderlande.com/ittp/appstack/rig-operator/internal/templates/harvester" + + "vanderlande.com/ittp/appstack/rig-operator/internal/provider/vsphere" + vsphereTemplate "vanderlande.com/ittp/appstack/rig-operator/internal/templates/vsphere" +) + +const ( + rigFinalizer = "rig.appstack.io/finalizer" +) + +// ClusterBlueprintReconciler reconciles a ClusterBlueprint object +type ClusterBlueprintReconciler struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +// +kubebuilder:rbac:groups=rig.appstack.io,resources=clusterblueprints,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=rig.appstack.io,resources=clusterblueprints/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=rig.appstack.io,resources=clusterblueprints/finalizers,verbs=update +// +kubebuilder:rbac:groups=rig.appstack.io,resources=infrablueprints,verbs=get;list;watch +// +kubebuilder:rbac:groups=rig.appstack.io,resources=harvesterblueprints,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete + +func (r *ClusterBlueprintReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + // 1. Fetch ClusterBlueprint (CBP) + cbp := &rigv1.ClusterBlueprint{} + if err := r.Get(ctx, req.NamespacedName, cbp); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // 2. Handle Deletion ... (Same as before) + if !cbp.ObjectMeta.DeletionTimestamp.IsZero() { + return r.handleDelete(ctx, cbp) + } + + // 3. Ensure Finalizer ... (Same as before) + if !controllerutil.ContainsFinalizer(cbp, rigFinalizer) { + controllerutil.AddFinalizer(cbp, rigFinalizer) + if err := r.Update(ctx, cbp); err != nil { + return ctrl.Result{}, err + } + } + + // 4. Fetch InfraBlueprint (IBP) + ibp := &rigv1.InfraBlueprint{} + if err := r.Get(ctx, types.NamespacedName{Name: cbp.Spec.InfraBlueprintRef, Namespace: cbp.Namespace}, ibp); err != nil { + l.Error(err, "InfraBlueprint not found", "Infra", cbp.Spec.InfraBlueprintRef) + r.updateStatus(ctx, cbp, "PendingInfra", false) + return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil + } + + // ===================================================================== + // 4.5. QUOTA CHECK (The Gatekeeper) + // Only check quota if we are NOT already deployed. + // (Existing clusters keep running even if quota shrinks later) + // ===================================================================== + if cbp.Status.Phase != "Deployed" { + if err := r.checkQuota(cbp, ibp); err != nil { + l.Error(err, "Quota Exceeded") + // We stop here! Helm Apply will NOT run. + r.updateStatus(ctx, cbp, "QuotaExceeded", false) + // Requeue slowly to check if resources freed up later + return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil + } + } + + // 5. Select Strategy based on Infra ProviderRef + var selectedStrategy provider.Strategy + var baseTemplate []byte + var credentialSecret string + + switch ibp.Spec.ProviderRef.Kind { + case "HarvesterBlueprint": + // A. Fetch the specific Harvester Config (HBP) + hbp := &rigv1.HarvesterBlueprint{} + hbpName := types.NamespacedName{Name: ibp.Spec.ProviderRef.Name, Namespace: cbp.Namespace} + if err := r.Get(ctx, hbpName, hbp); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to load HarvesterBlueprint: %w", err) + } + + // B. Ensure Identity (Mint ServiceAccount/Secret) + idMgr := harvester.NewIdentityManager(r.Client, r.Scheme) + secretName, err := idMgr.Ensure(ctx, cbp, ibp, hbp) + if err != nil { + l.Error(err, "Failed to ensure identity") + r.updateStatus(ctx, cbp, "ProvisioningFailed", false) + return ctrl.Result{RequeueAfter: 30 * time.Second}, nil + } + credentialSecret = secretName + + // C. Load Defaults & Init Strategy + defaults, err := harvesterTemplate.GetDefaults() + if err != nil { + return ctrl.Result{}, err + } + baseTemplate = harvesterTemplate.GetBaseValues() + // [UPDATED] Pass ibp.Spec.RancherURL to the factory + selectedStrategy = harvester.NewStrategy( + hbp, + ibp.Spec.UserData, + ibp.Spec.RancherURL, // <--- Passing the URL here + defaults, + ) + + case "VsphereBlueprint": + // A. Fetch the specific vSphere Config (VBP) + vbp := &rigv1.VsphereBlueprint{} + vbpName := types.NamespacedName{Name: ibp.Spec.ProviderRef.Name, Namespace: cbp.Namespace} + if err := r.Get(ctx, vbpName, vbp); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to load VsphereBlueprint: %w", err) + } + + // B. Load Defaults (CPU/RAM sizing safety nets) + defaults, err := vsphereTemplate.GetDefaults() + if err != nil { + return ctrl.Result{}, err + } + baseTemplate = vsphereTemplate.GetBaseValues() + + // C. Init Strategy + // Note: vSphere typically uses the global 'cloudCredentialSecret' defined in InfraBlueprint + // rather than minting dynamic tokens per cluster like Harvester does. + credentialSecret = ibp.Spec.CloudCredentialSecret + + selectedStrategy = vsphere.NewStrategy( + vbp, + ibp.Spec.UserData, + ibp.Spec.RancherURL, + defaults, + ) + + default: + return ctrl.Result{}, fmt.Errorf("unsupported provider kind: %s", ibp.Spec.ProviderRef.Kind) + } + + // 6. Build Helm Values (Generic Engine) + masterBuilder := builder.NewMasterBuilder(selectedStrategy, baseTemplate) + + values, err := masterBuilder.Build(ctx, cbp, credentialSecret) + if err != nil { + l.Error(err, "Failed to build helm values") + r.updateStatus(ctx, cbp, "ConfigGenerationFailed", false) + return ctrl.Result{}, nil // Fatal error, don't retry until config changes + } + + // 7. Apply Helm Chart + // We use the ChartConfig extracted by the MasterBuilder (from the YAML defaults) + chartCfg := masterBuilder.GetChartConfig() + + helmConfig := helm.Config{ + Namespace: cbp.Namespace, + ReleaseName: cbp.Name, // We use the Cluster name as the Release name + RepoURL: chartCfg.Repo, + ChartName: chartCfg.Name, + Version: chartCfg.Version, + Values: values, + } + + l.Info("Applying Helm Release", "Release", cbp.Name, "Chart", chartCfg.Name) + if err := helm.Apply(helmConfig); err != nil { + l.Error(err, "Helm Install/Upgrade failed") + r.updateStatus(ctx, cbp, "HelmApplyFailed", false) + return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil + } + + // 8. Success! + r.updateStatus(ctx, cbp, "Deployed", true) + return ctrl.Result{RequeueAfter: 10 * time.Minute}, nil // Re-sync periodically +} + +func (r *ClusterBlueprintReconciler) handleDelete(ctx context.Context, cbp *rigv1.ClusterBlueprint) (ctrl.Result, error) { + if controllerutil.ContainsFinalizer(cbp, rigFinalizer) { + // 1. Uninstall Helm Release + helmCfg := helm.Config{ + Namespace: cbp.Namespace, + ReleaseName: cbp.Name, + } + // Best effort uninstall + if err := helm.Uninstall(helmCfg); err != nil { + log.FromContext(ctx).Error(err, "Failed to uninstall helm release during cleanup") + } + + // 2. Cleanup Identity (Harvester SA) + // We need to look up IBP -> HBP again to know WHERE to clean up + // This is a simplified lookup; in production we might need to handle missing IBP gracefully + ibp := &rigv1.InfraBlueprint{} + if err := r.Get(ctx, types.NamespacedName{Name: cbp.Spec.InfraBlueprintRef, Namespace: cbp.Namespace}, ibp); err == nil { + if ibp.Spec.ProviderRef.Kind == "HarvesterBlueprint" { + hbp := &rigv1.HarvesterBlueprint{} + if err := r.Get(ctx, types.NamespacedName{Name: ibp.Spec.ProviderRef.Name, Namespace: cbp.Namespace}, hbp); err == nil { + idMgr := harvester.NewIdentityManager(r.Client, r.Scheme) + idMgr.Cleanup(ctx, cbp, ibp, hbp) + } + } + } + + // 3. Remove Finalizer + controllerutil.RemoveFinalizer(cbp, rigFinalizer) + if err := r.Update(ctx, cbp); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil +} + +func (r *ClusterBlueprintReconciler) updateStatus(ctx context.Context, cbp *rigv1.ClusterBlueprint, phase string, ready bool) { + cbp.Status.Phase = phase + cbp.Status.Ready = ready + if err := r.Status().Update(ctx, cbp); err != nil { + log.FromContext(ctx).Error(err, "Failed to update status") + } +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterBlueprintReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rigv1.ClusterBlueprint{}). + Complete(r) +} + +// Helper function to calculate required resources vs available +func (r *ClusterBlueprintReconciler) checkQuota(cbp *rigv1.ClusterBlueprint, ibp *rigv1.InfraBlueprint) error { + // 1. Calculate what this cluster needs + var reqCpu, reqMem, reqDisk int + + // Control Plane Sizing (Using safe defaults or template logic) + // Ideally, this should match the defaults in your template/strategy + cpCount := 1 + if cbp.Spec.ControlPlaneHA { + cpCount = 3 + } + reqCpu += cpCount * 4 + reqMem += cpCount * 8 + reqDisk += cpCount * 40 + + // Worker Pools Sizing + for _, pool := range cbp.Spec.WorkerPools { + reqCpu += pool.Quantity * pool.CpuCores + reqMem += pool.Quantity * pool.MemoryGB + reqDisk += pool.Quantity * pool.DiskGB + } + + // 2. Check against Limits + // Note: We use the Status.Usage which is calculated by the InfraController. + // This includes "other" clusters, but might include "this" cluster if it was already counted. + // For strict "Admission Control", usually we check: + // (CurrentUsage + Request) > MaxLimit + + // However, since InfraController runs asynchronously, 'Status.Usage' might NOT yet include this new cluster. + // So (Usage + Request) > Max is the safest check for a new provisioning. + + q := ibp.Spec.Quota + u := ibp.Status.Usage + + if q.MaxCPU > 0 && (u.UsedCPU+reqCpu) > q.MaxCPU { + return fmt.Errorf("requested CPU %d exceeds remaining quota (Max: %d, Used: %d)", reqCpu, q.MaxCPU, u.UsedCPU) + } + + if q.MaxMemoryGB > 0 && (u.UsedMemoryGB+reqMem) > q.MaxMemoryGB { + return fmt.Errorf("requested Mem %dGB exceeds remaining quota (Max: %d, Used: %d)", reqMem, q.MaxMemoryGB, u.UsedMemoryGB) + } + + if q.MaxDiskGB > 0 && (u.UsedDiskGB+reqDisk) > q.MaxDiskGB { + return fmt.Errorf("requested Disk %dGB exceeds remaining quota (Max: %d, Used: %d)", reqDisk, q.MaxDiskGB, u.UsedDiskGB) + } + + return nil +} diff --git a/deploy/rig-operator/internal/controller/clusterblueprint_controller_test.go b/deploy/rig-operator/internal/controller/clusterblueprint_controller_test.go new file mode 100644 index 0000000..beb6c1d --- /dev/null +++ b/deploy/rig-operator/internal/controller/clusterblueprint_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + rigv1alpha1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" +) + +var _ = Describe("ClusterBlueprint Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + clusterblueprint := &rigv1alpha1.ClusterBlueprint{} + + BeforeEach(func() { + By("creating the custom resource for the Kind ClusterBlueprint") + err := k8sClient.Get(ctx, typeNamespacedName, clusterblueprint) + if err != nil && errors.IsNotFound(err) { + resource := &rigv1alpha1.ClusterBlueprint{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &rigv1alpha1.ClusterBlueprint{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance ClusterBlueprint") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &ClusterBlueprintReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/deploy/rig-operator/internal/controller/infrablueprint_controller.go b/deploy/rig-operator/internal/controller/infrablueprint_controller.go new file mode 100644 index 0000000..54ee68f --- /dev/null +++ b/deploy/rig-operator/internal/controller/infrablueprint_controller.go @@ -0,0 +1,128 @@ +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + rigv1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" +) + +// InfraBlueprintReconciler reconciles a InfraBlueprint object +type InfraBlueprintReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=rig.appstack.io,resources=infrablueprints,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=rig.appstack.io,resources=infrablueprints/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=rig.appstack.io,resources=clusterblueprints,verbs=get;list;watch + +func (r *InfraBlueprintReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + // 1. Fetch the InfraBlueprint + infra := &rigv1.InfraBlueprint{} + if err := r.Get(ctx, req.NamespacedName, infra); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // 2. List ALL ClusterBlueprints in the same namespace + // (We assume Infra and Clusters live in the same namespace for security/tenancy) + var clusterList rigv1.ClusterBlueprintList + if err := r.List(ctx, &clusterList, client.InNamespace(req.Namespace)); err != nil { + l.Error(err, "Failed to list clusters for quota calculation") + return ctrl.Result{}, err + } + + // 3. Calculate Usage (The Accountant Logic) + var usedCpu, usedMem, usedDisk int + + for _, cluster := range clusterList.Items { + // Only count clusters that belong to THIS Infra + if cluster.Spec.InfraBlueprintRef != infra.Name { + continue + } + + // Sum Control Plane + if cluster.Spec.ControlPlaneHA { + // Hardcoded fallback or we could duplicate the defaults logic here. + // Ideally, we'd read the templates, but for accounting, safe estimates are usually okay. + // Or better: The Cluster status could report its own "ResourcesConsumed". + // For now, we use the standard defaults we know: + usedCpu += 3 * 4 // 3 nodes * 4 cores + usedMem += 3 * 8 // 3 nodes * 8 GB + usedDisk += 3 * 40 // 3 nodes * 40 GB + } else { + usedCpu += 1 * 4 + usedMem += 1 * 8 + usedDisk += 1 * 40 + } + + // Sum Worker Pools + for _, pool := range cluster.Spec.WorkerPools { + usedCpu += pool.Quantity * pool.CpuCores + usedMem += pool.Quantity * pool.MemoryGB + usedDisk += pool.Quantity * pool.DiskGB + } + } + + // 4. Update Status if changed + if infra.Status.Usage.UsedCPU != usedCpu || + infra.Status.Usage.UsedMemoryGB != usedMem || + infra.Status.Usage.UsedDiskGB != usedDisk { + + infra.Status.Usage.UsedCPU = usedCpu + infra.Status.Usage.UsedMemoryGB = usedMem + infra.Status.Usage.UsedDiskGB = usedDisk + + l.Info("Updating Infra Quota Usage", "Infra", infra.Name, "CPU", usedCpu, "Mem", usedMem) + if err := r.Status().Update(ctx, infra); err != nil { + return ctrl.Result{}, err + } + } + + // 5. Verify Connectivity (Optional) + // We could check if the ProviderRef exists here and set Ready=true + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *InfraBlueprintReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rigv1.InfraBlueprint{}). + // Watch ClusterBlueprints too! + // If a Cluster is added/modified, we need to Reconcile the Infra it points to. + Watches( + &rigv1.ClusterBlueprint{}, + handler.EnqueueRequestsFromMapFunc(r.findInfraForCluster), + ). + Complete(r) +} + +// findInfraForCluster maps a Cluster change event to a Reconcile request for its parent Infra +func (r *InfraBlueprintReconciler) findInfraForCluster(ctx context.Context, obj client.Object) []reconcile.Request { + cluster, ok := obj.(*rigv1.ClusterBlueprint) + if !ok { + return nil + } + + if cluster.Spec.InfraBlueprintRef != "" { + return []reconcile.Request{ + { + NamespacedName: types.NamespacedName{ + Name: cluster.Spec.InfraBlueprintRef, + Namespace: cluster.Namespace, + }, + }, + } + } + return nil +} diff --git a/deploy/rig-operator/internal/controller/infrablueprint_controller_test.go b/deploy/rig-operator/internal/controller/infrablueprint_controller_test.go new file mode 100644 index 0000000..3401958 --- /dev/null +++ b/deploy/rig-operator/internal/controller/infrablueprint_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + rigv1alpha1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" +) + +var _ = Describe("InfraBlueprint Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + infrablueprint := &rigv1alpha1.InfraBlueprint{} + + BeforeEach(func() { + By("creating the custom resource for the Kind InfraBlueprint") + err := k8sClient.Get(ctx, typeNamespacedName, infrablueprint) + if err != nil && errors.IsNotFound(err) { + resource := &rigv1alpha1.InfraBlueprint{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &rigv1alpha1.InfraBlueprint{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance InfraBlueprint") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &InfraBlueprintReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/deploy/rig-operator/internal/controller/suite_test.go b/deploy/rig-operator/internal/controller/suite_test.go new file mode 100644 index 0000000..250ba0d --- /dev/null +++ b/deploy/rig-operator/internal/controller/suite_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + rigv1alpha1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var ( + ctx context.Context + cancel context.CancelFunc + testEnv *envtest.Environment + cfg *rest.Config + k8sClient client.Client +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + ctx, cancel = context.WithCancel(context.TODO()) + + var err error + err = rigv1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + // +kubebuilder:scaffold:scheme + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + // Retrieve the first found binary directory to allow running tests from IDEs + if getFirstFoundEnvTestBinaryDir() != "" { + testEnv.BinaryAssetsDirectory = getFirstFoundEnvTestBinaryDir() + } + + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + cancel() + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) + +// getFirstFoundEnvTestBinaryDir locates the first binary in the specified path. +// ENVTEST-based tests depend on specific binaries, usually located in paths set by +// controller-runtime. When running tests directly (e.g., via an IDE) without using +// Makefile targets, the 'BinaryAssetsDirectory' must be explicitly configured. +// +// This function streamlines the process by finding the required binaries, similar to +// setting the 'KUBEBUILDER_ASSETS' environment variable. To ensure the binaries are +// properly set up, run 'make setup-envtest' beforehand. +func getFirstFoundEnvTestBinaryDir() string { + basePath := filepath.Join("..", "..", "bin", "k8s") + entries, err := os.ReadDir(basePath) + if err != nil { + logf.Log.Error(err, "Failed to read directory", "path", basePath) + return "" + } + for _, entry := range entries { + if entry.IsDir() { + return filepath.Join(basePath, entry.Name()) + } + } + return "" +} diff --git a/deploy/rig-operator/internal/helm/client.go b/deploy/rig-operator/internal/helm/client.go new file mode 100644 index 0000000..d2df63e --- /dev/null +++ b/deploy/rig-operator/internal/helm/client.go @@ -0,0 +1,126 @@ +package helm + +import ( + "fmt" + "log" + "os" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/registry" // [NEW] Required for OCI + "helm.sh/helm/v3/pkg/storage/driver" + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +type Config struct { + Namespace string + ReleaseName string + RepoURL string + ChartName string + Version string + Values map[string]interface{} +} + +func Apply(cfg Config) error { + settings := cli.New() + + // 1. Initialize Action Config + actionConfig := new(action.Configuration) + getter := genericclioptions.NewConfigFlags(false) + + if err := actionConfig.Init(getter, cfg.Namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil { + return fmt.Errorf("failed to init helm config: %w", err) + } + + // 2. [NEW] Initialize OCI Registry Client + // This tells Helm how to talk to ghcr.io, docker.io, etc. + registryClient, err := registry.NewClient( + registry.ClientOptDebug(true), + registry.ClientOptEnableCache(true), + registry.ClientOptCredentialsFile(settings.RegistryConfig), // Uses ~/.config/helm/registry/config.json + ) + if err != nil { + return fmt.Errorf("failed to init registry client: %w", err) + } + actionConfig.RegistryClient = registryClient + + // 3. Setup Install Action + client := action.NewInstall(actionConfig) + client.Version = cfg.Version + client.Namespace = cfg.Namespace + client.ReleaseName = cfg.ReleaseName + client.CreateNamespace = true + + if cfg.RepoURL != "" { + client.RepoURL = cfg.RepoURL + } + + // 4. Locate Chart (Now supports oci:// because RegistryClient is set) + cp, err := client.ChartPathOptions.LocateChart(cfg.ChartName, settings) + if err != nil { + return fmt.Errorf("failed to locate chart %s: %w", cfg.ChartName, err) + } + + chart, err := loader.Load(cp) + if err != nil { + return fmt.Errorf("failed to load chart: %w", err) + } + + // 5. Install or Upgrade + histClient := action.NewHistory(actionConfig) + histClient.Max = 1 + + if _, err := histClient.Run(cfg.ReleaseName); err == driver.ErrReleaseNotFound { + fmt.Printf("Installing OCI Release %s...\n", cfg.ReleaseName) + _, err := client.Run(chart, cfg.Values) + return err + } else if err != nil { + return err + } + + fmt.Printf("Upgrading OCI Release %s...\n", cfg.ReleaseName) + upgrade := action.NewUpgrade(actionConfig) + upgrade.Version = cfg.Version + upgrade.Namespace = cfg.Namespace + // Important: Upgrade also needs the RegistryClient, but it shares 'actionConfig' + // so it is already set up. + if cfg.RepoURL != "" { + upgrade.RepoURL = cfg.RepoURL + } + _, err = upgrade.Run(cfg.ReleaseName, chart, cfg.Values) + return err +} + +func Uninstall(cfg Config) error { + settings := cli.New() + + // 1. Initialize Action Config (Same as Apply) + actionConfig := new(action.Configuration) + getter := genericclioptions.NewConfigFlags(false) + if err := actionConfig.Init(getter, cfg.Namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil { + return fmt.Errorf("failed to init helm config: %w", err) + } + + // 2. Initialize OCI Registry Client (Crucial for OCI charts) + registryClient, err := registry.NewClient( + registry.ClientOptDebug(true), + registry.ClientOptEnableCache(true), + registry.ClientOptCredentialsFile(settings.RegistryConfig), + ) + if err != nil { + return fmt.Errorf("failed to init registry client: %w", err) + } + actionConfig.RegistryClient = registryClient + + // 3. Run Uninstall + client := action.NewUninstall(actionConfig) + // Don't fail if it's already gone + _, err = client.Run(cfg.ReleaseName) + if err != nil && err != driver.ErrReleaseNotFound { + return fmt.Errorf("failed to uninstall release: %w", err) + } + + fmt.Printf("✅ Uninstalled Release %s\n", cfg.ReleaseName) + return nil +} diff --git a/deploy/rig-operator/internal/provider/harvester/credential.go b/deploy/rig-operator/internal/provider/harvester/credential.go new file mode 100644 index 0000000..43e084d --- /dev/null +++ b/deploy/rig-operator/internal/provider/harvester/credential.go @@ -0,0 +1,176 @@ +package harvester + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + authenticationv1 "k8s.io/api/authentication/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +// DeleteCredentialResources connects to Harvester and removes the specific SA and bindings +func DeleteCredentialResources(ctx context.Context, masterKubeconfig []byte, serviceAccountName, vmNamespace string) error { + restConfig, err := clientcmd.RESTConfigFromKubeConfig(masterKubeconfig) + if err != nil { + return err + } + hvClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return err + } + + deletePolicy := metav1.DeletePropagationBackground + deleteOpts := metav1.DeleteOptions{PropagationPolicy: &deletePolicy} + + // 1. Delete Global CSI Binding (ClusterRoleBinding) + csiBindingName := fmt.Sprintf("%s-csi-binding", serviceAccountName) + // We ignore NotFound errors to make this idempotent + if err := hvClient.RbacV1().ClusterRoleBindings().Delete(ctx, csiBindingName, deleteOpts); err != nil && !apierrors.IsNotFound(err) { + return err + } + + // 2. Delete Cloud Provider Binding (RoleBinding in VM Namespace) + cpBindingName := fmt.Sprintf("%s-cloud-binding", serviceAccountName) + if err := hvClient.RbacV1().RoleBindings(vmNamespace).Delete(ctx, cpBindingName, deleteOpts); err != nil && !apierrors.IsNotFound(err) { + return err + } + + // 3. Delete ServiceAccount (VM Namespace) + if err := hvClient.CoreV1().ServiceAccounts(vmNamespace).Delete(ctx, serviceAccountName, deleteOpts); err != nil && !apierrors.IsNotFound(err) { + return err + } + + return nil +} + +// EnsureCredential mints a dedicated ServiceAccount in the specific VM Namespace +func EnsureCredential(ctx context.Context, masterKubeconfig []byte, clusterName, targetNamespace, vmNamespace, harvesterURL string) (*corev1.Secret, string, time.Time, error) { + + // --- PHASE 1: Connect --- + restConfig, err := clientcmd.RESTConfigFromKubeConfig(masterKubeconfig) + if err != nil { + return nil, "", time.Time{}, fmt.Errorf("invalid rancher cloud credential kubeconfig: %w", err) + } + hvClient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return nil, "", time.Time{}, err + } + + // --- PHASE 2: Create Identity --- + if vmNamespace == "" { + vmNamespace = "default" + } + saName := fmt.Sprintf("prov-%s", clusterName) + + // A. Create ServiceAccount + sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: saName, Namespace: vmNamespace}} + if _, err := hvClient.CoreV1().ServiceAccounts(vmNamespace).Create(ctx, sa, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { + return nil, "", time.Time{}, err + } + } + + // B. Create RoleBinding (Cloud Provider) + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: saName + "-cloud-binding", Namespace: vmNamespace}, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: saName, Namespace: vmNamespace}}, + RoleRef: rbacv1.RoleRef{Kind: "ClusterRole", Name: "harvesterhci.io:cloudprovider", APIGroup: "rbac.authorization.k8s.io"}, + } + if _, err := hvClient.RbacV1().RoleBindings(vmNamespace).Create(ctx, rb, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { /* Ignore */ + } + } + + // C. Create ClusterRoleBinding (CSI Driver) + crb := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: saName + "-csi-binding"}, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: saName, Namespace: vmNamespace}}, + RoleRef: rbacv1.RoleRef{Kind: "ClusterRole", Name: "harvesterhci.io:csi-driver", APIGroup: "rbac.authorization.k8s.io"}, + } + if _, err := hvClient.RbacV1().ClusterRoleBindings().Create(ctx, crb, metav1.CreateOptions{}); err != nil { + if !apierrors.IsAlreadyExists(err) { /* Ignore */ + } + } + + // D. Mint Token + ttlSeconds := int64(315360000) // ~10 years + tokenRequest, err := hvClient.CoreV1().ServiceAccounts(vmNamespace).CreateToken(ctx, saName, &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ExpirationSeconds: &ttlSeconds}, + }, metav1.CreateOptions{}) + if err != nil { + return nil, "", time.Time{}, fmt.Errorf("failed to mint harvester token: %w", err) + } + expiryTime := time.Now().Add(time.Duration(ttlSeconds) * time.Second) + + // --- PHASE 3: Determine URL & CA --- + if harvesterURL == "" { + harvesterURL = restConfig.Host + } + + // Fetch internal CA (required because proxy CA != internal CA) + harvesterCA := restConfig.CAData + caConfigMap, err := hvClient.CoreV1().ConfigMaps("default").Get(ctx, "kube-root-ca.crt", metav1.GetOptions{}) + if err == nil { + if caStr, ok := caConfigMap.Data["ca.crt"]; ok { + harvesterCA = []byte(caStr) + } + } + + // --- PHASE 4: Construct Kubeconfig --- + caData := base64.StdEncoding.EncodeToString(harvesterCA) + token := tokenRequest.Status.Token + + newKubeconfig := fmt.Sprintf( + `apiVersion: v1 +kind: Config +clusters: +- name: harvester + cluster: + server: %s + certificate-authority-data: %s +users: +- name: provisioner + user: + token: %s +contexts: +- name: default + context: + cluster: harvester + user: provisioner + namespace: %s +current-context: default +`, harvesterURL, caData, token, vmNamespace) + + // --- PHASE 5: Create Secret Object --- + secretName := fmt.Sprintf("harvesterconfig-%s", clusterName) + + secret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{Kind: "Secret", APIVersion: "v1"}, + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: targetNamespace, + Annotations: map[string]string{ + // [CRITICAL] These annotations authorize the guest cluster to use this secret + "v2prov-secret-authorized-for-cluster": clusterName, + "v2prov-authorized-secret-deletes-on-cluster-removal": "true", + }, + Labels: map[string]string{ + "cattle.io/creator": "rig-operator", // Updated creator + "rig.appstack.io/cluster": clusterName, + }, + }, + Type: "Opaque", + StringData: map[string]string{ + "credential": newKubeconfig, + }, + } + + return secret, saName, expiryTime, nil +} diff --git a/deploy/rig-operator/internal/provider/harvester/manager.go b/deploy/rig-operator/internal/provider/harvester/manager.go new file mode 100644 index 0000000..c16c712 --- /dev/null +++ b/deploy/rig-operator/internal/provider/harvester/manager.go @@ -0,0 +1,126 @@ +package harvester + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" +) + +type IdentityManager struct { + client client.Client + scheme *runtime.Scheme +} + +func NewIdentityManager(c client.Client, s *runtime.Scheme) *IdentityManager { + return &IdentityManager{client: c, scheme: s} +} + +// Ensure checks if an identity exists. If not, it fetches master creds, mints a new one, and updates Status. +func (m *IdentityManager) Ensure(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, ibp *v1alpha1.InfraBlueprint, hbp *v1alpha1.HarvesterBlueprint) (string, error) { + l := log.FromContext(ctx) + + // 1. Fast Path: If identity already exists in Status, return it + if cbp.Status.Identity != nil && cbp.Status.Identity.SecretRef != "" { + return cbp.Status.Identity.SecretRef, nil + } + + l.Info("Minting Harvester identity", "Cluster", cbp.Name) + + // 2. Fetch Master Credential (from Infra) + rancherCredName := ibp.Spec.CloudCredentialSecret + if rancherCredName == "" { + return "", fmt.Errorf("CloudCredentialSecret is missing in InfraBlueprint %s", ibp.Name) + } + + var rancherSecret corev1.Secret + // Note: Rancher secrets are expected in cattle-global-data + if err := m.client.Get(ctx, types.NamespacedName{Name: rancherCredName, Namespace: "cattle-global-data"}, &rancherSecret); err != nil { + return "", fmt.Errorf("failed to fetch rancher credential %s: %w", rancherCredName, err) + } + + // 3. Extract Kubeconfig + const kubeconfigKey = "harvestercredentialConfig-kubeconfigContent" + adminKubeconfigBytes := rancherSecret.Data[kubeconfigKey] + if len(adminKubeconfigBytes) == 0 { + if len(rancherSecret.Data["credential"]) > 0 { + adminKubeconfigBytes = rancherSecret.Data["credential"] + } else { + return "", fmt.Errorf("secret %s missing kubeconfig data", rancherCredName) + } + } + + // 4. Call Factory (low-level) + newSecret, saName, _, err := EnsureCredential( + ctx, + adminKubeconfigBytes, + cbp.Name, + cbp.Namespace, // Target Namespace (where secret goes) + hbp.Spec.VmNamespace, // Harvester Namespace (where VM goes) + hbp.Spec.HarvesterURL, // Explicit URL from HBP + ) + if err != nil { + return "", fmt.Errorf("failed to mint harvester credential: %w", err) + } + + // 5. Persist Secret + // Set OwnerRef so if CBP is deleted, Secret is deleted automatically + if err := controllerutil.SetControllerReference(cbp, newSecret, m.scheme); err != nil { + return "", err + } + + patchOpts := []client.PatchOption{client.ForceOwnership, client.FieldOwner("rig-operator")} + if err := m.client.Patch(ctx, newSecret, client.Apply, patchOpts...); err != nil { + return "", fmt.Errorf("failed to patch new secret: %w", err) + } + + // 6. Update CBP Status + // We do this here so the identity is "locked" to the object immediately + if cbp.Status.Identity == nil { + cbp.Status.Identity = &v1alpha1.IdentityStatus{} + } + cbp.Status.Identity.SecretRef = newSecret.Name + cbp.Status.Identity.ServiceAccount = saName + + if err := m.client.Status().Update(ctx, cbp); err != nil { + return "", fmt.Errorf("failed to update cluster status: %w", err) + } + + return newSecret.Name, nil +} + +// Cleanup removes the ServiceAccount from Harvester when the Cluster is deleted +func (m *IdentityManager) Cleanup(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, ibp *v1alpha1.InfraBlueprint, hbp *v1alpha1.HarvesterBlueprint) { + if cbp.Status.Identity == nil || cbp.Status.Identity.ServiceAccount == "" { + return + } + + // Fetch Master Secret again to get connection details + rancherCredName := ibp.Spec.CloudCredentialSecret + var rancherSecret corev1.Secret + if err := m.client.Get(ctx, types.NamespacedName{Name: rancherCredName, Namespace: "cattle-global-data"}, &rancherSecret); err != nil { + log.FromContext(ctx).V(1).Info("Cleanup: Could not fetch master secret (connection lost), skipping manual cleanup") + return + } + + var kubeBytes []byte + if len(rancherSecret.Data["harvestercredentialConfig-kubeconfigContent"]) > 0 { + kubeBytes = rancherSecret.Data["harvestercredentialConfig-kubeconfigContent"] + } else if len(rancherSecret.Data["credential"]) > 0 { + kubeBytes = rancherSecret.Data["credential"] + } else { + return + } + + // Delegate to low-level cleanup + if err := DeleteCredentialResources(ctx, kubeBytes, cbp.Status.Identity.ServiceAccount, hbp.Spec.VmNamespace); err != nil { + log.FromContext(ctx).Error(err, "Failed to cleanup Harvester resources (best effort)") + } +} diff --git a/deploy/rig-operator/internal/provider/harvester/strategy.go b/deploy/rig-operator/internal/provider/harvester/strategy.go new file mode 100644 index 0000000..3003612 --- /dev/null +++ b/deploy/rig-operator/internal/provider/harvester/strategy.go @@ -0,0 +1,140 @@ +package harvester + +import ( + "context" + "fmt" + + "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + template "vanderlande.com/ittp/appstack/rig-operator/internal/templates/harvester" +) + +// harvesterNodePool matches the exact JSON structure required by the Helm Chart +type harvesterNodePool struct { + Name string `json:"name"` + DisplayName string `json:"displayName"` + Quantity int `json:"quantity"` + Etcd bool `json:"etcd"` + ControlPlane bool `json:"controlplane"` + Worker bool `json:"worker"` + Paused bool `json:"paused"` + + // Harvester Specific Fields + CpuCount int `json:"cpuCount"` + MemorySize int `json:"memorySize"` // GB + DiskSize int `json:"diskSize"` // GB + ImageName string `json:"imageName"` + NetworkName string `json:"networkName"` + SshUser string `json:"sshUser"` + VmNamespace string `json:"vmNamespace"` + UserData string `json:"userData"` +} + +type Strategy struct { + blueprint *v1alpha1.HarvesterBlueprint + userData string + rancherURL string + defaults template.Defaults +} + +// NewStrategy initializes the strategy with defaults and optional overrides +func NewStrategy(hbp *v1alpha1.HarvesterBlueprint, infraUserData string, infraRancherURL string, defaults template.Defaults) *Strategy { // 1. Determine UserData priority: Infra (IBP) > Template Default + finalUserData := infraUserData + if finalUserData == "" { + finalUserData = defaults.UserData + } + + return &Strategy{ + blueprint: hbp, + userData: finalUserData, + rancherURL: infraRancherURL, + defaults: defaults, + } +} + +// GenerateNodePools implements provider.Strategy +func (s *Strategy) GenerateNodePools(ctx context.Context, cbp *v1alpha1.ClusterBlueprint) (interface{}, error) { + var pools []interface{} + + // Helper to map generic req -> harvester specific struct + mapPool := func(name string, qty, cpu, memGB, diskGB int, isEtcd, isCp, isWk bool) harvesterNodePool { + return harvesterNodePool{ + Name: name, + DisplayName: name, + Quantity: qty, + Etcd: isEtcd, + ControlPlane: isCp, + Worker: isWk, + Paused: false, + + // Mapping: Generic (GB) -> Harvester (GB) [No conversion needed] + CpuCount: cpu, + MemorySize: memGB, + DiskSize: diskGB, + + // Harvester Specifics from HBP + ImageName: s.blueprint.Spec.ImageName, + NetworkName: s.blueprint.Spec.NetworkName, + SshUser: s.blueprint.Spec.SshUser, + VmNamespace: s.blueprint.Spec.VmNamespace, + UserData: s.userData, + } + } + + // 1. Control Plane Pool + cpQty := 1 + if cbp.Spec.ControlPlaneHA { + cpQty = 3 + } + + // Use Defaults from YAML for CP sizing + pools = append(pools, mapPool( + "cp-pool", + cpQty, + s.defaults.CP_CPU, + s.defaults.CP_Mem, + s.defaults.CP_Disk, + true, true, false, + )) + + // 2. Worker Pools + for _, wp := range cbp.Spec.WorkerPools { + pools = append(pools, mapPool( + wp.Name, + wp.Quantity, + wp.CpuCores, + wp.MemoryGB, + wp.DiskGB, + false, false, true, + )) + } + + return pools, nil +} + +// GetGlobalOverrides implements provider.Strategy +func (s *Strategy) GetGlobalOverrides(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, credentialSecretName string) (map[string]interface{}, error) { + // secret://: + secretURI := fmt.Sprintf("secret://%s:%s", cbp.Namespace, credentialSecretName) + + overrides := map[string]interface{}{ + "cloud_provider_name": "harvester", + "cloud_provider_config": secretURI, + // Inject Rancher URL + "rancher": map[string]interface{}{ + "cattle": map[string]interface{}{ + "url": s.rancherURL, + }, + }, + + "chartValues": map[string]interface{}{ + "harvester-cloud-provider": map[string]interface{}{ + "global": map[string]interface{}{ + "cattle": map[string]interface{}{ + "clusterName": cbp.Name, + }, + }, + }, + }, + } + return overrides, nil +} diff --git a/deploy/rig-operator/internal/provider/interface.go b/deploy/rig-operator/internal/provider/interface.go new file mode 100644 index 0000000..b4a0d4b --- /dev/null +++ b/deploy/rig-operator/internal/provider/interface.go @@ -0,0 +1,16 @@ +package provider + +import ( + "context" + + "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" +) + +type Strategy interface { + // GenerateNodePools generates the provider-specific node pool list. + // [CHANGED] Return type is now interface{} to support both Structs and Maps + GenerateNodePools(ctx context.Context, cbp *v1alpha1.ClusterBlueprint) (interface{}, error) + + // GetGlobalOverrides returns the provider-specific helm values. + GetGlobalOverrides(ctx context.Context, cbp *v1alpha1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) +} diff --git a/deploy/rig-operator/internal/provider/vsphere/strategy.go b/deploy/rig-operator/internal/provider/vsphere/strategy.go new file mode 100644 index 0000000..b685871 --- /dev/null +++ b/deploy/rig-operator/internal/provider/vsphere/strategy.go @@ -0,0 +1,138 @@ +package vsphere + +import ( + "context" + + rigv1 "vanderlande.com/ittp/appstack/rig-operator/api/v1alpha1" + vspheretpl "vanderlande.com/ittp/appstack/rig-operator/internal/templates/vsphere" +) + +type Strategy struct { + blueprint *rigv1.VsphereBlueprint + userData string + rancherURL string + defaults vspheretpl.Defaults +} + +// NewStrategy creates the vSphere logic handler +func NewStrategy(vbp *rigv1.VsphereBlueprint, userData string, rancherURL string, defaults vspheretpl.Defaults) *Strategy { + // 1. Resolve UserData (Infra > Template Default) + finalUserData := userData + if finalUserData == "" { + finalUserData = defaults.UserData + } + + return &Strategy{ + blueprint: vbp, + userData: finalUserData, + rancherURL: rancherURL, + defaults: defaults, + } +} + +// GenerateNodePools maps the generic ClusterBlueprint to vSphere-specific NodePool maps +func (s *Strategy) GenerateNodePools(ctx context.Context, cbp *rigv1.ClusterBlueprint) (interface{}, error) { + var nodePools []map[string]interface{} + + // 1. Control Plane Node Pool + // We rely on the defaults extracted from values.yaml (e.g. 4 Core, 8GB) + // vSphere Chart expects MB, so we multiply GB * 1024. + cpQty := 1 + if cbp.Spec.ControlPlaneHA { + cpQty = 3 + } + + nodePools = append(nodePools, s.buildPool( + "control-plane-nodes", // Name + "cp-nodes", // Display Name + cpQty, // Quantity + s.defaults.CP_CPU, // Cores + s.defaults.CP_Mem*1024, // RAM (GB -> MB) + s.defaults.CP_Disk*1024, // Disk (GB -> MB) + true, // Etcd + true, // ControlPlane + false, // Worker + )) + + // 2. Worker Pools + // We iterate over the user's requested pools in the CBP + for _, wp := range cbp.Spec.WorkerPools { + nodePools = append(nodePools, s.buildPool( + wp.Name, + wp.Name, + wp.Quantity, + wp.CpuCores, + wp.MemoryGB*1024, // Convert GB to MB + wp.DiskGB*1024, // Convert GB to MB + false, // Etcd + false, // ControlPlane + true, // Worker + )) + } + + return nodePools, nil +} + +// GetGlobalOverrides injects the vSphere-specific global values (Cloud Provider, Credentials, URLs) +func (s *Strategy) GetGlobalOverrides(ctx context.Context, cbp *rigv1.ClusterBlueprint, credentialSecret string) (map[string]interface{}, error) { + overrides := map[string]interface{}{ + // Tell Helm we are on vSphere + "cloudprovider": "vsphere", + + // The Secret containing username/password/vcenter-address + "cloudCredentialSecretName": credentialSecret, + + // Register with the correct Rancher Manager + "rancher": map[string]interface{}{ + "cattle": map[string]interface{}{ + "url": s.rancherURL, + }, + }, + + // Cluster Metadata + "cluster": map[string]interface{}{ + "name": cbp.Name, + "config": map[string]interface{}{ + "kubernetesVersion": cbp.Spec.KubernetesVersion, + }, + }, + } + + return overrides, nil +} + +// buildPool is a private helper to construct the exact map structure the vSphere Helm Chart expects +func (s *Strategy) buildPool(name, displayName string, qty, cpu, ramMB, diskMB int, etcd, cp, worker bool) map[string]interface{} { + pool := map[string]interface{}{ + // Generic RKE2 Node Settings + "name": name, + "displayName": displayName, + "quantity": qty, + "etcd": etcd, + "controlplane": cp, + "worker": worker, + "paused": false, + + // vSphere Infrastructure Location (From Blueprint) + "vcenter": s.blueprint.Spec.VCenter, + "datacenter": s.blueprint.Spec.Datacenter, + "folder": s.blueprint.Spec.Folder, + "pool": s.blueprint.Spec.ResourcePool, + "datastoreCluster": s.blueprint.Spec.Datastore, // Assumes chart supports this key. If not, use "datastore". + "network": []string{s.blueprint.Spec.Network}, + + // Cloning Details + "creationType": "template", + "cloneFrom": s.blueprint.Spec.Template, + + // Hardware Sizing (Already converted to MB) + "cpuCount": cpu, + "memorySize": ramMB, + "diskSize": diskMB, + + // Cloud Init + "cloudConfig": s.userData, + } + + return pool +} diff --git a/deploy/rig-operator/internal/templates/harvester/embed.go b/deploy/rig-operator/internal/templates/harvester/embed.go new file mode 100644 index 0000000..123f277 --- /dev/null +++ b/deploy/rig-operator/internal/templates/harvester/embed.go @@ -0,0 +1,69 @@ +package harvester + +import ( + _ "embed" + "fmt" + + "gopkg.in/yaml.v3" +) + +//go:embed values.yaml +var valuesYAML []byte + +type Defaults struct { + CP_CPU int + CP_Mem int + CP_Disk int + + ChartRepo string + ChartName string + ChartVersion string + + // [NEW] Default UserData for this provider + UserData string +} + +func GetDefaults() (Defaults, error) { + var raw map[string]interface{} + if err := yaml.Unmarshal(valuesYAML, &raw); err != nil { + return Defaults{}, fmt.Errorf("failed to parse harvester base values: %w", err) + } + + d := Defaults{ + CP_CPU: 4, CP_Mem: 8, CP_Disk: 40, // Safety Fallbacks + } + + if defs, ok := raw["_defaults"].(map[string]interface{}); ok { + if cp, ok := defs["controlPlaneProfile"].(map[string]interface{}); ok { + if v, ok := cp["cpuCores"].(int); ok { + d.CP_CPU = v + } + if v, ok := cp["memoryGb"].(int); ok { + d.CP_Mem = v + } + if v, ok := cp["diskGb"].(int); ok { + d.CP_Disk = v + } + } + if chart, ok := defs["helmChart"].(map[string]interface{}); ok { + if v, ok := chart["repo"].(string); ok { + d.ChartRepo = v + } + if v, ok := chart["name"].(string); ok { + d.ChartName = v + } + if v, ok := chart["version"].(string); ok { + d.ChartVersion = v + } + } + // [NEW] Extract UserData + if v, ok := defs["userData"].(string); ok { + d.UserData = v + } + } + return d, nil +} + +func GetBaseValues() []byte { + return valuesYAML +} diff --git a/deploy/rig-operator/internal/templates/harvester/values.yaml b/deploy/rig-operator/internal/templates/harvester/values.yaml new file mode 100644 index 0000000..cabfb23 --- /dev/null +++ b/deploy/rig-operator/internal/templates/harvester/values.yaml @@ -0,0 +1,456 @@ +# ---------------------------------------------------------------- +# BASE TEMPLATE (internal/templates/base_values.yaml) +# ---------------------------------------------------------------- + +_defaults: + helmChart: + repo: "" + name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates" + version: "0.7.2" + controlPlaneProfile: + cpuCores: 4 + memoryGb: 8 + diskGb: 40 + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - qemu-guest-agent + - yq + - jq + - curl + - wget + + bootcmd: + - sysctl -w net.ipv6.conf.all.disable_ipv6=1 + - sysctl -w net.ipv6.conf.default.disable_ipv6=1 + + write_files: + # ---------------------------------------------------------------- + # 1. CNI Permission Fix Script & Cron (CIS 1.1.9 Persistence) + # ---------------------------------------------------------------- + - path: /usr/local/bin/fix-cni-perms.sh + permissions: '0700' + owner: root:root + content: | + #!/bin/bash + # Wait 60s on boot for RKE2 to write files + [ "$1" == "boot" ] && sleep 60 + + # Enforce 600 on CNI files (CIS 1.1.9) + if [ -d /etc/cni/net.d ]; then + find /etc/cni/net.d -type f -exec chmod 600 {} \; + fi + if [ -d /var/lib/cni/networks ]; then + find /var/lib/cni/networks -type f -exec chmod 600 {} \; + fi + + # Every RKE2 service restart can reset CNI file permissions, so we run + # this script on reboot and daily via cron to maintain CIS compliance. + + - path: /etc/cron.d/cis-cni-fix + permissions: '0644' + owner: root:root + content: | + # Run on Reboot (with delay) to fix files created during startup + @reboot root /usr/local/bin/fix-cni-perms.sh boot + # Run once daily at 00:00 to correct any drift + 0 0 * * * root /usr/local/bin/fix-cni-perms.sh + + # ---------------------------------------------------------------- + # 2. RKE2 Admission Config + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/rke2-admission.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: apiserver.config.k8s.io/v1 + kind: AdmissionConfiguration + plugins: + - name: PodSecurity + configuration: + apiVersion: pod-security.admission.config.k8s.io/v1beta1 + kind: PodSecurityConfiguration + defaults: + enforce: "restricted" + enforce-version: "latest" + audit: "restricted" + audit-version: "latest" + warn: "restricted" + warn-version: "latest" + exemptions: + usernames: [] + runtimeClasses: [] + namespaces: [compliance-operator-system,kube-system, cis-operator-system, tigera-operator, calico-system, rke2-ingress-nginx, cattle-system, cattle-fleet-system, longhorn-system, cattle-neuvector-system] + - name: EventRateLimit + configuration: + apiVersion: eventratelimit.admission.k8s.io/v1alpha1 + kind: Configuration + limits: + - type: Server + qps: 5000 + burst: 20000 + + # ---------------------------------------------------------------- + # 3. RKE2 Audit Policy + # ---------------------------------------------------------------- + - path: /etc/rancher/rke2/audit-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: audit.k8s.io/v1 + kind: Policy + rules: + - level: None + users: ["system:kube-controller-manager", "system:kube-scheduler", "system:serviceaccount:kube-system:endpoint-controller"] + verbs: ["get", "update"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status"] + - level: None + verbs: ["get"] + resources: + - group: "" + resources: ["nodes", "nodes/status", "pods", "pods/status"] + - level: None + users: ["kube-proxy"] + verbs: ["watch"] + resources: + - group: "" + resources: ["endpoints", "services", "services/status", "configmaps"] + - level: Metadata + resources: + - group: "" + resources: ["secrets", "configmaps"] + - level: RequestResponse + omitStages: + - RequestReceived + + # ---------------------------------------------------------------- + # 4. Static NetworkPolicies + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-network-policy.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: default-deny-ingress + namespace: default + spec: + podSelector: {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-metrics + namespace: kube-public + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + --- + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: allow-all-system + namespace: kube-system + spec: + podSelector: {} + ingress: + - {} + policyTypes: + - Ingress + + # ---------------------------------------------------------------- + # 5. Service Account Hardening + # ---------------------------------------------------------------- + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-config.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: default + automountServiceAccountToken: false + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: default + namespace: kube-system + automountServiceAccountToken: false + + - path: /var/lib/rancher/rke2/server/manifests/cis-sa-cron.yaml + permissions: '0600' + owner: root:root + content: | + apiVersion: v1 + kind: ServiceAccount + metadata: {name: sa-cleaner, namespace: kube-system} + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: {name: sa-cleaner-role} + rules: + - apiGroups: [""] + resources: ["namespaces", "serviceaccounts"] + verbs: ["get", "list", "patch"] + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: {name: sa-cleaner-binding} + subjects: [{kind: ServiceAccount, name: sa-cleaner, namespace: kube-system}] + roleRef: {kind: ClusterRole, name: sa-cleaner-role, apiGroup: rbac.authorization.k8s.io} + --- + apiVersion: batch/v1 + kind: CronJob + metadata: + name: sa-cleaner + namespace: kube-system + spec: + schedule: "0 */6 * * *" # Run every 6 hours + jobTemplate: + spec: + template: + spec: + serviceAccountName: sa-cleaner + containers: + - name: cleaner + image: rancher/kubectl:v1.26.0 + command: + - /bin/bash + - -c + - | + # Get all namespaces + for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do + # Check if default SA has automount=true (or null) + automount=$(kubectl get sa default -n $ns -o jsonpath='{.automountServiceAccountToken}') + if [ "$automount" != "false" ]; then + echo "Securing default SA in namespace: $ns" + kubectl patch sa default -n $ns -p '{"automountServiceAccountToken": false}' + fi + done + restartPolicy: OnFailure + + # ---------------------------------------------------------------- + # 6. OS Sysctls Hardening + # ---------------------------------------------------------------- + - path: /etc/sysctl.d/60-rke2-cis.conf + permissions: '0644' + content: | + vm.overcommit_memory=1 + vm.max_map_count=65530 + vm.panic_on_oom=0 + fs.inotify.max_user_watches=1048576 + fs.inotify.max_user_instances=8192 + kernel.panic=10 + kernel.panic_on_oops=1 + net.ipv4.conf.all.rp_filter=1 + net.ipv4.conf.default.rp_filter=1 + net.ipv4.conf.all.accept_source_route=0 + net.ipv4.conf.default.accept_source_route=0 + net.ipv4.conf.all.accept_redirects=0 + net.ipv4.conf.default.accept_redirects=0 + net.ipv4.conf.all.send_redirects=0 + net.ipv4.conf.default.send_redirects=0 + net.ipv4.conf.all.log_martians=1 + net.ipv4.conf.default.log_martians=1 + net.ipv4.icmp_echo_ignore_broadcasts=1 + net.ipv4.icmp_ignore_bogus_error_responses=1 + net.ipv6.conf.all.disable_ipv6=1 + net.ipv6.conf.default.disable_ipv6=1 + fs.protected_hardlinks=1 + fs.protected_symlinks=1 + + # ---------------------------------------------------------------- + # 7. Environment & Setup Scripts + # ---------------------------------------------------------------- + - path: /etc/profile.d/rke2.sh + permissions: '0644' + content: | + export PATH=$PATH:/var/lib/rancher/rke2/bin:/opt/rke2/bin + export KUBECONFIG=/etc/rancher/rke2/rke2.yaml + + + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + - name: etcd + gecos: "etcd user" + shell: /sbin/nologin + system: true + lock_passwd: true + + disable_root: true + ssh_pwauth: true + + runcmd: + - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + - /usr/local/bin/fix-cni-perms.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Node ready for Rancher! + +# amazonec2, azure, digitalocean, harvester, vsphere, custom +cloudprovider: harvester + +# cloud provider credentials +cloudCredentialSecretName: cc-mrklm + +# rancher manager url +rancher: + cattle: + url: rancher-mgmt.product.lan + +# cluster values +cluster: + + name: default-cluster + # labels: + # key: value + config: + kubernetesVersion: v1.33.5+rke2r1 + enableNetworkPolicy: true + localClusterAuthEndpoint: + enabled: false + chartValues: + harvester-cloud-provider: + global: + cattle: + clusterName: default-cluster + + # Pod Security Standard (Replaces PSP) + defaultPodSecurityAdmissionConfigurationTemplateName: "rancher-restricted" + + globalConfig: + systemDefaultRegistry: docker.io + cni: canal + docker: false + disable_scheduler: false + disable_cloud_controller: false + disable_kube_proxy: false + etcd_expose_metrics: false + profile: 'cis' + selinux: false + secrets_encryption: true + write_kubeconfig_mode: 0600 + use_service_account_credentials: false + protect_kernel_defaults: true + cloud_provider_name: harvester + cloud_provider_config: secret://fleet-default:harvesterconfigzswmd + + kube_apiserver_arg: + - "service-account-extend-token-expiration=false" + - "anonymous-auth=false" + - "enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit,DenyServiceExternalIPs" + - "admission-control-config-file=/etc/rancher/rke2/rke2-admission.yaml" + - "audit-policy-file=/etc/rancher/rke2/audit-policy.yaml" + - "audit-log-path=/var/lib/rancher/rke2/server/logs/audit.log" + - "audit-log-maxage=30" + - "audit-log-maxbackup=10" + - "audit-log-maxsize=100" + + kubelet_arg: + # Strong Ciphers (CIS 4.2.12) + - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + # PID Limit (CIS 4.2.13) + - "pod-max-pids=4096" + # Seccomp Default (CIS 4.2.14) + - "seccomp-default=true" + - "protect-kernel-defaults=true" + - "make-iptables-util-chains=true" + + upgradeStrategy: + controlPlaneConcurrency: 10% + controlPlaneDrainOptions: + enabled: false + workerConcurrency: 10% + workerDrainOptions: + enabled: false +addons: + monitoring: + enabled: false + logging: + enabled: false + longhorn: + enabled: false + neuvector: + enabled: false + +# node and nodepool(s) values +# ---------------------------------------------------------------- +# MANUAL TESTING SECTION +# The Operator will DELETE and OVERWRITE this section at runtime. +# These values are only used if you run 'helm install' manually. +# ---------------------------------------------------------------- +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + cpuCount: 4 + diskSize: 40 + imageName: vanderlande/image-qhtpc + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + + - name: worker-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + cpuCount: 2 + diskSize: 40 + imageName: vanderlande/image-qmx5q + memorySize: 8 + networkName: vanderlande/vm-lan + sshUser: rancher + vmNamespace: vanderlande + userData: *userData + diff --git a/deploy/rig-operator/internal/templates/vsphere/embed.go b/deploy/rig-operator/internal/templates/vsphere/embed.go new file mode 100644 index 0000000..db5a8b5 --- /dev/null +++ b/deploy/rig-operator/internal/templates/vsphere/embed.go @@ -0,0 +1,77 @@ +package vsphere + +import ( + _ "embed" + "fmt" + + "gopkg.in/yaml.v3" +) + +//go:embed values.yaml +var valuesYAML []byte + +type Defaults struct { + CP_CPU int + CP_Mem int + CP_Disk int + + ChartRepo string + ChartName string + ChartVersion string + + UserData string +} + +// GetDefaults parses the embedded values.yaml to extract global settings +func GetDefaults() (Defaults, error) { + var raw map[string]interface{} + if err := yaml.Unmarshal(valuesYAML, &raw); err != nil { + return Defaults{}, fmt.Errorf("failed to parse vsphere base values: %w", err) + } + + // 1. Set Hardcoded Fallbacks (Safety Net) + d := Defaults{ + CP_CPU: 2, CP_Mem: 4, CP_Disk: 40, // vSphere might need different defaults than Harvester + } + + // 2. Read from _defaults block + if defs, ok := raw["_defaults"].(map[string]interface{}); ok { + + // Profile Defaults + if cp, ok := defs["controlPlaneProfile"].(map[string]interface{}); ok { + if v, ok := cp["cpuCores"].(int); ok { + d.CP_CPU = v + } + if v, ok := cp["memoryGb"].(int); ok { + d.CP_Mem = v + } + if v, ok := cp["diskGb"].(int); ok { + d.CP_Disk = v + } + } + + // Helm Chart Defaults + if chart, ok := defs["helmChart"].(map[string]interface{}); ok { + if v, ok := chart["repo"].(string); ok { + d.ChartRepo = v + } + if v, ok := chart["name"].(string); ok { + d.ChartName = v + } + if v, ok := chart["version"].(string); ok { + d.ChartVersion = v + } + } + + // UserData Default + if v, ok := defs["userData"].(string); ok { + d.UserData = v + } + } + return d, nil +} + +// GetBaseValues returns the raw bytes for the MasterBuilder +func GetBaseValues() []byte { + return valuesYAML +} diff --git a/deploy/rig-operator/internal/templates/vsphere/values.yaml b/deploy/rig-operator/internal/templates/vsphere/values.yaml new file mode 100644 index 0000000..1adb15c --- /dev/null +++ b/deploy/rig-operator/internal/templates/vsphere/values.yaml @@ -0,0 +1,202 @@ +# ---------------------------------------------------------------- +# BASE TEMPLATE (internal/templates/base_values.yaml) +# ---------------------------------------------------------------- + +_defaults: + helmChart: + repo: "" + name: "oci://ghcr.io/rancherfederal/charts/rancher-cluster-templates" + version: "0.7.2" + controlPlaneProfile: + cpuCores: 4 + memoryGb: 8 + diskGb: 40 + userData: &userData | + #cloud-config + package_update: false + package_upgrade: false + snap: + commands: + 00: snap refresh --hold=forever + package_reboot_if_required: true + packages: + - yq + - jq + + disable_root: true + ssh_pwauth: false + + write_files: + - path: /root/updates.sh + permissions: '0550' + content: | + #!/bin/bash + export DEBIAN_FRONTEND=noninteractive + apt-mark hold linux-headers-generic + apt-mark hold linux-headers-virtual + apt-mark hold linux-image-virtual + apt-mark hold linux-virtual + apt-get update + apt-get upgrade -y + apt-get autoremove -y + + users: + - name: rancher + gecos: Rancher service account + hashed_passwd: $6$Mas.x2i7B2cefjUy$59363FmEuoU.LiTLNRZmtemlH2W0D0SWsig22KSZ3QzOmfxeZXxdSx5wIw9wO7GXF/M9W.9SHoKVBOYj1HPX3. + lock_passwd: false + shell: /bin/bash + groups: [users, sudo, docker] + sudo: ALL=(ALL:ALL) ALL + ssh_authorized_keys: + - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEwWnnOTAu0LlAZRczQ0Z0KvNlUdPhGQhpZie+nF1O3s' + + disable_root: true + ssh_pwauth: true + + runcmd: + # - systemctl enable --now qemu-guest-agent + - sysctl --system + - /root/updates.sh + # Immediate run of fix script + + bootcmd: + - sudo bash /root/networking.sh + + final_message: | + VI_CNV_CLOUD_INIT has been applied successfully. + Node ready for Rancher! + +# amazonec2, azure, digitalocean, harvester, vsphere, custom +cloudprovider: vsphere + +# cloud provider credentials +cloudCredentialSecretName: cc-lhtl9 + +# rancher manager url +rancher: + cattle: + url: rancher.tst.vanderlande.com + +# cluster values +cluster: + + name: default-cluster-005 + # labels: + # key: value + config: + kubernetesVersion: v1.31.12+rke2r1 + enableNetworkPolicy: true + localClusterAuthEndpoint: + enabled: false + + + # Pod Security Standard (Replaces PSP) + # defaultPodSecurityAdmissionConfigurationTemplateName: "rancher-restricted" + + globalConfig: + systemDefaultRegistry: docker.io + cni: canal + docker: false + disable_scheduler: false + disable_cloud_controller: false + disable_kube_proxy: false + etcd_expose_metrics: false + profile: '' + selinux: false + secrets_encryption: false + write_kubeconfig_mode: 0600 + use_service_account_credentials: false + protect_kernel_defaults: false + cloud_provider_name: '' + + # kube_apiserver_arg: + # - "service-account-extend-token-expiration=false" + # - "anonymous-auth=false" + # - "enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit,DenyServiceExternalIPs" + # - "admission-control-config-file=/etc/rancher/rke2/rke2-admission.yaml" + # - "audit-policy-file=/etc/rancher/rke2/audit-policy.yaml" + # - "audit-log-path=/var/lib/rancher/rke2/server/logs/audit.log" + # - "audit-log-maxage=30" + # - "audit-log-maxbackup=10" + # - "audit-log-maxsize=100" + + # kubelet_arg: + # # Strong Ciphers (CIS 4.2.12) + # - "tls-cipher-suites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + # # PID Limit (CIS 4.2.13) + # - "pod-max-pids=4096" + # # Seccomp Default (CIS 4.2.14) + # - "seccomp-default=true" + # - "protect-kernel-defaults=true" + # - "make-iptables-util-chains=true" + + upgradeStrategy: + controlPlaneConcurrency: 10% + controlPlaneDrainOptions: + enabled: false + workerConcurrency: 10% + workerDrainOptions: + enabled: false +addons: + monitoring: + enabled: false + logging: + enabled: false + longhorn: + enabled: true + neuvector: + enabled: false + +# node and nodepool(s) values +# ---------------------------------------------------------------- +# MANUAL TESTING SECTION +# The Operator will DELETE and OVERWRITE this section at runtime. +# These values are only used if you run 'helm install' manually. +# ---------------------------------------------------------------- +nodepools: + - name: control-plane-nodes + displayName: cp-nodes + quantity: 1 + etcd: true + controlplane: true + worker: false + paused: false + # VSPHERE SPECIFIC FIELDS + cpuCount: 2 + memorySize: 8192 + diskSize: 40000 + vcenter: "vcenter.vanderlande.com" + datacenter: "NL001" + folder: "ICT Digitalisation - Rancher" + pool: "NL001 Development - Rancher/Resources" + datastoreCluster: "NL001 Development - Rancher SDRS" # Matches your SDRS input + network: + - "nl001.vDS.Distri.Vlan.1542" + # Provisioning Source + creationType: "template" + cloneFrom: "nl001-cp-ubuntu-22.04-amd64-20250327-5.15.0-135-rke2-k3s" + cloudConfig: *userData # Using the anchor from your base file + + - name: worker-storage-nodes + displayName: wk-nodes + quantity: 2 + etcd: false + controlplane: false + worker: true + paused: false + # VSPHERE SPECIFIC FIELDS + cpuCount: 4 + memorySize: 8192 + diskSize: 100000 + vcenter: "vcenter.vanderlande.com" + datacenter: "NL001" + folder: "ICT Digitalisation - Rancher" + pool: "NL001 Development - Rancher/Resources" + datastoreCluster: "NL001 Development - Rancher SDRS" # Matches your SDRS input + network: + - "nl001.vDS.Distri.Vlan.1542" + # Provisioning Source + creationType: "template" + cloneFrom: "nl001-cp-ubuntu-22.04-amd64-20250327-5.15.0-135-rke2-k3s" + cloudConfig: *userData # Using the anchor from your base file \ No newline at end of file diff --git a/deploy/rig-operator/misc/patch-default-sa b/deploy/rig-operator/misc/patch-default-sa new file mode 100755 index 0000000..4408581 --- /dev/null +++ b/deploy/rig-operator/misc/patch-default-sa @@ -0,0 +1,11 @@ +#!/bin/sh + +# Copy script into /etc/cron.daily/ +# Make it executable chmod 0755 + +# TODO: Update path to actual kubeconfig +export KUBECONFIG=/home/rancher/.kube/config + +for n in $(kubectl get namespaces -A -o=jsonpath="{.items[*]['metadata.name']}"); do + kubectl patch serviceaccount default -p '{"automountServiceAccountToken": false}' -n $n +done diff --git a/deploy/rig-operator/test/e2e/e2e_suite_test.go b/deploy/rig-operator/test/e2e/e2e_suite_test.go new file mode 100644 index 0000000..f62e9fc --- /dev/null +++ b/deploy/rig-operator/test/e2e/e2e_suite_test.go @@ -0,0 +1,92 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "fmt" + "os" + "os/exec" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "vanderlande.com/ittp/appstack/rig-operator/test/utils" +) + +var ( + // Optional Environment Variables: + // - CERT_MANAGER_INSTALL_SKIP=true: Skips CertManager installation during test setup. + // These variables are useful if CertManager is already installed, avoiding + // re-installation and conflicts. + skipCertManagerInstall = os.Getenv("CERT_MANAGER_INSTALL_SKIP") == "true" + // isCertManagerAlreadyInstalled will be set true when CertManager CRDs be found on the cluster + isCertManagerAlreadyInstalled = false + + // projectImage is the name of the image which will be build and loaded + // with the code source changes to be tested. + projectImage = "example.com/deploy:v0.0.1" +) + +// TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated, +// temporary environment to validate project changes with the purpose of being used in CI jobs. +// The default setup requires Kind, builds/loads the Manager Docker image locally, and installs +// CertManager. +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + _, _ = fmt.Fprintf(GinkgoWriter, "Starting deploy integration test suite\n") + RunSpecs(t, "e2e suite") +} + +var _ = BeforeSuite(func() { + By("building the manager(Operator) image") + cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectImage)) + _, err := utils.Run(cmd) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to build the manager(Operator) image") + + // TODO(user): If you want to change the e2e test vendor from Kind, ensure the image is + // built and available before running the tests. Also, remove the following block. + By("loading the manager(Operator) image on Kind") + err = utils.LoadImageToKindClusterWithName(projectImage) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to load the manager(Operator) image into Kind") + + // The tests-e2e are intended to run on a temporary cluster that is created and destroyed for testing. + // To prevent errors when tests run in environments with CertManager already installed, + // we check for its presence before execution. + // Setup CertManager before the suite if not skipped and if not already installed + if !skipCertManagerInstall { + By("checking if cert manager is installed already") + isCertManagerAlreadyInstalled = utils.IsCertManagerCRDsInstalled() + if !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Installing CertManager...\n") + Expect(utils.InstallCertManager()).To(Succeed(), "Failed to install CertManager") + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "WARNING: CertManager is already installed. Skipping installation...\n") + } + } +}) + +var _ = AfterSuite(func() { + // Teardown CertManager after the suite if not skipped and if it was not already installed + if !skipCertManagerInstall && !isCertManagerAlreadyInstalled { + _, _ = fmt.Fprintf(GinkgoWriter, "Uninstalling CertManager...\n") + utils.UninstallCertManager() + } +}) diff --git a/deploy/rig-operator/test/e2e/e2e_test.go b/deploy/rig-operator/test/e2e/e2e_test.go new file mode 100644 index 0000000..6e581a9 --- /dev/null +++ b/deploy/rig-operator/test/e2e/e2e_test.go @@ -0,0 +1,337 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "vanderlande.com/ittp/appstack/rig-operator/test/utils" +) + +// namespace where the project is deployed in +const namespace = "deploy-system" + +// serviceAccountName created for the project +const serviceAccountName = "deploy-controller-manager" + +// metricsServiceName is the name of the metrics service of the project +const metricsServiceName = "deploy-controller-manager-metrics-service" + +// metricsRoleBindingName is the name of the RBAC that will be created to allow get the metrics data +const metricsRoleBindingName = "deploy-metrics-binding" + +var _ = Describe("Manager", Ordered, func() { + var controllerPodName string + + // Before running the tests, set up the environment by creating the namespace, + // enforce the restricted security policy to the namespace, installing CRDs, + // and deploying the controller. + BeforeAll(func() { + By("creating manager namespace") + cmd := exec.Command("kubectl", "create", "ns", namespace) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create namespace") + + By("labeling the namespace to enforce the restricted security policy") + cmd = exec.Command("kubectl", "label", "--overwrite", "ns", namespace, + "pod-security.kubernetes.io/enforce=restricted") + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to label namespace with restricted policy") + + By("installing CRDs") + cmd = exec.Command("make", "install") + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to install CRDs") + + By("deploying the controller-manager") + cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectImage)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager") + }) + + // After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs, + // and deleting the namespace. + AfterAll(func() { + By("cleaning up the curl pod for metrics") + cmd := exec.Command("kubectl", "delete", "pod", "curl-metrics", "-n", namespace) + _, _ = utils.Run(cmd) + + By("undeploying the controller-manager") + cmd = exec.Command("make", "undeploy") + _, _ = utils.Run(cmd) + + By("uninstalling CRDs") + cmd = exec.Command("make", "uninstall") + _, _ = utils.Run(cmd) + + By("removing manager namespace") + cmd = exec.Command("kubectl", "delete", "ns", namespace) + _, _ = utils.Run(cmd) + }) + + // After each test, check for failures and collect logs, events, + // and pod descriptions for debugging. + AfterEach(func() { + specReport := CurrentSpecReport() + if specReport.Failed() { + By("Fetching controller manager pod logs") + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + controllerLogs, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Controller logs:\n %s", controllerLogs) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get Controller logs: %s", err) + } + + By("Fetching Kubernetes events") + cmd = exec.Command("kubectl", "get", "events", "-n", namespace, "--sort-by=.lastTimestamp") + eventsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Kubernetes events:\n%s", eventsOutput) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get Kubernetes events: %s", err) + } + + By("Fetching curl-metrics logs") + cmd = exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + metricsOutput, err := utils.Run(cmd) + if err == nil { + _, _ = fmt.Fprintf(GinkgoWriter, "Metrics logs:\n %s", metricsOutput) + } else { + _, _ = fmt.Fprintf(GinkgoWriter, "Failed to get curl-metrics logs: %s", err) + } + + By("Fetching controller manager pod description") + cmd = exec.Command("kubectl", "describe", "pod", controllerPodName, "-n", namespace) + podDescription, err := utils.Run(cmd) + if err == nil { + fmt.Println("Pod description:\n", podDescription) + } else { + fmt.Println("Failed to describe controller pod") + } + } + }) + + SetDefaultEventuallyTimeout(2 * time.Minute) + SetDefaultEventuallyPollingInterval(time.Second) + + Context("Manager", func() { + It("should run successfully", func() { + By("validating that the controller-manager pod is running as expected") + verifyControllerUp := func(g Gomega) { + // Get the name of the controller-manager pod + cmd := exec.Command("kubectl", "get", + "pods", "-l", "control-plane=controller-manager", + "-o", "go-template={{ range .items }}"+ + "{{ if not .metadata.deletionTimestamp }}"+ + "{{ .metadata.name }}"+ + "{{ \"\\n\" }}{{ end }}{{ end }}", + "-n", namespace, + ) + + podOutput, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred(), "Failed to retrieve controller-manager pod information") + podNames := utils.GetNonEmptyLines(podOutput) + g.Expect(podNames).To(HaveLen(1), "expected 1 controller pod running") + controllerPodName = podNames[0] + g.Expect(controllerPodName).To(ContainSubstring("controller-manager")) + + // Validate the pod's status + cmd = exec.Command("kubectl", "get", + "pods", controllerPodName, "-o", "jsonpath={.status.phase}", + "-n", namespace, + ) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Running"), "Incorrect controller-manager pod status") + } + Eventually(verifyControllerUp).Should(Succeed()) + }) + + It("should ensure the metrics endpoint is serving metrics", func() { + By("creating a ClusterRoleBinding for the service account to allow access to metrics") + cmd := exec.Command("kubectl", "create", "clusterrolebinding", metricsRoleBindingName, + "--clusterrole=deploy-metrics-reader", + fmt.Sprintf("--serviceaccount=%s:%s", namespace, serviceAccountName), + ) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create ClusterRoleBinding") + + By("validating that the metrics service is available") + cmd = exec.Command("kubectl", "get", "service", metricsServiceName, "-n", namespace) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Metrics service should exist") + + By("getting the service account token") + token, err := serviceAccountToken() + Expect(err).NotTo(HaveOccurred()) + Expect(token).NotTo(BeEmpty()) + + By("ensuring the controller pod is ready") + verifyControllerPodReady := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pod", controllerPodName, "-n", namespace, + "-o", "jsonpath={.status.conditions[?(@.type=='Ready')].status}") + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("True"), "Controller pod not ready") + } + Eventually(verifyControllerPodReady, 3*time.Minute, time.Second).Should(Succeed()) + + By("verifying that the controller manager is serving the metrics server") + verifyMetricsServerStarted := func(g Gomega) { + cmd := exec.Command("kubectl", "logs", controllerPodName, "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(ContainSubstring("Serving metrics server"), + "Metrics server not yet started") + } + Eventually(verifyMetricsServerStarted, 3*time.Minute, time.Second).Should(Succeed()) + + // +kubebuilder:scaffold:e2e-metrics-webhooks-readiness + + By("creating the curl-metrics pod to access the metrics endpoint") + cmd = exec.Command("kubectl", "run", "curl-metrics", "--restart=Never", + "--namespace", namespace, + "--image=curlimages/curl:latest", + "--overrides", + fmt.Sprintf(`{ + "spec": { + "containers": [{ + "name": "curl", + "image": "curlimages/curl:latest", + "command": ["/bin/sh", "-c"], + "args": ["curl -v -k -H 'Authorization: Bearer %s' https://%s.%s.svc.cluster.local:8443/metrics"], + "securityContext": { + "readOnlyRootFilesystem": true, + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": ["ALL"] + }, + "runAsNonRoot": true, + "runAsUser": 1000, + "seccompProfile": { + "type": "RuntimeDefault" + } + } + }], + "serviceAccountName": "%s" + } + }`, token, metricsServiceName, namespace, serviceAccountName)) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred(), "Failed to create curl-metrics pod") + + By("waiting for the curl-metrics pod to complete.") + verifyCurlUp := func(g Gomega) { + cmd := exec.Command("kubectl", "get", "pods", "curl-metrics", + "-o", "jsonpath={.status.phase}", + "-n", namespace) + output, err := utils.Run(cmd) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(output).To(Equal("Succeeded"), "curl pod in wrong status") + } + Eventually(verifyCurlUp, 5*time.Minute).Should(Succeed()) + + By("getting the metrics by checking curl-metrics logs") + verifyMetricsAvailable := func(g Gomega) { + metricsOutput, err := getMetricsOutput() + g.Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + g.Expect(metricsOutput).NotTo(BeEmpty()) + g.Expect(metricsOutput).To(ContainSubstring("< HTTP/1.1 200 OK")) + } + Eventually(verifyMetricsAvailable, 2*time.Minute).Should(Succeed()) + }) + + // +kubebuilder:scaffold:e2e-webhooks-checks + + // TODO: Customize the e2e test suite with scenarios specific to your project. + // Consider applying sample/CR(s) and check their status and/or verifying + // the reconciliation by using the metrics, i.e.: + // metricsOutput, err := getMetricsOutput() + // Expect(err).NotTo(HaveOccurred(), "Failed to retrieve logs from curl pod") + // Expect(metricsOutput).To(ContainSubstring( + // fmt.Sprintf(`controller_runtime_reconcile_total{controller="%s",result="success"} 1`, + // strings.ToLower(), + // )) + }) +}) + +// serviceAccountToken returns a token for the specified service account in the given namespace. +// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request +// and parsing the resulting token from the API response. +func serviceAccountToken() (string, error) { + const tokenRequestRawString = `{ + "apiVersion": "authentication.k8s.io/v1", + "kind": "TokenRequest" + }` + + // Temporary file to store the token request + secretName := fmt.Sprintf("%s-token-request", serviceAccountName) + tokenRequestFile := filepath.Join("/tmp", secretName) + err := os.WriteFile(tokenRequestFile, []byte(tokenRequestRawString), os.FileMode(0o644)) + if err != nil { + return "", err + } + + var out string + verifyTokenCreation := func(g Gomega) { + // Execute kubectl command to create the token + cmd := exec.Command("kubectl", "create", "--raw", fmt.Sprintf( + "/api/v1/namespaces/%s/serviceaccounts/%s/token", + namespace, + serviceAccountName, + ), "-f", tokenRequestFile) + + output, err := cmd.CombinedOutput() + g.Expect(err).NotTo(HaveOccurred()) + + // Parse the JSON output to extract the token + var token tokenRequest + err = json.Unmarshal(output, &token) + g.Expect(err).NotTo(HaveOccurred()) + + out = token.Status.Token + } + Eventually(verifyTokenCreation).Should(Succeed()) + + return out, err +} + +// getMetricsOutput retrieves and returns the logs from the curl pod used to access the metrics endpoint. +func getMetricsOutput() (string, error) { + By("getting the curl-metrics logs") + cmd := exec.Command("kubectl", "logs", "curl-metrics", "-n", namespace) + return utils.Run(cmd) +} + +// tokenRequest is a simplified representation of the Kubernetes TokenRequest API response, +// containing only the token field that we need to extract. +type tokenRequest struct { + Status struct { + Token string `json:"token"` + } `json:"status"` +} diff --git a/deploy/rig-operator/test/utils/utils.go b/deploy/rig-operator/test/utils/utils.go new file mode 100644 index 0000000..495bc7f --- /dev/null +++ b/deploy/rig-operator/test/utils/utils.go @@ -0,0 +1,226 @@ +/* +Copyright 2026. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "bufio" + "bytes" + "fmt" + "os" + "os/exec" + "strings" + + . "github.com/onsi/ginkgo/v2" // nolint:revive,staticcheck +) + +const ( + certmanagerVersion = "v1.19.1" + certmanagerURLTmpl = "https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml" + + defaultKindBinary = "kind" + defaultKindCluster = "kind" +) + +func warnError(err error) { + _, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) +} + +// Run executes the provided command within this context +func Run(cmd *exec.Cmd) (string, error) { + dir, _ := GetProjectDir() + cmd.Dir = dir + + if err := os.Chdir(cmd.Dir); err != nil { + _, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %q\n", err) + } + + cmd.Env = append(os.Environ(), "GO111MODULE=on") + command := strings.Join(cmd.Args, " ") + _, _ = fmt.Fprintf(GinkgoWriter, "running: %q\n", command) + output, err := cmd.CombinedOutput() + if err != nil { + return string(output), fmt.Errorf("%q failed with error %q: %w", command, string(output), err) + } + + return string(output), nil +} + +// UninstallCertManager uninstalls the cert manager +func UninstallCertManager() { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "delete", "-f", url) + if _, err := Run(cmd); err != nil { + warnError(err) + } + + // Delete leftover leases in kube-system (not cleaned by default) + kubeSystemLeases := []string{ + "cert-manager-cainjector-leader-election", + "cert-manager-controller", + } + for _, lease := range kubeSystemLeases { + cmd = exec.Command("kubectl", "delete", "lease", lease, + "-n", "kube-system", "--ignore-not-found", "--force", "--grace-period=0") + if _, err := Run(cmd); err != nil { + warnError(err) + } + } +} + +// InstallCertManager installs the cert manager bundle. +func InstallCertManager() error { + url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) + cmd := exec.Command("kubectl", "apply", "-f", url) + if _, err := Run(cmd); err != nil { + return err + } + // Wait for cert-manager-webhook to be ready, which can take time if cert-manager + // was re-installed after uninstalling on a cluster. + cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook", + "--for", "condition=Available", + "--namespace", "cert-manager", + "--timeout", "5m", + ) + + _, err := Run(cmd) + return err +} + +// IsCertManagerCRDsInstalled checks if any Cert Manager CRDs are installed +// by verifying the existence of key CRDs related to Cert Manager. +func IsCertManagerCRDsInstalled() bool { + // List of common Cert Manager CRDs + certManagerCRDs := []string{ + "certificates.cert-manager.io", + "issuers.cert-manager.io", + "clusterissuers.cert-manager.io", + "certificaterequests.cert-manager.io", + "orders.acme.cert-manager.io", + "challenges.acme.cert-manager.io", + } + + // Execute the kubectl command to get all CRDs + cmd := exec.Command("kubectl", "get", "crds") + output, err := Run(cmd) + if err != nil { + return false + } + + // Check if any of the Cert Manager CRDs are present + crdList := GetNonEmptyLines(output) + for _, crd := range certManagerCRDs { + for _, line := range crdList { + if strings.Contains(line, crd) { + return true + } + } + } + + return false +} + +// LoadImageToKindClusterWithName loads a local docker image to the kind cluster +func LoadImageToKindClusterWithName(name string) error { + cluster := defaultKindCluster + if v, ok := os.LookupEnv("KIND_CLUSTER"); ok { + cluster = v + } + kindOptions := []string{"load", "docker-image", name, "--name", cluster} + kindBinary := defaultKindBinary + if v, ok := os.LookupEnv("KIND"); ok { + kindBinary = v + } + cmd := exec.Command(kindBinary, kindOptions...) + _, err := Run(cmd) + return err +} + +// GetNonEmptyLines converts given command output string into individual objects +// according to line breakers, and ignores the empty elements in it. +func GetNonEmptyLines(output string) []string { + var res []string + elements := strings.Split(output, "\n") + for _, element := range elements { + if element != "" { + res = append(res, element) + } + } + + return res +} + +// GetProjectDir will return the directory where the project is +func GetProjectDir() (string, error) { + wd, err := os.Getwd() + if err != nil { + return wd, fmt.Errorf("failed to get current working directory: %w", err) + } + wd = strings.ReplaceAll(wd, "/test/e2e", "") + return wd, nil +} + +// UncommentCode searches for target in the file and remove the comment prefix +// of the target content. The target content may span multiple lines. +func UncommentCode(filename, target, prefix string) error { + // false positive + // nolint:gosec + content, err := os.ReadFile(filename) + if err != nil { + return fmt.Errorf("failed to read file %q: %w", filename, err) + } + strContent := string(content) + + idx := strings.Index(strContent, target) + if idx < 0 { + return fmt.Errorf("unable to find the code %q to be uncomment", target) + } + + out := new(bytes.Buffer) + _, err = out.Write(content[:idx]) + if err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + + scanner := bufio.NewScanner(bytes.NewBufferString(target)) + if !scanner.Scan() { + return nil + } + for { + if _, err = out.WriteString(strings.TrimPrefix(scanner.Text(), prefix)); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + // Avoid writing a newline in case the previous line was the last in target. + if !scanner.Scan() { + break + } + if _, err = out.WriteString("\n"); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + } + + if _, err = out.Write(content[idx+len(target):]); err != nil { + return fmt.Errorf("failed to write to output: %w", err) + } + + // false positive + // nolint:gosec + if err = os.WriteFile(filename, out.Bytes(), 0644); err != nil { + return fmt.Errorf("failed to write file %q: %w", filename, err) + } + + return nil +} diff --git a/docs/TEST.md b/docs/TEST.md new file mode 100644 index 0000000..9f0ae2f --- /dev/null +++ b/docs/TEST.md @@ -0,0 +1,9 @@ + + + + +# {{ release_version }} - TEST + +TEST123 - TEST123 + +--- IT WILL BE REMOVED BEFORE MAIN MERGE --- diff --git a/docs/_changelog.md b/docs/_changelog.md new file mode 100644 index 0000000..499c2bb --- /dev/null +++ b/docs/_changelog.md @@ -0,0 +1,9 @@ + + + + +# {{ release_version }} - Changelog + + + +