diff --git a/components/site-workflows/eventsources/eventsource-openstack-nova.yaml b/components/site-workflows/eventsources/eventsource-openstack-nova.yaml new file mode 100644 index 000000000..3942f46ec --- /dev/null +++ b/components/site-workflows/eventsources/eventsource-openstack-nova.yaml @@ -0,0 +1,36 @@ +apiVersion: argoproj.io/v1alpha1 +kind: EventSource +metadata: + name: openstack-nova +spec: + amqp: + # this is our eventName + openstack: + # amqp server url + url: amqp://rabbitmq-server-0.rabbitmq-nodes.openstack.svc.cluster.local:5672/nova + # jsonBody specifies that all event body payload coming from this + # source will be JSON + jsonBody: true + # name of the exchange. + exchangeName: nova + exchangeType: topic + exchangeDeclare: + durable: false + # routing key for messages within the exchange + routingKey: 'notifications.info' + # optional consume settings + # if not provided, default values will be used + consume: + consumerTag: "argo-events" + autoAck: true + exclusive: false + noLocal: false + # username and password for authentication + # use secret selectors + auth: + username: + name: argo-nova-user-credentials + key: username + password: + name: argo-nova-user-credentials + key: password diff --git a/components/site-workflows/eventsources/rabbitmq-user-argo-nova.yaml b/components/site-workflows/eventsources/rabbitmq-user-argo-nova.yaml new file mode 100644 index 000000000..fb8be5818 --- /dev/null +++ b/components/site-workflows/eventsources/rabbitmq-user-argo-nova.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: rabbitmq.com/v1beta1 +kind: User +metadata: + name: argo-nova +spec: + rabbitmqClusterReference: + name: rabbitmq # rabbitmqCluster must exist in the same namespace as this resource + namespace: openstack +--- +apiVersion: rabbitmq.com/v1beta1 +kind: Permission +metadata: + name: argo-nova +spec: + vhost: "nova" + userReference: + name: "argo-nova" # 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/site-workflows/kustomization.yaml b/components/site-workflows/kustomization.yaml index fd4605e00..fd959a51e 100644 --- a/components/site-workflows/kustomization.yaml +++ b/components/site-workflows/kustomization.yaml @@ -5,9 +5,11 @@ resources: - eventbus/eventbus-default.yaml - eventbus/poddisruptionbudget-eventbus-default-pdb.yaml - eventsources/eventsource-openstack-ironic.yaml + - eventsources/eventsource-openstack-nova.yaml - eventsources/eventsource-openstack-keystone.yaml - eventsources/eventsource-openstack-neutron.yaml - eventsources/rabbitmq-user-argo-ironic.yaml + - eventsources/rabbitmq-user-argo-nova.yaml - eventsources/rabbitmq-user-argo-keystone.yaml - eventsources/rabbitmq-user-argo-neutron.yaml - eventsources/eventsource-k8s-openstack-secrets.yaml @@ -24,6 +26,7 @@ resources: - sensors/sensor-ironic-node-port.yaml - sensors/sensor-ironic-node-portgroup.yaml - sensors/sensor-ironic-oslo-event.yaml + - sensors/sensor-nova-oslo-event.yaml helmCharts: - name: nautobot-token diff --git a/components/site-workflows/sensors/sensor-nova-oslo-event.yaml b/components/site-workflows/sensors/sensor-nova-oslo-event.yaml new file mode 100644 index 000000000..f4058b7c1 --- /dev/null +++ b/components/site-workflows/sensors/sensor-nova-oslo-event.yaml @@ -0,0 +1,93 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Sensor +metadata: + name: nova-oslo-event + annotations: + workflows.argoproj.io/title: Process oslo_events for nova compute + workflows.argoproj.io/description: |+ + Triggers on the following Nova Events: + + - compute.instance.delete.end which happens when a server is deleted + AND the server has metadata.storage == "wanted" + + This sensor uses data filters to check the storage metadata and directly + triggers the ansible playbook without requiring a Python handler. + + The sensor extracts the following parameters from the event: + - device_id: from payload.node (the Ironic node UUID) + - project_id: from payload.tenant_id (UUID without dashes) + + These are passed directly to the storage_on_server_delete.yml ansible playbook. + + Defined in `components/site-workflows/sensors/sensor-nova-oslo-event.yaml` +spec: + dependencies: + - eventName: notifications + eventSourceName: openstack-nova + name: nova-dep + transform: + # the event is a string-ified JSON so we need to decode it + # replace the whole event body + jq: | + .body = (.body["oslo.message"] | fromjson) + filters: + # applies each of the items in data with 'and' + dataLogicalOperator: "and" + data: + - path: "body.event_type" + type: "string" + value: + - "compute.instance.delete.end" + # Only process if storage was wanted +# - path: "body.payload.metadata.storage" +# type: "string" +# value: +# - "wanted" + template: + serviceAccountName: sensor-submit-workflow + triggers: + - template: + name: nova-instance-delete + k8s: + operation: create + parameters: + - dest: spec.arguments.parameters.0.value + src: + dataKey: body.payload.node + dependencyName: nova-dep + - dest: spec.arguments.parameters.1.value + src: + dataKey: body.payload.tenant_id + dependencyName: nova-dep + source: + # create a workflow in argo-events prefixed with nova-delete- + resource: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + generateName: nova-delete- + namespace: argo-events + spec: + serviceAccountName: workflow + entrypoint: main + # defines the parameters extracted from the event + arguments: + parameters: + - name: device_id + - name: project_id + templates: + - name: main + steps: + - - name: ansible-delete-server-storage + templateRef: + name: ansible-workflow-template + template: ansible-run + arguments: + parameters: + - name: playbook + value: storage_on_server_delete.yml + - name: extra_vars + value: device_id={{workflow.parameters.device_id}} project_id={{workflow.parameters.project_id}} + - name: check_mode + value: "false" diff --git a/python/understack-workflows/understack_workflows/main/openstack_oslo_event.py b/python/understack-workflows/understack_workflows/main/openstack_oslo_event.py index 2ef7946ea..5d1bb9ec1 100644 --- a/python/understack-workflows/understack_workflows/main/openstack_oslo_event.py +++ b/python/understack-workflows/understack_workflows/main/openstack_oslo_event.py @@ -78,6 +78,8 @@ class NoEventHandlerError(Exception): ironic_node.handle_provision_end, nautobot_device_sync.handle_node_event, ], + # "compute.instance.delete.end" is now handled directly by the sensor with filters + # See: components/site-workflows/sensors/sensor-nova-oslo-event.yaml "identity.project.created": keystone_project.handle_project_created, "identity.project.updated": keystone_project.handle_project_updated, "identity.project.deleted": keystone_project.handle_project_deleted, diff --git a/workflows/argo-events/workflowtemplates/ansible-run.yaml b/workflows/argo-events/workflowtemplates/ansible-run.yaml index 53ff28f08..5746078c8 100644 --- a/workflows/argo-events/workflowtemplates/ansible-run.yaml +++ b/workflows/argo-events/workflowtemplates/ansible-run.yaml @@ -19,6 +19,8 @@ spec: default: "var=default" - name: inventory_file default: inventory/in-cluster/01-nautobot.yaml + - name: check_mode + default: "false" container: image: ghcr.io/rss-engineering/undercloud-nautobot/ansible:latest command: [ansible-playbook] @@ -29,6 +31,7 @@ spec: - "-i" - "{{ inputs.parameters.inventory_file }}" - "-vvv" + - "{{- if eq inputs.parameters.check_mode \"true\" }}--check{{- end }}" env: - name: NAUTOBOT_TOKEN valueFrom: