-
Notifications
You must be signed in to change notification settings - Fork 898
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 OrchestrationTemplateRunner to queue up orchestration stack deployment #18374
Merged
gmcculloug
merged 2 commits into
ManageIQ:master
from
lfu:service_orchestration_region_1656351
Mar 5, 2019
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
165 changes: 165 additions & 0 deletions
165
app/models/manageiq/providers/cloud_manager/orchestration_template_runner.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
class ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner < ::Job | ||
DEFAULT_EXECUTION_TTL = 10 # minutes | ||
|
||
# options are job table columns, including options column which is the playbook context info | ||
def self.create_job(options) | ||
super(name, options) | ||
end | ||
|
||
def minimize_indirect | ||
@minimize_indirect = true if @minimize_indirect.nil? | ||
@minimize_indirect | ||
end | ||
|
||
def current_job_timeout(_timeout_adjustment = 1) | ||
@execution_ttl ||= | ||
(options[:execution_ttl].present? ? options[:execution_ttl].try(:to_i) : DEFAULT_EXECUTION_TTL) * 60 | ||
end | ||
|
||
def start | ||
time = Time.zone.now | ||
update_attributes(:started_on => time) | ||
miq_task.update_attributes(:started_on => time) | ||
my_signal(false, :deploy_orchestration_stack, :priority => MiqQueue::HIGH_PRIORITY) | ||
end | ||
|
||
def update | ||
time = Time.zone.now | ||
update_attributes(:started_on => time) | ||
miq_task.update_attributes(:started_on => time) | ||
my_signal(false, :update_orchestration_stack) | ||
end | ||
|
||
def deploy_orchestration_stack | ||
set_status('deploying orchestration stack') | ||
|
||
@orchestration_stack = ManageIQ::Providers::CloudManager::OrchestrationStack.create_stack( | ||
orchestration_manager, options[:stack_name], orchestration_template, options[:create_options] | ||
) | ||
options[:orchestration_stack_id] = @orchestration_stack.id | ||
self.name = "#{name}, Orchestration Stack ID: #{@orchestration_stack.id}" | ||
miq_task.update_attributes(:name => name) | ||
save! | ||
my_signal(false, :poll_stack_status, 10) | ||
rescue StandardError => err | ||
_log.log_backtrace(err) | ||
my_signal(minimize_indirect, :post_stack_run, err.message, 'error') | ||
end | ||
|
||
def update_orchestration_stack | ||
set_status('updating orchestration stack') | ||
|
||
orchestration_stack.raw_update_stack(orchestration_template, options[:update_options]) | ||
self.name = "#{name}, update Orchestration Stack ID: #{orchestration_stack.id}" | ||
miq_task.update_attributes(:name => name) | ||
save! | ||
my_signal(false, :poll_stack_status, 10) | ||
rescue StandardError => err | ||
_log.log_backtrace(err) | ||
my_signal(minimize_indirect, :post_stack_run, err.message, 'error') | ||
end | ||
|
||
def poll_stack_status(interval) | ||
set_status('checking orchestration stack deployment status') | ||
|
||
status, message = orchestration_stack ? orchestration_stack.raw_status.normalized_status : ["check_status_failed", "stack has not been deployed"] | ||
options.merge!(:orchestration_stack_status => status, :orchestration_stack_message => message) | ||
save! | ||
_log.info("Stack deployment status: #{status}, reason: #{message}") | ||
|
||
case status.downcase | ||
when 'create_complete', 'update_complete' | ||
my_signal(minimize_indirect, :post_stack_run, "Orchestration stack [#{orchestration_stack.name}] #{status}", 'ok') | ||
when 'rollback_complete', 'delete_complete', /failed$/, /canceled$/ | ||
_log.error("Orchestration stack deployment error: #{message}. Please examine stack resources for more details") | ||
my_signal(minimize_indirect, :post_stack_run, "Orchestration stack deployment error: #{message}", 'error') | ||
else | ||
interval = 60 if interval > 60 | ||
my_signal(false, :poll_stack_status, interval * 2, :deliver_on => Time.now.utc + interval) | ||
end | ||
rescue MiqException::MiqOrchestrationStackNotExistError, MiqException::MiqOrchestrationStatusError => err | ||
# naming convention requires status to end with "failed" | ||
options.merge!(:orchestration_stack_status => 'check_status_failed', :orchestration_stack_message => err.message) | ||
save! | ||
_log.log_backtrace(err) | ||
my_signal(minimize_indirect, :post_stack_run, err.message, 'error') | ||
end | ||
|
||
def post_stack_run(message, status) | ||
my_signal(true, :finish, message, status) | ||
end | ||
|
||
def set_status(message, status = "ok") | ||
_log.info(message) | ||
super | ||
end | ||
|
||
def my_signal(no_queue, action, *args, deliver_on: nil, priority: MiqQueue::NORMAL_PRIORITY) | ||
if no_queue | ||
signal(action, *args) | ||
else | ||
queue_signal(action, *args, :deliver_on => deliver_on, :priority => priority) | ||
end | ||
end | ||
|
||
def orchestration_stack | ||
OrchestrationStack.find_by(:id => options[:orchestration_stack_id]) | ||
end | ||
|
||
def orchestration_stack_status | ||
options[:orchestration_stack_status] | ||
end | ||
|
||
def orchestration_stack_message | ||
options[:orchestration_stack_message] | ||
end | ||
|
||
alias initializing dispatch_start | ||
alias finish process_finished | ||
alias abort_job process_abort | ||
alias cancel process_cancel | ||
alias error process_error | ||
|
||
private | ||
|
||
attr_writer :minimize_indirect | ||
|
||
def load_transitions | ||
self.state ||= 'initialize' | ||
|
||
{ | ||
:initializing => {'initialize' => 'waiting_to_start'}, | ||
:start => {'waiting_to_start' => 'running'}, | ||
:update => {'waiting_to_start' => 'updating'}, | ||
:deploy_orchestration_stack => {'running' => 'stack_job'}, | ||
:update_orchestration_stack => {'updating' => 'stack_job'}, | ||
:poll_stack_status => {'stack_job' => 'stack_job'}, | ||
:post_stack_run => {'stack_job' => 'stack_done'}, | ||
:finish => {'*' => 'finished'}, | ||
:abort_job => {'*' => 'aborting'}, | ||
:cancel => {'*' => 'canceling'}, | ||
:error => {'*' => '*'} | ||
} | ||
end | ||
|
||
def queue_signal(*args, deliver_on: nil, priority: MiqQueue::NORMAL_PRIORITY) | ||
MiqQueue.put( | ||
:class_name => self.class.name, | ||
:method_name => "signal", | ||
:instance_id => id, | ||
:priority => priority, | ||
:role => 'ems_operations', | ||
:zone => options[:zone], | ||
:args => args, | ||
:deliver_on => deliver_on | ||
) | ||
end | ||
|
||
def orchestration_manager | ||
ExtManagementSystem.find_by(:id => options[:orchestration_manager_id]) | ||
end | ||
|
||
def orchestration_template | ||
OrchestrationTemplate.find_by(:id => options[:orchestration_template_id]) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,27 +17,47 @@ def stack_name=(stname) | |
end | ||
|
||
def orchestration_stack_status | ||
return "check_status_failed", "stack has not been deployed" unless orchestration_stack | ||
return ['deploy_failed', "can't find orchestration stack job for the service"] unless orchestration_runner_job | ||
|
||
orchestration_stack.raw_status.normalized_status | ||
rescue MiqException::MiqOrchestrationStackNotExistError, MiqException::MiqOrchestrationStatusError => err | ||
# naming convention requires status to end with "failed" | ||
["check_status_failed", err.message] | ||
return ['deploy_failed', orchestration_runner_job.message] if orchestration_runner_job.status == 'error' | ||
|
||
return ['deploy_active', 'waiting for the orchestration stack status'] unless orchestration_runner_job.orchestration_stack_status | ||
|
||
[orchestration_runner_job.orchestration_stack_status, orchestration_runner_job.orchestration_stack_message] | ||
end | ||
|
||
def deploy_orchestration_stack | ||
creation_options = stack_options | ||
@orchestration_stack = ManageIQ::Providers::CloudManager::OrchestrationStack.create_stack( | ||
orchestration_manager, stack_name, orchestration_template, creation_options | ||
) | ||
deploy_stack_options = stack_options | ||
job_options = { | ||
:create_options => deploy_stack_options, | ||
:orchestration_manager_id => orchestration_manager.id, | ||
:orchestration_template_id => orchestration_template.id, | ||
:stack_name => stack_name, | ||
:zone => my_zone | ||
} | ||
|
||
@deploy_stack_job = ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner.create_job(job_options) | ||
update_attributes(:options => options.merge(:deploy_stack_job_id => @deploy_stack_job.id)) | ||
@deploy_stack_job.signal(:start) | ||
|
||
wait_on_orchestration_stack | ||
orchestration_stack | ||
ensure | ||
# create options may never be saved before unless they were overridden | ||
save_create_options | ||
end | ||
|
||
def update_orchestration_stack | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly we should have a queue version for update too. It can be either included here or with a separate PR. |
||
# use orchestration_template from service_template, which may be different from existing orchestration_template | ||
orchestration_stack.raw_update_stack(service_template.orchestration_template, update_options) | ||
job_options = { | ||
# use orchestration_template from service_template, which may be different from existing orchestration_template | ||
:orchestration_template_id => service_template.orchestration_template.id, | ||
:orchestration_stack_id => orchestration_stack.id, | ||
:update_options => update_options, | ||
:zone => my_zone | ||
} | ||
@update_stack_job = ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner.create_job(job_options) | ||
update_attributes(:options => options.merge(:update_stack_job_id => @update_stack_job.id)) | ||
@update_stack_job.signal(:update) | ||
end | ||
|
||
def orchestration_stack | ||
|
@@ -47,6 +67,7 @@ def orchestration_stack | |
if @orchestration_stack.nil? && options.fetch_path(:orchestration_stack, 'ems_id') | ||
@orchestration_stack = OrchestrationStack.new(options[:orchestration_stack]) | ||
end | ||
|
||
@orchestration_stack | ||
end | ||
|
||
|
@@ -107,8 +128,8 @@ def add_stack_to_resource | |
|
||
def link_orchestration_template | ||
# some orchestration stacks do not have associations with their templates in their provider, we can link them here | ||
return if @orchestration_stack.nil? || @orchestration_stack.orchestration_template | ||
@orchestration_stack.update_attributes(:orchestration_template => orchestration_template) | ||
return if orchestration_stack.nil? || orchestration_stack.orchestration_template | ||
orchestration_stack.update_attributes(:orchestration_template => orchestration_template) | ||
end | ||
|
||
def assign_vms_owner | ||
|
@@ -146,8 +167,8 @@ def pick_orchestration_template(dialog_options) | |
end | ||
|
||
def save_create_options | ||
stack_attributes = if @orchestration_stack | ||
@orchestration_stack.attributes.compact | ||
stack_attributes = if orchestration_stack | ||
orchestration_stack.attributes.compact | ||
else | ||
{:name => stack_name} | ||
end | ||
|
@@ -156,4 +177,28 @@ def save_create_options | |
:create_options => dup_and_process_password(stack_options)) | ||
save! | ||
end | ||
|
||
def deploy_stack_job | ||
@deploy_stack_job ||= Job.find_by(:id => options.fetch_path(:deploy_stack_job_id)) | ||
end | ||
|
||
def update_stack_job | ||
@update_stack_job ||= Job.find_by(:id => options.fetch_path(:update_stack_job_id)) | ||
end | ||
|
||
def orchestration_runner_job | ||
update_stack_job || deploy_stack_job | ||
end | ||
|
||
def wait_on_orchestration_stack | ||
while deploy_stack_job.orchestration_stack.blank? | ||
_log.info("Waiting for the deployment of orchestration stack [#{stack_name}]...") | ||
sleep 2 | ||
# Code running with Rails QueryCache enabled, | ||
# need to disable caching for the reload to see updates. | ||
self.class.uncached { reload } | ||
deploy_stack_job.class.uncached { deploy_stack_job.reload } | ||
end | ||
@orchestration_stack = deploy_stack_job.orchestration_stack | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
why not place all options together without a merge?
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_options
might changeorchestration_manager
andorchestration_template
.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.
It is hard to understand. In this case, we can do