diff --git a/app/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter.rb b/app/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter.rb index 025a1cfd7..9d29a58b2 100644 --- a/app/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter.rb +++ b/app/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter.rb @@ -1,10 +1,58 @@ class ManageIQ::Providers::Amazon::CloudManager::OrchestrationServiceOptionConverter < ::ServiceOrchestration::OptionConverter + REGEX_TAGS = /([^(=>)\n ]+)[(=>) ]+([^(=>)\n ]+)[ \n]*/ + private_constant :REGEX_TAGS, :REGEX_TAGS + def stack_create_options - on_failure = @dialog_options['dialog_stack_onfailure'] timeout = @dialog_options['dialog_stack_timeout'] - stack_options = {:parameters => stack_parameters, :disable_rollback => on_failure != 'ROLLBACK'} - stack_options[:timeout_in_minutes] = timeout.to_i unless timeout.blank? + policy_body, policy_url = parse_policy(@dialog_options['dialog_stack_policy']) + + stack_options = { + :parameters => stack_parameters, + :on_failure => @dialog_options['dialog_stack_onfailure'], + :timeout_in_minutes => timeout.blank? ? nil : timeout.to_i, + :notification_arns => parse_multiple_lines(@dialog_options['dialog_stack_notifications']), + :capabilities => parse_capacities(@dialog_options['dialog_stack_capabilities']), + :resource_types => parse_multiple_lines(@dialog_options['dialog_stack_resource_types']), + :role_arn => @dialog_options['dialog_stack_role'], + :stack_policy_body => policy_body, + :stack_policy_url => policy_url, + :tags => parse_tags(@dialog_options['dialog_stack_tags']) + } + + stack_options.select { |_k, v| v.present? } + end + + private + + def parse_capacities(input) + return input if input.blank? || input.kind_of?(Array) + + # currently the dropdown cannot be multi-selected, but it will be enabled soon + [input] + end + + def parse_multiple_lines(input) + return if input.blank? + + input.split("\n").collect(&:strip).select(&:present?) + end + + def parse_tags(input) + return if input.blank? + + # input example: "tag_key1 => tag_val1\n tag_key2 => tag_val2" + input.scan(REGEX_TAGS).each_with_object([]) { |tag, arr| arr.push({:key => tag.first, :value => tag.last}) } + end + + def parse_policy(input) + return unless input - stack_options + begin + JSON.parse(input) + policy_body = input + rescue JSON::ParserError + policy_url = input + end + [policy_body, policy_url] end end diff --git a/spec/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter_spec.rb b/spec/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter_spec.rb new file mode 100644 index 000000000..f623278a0 --- /dev/null +++ b/spec/models/manageiq/providers/amazon/cloud_manager/orchestration_service_option_converter_spec.rb @@ -0,0 +1,93 @@ +describe ManageIQ::Providers::Amazon::CloudManager::OrchestrationServiceOptionConverter do + subject { described_class.new(options) } + + describe '#stack_create_options' do + context 'no option is set' do + let(:options) { {} } + + it 'returns an empty option hash for stack creation' do + expect(subject.stack_create_options).to be_empty + end + end + + context 'all options are empty' do + let(:options) do + { + "dialog_stack_timeout" => "", + "dialog_stack_onfailure" => "", + "dialog_stack_notifications" => "", + "dialog_stack_capabilities" => "", + "dialog_stack_resource_types" => "", + "dialog_stack_policy" => "", + "dialog_stack_role" => "", + "dialog_stack_tags" => "" + } + end + + it 'returns an empty option hash for stack creation' do + expect(subject.stack_create_options).to be_empty + end + end + end + + context 'timeout option' do + let(:options) { {'dialog_stack_timeout' => '30'} } + + it { expect(subject.stack_create_options[:timeout_in_minutes]).to eq(30) } + end + + context 'on_failure option' do + let(:options) { {'dialog_stack_onfailure' => 'ROLLBACK'} } + + it { expect(subject.stack_create_options[:on_failure]).to eq('ROLLBACK') } + end + + context 'notification arn option' do + let(:options) { {'dialog_stack_notifications' => "ARN1\n ARN2\n\n"} } + + it { expect(subject.stack_create_options[:notification_arns]).to eq(%w(ARN1 ARN2)) } + end + + context 'capabilities option' do + let(:options) { {'dialog_stack_capabilities' => %w(CAPABILITY_IAM CAPABILITY_NAMED_IAM)} } + + it { expect(subject.stack_create_options[:capabilities]).to eq(%w(CAPABILITY_IAM CAPABILITY_NAMED_IAM)) } + end + + context 'capabilities option with single value' do + let(:options) { {'dialog_stack_capabilities' => 'CAPABILITY_IAM'} } + + it { expect(subject.stack_create_options[:capabilities]).to eq(['CAPABILITY_IAM']) } + end + + context 'resource types option' do + let(:options) { {'dialog_stack_resource_types' => "AWS::EC2::Instance \nAWS::EC2::*"} } + + it { expect(subject.stack_create_options[:resource_types]).to eq(%w(AWS::EC2::Instance AWS::EC2::*)) } + end + + context 'role arn option' do + let(:options) { {'dialog_stack_role' => 'RoleARN'} } + + it { expect(subject.stack_create_options[:role_arn]).to eq('RoleARN') } + end + + context 'policy body option' do + let(:options) { {'dialog_stack_policy' => '{"valid":"JSON string"}'} } + + it { expect(subject.stack_create_options[:stack_policy_body]).to eq('{"valid":"JSON string"}') } + end + + context 'policy url option' do + let(:options) { {'dialog_stack_policy' => 'http://url'} } + + it { expect(subject.stack_create_options[:stack_policy_url]).to eq('http://url') } + end + + context 'tags option' do + let(:options) { {'dialog_stack_tags' => "tag_key1 => tag_val1 \ntag_key2=>tag_val2\n\n"} } + + it { expect(subject.stack_create_options[:tags]).to eq( + [{:key => 'tag_key1', :value => 'tag_val1'}, {:key => 'tag_key2', :value => 'tag_val2'}]) } + end +end