diff --git a/app/models/manageiq/providers/openstack/network_manager/event_target_parser.rb b/app/models/manageiq/providers/openstack/network_manager/event_target_parser.rb index 7a3836e64b..a6e1768009 100644 --- a/app/models/manageiq/providers/openstack/network_manager/event_target_parser.rb +++ b/app/models/manageiq/providers/openstack/network_manager/event_target_parser.rb @@ -6,7 +6,7 @@ def initialize(ems_event) @ems_event = ems_event end - # Parses all targets present in the EmsEvent givin in the initializer + # Parses all targets present in the EmsEvent given in the initializer # @return [Array] Array of InventoryRefresh::Target objects def parse parse_ems_event_targets(ems_event) @@ -24,23 +24,23 @@ def parse_ems_event_targets(ems_event) # there's almost always a tenant id regardless of event type collect_identity_tenant_references!(target_collection) - target_type = if ems_event.event_type.start_with?("floatingip.") + target_type = case resource_type + when "floatingip" :floating_ips - elsif ems_event.event_type.start_with?("router.") + when "router" :network_routers - elsif ems_event.event_type.start_with?("port.") + when "port" :network_ports - elsif ems_event.event_type.start_with?("network.") + when "network" :cloud_networks - elsif ems_event.event_type.start_with?("subnet.") + when "subnet" :cloud_subnets - elsif ems_event.event_type.start_with?("security_group.") + when "security_group" :security_groups - elsif ems_event.event_type.start_with?("security_group_rule.") + when "security_group_rule" :firewall_rules end - resource_id = event_payload['resource_id'] if resource_id add_target(target_collection, target_type, resource_id) elsif target_type == :security_groups @@ -58,7 +58,12 @@ def parse_ems_event_targets(ems_event) end def collect_identity_tenant_references!(target_collection) - tenant_id = event_payload['tenant_id'] || event_payload['project_id'] || event_payload.fetch_path('initiator', 'project_id') + tenant_id = event_payload['tenant_id'] || + event_payload['project_id'] || + event_payload.dig(resource_type, 'tenant_id') || + event_payload.dig(resource_type, 'project_id') || + event_payload.dig('initiator', 'project_id') + add_target(target_collection, :cloud_tenants, tenant_id) if tenant_id end @@ -73,4 +78,12 @@ def add_target(target_collection, association, ref) def event_payload @event_payload ||= ManageIQ::Providers::Openstack::EventParserCommon.message_content(ems_event).fetch('payload', {}) end -end + + def resource_type + @resource_type ||= ems_event.event_type.split(".").first + end + + def resource_id + @resource_id ||= event_payload.dig(resource_type, "id") || event_payload["resource_id"] + end +end \ No newline at end of file diff --git a/spec/models/manageiq/providers/openstack/network_manager/event_target_parser_spec.rb b/spec/models/manageiq/providers/openstack/network_manager/event_target_parser_spec.rb index 5ba3652f38..ad961f5df4 100644 --- a/spec/models/manageiq/providers/openstack/network_manager/event_target_parser_spec.rb +++ b/spec/models/manageiq/providers/openstack/network_manager/event_target_parser_spec.rb @@ -13,14 +13,22 @@ oslo_message_text = "with#{"out" unless oslo_message} oslo_message" it "parses network events #{oslo_message_text}" do - payload = {"resource_id" => "network_id_test"} + payload = { + "network" => { + "id" => "network_id_test", + "name" => "test_network", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test" + } + } ems_event = create_ems_event(@manager, "network.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # network + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:cloud_networks, {:ems_ref => "network_id_test"}] ] ) @@ -28,14 +36,23 @@ end it "parses subnet events #{oslo_message_text}" do - payload = {"resource_id" => "subnet_id_test"} + payload = { + "subnet" => { + "id" => "subnet_id_test", + "name" => "test_subnet", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test", + "network_id" => "network_id_test" + } + } ems_event = create_ems_event(@manager, "subnet.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # subnet + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:cloud_subnets, {:ems_ref => "subnet_id_test"}] ] ) @@ -43,14 +60,22 @@ end it "parses router events #{oslo_message_text}" do - payload = {"resource_id" => "router_id_test"} + payload = { + "router" => { + "id" => "router_id_test", + "name" => "test_router", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test" + } + } ems_event = create_ems_event(@manager, "router.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # router + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:network_routers, {:ems_ref => "router_id_test"}] ] ) @@ -58,14 +83,23 @@ end it "parses port events #{oslo_message_text}" do - payload = {"resource_id" => "port_id_test"} + payload = { + "port" => { + "id" => "port_id_test", + "name" => "test_port", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test", + "network_id" => "network_id_test" + } + } ems_event = create_ems_event(@manager, "port.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # port + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:network_ports, {:ems_ref => "port_id_test"}] ] ) @@ -73,14 +107,22 @@ end it "parses floating ip events #{oslo_message_text}" do - payload = {"resource_id" => "floating_ip_id_test"} + payload = { + "floatingip" => { + "id" => "floating_ip_id_test", + "floating_ip_address" => "192.168.1.100", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test" + } + } ems_event = create_ems_event(@manager, "floatingip.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # floating_ip + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:floating_ips, {:ems_ref => "floating_ip_id_test"}] ] ) @@ -88,23 +130,87 @@ end it "parses security_group events #{oslo_message_text}" do - payload = {"resource_id" => "security_group_id_test"} + payload = { + "security_group" => { + "id" => "security_group_id_test", + "name" => "test_security_group", + "tenant_id" => "tenant_id_test", + "project_id" => "tenant_id_test" + } + } ems_event = create_ems_event(@manager, "security_group.create.end", oslo_message, payload) parsed_targets = described_class.new(ems_event).parse - expect(parsed_targets.size).to eq(1) + expect(parsed_targets.size).to eq(2) # security_group + tenant expect(target_references(parsed_targets)).to( match_array( [ + [:cloud_tenants, {:ems_ref => "tenant_id_test"}], [:security_groups, {:ems_ref => "security_group_id_test"}] ] ) ) end + + it "parses security_group_rule events without ID #{oslo_message_text}" do + payload = { + "security_group_rule" => { + "ethertype" => "IPv4", + "direction" => "ingress", + "security_group_id" => "security_group_id_test", + "protocol" => "tcp" + } + } + ems_event = create_ems_event(@manager, "security_group_rule.create.end", oslo_message, payload) + + parsed_targets = described_class.new(ems_event).parse + expect(parsed_targets.size).to eq(1) # firewall_rules with nil (full refresh) + expect(target_references(parsed_targets)).to( + match_array( + [ + [:firewall_rules, {:ems_ref => nil}] + ] + ) + ) + end + + it "falls back to direct resource_id field when nested structure not present #{oslo_message_text}" do + payload = {"resource_id" => "network_id_test"} + ems_event = create_ems_event(@manager, "network.create.end", oslo_message, payload) + + parsed_targets = described_class.new(ems_event).parse + expect(parsed_targets.size).to eq(1) + expect(target_references(parsed_targets)).to( + match_array( + [ + [:cloud_networks, {:ems_ref => "network_id_test"}] + ] + ) + ) + end + + it "extracts tenant_id from initiator when not in resource #{oslo_message_text}" do + payload = { + "network" => { + "id" => "network_id_test", + "name" => "test_network" + }, + "initiator" => { + "project_id" => "initiator_tenant_id" + } + } + ems_event = create_ems_event(@manager, "network.create.end", oslo_message, payload) + + parsed_targets = described_class.new(ems_event).parse + expect(parsed_targets.size).to eq(2) + expect(target_references(parsed_targets)).to( + include([:cloud_tenants, {:ems_ref => "initiator_tenant_id"}]) + ) + end end end def target_references(parsed_targets) parsed_targets.map { |x| [x.association, x.manager_ref] }.uniq end -end +end \ No newline at end of file