diff --git a/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest.rb b/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest.rb index cbee2dca2..c50f744c7 100644 --- a/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest.rb +++ b/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest.rb @@ -2,99 +2,166 @@ # Description: This method is used to Customize the Amazon Provisioning Request # -# process_customization - mapping instance_types, key pairs, security groups and cloud-init templates -def process_customization(mapping, prov, template, product, provider ) - log(:info, "Processing Amazon customizations...", true) - case mapping - when 0 - # No mapping - when 1 - ws_values = prov.options.fetch(:ws_values, {}) - - if prov.get_option(:instance_type).nil? && ws_values.has_key?(:instance_type) - provider.flavors.each do |flavor| - if flavor.name.downcase == ws_values[:instance_type].downcase - prov.set_option(:instance_type, [flavor.id, "#{flavor.name}':'#{flavor.description}"]) - log(:info, "Provisioning object updated {:instance_type => #{prov.get_option(:instance_type).inspect}}") - end - end - end +module ManageIQ + module Automate + module Cloud + module VM + module Provisioning + module StateMachines + module Methods + class AmazonCustomizeRequest + def initialize(handle = $evm) + @handle = handle + @mapping = false + end - if prov.get_option(:guest_access_key_pair).nil? && ws_values.has_key?(:guest_access_key_pair) - provider.key_pairs.each do |keypair| - if keypair.name == ws_values[:guest_access_key_pair] - prov.set_option(:guest_access_key_pair, [keypair.id,keypair.name]) - log(:info, "Provisioning object updated {:guest_access_key_pair => #{prov.get_option(:guest_access_key_pair).inspect}}") - end - end - end + def main + log(:info, "Provision:<#{prov.id}> Request:<#{prov.miq_provision_request.id}> Type:<#{prov.type}>") + log(:info, "Template: #{template.name} Provider: #{provider.name} Vendor: #{template.vendor} Product: #{product}") + log(:info, "Processing Amazon customizations...", true) + process_customization if @mapping + log(:info, "Processing Amazon customizations...Complete", true) + end - if prov.get_option(:security_groups).blank? && ws_values.has_key?(:security_groups) - provider.security_groups.each do |securitygroup| - if securitygroup.name == ws_values[:security_groups] - prov.set_option(:security_groups, [securitygroup.id]) - log(:info, "Provisioning object updated {:security_groups => #{prov.get_option(:security_groups).inspect}}") - end - end - end + private - if prov.get_option(:customization_template_id).nil? - customization_template_search_by_function = "#{prov.type}_#{prov.get_tags[:function]}" rescue nil - customization_template_search_by_template_name = template.name - customization_template_search_by_ws_values = ws_values[:customization_template] rescue nil - log(:info, "prov.eligible_customization_templates: #{prov.eligible_customization_templates.inspect}") - customization_template = nil - - unless customization_template_search_by_function.nil? - # Search for customization templates enabled for Cloud-Init that equal MiqProvisionAmazon_prov.get_tags[:function] - if customization_template.blank? - log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: #{customization_template_search_by_function}") - customization_template = prov.eligible_customization_templates.detect { |ct| ct.name.casecmp(customization_template_search_by_function)==0 } - end - end - unless customization_template_search_by_template_name.nil? - # Search for customization templates enabled for Cloud-Init that match the template/image name - if customization_template.blank? - log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: #{customization_template_search_by_template_name}") - customization_template = prov.eligible_customization_templates.detect { |ct| ct.name.casecmp(customization_template_search_by_template_name)==0 } - end - end - unless customization_template_search_by_ws_values.nil? - # Search for customization templates enabled for Cloud-Init that match ws_values[:customization_template] - if customization_template.blank? - log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: #{customization_template_search_by_ws_values}") - customization_template = prov.eligible_customization_templates.detect { |ct| ct.name.casecmp(customization_template_search_by_ws_values)==0 } - end - end - if customization_template.blank? - log(:warn, "Failed to find matching Customization Template", true) - else - log(:info, "Found Customization Template ID: #{customization_template.id} Name: #{customization_template.name} Description: #{customization_template.description}") - prov.set_customization_template(customization_template) rescue nil - log(:info, "Provisioning object updated {:customization_template_id => #{prov.get_option(:customization_template_id).inspect}}") - log(:info, "Provisioning object updated {:customization_template_script => #{prov.get_option(:customization_template_script).inspect}}") - end - else - log(:info, "Customization Template selected from dialog ID: #{prov.get_option(:customization_template_id).inspect}} Script: #{prov.get_option(:customization_template_script).inspect}") - end - end # case mapping - log(:info, "Processing Amazon customizations...Complete", true) -end + def prov + @prov ||= @handle.root["miq_provision"].tap do |req| + raise 'miq_provision not specified' if req.nil? + end + end -def log(level, msg, update_message=false) - $evm.log(level, "#{msg}") - $evm.root['miq_provision'].message = "#{msg}" if $evm.root['miq_provision'] && update_message -end + def template + @template ||= prov.vm_template.tap do |req| + raise 'vm_template not specified' if req.nil? + end + end + + def provider + @provider ||= template.ext_management_system.tap do |ems| + raise 'ext_management_system not specified' if ems.nil? + end + end + + def product + @product ||= template.operating_system&.product_name&.downcase + end + + def ws_values + @ws_values ||= prov.options.fetch(:ws_values, {}) + end + + def process_customization + set_options + set_customization_template + end + + def set_options + if prov.get_option(:instance_type).nil? && ws_values.key?(:instance_type) + provider.flavors.each do |flavor| + if flavor.name.downcase == ws_values[:instance_type].downcase + prov.set_option(:instance_type, [flavor.id, "#{flavor.name}':'#{flavor.description}"]) + log(:info, "Provisioning object updated {:instance_type => #{prov.get_option(:instance_type).inspect}}") + end + end + end -# Get provisioning object -prov = $evm.root["miq_provision"] + if prov.get_option(:guest_access_key_pair).nil? && ws_values.key?(:guest_access_key_pair) + provider.key_pairs.each do |keypair| + if keypair.name == ws_values[:guest_access_key_pair] + prov.set_option(:guest_access_key_pair, [keypair.id, keypair.name]) + log(:info, "Provisioning object updated {:guest_access_key_pair => #{prov.get_option(:guest_access_key_pair).inspect}}") + end + end + end -log(:info, "Provision:<#{prov.id}> Request:<#{prov.miq_provision_request.id}> Type:<#{prov.type}>") + if prov.get_option(:security_groups).blank? && ws_values.key?(:security_groups) + provider.security_groups.each do |securitygroup| + if securitygroup.name == ws_values[:security_groups] + prov.set_option(:security_groups, [securitygroup.id]) + log(:info, "Provisioning object updated {:security_groups => #{prov.get_option(:security_groups).inspect}}") + end + end + end + end -template = prov.vm_template -provider = template.ext_management_system -product = template.operating_system['product_name'].downcase rescue nil -log(:info, "Template: #{template.name} Provider: #{provider.name} Vendor: #{template.vendor} Product: #{product}") + def set_customization_template + if prov.get_option(:customization_template_id).present? + log(:info, "Customization Template selected from dialog ID: %{id} Script: %{script}" % { + :id => prov.get_option(:customization_template_id).inspect, + :script => prov.get_option(:customization_template_script).inspect + }) + return + end + + customization_template_search_by_function = "#{prov.type}_#{prov.get_tags[:function]}" + customization_template_search_by_template_name = template.name + customization_template_search_by_ws_values = ws_values[:customization_template] + log(:info, "prov.eligible_customization_templates: #{prov.eligible_customization_templates.inspect}") + customization_template = nil + + unless customization_template_search_by_function.nil? + # Search for customization templates enabled for Cloud-Init that equal MiqProvisionAmazon_prov.get_tags[:function] + if customization_template.blank? + log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: %{function}" % { + :function => customization_template_search_by_function + }) + customization_template = prov.eligible_customization_templates.detect do |ct| + ct.name.casecmp(customization_template_search_by_function) == 0 + end + end + end + unless customization_template_search_by_template_name.nil? + # Search for customization templates enabled for Cloud-Init that match the template/image name + if customization_template.blank? + log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: %{name}" % { + :name => customization_template_search_by_template_name + }) + customization_template = prov.eligible_customization_templates.detect do |ct| + ct.name.casecmp(customization_template_search_by_template_name) == 0 + end + end + end + unless customization_template_search_by_ws_values.nil? + # Search for customization templates enabled for Cloud-Init that match ws_values[:customization_template] + if customization_template.blank? + log(:info, "Searching for customization templates (Cloud-Init) enabled that are named: %{ws_value}" % { + :ws_value => customization_template_search_by_ws_values + }) + customization_template = prov.eligible_customization_templates.detect do |ct| + ct.name.casecmp(customization_template_search_by_ws_values) == 0 + end + end + end + if customization_template.blank? + log(:warn, "Failed to find matching Customization Template", true) + else + log(:info, "Found Customization Template ID: %{id} Name: %{name} Description: %{desc}" % { + :id => customization_template.id, + :name => customization_template.name, + :desc => customization_template.description + }) + prov.set_customization_template(customization_template) rescue nil + log(:info, "Provisioning object updated {:customization_template_id => %{id}}" % { + :id => prov.get_option(:customization_template_id).inspect + }) + log(:info, "Provisioning object updated {:customization_template_script => %{script}}" % { + :script => prov.get_option(:customization_template_script).inspect + }) + end + end + + def log(level, msg, update_message = false) + @handle.log(level, msg) + @handle.root['miq_provision'].message = msg if @handle.root['miq_provision'] && update_message + end + end + end + end + end + end + end + end +end -mapping = 0 -process_customization(mapping, prov, template, product, provider) +ManageIQ::Automate::Cloud::VM::Provisioning::StateMachines::Methods::AmazonCustomizeRequest.new.main diff --git a/spec/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest_spec.rb b/spec/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest_spec.rb new file mode 100644 index 000000000..b0db5f047 --- /dev/null +++ b/spec/content/automate/ManageIQ/Cloud/VM/Provisioning/StateMachines/Methods.class/__methods__/amazon_customizerequest_spec.rb @@ -0,0 +1,140 @@ +require_domain_file + +describe ManageIQ::Automate::Cloud::VM::Provisioning::StateMachines::Methods::AmazonCustomizeRequest do + let(:ems) { FactoryBot.create(:ems_amazon_with_authentication) } + let(:template) { FactoryBot.create(:miq_template, :ext_management_system => ems) } + let(:prov_req) { FactoryBot.create(:miq_provision_request, :options => {:src_vm_id => template.id}) } + let(:prov) { FactoryBot.create(:miq_provision, :miq_provision_request => prov_req, :options => {:src_vm_id => template.id}) } + let(:svc_prov) { MiqAeMethodService::MiqAeServiceMiqProvision.find(prov.id) } + let(:root_hash) { {'miq_provision' => svc_prov} } + let(:root_object) { Spec::Support::MiqAeMockObject.new(root_hash) } + let(:ae_service) do + Spec::Support::MiqAeMockService.new(root_object).tap do |service| + current_object = Spec::Support::MiqAeMockObject.new + current_object.parent = root_object + service.object = current_object + end + end + + it "process customization without mapping" do + described_class.new(ae_service).main + expect(svc_prov.message).to eq("Processing Amazon customizations...Complete") + end + + context 'customization with mapping' do + let(:customization_template) { FactoryBot.create(:customization_template) } + + after(:each) { expect(svc_prov.message).to eq("Processing Amazon customizations...Complete") } + + def options_with_template(ws_values) + ae_service.root["miq_provision"].options[:ws_values] = ws_values + ae_service.root["miq_provision"].options[:customization_template_id] = customization_template.id + ae_service.root["miq_provision"].options[:customization_template_script] = customization_template.script + end + + context '#instance_type' do + let(:ems) { FactoryBot.create(:ems_amazon_with_authentication, :flavors => [flavor]) } + let(:flavor) { FactoryBot.create(:flavor, :description => 'desc') } + + it "sets flavor as an instance_type" do + options_with_template(:instance_type => flavor.name) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + expect(svc_prov.options[:instance_type]).to eq([flavor.id, "#{flavor.name}':'#{flavor.description}"]) + end + end + + context '#guest_access_key_pair' do + let(:keypair) { FactoryBot.create(:auth_key_pair_cloud, :name => "test_auth_key_pair_cloud") } + let(:ems) { FactoryBot.create(:ems_amazon_with_authentication, :key_pairs => [keypair]) } + + it "sets keypair as a guest_access_key_pair" do + options_with_template(:guest_access_key_pair => keypair.name) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + expect(svc_prov.options[:guest_access_key_pair]).to eq([keypair.id, keypair.name]) + end + end + + context '#security_groups' do + let(:sec_group) { FactoryBot.create(:security_group_amazon) } + + it "sets security_groups for network_manager" do + options_with_template(:security_groups => sec_group.name) + ems.network_manager.security_groups = [sec_group] + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + expect(svc_prov.options[:security_groups]).to eq([sec_group.id]) + end + end + + context '#customization_templates' do + it "fails to find template" do + allow(ae_service.root["miq_provision"]).to receive(:eligible_customization_templates).and_return([]) + expect(ae_service.root["miq_provision"]).not_to receive(:set_customization_template) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + end + + it "finds a template by name" do + customization_template.name = template.name + allow(ae_service.root["miq_provision"]).to receive(:eligible_customization_templates).and_return([customization_template]) + expect(ae_service.root["miq_provision"]).to receive(:set_customization_template).with(customization_template) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + end + + it "finds a template by ws_values" do + ae_service.root["miq_provision"].options[:ws_values] = {:customization_template => customization_template.name} + allow(ae_service.root["miq_provision"]).to receive(:eligible_customization_templates).and_return([customization_template]) + expect(ae_service.root["miq_provision"]).to receive(:set_customization_template).with(customization_template) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + end + + it "finds a template by functions" do + customization_template.name = "#{svc_prov.type}_#{svc_prov.get_tags[:function]}" + allow(ae_service.root["miq_provision"]).to receive(:eligible_customization_templates).and_return([customization_template]) + expect(ae_service.root["miq_provision"]).to receive(:set_customization_template).with(customization_template) + + described_class.new(ae_service).instance_eval do + @mapping = true + main + end + end + end + end + + it 'raises error for missing miq_provision' do + ae_service.root["miq_provision"] = nil + expect { described_class.new(ae_service).main }.to raise_error('miq_provision not specified') + end + + it 'raises error for missing vm_template' do + allow(ae_service.root["miq_provision"]).to receive(:vm_template).and_return(nil) + expect { described_class.new(ae_service).main }.to raise_error('vm_template not specified') + end + + it 'raises error for missing ext_management_system' do + allow_any_instance_of(MiqAeMethodService::MiqAeServiceMiqTemplate).to receive(:ext_management_system).and_return(nil) + expect { described_class.new(ae_service).main }.to raise_error('ext_management_system not specified') + end +end