Skip to content

Commit

Permalink
Merge pull request #19222 from fdupont-redhat/v2v_state_machine_trans…
Browse files Browse the repository at this point in the history
…form_vm

V2v state machine transform vm
  • Loading branch information
agrare authored Aug 29, 2019
2 parents c799da3 + 21f6c70 commit 4c54666
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 9 deletions.
55 changes: 51 additions & 4 deletions app/models/infra_conversion_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ def load_transitions
:poll_run_migration_playbook_complete => {'running_migration_playbook' => 'running_migration_playbook'},
:shutdown_vm => {'running_migration_playbook' => 'shutting_down_vm' },
:poll_shutdown_vm_complete => {'shutting_down_vm' => 'shutting_down_vm'},
:transform_vm => {'shutting_down_vm' => 'transforming_vm'},
:poll_transform_vm_complete => {'transforming_vm' => 'transforming_vm'},
:poll_automate_state_machine => {
'shutting_down_vm' => 'running_in_automate',
'transforming_vm' => 'running_in_automate',
'running_in_automate' => 'running_in_automate'
},
:finish => {'*' => 'finished'},
Expand Down Expand Up @@ -81,6 +83,11 @@ def state_settings
:weight => 1,
:max_retries => 15.minutes / state_retry_interval
},
:transforming_vm => {
:description => "Converting disks",
:weight => 60,
:max_retries => 1.day / state_retry_interval
},
:running_in_automate => {
:max_retries => 36.hours / state_retry_interval
}
Expand Down Expand Up @@ -332,7 +339,7 @@ def shutdown_vm

update_migration_task_progress(:on_exit)
handover_to_automate
queue_signal(:poll_automate_state_machine)
queue_signal(:transform_vm)
rescue StandardError => error
update_migration_task_progress(:on_error)
abort_conversion(error.message, 'error')
Expand All @@ -344,8 +351,7 @@ def poll_shutdown_vm_complete

if target_vm.power_state == 'off'
update_migration_task_progress(:on_exit)
handover_to_automate
return queue_signal(:poll_automate_state_machine)
return queue_signal(:transform_vm)
end

update_migration_task_progress(:on_retry)
Expand All @@ -355,6 +361,47 @@ def poll_shutdown_vm_complete
abort_conversion(error.message, 'error')
end

def transform_vm
update_migration_task_progress(:on_entry)
migration_task.run_conversion
update_migration_task_progress(:on_exit)
queue_signal(:poll_transform_vm_complete, :deliver_on => Time.now.utc + state_retry_interval)
rescue StandardError => error
update_migration_task_progress(:on_error)
abort_conversion(error.message, 'error')
end

def poll_transform_vm_complete
update_migration_task_progress(:on_entry)
return abort_conversion('Converting disks timed out', 'error') if polling_timeout

migration_task.get_conversion_state
case migration_task.options[:virtv2v_status]
when 'active'
virtv2v_disks = migration_task.options[:virtv2v_disks]
converted_disks = virtv2v_disks.reject { |disk| disk[:percent].zero? }
if converted_disks.empty?
message = 'Disk transformation is initializing.'
percent = 1
else
percent = 0
converted_disks.each { |disk| percent += (disk[:percent].to_f * disk[:weight].to_f / 100.0) }
message = "Converting disk #{converted_disks.length} / #{virtv2v_disks.length} [#{percent.round(2)}%]."
end
update_migration_task_progress(:on_retry, :message => message, :percent => percent)
queue_signal(:poll_transform_vm_complete, :deliver_on => Time.now.utc + state_retry_interval)
when 'failed'
raise migration_task.options[:virtv2v_message]
when 'succeeded'
update_migration_task_progress(:on_exit)
handover_to_automate
queue_signal(:poll_automate_state_machine)
end
rescue StandardError => error
update_migration_task_progress(:on_error)
abort_conversion(error.message, 'error')
end

def poll_automate_state_machine
return abort_conversion('Polling Automate state machine timed out', 'error') if polling_timeout

Expand Down
138 changes: 133 additions & 5 deletions spec/models/infra_conversion_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@
end

context 'state transitions' do
%w[start remove_snapshots poll_remove_snapshots_complete wait_for_ip_address run_migration_playbook poll_run_migration_playbook_complete shutdown_vm poll_shutdown_vm_complete poll_automate_state_machine finish abort_job cancel error].each do |signal|
%w[start remove_snapshots poll_remove_snapshots_complete wait_for_ip_address run_migration_playbook poll_run_migration_playbook_complete shutdown_vm poll_shutdown_vm_complete transform_vm poll_transform_vm_complete poll_automate_state_machine finish abort_job cancel error].each do |signal|
shared_examples_for "allows #{signal} signal" do
it signal.to_s do
expect(job).to receive(signal.to_sym)
Expand All @@ -357,7 +357,7 @@
end
end

%w[start remove_snapshots poll_remove_snapshots_complete wait_for_ip_address run_migration_playbook poll_run_migration_playbook_complete shutdown_vm poll_shutdown_vm_complete poll_automate_state_machine].each do |signal|
%w[start remove_snapshots poll_remove_snapshots_complete wait_for_ip_address run_migration_playbook poll_run_migration_playbook_complete shutdown_vm poll_shutdown_vm_complete transform_vm poll_transform_vm_complete poll_automate_state_machine].each do |signal|
shared_examples_for "doesn't allow #{signal} signal" do
it signal.to_s do
expect { job.signal(signal.to_sym) }.to raise_error(RuntimeError, /#{signal} is not permitted at state #{job.state}/)
Expand All @@ -383,6 +383,8 @@
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

Expand All @@ -404,6 +406,8 @@
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

Expand All @@ -425,6 +429,8 @@
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

Expand All @@ -446,6 +452,8 @@
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

Expand All @@ -467,6 +475,8 @@
it_behaves_like 'doesn\'t allow wait_for_ip_address signal'
it_behaves_like 'doesn\'t allow run_migration_playbook signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

Expand All @@ -475,7 +485,30 @@
job.state = 'shutting_down_vm'
end

it_behaves_like 'allows transform_vm signal'
it_behaves_like 'allows poll_shutdown_vm_complete signal'
it_behaves_like 'allows finish signal'
it_behaves_like 'allows abort_job signal'
it_behaves_like 'allows cancel signal'
it_behaves_like 'allows error signal'

it_behaves_like 'doesn\'t allow start signal'
it_behaves_like 'doesn\'t allow remove_snapshots signal'
it_behaves_like 'doesn\'t allow poll_remove_snapshots_complete signal'
it_behaves_like 'doesn\'t allow wait_for_ip_address signal'
it_behaves_like 'doesn\'t allow run_migration_playbook signal'
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
it_behaves_like 'doesn\'t allow poll_automate_state_machine signal'
end

context 'transforming_vm' do
before do
job.state = 'transforming_vm'
end

it_behaves_like 'allows poll_transform_vm_complete signal'
it_behaves_like 'allows poll_automate_state_machine signal'
it_behaves_like 'allows finish signal'
it_behaves_like 'allows abort_job signal'
Expand All @@ -489,6 +522,8 @@
it_behaves_like 'doesn\'t allow run_migration_playbook signal'
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
end

context 'running_in_automate' do
Expand All @@ -510,6 +545,8 @@
it_behaves_like 'doesn\'t allow poll_run_migration_playbook_complete signal'
it_behaves_like 'doesn\'t allow shutdown_vm signal'
it_behaves_like 'doesn\'t allow poll_shutdown_vm_complete signal'
it_behaves_like 'doesn\'t allow transform_vm signal'
it_behaves_like 'doesn\'t allow poll_transform_vm_complete signal'
end
end

Expand Down Expand Up @@ -735,7 +772,7 @@
vm_vmware.update!(:raw_power_state => 'poweredOff')
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry)
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_exit)
expect(job).to receive(:queue_signal).with(:poll_automate_state_machine)
expect(job).to receive(:queue_signal).with(:transform_vm)
job.signal(:shutdown_vm)
expect(task.reload.options[:workflow_runner]).to eq('automate')
end
Expand Down Expand Up @@ -789,9 +826,100 @@
vm_vmware.update!(:raw_power_state => 'poweredOff')
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry)
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_exit)
expect(job).to receive(:queue_signal).with(:poll_automate_state_machine)
expect(job).to receive(:queue_signal).with(:transform_vm)
job.signal(:poll_shutdown_vm_complete)
expect(task.reload.options[:workflow_runner]).to eq('automate')
end
end

context '#transform_vm' do
before do
task.update_options(:migration_phase => 'pre')
job.state = 'shutting_down_vm'
end

it 'sends run_conversion to migration task and exits' do
Timecop.freeze(2019, 2, 6) do
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry)
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_exit)
expect(job.migration_task).to receive(:run_conversion)
expect(job).to receive(:queue_signal).with(:poll_transform_vm_complete, :deliver_on => Time.now.utc + job.state_retry_interval)
job.signal(:transform_vm)
end
end
end

context '#poll_transform_vm_complete' do
before do
job.state = 'transforming_vm'
allow(job.migration_task).to receive(:get_conversion_state)
end

it 'abort_conversion when shutting_down_vm times out' do
job.context[:retries_transforming_vm] = 5760
expect(job).to receive(:abort_conversion).with('Converting disks timed out', 'error')
job.signal(:poll_transform_vm_complete)
end

context 'virt-v2v has not started conversion' do
let(:virtv2v_disks) do
[
{ :path => '[datastore] test_vm/test_vm.vmdk', :size => 1_234_567, :percent => 0, :weight => 25 },
{ :path => '[datastore] test_vm/test_vm-2.vmdk', :size => 3_703_701, :percent => 0, :weight => 75 }
]
end

it 'returns a message stating conversion has not started' do
task.update_options(:virtv2v_status => 'active', :virtv2v_disks => virtv2v_disks)
Timecop.freeze(2019, 2, 6) do
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry).and_call_original
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_retry, :message => 'Disk transformation is initializing.', :percent => 1).and_call_original
expect(job).to receive(:queue_signal).with(:poll_transform_vm_complete, :deliver_on => Time.now.utc + job.state_retry_interval)
job.signal(:poll_transform_vm_complete)
expect(task.reload.options[:progress][:states][job.state.to_sym]).to include(
:message => 'Disk transformation is initializing.',
:percent => 1
)
end
end
end

context "conversion is still running" do
let(:virtv2v_disks) do
[
{ :path => '[datastore] test_vm/test_vm.vmdk', :size => 1_234_567, :percent => 100, :weight => 25 },
{ :path => '[datastore] test_vm/test_vm-2.vmdk', :size => 3_703_701, :percent => 25, :weight => 75 }
]
end

it "updates message and percentage, and retries if conversion is not finished" do
task.update_options(:virtv2v_status => 'active', :virtv2v_disks => virtv2v_disks)
Timecop.freeze(2019, 2, 6) do
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry).and_call_original
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_retry, :message => 'Converting disk 2 / 2 [43.75%].', :percent => 43.75).and_call_original
expect(job).to receive(:queue_signal).with(:poll_transform_vm_complete, :deliver_on => Time.now.utc + job.state_retry_interval)
job.signal(:poll_transform_vm_complete)
expect(task.reload.options[:progress][:states][job.state.to_sym]).to include(
:message => 'Converting disk 2 / 2 [43.75%].',
:percent => 43.75
)
end
end

it "aborts if conversion failed" do
task.update_options(:virtv2v_status => 'failed', :virtv2v_message => 'virt-v2v failed for some reason')
expect(job).to receive(:abort_conversion).with('virt-v2v failed for some reason', 'error').and_call_original
job.signal(:poll_transform_vm_complete)
end

it "exits if conversion succeeded" do
task.update_options(:virtv2v_status => 'succeeded')
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_entry).and_call_original
expect(job).to receive(:update_migration_task_progress).once.ordered.with(:on_exit).and_call_original
expect(job).to receive(:queue_signal).with(:poll_automate_state_machine)
job.signal(:poll_transform_vm_complete)
expect(task.reload.options[:progress][:states][job.state.to_sym]).to include(:percent => 100.0)
expect(task.options[:workflow_runner]).to eq('automate')
end
end
end

Expand Down

0 comments on commit 4c54666

Please sign in to comment.