Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions components/site-workflows/sensors/sensor-nova-oslo-event.yaml
Original file line number Diff line number Diff line change
@@ -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"
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,53 @@ def create_volume_connector(conn: Connection, event: IronicProvisionSetEvent):

def instance_nqn(instance_id: str | None) -> str:
return f"nqn.2014-08.org.nvmexpress:uuid:{instance_id}"


def handle_instance_delete(_conn: Connection, _: Nautobot, event_data: dict) -> int:
"""DEPRECATED: This handler is no longer used.

Instance delete events are now handled directly by the sensor using data filters.
See: components/site-workflows/sensors/sensor-nova-oslo-event.yaml

This function is kept for reference but should not be called.

Original purpose: Operated on a Nova instance delete event to clean up storage networking.
"""
logger.warning(
"handle_instance_delete called but is deprecated. "
"This event should be handled by the sensor directly."
)
payload = event_data.get("payload", {})
instance_uuid = payload.get("instance_id")
project_id = payload.get("tenant_id")

if not instance_uuid or not project_id:
logger.error("No instance_id found in delete event payload")
return 1

logger.info("Processing instance delete for {}, Tenant {}".format(instance_uuid, project_id))

# Get the server to find the node_uuid
try:

# Check if this server had storage enabled
if payload.metadata.get("storage") != "wanted":
logger.info("Server %s did not have storage enabled, skipping cleanup", instance_uuid)
save_output("server_storage_deleted", "False")
return 0

# Get node_uuid from the server's hypervisor_hostname or other field
# The node_uuid might be in server properties
node_uuid = payload.get("node")

logger.info("Marking server storage for deletion: instance=%s, node=%s", instance_uuid, node_uuid)
save_output("server_storage_deleted", "True")
save_output("node_uuid", str(node_uuid) if node_uuid else "unknown")
save_output("instance_uuid", str(instance_uuid))
save_output("project_id", project_id)

return 0

except Exception as e:
logger.exception("Error processing instance delete: %s", e)
return 1
3 changes: 3 additions & 0 deletions workflows/argo-events/workflowtemplates/ansible-run.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,9 @@ spec:
valueFrom:
path: /var/run/argo/output.instance_uuid
default: "undefined"
# server_storage_deleted is deprecated - now handled by sensor filters
# Kept for backward compatibility but should not be used
- name: server_storage_deleted
valueFrom:
path: /var/run/argo/output.server_storage_deleted
default: "False"
Loading