Skip to content

Commit

Permalink
Create temporary inventory when execute a playbook
Browse files Browse the repository at this point in the history
  • Loading branch information
bzwei committed Feb 22, 2017
1 parent 0dd941a commit c76637f
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 26 deletions.
64 changes: 55 additions & 9 deletions app/models/service_ansible_playbook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ class ServiceAnsiblePlaybook < ServiceGeneric

# A chance for taking options from automate script to override options from a service dialog
def preprocess(action, add_options = {})
_log.info("Override with new options: #{add_options}") unless add_options.blank?
save_job_options(action, add_options)
end

Expand Down Expand Up @@ -38,30 +39,46 @@ def job(action)
service_resources.find_by!(:name => action, :resource_type => 'OrchestrationStack').try(:resource)
end

def postprocess(action)
hosts = options.fetch_path(job_option_key(action), :inventory)
delete_inventory(action) unless use_default_inventory?(hosts)
end

private

def get_job_options(action)
job_opts = options["#{action.downcase}_job_options".to_sym].deep_dup
credential_id = job_opts.delete(:credential_id)
job_opts[:credential] = Authentication.find(credential_id).manager_ref unless credential_id.blank?
job_opts = options[job_option_key(action)].deep_dup

# TODO: decryption may be needed
job_opts
end

def save_job_options(action, overrides)
job_options = parse_dialog_options
job_options[:extra_vars] = (job_options[:extra_vars] || {}).merge(overrides[:extra_vars]) if overrides[:extra_vars]
job_options.merge!(overrides.except(:extra_vars))
job_options = options.fetch_path(:config_info, action.downcase.to_sym).slice(:hosts, :extra_vars)
job_options.deep_merge!(parse_dialog_options)
job_options.deep_merge!(overrides)

credential_id = job_options.delete(:credential_id)
job_options[:credential] = Authentication.find(credential_id).manager_ref unless credential_id.blank?

options["#{action.downcase}_job_options".to_sym] = job_options
hosts = job_options.delete(:hosts)
job_options[:inventory] = create_inventory_with_hosts(action, hosts).id unless use_default_inventory?(hosts)

# TODO: encryption my be needed
options[job_option_key(action)] = job_options
save!
end

def job_option_key(action)
"#{action.downcase}_job_options".to_sym
end

def parse_dialog_options
dialog_options = options[:dialog] || {}

{
:credential_id => dialog_options['dialog_credential_id'],
:hosts => dialog_options['dialog_hosts']
:credential_id => dialog_options['dialog_credential'],
:hosts => dialog_options['dialog_hosts'].to_s.strip.presence
}.compact.merge(extra_vars_from_dialog)
end

Expand All @@ -73,4 +90,33 @@ def extra_vars_from_dialog

params.blank? ? {} : {:extra_vars => params}
end

def create_inventory_with_hosts(action, hosts)
manager(action).with_provider_connection do |connection|
connection.api.inventories.create!(:name => inventory_name(action), :organization => 1).tap do |inventory|
hosts.split(',').each do |host|
connection.api.hosts.create!(:name => host, :inventory => inventory.id)
end
end
end
end

def delete_inventory(action)
manager(action).with_provider_connection do |connection|
inventory_id = options.fetch_path(job_option_key(action), :inventory)
connection.api.inventories.find(inventory_id).destroy!
end
end

def manager(action)
job_template(action).manager
end

def inventory_name(action)
"#{job_template(action).name}_#{id}"
end

def use_default_inventory?(hosts)
hosts.blank? || hosts == 'localhost'
end
end
96 changes: 79 additions & 17 deletions spec/models/service_ansible_playbook_spec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
describe(ServiceAnsiblePlaybook) do
let(:tower_job) { FactoryGirl.create(:ansible_tower_job) }
let(:tower_job_temp) { FactoryGirl.create(:ansible_configuration_script) }
let(:basic_service) { FactoryGirl.create(:service_ansible_playbook, :options => dialog_options) }
let(:basic_service) { FactoryGirl.create(:service_ansible_playbook, :options => config_info_options) }
let(:service) { FactoryGirl.create(:service_ansible_playbook, :options => config_info_options.merge(dialog_options)) }
let(:action) { ResourceAction::PROVISION }
let(:credential_1) { FactoryGirl.create(:authentication, :manager_ref => 'a') }
let(:credential_2) { FactoryGirl.create(:authentication, :manager_ref => 'b') }

let(:loaded_service) do
service_template = FactoryGirl.create(:service_template_ansible_playbook)
Expand All @@ -12,40 +15,92 @@
end

let(:executed_service) do
basic_service.tap do |service|
FactoryGirl.create(:service_ansible_playbook, :options => provision_options).tap do |service|
allow(service).to receive(:job).with(action).and_return(tower_job)
end
end

let(:dialog_options) do
{
:dialog => {
'dialog_hosts' => 'host1,host2',
'dialog_credential_id' => 1,
'dialog_param_var1' => 'value1',
'dialog_param_var2' => 'value2'
'dialog_hosts' => 'host1,host2',
'dialog_credential' => credential_1.id,
'dialog_param_var1' => 'value1',
'dialog_param_var2' => 'value2'
}
}
end

let(:config_info_options) do
{
:config_info => {
:provision => {
:hosts => "default_host1,default_host2",
:extra_vars => {
"var1" => "default_val1",
"var2" => "default_val2",
"var3" => "default_val3"
},
}
}
}
end

let(:override_options) do
{
:hosts => 'host3',
:extra_vars => { 'var1' => 'new_val1' }
:credential_id => credential_2.id,
:hosts => 'host3',
:extra_vars => { 'var1' => 'new_val1' }
}
end

let(:provision_options) { {:provision_job_options => override_options} }
let(:provision_options) do
{
:provision_job_options => {
:credential => 1,
:inventory => 2,
:extra_vars => {'var1' => 'value1', 'var2' => 'value2'}
}
}
end

describe '#preprocess' do
it 'prepares options for action' do
basic_service.preprocess(action, override_options)
basic_service.reload
expect(basic_service.options[:provision_job_options]).to have_attributes(
:hosts => 'host3',
:credential_id => 1,
:extra_vars => {'var1' => 'new_val1', 'var2' => 'value2'}
)
context 'basic service' do
it 'prepares job options from service template' do
hosts = config_info_options.fetch_path(:config_info, :provision, :hosts)
expect(basic_service).to receive(:create_inventory_with_hosts).with(action, hosts).and_return(double(:id => 10))
basic_service.preprocess(action)
service.reload
expect(basic_service.options[:provision_job_options]).to have_attributes(:inventory => 10)
end
end

context 'with dialog overrides' do
it 'prepares job options combines from service template and dialog' do
hosts = dialog_options[:dialog]['dialog_hosts']
expect(service).to receive(:create_inventory_with_hosts).with(action, hosts).and_return(double(:id => 20))
service.preprocess(action)
service.reload
expect(service.options[:provision_job_options]).to have_attributes(
:inventory => 20,
:credential => credential_1.manager_ref,
:extra_vars => {'var1' => 'value1', 'var2' => 'value2', 'var3' => 'default_val3'}
)
end
end

context 'with runtime overrides' do
it 'prepares job options combined from service template, dialog, and overrides' do
hosts = override_options[:hosts]
expect(service).to receive(:create_inventory_with_hosts).with(action, hosts).and_return(double(:id => 30))
service.preprocess(action, override_options)
service.reload
expect(service.options[:provision_job_options]).to have_attributes(
:inventory => 30,
:credential => credential_2.manager_ref,
:extra_vars => {'var1' => 'new_val1', 'var2' => 'value2', 'var3' => 'default_val3'}
)
end
end
end

Expand Down Expand Up @@ -90,4 +145,11 @@
describe '#check_refreshed' do
it { expect(executed_service.check_refreshed(action)).to eq([true, nil]) }
end

describe '#postprocess' do
it 'deletes inventory' do
expect(executed_service).to receive(:delete_inventory)
executed_service.postprocess(action)
end
end
end

0 comments on commit c76637f

Please sign in to comment.