diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index f64a58fb9..84f1fde81 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -53,6 +53,7 @@ type Config struct { SSHAuthorizedKeyFile string `mapstructure:"ssh_authorized_key_file"` SFTPCmd string `mapstructure:"sftp_command"` UseSFTP bool `mapstructure:"use_sftp"` + InventoryDirectory string `mapstructure:"inventory_directory"` inventoryFile string } @@ -123,6 +124,14 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { p.config.LocalPort = "0" } + if len(p.config.InventoryDirectory) > 0 { + err = validateInventoryDirectoryConfig(p.config.InventoryDirectory) + if err != nil { + log.Println(p.config.InventoryDirectory, "does not exist") + errs = packer.MultiErrorAppend(errs, err) + } + } + err = p.getVersion() if err != nil { errs = packer.MultiErrorAppend(errs, err) @@ -249,7 +258,7 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { go p.adapter.Serve() if len(p.config.inventoryFile) == 0 { - tf, err := ioutil.TempFile("", "packer-provisioner-ansible") + tf, err := ioutil.TempFile(p.config.InventoryDirectory, "packer-provisioner-ansible") if err != nil { return fmt.Errorf("Error preparing inventory file: %s", err) } @@ -384,6 +393,16 @@ func validateFileConfig(name string, config string, req bool) error { return nil } +func validateInventoryDirectoryConfig(name string) error { + info, err := os.Stat(name) + if err != nil { + return fmt.Errorf("inventory_directory: %s is invalid: %s", name, err) + } else if !info.IsDir() { + return fmt.Errorf("inventory_directory: %s must point to a directory", name) + } + return nil +} + type userKey struct { ssh.PublicKey privKeyFile string diff --git a/provisioner/ansible/provisioner_test.go b/provisioner/ansible/provisioner_test.go index bda07080b..47f185c9e 100644 --- a/provisioner/ansible/provisioner_test.go +++ b/provisioner/ansible/provisioner_test.go @@ -246,6 +246,52 @@ func TestProvisionerPrepare_LocalPort(t *testing.T) { } } +func TestProvisionerPrepare_InventoryDirectory(t *testing.T) { + var p Provisioner + config := testConfig(t) + defer os.Remove(config["command"].(string)) + + hostkey_file, err := ioutil.TempFile("", "hostkey") + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.Remove(hostkey_file.Name()) + + publickey_file, err := ioutil.TempFile("", "publickey") + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.Remove(publickey_file.Name()) + + playbook_file, err := ioutil.TempFile("", "playbook") + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.Remove(playbook_file.Name()) + + config["ssh_host_key_file"] = hostkey_file.Name() + config["ssh_authorized_key_file"] = publickey_file.Name() + config["playbook_file"] = playbook_file.Name() + + config["inventory_directory"] = "doesnotexist" + err = p.Prepare(config) + if err == nil { + t.Errorf("should error if inventory_directory does not exist") + } + + inventoryDirectory, err := ioutil.TempDir("", "some_inventory_dir") + if err != nil { + t.Fatalf("err: %s", err) + } + defer os.Remove(inventoryDirectory) + + config["inventory_directory"] = inventoryDirectory + err = p.Prepare(config) + if err != nil { + t.Fatalf("err: %s", err) + } +} + func TestAnsibleGetVersion(t *testing.T) { if os.Getenv("PACKER_ACC") == "" { t.Skip("This test is only run with PACKER_ACC=1 and it requires Ansible to be installed") diff --git a/website/source/docs/provisioners/ansible.html.md b/website/source/docs/provisioners/ansible.html.md index c578e9a68..97a231fba 100644 --- a/website/source/docs/provisioners/ansible.html.md +++ b/website/source/docs/provisioners/ansible.html.md @@ -114,6 +114,13 @@ Optional Parameters: - `user` (string) - The `ansible_user` to use. Defaults to the user running packer. +- `inventory_directory` (string) - The directory in which to place the + temporary generated Ansible inventory file. By default, this is the + system-specific temporary file location. The fully-qualified name of this + temporary file will be passed to the `-i` argument of the `ansible` command + when this provisioner runs ansible. Specify this if you have an existing + inventory directory with `host_vars` `group_vars` that you would like to use + in the playbook that this provisioner will run. ## Default Extra Variables @@ -129,7 +136,6 @@ commonly useful Ansible variables: machine that the script is running on. This is useful if you want to run only certain parts of the playbook on systems built with certain builders. - ## Limitations ### Redhat / CentOS