diff --git a/.rubocop.yml b/.rubocop.yml index eeeaf25..a6cb5cc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -39,3 +39,6 @@ Metrics/CyclomaticComplexity: # Offense count: 3 Metrics/PerceivedComplexity: Max: 30 + +Metrics/ClassLength: + Max: 260 \ No newline at end of file diff --git a/README.md b/README.md index c56018e..07faf14 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,11 @@ gem install kitchen-ansiblepush-.gem provisioner : ## required options name : ansible_push + ## Either `playbook` or `playbooks` is required playbook : "../../plays/web.yml" # Path to Play yaml + playbooks : + - "../../plays/database.yml" # Path to database play yaml + - "../../plays/web.yml" # Path to web play yaml ## ## Optional argument ansible_config : "/path/to/ansible/ansible.cfg" # path to ansible config file diff --git a/lib/kitchen-ansible/idempotancy.rb b/lib/kitchen-ansible/idempotancy.rb index 6c354c6..531530a 100644 --- a/lib/kitchen-ansible/idempotancy.rb +++ b/lib/kitchen-ansible/idempotancy.rb @@ -2,13 +2,21 @@ def idempotency_test info('*************** idempotency test ***************') + conf[:playbooks].each do |playbook| + _idempotency_test_single(playbook) + end +end + +def _idempotency_test_single(playbook) file_path = "/tmp/kitchen_ansible_callback/#{SecureRandom.uuid}.changes" exec_ansible_command( command_env.merge( 'ANSIBLE_CALLBACK_PLUGINS' => "#{File.dirname(__FILE__)}/../../callback/", 'ANSIBLE_CALLBACK_WHITELIST' => 'changes', 'PLUGIN_CHANGES_FILE' => file_path - ), command, 'ansible-playbook' + ), + command(playbook), + 'ansible-playbook' ) debug("idempotency file #{file_path}") # Check ansible callback if changes has occured in the second run diff --git a/lib/kitchen/provisioner/ansible_push.rb b/lib/kitchen/provisioner/ansible_push.rb index 567ade1..1fd1a9a 100644 --- a/lib/kitchen/provisioner/ansible_push.rb +++ b/lib/kitchen/provisioner/ansible_push.rb @@ -39,6 +39,7 @@ class AnsiblePush < Base default_config :host_key_checking, false default_config :mygroup, nil default_config :playbook, nil + default_config :playbooks, [] default_config :generate_inv, true default_config :generate_inv_path, '`which kitchen-ansible-inventory`' default_config :raw_arguments, nil @@ -66,9 +67,24 @@ class AnsiblePush < Base def conf return @validated_config if defined? @validated_config - raise UserError, 'No playbook defined. Please specify one in .kitchen.yml' unless config[:playbook] + unless config[:playbooks].is_a?(Array) + raise UserError, + "ansible playbooks is not an `Array` type. Given type: #{config[:playbooks].class}" + end + + playbooks_to_run = config[:playbooks].clone + + if config[:playbooks] && config[:playbook] + playbooks_to_run << config[:playbook] + end - raise UserError, "playbook '#{config[:playbook]}' could not be found. Please check path" unless File.exist?(config[:playbook]) + if !playbooks_to_run || playbooks_to_run.empty? + raise UserError, 'No `playbook` or `playbooks` defined. Please specify one in .kitchen.yml' + end + + playbooks_to_run.each do |playbook| + raise UserError, "playbook '#{config[:playbook]}' could not be found. Please check path" unless File.exist?(playbook) + end if config[:vault_password_file] && !File.exist?(config[:vault_password_file]) raise UserError, "Vault password '#{config[:vault_password_file]}' could not be found. Please check path" @@ -167,10 +183,9 @@ def options @options = options end - def command - return @command if defined? @command + def command(playbook) @command = [conf[:ansible_playbook_bin]] - @command = (@command << options << conf[:playbook]).flatten.join(' ') + @command = (@command << options << playbook).flatten.join(' ') debug("Ansible push command= #{@command}") @command end @@ -209,7 +224,7 @@ def true_command def install_command info('*************** AnsiblePush install_command ***************') # Test if ansible-playbook is installed and give a meaningful error message - version_check = command + ' --version' + version_check = command(conf[:playbooks].first) + ' --version' _, stdout, stderr, wait_thr = Open3.popen3(command_env, version_check) exit_status = wait_thr.value raise UserError, "#{version_check} returned a non zero '#{exit_status}' stdout : '#{stdout.read}', stderr: '#{stderr.read}'" unless exit_status.success? @@ -232,8 +247,11 @@ def chef_installation(chef_url, omnibus_download_dir) def run_command info('*************** AnsiblePush run ***************') - exec_ansible_command(command_env, command, 'ansible-playbook') - idempotency_test if conf[:idempotency_test] + conf[:playbooks].each do |playbook| + exec_ansible_command(command_env, command(playbook), 'ansible-playbook') + idempotency_test if conf[:idempotency_test] + end + info('*************** AnsiblePush end run *******************') debug("[#{name}] Converge completed (#{conf[:sleep]}s).") true_command # Place holder so a string is returned. This will execute true on remote host diff --git a/spec/kitchen/provisioner/ansible_push_spec.rb b/spec/kitchen/provisioner/ansible_push_spec.rb index 6b9b9f2..30b72d5 100644 --- a/spec/kitchen/provisioner/ansible_push_spec.rb +++ b/spec/kitchen/provisioner/ansible_push_spec.rb @@ -24,7 +24,14 @@ end let(:instance) do - instance_double('Kitchen::Instance', name: 'coolbeans', logger: logger, suite: suite, platform: platform) + double = instance_double( + 'Kitchen::Instance', + name: 'coolbeans', + logger: logger, + suite: suite, + platform: platform + ) + double end # let(:machine_name) do @@ -39,11 +46,11 @@ expect(provisioner.diagnose_plugin[:api_version]).to eq(2) end - it 'Should fail with no playbook file' do + it "fails with no 'playbook' and 'playbooks' specified" do expect { provisioner.prepare_command }.to raise_error(Kitchen::UserError) end - describe 'Baisc config' do + describe 'Basic config' do let(:config) do { test_base_path: '/b',