diff --git a/tests/09-persistent-boot-order/boot-order-discover.yaml b/tests/09-persistent-boot-order/boot-order-discover.yaml new file mode 100644 index 0000000..1414d2b --- /dev/null +++ b/tests/09-persistent-boot-order/boot-order-discover.yaml @@ -0,0 +1,75 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: (join('-', ['compatibility', $namespace, 'boot-order'])) +data: + order: "" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: boot-order-discover + namespace: ($namespace) +rules: + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: + - (join('-', ['compatibility', $namespace, 'boot-order'])) + verbs: ["get", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: boot-order-discover + namespace: ($namespace) +subjects: + - kind: ServiceAccount + name: default + namespace: ($namespace) +roleRef: + kind: Role + name: boot-order-discover + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: boot-order-discover + namespace: ($namespace) +spec: + backoffLimit: 0 + template: + spec: + restartPolicy: Never + containers: + - name: discover + image: curlimages/curl:8.11.1 + securityContext: + runAsUser: 0 + env: + - name: URL + value: (join('', [$values.bmcScheme, '://', $values.bmcIP, ':', to_string($values.bmcPort), $systemURI, '/BootOptions'])) + - name: CREDENTIALS + value: (join(':', [$values.username, $values.password])) + - name: CONFIGMAP_NAME + value: (join('-', ['compatibility', $namespace, 'boot-order'])) + - name: POD_NAMESPACE + value: ($namespace) + command: ["/bin/sh", "-c"] + args: + - | + set -eu + apk add --no-cache jq + body=$(curl -fsS -k -u "$CREDENTIALS" "$URL") + echo "BootOptions response: $body" + order=$(printf '%s' "$body" \ + | jq -r '[.Members[]."@odata.id" | split("/") | last] | join(",")') + echo "discovered boot order: $order" + + TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + CACERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + API="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}" + curl -fsS --cacert "$CACERT" -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/merge-patch+json" \ + -X PATCH "$API/api/v1/namespaces/$POD_NAMESPACE/configmaps/$CONFIGMAP_NAME" \ + -d "{\"data\":{\"order\":\"$order\"}}" diff --git a/tests/09-persistent-boot-order/bootorder-check-job.yaml b/tests/09-persistent-boot-order/bootorder-check-job.yaml index 55dd212..d73e9ad 100644 --- a/tests/09-persistent-boot-order/bootorder-check-job.yaml +++ b/tests/09-persistent-boot-order/bootorder-check-job.yaml @@ -14,11 +14,11 @@ spec: image: curlimages/curl:8.11.1 env: - name: URL - value: (join('', [$values.bmcScheme, '://', $values.bmcIP, ':', to_string($values.bmcPort), '/redfish/v1/Systems/1'])) + value: (join('', [$values.bmcScheme, '://', $values.bmcIP, ':', to_string($values.bmcPort), $systemURI])) - name: CREDENTIALS value: (join(':', [$values.username, $values.password])) - name: ORDER - value: (join('', ['"BootOrder":["', join('","', $values.bootOrder), '"]'])) + value: (join('', ['"BootOrder":["', join('","', $discoveredBootOrder), '"]'])) command: ["/bin/sh", "-c"] args: - | diff --git a/tests/09-persistent-boot-order/chainsaw-test.yaml b/tests/09-persistent-boot-order/chainsaw-test.yaml index 423d419..8403352 100644 --- a/tests/09-persistent-boot-order/chainsaw-test.yaml +++ b/tests/09-persistent-boot-order/chainsaw-test.yaml @@ -31,7 +31,47 @@ spec: name: (join('-', ['compatibility', $namespace, 'system-0'])) status: state: Available + - name: claim-server + try: + - apply: + file: ignitionsecret.yaml + - apply: + file: serverclaim.yaml + - assert: + resource: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: Server + metadata: + name: (join('-', ['compatibility', $namespace, 'system-0'])) + status: + state: Reserved + powerState: "On" + # Fetches the current boot order directly from the BMC's redfish API. + # The Job needs to write the result into a ConfigMap for chainsaw to fetch + # later. If the script was ran by chainsaw directly, network access to the + # BMC would be necessary but is avoided by design of this framework. + - name: discover-boot-order + bindings: + - name: systemURI + value: (x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'Server', '', join('-', ['compatibility', $namespace, 'system-0'])).spec.systemURI) + try: + - apply: + file: boot-order-discover.yaml + - assert: + timeout: 2m + resource: + apiVersion: batch/v1 + kind: Job + metadata: + name: boot-order-discover + status: + (conditions[?type == 'Complete'] | [0].status): "True" + # Use the fist four elements of the fetched boot order in reverse to have a + # change in most cases. - name: patch-boot-order + bindings: + - name: discoveredBootOrder + value: (split(x_k8s_get($client, 'v1', 'ConfigMap', $namespace, join('-', ['compatibility', $namespace, 'boot-order'])).data.order, ',')) try: - patch: resource: @@ -40,20 +80,15 @@ spec: metadata: name: (join('-', ['compatibility', $namespace, 'system-0'])) spec: - bootOrder: - - name: ($values.bootOrder[0]) - device: ($values.bootOrder[0]) - priority: 1 - - name: ($values.bootOrder[1]) - device: ($values.bootOrder[1]) - priority: 2 - - name: ($values.bootOrder[2]) - device: ($values.bootOrder[2]) - priority: 3 + bootOrder: (([{name:($discoveredBootOrder[-1]),device:($discoveredBootOrder[-1]),priority:`1`},{name:($discoveredBootOrder[-2]),device:($discoveredBootOrder[-2]),priority:`2`},{name:($discoveredBootOrder[-3]),device:($discoveredBootOrder[-3]),priority:`3`}])[?device != null]) - name: assert-boot-order-on-bmc bindings: - name: jobName value: bootorder-check + - name: systemURI + value: (x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'Server', '', join('-', ['compatibility', $namespace, 'system-0'])).spec.systemURI) + - name: discoveredBootOrder + value: (map(&device, x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'Server', '', join('-', ['compatibility', $namespace, 'system-0'])).spec.bootOrder)) try: - apply: file: bootorder-check-job.yaml @@ -89,6 +124,10 @@ spec: bindings: - name: jobName value: bootorder-check-after-cycle + - name: systemURI + value: (x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'Server', '', join('-', ['compatibility', $namespace, 'system-0'])).spec.systemURI) + - name: discoveredBootOrder + value: (map(&device, x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'Server', '', join('-', ['compatibility', $namespace, 'system-0'])).spec.bootOrder)) try: - apply: file: bootorder-check-job.yaml @@ -101,3 +140,10 @@ spec: name: ($jobName) status: (conditions[?type == 'Complete'] | [0].status): "True" + - name: release-server + try: + - delete: + ref: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: ServerClaim + name: (join('-', ['compatibility', $namespace])) diff --git a/tests/09-persistent-boot-order/ignitionsecret.yaml b/tests/09-persistent-boot-order/ignitionsecret.yaml new file mode 100644 index 0000000..4adc381 --- /dev/null +++ b/tests/09-persistent-boot-order/ignitionsecret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: (join('-', ['compatibility', $namespace, 'ignition'])) +type: Opaque +stringData: + ignition: | + {"ignition":{"version":"3.4.0"}} diff --git a/tests/09-persistent-boot-order/serverclaim.yaml b/tests/09-persistent-boot-order/serverclaim.yaml new file mode 100644 index 0000000..db78851 --- /dev/null +++ b/tests/09-persistent-boot-order/serverclaim.yaml @@ -0,0 +1,11 @@ +apiVersion: metal.ironcore.dev/v1alpha1 +kind: ServerClaim +metadata: + name: (join('-', ['compatibility', $namespace])) +spec: + power: "On" + serverRef: + name: (join('-', ['compatibility', $namespace, 'system-0'])) + ignitionSecretRef: + name: (join('-', ['compatibility', $namespace, 'ignition'])) + image: ghcr.io/simontesar/metal-lab/metalprobe:main