diff --git a/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/requested.rb b/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/requested.rb index a17affcbd..fbc980b6b 100644 --- a/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/requested.rb +++ b/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/requested.rb @@ -50,6 +50,10 @@ def service_prov_option(prov_option, options_array = []) options_array end +def vendor + @reconfigure_request ? @vm.vendor : @miq_request.source.vendor +end + def service_prov_option_value(prov_option, resource, options_array = []) args_hash = {:prov_option => prov_option, :options_array => options_array, @@ -86,10 +90,12 @@ def vm_prov_option_value(prov_option, options_array = []) :flavor => flavor_obj(@miq_request.get_option(:instance_type)), :number_of_vms => get_option_value(@miq_request, :number_of_vms), :cloud => vm_provision_cloud?} + # number_of_vms doesn't exist for VmReconfigureRequest + args_hash[:number_of_vms] = 1 if @reconfigure_request case prov_option when :vm_memory - requested_memory(args_hash, @miq_request.source.vendor) + requested_memory(args_hash, vendor) when :number_of_cpus requested_number_of_cpus(args_hash) when :storage @@ -104,6 +110,15 @@ def requested_memory(args_hash, vendor) memory = get_option_value(args_hash[:resource], :vm_memory) memory = memory.megabytes if %w(amazon openstack google).exclude?(vendor) args_hash[:prov_value] = args_hash[:number_of_vms] * memory + + if @reconfigure_request && args_hash[:resource].options[:vm_memory] + # Account for the VM's existing memory + args_hash[:prov_value] = args_hash[:prov_value].to_i - @vm.hardware.memory_mb.to_i.megabytes + + $evm.log(:info, "vm_memory: #{@vm.hardware.memory_mb.to_i.megabytes}") + $evm.log(:info, "requested_memory: #{args_hash[:prov_value].to_i}") + @check_quota = true if args_hash[:prov_value].to_i > 0 + end request_hash_value(args_hash) end @@ -112,6 +127,17 @@ def requested_number_of_cpus(args_hash) get_option_value(args_hash[:resource], :cores_per_socket) cpu_in_request = get_option_value(args_hash[:resource], args_hash[:number_of_cpus]) if cpu_in_request.zero? args_hash[:prov_value] = args_hash[:number_of_vms] * cpu_in_request + + if @reconfigure_request && args_hash[:resource].options[:number_of_sockets] + # Account for the VM's existing CPUs + args_hash[:prov_value] = args_hash[:prov_value].to_i - @vm.hardware.cpu_total_cores.to_i \ + * @vm.hardware.cpu_cores_per_socket.to_i + + $evm.log(:info, "vm_number_of_cpus: #{@vm.hardware.cpu_total_cores.to_i \ + * @vm.hardware.cpu_cores_per_socket.to_i}") + $evm.log(:info, "requested_number_of_cpus: #{args_hash[:prov_value].to_i}") + @check_quota = true if args_hash[:prov_value].to_i > 0 + end request_hash_value(args_hash) end @@ -120,8 +146,36 @@ def vmdb_object(model, id) end def requested_storage(args_hash) - vm_size = args_hash[:resource].vm_template.provisioned_storage - args_hash[:prov_value] = args_hash[:number_of_vms] * vm_size + if @reconfigure_request + args_hash[:prov_value] = 0 + # Adding/removing disks only supported for VMware + if args_hash[:resource].options[:disk_add] + args_hash[:resource].options[:disk_add].each do |disk| + $evm.log(:info, "Adding a disk: #{disk.inspect}") + args_hash[:prov_value] += disk['disk_size_in_mb'].to_i.megabytes + end + end + if args_hash[:resource].options[:disk_remove] + args_hash[:resource].options[:disk_remove].each do |disk| + disk_num = disk[:disk_name].match(/_(\d).vmdk/) + next unless disk_num + $evm.log(:info, "Reconfigure Disk Removal: #{disk.inspect}") + disk_n_number = "disk_#{disk_num[1].succ}_size" + disk_n_size = @vm.send(disk_n_number.to_s) + next unless disk_n_size + $evm.log(:info, "Disk size: #{disk_n_size.to_s(:human_size)}") + args_hash[:prov_value] -= disk_n_size.to_i + end + end + else + vm_size = args_hash[:resource].vm_template.provisioned_storage + args_hash[:prov_value] = args_hash[:number_of_vms] * vm_size + end + + if @reconfigure_request + $evm.log(:info, "VM Reconfigure storage change: #{args_hash[:prov_value].to_s(:human_size)}") + @check_quota = true if args_hash[:prov_value].to_i > 0 + end request_hash_value(args_hash) end @@ -265,4 +319,14 @@ def error(type) exit MIQ_OK end +@reconfigure_request = @miq_request.type == "VmReconfigureRequest" +if @reconfigure_request + @check_quota = false # default, unless additional quota is requested + vm_id = @miq_request.options[:src_ids] + @vm = $evm.vmdb(:vm).find_by(:id => vm_id) + raise "VM not found" if @vm.nil? +end + $evm.root['quota_requested'] = calculate_requested(options_hash) + +$evm.root['check_quota'] = @check_quota unless @check_quota.nil? diff --git a/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/validate_quota.rb b/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/validate_quota.rb index d19ab3535..64a53d335 100644 --- a/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/validate_quota.rb +++ b/content/automate/ManageIQ/System/CommonMethods/QuotaMethods.class/__methods__/validate_quota.rb @@ -155,6 +155,14 @@ def error(type) exit MIQ_OK end +unless $evm.root['check_quota'].nil? + if $evm.root['check_quota'] == false + $evm.log(:info, "VmReconfigureRequest: Bypassing quota check.") + $evm.root['ae_result'] = 'ok' + exit MIQ_OK + end +end + check_quotas check_quota_results diff --git a/content/automate/ManageIQ/System/Policy.class/vmreconfigurerequest_starting.yaml b/content/automate/ManageIQ/System/Policy.class/vmreconfigurerequest_starting.yaml new file mode 100644 index 000000000..efc993cf0 --- /dev/null +++ b/content/automate/ManageIQ/System/Policy.class/vmreconfigurerequest_starting.yaml @@ -0,0 +1,12 @@ +--- +object_type: instance +version: 1.0 +object: + attributes: + display_name: + name: VmReconfigureRequest_starting + inherits: + description: + fields: + - rel2: + value: "/System/CommonMethods/QuotaStatemachine/quota" diff --git a/spec/automation/unit/method_validation/calculate_requested_spec.rb b/spec/automation/unit/method_validation/calculate_requested_spec.rb index 554c7be40..beb196b0c 100644 --- a/spec/automation/unit/method_validation/calculate_requested_spec.rb +++ b/spec/automation/unit/method_validation/calculate_requested_spec.rb @@ -12,10 +12,15 @@ def vm_attrs end def service_attrs - ["MiqRequest::miq_request=#{@service_request.id}&" \ + ["MiqRequest::miq_request=#{@service_request.id}&"\ "vmdb_object_type=service_template_provision_request"] end + def reconfigure_attrs + ["MiqRequest::miq_request=#{@reconfigure_request.id}&"\ + "vmdb_object_type=VmReconfigureRequest"] + end + def check_results(requested_hash, storage, cpu, vms, memory) expect(requested_hash[:storage]).to eq(storage) expect(requested_hash[:cpu]).to eq(cpu) @@ -70,4 +75,32 @@ def check_results(requested_hash, storage, cpu, vms, memory) check_results(ws.root['quota_requested'], 10.gigabytes, 4, 1, 1024) end end + + context "VmReconfig quota calculate_request" do + it "add 2 cpus and add 4096 memory " do + setup_model("vmware_reconfigure") + @reconfigure_request.update_attributes(:options => {:src_ids => [@vm_vmware.id], :cores_per_socket => 2,\ + :number_of_sockets => 2, :number_of_cpus => 4, :vm_memory => 8192, :request_type => :vm_reconfigure,\ + :disk_add => [{"disk_size_in_mb" => "10", "persistent" => true, "thin_provisioned" => true,\ + "dependent" => true, "bootable" => false}]}) + ws = run_automate_method(reconfigure_attrs) + check_results(ws.root['quota_requested'], 10.megabytes, 2, 0, 4096.megabytes) + end + + it "minus 1 cpu and minus 2048 memory" do + setup_model("vmware_reconfigure") + @reconfigure_request.update_attributes(:options => {:src_ids => [@vm_vmware.id], :cores_per_socket => 1,\ + :number_of_sockets => 1, :number_of_cpus => 1, :vm_memory => 2048, :request_type => :vm_reconfigure}) + ws = run_automate_method(reconfigure_attrs) + check_results(ws.root['quota_requested'], 0, -1, 0, -2048.megabytes) + end + + it "no change" do + setup_model("vmware_reconfigure") + @reconfigure_request.update_attributes(:options => {:src_ids => [@vm_vmware.id], :cores_per_socket => 2,\ + :number_of_sockets => 1, :number_of_cpus => 2, :vm_memory => 4096, :request_type => :vm_reconfigure}) + ws = run_automate_method(reconfigure_attrs) + check_results(ws.root['quota_requested'], 0, 0, 0, 0.megabytes) + end + end end diff --git a/spec/automation/unit/method_validation/validate_quota_spec.rb b/spec/automation/unit/method_validation/validate_quota_spec.rb index f39b9d52f..cb92fe621 100644 --- a/spec/automation/unit/method_validation/validate_quota_spec.rb +++ b/spec/automation/unit/method_validation/validate_quota_spec.rb @@ -1,7 +1,7 @@ describe "Quota Validation" do include Spec::Support::QuotaHelper - def run_automate_method(provision_request) + def run_automate_method @quota_used = YAML.dump(:storage => 32_768, :vms => 2, :cpu => 2, :memory => 4096) @quota_requested = YAML.dump(:storage => 10_240, :vms => 1, :cpu => 1, :memory => 1024) attrs = [] @@ -11,7 +11,8 @@ def run_automate_method(provision_request) "quota_limit_warn_yaml=#{@quota_limit_warn}&" \ "quota_used_yaml=#{@quota_used}&" \ "Tenant::quota_source=#{@tenant.id}&" \ - "quota_requested_yaml=#{@quota_requested}" if provision_request + "quota_requested_yaml=#{@quota_requested}" + attrs << @extra_attrs if @extra_attrs MiqAeEngine.instantiate("/ManageIQ/system/request/Call_Instance?namespace=System/CommonMethods&" \ "class=QuotaMethods&instance=validate_quota&#{attrs.join('&')}", @user) end @@ -24,7 +25,7 @@ def run_automate_method(provision_request) it "no quota limits set" do @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eq('ok') end end @@ -35,7 +36,7 @@ def run_automate_method(provision_request) @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds maximum allowed for the following:" \ " (memory - Used: 4 KB plus requested: 1 KB exceeds quota: 4 KB) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('error') @miq_request.reload expect(@miq_request.options[:quota_max_exceeded]).to eql(err_msg) @@ -47,7 +48,7 @@ def run_automate_method(provision_request) @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds warning limits for the following:" \ " (memory - Used: 4 KB plus requested: 1 KB exceeds quota: 4 KB) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('ok') @miq_request.reload expect(@miq_request.options[:quota_warn_exceeded]).to eql(err_msg) @@ -59,7 +60,7 @@ def run_automate_method(provision_request) @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds maximum allowed for the following:" \ " (vms - Used: 2 plus requested: 1 exceeds quota: 2) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('error') @miq_request.reload expect(@miq_request.options[:quota_max_exceeded]).to eql(err_msg) @@ -67,11 +68,11 @@ def run_automate_method(provision_request) end it "failure warn vms" do - @quota_limit_warn = YAML.dump(:storage => 0, :vms => 1, :cpu => 0, :memory => 0) - @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) + @quota_limit_warn = YAML.dump(:storage => 0, :vms => 1, :cpu => 0, :memory => 0) + @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds warning limits for the following:" \ " (vms - Used: 2 plus requested: 1 exceeds quota: 1) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('ok') @miq_request.reload expect(@miq_request.options[:quota_warn_exceeded]).to eql(err_msg) @@ -83,7 +84,7 @@ def run_automate_method(provision_request) @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds maximum allowed for the following:" \ " (cpu - Used: 2 plus requested: 1 exceeds quota: 2) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('error') @miq_request.reload expect(@miq_request.options[:quota_max_exceeded]).to eql(err_msg) @@ -91,11 +92,11 @@ def run_automate_method(provision_request) end it "failure warn cpu" do - @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 1, :memory => 0) - @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) + @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 1, :memory => 0) + @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds warning limits for the following:" \ " (cpu - Used: 2 plus requested: 1 exceeds quota: 1) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('ok') @miq_request.reload expect(@miq_request.options[:quota_warn_exceeded]).to eql(err_msg) @@ -107,7 +108,7 @@ def run_automate_method(provision_request) @quota_limit_warn = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds maximum allowed for the following:" \ " (storage - Used: 32 KB plus requested: 10 KB exceeds quota: 20 KB) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('error') @miq_request.reload expect(@miq_request.options[:quota_max_exceeded]).to eql(err_msg) @@ -115,15 +116,30 @@ def run_automate_method(provision_request) end it "failure warn storage" do - @quota_limit_warn = YAML.dump(:storage => 10_240, :vms => 0, :cpu => 0, :memory => 0) - @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) + @quota_limit_warn = YAML.dump(:storage => 10_240, :vms => 0, :cpu => 0, :memory => 0) + @quota_limit_max = YAML.dump(:storage => 0, :vms => 0, :cpu => 0, :memory => 0) err_msg = "Request exceeds warning limits for the following:" \ " (storage - Used: 32 KB plus requested: 10 KB exceeds quota: 10 KB) " - ws = run_automate_method(@miq_provision_request) + ws = run_automate_method expect(ws.root['ae_result']).to eql('ok') @miq_request.reload expect(@miq_request.options[:quota_warn_exceeded]).to eql(err_msg) expect(@miq_request.message).to eql(err_msg) end end + + context "check_quota for VMReconfigure" do + it "check_quota false " do + ws = run_automate_method + expect(ws.root['ae_result']).to eq('ok') + expect(ws.root['check_quota']).to be_nil + end + + it "check_quota true " do + @extra_attrs = "check_quota=true" + ws = run_automate_method + expect(ws.root['ae_result']).to eq('ok') + expect(ws.root['check_quota']).to eq('true') + end + end end