diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index d6e785c70..ead4d44b2 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -26,6 +26,7 @@ import ( "golang.org/x/crypto/ssh" "github.com/hashicorp/packer/common" + commonhelper "github.com/hashicorp/packer/helper/common" "github.com/hashicorp/packer/helper/config" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template/interpolate" @@ -67,9 +68,19 @@ type Provisioner struct { ansibleMajVersion uint } +type PassthroughTemplate struct { + WinRMPassword string +} + func (p *Provisioner) Prepare(raws ...interface{}) error { p.done = make(chan struct{}) + // Create passthrough for winrm password so we can fill it in once we know + // it + p.config.ctx.Data = &PassthroughTemplate{ + WinRMPassword: `{{.WinRMPassword}}`, + } + err := config.Decode(&p.config, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &p.config.ctx, @@ -188,6 +199,25 @@ func (p *Provisioner) getVersion() error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") + // Interpolate env vars to check for .WinRMPassword + p.config.ctx.Data = &PassthroughTemplate{ + WinRMPassword: getWinRMPassword(p.config.PackerBuildName), + } + for i, envVar := range p.config.AnsibleEnvVars { + envVar, err := interpolate.Render(envVar, &p.config.ctx) + if err != nil { + return fmt.Errorf("Could not interpolate ansible env vars: %s", err) + } + p.config.AnsibleEnvVars[i] = envVar + } + // Interpolate extra vars to check for .WinRMPassword + for i, arg := range p.config.ExtraArguments { + arg, err := interpolate.Render(arg, &p.config.ctx) + if err != nil { + return fmt.Errorf("Could not interpolate ansible env vars: %s", err) + } + p.config.ExtraArguments[i] = arg + } k, err := newUserKey(p.config.SSHAuthorizedKeyFile) if err != nil { @@ -381,7 +411,15 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri go repeat(stdout) go repeat(stderr) - ui.Say(fmt.Sprintf("Executing Ansible: %s", strings.Join(cmd.Args, " "))) + // remove winrm password from command, if it's been added + flattenedCmd := strings.Join(cmd.Args, " ") + sanitized := flattenedCmd + if len(getWinRMPassword(p.config.PackerBuildName)) > 0 { + sanitized = strings.Replace(sanitized, + getWinRMPassword(p.config.PackerBuildName), "*****", -1) + } + ui.Say(fmt.Sprintf("Executing Ansible: %s", sanitized)) + if err := cmd.Start(); err != nil { return err } @@ -508,6 +546,11 @@ func newSigner(privKeyFile string) (*signer, error) { return signer, nil } +func getWinRMPassword(buildName string) string { + winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName) + return winRMPass +} + // Ui provides concurrency-safe access to packer.Ui. type Ui struct { sem chan int diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index 26047458d..bf1145f64 100644 --- a/website/source/docs/provisioners/ansible.html.md +++ b/website/source/docs/provisioners/ansible.html.md @@ -14,7 +14,7 @@ Type: `ansible` The `ansible` Packer provisioner runs Ansible playbooks. It dynamically creates an Ansible inventory file configured to use SSH, runs an SSH server, executes `ansible-playbook`, and marshals Ansible plays through the SSH server to the -machine being provisioned by Packer. +machine being provisioned by Packer. -> **Note:**: Any `remote_user` defined in tasks will be ignored. Packer will always connect with the user given in the json config for this provisioner. @@ -61,6 +61,15 @@ Optional Parameters: "ansible_env_vars": [ "ANSIBLE_HOST_KEY_CHECKING=False", "ANSIBLE_SSH_ARGS='-o ForwardAgent=yes -o ControlMaster=auto -o ControlPersist=60s'", "ANSIBLE_NOCOLOR=True" ] } ``` + If you are running a Windows build on AWS, Azure or Google Compute and would + like to access the auto-generated password that Packer uses to connect to a + Windows instance via WinRM, you can use the template variable + {{.WinRMPassword}} in this option. + For example: + + ```json + "ansible_env_vars": [ "WINRM_PASSWORD={{.WinRMPassword}}" ], + ``` - `command` (string) - The command to invoke ansible. Defaults to `ansible-playbook`. @@ -72,12 +81,24 @@ Optional Parameters: These arguments *will not* be passed through a shell and arguments should not be quoted. Usage example: - ``` json + ```json { "extra_arguments": [ "--extra-vars", "Region={{user `Region`}} Stage={{user `Stage`}}" ] } ``` + If you are running a Windows build on AWS, Azure or Google Compute and would + like to access the auto-generated password that Packer uses to connect to a + Windows instance via WinRM, you can use the template variable + {{.WinRMPassword}} in this option. + For example: + + ```json + "extra_arguments": [ + "--extra-vars", "winrm_password={{ .WinRMPassword }}" + ] + ``` + - `groups` (array of strings) - The groups into which the Ansible host should be placed. When unspecified, the host is not associated with any groups. @@ -146,7 +167,7 @@ commonly useful Ansible variables: To debug underlying issues with Ansible, add `"-vvvv"` to `"extra_arguments"` to enable verbose logging. -``` json +```json { "extra_arguments": [ "-vvvv" ] } @@ -167,7 +188,7 @@ Redhat / CentOS builds have been known to fail with the following error due to ` Building within a chroot (e.g. `amazon-chroot`) requires changing the Ansible connection to chroot. -``` json +```json { "builders": [ {