inventory_directory option for ansible provisioner

Add an `inventory_directory` setting to the Ansible provisioner that
allows a user to specify a directory in which the Packer Ansible
provisioner would write the generated inventory file.  If a value is
specified for this setting, then have the Packer Ansible provisioner
pass this directory as the -i arg when it calls ansible.

This would allow an Ansible playbook used by the Packer Ansible
provisioner to use variables specified in `host_vars` and `group_vars`
in this inventory directory.
This commit is contained in:
Dan Fuchs 2017-04-04 16:43:46 -05:00
parent 747bee35bd
commit 609e70face
3 changed files with 74 additions and 2 deletions

View File

@ -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
}
@ -249,7 +250,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)
}
@ -300,9 +301,16 @@ func (p *Provisioner) Cancel() {
os.Exit(0)
}
func (p *Provisioner) getInventoryArg() string {
if len(p.config.InventoryDirectory) != 0 {
return p.config.InventoryDirectory
}
return p.config.inventoryFile
}
func (p *Provisioner) executeAnsible(ui packer.Ui, comm packer.Communicator, privKeyFile string) error {
playbook, _ := filepath.Abs(p.config.PlaybookFile)
inventory := p.config.inventoryFile
inventory := p.getInventoryArg()
var envvars []string
args := []string{playbook, "-i", inventory}

View File

@ -76,6 +76,12 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
if err != nil {
t.Fatalf("err: %s", err)
}
config["inventory_directory"] = "some_directory"
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvisionerPrepare_PlaybookFile(t *testing.T) {
@ -246,6 +252,55 @@ func TestProvisionerPrepare_LocalPort(t *testing.T) {
}
}
func TestProvisioner_getInventoryArg(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()
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
p.config.inventoryFile = "somefile"
if p.getInventoryArg() != "somefile" {
t.Fatal("getInventoryArg should return inventoryFile if InventoryDirectory is not set.")
}
// Uses InventoryDirectory if set
config["inventory_directory"] = "somedirectory"
err = p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
if p.getInventoryArg() != "somedirectory" {
t.Fatal("getInventoryArg should return InventoryDirectory if InventoryDirectory is set.")
}
}
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")

View File

@ -113,6 +113,15 @@ 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
generated ansible inventory file. If this is specified, then this directory
is what will get passed to the `-i` argument of the `ansible` command when
this provisioner runs Ansible. By default, the generated ansible inventory
will be placed in a temporary file in the system-specific temporary file
location, and the fully-qualified name of this temporary file will be passed
to the `-i` argument of the `ansible` command when this provisioner runs
ansible.
## Limitations
### Redhat / CentOS