From 90f3401d0c7c72fa252c56306323e6af5b0657fc Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Fri, 23 Feb 2024 12:37:59 -0600 Subject: [PATCH] feat: add installation of OpenStack Ironic Create an initial configuration to install OpenStack Ironic. The PXE service right now binds to the host's network device so this configuration won't work on all systems but it's a first step in getting this deployed. --- apps/components/ironic.yaml | 16 +++ apps/components/kustomization.yaml | 1 + components/01-secrets/README.md | 38 +++++++ components/13-ironic/README.md | 81 ++++++++++++++ components/13-ironic/aio-values.yaml | 100 ++++++++++++++++++ components/13-ironic/ironic-mariadb-db.yaml | 52 +++++++++ .../13-ironic/ironic-rabbitmq-queue.yaml | 59 +++++++++++ components/13-ironic/kustomization.yaml | 7 ++ 8 files changed, 354 insertions(+) create mode 100644 apps/components/ironic.yaml create mode 100644 components/13-ironic/README.md create mode 100644 components/13-ironic/aio-values.yaml create mode 100644 components/13-ironic/ironic-mariadb-db.yaml create mode 100644 components/13-ironic/ironic-rabbitmq-queue.yaml create mode 100644 components/13-ironic/kustomization.yaml diff --git a/apps/components/ironic.yaml b/apps/components/ironic.yaml new file mode 100644 index 000000000..e2fe211f0 --- /dev/null +++ b/apps/components/ironic.yaml @@ -0,0 +1,16 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ironic +spec: + project: understack + source: + repoURL: https://github.com/rackerlabs/understack.git + path: components/13-ironic/ + targetRevision: HEAD + destination: + server: "https://kubernetes.default.svc" + namespace: openstack + syncPolicy: + automated: + selfHeal: true diff --git a/apps/components/kustomization.yaml b/apps/components/kustomization.yaml index ef47c36b4..d717c9ee1 100644 --- a/apps/components/kustomization.yaml +++ b/apps/components/kustomization.yaml @@ -15,3 +15,4 @@ resources: - keystone.yaml - argo-workflows.yaml - argo-events.yaml + - ironic.yaml diff --git a/components/01-secrets/README.md b/components/01-secrets/README.md index eb398d45a..c7f6323ca 100644 --- a/components/01-secrets/README.md +++ b/components/01-secrets/README.md @@ -121,6 +121,44 @@ for skrt in $(find . -name "secret-keystone*.yaml" -depth 1); do done ``` +## Ironic + +Generate the necessary secrets for OpenStack Ironic. + +```bash +kubectl --namespace openstack \ + create secret generic ironic-rabbitmq-password \ + --type Opaque \ + --from-literal=username="ironic" \ + --from-literal=password="$($(git rev-parse --show-toplevel)/scripts/pwgen.sh)" \ + --dry-run -o yaml > secret-ironic-rabbitmq-password.yaml +kubectl --namespace openstack \ + create secret generic ironic-db-password \ + --type Opaque \ + --from-literal=password="$($(git rev-parse --show-toplevel)/scripts/pwgen.sh)" \ + --dry-run -o yaml > secret-ironic-db-password.yaml +kubectl --namespace openstack \ + create secret generic ironic-keystone-password \ + --type Opaque \ + --from-literal=username="ironic" \ + --from-literal=password="$($(git rev-parse --show-toplevel)/scripts/pwgen.sh)" \ + --dry-run -o yaml > secret-ironic-keystone-password.yaml +``` + +Now let's seal them. + +```bash +for skrt in $(find . -maxdepth 1-name "secret-ironic*.yaml"); do + encskrt=$(echo "${skrt}" | sed -e 's/secret-/components\/01-secrets\/encrypted-/') + kubeseal \ + --scope cluster-wide \ + --allow-empty-data \ + -o yaml \ + -f "${skrt}" \ + -w "${encskrt}" +done +``` + ## Generate Kustomize for the Install Now generate the kustomize for this. diff --git a/components/13-ironic/README.md b/components/13-ironic/README.md new file mode 100644 index 000000000..a9bfd888b --- /dev/null +++ b/components/13-ironic/README.md @@ -0,0 +1,81 @@ +# OpenStack Ironic + +So unfortunately OpenStack Helm doesn't publish helm charts that can be consumed like +regular helm charts. You must instead clone two of their git repos side by side and +build the dependencies manually. They additionally don't split out secrets but instead +template them into giant config files or even executable scripts that then get stored +as secrets, a clear violation of . As a result we cannot store +a declarative config of Keystone and allow users to supply their own secrets. + +Due to the above issues, for now we'll skip the ArgoCD ability for this deployment. + +## Get OpenStack Helm Ready + +You may have done this for another OpenStack component and can share the same +git clones. This assumes you're doing this from the top level of this repo. + +```bash +# clone the two repos because they reference the infra one as a relative path +# so you can't use real helm commands +git clone https://github.com/openstack/openstack-helm +git clone https://github.com/openstack/openstack-helm-infra +# update the dependencies cause we can't use real helm references +./scripts/openstack-helm-depend-sync.sh ironic +``` + +## Deploy Ironic + +NOTE: The PXE service currently has the host network devices mapped into +the container. You'll have to edit the [aio-values.yaml](./aio-values.yaml) +file in the `network.pxe.device` field to the correct value for your +server to have this start up successfully. + +Since we cannot refer to the secrets by name, we must look them up live from the cluster +so that we can inject them into the templated configs. Upstream should really allow +secrets to be passed by reference. As a result of this we cannot use GitOps to generate +these charts and have them applied to the cluster. + +Secrets Reference: + +- keystone-admin is the admin password for creating other users, services and endpoints. + It is used by the initialization / bootstrap jobs. +- ironic-db-password is the DB password for the ironic DB user. +- ironic-rabbitmq-password is the RabbitMQ password for the ironic user. +- ironic-keystone-password is the Keystone service account for the Ironic service, this + is created by the ks-user job using the keystone-admin credential. + +```bash +helm --namespace openstack template \ + ironic \ + ./openstack-helm/ironic/ \ + -f components/13-ironic/aio-values.yaml \ + --set endpoints.identity.auth.admin.password="$(kubectl --namespace openstack get secret keystone-admin -o jsonpath='{.data.password}' | base64 -d)" \ + --set endpoints.oslo_db.auth.ironic.password="$(kubectl --namespace openstack get secret ironic-db-password -o jsonpath='{.data.password}' | base64 -d)" \ + --set endpoints.oslo_messaging.auth.ironic.password="$(kubectl --namespace openstack get secret ironic-rabbitmq-password -o jsonpath='{.data.password}' | base64 -d)" \ + --set endpoints.identity.auth.ironic.password="$(kubeclt --namespace openstack get secret ironic-keystone-password -o jsonpath='{.data.password}' | base64 -d)" \ + --post-renderer $(git rev-parse --show-toplevel)/scripts/openstack-helm-sealed-secrets.sh \ + | kubectl -n openstack apply -f - +``` + +At this point Ironic will go through some initialization and start up. + +## Validating Ironic + +You can run an OpenStack client in the cluster to validate it is running correctly. + +```bash +# start up a pod with the client +kubectl -n openstack apply -f https://raw.githubusercontent.com/rackerlabs/genestack/main/manifests/utils/utils-openstack-client-admin.yaml +``` + +Show the driver list + +```bash +kubectl exec -it openstack-admin-client -n openstack -- openstack baremetal driver list +``` + +Show the conductor list + +```bash +kubectl exec -it openstack-admin-client -n openstack -- openstack baremetal conductor list +``` diff --git a/components/13-ironic/aio-values.yaml b/components/13-ironic/aio-values.yaml new file mode 100644 index 000000000..8b2d45710 --- /dev/null +++ b/components/13-ironic/aio-values.yaml @@ -0,0 +1,100 @@ +--- + +images: + tags: + ironic_manage_cleaning_network: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + ironic_retrive_cleaning_network: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + ironic_retrive_swift_config: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + bootstrap: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + db_init: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + db_drop: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + ironic_db_sync: "docker.io/openstackhelm/ironic:2023.1-ubuntu_jammy" + ironic_api: "docker.io/openstackhelm/ironic:2023.1-ubuntu_jammy" + ironic_conductor: "docker.io/openstackhelm/ironic:2023.1-ubuntu_jammy" + ironic_pxe: "docker.io/openstackhelm/ironic:2023.1-ubuntu_jammy" + ironic_pxe_init: "docker.io/openstackhelm/ironic:2023.1-ubuntu_jammy" + ironic_pxe_http: docker.io/nginx:1.13.3 + ks_user: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + ks_service: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + ks_endpoints: "docker.io/openstackhelm/heat:2023.1-ubuntu_jammy" + rabbit_init: docker.io/rabbitmq:3.7-management + dep_check: quay.io/airshipit/kubernetes-entrypoint:v1.0.0 + image_repo_sync: docker.io/docker:17.07.0 + pull_policy: "IfNotPresent" + local_registry: + active: false + exclude: + - dep_check + - image_repo_sync + +bootstrap: + image: + enabled: false + openstack: + enabled: false + network: + enabled: false + openstack: + enabled: false + object_store: + enabled: false + openstack: + enabled: false + +conf: + ironic: + conductor: + automated_clean: false + dhcp: + dhcp_provider: none + +network: + api: + ingress: + public: true + classes: + namespace: "nginx" + cluster: "nginx-openstack" + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + external_policy_local: false + node_port: + enabled: false + pxe: + device: ens1f0 + +dependencies: + dynamic: + common: + local_image_registry: + jobs: null + static: + api: + jobs: + - ironic-db-sync + - ironic-ks-user + - ironic-ks-endpoints + services: + - endpoint: internal + service: oslo_db + - endpoint: internal + service: oslo_messaging + conductor: + jobs: + - ironic-db-sync + - ironic-ks-user + - ironic-ks-endpoints + services: + - endpoint: internal + service: oslo_db + - endpoint: internal + service: oslo_messaging + +manifests: + job_db_init: false + job_db_drop: false + job_manage_cleaning_network: false + job_rabbit_init: false + secret_db: false + secret_rabbitmq: false + secret_registry: false diff --git a/components/13-ironic/ironic-mariadb-db.yaml b/components/13-ironic/ironic-mariadb-db.yaml new file mode 100644 index 000000000..92c4e7d67 --- /dev/null +++ b/components/13-ironic/ironic-mariadb-db.yaml @@ -0,0 +1,52 @@ +--- +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: Database +metadata: + name: ironic + namespace: openstack +spec: + # If you want the database to be created with a different name than the resource name + # name: data-custom + mariaDbRef: + name: mariadb # name of the MariaDB kind + waitForIt: true + characterSet: utf8 + collate: utf8_general_ci + retryInterval: 5s +--- +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: User +metadata: + name: ironic + namespace: openstack +spec: + # If you want the user to be created with a different name than the resource name + # name: user-custom + mariaDbRef: + name: mariadb # name of the MariaDB kind + waitForIt: true + passwordSecretKeyRef: + name: ironic-db-password + key: password + # This field is immutable and defaults to 10, 0 means unlimited. + maxUserConnections: 0 + host: "%" + retryInterval: 5s +--- +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: Grant +metadata: + name: ironic-grant + namespace: openstack +spec: + mariaDbRef: + name: mariadb # name of the MariaDB kind + waitForIt: true + privileges: + - "ALL" + database: "ironic" + table: "*" + username: ironic + grantOption: true + host: "%" + retryInterval: 5s diff --git a/components/13-ironic/ironic-rabbitmq-queue.yaml b/components/13-ironic/ironic-rabbitmq-queue.yaml new file mode 100644 index 000000000..d85c50802 --- /dev/null +++ b/components/13-ironic/ironic-rabbitmq-queue.yaml @@ -0,0 +1,59 @@ +--- +apiVersion: rabbitmq.com/v1beta1 +kind: User +metadata: + name: ironic + namespace: openstack +spec: + tags: + - management # available tags are 'management', 'policymaker', 'monitoring' and 'administrator' + - policymaker + rabbitmqClusterReference: + name: rabbitmq # rabbitmqCluster must exist in the same namespace as this resource + namespace: openstack + importCredentialsSecret: + name: ironic-rabbitmq-password +--- +apiVersion: rabbitmq.com/v1beta1 +kind: Vhost +metadata: + name: ironic-vhost + namespace: openstack +spec: + name: "ironic" # vhost name; required and cannot be updated + defaultQueueType: quorum # default queue type for this vhost; require RabbitMQ version 3.11.12 or above + rabbitmqClusterReference: + name: rabbitmq # rabbitmqCluster must exist in the same namespace as this resource + namespace: openstack +--- +apiVersion: rabbitmq.com/v1beta1 +kind: Queue +metadata: + name: ironic-queue + namespace: openstack +spec: + name: ironic-qq # name of the queue + vhost: "ironic" # default to '/' if not provided + type: quorum # without providing a queue type, rabbitmq creates a classic queue + autoDelete: false + durable: true # seting 'durable' to false means this queue won't survive a server restart + rabbitmqClusterReference: + name: rabbitmq # rabbitmqCluster must exist in the same namespace as this resource + namespace: openstack +--- +apiVersion: rabbitmq.com/v1beta1 +kind: Permission +metadata: + name: ironic-permission + namespace: openstack +spec: + vhost: "ironic" # name of a vhost + userReference: + name: "ironic" # name of a user.rabbitmq.com in the same namespace; must specify either spec.userReference or spec.user + permissions: + write: ".*" + configure: ".*" + read: ".*" + rabbitmqClusterReference: + name: rabbitmq # rabbitmqCluster must exist in the same namespace as this resource + namespace: openstack diff --git a/components/13-ironic/kustomization.yaml b/components/13-ironic/kustomization.yaml new file mode 100644 index 000000000..f38634783 --- /dev/null +++ b/components/13-ironic/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ironic-mariadb-db.yaml + - ironic-rabbitmq-queue.yaml