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 Feb 27, 2019
1 parent bf2ad3d commit 136b53e
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 68 deletions.
82 changes: 56 additions & 26 deletions app/models/service_orchestration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,35 @@ 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_stack_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]
if orchestration_stack_job.state == 'finished' && orchestration_stack_job.status == 'error'
return ['deploy_failed', orchestration_stack_job.message]
end

return ['deploy_active', 'waiting for the orchestration stack status'] unless orchestration_stack_job.orchestration_stack_status

[orchestration_stack_job.orchestration_stack_status, orchestration_stack_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
)
ensure
# create options may never be saved before unless they were overridden
save_create_options
job_options = stack_options
job_options[:service_id] = 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
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 = update_options
job_options[:service_id] = id
@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 Down Expand Up @@ -95,6 +103,18 @@ def my_zone
orchestration_manager.try(:my_zone) || super
end

def save_create_options
stack_attributes = if orchestration_stack
orchestration_stack.attributes.compact
else
{:name => stack_name}
end
stack_attributes.delete('id')
options.merge!(:orchestration_stack => stack_attributes,
:create_options => dup_and_process_password(stack_options))
save!
end

private

def add_stack_to_resource
Expand All @@ -107,8 +127,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 @@ -145,15 +165,25 @@ def pick_orchestration_template(dialog_options)
raise _("orchestration template was not set") if orchestration_template.nil?
end

def save_create_options
stack_attributes = if @orchestration_stack
@orchestration_stack.attributes.compact
else
{:name => stack_name}
end
stack_attributes.delete('id')
options.merge!(:orchestration_stack => stack_attributes,
:create_options => dup_and_process_password(stack_options))
save!
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_stack_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 }
end
end
end
79 changes: 37 additions & 42 deletions spec/models/service_orchestration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,24 +178,14 @@
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 = FactoryBot.create(:job)
allow(job).to receive(:signal).with(:start)
allow(service_with_dialog_options).to receive(:wait_on_orchestration_stack)
expect(ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner).to receive(:create_job)
.with(hash_including(:service_id => service.id)).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
Expand All @@ -211,44 +201,46 @@
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(
'InstanceType' => 'cg1.4xlarge',
'DBRootPassword' => 'admin',
'key_in_symbol' => 'not_expected'
)
expect(new_template).to eq(template_by_setter)
end
it 'calls OrchestrationTemplateRunner' do
job = FactoryBot.create(:job)
allow(job).to receive(:signal).with(:update)
expect(ManageIQ::Providers::CloudManager::OrchestrationTemplateRunner).to receive(:create_job)
.with(hash_including(:service_id => service.id)).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 '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 '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_stack_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 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_stack_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_stack_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 +269,13 @@

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")
creation_options = service.stack_options
@resulting_stack = ManageIQ::Providers::CloudManager::OrchestrationStack.create_stack(
service.orchestration_manager, service.stack_name, service.orchestration_template, creation_options
)
service.add_resource(@resulting_stack)
service.save_create_options
service.miq_request_task = FactoryBot.create(:service_template_provision_task)
end

Expand Down

0 comments on commit 136b53e

Please sign in to comment.