-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for pre/post-migration playbook #355
Add support for pre/post-migration playbook #355
Conversation
@miq-bot add-label transformation |
@miq-bot add-label enhancement |
service_request_task = service_request.miq_request_tasks.first | ||
unless service_request_task.nil? | ||
stack = service_request_task.destination.service_resources.first | ||
job = stack.resource unless stack.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stack
is already the ansible job instance. There is no stack.resource
method.
service_request_id = task.get_option("#{transformation_hook}_ansible_playbook_service_request_id") | ||
service_request = @handle.vmdb(:miq_request).find_by(:id => service_request_id) | ||
|
||
set_ansible_job(task, service_request, transformation_hook) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should not drill down to examine the ansible job every time. You should rely on the service request_state. Only after the service completes you can fetch the ansible job status just one time.
… job id only when the service request is finished.
@bzwei |
Part of the front-end support (the Overview page parts) for this will be merged with ManageIQ/manageiq-v2v#467 within the next day or two. The rest is already merge-ready I believe, as soon as this merges we should be all set end-to-end! |
@miq-bot add-label gaprindashvili/yes |
playbooks_status[transformation_hook][:job_status] = service_request.status | ||
playbooks_status[transformation_hook][:job_id] = service_request.miq_request_tasks.first.destination.service_resources.first.resource.id | ||
task.set_option(:playbooks, playbooks_status) | ||
if service_request.status == 'Error' && transformation_hook == 'pre' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fdupont-redhat is it intentional to ignore the errors for post playbooks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkanoor
Yes, it is. We consider that the migration has gone far enough to not cancel it for a post migration playbook failure. The playbook or any other problem can be fixed afterwards, with a warning message. The UI knows that the playbook has failed, and it can show the log to the user.
if service_request.request_state == 'finished' | ||
@handle.log(:info, "Ansible playbook service request (id: #{service_request_id}) is finished.") | ||
playbooks_status[transformation_hook][:job_status] = service_request.status | ||
playbooks_status[transformation_hook][:job_id] = service_request.miq_request_tasks.first.destination.service_resources.first.resource.id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fdupont-redhat This is a pretty long chain of commands where we could get a nil in the middle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkanoor
Good catch. I had the same feeling, but aesthetics won over security. I'll add extra tests.
task.set_option(:playbooks, playbooks_status) | ||
end | ||
rescue => e | ||
@handle.set_state_var(:ae_state_progress, 'message' => e.message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fdupont-redhat do you want to report progress only when an error happens or should that also happen on success?
Does :ae_state_progress only mean error messages, if it does we should change it to something like :ae_state_error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mkanoor
It's a default behavior to catch the error and log it in :ae_state_progress
, so that it can be used by WeightedUpdateStatus
. Here, we don't plan to add additional information because the description
argument set in the state machine is explicit enough.
@handle.log(:info, "Service Template Id: #{service_template.id}") | ||
unless service_template.nil? | ||
target_host = target_host(task, transformation_hook) | ||
unless target_host.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fdupont-redhat
Can this be a positive case with an 'if' statement instead of an unless, it makes it easier to read
if service_template
.....
target_host = target_host(task, transformation_hook)
if target_host
......
end
end
Also what happens if you can't find a target_host or service_template should we report on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rubocop actually prefer earlier termination. In this example you can code this way
return if service_template.nil?
...
return if target_host.nil?
...
return unless target_host.power_state == 'on'
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bzwei @mkanoor
Good idea. It's better to be positive ;) And it makes the code shorter.
If service template is nil, it simply means that no playbook is expected to be run.
If target host is nil, it means that transformation_hook
is neither pre
, nor post
. As we don't currently support any other hook, we can skip it. BTW, I don't know if we'll ever support other hooks, but the implementation is generic and could be reused for another use case.
if service_request_id.present? | ||
service_request = @handle.vmdb(:miq_request).find_by(:id => service_request_id) | ||
|
||
playbooks_status = task.get_option(:playbooks) || {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't mix string and symbol as keys at the same level. Here the examples are :playbooks
and "pre_ansible_playbook_service_request_id"
(BTW, the key is very long)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bzwei
Code changed to use to_sym
with the substituted string.
I know the key is very long, but it makes it really explicit.
@handle.log(:info, "Service Template Id: #{service_template.id}") | ||
unless service_template.nil? | ||
target_host = target_host(task, transformation_hook) | ||
unless target_host.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rubocop actually prefer earlier termination. In this example you can code this way
return if service_template.nil?
...
return if target_host.nil?
...
return unless target_host.power_state == 'on'
...
task = @handle.root['service_template_transformation_plan_task'] | ||
transformation_hook = @handle.inputs['transformation_hook'] | ||
|
||
unless transformation_hook == '_' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return if transformation_hook == '_'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
return if service_template.nil? | ||
target_host = target_host(task, transformation_hook) | ||
return if target_host.nil? | ||
return unless target_host.power_state == 'on' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
combine into return if target_host.nil? || target_host.power_state != 'on'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
unless transformation_hook == '_' | ||
service_template = task.send("#{transformation_hook}_ansible_playbook_service_template") | ||
@handle.log(:info, "Service Template Id: #{service_template.id}") | ||
return if service_template.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if service_template.nil?
then the previous line service_template.id
will blow up. A simple fix is #{service_template.try(:id)}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the @handle.log
as it is mainly used for debug.
Checked commits fabiendupont/manageiq-content@5c55d63~...6db4635 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0 content/automate/ManageIQ/Transformation/Ansible.class/methods/checkplaybookasaservice.rb
content/automate/ManageIQ/Transformation/Ansible.class/methods/launchplaybookasaservice.rb
|
…aybook_support Add support for pre/post-migration playbook (cherry picked from commit f5fdc82) https://bugzilla.redhat.com/show_bug.cgi?id=1608420
Gaprindashvili backport details:
|
This PR adds support to call playbooks in pre and post migration phases. The implementation is generic to allow calling playbooks for other hooks. The backend provides methods to get the service template associated to pre and post hooks. The
LaunchPlaybookAsAService
method callcreate_provision_request
and stores the request id in the task options hash. TheCheckPlaybookAsAService
method checks the status of the request. It gracefully fails if the playbook fails in post migration.The
CheckPlaybookAsAService
method also updates the Ansible Tower job status in the task options hash, so that the UI can display it and also collect the job output.Unfortunately, the test to check whether the destination VM is on was introduced inconsistency. It used the oVirt SDK gem to get the information from the provider. It was meant to be faster than wait for refresh. However, with targeted refresh, the power state is reported fast. So I changed the test to use
destination_vm.power_state == 'on'
. Without it the post migration playbook could be skipped due to race condition.This PR adds add the following attributes to task options hash (example):
Associated RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1564250