diff --git a/app/models/miq_request.rb b/app/models/miq_request.rb index 06c31853abf..6d6f2ba7129 100644 --- a/app/models/miq_request.rb +++ b/app/models/miq_request.rb @@ -77,6 +77,15 @@ class MiqRequest < ApplicationRecord :VmMigrateRequest => { :vm_migrate => N_("VM Migrate") }, + :VmRetireRequest => { + :vm_retire => N_("VM Retire") + }, + :ServiceRetireRequest => { + :service_retire => N_("Service Retire") + }, + :OrchestrationStackRetireRequest => { + :orchestration_stack_retire => N_("Orchestration Stack Retire") + }, :ServiceTemplateProvisionRequest => { :clone_to_service => N_("Service Provision") }, diff --git a/app/models/miq_retire_request.rb b/app/models/miq_retire_request.rb new file mode 100644 index 00000000000..b919c01ce73 --- /dev/null +++ b/app/models/miq_retire_request.rb @@ -0,0 +1,13 @@ +class MiqRetireRequest < MiqRequest + # subclasses must set this + SOURCE_CLASS_NAME = nil + + validates :request_state, :inclusion => { :in => %w(pending finished) + ACTIVE_STATES, :message => "should be pending, #{ACTIVE_STATES.join(", ")} or finished" } + validate :must_have_user + + default_value_for(:source_id) { |r| r.get_option(:src_id) } + default_value_for :source_type, SOURCE_CLASS_NAME + + def my_zone + end +end diff --git a/app/models/miq_retire_task.rb b/app/models/miq_retire_task.rb new file mode 100644 index 00000000000..97a5d59a798 --- /dev/null +++ b/app/models/miq_retire_task.rb @@ -0,0 +1,89 @@ +class MiqRetireTask < MiqRequestTask + validate :validate_request_type, :validate_state + + AUTOMATE_DRIVES = true + + def self.get_description(req_obj) + name = if req_obj.source.nil? + # Single source has not been selected yet + if req_obj.options[:src_ids].length == 1 + m = model_being_retired.find_by(:id => req_obj.options[:src_ids].first) + m.nil? ? "" : m.name + else + "Multiple " + model_being_retired.to_s.pluralize + end + else + req_obj.source.name + end + + new_settings = [] + "#{request_class::TASK_DESCRIPTION} for: #{name} - #{new_settings.join(", ")}" + end + + def deliver_to_automate(req_type = request_type, zone = nil) + task_check_on_delivery + + _log.info("Queuing #{request_class::TASK_DESCRIPTION}: [#{description}]...") + if self.class::AUTOMATE_DRIVES + args = { + :object_type => self.class.name, + :object_id => id, + :attrs => {"request" => req_type}, + :instance_name => "AUTOMATION", + :user_id => 1, + :miq_group_id => 2, + :tenant_id => 1, + } + + args[:attrs].merge!(MiqAeEngine.create_automation_attributes(source.class.base_model.name => source)) + + zone ||= source.respond_to?(:my_zone) ? source.my_zone : MiqServer.my_zone + MiqQueue.put( + :class_name => 'MiqAeEngine', + :method_name => 'deliver', + :args => [args], + :role => 'automate', + :zone => options.fetch(:miq_zone, zone), + :tracking_label => my_task_id, + ) + update_and_notify_parent(:state => "pending", :status => "Ok", :message => "Automation Starting") + else + execute_queue + end + end + + def after_request_task_create + update_attributes(:description, get_description) + end + + def after_ae_delivery(ae_result) + _log.info("ae_result=#{ae_result.inspect}") + reload + + return if ae_result == 'retry' + return if miq_request.state == 'finished' + + if ae_result == 'ok' + update_and_notify_parent(:state => "finished", :status => "Ok", :message => display_message("#{request_class::TASK_DESCRIPTION} completed")) + else + mark_pending_items_as_finished + update_and_notify_parent(:state => "finished", :status => "Error", :message => display_message("#{request_class::TASK_DESCRIPTION} failed")) + end + end + + def before_ae_starts(_options) + reload + if state.to_s.downcase.in?(%w(pending queued)) + _log.info("Executing #{request_class::TASK_DESCRIPTION} request: [#{description}]") + update_and_notify_parent(:state => "active", :status => "Ok", :message => "In Process") + end + end + + def mark_pending_items_as_finished + miq_request.miq_request_tasks.each do |s| + if s.state == 'pending' + s.update_and_notify_parent(:state => "finished", :status => "Warn", :message => "Error in Request: #{miq_request.id}. Setting pending Task: #{id} to finished.") unless id == s.id + end + end + end +end diff --git a/app/models/mixins/retirement_mixin.rb b/app/models/mixins/retirement_mixin.rb index a2ee2e75c65..61273f64bc0 100644 --- a/app/models/mixins/retirement_mixin.rb +++ b/app/models/mixins/retirement_mixin.rb @@ -10,6 +10,11 @@ module RetirementMixin end module ClassMethods + def make_retire_request + options = {:task => task, :userid => current_user, :ids => objs, :src_ids => objs} + (klass.to_s + "RetireRequest").constantize.make_request(@request_id, options, current_user) + end + def retire(ids, options = {}) ids.each do |id| object = find_by(:id => id) @@ -117,7 +122,7 @@ def retirement_check end end - retire_now if retirement_due? + make_retire_request if retirement_due? end def retire_now(requester = nil) diff --git a/app/models/orchestration_stack_retire_request.rb b/app/models/orchestration_stack_retire_request.rb new file mode 100644 index 00000000000..d45ec318745 --- /dev/null +++ b/app/models/orchestration_stack_retire_request.rb @@ -0,0 +1,4 @@ +class OrchestrationStackRetireRequest < MiqRetireRequest + TASK_DESCRIPTION = 'OrchestrationStack Retire'.freeze + SOURCE_CLASS_NAME = 'OrchestrationStack'.freeze +end diff --git a/app/models/orchestration_stack_retire_task.rb b/app/models/orchestration_stack_retire_task.rb new file mode 100644 index 00000000000..a0b32a5a598 --- /dev/null +++ b/app/models/orchestration_stack_retire_task.rb @@ -0,0 +1,9 @@ +class OrchestrationStackRetireTask < MiqRetireTask + def self.base_model + OrchestrationStackRetireTask + end + + def self.model_being_retired + OrchestrationStack + end +end diff --git a/app/models/service/retirement_management.rb b/app/models/service/retirement_management.rb index cc2db5109fc..7059d1fd17b 100644 --- a/app/models/service/retirement_management.rb +++ b/app/models/service/retirement_management.rb @@ -7,6 +7,8 @@ def before_retirement end def retire_service_resources + # TODO: delete me per https://github.com/ManageIQ/manageiq/pull/16933#discussion_r175805070 + return direct_service_children.each(&:retire_service_resources) service_resources.each do |sr| diff --git a/app/models/service_retire_request.rb b/app/models/service_retire_request.rb new file mode 100644 index 00000000000..afd4c3c69d4 --- /dev/null +++ b/app/models/service_retire_request.rb @@ -0,0 +1,6 @@ +class ServiceRetireRequest < MiqRetireRequest + TASK_DESCRIPTION = 'Service Retire'.freeze + SOURCE_CLASS_NAME = 'Service'.freeze + + delegate :service_template, :to => :source, :allow_nil => true +end diff --git a/app/models/service_retire_task.rb b/app/models/service_retire_task.rb new file mode 100644 index 00000000000..70bca689b28 --- /dev/null +++ b/app/models/service_retire_task.rb @@ -0,0 +1,18 @@ +class ServiceRetireTask < MiqRetireTask + def self.base_model + ServiceRetireTask + end + + def self.model_being_retired + Service + end + + def update_and_notify_parent(*args) + prev_state = state + super + task_finished if state == "finished" && prev_state != "finished" + end + + def task_finished + end +end diff --git a/app/models/vm_retire_request.rb b/app/models/vm_retire_request.rb new file mode 100644 index 00000000000..8cc69b45333 --- /dev/null +++ b/app/models/vm_retire_request.rb @@ -0,0 +1,10 @@ +class VmRetireRequest < MiqRetireRequest + TASK_DESCRIPTION = 'VM Retire'.freeze + SOURCE_CLASS_NAME = 'Vm'.freeze + ACTIVE_STATES = %w(retired) + base_class::ACTIVE_STATES + + def my_zone + vm = Vm.find_by(:id => options[:src_ids]) + vm.nil? ? super : vm.my_zone + end +end diff --git a/app/models/vm_retire_task.rb b/app/models/vm_retire_task.rb new file mode 100644 index 00000000000..730175f3430 --- /dev/null +++ b/app/models/vm_retire_task.rb @@ -0,0 +1,11 @@ +class VmRetireTask < MiqRetireTask + alias_attribute :vm, :source + + def self.base_model + VmRetireTask + end + + def self.model_being_retired + Vm + end +end diff --git a/spec/models/miq_request_spec.rb b/spec/models/miq_request_spec.rb index adc42414a48..39d7167ca17 100644 --- a/spec/models/miq_request_spec.rb +++ b/spec/models/miq_request_spec.rb @@ -7,18 +7,21 @@ context "CONSTANTS" do it "REQUEST_TYPES" do expected_request_types = { - :MiqProvisionRequest => {:template => "VM Provision", :clone_to_vm => "VM Clone", :clone_to_template => "VM Publish"}, - :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, - :MiqHostProvisionRequest => {:host_pxe_install => "Host Provision"}, - :MiqProvisionConfiguredSystemRequest => {:provision_via_foreman => "#{ui_lookup(:ui_title => 'foreman')} Provision"}, - :VmReconfigureRequest => {:vm_reconfigure => "VM Reconfigure"}, - :VmCloudReconfigureRequest => {:vm_cloud_reconfigure => "VM Cloud Reconfigure"}, - :VmMigrateRequest => {:vm_migrate => "VM Migrate"}, - :AutomationRequest => {:automation => "Automation"}, - :ServiceTemplateProvisionRequest => {:clone_to_service => "Service Provision"}, - :ServiceReconfigureRequest => {:service_reconfigure => "Service Reconfigure"}, - :PhysicalServerProvisionRequest => {:provision_physical_server => "Physical Server Provision"}, - :ServiceTemplateTransformationPlanRequest => {:transformation_plan => "Transformation Plan"} + :MiqProvisionRequest => {:template => "VM Provision", :clone_to_vm => "VM Clone", :clone_to_template => "VM Publish"}, + :MiqProvisionRequestTemplate => {:template => "VM Provision Template"}, + :MiqHostProvisionRequest => {:host_pxe_install => "Host Provision"}, + :MiqProvisionConfiguredSystemRequest => {:provision_via_foreman => "#{ui_lookup(:ui_title => 'foreman')} Provision"}, + :VmReconfigureRequest => {:vm_reconfigure => "VM Reconfigure"}, + :VmCloudReconfigureRequest => {:vm_cloud_reconfigure => "VM Cloud Reconfigure"}, + :VmMigrateRequest => {:vm_migrate => "VM Migrate"}, + :VmRetireRequest => {:vm_retire => "VM Retire"}, + :ServiceRetireRequest => {:service_retire => "Service Retire"}, + :OrchestrationStackRetireRequest => {:orchestration_stack_retire => "Orchestration Stack Retire"}, + :AutomationRequest => {:automation => "Automation"}, + :ServiceTemplateProvisionRequest => {:clone_to_service => "Service Provision"}, + :ServiceReconfigureRequest => {:service_reconfigure => "Service Reconfigure"}, + :PhysicalServerProvisionRequest => {:provision_physical_server => "Physical Server Provision"}, + :ServiceTemplateTransformationPlanRequest => {:transformation_plan => "Transformation Plan"} } expect(described_class::REQUEST_TYPES).to eq(expected_request_types) diff --git a/spec/models/orchestration_stack/retirement_management_spec.rb b/spec/models/orchestration_stack/retirement_management_spec.rb index 20cfd6b5501..a681d589487 100644 --- a/spec/models/orchestration_stack/retirement_management_spec.rb +++ b/spec/models/orchestration_stack/retirement_management_spec.rb @@ -8,7 +8,7 @@ expect(MiqEvent).to receive(:raise_evm_event) @stack.update_attributes(:retires_on => 90.days.ago, :retirement_warn => 60, :retirement_last_warn => nil) expect(@stack.retirement_last_warn).to be_nil - expect_any_instance_of(@stack.class).to receive(:retire_now).once + expect(@stack).to receive(:make_retire_request).once @stack.retirement_check @stack.reload expect(@stack.retirement_last_warn).not_to be_nil @@ -24,7 +24,7 @@ it "#retire_now" do expect(@stack.retirement_state).to be_nil - expect(MiqEvent).to receive(:raise_evm_event).once + expect(OrchestrationStackRetireRequest).to_not receive(:make_request) @stack.retire_now @stack.reload end @@ -35,7 +35,7 @@ event_hash = {:orchestration_stack => @stack, :type => "OrchestrationStack", :retirement_initiator => "user", :userid => "freddy"} - expect(MiqEvent).to receive(:raise_evm_event).with(@stack, event_name, event_hash, {}).once + expect(OrchestrationStackRetireRequest).to_not receive(:make_request) @stack.retire_now('freddy') @stack.reload @@ -47,7 +47,7 @@ event_hash = {:orchestration_stack => @stack, :type => "OrchestrationStack", :retirement_initiator => "system"} - expect(MiqEvent).to receive(:raise_evm_event).with(@stack, event_name, event_hash, {}).once + expect(OrchestrationStackRetireRequest).to_not receive(:make_request) @stack.retire_now @stack.reload diff --git a/spec/models/service/retirement_management_spec.rb b/spec/models/service/retirement_management_spec.rb index 0917eef7a3f..f6ca597cb98 100644 --- a/spec/models/service/retirement_management_spec.rb +++ b/spec/models/service/retirement_management_spec.rb @@ -4,11 +4,12 @@ @service = FactoryGirl.create(:service) end + # shouldn't be running make_retire_request because it's the bimodal not from ui part it "#retirement_check" do expect(MiqEvent).to receive(:raise_evm_event) @service.update_attributes(:retires_on => 90.days.ago, :retirement_warn => 60, :retirement_last_warn => nil) expect(@service.retirement_last_warn).to be_nil - expect_any_instance_of(@service.class).to receive(:retire_now).once + expect(@service).to receive(:make_retire_request).once @service.retirement_check @service.reload expect(@service.retirement_last_warn).not_to be_nil @@ -76,7 +77,7 @@ vm = FactoryGirl.create(:vm_vmware, :ems_id => ems.id) @service << vm expect(@service.service_resources.size).to eq(1) - expect(@service.service_resources.first.resource).to receive(:retire_now).once + expect(@service.service_resources.first.resource).to_not receive(:retire_now) @service.retire_service_resources end @@ -87,7 +88,7 @@ @service.update_attributes(:retirement_requester => userid) @service << vm expect(@service.service_resources.size).to eq(1) - expect(@service.service_resources.first.resource).to receive(:retire_now).with(userid).once + expect(@service.service_resources.first.resource).to_not receive(:retire_now).with(userid) @service.retire_service_resources end @@ -96,7 +97,7 @@ vm = FactoryGirl.create(:vm_vmware, :ems_id => ems.id) @service << vm expect(@service.service_resources.size).to eq(1) - expect(@service.service_resources.first.resource).to receive(:retire_now).with(nil).once + expect(@service.service_resources.first.resource).to_not receive(:retire_now).with(nil) @service.retire_service_resources end diff --git a/spec/models/vm/retirement_management_spec.rb b/spec/models/vm/retirement_management_spec.rb index a9d2d702a30..ab14fafdc5e 100644 --- a/spec/models/vm/retirement_management_spec.rb +++ b/spec/models/vm/retirement_management_spec.rb @@ -10,7 +10,7 @@ expect(MiqEvent).to receive(:raise_evm_event).once @vm.update_attributes(:retires_on => 90.days.ago, :retirement_warn => 60, :retirement_last_warn => nil) expect(@vm.retirement_last_warn).to be_nil - expect_any_instance_of(@vm.class).to receive(:retire_now).once + expect(@vm).to receive(:make_retire_request).once @vm.retirement_check @vm.reload expect(@vm.retirement_last_warn).not_to be_nil