Skip to content

Commit

Permalink
Add policy check to Vm retirement.
Browse files Browse the repository at this point in the history
  • Loading branch information
lfu committed Aug 19, 2019
1 parent f58d85a commit 710fecf
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 10 deletions.
19 changes: 19 additions & 0 deletions app/models/vm_or_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,25 @@ def run_command_via_parent(verb, options = {})
ext_management_system.send(verb, self, options)
end

# keep the same method signature as others in retirement mixin
def self.make_retire_request(*src_ids, requester, initiated_by: 'user')
vms = where(:id => src_ids)

missing_ids = src_ids - vms.pluck(:id)
_log.error("Retirement of [Vm] IDs: [#{missing_ids.join(', ')}] skipped - target(s) does not exist")

vms.each do |target|
target.check_policy_prevent('request_vm_retire', "retire_request_after_policy_check", requester.userid, :initiated_by => initiated_by)
end
end

def retire_request_after_policy_check(userid, initiated_by: 'user')
options = {:src_ids => [id], :__initiated_by__ => initiated_by, :__request_type__ => VmRetireRequest.request_types.first}
requester = User.find_by(:userid => userid)
self.class.set_retirement_requester(options[:src_ids], requester)
VmRetireRequest.make_request(nil, options, requester)
end

# policy_event: the event sent to automate for policy resolution
# cb_method: the MiqQueue callback method along with the parameters that is called
# when automate process is done and the event is not prevented to proceed by policy
Expand Down
67 changes: 57 additions & 10 deletions spec/models/vm/retirement_management_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe "VM Retirement Management" do
let(:user) { FactoryBot.create(:user_miq_request_approver) }
let(:vm_with_owner) { FactoryBot.create(:vm, :evm_owner => user) }
let(:vm_with_owner) { FactoryBot.create(:vm, :evm_owner => user, :host => FactoryBot.create(:host)) }
let(:region) { FactoryBot.create(:miq_region, :region => ApplicationRecord.my_region_number) }
let(:vm2) { FactoryBot.create(:vm) }

Expand All @@ -11,12 +11,23 @@
end

describe "#retirement_check" do
before do
FactoryBot.create(:miq_event_definition, :name => :request_vm_retire)
# admin user is needed to process Events
# system_context_retirement relies on the presence of a user with this userid
FactoryBot.create(:user_with_group, :userid => "admin")
end

context "with user" do
it "uses user as requester" do
expect(MiqEvent).to receive(:raise_evm_event)
vm_with_owner.update_attributes(:retires_on => 90.days.ago, :retirement_warn => 60, :retirement_last_warn => nil)
expect(vm_with_owner.retirement_last_warn).to be_nil

allow(MiqAeEngine).to receive_messages(:deliver => ['ok', 'success', MiqAeEngine::MiqAeWorkspaceRuntime.new])
vm_with_owner.retirement_check
status, message, result = MiqQueue.first.deliver
MiqQueue.first.delivered(status, message, result)

vm_with_owner.reload
expect(vm_with_owner.retirement_last_warn).not_to be_nil
expect(vm_with_owner.retirement_requester).to eq(user.userid)
Expand All @@ -25,17 +36,19 @@

context "without user" do
before do
# system_context_retirement relies on the presence of a user with this userid
FactoryBot.create(:user, :userid => 'admin', :role => 'super_administrator')
user.destroy
vm_with_owner.reload
end

it "uses admin as requester" do
expect(MiqEvent).to receive(:raise_evm_event)
vm_with_owner.update_attributes(:retires_on => 90.days.ago, :retirement_warn => 60, :retirement_last_warn => nil)
expect(vm_with_owner.retirement_last_warn).to be_nil

allow(MiqAeEngine).to receive_messages(:deliver => ['ok', 'success', MiqAeEngine::MiqAeWorkspaceRuntime.new])
vm_with_owner.retirement_check
status, message, result = MiqQueue.first.deliver
MiqQueue.first.delivered(status, message, result)

vm_with_owner.reload
expect(vm_with_owner.retirement_last_warn).not_to be_nil
expect(vm_with_owner.retirement_requester).to eq('admin')
Expand Down Expand Up @@ -105,23 +118,57 @@
end

describe "retire request" do
let(:ws) { MiqAeEngine::MiqAeWorkspaceRuntime.new }
before do
FactoryBot.create(:miq_event_definition, :name => :request_vm_retire)
# admin user is needed to process Events
FactoryBot.create(:user_with_group, :userid => "admin")
end

it "with one src_id" do
expect(VmRetireRequest).to receive(:make_request).with(nil, {:src_ids => [@vm.id], :__initiated_by__ => 'user', :__request_type__ => "vm_retire"}, user)
allow(Vm).to receive(:where).with(:id => [@vm.id]).and_return([@vm])
expect(@vm).to receive(:check_policy_prevent).once
Vm.make_retire_request(@vm.id, user)
end

it "with many src_ids" do
expect(VmRetireRequest).to receive(:make_request).with(nil, {:src_ids => [@vm.id, vm2.id], :__initiated_by__ => 'user', :__request_type__ => "vm_retire"}, user)
allow(Vm).to receive(:where).with(:id => [@vm.id, vm2.id]).and_return([@vm, vm2])
expect(@vm).to receive(:check_policy_prevent).once
expect(vm2).to receive(:check_policy_prevent).once
Vm.make_retire_request(@vm.id, vm2.id, user)
end

it "initiated by system" do
expect(VmRetireRequest).to receive(:make_request).with(nil, {:src_ids => [@vm.id, vm2.id], :__initiated_by__ => 'system', :__request_type__ => "vm_retire"}, user)
Vm.make_retire_request(@vm.id, vm2.id, user, :initiated_by => 'system')
expect(VmRetireRequest).to receive(:make_request).with(nil, {:src_ids => [@vm.id], :__initiated_by__ => 'system', :__request_type__ => "vm_retire"}, user)

allow(MiqAeEngine).to receive_messages(:deliver => ['ok', 'success', ws])
Vm.make_retire_request(@vm.id, user, :initiated_by => 'system')
status, message, result = MiqQueue.first.deliver
MiqQueue.first.delivered(status, message, result)
end

it "with user as initiated_by" do
expect { Vm.make_retire_request(@vm.id, vm2.id, user, :initiated_by => user) }.to raise_error(/Initiated by is not included in the list/)
allow(MiqAeEngine).to receive_messages(:deliver => ['ok', 'success', ws])
Vm.make_retire_request(@vm.id, user, :initiated_by => user)
q = MiqQueue.first
status, message, result = q.deliver
log_stub = instance_double("_log")
expect(q).to receive(:_log).and_return(log_stub).at_least(:once)
expect(log_stub).to receive(:info).at_least(:once)
expect(log_stub).to receive(:error).with(/Validation failed: VmRetireRequest: Initiated by is not included in the list/)
expect(log_stub).to receive(:log_backtrace)
q.delivered(status, message, result)
end

it "policy prevents" do
expect(VmRetireRequest).not_to receive(:make_request)

event = {:attributes => {"full_data" => {:policy => {:prevented => true}}}}
allow(ws).to receive(:get_obj_from_path).with("/").and_return(:event_stream => event)
allow(MiqAeEngine).to receive_messages(:deliver => ['ok', 'success', ws])
Vm.make_retire_request(@vm.id, user)
status, message, _result = MiqQueue.first.deliver
MiqQueue.first.delivered(status, message, ws)
end
end

Expand Down

0 comments on commit 710fecf

Please sign in to comment.