2014-03-21 11:02:23 +00:00
require_relative " ../../../base "
2014-03-22 16:18:00 +00:00
require Vagrant . source_root . join ( " plugins/provisioners/ansible/config " )
2014-03-21 11:02:23 +00:00
require Vagrant . source_root . join ( " plugins/provisioners/ansible/provisioner " )
2014-03-29 08:19:26 +00:00
#
# Helper Functions
#
def find_last_argument_after ( ref_index , ansible_playbook_args , arg_pattern )
subset = ansible_playbook_args [ ( ref_index + 1 ) .. ( ansible_playbook_args . length - 2 ) ] . reverse
subset . each do | i |
return true if i =~ arg_pattern
end
return false
end
2014-03-21 11:02:23 +00:00
describe VagrantPlugins :: Ansible :: Provisioner do
include_context " unit "
subject { described_class . new ( machine , config ) }
let ( :iso_env ) do
2014-03-29 08:19:26 +00:00
# We have to create a Vagrantfile so there is a Vagrant Environment to provide:
# - a location for the generated inventory
# - multi-machines configuration
2014-03-21 11:02:23 +00:00
env = isolated_environment
2014-03-29 08:19:26 +00:00
env . vagrantfile ( <<-VF)
Vagrant . configure ( " 2 " ) do | config |
config . vm . box = " base "
config . vm . define :machine1
config . vm . define :machine2
end
VF
2014-03-21 11:02:23 +00:00
env . create_vagrant_env
end
let ( :machine ) { iso_env . machine ( iso_env . machine_names [ 0 ] , :dummy ) }
2014-03-22 16:18:00 +00:00
let ( :config ) { VagrantPlugins :: Ansible :: Config . new }
2014-03-21 11:02:23 +00:00
let ( :ssh_info ) { {
private_key_path : [ '/path/to/my/key' ] ,
2014-03-29 08:19:26 +00:00
username : 'testuser' ,
host : '127.0.0.1' ,
port : 2223
2014-03-21 11:02:23 +00:00
} }
2014-03-29 08:19:26 +00:00
let ( :existing_file ) { File . expand_path ( __FILE__ ) }
2014-04-12 06:29:40 +00:00
let ( :generated_inventory_dir ) { File . join ( machine . env . local_data_path , %w( provisioners ansible inventory ) ) }
let ( :generated_inventory_file ) { File . join ( generated_inventory_dir , 'vagrant_ansible_inventory' ) }
2014-03-29 08:19:26 +00:00
2014-03-21 11:02:23 +00:00
before do
2015-01-12 07:58:29 +00:00
Vagrant :: Util :: Platform . stub ( solaris? : false )
2014-11-25 07:12:43 +00:00
2014-03-21 11:02:23 +00:00
machine . stub ( ssh_info : ssh_info )
2014-03-29 08:19:26 +00:00
machine . env . stub ( active_machines : [ [ iso_env . machine_names [ 0 ] , :dummy ] , [ iso_env . machine_names [ 1 ] , :dummy ] ] )
2014-03-21 11:02:23 +00:00
2015-06-01 06:36:09 +00:00
stubbed_ui = Vagrant :: UI :: Colored . new
stubbed_ui . stub ( detail : " " )
machine . env . stub ( ui : stubbed_ui )
2014-03-22 16:18:00 +00:00
config . playbook = 'playbook.yml'
2014-03-21 11:02:23 +00:00
end
2014-03-29 08:19:26 +00:00
#
# Class methods for code reuse across examples
#
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
def self . it_should_set_arguments_and_environment_variables (
2014-12-22 04:13:14 +00:00
expected_args_count = 6 , expected_vars_count = 4 , expected_host_key_checking = false , expected_transport_mode = " ssh " )
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
2014-03-29 08:19:26 +00:00
it " sets implicit arguments in a specific order " do
2014-03-21 11:02:23 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-03-22 16:18:00 +00:00
expect ( args [ 0 ] ) . to eq ( " ansible-playbook " )
2014-12-22 04:13:14 +00:00
expect ( args [ 1 ] ) . to eq ( " --user= #{ machine . ssh_info [ :username ] } " )
expect ( args [ 2 ] ) . to eq ( " --connection=ssh " )
expect ( args [ 3 ] ) . to eq ( " --timeout=30 " )
2014-03-21 11:02:23 +00:00
2014-05-05 07:08:10 +00:00
inventory_count = args . count { | x | x =~ / ^--inventory-file=.+$ / }
2014-03-29 08:19:26 +00:00
expect ( inventory_count ) . to be > 0
2014-03-21 11:02:23 +00:00
2014-03-22 16:18:00 +00:00
expect ( args [ args . length - 2 ] ) . to eq ( " playbook.yml " )
2014-03-21 11:02:23 +00:00
}
end
2014-04-26 12:08:10 +00:00
it " sets --limit argument " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-11-30 01:02:29 +00:00
all_limits = args . select { | x | x =~ / ^(--limit=|-l) / }
2014-04-26 12:08:10 +00:00
if config . raw_arguments
2014-05-05 07:08:10 +00:00
raw_limits = config . raw_arguments . select { | x | x =~ / ^(--limit=|-l) / }
2014-11-30 01:02:29 +00:00
expect ( all_limits . length - raw_limits . length ) . to eq ( 1 )
expect ( all_limits . last ) . to eq ( raw_limits . last )
2014-04-26 12:08:10 +00:00
else
2014-11-30 01:02:29 +00:00
if config . limit
limit = config . limit . kind_of? ( Array ) ? config . limit . join ( ',' ) : config . limit
expect ( all_limits . last ) . to eq ( " --limit= #{ limit } " )
else
expect ( all_limits . first ) . to eq ( " --limit= #{ machine . name } " )
end
2014-04-26 12:08:10 +00:00
end
}
end
2014-03-29 08:19:26 +00:00
it " exports environment variables " do
2014-03-21 11:02:23 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
2014-11-30 05:55:21 +00:00
if expected_host_key_checking
2015-01-12 07:58:29 +00:00
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to_not include ( " -o UserKnownHostsFile=/dev/null " )
2014-11-30 05:55:21 +00:00
else
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o UserKnownHostsFile=/dev/null " )
end
2015-01-12 07:58:29 +00:00
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o IdentitiesOnly=yes " )
2015-06-01 06:36:09 +00:00
expect ( cmd_opts [ :env ] [ 'ANSIBLE_FORCE_COLOR' ] ) . to eql ( " true " )
expect ( cmd_opts [ :env ] ) . to_not include ( " ANSIBLE_NOCOLOR " )
2014-03-29 08:19:26 +00:00
expect ( cmd_opts [ :env ] [ 'ANSIBLE_HOST_KEY_CHECKING' ] ) . to eql ( expected_host_key_checking . to_s )
2014-03-21 11:02:23 +00:00
expect ( cmd_opts [ :env ] [ 'PYTHONUNBUFFERED' ] ) . to eql ( 1 )
}
end
2014-03-29 08:19:26 +00:00
# "roughly" verify that only expected args/vars have been defined by the provisioner
it " sets the expected number of arguments and environment variables " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( args . length - 2 ) . to eq ( expected_args_count )
expect ( args . last [ :env ] . length ) . to eq ( expected_vars_count )
}
end
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
it " enables ' #{ expected_transport_mode } ' transport mode " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
index = args . rindex ( " --connection= #{ expected_transport_mode } " )
expect ( index ) . to be > 0
expect ( find_last_argument_after ( index , args , / --connection= \ w+ / ) ) . to be_false
}
end
2014-03-21 11:02:23 +00:00
end
2014-03-29 08:19:26 +00:00
def self . it_should_set_optional_arguments ( arg_map )
it " sets optional arguments " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
arg_map . each_pair do | vagrant_option , ansible_argument |
index = args . index ( ansible_argument )
if config . send ( vagrant_option )
expect ( index ) . to be > 0
else
expect ( index ) . to be_nil
end
end
}
end
end
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
def self . it_should_explicitly_enable_ansible_ssh_control_persist_defaults
2014-03-29 08:19:26 +00:00
it " configures ControlPersist (like Ansible defaults) via ANSIBLE_SSH_ARGS " do
2014-03-21 11:02:23 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o ControlMaster=auto " )
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o ControlPersist=60s " )
}
end
end
2014-03-29 08:19:26 +00:00
def self . it_should_create_and_use_generated_inventory
it " generates an inventory with all active machines " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( config . inventory_path ) . to be_nil
expect ( File . exists? ( generated_inventory_file ) ) . to be_true
inventory_content = File . read ( generated_inventory_file )
2015-08-29 09:00:20 +00:00
expect ( inventory_content ) . to include ( " #{ machine . name } ansible_ssh_host= #{ machine . ssh_info [ :host ] } ansible_ssh_port= #{ machine . ssh_info [ :port ] } ansible_ssh_private_key_file=' #{ machine . ssh_info [ :private_key_path ] [ 0 ] } ' \n " )
2014-03-29 08:19:26 +00:00
expect ( inventory_content ) . to include ( " # MISSING: ' #{ iso_env . machine_names [ 1 ] } ' machine was probably removed without using Vagrant. This machine should be recreated. \n " )
}
end
2014-04-12 06:29:40 +00:00
it " sets as ansible inventory the directory containing the auto-generated inventory file " do
2014-03-29 08:19:26 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-04-12 06:29:40 +00:00
inventory_index = args . rindex ( " --inventory-file= #{ generated_inventory_dir } " )
2014-03-29 08:19:26 +00:00
expect ( inventory_index ) . to be > 0
expect ( find_last_argument_after ( inventory_index , args , / --inventory-file= \ w+ / ) ) . to be_false
}
end
end
2014-03-21 11:02:23 +00:00
describe " # provision " do
before do
2014-03-22 16:18:00 +00:00
unless example . metadata [ :skip_before ]
config . finalize!
Vagrant :: Util :: Subprocess . stub ( execute : Vagrant :: Util :: Subprocess :: Result . new ( 0 , " " , " " ) )
end
end
after do
unless example . metadata [ :skip_after ]
subject . provision
end
2014-03-21 11:02:23 +00:00
end
2014-03-29 08:19:26 +00:00
describe 'when ansible-playbook fails' do
it " raises an error " , skip_before : true , skip_after : true do
config . finalize!
Vagrant :: Util :: Subprocess . stub ( execute : Vagrant :: Util :: Subprocess :: Result . new ( 1 , " " , " " ) )
expect { subject . provision } . to raise_error ( Vagrant :: Errors :: AnsibleFailed )
end
2014-03-21 11:02:23 +00:00
end
2014-03-29 08:19:26 +00:00
describe " with default options " do
it_should_set_arguments_and_environment_variables
it_should_create_and_use_generated_inventory
2014-03-21 11:02:23 +00:00
2014-03-29 08:19:26 +00:00
it " does not add any group section to the generated inventory " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
inventory_content = File . read ( generated_inventory_file )
expect ( inventory_content ) . to_not match ( / ^ \ s* \ [^ \\ + \ ] \ s*$ / )
# Note:
# The expectation below is a workaround to a possible misuse (or bug) in RSpec/Ruby stack.
# If 'args' variable is not required by in this block, the "Vagrant::Util::Subprocess).to receive"
# surprisingly expects to receive "no args".
# This problem can be "solved" by using args the "unnecessary" (but harmless) expectation below:
expect ( args . length ) . to be > 0
}
end
2014-03-31 14:25:16 +00:00
it " does not show the ansible-playbook command " do
expect ( machine . env . ui ) . not_to receive ( :detail ) . with { | full_command |
expect ( full_command ) . to include ( " ansible-playbook " )
}
end
2014-03-21 11:02:23 +00:00
end
2014-03-29 08:19:26 +00:00
describe " with groups option " do
it_should_create_and_use_generated_inventory
it " adds group sections to the generated inventory " do
config . groups = {
" group1 " = > " #{ machine . name } " ,
" group1:children " = > 'bar' ,
2014-04-25 20:11:13 +00:00
" group2 " = > [ iso_env . machine_names [ 1 ] ] ,
2014-03-29 08:19:26 +00:00
" group3 " = > [ " unknown " , " #{ machine . name } " ] ,
" bar " = > [ " #{ machine . name } " , " group3 " ] ,
" bar:children " = > [ " group1 " , " group2 " , " group3 " , " group4 " ] ,
" bar:vars " = > [ " myvar=foo " ] ,
}
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
inventory_content = File . read ( generated_inventory_file )
# Group variables are intentionally not supported in generated inventory
expect ( inventory_content ) . not_to match ( / ^ \ [.*:vars \ ]$ / )
# Accept String instead of Array for group that contains a single item
expect ( inventory_content ) . to include ( " [group1] \n #{ machine . name } \n " )
expect ( inventory_content ) . to include ( " [group1:children] \n bar \n " )
# Skip "lost" machines
expect ( inventory_content ) . to include ( " [group2] \n \n " )
2014-03-22 16:18:00 +00:00
2014-03-29 08:19:26 +00:00
# Skip "unknown" machines
expect ( inventory_content ) . to include ( " [group3] \n #{ machine . name } \n " )
2014-03-21 11:02:23 +00:00
2014-03-29 08:19:26 +00:00
# Don't mix group names and host names
expect ( inventory_content ) . to include ( " [bar] \n #{ machine . name } \n " )
# A group of groups only includes declared groups
expect ( inventory_content ) . not_to match ( / ^group4$ / )
expect ( inventory_content ) . to include ( " [bar:children] \n group1 \n group2 \n group3 \n " )
}
end
end
describe " with host_key_checking option enabled " do
before do
2014-04-12 09:00:34 +00:00
config . host_key_checking = true
2014-03-29 08:19:26 +00:00
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 6 , 4 , true
2014-03-29 08:19:26 +00:00
end
describe " with boolean (flag) options disabled " do
before do
config . sudo = false
config . ask_sudo_pass = false
2014-04-14 08:29:10 +00:00
config . ask_vault_pass = false
2014-03-29 08:19:26 +00:00
config . sudo_user = 'root'
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 7
2014-03-29 08:19:26 +00:00
it_should_set_optional_arguments ( { " sudo_user " = > " --sudo-user=root " } )
it " it does not set boolean flag when corresponding option is set to false " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( args . index ( " --sudo " ) ) . to be_nil
expect ( args . index ( " --ask-sudo-pass " ) ) . to be_nil
2014-04-14 08:29:10 +00:00
expect ( args . index ( " --ask-vault-pass " ) ) . to be_nil
2014-03-29 08:19:26 +00:00
}
end
end
describe " with raw_arguments option " do
before do
config . sudo = false
config . skip_tags = %w( foo bar )
2014-11-30 01:02:29 +00:00
config . limit = " all "
2014-03-29 08:19:26 +00:00
config . raw_arguments = [ " --connection=paramiko " ,
" --skip-tags=ignored " ,
" --module-path=/other/modules " ,
" --sudo " ,
2014-04-26 12:08:10 +00:00
" -l localhost " ,
" --limit=foo " ,
" --limit=bar " ,
2014-03-29 08:19:26 +00:00
" --inventory-file=/forget/it/my/friend " ,
2014-11-30 01:02:29 +00:00
" --user=lion " ,
2014-03-29 08:19:26 +00:00
" --new-arg=yeah " ]
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 17 , 4 , false , " paramiko "
2014-03-29 08:19:26 +00:00
it " sets all raw arguments " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
config . raw_arguments . each do | raw_arg |
expect ( args ) . to include ( raw_arg )
end
}
end
2014-11-30 01:02:29 +00:00
it " sets raw arguments after arguments related to supported options " do
2014-03-29 08:19:26 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-11-30 01:02:29 +00:00
expect ( args . index ( " --user=lion " ) ) . to be > args . index ( " --user=testuser " )
expect ( args . index ( " --inventory-file=/forget/it/my/friend " ) ) . to be > args . index ( " --inventory-file= #{ generated_inventory_dir } " )
expect ( args . index ( " --limit=bar " ) ) . to be > args . index ( " --limit=all " )
expect ( args . index ( " --skip-tags=ignored " ) ) . to be > args . index ( " --skip-tags=foo,bar " )
2014-03-29 08:19:26 +00:00
}
end
it " sets boolean flag (e.g. --sudo) defined in raw_arguments, even if corresponding option is set to false " do
2014-03-21 11:02:23 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-03-29 08:19:26 +00:00
expect ( args ) . to include ( '--sudo' )
}
end
end
describe " with limit option " do
before do
config . limit = %w( foo !bar )
end
2014-04-26 12:08:10 +00:00
it_should_set_arguments_and_environment_variables
2014-03-22 16:18:00 +00:00
end
describe " with inventory_path option " do
before do
2014-03-29 08:19:26 +00:00
config . inventory_path = existing_file
end
it_should_set_arguments_and_environment_variables
it " does not generate the inventory and uses given inventory path instead " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( args ) . to include ( " --inventory-file= #{ existing_file } " )
expect ( args ) . not_to include ( " --inventory-file= #{ generated_inventory_file } " )
expect ( File . exists? ( generated_inventory_file ) ) . to be_false
}
end
end
2014-04-14 08:29:10 +00:00
describe " with ask_vault_pass option " do
before do
config . ask_vault_pass = true
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 7
2014-04-14 08:29:10 +00:00
it " should ask the vault password " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( args ) . to include ( " --ask-vault-pass " )
}
end
end
describe " with vault_password_file option " do
before do
config . vault_password_file = existing_file
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 7
2014-04-14 08:29:10 +00:00
it " uses the given vault password file " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
expect ( args ) . to include ( " --vault-password-file= #{ existing_file } " )
}
end
end
2014-03-29 08:19:26 +00:00
describe " with raw_ssh_args " do
before do
2014-05-04 19:25:43 +00:00
config . raw_ssh_args = [ '-o ControlMaster=no' , '-o ForwardAgent=no' ]
2014-03-22 16:18:00 +00:00
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 6 , 4
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
2014-03-22 16:18:00 +00:00
2014-03-29 08:19:26 +00:00
it " passes custom SSH options via ANSIBLE_SSH_ARGS with the highest priority " do
2014-03-22 16:18:00 +00:00
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2014-03-29 08:19:26 +00:00
cmd_opts = args . last
raw_opt_index = cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] . index ( " -o ControlMaster=no " )
default_opt_index = cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] . index ( " -o ControlMaster=auto " )
expect ( raw_opt_index ) . to be < default_opt_index
2014-03-21 11:02:23 +00:00
}
end
2014-03-29 08:19:26 +00:00
2014-05-04 19:25:43 +00:00
describe " and with ssh forwarding enabled " do
before do
ssh_info [ :forward_agent ] = true
end
it " sets '-o ForwardAgent=yes' via ANSIBLE_SSH_ARGS with higher priority than raw_ssh_args values " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
forwardAgentYes = cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] . index ( " -o ForwardAgent=yes " )
forwardAgentNo = cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] . index ( " -o ForwardAgent=no " )
expect ( forwardAgentYes ) . to be < forwardAgentNo
}
end
end
2014-03-21 11:02:23 +00:00
end
describe " with multiple SSH identities " do
before do
ssh_info [ :private_key_path ] = [ '/path/to/my/key' , '/an/other/identity' , '/yet/an/other/key' ]
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 6 , 4
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
2014-03-21 11:02:23 +00:00
it " passes additional Identity Files via ANSIBLE_SSH_ARGS " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o IdentityFile=/an/other/identity " )
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o IdentityFile=/yet/an/other/key " )
}
end
end
describe " with ssh forwarding enabled " do
before do
ssh_info [ :forward_agent ] = true
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 6 , 4
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
2014-03-21 11:02:23 +00:00
it " enables SSH-Forwarding via ANSIBLE_SSH_ARGS " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o ForwardAgent=yes " )
}
end
end
2014-03-31 14:25:16 +00:00
describe " with verbose option " do
before do
config . verbose = 'v'
end
2014-12-22 04:13:14 +00:00
it_should_set_arguments_and_environment_variables 7
2014-03-31 14:25:16 +00:00
it_should_set_optional_arguments ( { " verbose " = > " -v " } )
it " shows the ansible-playbook command " do
expect ( machine . env . ui ) . to receive ( :detail ) . with { | full_command |
2014-12-22 04:13:14 +00:00
expect ( full_command ) . to eq ( " PYTHONUNBUFFERED=1 ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_FORCE_COLOR=true ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --user=testuser --connection=ssh --timeout=30 --limit='machine1' --inventory-file= #{ generated_inventory_dir } -v playbook.yml " )
2015-06-01 06:36:09 +00:00
}
end
end
describe " without colorized output " do
before do
machine . env . stub ( ui : Vagrant :: UI :: Basic . new )
end
it " disables ansible-playbook colored output " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] ) . to_not include ( " ANSIBLE_FORCE_COLOR " )
expect ( cmd_opts [ :env ] [ 'ANSIBLE_NOCOLOR' ] ) . to eql ( " true " )
2014-03-31 14:25:16 +00:00
}
end
end
2014-03-29 08:19:26 +00:00
# Note:
2014-04-16 20:26:19 +00:00
# The Vagrant Ansible provisioner does not validate the coherency of argument combinations,
2014-04-25 19:59:39 +00:00
# and let ansible-playbook complain.
2014-03-29 08:19:26 +00:00
describe " with a maximum of options " do
before do
2014-03-31 14:25:16 +00:00
# vagrant general options
ssh_info [ :forward_agent ] = true
ssh_info [ :private_key_path ] = [ '/my/key1' , '/my/key2' ]
2014-03-29 08:19:26 +00:00
# command line arguments
config . extra_vars = " @ #{ existing_file } "
config . sudo = true
config . sudo_user = 'deployer'
config . verbose = " vvv "
config . ask_sudo_pass = true
2014-04-25 19:59:39 +00:00
config . ask_vault_pass = true
config . vault_password_file = existing_file
2014-03-29 08:19:26 +00:00
config . tags = %w( db www )
config . skip_tags = %w( foo bar )
config . limit = 'machine*:&vagrant:!that_one'
config . start_at_task = 'an awesome task'
2015-05-29 08:18:21 +00:00
config . raw_arguments = [ " --why-not " , " --su-user=foot " , " --ask-su-pass " , " --limit=all " , " --private-key=./myself.key " ]
2014-03-29 08:19:26 +00:00
# environment variables
config . host_key_checking = true
config . raw_ssh_args = [ '-o ControlMaster=no' ]
end
2015-05-29 08:18:21 +00:00
it_should_set_arguments_and_environment_variables 21 , 4 , true
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
2014-04-25 19:59:39 +00:00
it_should_set_optional_arguments ( { " extra_vars " = > " --extra-vars=@ #{ File . expand_path ( __FILE__ ) } " ,
" sudo " = > " --sudo " ,
" sudo_user " = > " --sudo-user=deployer " ,
" verbose " = > " -vvv " ,
" ask_sudo_pass " = > " --ask-sudo-pass " ,
" ask_vault_pass " = > " --ask-vault-pass " ,
" vault_password_file " = > " --vault-password-file= #{ File . expand_path ( __FILE__ ) } " ,
" tags " = > " --tags=db,www " ,
" skip_tags " = > " --skip-tags=foo,bar " ,
" limit " = > " --limit=machine*:&vagrant:!that_one " ,
" start_at_task " = > " --start-at-task=an awesome task " ,
2014-03-29 08:19:26 +00:00
} )
provisioners/ansible: force --connection=ssh
When `--connection` argument is not specified, Ansible will use the
'smart' mode, which can either use `ssh` or `paramiko` transports,
depending of the version of OpenSSH available. If OpenSSH version is new
enough to support ControlPersist technology, `ssh` will be used.
See also http://docs.ansible.com/intro_configuration.html#transport.
In order to support some advanced features of Vagrant (e.g. multiple ssh
private key identities or ssh forwarding), the Ansible provisioner
already must force `ssh` connection mode.
Having to deal with the possible fallback to `paramiko` increase the
burden of special cases that Ansible provisioner must handle, without
any added value, as Vagrant is based on OpenSSH and its users are
usually using modern operating systems.
With this change, the Ansible provisioner will officially only support
`ssh`. It will still be possible to switch to another connection mode
via `raw_arguments`, but it will breach the "contract", and no
(community) support can be expected in such use case.
ref #3900, #3396
2014-11-29 22:29:46 +00:00
2014-04-25 19:59:39 +00:00
it " also includes given raw arguments " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
2015-05-29 08:18:21 +00:00
expect ( args ) . to include ( " --why-not " )
2014-04-25 19:59:39 +00:00
expect ( args ) . to include ( " --su-user=foot " )
expect ( args ) . to include ( " --ask-su-pass " )
2015-05-29 08:18:21 +00:00
expect ( args ) . to include ( " --limit=all " )
expect ( args ) . to include ( " --private-key=./myself.key " )
2014-04-25 19:59:39 +00:00
}
end
2014-03-31 14:25:16 +00:00
it " shows the ansible-playbook command, with additional quotes when required " do
expect ( machine . env . ui ) . to receive ( :detail ) . with { | full_command |
2015-05-29 08:18:21 +00:00
expect ( full_command ) . to eq ( " PYTHONUNBUFFERED=1 ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_FORCE_COLOR=true ANSIBLE_SSH_ARGS='-o IdentitiesOnly=yes -o IdentityFile=/my/key1 -o IdentityFile=/my/key2 -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --user=testuser --connection=ssh --timeout=30 --limit='machine*:&vagrant:!that_one' --inventory-file= #{ generated_inventory_dir } --extra-vars=@ #{ File . expand_path ( __FILE__ ) } --sudo --sudo-user=deployer -vvv --ask-sudo-pass --ask-vault-pass --vault-password-file= #{ File . expand_path ( __FILE__ ) } --tags=db,www --skip-tags=foo,bar --start-at-task='an awesome task' --why-not --su-user=foot --ask-su-pass --limit='all' --private-key=./myself.key playbook.yml " )
2014-03-31 14:25:16 +00:00
}
end
2014-03-29 08:19:26 +00:00
end
2015-01-12 08:37:16 +00:00
#
# Special cases related to the VM provider context
#
context " with Docker provider on a non-Linux host " do
2015-05-29 08:36:17 +00:00
2015-01-12 08:37:16 +00:00
let ( :fake_host_ssh_info ) { {
private_key_path : [ '/path/to/docker/host/key' ] ,
username : 'boot9docker' ,
host : '127.0.0.1' ,
port : 2299
} }
let ( :fake_host_vm ) {
double ( " host_vm " ) . tap do | h |
h . stub ( ssh_info : fake_host_ssh_info )
2015-05-29 08:36:17 +00:00
end
2015-01-12 08:37:16 +00:00
}
before do
machine . stub ( provider_name : :docker )
machine . provider . stub ( host_vm? : true )
machine . provider . stub ( host_vm : fake_host_vm )
end
it " uses an SSH ProxyCommand to reach the VM " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to include ( " -o ProxyCommand='ssh boot9docker@127.0.0.1 -p 2299 -i /path/to/docker/host/key -o Compression=yes -o ConnectTimeout=5 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no exec nc %h %p 2>/dev/null' " )
}
end
end
2015-01-12 07:58:29 +00:00
#
# Special cases related to the Vagrant Host operating system in use
#
context " with a Solaris-like host " do
before do
Vagrant :: Util :: Platform . stub ( solaris? : true )
end
it " does not set IdentitiesOnly=yes in ANSIBLE_SSH_ARGS " do
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] [ 'ANSIBLE_SSH_ARGS' ] ) . to_not include ( " -o IdentitiesOnly=yes " )
# Note:
# The expectation below is a workaround to a possible misuse (or bug) in RSpec/Ruby stack.
# If 'args' variable is not required by in this block, the "Vagrant::Util::Subprocess).to receive"
# surprisingly expects to receive "no args".
# This problem can be "solved" by using args the "unnecessary" (but harmless) expectation below:
expect ( true ) . to be_true
}
end
describe " and with host_key_checking option enabled " do
it " does not set ANSIBLE_SSH_ARGS environment variable " do
config . host_key_checking = true
expect ( Vagrant :: Util :: Subprocess ) . to receive ( :execute ) . with { | * args |
cmd_opts = args . last
expect ( cmd_opts [ :env ] ) . to_not include ( 'ANSIBLE_SSH_ARGS' )
# Note:
# The expectation below is a workaround to a possible misuse (or bug) in RSpec/Ruby stack.
# If 'args' variable is not required by in this block, the "Vagrant::Util::Subprocess).to receive"
# surprisingly expects to receive "no args".
# This problem can be "solved" by using args the "unnecessary" (but harmless) expectation below:
expect ( true ) . to be_true
}
end
end
end
2014-03-21 11:02:23 +00:00
end
end