Skip to content

Commit

Permalink
Calls OrchestrationTemplateRunner for provider calls.
Browse files Browse the repository at this point in the history
  • Loading branch information
lfu committed Mar 4, 2019
1 parent a68d8c6 commit af1562c
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 54 deletions.
74 changes: 60 additions & 14 deletions app/models/service_orchestration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,48 @@ 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
job_options = {
:create_options => stack_options,
:priority => MiqQueue::HIGH_PRIORITY,
:zone => my_zone
}.merge(
:orchestration_manager_id => orchestration_manager.id,
:stack_name => stack_name,
:orchestration_template_id => orchestration_template.id
)

@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
# 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
Expand All @@ -47,6 +68,8 @@ def orchestration_stack
if @orchestration_stack.nil? && options.fetch_path(:orchestration_stack, 'ems_id')
@orchestration_stack = OrchestrationStack.new(options[:orchestration_stack])
end

@orchestration_stack ||= orchestration_runner_job.orchestration_stack if orchestration_runner_job
@orchestration_stack
end

Expand Down Expand Up @@ -107,8 +130,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
Expand Down Expand Up @@ -146,8 +169,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
Expand All @@ -156,4 +179,27 @@ 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 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 }
orchestration_runner_job.class.uncached { orchestration_runner_job.reload }
end
end
end
100 changes: 60 additions & 40 deletions spec/models/service_orchestration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,77 +178,95 @@
end

describe '#deploy_orchestration_stack' do
it 'creates a stack through cloud manager' do
allow(ManageIQ::Providers::Amazon::CloudManager::OrchestrationStack).to receive(:raw_create_stack) do |manager, name, template, opts|
expect(manager).to eq(manager_by_dialog)
expect(name).to eq('test123')
expect(template).to be_kind_of OrchestrationTemplate
expect(opts).to be_kind_of Hash
end

it 'calls OrchestrationTemplateRunner' do
job = double(:job, :id => 1, :orchestration_stack => FactoryBot.create(:orchestration_stack))
allow(job).to receive(:signal).with(:start)
allow(service_with_dialog_options).to receive(:wait_on_orchestration_stack)
allow(ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner).to receive(:create_job) do |options|
expect(options).to include(
:orchestration_manager_id => manager_by_dialog.id,
:stack_name => service_with_dialog_options.stack_name,
:orchestration_template_id => template_by_dialog.id,
:priority => 20,
:zone => service_with_dialog_options.my_zone
)
expect(options[:create_options]).to include(
:parameters => {
"InstanceType" => "cg1.4xlarge",
"DBRootPassword" => "admin",
"key_in_symbol" => "not_expected"
},
:on_failure => "ROLLBACK",
:timeout_in_minutes => 30
)
end.and_return(job)
service_with_dialog_options.deploy_orchestration_stack
end

it 'always saves options even when the manager fails to create a stack' do
provision_error = MiqException::MiqOrchestrationProvisionError
allow_any_instance_of(ManageIQ::Providers::Amazon::CloudManager).to receive(:stack_create).and_raise(provision_error, 'test failure')

expect(service_with_dialog_options).to receive(:save_create_options)
expect { service_with_dialog_options.deploy_orchestration_stack }.to raise_error(provision_error)
end
end

describe '#update_orchestration_stack' do
let(:reconfigurable_service) do
stack = FactoryBot.create(:orchestration_stack)
@stack = FactoryBot.create(:orchestration_stack)
service_template = FactoryBot.create(:service_template_orchestration)
service_template.orchestration_template = template_by_setter

service.service_template = service_template
service.orchestration_manager = manager_by_setter
service.add_resource(stack)
service.add_resource(@stack)
service.update_options = service.build_stack_options_from_dialog(dialog_options)
service
end

it 'updates a stack through cloud manager' do
allow_any_instance_of(OrchestrationStack).to receive(:raw_update_stack) do |_instance, new_template, opts|
expect(opts[:parameters]).to include(
it 'calls OrchestrationTemplateRunner' do
job = FactoryBot.create(:job)
allow(job).to receive(:signal).with(:update)
allow(ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner).to receive(:create_job) do |options|
expect(options[:update_options][:parameters]).to include(
'InstanceType' => 'cg1.4xlarge',
'DBRootPassword' => 'admin',
'key_in_symbol' => 'not_expected'
)
expect(new_template).to eq(template_by_setter)
end
expect(options).to include(
:orchestration_stack_id => @stack.id,
:orchestration_template_id => template_by_setter.id,
:zone => reconfigurable_service.my_zone
)
end.and_return(job)
reconfigurable_service.update_orchestration_stack
end

it 'saves update options and encrypts password' do
expect(reconfigurable_service.options[:update_options][:parameters]['DBRootPassword']).to eq(MiqPassword.encrypt("admin"))
end
end

describe '#orchestration_stack_status' do
it 'returns an error if stack has never been deployed' do
it 'returns an error if stack runner job has never been created' do
status, _message = service.orchestration_stack_status
expect(status).to eq('check_status_failed')
expect(status).to eq('deploy_failed')
end

it 'return an error if stack runner finishes with an error' do
stack_job = double(:state => 'finished', :status => 'error', :message => 'deploy error')
allow(service_with_deployed_stack).to receive(:orchestration_runner_job).and_return(stack_job)

status, message = service_with_deployed_stack.orchestration_stack_status
expect(status).to eq('deploy_failed')
expect(message).to eq('deploy error')
end

it 'returns current stack status through provider' do
status_obj = ManageIQ::Providers::Amazon::CloudManager::OrchestrationStack::Status.new('CREATE_COMPLETE', 'no error')
allow(deployed_stack).to receive(:raw_status).and_return(status_obj)
it 'returns current stack status through stack runner' do
stack_job = double(:orchestration_stack_status => 'create_complete', :orchestration_stack_message => 'no error', :state => 'finished', :status => 'ok')
allow(service_with_deployed_stack).to receive(:orchestration_runner_job).and_return(stack_job)

status, message = service_with_deployed_stack.orchestration_stack_status
expect(status).to eq('create_complete')
expect(message).to eq('no error')
end

it 'returns an error message when the provider fails to retrieve the status' do
allow(deployed_stack).to receive(:raw_status).and_raise(MiqException::MiqOrchestrationStatusError, 'test failure')
it "returns deploy_active when stack status not set in stack job's options" do
stack_job = double(:state => 'active', :status => 'ok', :orchestration_stack_status => nil)
allow(service_with_deployed_stack).to receive(:orchestration_runner_job).and_return(stack_job)

status, message = service_with_deployed_stack.orchestration_stack_status
expect(status).to eq('check_status_failed')
expect(message).to eq('test failure')
expect(status).to eq('deploy_active')
expect(message).to eq('waiting for the orchestration stack status')
end
end

Expand Down Expand Up @@ -277,10 +295,12 @@

describe '#post_provision_configure' do
before do
allow(ManageIQ::Providers::Amazon::CloudManager::OrchestrationStack)
.to receive(:raw_create_stack).and_return("ems_ref")
@resulting_stack = service.deploy_orchestration_stack

allow(ManageIQ::Providers::Amazon::CloudManager::OrchestrationStack).to receive(:raw_create_stack).and_return("ems_ref")
@resulting_stack = ManageIQ::Providers::CloudManager::OrchestrationStack.create_stack(
service.orchestration_manager, service.stack_name, service.orchestration_template, service.stack_options
)
service.update_attributes(:options => service.options.merge!(:orchestration_stack => @resulting_stack.attributes.compact.except(:id)))
allow(service).to receive(:orchestration_stack).and_return(@resulting_stack)
service.miq_request_task = FactoryBot.create(:service_template_provision_task)
end

Expand Down

0 comments on commit af1562c

Please sign in to comment.