diff --git a/app/models/vm_scan.rb b/app/models/vm_scan.rb index 84b47cb93c25..0ced37ff85c3 100644 --- a/app/models/vm_scan.rb +++ b/app/models/vm_scan.rb @@ -15,25 +15,19 @@ def self.current_job_timeout(timeout_adjustment = 1) def load_transitions self.state ||= 'initialize' { - :initializing => {'initialize' => 'waiting_to_start'}, - :snapshot_delete => {'scanning' => 'snapshot_delete'}, - :broker_unavailable => {'snapshot_create' => 'wait_for_broker'}, - :scan_retry => {'scanning' => 'scanning'}, - :abort_retry => {'scanning' => 'scanning'}, - :abort_job => {'*' => 'aborting'}, - :cancel => {'*' => 'canceling'}, - :finish => {'*' => 'finished'}, - :error => {'*' => '*'}, - :start => {'waiting_to_start' => 'wait_for_policy'}, - :start_snapshot => {'wait_for_policy' => 'snapshot_create', - 'wait_for_broker' => 'snapshot_create'}, - :snapshot_complete => {'snapshot_create' => 'scanning', - 'snapshot_delete' => 'synchronizing'}, - :data => {'snapshot_create' => 'scanning', - 'scanning' => 'scanning', - 'snapshot_delete' => 'snapshot_delete', - 'synchronizing' => 'synchronizing', - 'finished' => 'finished'} + :initializing => {'initialize' => 'waiting_to_start'}, + :start => {'waiting_to_start' => 'checking_policy'}, + :before_scan => {'checking_policy' => 'before_scan'}, + :start_scan => {'before_scan' => 'scanning'}, + :after_scan => {'scanning' => 'after_scan'}, + :synchronize => {'after_scan' => 'synchronize'}, + :finish => {'*' => 'finished'}, + :abort_job => {'*' => 'aborting'}, + :cancel => {'*' => 'canceling'}, + :error => {'*' => '*'}, + :data => {'scanning' => 'scanning', + 'synchronizing' => 'synchronizing', + 'finished' => 'finished'}, } end @@ -82,78 +76,18 @@ def check_policy_complete(from_zone, status, message, result) :class_name => self.class.to_s, :instance_id => id, :method_name => "signal", - :args => [:start_snapshot], + :args => [:before_scan], :zone => from_zone, :role => "smartstate" ) end - def call_snapshot_create + def before_scan _log.info("Enter") - begin - vm = VmOrTemplate.find(target_id) - context[:snapshot_mor] = nil - - options[:snapshot] = :skipped - options[:use_existing_snapshot] = false - - # TODO: should this logic be moved to a VM subclass implementation? - # or, make type-specific Job classes. - if vm.kind_of?(ManageIQ::Providers::Openstack::CloudManager::Vm) || - vm.kind_of?(ManageIQ::Providers::Microsoft::InfraManager::Vm) - return unless create_snapshot(vm) - elsif vm.kind_of?(ManageIQ::Providers::Azure::CloudManager::Vm) && vm.require_snapshot_for_scan? - return unless create_snapshot(vm) - elsif vm.require_snapshot_for_scan? - proxy = MiqServer.find(miq_server_id) - - # Check if the broker is available - if MiqServer.use_broker_for_embedded_proxy? && !MiqVimBrokerWorker.available? - _log.warn("VimBroker is not available") - signal(:broker_unavailable) - return - end - - if proxy && proxy.forceVmScan - options[:snapshot] = :smartProxy - _log.info("Skipping snapshot creation, it will be performed by the SmartProxy") - context[:snapshot_mor] = options[:snapshot_description] = snapshotDescription("(embedded)") - log_start_user_event_message(vm) - else - set_status("Creating VM snapshot") - - return unless create_snapshot(vm) - end - else - log_start_user_event_message(vm) - end - signal(:snapshot_complete) - rescue => err - _log.log_backtrace(err) - signal(:abort, err.message, "error") - return - rescue Timeout::Error - msg = case options[:snapshot] - when :smartProxy, :skipped then "Request to log snapshot user event with EMS timed out." - else "Request to create snapshot timed out" - end - _log.error(msg) - signal(:abort, msg, "error") - end - end - - def wait_for_vim_broker - _log.info("Enter") - i = 0 - loop do - set_status("Waiting for VimBroker to become available (#{i += 1})") - sleep(60) - _log.info("Checking VimBroker connection status. Count=[#{i}]") - break if MiqVimBrokerWorker.available? - end - - signal(:start_snapshot) + vm = VmOrTemplate.find(target_id) + log_start_user_event_message(vm) + signal(:start_scan) end def call_scan @@ -164,22 +98,9 @@ def call_scan vm = VmOrTemplate.find(target_id) # Send down metadata to allow the host to make decisions. scan_args = create_scan_args(vm) - options[:ems_list] = ems_list = scan_args["ems"] + options[:ems_list] = scan_args["ems"] options[:categories] = vm.scan_profile_categories(scan_args["vmScanProfiles"]) - # If the host supports VixDisk Lib then we need to validate that the host has the required credentials set. - if vm.vendor == 'vmware' - scan_ci_type = ems_list['connect_to'] - if host.is_vix_disk? && ems_list[scan_ci_type] && (ems_list[scan_ci_type][:username].nil? || ems_list[scan_ci_type][:password].nil?) - context[:snapshot_mor] = nil unless options[:snapshot] == :created - raise _("no credentials defined for %{type} %{name}") % {:type => scan_ci_type, - :name => ems_list[scan_ci_type][:hostname]} - end - end - if ems_list[scan_ci_type] - _log.info("[#{host.name}] communicates with [#{scan_ci_type}:#{ems_list[scan_ci_type][:hostname]}"\ - "(#{ems_list[scan_ci_type][:address]})] to scan vm [#{vm.name}]") - end vm.scan_metadata(options[:categories], "taskid" => jobid, "host" => host, "args" => [YAML.dump(scan_args)]) rescue Timeout::Error message = "timed out attempting to scan, aborting" @@ -194,87 +115,20 @@ def call_scan set_status("Scanning for metadata from VM") end - def config_snapshot - snapshot = {"use_existing" => options[:use_existing_snapshot], - "description" => options[:snapshot_description]} - snapshot['create_free_percent'] = ::Settings.snapshots.create_free_percent - snapshot['remove_free_percent'] = ::Settings.snapshots.remove_free_percent - snapshot['name'] = context[:snapshot_mor] - snapshot - end - def config_ems_list(vm) ems_list = vm.ems_host_list ems_list['connect_to'] = vm.scan_via_ems? ? 'ems' : 'host' - - # Disable connecting to EMS for COS SmartProxy. Embedded Proxy will - # enable this if needed in the scan_sync_vm method in server_smart_proxy.rb. - ems_list['connect'] = false if vm.vendor == 'redhat' ems_list end def create_scan_args(vm) - scan_args = {"ems" => config_ems_list(vm), "snapshot" => config_snapshot} + scan_args = { 'ems' => config_ems_list(vm) } # Check if Policy returned scan profiles to use, otherwise use the default profile if available. scan_args["vmScanProfiles"] = options[:scan_profiles] || vm.scan_profile_list - scan_args['snapshot']['forceFleeceDefault'] = false if vm.scan_via_ems? && vm.template? - scan_args['permissions'] = {'group' => 36} if vm.vendor == 'redhat' scan_args end - def call_snapshot_delete - _log.info("Enter") - - # TODO: remove snapshot here if Vm was running - vm = VmOrTemplate.find(target_id) - if context[:snapshot_mor] - mor = context[:snapshot_mor] - context[:snapshot_mor] = nil - - if options[:snapshot] == :smartProxy - set_status("Snapshot delete was performed by the SmartProxy") - else - set_status("Deleting VM snapshot: reference: [#{mor}]") - end - - if vm.ext_management_system - _log.info("Deleting snapshot: reference: [#{mor}]") - begin - # TODO: should this logic be moved to a VM subclass implementation? - # or, make type-specific Job classes. - if vm.kind_of?(ManageIQ::Providers::Openstack::CloudManager::Vm) - vm.ext_management_system.vm_delete_evm_snapshot(vm, mor) - elsif vm.kind_of?(ManageIQ::Providers::Microsoft::InfraManager::Vm) || - (vm.kind_of?(ManageIQ::Providers::Azure::CloudManager::Vm) && vm.require_snapshot_for_scan?) - vm.ext_management_system.vm_delete_evm_snapshot(vm, :snMor => mor) - else - delete_snapshot(mor, vm) - end - rescue => err - _log.error(err.to_s) - return - rescue Timeout::Error - msg = "Request to delete snapshot timed out" - _log.error(msg) - end - - unless options[:snapshot] == :smartProxy - _log.info("Deleted snapshot: reference: [#{mor}]") - set_status("Snapshot deleted: reference: [#{mor}]") - end - else - _log.error("Deleting snapshot: reference: [#{mor}], No Providers available to delete snapshot") - set_status("No Providers available to delete snapshot, skipping", "error") - end - else - set_status("Snapshot was not taken, delete not required") if options[:snapshot] == :skipped - log_end_user_event_message(vm) - end - - signal(:snapshot_complete) - end - def call_synchronize _log.info("Enter") @@ -297,7 +151,7 @@ def call_synchronize end set_status("Synchronizing metadata from VM") - dispatch_finish # let the dispatcher know that it is ok to start the next job since we are no longer holding then snapshot. + dispatch_finish # let the dispatcher know that it is ok to start the next job end def synchronizing @@ -374,7 +228,7 @@ def process_data(*args) if result.status_code == 16 # fatal error on proxy signal(:abort_retry, result.message, "error", false) else - signal(:snapshot_delete) + signal(:after_scan) end else _log.info("no action taken") @@ -384,105 +238,36 @@ def process_data(*args) # got data to process end - def delete_snapshot(mor, vm = nil) - vm ||= VmOrTemplate.find(target_id) - if mor - begin - if vm.ext_management_system - if options[:snapshot] == :smartProxy - log_end_user_event_message(vm) - delete_snapshot_by_description(mor, vm) - else - user_event = end_user_event_message(vm) - if vm.kind_of?(ManageIQ::Providers::Openstack::CloudManager::Vm) - vm.ext_management_system.vm_delete_evm_snapshot(vm, mor) - elsif vm.kind_of?(ManageIQ::Providers::Microsoft::InfraManager::Vm) || - (vm.kind_of?(ManageIQ::Providers::Azure::CloudManager::Vm) && vm.require_snapshot_for_scan?) - vm.ext_management_system.vm_delete_evm_snapshot(vm, :snMor => mor) - else - vm.ext_management_system.vm_remove_snapshot(vm, :snMor => mor, :user_event => user_event) - end - end - else - raise _("No Providers available to delete snapshot") - end - rescue => err - _log.error(err.message) - _log.log_backtrace(err, :debug) - end - else - log_end_user_event_message(vm) - end - end - - def delete_snapshot_by_description(mor, vm) - if mor - ems_type = 'host' - options[:ems_list] = vm.ems_host_list - miqVimHost = options[:ems_list][ems_type] - - miqVim = nil - # Make sure we were given a host to connect to and have a non-nil encrypted password - if miqVimHost && !miqVimHost[:password].nil? - server = miqVimHost[:hostname] || miqVimHost[:ipaddress] - begin - password_decrypt = ManageIQ::Password.decrypt(miqVimHost[:password]) - if MiqServer.use_broker_for_embedded_proxy?(ems_type) - $vim_broker_client ||= MiqVimBroker.new(:client, MiqVimBrokerWorker.drb_port) - miqVim = $vim_broker_client.getMiqVim(server, miqVimHost[:username], password_decrypt) - else - require 'VMwareWebService/MiqVim' - miqVim = MiqVim.new(server, miqVimHost[:username], password_decrypt) - end - - vimVm = miqVim.getVimVm(vm.path) - vimVm.removeSnapshotByDescription(mor, true) unless vimVm.nil? - ensure - vimVm.release if vimVm rescue nil - miqVim.disconnect unless miqVim.nil? - end - end - end - end - def user_event_message(vm, verb) "EVM SmartState Analysis #{verb} for VM [#{vm.name}]" end - def start_user_event_message(vm) + def start_user_event_message(vm = nil) + vm ||= VmOrTemplate.find(target_id) user_event_message(vm, "Initiated") end - def end_user_event_message(vm) + def end_user_event_message(vm = nil) + vm ||= VmOrTemplate.find(target_id) user_event_message(vm, "completed") end - def log_start_user_event_message(vm) + def log_start_user_event_message(vm = nil) + vm ||= VmOrTemplate.find(target_id) log_user_event(start_user_event_message(vm), vm) end - def log_end_user_event_message(vm) + def log_end_user_event_message(vm = nil) unless options[:end_message_sent] + vm ||= VmOrTemplate.find(target_id) log_user_event(end_user_event_message(vm), vm) options[:end_message_sent] = true end end - def snapshotDescription(type = nil) - Snapshot.evm_snapshot_description(jobid, type) - end - def process_cancel(*args) options = args.first || {} - _log.info("job canceling, #{options[:message]}") - - begin - delete_snapshot(context[:snapshot_mor]) - rescue => err - _log.log_backtrace(err) - end - super end @@ -506,12 +291,6 @@ def call_abort_retry(*args) def process_abort(*args) begin vm = VmOrTemplate.find_by(:id => target_id) - unless context[:snapshot_mor].nil? - mor = context[:snapshot_mor] - context[:snapshot_mor] = nil - set_status("Deleting snapshot before aborting job") - delete_snapshot(mor, vm) - end if vm inputs = {:vm => vm, :host => vm.host} MiqEvent.raise_evm_job_event(vm, {:type => "scan", :suffix => "abort"}, inputs) @@ -524,23 +303,12 @@ def process_abort(*args) end # Signals - def snapshot_complete - if state == 'scanning' - scanning - call_scan - else - call_synchronize - end - end - def data(*args) process_data(*args) if state == 'scanning' scanning elsif state == 'synchronizing' synchronizing - # state == 'snapshot_delete' - # do nothing? end end @@ -557,9 +325,6 @@ def abort_retry(*args) # All other signals alias_method :initializing, :dispatch_start alias_method :start, :call_check_policy - alias_method :start_snapshot, :call_snapshot_create - alias_method :snapshot_delete, :call_snapshot_delete - alias_method :broker_unavailable, :wait_for_vim_broker alias_method :abort_job, :process_abort alias_method :cancel, :process_cancel alias_method :finish, :process_finished @@ -567,33 +332,6 @@ def abort_retry(*args) private - def create_snapshot(vm) - if vm.ext_management_system - sn_description = snapshotDescription - _log.info("Creating snapshot, description: [#{sn_description}]") - user_event = start_user_event_message(vm) - options[:snapshot] = :server - begin - # TODO: should this be a vm method? - sn = vm.ext_management_system.vm_create_evm_snapshot(vm, :desc => sn_description, :user_event => user_event).to_s - rescue Exception => err - msg = "Failed to create evm snapshot with EMS. Error: [#{err.class.name}]: [#{err}]" - _log.error(msg) - err.kind_of?(MiqException::MiqVimBrokerUnavailable) ? signal(:broker_unavailable) : signal(:abort, msg, "error") - return false - end - context[:snapshot_mor] = sn - _log.info("Created snapshot, description: [#{sn_description}], reference: [#{context[:snapshot_mor]}]") - set_status("Snapshot created: reference: [#{context[:snapshot_mor]}]") - options[:snapshot] = :created - options[:use_existing_snapshot] = true - return true - else - signal(:abort, "No Providers available to create snapshot, skipping", "error") - return false - end - end - def log_user_event(user_event, vm) begin vm.log_user_event(user_event) diff --git a/spec/models/vm_scan_spec.rb b/spec/models/vm_scan_spec.rb index aa25cd31b2d9..646fe12cb93b 100644 --- a/spec/models/vm_scan_spec.rb +++ b/spec/models/vm_scan_spec.rb @@ -57,12 +57,12 @@ @job.check_policy_complete(@server1.my_zone, 'ok', nil, nil) end - it "sends signal :start_snapshot if status is 'ok' to local zone" do + it "sends signal :before_scan if status is 'ok' to local zone" do expect(MiqQueue).to receive(:put).with( :class_name => @job.class.to_s, :instance_id => @job.id, :method_name => "signal", - :args => [:start_snapshot], + :args => [:before_scan], :zone => @server1.my_zone, :role => "smartstate" ) @@ -89,12 +89,12 @@ @job.check_policy_complete(@server2.my_zone, 'ok', nil, nil) end - it "signals :start_snapshot if status is 'ok' to remote zone" do + it "signals :before_scan if status is 'ok' to remote zone" do expect(MiqQueue).to receive(:put).with( :class_name => @job.class.to_s, :instance_id => @job.id, :method_name => "signal", - :args => [:start_snapshot], + :args => [:before_scan], :zone => @server2.my_zone, :role => "smartstate" )