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..a44a6c178 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 . -name "secret-ironic*.yaml" -depth 1); 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..32c3e4361 --- /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 injected 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