parent
b9738a8c4c
commit
c1f3d114f5
|
@ -4,6 +4,9 @@ module VagrantPlugins
|
|||
class Base < Vagrant.plugin("2", :config)
|
||||
|
||||
attr_accessor :extra_vars
|
||||
attr_accessor :galaxy_role_file
|
||||
attr_accessor :galaxy_roles_path
|
||||
attr_accessor :galaxy_command
|
||||
attr_accessor :groups
|
||||
attr_accessor :inventory_path
|
||||
attr_accessor :limit
|
||||
|
@ -19,6 +22,9 @@ module VagrantPlugins
|
|||
|
||||
def initialize
|
||||
@extra_vars = UNSET_VALUE
|
||||
@galaxy_role_file = UNSET_VALUE
|
||||
@galaxy_roles_path = UNSET_VALUE
|
||||
@galaxy_command = UNSET_VALUE
|
||||
@groups = UNSET_VALUE
|
||||
@inventory_path = UNSET_VALUE
|
||||
@limit = UNSET_VALUE
|
||||
|
@ -35,6 +41,9 @@ module VagrantPlugins
|
|||
|
||||
def finalize!
|
||||
@extra_vars = nil if @extra_vars == UNSET_VALUE
|
||||
@galaxy_role_file = nil if @galaxy_role_file == UNSET_VALUE
|
||||
@galaxy_roles_path = nil if @galaxy_roles_path == UNSET_VALUE
|
||||
@galaxy_command = "ansible-galaxy install --role-file=%{ROLE_FILE} --roles-path=%{ROLES_PATH} --force" if @galaxy_command == UNSET_VALUE
|
||||
@groups = {} if @groups == UNSET_VALUE
|
||||
@inventory_path = nil if @inventory_path == UNSET_VALUE
|
||||
@limit = nil if @limit == UNSET_VALUE
|
||||
|
@ -68,6 +77,10 @@ module VagrantPlugins
|
|||
check_path_exists(machine, inventory_path, "vagrant.provisioners.ansible.errors.inventory_path_invalid")
|
||||
end
|
||||
|
||||
if galaxy_role_file
|
||||
check_path_is_a_file(machine, galaxy_role_file, "vagrant.provisioners.ansible.errors.galaxy_role_file_invalid")
|
||||
end
|
||||
|
||||
if vault_password_file
|
||||
check_path_is_a_file(machine, vault_password_file, "vagrant.provisioners.ansible.errors.vault_password_file_invalid")
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ module VagrantPlugins
|
|||
error_namespace("vagrant.provisioners.ansible.errors")
|
||||
end
|
||||
|
||||
class AnsiblePlaybookAppFailed < AnsibleError
|
||||
class AnsibleCommandFailed < AnsibleError
|
||||
error_key(:ansible_command_failed)
|
||||
end
|
||||
|
||||
|
|
|
@ -132,6 +132,26 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def get_galaxy_role_file(basedir)
|
||||
Pathname.new(config.galaxy_role_file).expand_path(basedir)
|
||||
end
|
||||
|
||||
def get_galaxy_roles_path(basedir)
|
||||
if config.galaxy_roles_path
|
||||
Pathname.new(config.galaxy_roles_path).expand_path(basedir)
|
||||
else
|
||||
File.join(Pathname.new(config.playbook).expand_path(basedir).parent, 'roles')
|
||||
end
|
||||
end
|
||||
|
||||
def ui_running_ansible_command(name, command)
|
||||
@machine.ui.detail I18n.t("vagrant.provisioners.ansible.running_#{name}")
|
||||
if verbosity_is_enabled?
|
||||
# Show the ansible command in use
|
||||
@machine.env.ui.detail(command)
|
||||
end
|
||||
end
|
||||
|
||||
def verbosity_is_enabled?
|
||||
config.verbose && !config.verbose.to_s.empty?
|
||||
end
|
||||
|
|
|
@ -14,8 +14,7 @@ module VagrantPlugins
|
|||
|
||||
def provision
|
||||
check_and_install_ansible
|
||||
prepare_common_command_arguments
|
||||
prepare_common_environment_variables
|
||||
execute_ansible_galaxy_on_guest if config.galaxy_role_file
|
||||
execute_ansible_playbook_on_guest
|
||||
end
|
||||
|
||||
|
@ -51,9 +50,9 @@ module VagrantPlugins
|
|||
@machine.guest.capability(:ansible_install)
|
||||
end
|
||||
|
||||
# Check for the existence of ansible-playbook binary on the guest,
|
||||
# Check that ansible binaries are well installed on the guest,
|
||||
@machine.communicate.execute(
|
||||
"ansible-playbook --help",
|
||||
"ansible-galaxy --help && ansible-playbook --help",
|
||||
:error_class => Ansible::Errors::AnsibleNotFoundOnGuest,
|
||||
:error_key => :ansible_not_found_on_guest)
|
||||
|
||||
|
@ -65,15 +64,27 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def execute_ansible_galaxy_on_guest
|
||||
command_values = {
|
||||
:ROLE_FILE => get_galaxy_role_file(config.provisioning_path),
|
||||
:ROLES_PATH => get_galaxy_roles_path(config.provisioning_path)
|
||||
}
|
||||
remote_command = config.galaxy_command % command_values
|
||||
|
||||
ui_running_ansible_command "galaxy", remote_command
|
||||
|
||||
result = execute_on_guest(remote_command)
|
||||
raise Ansible::Errors::AnsibleGalaxyAppFailed if result != 0
|
||||
end
|
||||
|
||||
def execute_ansible_playbook_on_guest
|
||||
prepare_common_command_arguments
|
||||
prepare_common_environment_variables
|
||||
|
||||
command = (%w(ansible-playbook) << @command_arguments << config.playbook).flatten
|
||||
remote_command = "cd #{config.provisioning_path} && #{Helpers::stringify_ansible_playbook_command(@environment_variables, command)}"
|
||||
|
||||
# TODO: generic HOOK ???
|
||||
# Show the ansible command in use
|
||||
if verbosity_is_enabled?
|
||||
@machine.env.ui.detail(remote_command)
|
||||
end
|
||||
ui_running_ansible_command "playbook", remote_command
|
||||
|
||||
result = execute_on_guest(remote_command)
|
||||
raise Ansible::Errors::AnsiblePlaybookAppFailed if result != 0
|
||||
|
|
|
@ -19,8 +19,7 @@ module VagrantPlugins
|
|||
@ssh_info = @machine.ssh_info
|
||||
|
||||
warn_for_unsupported_platform
|
||||
prepare_command_arguments
|
||||
prepare_environment_variables
|
||||
execute_ansible_galaxy_from_host if config.galaxy_role_file
|
||||
execute_ansible_playbook_from_host
|
||||
end
|
||||
|
||||
|
@ -72,33 +71,57 @@ module VagrantPlugins
|
|||
@environment_variables["ANSIBLE_SSH_ARGS"] = ansible_ssh_args unless ansible_ssh_args.empty?
|
||||
end
|
||||
|
||||
def execute_ansible_playbook_from_host
|
||||
# Assemble the full ansible-playbook command
|
||||
command = (%w(ansible-playbook) << @command_arguments << config.playbook).flatten
|
||||
|
||||
# TODO: generic HOOK ???
|
||||
# Show the ansible command in use
|
||||
if verbosity_is_enabled?
|
||||
@machine.env.ui.detail(Helpers::stringify_ansible_playbook_command(@environment_variables, command))
|
||||
def execute_command_from_host(command)
|
||||
begin
|
||||
result = Vagrant::Util::Subprocess.execute(*command) do |type, data|
|
||||
if type == :stdout || type == :stderr
|
||||
@machine.env.ui.detail(data, new_line: false, prefix: false)
|
||||
end
|
||||
end
|
||||
raise Ansible::Errors::AnsibleCommandFailed if result.exit_code != 0
|
||||
rescue Vagrant::Errors::CommandUnavailable
|
||||
raise Ansible::Errors::AnsibleNotFoundOnHost
|
||||
end
|
||||
end
|
||||
|
||||
# Write stdout and stderr data, since it's the regular Ansible output
|
||||
def execute_ansible_galaxy_from_host
|
||||
command_values = {
|
||||
:ROLE_FILE => get_galaxy_role_file(machine.env.root_path),
|
||||
:ROLES_PATH => get_galaxy_roles_path(machine.env.root_path)
|
||||
}
|
||||
arg_separator = '__VAGRANT_ARG_SEPARATOR__'
|
||||
command_template = config.galaxy_command.gsub(' ', arg_separator)
|
||||
str_command = command_template % command_values
|
||||
|
||||
ui_running_ansible_command "galaxy", str_command.gsub(arg_separator, ' ')
|
||||
|
||||
command = str_command.split(arg_separator)
|
||||
command << {
|
||||
env: @environment_variables,
|
||||
# Write stdout and stderr data, since it's the regular Ansible output
|
||||
notify: [:stdout, :stderr],
|
||||
workdir: @machine.env.root_path.to_s
|
||||
}
|
||||
|
||||
begin
|
||||
result = Vagrant::Util::Subprocess.execute(*command) do |type, data|
|
||||
if type == :stdout || type == :stderr
|
||||
@machine.env.ui.info(data, new_line: false, prefix: false)
|
||||
end
|
||||
end
|
||||
raise Ansible::Errors::AnsiblePlaybookAppFailed if result.exit_code != 0
|
||||
rescue Vagrant::Errors::CommandUnavailable
|
||||
raise Ansible::Errors::AnsibleNotFoundOnHost
|
||||
end
|
||||
execute_command_from_host command
|
||||
end
|
||||
|
||||
def execute_ansible_playbook_from_host
|
||||
prepare_command_arguments
|
||||
prepare_environment_variables
|
||||
|
||||
# Assemble the full ansible-playbook command
|
||||
command = (%w(ansible-playbook) << @command_arguments << config.playbook).flatten
|
||||
|
||||
ui_running_ansible_command "playbook", Helpers::stringify_ansible_playbook_command(@environment_variables, command)
|
||||
|
||||
command << {
|
||||
env: @environment_variables,
|
||||
# Write stdout and stderr data, since it's the regular Ansible output
|
||||
notify: [:stdout, :stderr],
|
||||
workdir: @machine.env.root_path.to_s
|
||||
}
|
||||
|
||||
execute_command_from_host command
|
||||
end
|
||||
|
||||
def ship_generated_inventory(inventory_content)
|
||||
|
|
|
@ -2072,6 +2072,8 @@ en:
|
|||
for more information.
|
||||
extra_vars_invalid: |-
|
||||
`extra_vars` must be a hash or a path to an existing file. Received: %{value} (as %{type})
|
||||
galaxy_role_file_invalid: |-
|
||||
`galaxy_role_file` does not exist on the %{system}: %{path}
|
||||
inventory_path_invalid: |-
|
||||
`inventory_path` does not exist on the %{system}: %{path}
|
||||
no_playbook: |-
|
||||
|
@ -2081,6 +2083,7 @@ en:
|
|||
vault_password_file_invalid: |-
|
||||
`vault_password_file` does not exist on the %{system}: %{path}
|
||||
installing: "Installing Ansible..."
|
||||
running_galaxy: "Running ansible-galaxy..."
|
||||
running_playbook: "Running ansible-playbook..."
|
||||
windows_not_supported_for_control_machine: |-
|
||||
Windows is not officially supported for the Ansible Control Machine.
|
||||
|
|
|
@ -20,6 +20,9 @@ describe VagrantPlugins::Ansible::Config::Host do
|
|||
ask_vault_pass
|
||||
extra_vars
|
||||
force_remote_user
|
||||
galaxy_command
|
||||
galaxy_role_file
|
||||
galaxy_roles_path
|
||||
groups
|
||||
host_key_checking
|
||||
inventory_path
|
||||
|
@ -176,6 +179,16 @@ describe VagrantPlugins::Ansible::Config::Host do
|
|||
expect(result["ansible remote provisioner"]).to eql([
|
||||
I18n.t("vagrant.provisioners.ansible.errors.vault_password_file_invalid",
|
||||
path: non_existing_file, system: "host")
|
||||
])
|
||||
end
|
||||
|
||||
it "returns an error if galaxy_role_file is specified, but does not exist" do
|
||||
subject.galaxy_role_file = non_existing_file
|
||||
subject.finalize!
|
||||
|
||||
result = subject.validate(machine)
|
||||
expect(result["ansible remote provisioner"]).to eql([
|
||||
I18n.t("vagrant.provisioners.ansible.errors.galaxy_role_file_invalid",
|
||||
path: non_existing_file, system: "host")
|
||||
])
|
||||
end
|
||||
|
|
|
@ -208,7 +208,7 @@ VF
|
|||
config.finalize!
|
||||
Vagrant::Util::Subprocess.stub(execute: Vagrant::Util::Subprocess::Result.new(1, "", ""))
|
||||
|
||||
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsiblePlaybookAppFailed)
|
||||
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleCommandFailed)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -583,6 +583,33 @@ VF
|
|||
end
|
||||
end
|
||||
|
||||
describe "with galaxy support" do
|
||||
|
||||
before do
|
||||
config.galaxy_role_file = existing_file
|
||||
end
|
||||
|
||||
it "raises an error when ansible-galaxy command fails", 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(VagrantPlugins::Ansible::Errors::AnsibleCommandFailed)
|
||||
end
|
||||
|
||||
it "execute ansible-galaxy and ansible-playbook" do
|
||||
# TODO: to be improved, but I'm currenty facing some issues, maybe only present in RSpec 2.14...
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).twice
|
||||
end
|
||||
|
||||
describe "with verbose option enabled" do
|
||||
before do
|
||||
config.verbose = true
|
||||
end
|
||||
|
||||
xit "shows the ansible-galaxy command in use"
|
||||
end
|
||||
end
|
||||
|
||||
# The Vagrant Ansible provisioner does not validate the coherency of
|
||||
# argument combinations, and let ansible-playbook complain.
|
||||
describe "with a maximum of options" do
|
||||
|
|
|
@ -51,6 +51,30 @@ Some of these options are for advanced usage only and should not be used unless
|
|||
|
||||
By default, this option is disabled and Vagrant generates an inventory based on the `Vagrantfile` information.
|
||||
|
||||
- `galaxy_command` (template string) - The command pattern used to install Galaxy roles when `galaxy_role_file` is set.
|
||||
|
||||
The following placeholders can be used in this command pattern:
|
||||
- `%{ROLE_FILE}` is replaced by the absolute path to the `galaxy_role_file` option
|
||||
- `%{ROLES_PATH}` is
|
||||
* replaced by the absolute path to the `galaxy_roles_path` option when such option is defined
|
||||
* replaced by the absolute path to a `roles` subdirectory sitting in the parent directory of the configured `playbook` file otherwise.
|
||||
|
||||
By default, this option is set to
|
||||
|
||||
```
|
||||
ansible-galaxy install --role-file=%{ROLE_FILE} --roles-path=%{ROLES_PATH} --force
|
||||
```
|
||||
|
||||
- `galaxy_role_file` (string) - The path to the Ansible Galaxy role file.
|
||||
|
||||
By default, this option is set to `nil` and Galaxy support is then disabled.
|
||||
|
||||
Note: if an absolute path is given, the `ansible_local` provisioner will assume that it corresponds to the exact location on the guest system.
|
||||
|
||||
- `galaxy_roles_path` (string) - The path to the directory where Ansible Galaxy roles must be installed
|
||||
|
||||
By default, this option is set to `nil`, which means that the Galaxy roles will be installed in a `roles` subdirectory located in the parent directory of the `playbook` file.
|
||||
|
||||
- `limit` (string or array of strings) - Set of machines or groups from the inventory file to further control which hosts [are affected](http://docs.ansible.com/glossary.html#limit-groups).
|
||||
|
||||
The default value is set to the machine name (taken from `Vagrantfile`) to ensure that `vagrant provision` command only affect the expected machine.
|
||||
|
|
Loading…
Reference in New Issue