diff --git a/Makefile b/Makefile index 72d32e7..a2373a0 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,8 @@ TESTS := \ 08-bmcsettings \ 09-persistent-boot-order \ 10-bmcversion \ - 11-bmcuser + 11-bmcuser \ + 13-event-subscriptions .PHONY: help help: ## Show available targets @@ -41,6 +42,7 @@ help: ## Show available targets @echo " test/09-persistent-boot-order (persistent boot order)" @echo " test/10-bmcversion (BMCVersion, version read without upgrade)" @echo " test/11-bmcuser (BMCUser, BMC account create/rotate/delete)" + @echo " test/13-event-subscriptions (Redfish event subscriptions via metal-maintenance-operator telemetry)" @echo "" .PHONY: require-values diff --git a/README.md b/README.md index 93da324..57eb864 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,10 @@ biosVersion: "1.0.0" key: "EmailAlert.1.Address" value: "alerts@example.com" baselineValue: "compat-base@example.com" +13-event-subscriptions: + testMessageId: "TestEventId" # a MessageId your BMC accepts in SubmitTestEvent, e.g. "SYS1000" on Dell iDRAC + testSeverity: "OK" + testOriginOfCondition: "/redfish/v1/Managers/1" ``` Adjust the credentials and expectations to your respective values and point the tests to it: diff --git a/capability-matrix.md b/capability-matrix.md index f10945a..b80c7af 100644 --- a/capability-matrix.md +++ b/capability-matrix.md @@ -107,7 +107,16 @@ Which Chainsaw tests cover each capability is tracked in the [coverage document] ## [EventSubscriber](https://github.com/ironcore-dev/metal-operator/blob/4d2a4eb1a372c9a01602a5bda26f6c9489393918/bmc/bmc.go#L179) -| Capability id | `BMC` method | Level | Redfish API | Redfish request body | -|----------------------|---------------------------|:--------:|--------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------| -| `events.subscribe` | `CreateEventSubscription` | OPTIONAL | `GET` `EventService` (`ServiceEnabled`), then `POST` `EventService/Subscriptions`; read the new URI from the `Location` header | `{"Destination": "", "Protocol": "Redfish", "EventFormatType": "Event", "Context": "metal-operator"}` | -| `events.unsubscribe` | `DeleteEventSubscription` | OPTIONAL | `DELETE` the `EventDestination` URI | - | +| Capability id | `BMC` method | Level | Redfish API | Redfish request body | +|----------------------|---------------------------|:--------:|--------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| +| `events.subscribe` | `CreateEventSubscription` | OPTIONAL | `GET` `EventService` (`ServiceEnabled`, `ResourceTypes`), `POST` `EventService/Subscriptions` | `{"Destination": "", "Protocol": "Redfish", "EventFormatType": "Event", "DeliveryRetryPolicy": "RetryForever", "Context": "metal-operator"}` | +| `events.unsubscribe` | `DeleteEventSubscription` | OPTIONAL | `GET` `EventService` (`ServiceEnabled`), `GET` `EventDestination` URI, `DELETE` `EventDestination` URI | - | + +### metal-maintenance-operator telemetry +Telemetry also uses Redfish calls outside the `BMC` interface, see [`runtime.go`](https://github.com/ironcore-dev/metal-maintenance-operator/blob/0bd257d819e8cb39e59510fd39386cf2d72669bc/internal/telemetry/runtime/runtime.go) and [`events/server.go`](https://github.com/ironcore-dev/metal-maintenance-operator/blob/0bd257d819e8cb39e59510fd39386cf2d72669bc/internal/telemetry/events/server.go). + +| Capability id | Operation | Level | Redfish API | Redfish request body | +|---------------------|--------------------------|:--------:|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `events.list` | `ListEventSubscriptions` | OPTIONAL | `GET` `EventService`/`Subscriptions` | - | +| `events.test-event` | `SubmitTestEvent` | OPTIONAL | `POST` `#EventService.SubmitTestEvent` | `{"EventId": "1", "EventTimestamp": "", "MessageId": "", "Message": "", "MessageArgs": [], "Severity": "OK", "OriginOfCondition": ""}` | +| `events.delivery` | - | OPTIONAL | `POST` `Destination` | - | diff --git a/coverage.md b/coverage.md index e6d53c5..92f9c1c 100644 --- a/coverage.md +++ b/coverage.md @@ -33,6 +33,7 @@ These rows/capabilities include the following placeholders in their `test` field | `tests/10-bmcversion` | `BMC Registration`, `Discovery`, `bmc.version` | | `tests/11-bmcuser` | `BMC Registration`, `account.service`, `account.list`, `account.create-update`, `account.delete` | | `tests/12-force-power-off` | `BMC Registration`, `Discovery`, `power.off-graceful`, `power.off-force`, `power.wait-state` | +| `tests/13-event-subscriptions` | `BMC Registration`, `events.subscribe`, `events.unsubscribe`, `events.list`, `events.test-event`, `events.delivery` | ## Coverage by capability @@ -73,8 +74,11 @@ These rows/capabilities include the following placeholders in their `test` field | `account.list` | `tests/11-bmcuser` | yes | | `account.service` | `tests/11-bmcuser` | yes | | `indicator.set-led` | `tests/05-indicator-led` | yes | -| `events.subscribe` | uncovered | - | -| `events.unsubscribe` | uncovered | - | +| `events.subscribe` | `tests/13-event-subscriptions` | yes | +| `events.unsubscribe` | `tests/13-event-subscriptions` | yes | +| `events.list` | `tests/13-event-subscriptions` | yes | +| `events.test-event` | `tests/13-event-subscriptions` | yes | +| `events.delivery` | `tests/13-event-subscriptions` | yes | #### Footnotes **[0]**: The test is using the `Reset`-method of the `BMC` interface, but the result is the same capability being tested as using the `ForcePowerOff`-method. diff --git a/tests/13-event-subscriptions/chainsaw-test.yaml b/tests/13-event-subscriptions/chainsaw-test.yaml new file mode 100644 index 0000000..c648e80 --- /dev/null +++ b/tests/13-event-subscriptions/chainsaw-test.yaml @@ -0,0 +1,86 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: 13-event-subscriptions +spec: + concurrent: false + bindings: + - name: operatorNamespace + value: metal-maintenance-operator-system + - name: operatorDeployment + value: metal-maintenance-operator-controller-manager + - name: metricsService + value: metal-maintenance-operator-controller-manager-metrics-service + - name: metricsReaderRole + value: metal-maintenance-operator-metrics-reader + - name: telemetryConfigName + value: telemetry-collector-config + - name: subscriptionFinalizer + value: telemetry.metal.ironcore.dev/subscriptions + steps: + - name: register-bmc + try: + - apply: + file: ../shared/bmcsecret.yaml + - apply: + file: ../shared/bmc.yaml + cleanup: + - sleep: + duration: 10s + - delete: + timeout: 2m + ref: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: Server + labels: + metal-operator-test-framework/namespace: ($namespace) + - name: assert-bmc-enabled + try: + - assert: + resource: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: BMC + metadata: + name: (join('-', ['compatibility', $namespace])) + status: + state: Enabled + - name: subscribe + bindings: + - name: vendor + value: (x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'BMC', '', join('-', ['compatibility', $namespace])).status.manufacturer) + - name: model + value: (x_k8s_get($client, 'metal.ironcore.dev/v1alpha1', 'BMC', '', join('-', ['compatibility', $namespace])).status.model) + try: + - apply: + file: telemetry-config.yaml + # The subscription controller watches BMCs, not its ConfigMap. Touch the + # BMC so the new config is picked up without waiting for a requeue. + - patch: + resource: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: BMC + metadata: + name: (join('-', ['compatibility', $namespace])) + annotations: + metal-operator-test-framework/reconcile: subscribe + - name: unsubscribe + try: + - apply: + file: telemetry-config-baseline.yaml + - patch: + resource: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: BMC + metadata: + name: (join('-', ['compatibility', $namespace])) + annotations: + metal-operator-test-framework/reconcile: unsubscribe + # The finalizer is only released once every subscription was deleted. + - assert: + timeout: 2m + resource: + apiVersion: metal.ironcore.dev/v1alpha1 + kind: BMC + metadata: + name: (join('-', ['compatibility', $namespace])) + (contains(finalizers || `[]`, $subscriptionFinalizer)): false diff --git a/tests/13-event-subscriptions/telemetry-config-baseline.yaml b/tests/13-event-subscriptions/telemetry-config-baseline.yaml new file mode 100644 index 0000000..6dab7fc --- /dev/null +++ b/tests/13-event-subscriptions/telemetry-config-baseline.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ($telemetryConfigName) + namespace: ($operatorNamespace) +data: + config.yaml: | + apiVersion: telemetry.metal.ironcore.dev/v1alpha1 + subscriptionReconcileInterval: 10s + perBMCTimeout: 30s + eventBasedHardware: [] diff --git a/tests/13-event-subscriptions/telemetry-config.yaml b/tests/13-event-subscriptions/telemetry-config.yaml new file mode 100644 index 0000000..e31f8bf --- /dev/null +++ b/tests/13-event-subscriptions/telemetry-config.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ($telemetryConfigName) + namespace: ($operatorNamespace) +data: + config.yaml: (to_string($values | {apiVersion:'telemetry.metal.ironcore.dev/v1alpha1', subscriptionReconcileInterval:'10s', perBMCTimeout:'30s', testEventInterval:'1m', testEventTimeout:'30s', eventBasedHardware:[{vendor:$vendor, models:[$model], testMessageId:"13-event-subscriptions".testMessageId, testSeverity:"13-event-subscriptions".testSeverity, testOriginOfCondition:"13-event-subscriptions".testOriginOfCondition}]}))