From 37fd50995fbcac28a085e51a49cd98bef337f4e9 Mon Sep 17 00:00:00 2001 From: Levi Date: Mon, 2 Jul 2018 20:09:38 -0400 Subject: [PATCH 1/9] added parameter for setting packer password as env variable --- provisioner/ansible/provisioner.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index d6e785c70..0f92c9ef4 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -57,6 +57,7 @@ type Config struct { UseSFTP bool `mapstructure:"use_sftp"` InventoryDirectory string `mapstructure:"inventory_directory"` InventoryFile string `mapstructure:"inventory_file"` + SetPackerPasswd bool `mapstructure:"set_packer_passwd"` } type Provisioner struct { @@ -118,6 +119,10 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, "ANSIBLE_SCP_IF_SSH=True") } + if p.config.SetPackerPasswd { + p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, "PACKER_RANDOM_PASSWORD=TEST") + } + if len(p.config.LocalPort) > 0 { if _, err := strconv.ParseUint(p.config.LocalPort, 10, 16); err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("local_port: %s must be a valid port", p.config.LocalPort)) From 636cec8f2bebf9b2b202678d779f0f4ab3e268ab Mon Sep 17 00:00:00 2001 From: Levi Date: Mon, 2 Jul 2018 20:10:06 -0400 Subject: [PATCH 2/9] added commonhelper import --- provisioner/ansible/provisioner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index 0f92c9ef4..fd037c6ce 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" From 68ec630fde9f20ec27d22d11496a03289be1d6bc Mon Sep 17 00:00:00 2001 From: Levi Date: Mon, 2 Jul 2018 20:12:04 -0400 Subject: [PATCH 3/9] added function to retreive winrm password from commonhelper --- provisioner/ansible/provisioner.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index fd037c6ce..a01d3f4cb 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -121,7 +121,8 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.SetPackerPasswd { - p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, "PACKER_RANDOM_PASSWORD=TEST") + var PackerEnvVar string = fmt.Sprintf("PACKER_RANDOM_PASSWORD=%s", getWinRMPassword()) + p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, PackerEnvVar) } if len(p.config.LocalPort) > 0 { @@ -514,6 +515,12 @@ func newSigner(privKeyFile string) (*signer, error) { return signer, nil } +func getWinRMPassword() string { + winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password") + return winRMPass + +} + // Ui provides concurrency-safe access to packer.Ui. type Ui struct { sem chan int From 6646d42490aba125d05dc86e0d2dbe8f071bda13 Mon Sep 17 00:00:00 2001 From: Levi Date: Mon, 2 Jul 2018 20:42:21 -0400 Subject: [PATCH 4/9] updated function calls to include buildname and changed variable names --- provisioner/ansible/provisioner.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index a01d3f4cb..a221d02da 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -58,7 +58,7 @@ type Config struct { UseSFTP bool `mapstructure:"use_sftp"` InventoryDirectory string `mapstructure:"inventory_directory"` InventoryFile string `mapstructure:"inventory_file"` - SetPackerPasswd bool `mapstructure:"set_packer_passwd"` + SetWinrmPasswd bool `mapstructure:"set_winrm_passwd"` } type Provisioner struct { @@ -120,11 +120,6 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, "ANSIBLE_SCP_IF_SSH=True") } - if p.config.SetPackerPasswd { - var PackerEnvVar string = fmt.Sprintf("PACKER_RANDOM_PASSWORD=%s", getWinRMPassword()) - p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, PackerEnvVar) - } - if len(p.config.LocalPort) > 0 { if _, err := strconv.ParseUint(p.config.LocalPort, 10, 16); err != nil { errs = packer.MultiErrorAppend(errs, fmt.Errorf("local_port: %s must be a valid port", p.config.LocalPort)) @@ -196,6 +191,12 @@ func (p *Provisioner) getVersion() error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") + if p.config.SetWinrmPasswd { + var WinrmEnvVar string = fmt.Sprintf("GENERATED_WINRM_PASSWORD=%s", getWinRMPassword(p.config.PackerBuildName)) + p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, WinrmEnvVar) + ui.Say("Setting Environment variable GENERATED_WINRM_PASSWORD to WinRM password.") + } + k, err := newUserKey(p.config.SSHAuthorizedKeyFile) if err != nil { return err @@ -515,10 +516,9 @@ func newSigner(privKeyFile string) (*signer, error) { return signer, nil } -func getWinRMPassword() string { - winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password") +func getWinRMPassword(buildName string) string { + winRMPass, _ := commonhelper.RetrieveSharedState("winrm_password", buildName) return winRMPass - } // Ui provides concurrency-safe access to packer.Ui. From 17074cda2ce6652543afd2857e3ecc60551888dd Mon Sep 17 00:00:00 2001 From: Levi Date: Sat, 14 Jul 2018 15:09:48 -0400 Subject: [PATCH 5/9] added set_winrm_passwd usage instructions --- website/source/docs/provisioners/ansible.html.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index 26047458d..8bc697cad 100644 --- a/website/source/docs/provisioners/ansible.html.md +++ b/website/source/docs/provisioners/ansible.html.md @@ -128,6 +128,11 @@ Optional Parameters: - `user` (string) - The `ansible_user` to use. Defaults to the user running packer. +- `set_winrm_passwd` (boolean) - Set to `true` to access the randomly-generated + EC2 Windows password through the environment variable `GENERATED_WINRM_PASSWORD`. + You will also need to set `ansible_password` in your ansible playbook, for example, + `ansible_password: "{{ lookup('env','GENERATED_WINRM_PASSWORD') }}"` + ## Default Extra Variables In addition to being able to specify extra arguments using the From a5493e49061a1d6340d4632fe43675f0d5eff975 Mon Sep 17 00:00:00 2001 From: Levi Blaney Date: Mon, 16 Jul 2018 17:26:38 -0400 Subject: [PATCH 6/9] added the builders that set_winrm_passwd works with --- website/source/docs/provisioners/ansible.html.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index 8bc697cad..64630822d 100644 --- a/website/source/docs/provisioners/ansible.html.md +++ b/website/source/docs/provisioners/ansible.html.md @@ -128,9 +128,11 @@ Optional Parameters: - `user` (string) - The `ansible_user` to use. Defaults to the user running packer. -- `set_winrm_passwd` (boolean) - Set to `true` to access the randomly-generated - EC2 Windows password through the environment variable `GENERATED_WINRM_PASSWORD`. - You will also need to set `ansible_password` in your ansible playbook, for example, +- `set_winrm_passwd` (boolean) - Set to `true` if you are running on AWS, Azure or + Google Compute and would like to access the generated password that Packer uses to + connect to the instance via WinRM. The password will be avaliable on the builder + through the environment variable `GENERATED_WINRM_PASSWORD`. You will also need to + set `ansible_password` in your ansible playbook, for example, `ansible_password: "{{ lookup('env','GENERATED_WINRM_PASSWORD') }}"` ## Default Extra Variables From f5e17d1cad159e2f4122bb7a8ff7743e8c531574 Mon Sep 17 00:00:00 2001 From: Levi Blaney Date: Mon, 16 Jul 2018 19:13:05 -0400 Subject: [PATCH 7/9] changed wording from builder to provisoner --- website/source/docs/provisioners/ansible.html.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index 64630822d..2fda46679 100644 --- a/website/source/docs/provisioners/ansible.html.md +++ b/website/source/docs/provisioners/ansible.html.md @@ -130,9 +130,9 @@ Optional Parameters: - `set_winrm_passwd` (boolean) - Set to `true` if you are running on AWS, Azure or Google Compute and would like to access the generated password that Packer uses to - connect to the instance via WinRM. The password will be avaliable on the builder - through the environment variable `GENERATED_WINRM_PASSWORD`. You will also need to - set `ansible_password` in your ansible playbook, for example, + connect to the instance via WinRM. The password will be avaliable to the Ansible + provisioner through the environment variable `GENERATED_WINRM_PASSWORD`. You will + also need to set `ansible_password` in your ansible playbook, for example, `ansible_password: "{{ lookup('env','GENERATED_WINRM_PASSWORD') }}"` ## Default Extra Variables From e146973d081c876022f21bd7b111cd932ce71e1c Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Tue, 17 Jul 2018 12:52:32 -0700 Subject: [PATCH 8/9] change implementation to set winrm password in way that matches powershell and shell-local implementations; sanitize logs --- provisioner/ansible/provisioner.go | 44 +++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index a221d02da..ead4d44b2 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -58,7 +58,6 @@ type Config struct { UseSFTP bool `mapstructure:"use_sftp"` InventoryDirectory string `mapstructure:"inventory_directory"` InventoryFile string `mapstructure:"inventory_file"` - SetWinrmPasswd bool `mapstructure:"set_winrm_passwd"` } type Provisioner struct { @@ -69,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, @@ -190,11 +199,24 @@ func (p *Provisioner) getVersion() error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") - - if p.config.SetWinrmPasswd { - var WinrmEnvVar string = fmt.Sprintf("GENERATED_WINRM_PASSWORD=%s", getWinRMPassword(p.config.PackerBuildName)) - p.config.AnsibleEnvVars = append(p.config.AnsibleEnvVars, WinrmEnvVar) - ui.Say("Setting Environment variable GENERATED_WINRM_PASSWORD to WinRM password.") + // 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) @@ -389,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 } From e8a7d948dbf0a45b1022b6ca4856b9893bbbfe91 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Wed, 18 Jul 2018 09:42:15 -0700 Subject: [PATCH 9/9] update docs --- .../source/docs/provisioners/ansible.html.md | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index 2fda46679..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. @@ -128,13 +149,6 @@ Optional Parameters: - `user` (string) - The `ansible_user` to use. Defaults to the user running packer. -- `set_winrm_passwd` (boolean) - Set to `true` if you are running on AWS, Azure or - Google Compute and would like to access the generated password that Packer uses to - connect to the instance via WinRM. The password will be avaliable to the Ansible - provisioner through the environment variable `GENERATED_WINRM_PASSWORD`. You will - also need to set `ansible_password` in your ansible playbook, for example, - `ansible_password: "{{ lookup('env','GENERATED_WINRM_PASSWORD') }}"` - ## Default Extra Variables In addition to being able to specify extra arguments using the @@ -153,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" ] } @@ -174,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": [ {