Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for ansible_password #9350

Merged
merged 1 commit into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 39 additions & 15 deletions provisioner/ansible/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,41 +550,48 @@ func (p *Provisioner) executeGalaxy(ui packer.Ui, comm packer.Communicator) erro
func (p *Provisioner) createCmdArgs(httpAddr, inventory, playbook, privKeyFile string) (args []string, envVars []string) {
args = []string{}

//Setting up AnsibleEnvVars at begining so additional checks can take them into account
if len(p.config.AnsibleEnvVars) > 0 {
envVars = append(envVars, p.config.AnsibleEnvVars...)
}

if p.config.PackerBuildName != "" {
// HCL configs don't currently have the PakcerBuildName. Don't
// cause weirdness with a half-set variable
args = append(args, "-e", fmt.Sprintf("packer_build_name=%s", p.config.PackerBuildName))
}

args = append(args, "-e", fmt.Sprintf("packer_builder_type=%s", p.config.PackerBuilderType))
if len(privKeyFile) > 0 {
// "-e ansible_ssh_private_key_file" is preferable to "--private-key"
// because it is a higher priority variable and therefore won't get
// overridden by dynamic variables. See #5852 for more details.
args = append(args, "-e", fmt.Sprintf("ansible_ssh_private_key_file=%s", privKeyFile))
}

// expose packer_http_addr extra variable
if httpAddr != "" {
args = append(args, "-e", fmt.Sprintf("packer_http_addr=%s", httpAddr))
}

// Add password to ansible call.
if p.config.UseProxy.False() && p.generatedData["ConnType"] == "winrm" {
args = append(args, "-e", fmt.Sprintf("ansible_password=%s", p.generatedData["Password"]))
}

if p.generatedData["ConnType"] == "ssh" {
// Add ssh extra args to set IdentitiesOnly
args = append(args, "--ssh-extra-args", "-o IdentitiesOnly=yes")
args = append(args, "--ssh-extra-args", "'-o IdentitiesOnly=yes'")
}

args = append(args, p.config.ExtraArguments...)

if len(p.config.AnsibleEnvVars) > 0 {
envVars = append(envVars, p.config.AnsibleEnvVars...)
// Add password to ansible call.
if !checkArg("ansible_password", args) && p.config.UseProxy.False() && p.generatedData["ConnType"] == "winrm" {
args = append(args, "-e", fmt.Sprintf("ansible_password=%s", p.generatedData["Password"]))
}

if !checkArg("ansible_password", args) && len(privKeyFile) > 0 {
// "-e ansible_ssh_private_key_file" is preferable to "--private-key"
// because it is a higher priority variable and therefore won't get
// overridden by dynamic variables. See #5852 for more details.
args = append(args, "-e", fmt.Sprintf("ansible_ssh_private_key_file=%s", privKeyFile))
}

if checkArg("ansible_password", args) && p.generatedData["ConnType"] == "ssh" {
if !checkArg("ansible_host_key_checking", args) && !checkArg("ANSIBLE_HOST_KEY_CHECKING", envVars) {
args = append(args, "-e", "ansible_host_key_checking=False")
}
}
// This must be the last arg appended to args
args = append(args, "-i", inventory, playbook)
return args, envVars
Expand All @@ -601,7 +608,6 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri
return fmt.Errorf("Error executing Ansible Galaxy: %s", err)
}
}

args, envvars := p.createCmdArgs(httpAddr, inventory, playbook, privKeyFile)

cmd := exec.Command(p.config.Command, args...)
Expand Down Expand Up @@ -652,6 +658,12 @@ func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, pri
sanitized = strings.Replace(sanitized,
winRMPass.(string), "*****", -1)
}
if checkArg("ansible_password", args) {
usePass, ok := p.generatedData["Password"]
if ok && usePass != "" {
sanitized = strings.Replace(sanitized, usePass.(string), "*****", -1)
}
}
ui.Say(fmt.Sprintf("Executing Ansible: %s", sanitized))

if err := cmd.Start(); err != nil {
Expand Down Expand Up @@ -779,3 +791,15 @@ func newSigner(privKeyFile string) (*signer, error) {

return signer, nil
}

//checkArg Evaluates if argname is in args
func checkArg(argname string, args []string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this helper function. Nice job!

for _, arg := range args {
for _, ansibleArg := range strings.Split(arg, "=") {
if ansibleArg == argname {
return true
}
}
}
return false
}
66 changes: 56 additions & 10 deletions provisioner/ansible/provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ func basicGenData(input map[string]interface{}) map[string]interface{} {

func TestCreateCmdArgs(t *testing.T) {
type testcase struct {
TestName string
PackerBuildName string
PackerBuilderType string
UseProxy confighelper.Trilean
Expand All @@ -498,46 +499,51 @@ func TestCreateCmdArgs(t *testing.T) {
TestCases := []testcase{
{
// SSH with private key and an extra argument.
TestName: "SSH with private key and an extra argument",
PackerBuildName: "packerparty",
generatedData: basicGenData(nil),
ExtraArguments: []string{"-e", "hello-world"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
callArgs: []string{"", "/var/inventory", "test-playbook.yml", "/path/to/privkey.pem"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "ansible_ssh_private_key_file=/path/to/privkey.pem", "--ssh-extra-args", "-o IdentitiesOnly=yes", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "ansible_ssh_private_key_file=/path/to/privkey.pem", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
},
{
TestName: "SSH with private key and an extra argument and UseProxy",
PackerBuildName: "packerparty",
UseProxy: confighelper.TriTrue,
generatedData: basicGenData(nil),
ExtraArguments: []string{"-e", "hello-world"},
callArgs: []string{"", "/var/inventory", "test-playbook.yml", "/path/to/privkey.pem"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "ansible_ssh_private_key_file=/path/to/privkey.pem", "--ssh-extra-args", "-o IdentitiesOnly=yes", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "ansible_ssh_private_key_file=/path/to/privkey.pem", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{},
},
{
// Winrm, but no_proxy is unset so we don't do anything with ansible_password.
TestName: "Winrm, but no_proxy is unset so we don't do anything with ansible_password",
PackerBuildName: "packerparty",
generatedData: basicGenData(map[string]interface{}{
"ConnType": "winrm",
}),
ExtraArguments: []string{"-e", "hello-world"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
callArgs: []string{"", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
},
{
// HTTPAddr should be set. No env vars.
TestName: "HTTPAddr should be set. No env vars",
PackerBuildName: "packerparty",
ExtraArguments: []string{"-e", "hello-world"},
generatedData: basicGenData(nil),
callArgs: []string{"123.45.67.89", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "--ssh-extra-args", "-o IdentitiesOnly=yes", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{},
},
{
// Add ansible_password for proxyless winrm connection.
TestName: "Add ansible_password for proxyless winrm connection.",
UseProxy: confighelper.TriFalse,
generatedData: basicGenData(map[string]interface{}{
"ConnType": "winrm",
Expand All @@ -550,18 +556,20 @@ func TestCreateCmdArgs(t *testing.T) {
},
{
// Neither special ssh stuff, nor special windows stuff. This is docker!
TestName: "Neither special ssh stuff, nor special windows stuff. This is docker!",
PackerBuildName: "packerparty",
generatedData: basicGenData(map[string]interface{}{
"ConnType": "docker",
}),
ExtraArguments: []string{"-e", "hello-world"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
callArgs: []string{"", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
},
{
// Windows, no proxy, with extra vars.
TestName: "Windows, no proxy, with extra vars.",
UseProxy: confighelper.TriFalse,
generatedData: basicGenData(map[string]interface{}{
"ConnType": "winrm",
Expand All @@ -570,14 +578,51 @@ func TestCreateCmdArgs(t *testing.T) {
ExtraArguments: []string{"-e", "hello-world"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
callArgs: []string{"123.45.67.89", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "-e", "ansible_password=ilovebananapancakes", "-i", "/var/inventory", "test-playbook.yml", "-e", "hello-world"},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "-e", "ansible_password=ilovebananapancakes", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
},
{
// SSH, use Password.
TestName: "SSH, use ansible_password.",
generatedData: basicGenData(map[string]interface{}{
"ConnType": "ssh",
"Password": "ilovebananapancakes",
}),
ExtraArguments: []string{"-e", "hello-world", "-e", "ansible_password=ilovebananapancakes"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
callArgs: []string{"123.45.67.89", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-e", "ansible_password=ilovebananapancakes", "-e", "ansible_host_key_checking=False", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas"},
},
{
// SSH, use Password .
TestName: "SSH, already in ENV ansible_host_key_checking.",
generatedData: basicGenData(map[string]interface{}{
"ConnType": "ssh",
"Password": "ilovebananapancakes",
}),
ExtraArguments: []string{"-e", "hello-world", "-e", "ansible_password=ilovebananapancakes"},
AnsibleEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas", "ANSIBLE_HOST_KEY_CHECKING=False"},
callArgs: []string{"123.45.67.89", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "-e", "packer_http_addr=123.45.67.89", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-e", "ansible_password=ilovebananapancakes", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{"ENV_1=pancakes", "ENV_2=bananas", "ANSIBLE_HOST_KEY_CHECKING=False"},
},
{
TestName: "Use PrivateKey",
PackerBuildName: "packerparty",
UseProxy: confighelper.TriTrue,
generatedData: basicGenData(nil),
ExtraArguments: []string{"-e", "hello-world"},
callArgs: []string{"", "/var/inventory", "test-playbook.yml", "/path/to/privkey.pem"},
ExpectedArgs: []string{"-e", "packer_build_name=packerparty", "-e", "packer_builder_type=fakebuilder", "-e", "ansible_ssh_private_key_file=/path/to/privkey.pem", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-e", "hello-world", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{},
},
{
// No builder name. This shouldn't cause an error, it just shouldn't be set. HCL, yo.
TestName: "No builder name. This shouldn't cause an error, it just shouldn't be set. HCL, yo.",
generatedData: basicGenData(nil),
callArgs: []string{"", "/var/inventory", "test-playbook.yml", ""},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "--ssh-extra-args", "-o IdentitiesOnly=yes", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedArgs: []string{"-e", "packer_builder_type=fakebuilder", "--ssh-extra-args", "'-o IdentitiesOnly=yes'", "-i", "/var/inventory", "test-playbook.yml"},
ExpectedEnvVars: []string{},
},
}
Expand All @@ -595,10 +640,11 @@ func TestCreateCmdArgs(t *testing.T) {

args, envVars := p.createCmdArgs(tc.callArgs[0], tc.callArgs[1], tc.callArgs[2], tc.callArgs[3])
assert.ElementsMatch(t, args, tc.ExpectedArgs,
"Args didn't match expected:\n\n expected: \n%s\n; recieved: \n%s\n", tc.ExpectedArgs, args)
assert.ElementsMatch(t, envVars, tc.ExpectedEnvVars, "EnvVars didn't match expected:\n\n expected: \n%s\n; recieved: \n%s\n", tc.ExpectedEnvVars, envVars)
"TestName: %s\nArgs didn't match expected:\nexpected: \n%s\n; recieved: \n%s\n", tc.TestName, tc.ExpectedArgs, args)
assert.ElementsMatch(t, envVars, tc.ExpectedEnvVars,
"TestName: %s\nArgs didn't match expected:\n\nEnvVars didn't match expected:\n\n expected: \n%s\n; recieved: \n%s\n", tc.TestName, tc.ExpectedEnvVars, envVars)
assert.EqualValues(t, tc.callArgs[2], args[len(args)-1],
"PlayBook File Not Returned as last element: \nexpected: %s\nrecieved: %s\n", tc.callArgs[2], args[len(args)-1])
"TestName: %s\nPlayBook File Not Returned as last element: \nexpected: %s\nrecieved: %s\n", tc.TestName, tc.callArgs[2], args[len(args)-1])
}
}

Expand Down