diff --git a/app/models/manageiq/providers/amazon/builder.rb b/app/models/manageiq/providers/amazon/builder.rb index bc6db0043..f9aec6709 100644 --- a/app/models/manageiq/providers/amazon/builder.rb +++ b/app/models/manageiq/providers/amazon/builder.rb @@ -28,7 +28,7 @@ def build_inventory(ems, target) ManageIQ::Providers::Amazon::Inventory::Persister::StorageManager::S3, [ManageIQ::Providers::Amazon::Inventory::Parser::StorageManager::S3] ) - when ManageIQ::Providers::Amazon::TargetCollection + when ManagerRefresh::TargetCollection inventory( ems, target, diff --git a/app/models/manageiq/providers/amazon/cloud_manager/event_target_parser.rb b/app/models/manageiq/providers/amazon/cloud_manager/event_target_parser.rb new file mode 100644 index 000000000..62a9a262d --- /dev/null +++ b/app/models/manageiq/providers/amazon/cloud_manager/event_target_parser.rb @@ -0,0 +1,122 @@ +class ManageIQ::Providers::Amazon::CloudManager::EventTargetParser + attr_reader :ems_event + + # @param ems_event [EmsEvent] EmsEvent object + def initialize(ems_event) + @ems_event = ems_event + end + + # Parses all targets that are present in the EmsEvent given in the initializer + # + # @return [Array] Array of ManagerRefresh::Target objects + def parse + parse_ems_event_targets(ems_event) + end + + private + + # Parses list of ManagerRefresh::Target out of the given EmsEvent + # + # @param event [EmsEvent] EmsEvent object + # @return [Array] Array of ManagerRefresh::Target objects + def parse_ems_event_targets(event) + target_collection = ManagerRefresh::TargetCollection.new(:manager => event.ext_management_system, :event => event) + + case event.full_data["event_source"] + when :cloud_watch_api + collect_cloudwatch_api_references!(target_collection, + event.full_data.fetch_path("detail", "requestParameters") || {}) + collect_cloudwatch_api_references!(target_collection, + event.full_data.fetch_path("detail", "responseElements") || {}) + when :cloud_watch_ec2 + collect_cloudwatch_ec2_references!(target_collection, event.full_data) + when :config + collect_config_references!(target_collection, event.full_data) + end + + target_collection.targets + end + + def parsed_targets(target_collection = {}) + target_collection.select { |_target_class, references| references[:manager_ref].present? } + end + + def add_target(target_collection, association, ref) + target_collection.add_target(:association => association, :manager_ref => {:ems_ref => ref}) + end + + def collect_cloudwatch_ec2_references!(target_collection, event_data) + instance_id = event_data.fetch_path("detail", "instance-id") + add_target(target_collection, :vms, instance_id) if instance_id + end + + def collect_config_references!(target_collection, event_data) + resource_type = event_data.fetch_path("configurationItem", "resourceType") + resource_id = event_data.fetch_path("configurationItem", "resourceId") + target_class = case resource_type + when "AWS::EC2::Instance" + :vms + when "AWS::EC2::SecurityGroup" + :security_groups + when "AWS::EC2::Volume" + :cloud_volumes + when "AWS::EC2::NetworkInterface" + :network_ports + when "AWS::EC2::VPC" + :cloud_networks + when "AWS::EC2::Subnet" + :cloud_subnets + when "AWS::EC2::EIP" + :floating_ips + end + + add_target(target_collection, target_class, resource_id) if target_class && resource_id + end + + def collect_cloudwatch_api_references!(target_collection, event_data, depth = 0) + # Check a reasonable depth, so this can't fail with max stack size + raise "Depth 20 reached when scanning EmsEvent for Targets" if depth > 20 + + # Cloud + add_target(target_collection, :vms, event_data["instanceId"]) if event_data["instanceId"] + add_target(target_collection, :miq_templates, event_data["imageId"]) if event_data["imageId"] + add_target(target_collection, :key_pairs, event_data["keyName"]) if event_data["keyName"] + add_target(target_collection, :orchestration_stacks, event_data["stackId"]) if event_data["stackId"] + add_target(target_collection, :orchestration_stacks, event_data["stackName"]) if event_data["stackName"] + # Network + add_target(target_collection, :cloud_networks, event_data["vpcId"]) if event_data["vpcId"] + add_target(target_collection, :cloud_subnets, event_data["subnetId"]) if event_data["subnetId"] + add_target(target_collection, :network_ports, event_data["networkInterfaceId"]) if event_data["networkInterfaceId"] + add_target(target_collection, :security_groups, event_data["groupId"]) if event_data["groupId"] + add_target(target_collection, :floating_ips, event_data["allocationId"]) if event_data["allocationId"] + add_target(target_collection, :load_balancers, event_data["loadBalancerName"]) if event_data["loadBalancerName"] + # Block Storage + add_target(target_collection, :cloud_volumes, event_data["volumeId"]) if event_data["volumeId"] + add_target(target_collection, :cloud_volume_snapshots, event_data["snapshotId"]) if event_data["snapshotId"] + + # TODO(lsmola) how to handle tagging? Tagging affects e.g. a name of any resource, but contains only a generic + # resourceID + # "requestParameters"=> + # {"resourcesSet"=>{"items"=>[{"resourceId"=>"vol-07ad036724e3175a5"}]}, + # "tagSet"=>{"items"=>[{"key"=>"Name", "value"=>"ladas_volue_2"}]}}, + # I think we can parse the resource id, so guess where it belongs. + # TODO(lsmola) RegisterImage, by creating image from a volume snapshot, should we track the block device + # mapping and refresh also snapshot? + + # Collect nested references + collect_cloudwatch_api_references!(target_collection, event_data["networkInterface"], depth + 1) if event_data["networkInterface"] + + (event_data.fetch_path("groupSet", "items") || []).each do |x| + collect_cloudwatch_api_references!(target_collection, x, depth + 1) + end + (event_data.fetch_path("instancesSet", "items") || []).each do |x| + collect_cloudwatch_api_references!(target_collection, x, depth + 1) + end + (event_data.fetch_path("instances") || []).each do |x| + collect_cloudwatch_api_references!(target_collection, x, depth + 1) + end + (event_data.fetch_path("networkInterfaceSet", "items") || []).each do |x| + collect_cloudwatch_api_references!(target_collection, x, depth + 1) + end + end +end diff --git a/app/models/manageiq/providers/amazon/cloud_manager/refresher.rb b/app/models/manageiq/providers/amazon/cloud_manager/refresher.rb index 02d06379d..3eb397e3f 100644 --- a/app/models/manageiq/providers/amazon/cloud_manager/refresher.rb +++ b/app/models/manageiq/providers/amazon/cloud_manager/refresher.rb @@ -46,9 +46,10 @@ def preprocess_targets all_targets, sub_ems_targets = targets.partition { |x| x.kind_of?(ExtManagementSystem) } unless sub_ems_targets.blank? - ems_event_collection = ManageIQ::Providers::Amazon::TargetCollection.new(sub_ems_targets) if refresher_options.try(:[], :event_targeted_refresh) # We can disable targeted refresh with a setting, then we will just do full ems refresh on any event + ems_event_collection = ManagerRefresh::TargetCollection.new(:targets => sub_ems_targets, + :manager_id => ems_id) all_targets << ems_event_collection else all_targets << @ems_by_ems_id[ems_id] diff --git a/app/models/manageiq/providers/amazon/inventory/collector.rb b/app/models/manageiq/providers/amazon/inventory/collector.rb index 112220d3a..e0db51470 100644 --- a/app/models/manageiq/providers/amazon/inventory/collector.rb +++ b/app/models/manageiq/providers/amazon/inventory/collector.rb @@ -3,22 +3,22 @@ class ManageIQ::Providers::Amazon::Inventory::Collector < ManagerRefresh::Invent require_nested :NetworkManager require_nested :TargetCollection - attr_reader :instances, :instances_refs, :instances_deleted - attr_reader :flavors, :flavors_refs, :flavors_deleted - attr_reader :availability_zones, :availability_zones_refs, :availability_zones_deleted - attr_reader :key_pairs, :key_pairs_refs, :key_pairs_deleted - attr_reader :private_images, :private_images_refs, :private_images_deleted - attr_reader :shared_images, :shared_images_refs, :shared_images_deleted - attr_reader :public_images, :public_images_refs, :public_images_deleted - attr_reader :cloud_networks, :cloud_networks_refs, :cloud_networks_deleted - attr_reader :cloud_subnets, :cloud_subnets_refs, :cloud_subnets_deleted - attr_reader :security_groups, :security_groups_refs, :security_groups_deleted - attr_reader :floating_ips, :floating_ips_refs, :floating_ips_deleted - attr_reader :network_ports, :network_ports_refs, :network_ports_deleted - attr_reader :load_balancers, :load_balancers_refs, :load_balancers_deleted - attr_reader :stacks, :stacks_refs, :stacks_deleted - attr_reader :cloud_volumes, :cloud_volumes_refs - attr_reader :cloud_volume_snapshots, :cloud_volume_snapshots_refs + attr_reader :instances + attr_reader :flavors + attr_reader :availability_zones + attr_reader :key_pairs + attr_reader :private_images + attr_reader :shared_images + attr_reader :public_images + attr_reader :cloud_networks + attr_reader :cloud_subnets + attr_reader :security_groups + attr_reader :floating_ips + attr_reader :network_ports + attr_reader :load_balancers + attr_reader :stacks + attr_reader :cloud_volumes + attr_reader :cloud_volume_snapshots attr_reader :cloud_objects_store_containers attr_reader :cloud_objects_store_objects @@ -30,49 +30,21 @@ def initialize(_manager, _target) def initialize_inventory_sources @instances = [] - @instances_refs = Set.new - @instances_deleted = [] @flavors = [] - @flavors_refs = Set.new - @flavors_deleted = [] @availability_zones = [] - @availability_zones_refs = Set.new - @availability_zones_deleted = [] @key_pairs = [] - @key_pairs_refs = Set.new - @key_pairs_deleted = [] @private_images = [] - @private_images_refs = Set.new - @private_images_deleted = [] @shared_images = [] - @shared_images_refs = Set.new - @shared_images_deleted = [] @public_images = [] - @public_images_refs = Set.new - @public_images_deleted = [] @cloud_networks = [] - @cloud_networks_refs = Set.new - @cloud_networks_deleted = [] @cloud_subnets = [] - @cloud_subnets_refs = Set.new - @cloud_subnets_deleted = [] @security_groups = [] - @security_groups_refs = Set.new - @security_groups_deleted = [] @floating_ips = [] - @floating_ips_refs = Set.new - @floating_ips_deleted = [] @network_ports = [] - @network_ports_refs = Set.new - @network_ports_deleted = [] @load_balancers = [] - @load_balancers_refs = Set.new @stacks = [] - @stacks_refs = Set.new @cloud_volumes = [] - @cloud_volumes_refs = Set.new @cloud_volume_snapshots = [] - @cloud_volume_snapshots_refs = Set.new # Nested resources @stack_resources = {} @stack_resources_refs = {} diff --git a/app/models/manageiq/providers/amazon/inventory/collector/target_collection.rb b/app/models/manageiq/providers/amazon/inventory/collector/target_collection.rb index b94d76b21..0e8d8db23 100644 --- a/app/models/manageiq/providers/amazon/inventory/collector/target_collection.rb +++ b/app/models/manageiq/providers/amazon/inventory/collector/target_collection.rb @@ -3,24 +3,30 @@ def initialize(_manager, _target) super parse_targets! infer_related_ems_refs! + + target.manager_refs_by_association_reset + end + + def references(collection) + target.manager_refs_by_association.try(:[], collection).try(:[], :ems_ref).try(:to_a) || [] end def instances hash_collection.new( - aws_ec2.instances(:filters => [{:name => 'instance-id', :values => instances_refs.to_a}]) + aws_ec2.instances(:filters => [{:name => 'instance-id', :values => references(:vms)}]) ) end def private_images hash_collection.new( - aws_ec2.client.describe_images(:filters => [{:name => 'image-id', :values => private_images_refs.to_a}]).images + aws_ec2.client.describe_images(:filters => [{:name => 'image-id', :values => references(:miq_templates)}]).images ) end def stacks # TODO(lsmola) we can filter only one stack, so that means too many requests, lets try to figure out why # CLoudFormations API doesn't support a standard filter - result = stacks_refs.to_a.map do |stack_ref| + result = references(:orchestrations_stacks).map do |stack_ref| begin aws_cloud_formation.client.describe_stacks(:stack_name => stack_ref)[:stacks] rescue Aws::CloudFormation::Errors::ValidationError => _e @@ -33,33 +39,33 @@ def stacks def cloud_networks hash_collection.new( - aws_ec2.client.describe_vpcs(:filters => [{:name => 'vpc-id', :values => cloud_networks_refs.to_a}]).vpcs + aws_ec2.client.describe_vpcs(:filters => [{:name => 'vpc-id', :values => references(:cloud_networks)}]).vpcs ) end def cloud_subnets hash_collection.new( - aws_ec2.client.describe_subnets(:filters => [{:name => 'subnet-id', :values => cloud_subnets_refs.to_a}]).subnets + aws_ec2.client.describe_subnets(:filters => [{:name => 'subnet-id', :values => references(:cloud_subnets)}]).subnets ) end def security_groups hash_collection.new( - aws_ec2.security_groups(:filters => [{:name => 'group-id', :values => security_groups_refs.to_a}]) + aws_ec2.security_groups(:filters => [{:name => 'group-id', :values => references(:security_groups).to_a}]) ) end def network_ports hash_collection.new(aws_ec2.client.describe_network_interfaces( - :filters => [{:name => 'network-interface-id', :values => network_ports_refs.to_a}] + :filters => [{:name => 'network-interface-id', :values => references(:network_ports).to_a}] ).network_interfaces) end def load_balancers - return [] if load_balancers_refs.blank? + return [] if references(:load_balancers).blank? result = [] - load_balancers_refs.to_a.each do |load_balancers_ref| + references(:load_balancers).each do |load_balancers_ref| begin result += aws_elb.client.describe_load_balancers( :load_balancer_names => [load_balancers_ref] @@ -75,20 +81,20 @@ def load_balancers def floating_ips hash_collection.new( - aws_ec2.client.describe_addresses(:filters => [{:name => 'allocation-id', :values => floating_ips_refs.to_a}]).addresses + aws_ec2.client.describe_addresses(:filters => [{:name => 'allocation-id', :values => references(:floating_ips)}]).addresses ) end def cloud_volumes hash_collection.new( - aws_ec2.client.describe_volumes(:filters => [{:name => 'volume-id', :values => cloud_volumes_refs.to_a}]).volumes + aws_ec2.client.describe_volumes(:filters => [{:name => 'volume-id', :values => references(:cloud_volumes)}]).volumes ) end def cloud_volume_snapshots hash_collection.new( aws_ec2.client.describe_snapshots( - :filters => [{:name => 'snapshot-id', :values => cloud_volume_snapshots_refs.to_a}] + :filters => [{:name => 'snapshot-id', :values => references(:cloud_volumes_snapshots)}] ).snapshots ) end @@ -131,56 +137,15 @@ def stack_template(stack_name) def parse_targets! target.targets.each do |t| - if t.kind_of?(::EmsEvent) - parse_parse_ems_event_target!(t) - elsif t.kind_of?(::Vm) + case t + when Vm parse_vm_target!(t) end end end - def parse_parse_ems_event_target!(t) - collect_references!(t.full_data.fetch_path("detail", "requestParameters") || {}) - collect_references!(t.full_data.fetch_path("detail", "responseElements") || {}) - - instance_id = t.full_data.fetch_path("detail", "instance-id") - instances_refs << instance_id if instance_id - end - - def collect_references!(hash) - instances_refs << hash["instanceId"] if hash["instanceId"] - private_images_refs << hash["imageId"] if hash["imageId"] - key_pairs_refs << hash["keyName"] if hash["keyName"] - stacks_refs << hash["stackId"] if hash["stackId"] - stacks_refs << hash["stackName"] if hash["stackName"] - cloud_networks_refs << hash["vpcId"] if hash["vpcId"] - cloud_subnets_refs << hash["subnetId"] if hash["subnetId"] - network_ports_refs << hash["networkInterfaceId"] if hash["networkInterfaceId"] - security_groups_refs << hash["groupId"] if hash["groupId"] - floating_ips_refs << hash["allocationId"] if hash["allocationId"] - load_balancers_refs << hash["loadBalancerName"] if hash["loadBalancerName"] - cloud_volumes_refs << hash["volumeId"] if hash["volumeId"] - cloud_volume_snapshots_refs << hash["snapshotId"] if hash["snapshotId"] - - # TODO(lsmola) how to handle tagging? Tagging affects e.g. a name of any resource, but contains only a generic - # resourceID - # "requestParameters"=> - # {"resourcesSet"=>{"items"=>[{"resourceId"=>"vol-07ad036724e3175a5"}]}, - # "tagSet"=>{"items"=>[{"key"=>"Name", "value"=>"ladas_volue_2"}]}}, - # I think we can parse the resource id, so guess where it belongs. - # TODO(lsmola) RegisterImage, by creating image from a volume snapshot, should we track the block device - # mapping and refresh also snapshot? - - collect_references!(hash["networkInterface"]) if hash["networkInterface"] - - (hash.fetch_path("groupSet", "items") || []).each { |x| collect_references!(x) } - (hash.fetch_path("instancesSet", "items") || []).each { |x| collect_references!(x) } - (hash.fetch_path("instances") || []).each { |x| collect_references!(x) } - (hash.fetch_path("networkInterfaceSet", "items") || []).each { |x| collect_references!(x) } - end - def parse_vm_target!(t) - instances_refs << t.ems_ref if t.ems_ref + target.add_target(:association => :vms, :manager_ref => {:ems_ref => t.ems_ref}) if t.ems_ref end def infer_related_ems_refs! @@ -188,15 +153,27 @@ def infer_related_ems_refs! # ems_refs of every related object. Now this is not very nice fro ma design point of view, but we really want # to see changes in VM's associated objects, so the VM view is always consistent and have fresh data. The partial # reason for this is, that AWS doesn't send all the objects state change, - changed_vms = manager.vms.where(:ems_ref => instances_refs.to_a).includes(:key_pairs, :network_ports, :floating_ips, - :orchestration_stack) + changed_vms = manager.vms.where(:ems_ref => references(:vms)).includes(:key_pairs, :network_ports, :floating_ips, + :orchestration_stack) changed_vms.each do |vm| stack = vm.orchestration_stack all_stacks = ([stack] + (stack.try(:ancestors) || [])).compact - stacks_refs.merge all_stacks.collect(&:ems_ref).compact - key_pairs_refs.merge vm.key_pairs.collect(&:name).compact - network_ports_refs.merge vm.network_ports.collect(&:ems_ref).compact - floating_ips_refs.merge vm.floating_ips.collect(&:ems_ref).compact + + all_stacks.collect(&:ems_ref).compact.each do |ems_ref| + target.add_target(:association => :orchestration_stacks, :manager_ref => {:ems_ref => ems_ref}) + end + + vm.key_pairs.collect(&:name).compact.each do |ems_ref| + target.add_target(:association => :key_pairs, :manager_ref => {:ems_ref => ems_ref}) + end + + vm.network_ports.collect(&:ems_ref).compact.each do |ems_ref| + target.add_target(:association => :network_ports, :manager_ref => {:ems_ref => ems_ref}) + end + + vm.floating_ips.collect(&:ems_ref).compact.each do |ems_ref| + target.add_target(:association => :floating_ips, :manager_ref => {:ems_ref => ems_ref}) + end end end end diff --git a/app/models/manageiq/providers/amazon/inventory/persister/target_collection.rb b/app/models/manageiq/providers/amazon/inventory/persister/target_collection.rb index b3143bafa..a44eb5c92 100644 --- a/app/models/manageiq/providers/amazon/inventory/persister/target_collection.rb +++ b/app/models/manageiq/providers/amazon/inventory/persister/target_collection.rb @@ -24,6 +24,10 @@ def initialize_inventory_collections private + def references(collection) + target.manager_refs_by_association.try(:[], collection).try(:[], :ems_ref).try(:to_a) || [] + end + def cloud ManageIQ::Providers::Amazon::InventoryCollectionDefault::CloudManager end @@ -37,25 +41,23 @@ def storage end def add_targeted_inventory_collections - images_refs = collector.private_images_refs.to_a + collector.shared_images_refs.to_a + collector.public_images_refs.to_a - # Cloud - add_vms_inventory_collections(collector.instances_refs.to_a) - add_miq_templates_inventory_collections(images_refs) - add_hardwares_inventory_collections(collector.instances_refs.to_a + images_refs) - add_stacks_inventory_collections(collector.stacks_refs.to_a) + add_vms_inventory_collections(references(:vms)) + add_miq_templates_inventory_collections(references(:miq_templates)) + add_hardwares_inventory_collections(references(:vms) + references(:miq_templates)) + add_stacks_inventory_collections(references(:orchestration_stacks)) # Network - add_cloud_networks_inventory_collections(collector.cloud_networks_refs.to_a) - add_cloud_subnets_inventory_collections(collector.cloud_subnets_refs.to_a) - add_network_ports_inventory_collections(collector.instances_refs.to_a + collector.network_ports_refs.to_a) - add_security_groups_inventory_collections(collector.security_groups_refs.to_a) - add_floating_ips_inventory_collections(collector.floating_ips_refs.to_a) - add_load_balancers_collections(collector.load_balancers_refs.to_a) + add_cloud_networks_inventory_collections(references(:cloud_networks)) + add_cloud_subnets_inventory_collections(references(:cloud_subnets)) + add_network_ports_inventory_collections(references(:vms) + references(:network_ports)) + add_security_groups_inventory_collections(references(:security_groups)) + add_floating_ips_inventory_collections(references(:floating_ips)) + add_load_balancers_collections(references(:load_balancers)) # Storage - add_cloud_volumes_collections(collector.cloud_volumes_refs.to_a) - add_cloud_volume_snapshots_collections(collector.cloud_volume_snapshots_refs.to_a) + add_cloud_volumes_collections(references(:cloud_volumes)) + add_cloud_volume_snapshots_collections(references(:cloud_volume_snapshots)) end def add_vms_inventory_collections(manager_refs) diff --git a/app/models/manageiq/providers/amazon/target_collection.rb b/app/models/manageiq/providers/amazon/target_collection.rb deleted file mode 100644 index a8bc0b2a6..000000000 --- a/app/models/manageiq/providers/amazon/target_collection.rb +++ /dev/null @@ -1,15 +0,0 @@ -class ManageIQ::Providers::Amazon::TargetCollection - attr_accessor :targets - - def initialize(targets) - @targets = targets - end - - def name - "Collection of targets with name: #{targets.collect(&:name)}" - end - - def id - "Collection of targets with id: #{targets.collect(&:id)}" - end -end diff --git a/spec/models/manageiq/providers/amazon/cloud_manager/event_target_parser_spec.rb b/spec/models/manageiq/providers/amazon/cloud_manager/event_target_parser_spec.rb new file mode 100644 index 000000000..75c3a965a --- /dev/null +++ b/spec/models/manageiq/providers/amazon/cloud_manager/event_target_parser_spec.rb @@ -0,0 +1,90 @@ +describe ManageIQ::Providers::Amazon::CloudManager::EventTargetParser do + before :each do + _guid, _server, zone = EvmSpecHelper.create_guid_miq_server_zone + @ems = FactoryGirl.create(:ems_amazon, :zone => zone) + + allow_any_instance_of(EmsEvent).to receive(:handle_event) + allow(EmsEvent).to receive(:create_completed_event) + end + + context "AWS Config Event" do + it "parses vm_ems_ref into event" do + ems_event = create_ems_event("sqs_message.json") + + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(1) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-06199fba'}]) + end + end + + context "AWS CloudWatch with CloudTrail API" do + it "parses StartInstances event" do + ems_event = create_ems_event("cloud_watch/StartInstances.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(2) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-0aeefa44d61669849'}]) + end + + it "parses StopInstances" do + ems_event = create_ems_event("cloud_watch/StopInstances.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(2) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-0aeefa44d61669849'}]) + end + end + + context "AWS CloudWatch EC2" do + it "parses EC2_Instance_State_change_Notification_pending event" do + ems_event = create_ems_event("cloud_watch/EC2_Instance_State_change_Notification_pending.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(1) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-0aeefa44d61669849'}]) + end + + it "parses EC2_Instance_State_change_Notification_running event" do + ems_event = create_ems_event("cloud_watch/EC2_Instance_State_change_Notification_running.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(1) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-0aeefa44d61669849'}]) + end + + it "parses EC2_Instance_State_change_Notification_stopped event" do + ems_event = create_ems_event("cloud_watch/EC2_Instance_State_change_Notification_stopped.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(1) + expect(parsed_targets.collect(&:manager_ref).uniq).to match_array([{:ems_ref => 'i-0aeefa44d61669849'}]) + end + end + + context "AWS CloudWatch Alarm" do + it "parses AWS_ALARM_awselb-EmSRefreshSpecVPCELB-Unhealthy-Hosts alarm event" do + ems_event = create_ems_event("cloud_watch/AWS_ALARM_awselb-EmSRefreshSpecVPCELB-Unhealthy-Hosts.json") + parsed_targets = described_class.new(ems_event).parse + + expect(parsed_targets.size).to eq(0) + end + end + + def response(path) + response = double + allow(response).to receive(:body).and_return( + File.read(File.join(File.dirname(__FILE__), "/event_catcher/#{path}")) + ) + + allow(response).to receive(:message_id).and_return("mocked_message_id") + + response + end + + def create_ems_event(path) + event = ManageIQ::Providers::Amazon::CloudManager::EventCatcher::Stream.new(double).send(:parse_event, response(path)) + event_hash = ManageIQ::Providers::Amazon::CloudManager::EventParser.event_to_hash(event, @ems.id) + EmsEvent.add(@ems.id, event_hash) + end +end