diff --git a/plugins/provisioners/ansible/config.rb b/plugins/provisioners/ansible/config.rb index b206e224d..416ec066d 100644 --- a/plugins/provisioners/ansible/config.rb +++ b/plugins/provisioners/ansible/config.rb @@ -47,12 +47,6 @@ module VagrantPlugins @start_at_task = nil if @start_at_task == UNSET_VALUE @raw_arguments = nil if @raw_arguments == UNSET_VALUE @host_key_checking = nil if @host_key_checking == UNSET_VALUE - - if @extra_vars && @extra_vars.is_a?(Hash) - @extra_vars.each do |k, v| - @extra_vars[k] = v.to_s - end - end end def validate(machine) @@ -72,10 +66,26 @@ module VagrantPlugins end end - # Validate that extra_vars is a hash, if set + # Validate that extra_vars is either a hash, or a path to an existing file if extra_vars - if !extra_vars.kind_of?(Hash) - errors << I18n.t("vagrant.provisioners.ansible.extra_vars_not_hash") + extra_vars_is_valid = (extra_vars.kind_of?(Hash) or extra_vars.kind_of?(String)) + + if extra_vars.kind_of?(String) + # Accept the usage of '@' prefix in Vagrantfile (e.g. '@vars.yml' and 'vars.yml' are both supported) + extra_vars =~ /^@?(.+)$/ + extra_vars_path = $1.to_s + expanded_path = Pathname.new(extra_vars_path).expand_path(machine.env.root_path) + extra_vars_is_valid = expanded_path.exist? + if extra_vars_is_valid + @extra_vars = '@' + extra_vars_path + end + end + + if !extra_vars_is_valid + errors << I18n.t("vagrant.provisioners.ansible.extra_vars_invalid", + :type => extra_vars.class.to_s, + :value => extra_vars.to_s + ) end end diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index c8f3af80c..00f53f67b 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -11,20 +11,8 @@ module VagrantPlugins options << "#{config.raw_arguments}" if config.raw_arguments # Append Provisioner options (highest precedence): - if config.extra_vars - extra_vars = config.extra_vars.map do |k,v| - v = v.gsub('"', '\\"') - if v.include?(' ') - v = v.gsub("'", "\\'") - v = "'#{v}'" - end - - "#{k}=#{v}" - end - options << "--extra-vars=\"#{extra_vars.join(" ")}\"" - end - options << "--inventory-file=#{self.setup_inventory_file}" + options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars options << "--sudo" if config.sudo options << "--sudo-user=#{config.sudo_user}" if config.sudo_user options << "#{self.get_verbosity_argument}" if config.verbose @@ -83,6 +71,16 @@ module VagrantPlugins return generated_inventory_file.to_s end + def get_extra_vars_argument + if config.extra_vars.kind_of?(String) and config.extra_vars =~ /^@.+$/ + # A JSON or YAML file is referenced (requires Ansible 1.3+) + return config.extra_vars + else + # Expected to be a Hash after config validation. (extra_vars as JSON requires Ansible 1.2+, while YAML requires Ansible 1.3+) + return config.extra_vars.to_json + end + end + def get_verbosity_argument if config.verbose.to_s =~ /^v+$/ # ansible-playbook accepts "silly" arguments like '-vvvvv' as '-vvvv' for now diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 1f82cfb14..332ac97ee 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1246,4 +1246,4 @@ en: no_playbook: "`playbook` must be set for the Ansible provisioner." playbook_path_invalid: "`playbook` for the Ansible provisioner does not exist on the host system: %{path}" inventory_path_invalid: "`inventory_path` for the Ansible provisioner does not exist on the host system: %{path}" - extra_vars_not_hash: "`extra_vars` for the Ansible provisioner must be a hash" + extra_vars_invalid: "`extra_vars` for the Ansible provisioner must be a hash or a path to an existing file. Received: %{value} (as %{type})" diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 47565b8f8..619b8e71a 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -119,11 +119,14 @@ end The Ansible provisioner also includes a number of additional options that can be set, all of which get passed to the `ansible-playbook` command that ships with Ansible. -* `ansible.extra_vars` can be used to pass a hash of additional variables to the playbook. For example: +* `ansible.extra_vars` can be used to pass additional variables (with highest priority) to the playbook. This parameter can be a path to a JSON or YAML file, or a hash. For example: ``` ansible.extra_vars = { ntp_server: "pool.ntp.org", - nginx_workers: 4 + nginx: { + port: 8008, + workers: 4 + } } ``` These variables take the highest precedence over any other variables.