From b5b8f2e308fc5f7c79b6884654e8303b22e289aa Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Wed, 17 Jun 2020 02:05:48 -0700 Subject: [PATCH] add template option for templating the inventory file lines (#9438) --- provisioner/ansible/provisioner.go | 32 +++++++--- provisioner/ansible/provisioner.hcl2spec.go | 60 ++++++++++--------- .../ansible/Config-not-required.mdx | 9 +++ 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/provisioner/ansible/provisioner.go b/provisioner/ansible/provisioner.go index 6d7f079e8..bb2a406ce 100644 --- a/provisioner/ansible/provisioner.go +++ b/provisioner/ansible/provisioner.go @@ -137,6 +137,15 @@ type Config struct { // inventory directory with `host_vars` `group_vars` that you would like to // use in the playbook that this provisioner will run. InventoryDirectory string `mapstructure:"inventory_directory"` + // This template represents the format for the lines added to the temporary + // inventory file that Packer will create to run Ansible against your image. + // The default for recent versions of Ansible is: + // "{{ .HostAlias }} ansible_host={{ .Host }} ansible_user={{ .User }} ansible_port={{ .Port }}\n" + // Available template engines are: This option is a template engine; + // variables available to you include the examples in the default (Host, + // HostAlias, User, Port) as well as any variables available to you via the + // "build" template engine. + InventoryFileTemplate string `mapstructure:"inventory_file_template"` // The inventory file to use during provisioning. // When unspecified, Packer will create a temporary inventory file and will // use the `host_alias`. @@ -207,7 +216,9 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { Interpolate: true, InterpolateContext: &p.config.ctx, InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{}, + Exclude: []string{ + "inventory_file_template", + }, }, }, raws...) if err != nil { @@ -429,13 +440,17 @@ func (p *Provisioner) createInventoryFile() error { return fmt.Errorf("Error preparing inventory file: %s", err) } - // figure out which inventory line template to use - hostTemplate := DefaultSSHInventoryFilev2 - if p.ansibleMajVersion < 2 { - hostTemplate = DefaultSSHInventoryFilev1 - } - if p.config.UseProxy.False() && p.generatedData["ConnType"] == "winrm" { - hostTemplate = DefaultWinRMInventoryFilev2 + // If user has defiend their own inventory template, use it. + hostTemplate := p.config.InventoryFileTemplate + if hostTemplate == "" { + // figure out which inventory line template to use + hostTemplate = DefaultSSHInventoryFilev2 + if p.ansibleMajVersion < 2 { + hostTemplate = DefaultSSHInventoryFilev1 + } + if p.config.UseProxy.False() && p.generatedData["ConnType"] == "winrm" { + hostTemplate = DefaultWinRMInventoryFilev2 + } } // interpolate template to generate host with necessary vars. @@ -449,7 +464,6 @@ func (p *Provisioner) createInventoryFile() error { p.config.ctx.Data = ctxData host, err := interpolate.Render(hostTemplate, &p.config.ctx) - if err != nil { return fmt.Errorf("Error generating inventory file from template: %s", err) } diff --git a/provisioner/ansible/provisioner.hcl2spec.go b/provisioner/ansible/provisioner.hcl2spec.go index dafd53d04..4b4bde62d 100644 --- a/provisioner/ansible/provisioner.hcl2spec.go +++ b/provisioner/ansible/provisioner.hcl2spec.go @@ -9,35 +9,36 @@ import ( // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - Command *string `cty:"command" hcl:"command"` - ExtraArguments []string `mapstructure:"extra_arguments" cty:"extra_arguments" hcl:"extra_arguments"` - AnsibleEnvVars []string `mapstructure:"ansible_env_vars" cty:"ansible_env_vars" hcl:"ansible_env_vars"` - PlaybookFile *string `mapstructure:"playbook_file" required:"true" cty:"playbook_file" hcl:"playbook_file"` - Groups []string `mapstructure:"groups" cty:"groups" hcl:"groups"` - EmptyGroups []string `mapstructure:"empty_groups" cty:"empty_groups" hcl:"empty_groups"` - HostAlias *string `mapstructure:"host_alias" cty:"host_alias" hcl:"host_alias"` - User *string `mapstructure:"user" cty:"user" hcl:"user"` - LocalPort *int `mapstructure:"local_port" cty:"local_port" hcl:"local_port"` - SSHHostKeyFile *string `mapstructure:"ssh_host_key_file" cty:"ssh_host_key_file" hcl:"ssh_host_key_file"` - SSHAuthorizedKeyFile *string `mapstructure:"ssh_authorized_key_file" cty:"ssh_authorized_key_file" hcl:"ssh_authorized_key_file"` - SFTPCmd *string `mapstructure:"sftp_command" cty:"sftp_command" hcl:"sftp_command"` - SkipVersionCheck *bool `mapstructure:"skip_version_check" cty:"skip_version_check" hcl:"skip_version_check"` - UseSFTP *bool `mapstructure:"use_sftp" cty:"use_sftp" hcl:"use_sftp"` - InventoryDirectory *string `mapstructure:"inventory_directory" cty:"inventory_directory" hcl:"inventory_directory"` - InventoryFile *string `mapstructure:"inventory_file" cty:"inventory_file" hcl:"inventory_file"` - KeepInventoryFile *bool `mapstructure:"keep_inventory_file" cty:"keep_inventory_file" hcl:"keep_inventory_file"` - GalaxyFile *string `mapstructure:"galaxy_file" cty:"galaxy_file" hcl:"galaxy_file"` - GalaxyCommand *string `mapstructure:"galaxy_command" cty:"galaxy_command" hcl:"galaxy_command"` - GalaxyForceInstall *bool `mapstructure:"galaxy_force_install" cty:"galaxy_force_install" hcl:"galaxy_force_install"` - RolesPath *string `mapstructure:"roles_path" cty:"roles_path" hcl:"roles_path"` - UseProxy *bool `mapstructure:"use_proxy" cty:"use_proxy" hcl:"use_proxy"` + PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` + PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` + PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` + PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` + PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` + PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` + PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` + Command *string `cty:"command" hcl:"command"` + ExtraArguments []string `mapstructure:"extra_arguments" cty:"extra_arguments" hcl:"extra_arguments"` + AnsibleEnvVars []string `mapstructure:"ansible_env_vars" cty:"ansible_env_vars" hcl:"ansible_env_vars"` + PlaybookFile *string `mapstructure:"playbook_file" required:"true" cty:"playbook_file" hcl:"playbook_file"` + Groups []string `mapstructure:"groups" cty:"groups" hcl:"groups"` + EmptyGroups []string `mapstructure:"empty_groups" cty:"empty_groups" hcl:"empty_groups"` + HostAlias *string `mapstructure:"host_alias" cty:"host_alias" hcl:"host_alias"` + User *string `mapstructure:"user" cty:"user" hcl:"user"` + LocalPort *int `mapstructure:"local_port" cty:"local_port" hcl:"local_port"` + SSHHostKeyFile *string `mapstructure:"ssh_host_key_file" cty:"ssh_host_key_file" hcl:"ssh_host_key_file"` + SSHAuthorizedKeyFile *string `mapstructure:"ssh_authorized_key_file" cty:"ssh_authorized_key_file" hcl:"ssh_authorized_key_file"` + SFTPCmd *string `mapstructure:"sftp_command" cty:"sftp_command" hcl:"sftp_command"` + SkipVersionCheck *bool `mapstructure:"skip_version_check" cty:"skip_version_check" hcl:"skip_version_check"` + UseSFTP *bool `mapstructure:"use_sftp" cty:"use_sftp" hcl:"use_sftp"` + InventoryDirectory *string `mapstructure:"inventory_directory" cty:"inventory_directory" hcl:"inventory_directory"` + InventoryFileTemplate *string `mapstructure:"inventory_file_template" cty:"inventory_file_template" hcl:"inventory_file_template"` + InventoryFile *string `mapstructure:"inventory_file" cty:"inventory_file" hcl:"inventory_file"` + KeepInventoryFile *bool `mapstructure:"keep_inventory_file" cty:"keep_inventory_file" hcl:"keep_inventory_file"` + GalaxyFile *string `mapstructure:"galaxy_file" cty:"galaxy_file" hcl:"galaxy_file"` + GalaxyCommand *string `mapstructure:"galaxy_command" cty:"galaxy_command" hcl:"galaxy_command"` + GalaxyForceInstall *bool `mapstructure:"galaxy_force_install" cty:"galaxy_force_install" hcl:"galaxy_force_install"` + RolesPath *string `mapstructure:"roles_path" cty:"roles_path" hcl:"roles_path"` + UseProxy *bool `mapstructure:"use_proxy" cty:"use_proxy" hcl:"use_proxy"` } // FlatMapstructure returns a new FlatConfig. @@ -74,6 +75,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "skip_version_check": &hcldec.AttrSpec{Name: "skip_version_check", Type: cty.Bool, Required: false}, "use_sftp": &hcldec.AttrSpec{Name: "use_sftp", Type: cty.Bool, Required: false}, "inventory_directory": &hcldec.AttrSpec{Name: "inventory_directory", Type: cty.String, Required: false}, + "inventory_file_template": &hcldec.AttrSpec{Name: "inventory_file_template", Type: cty.String, Required: false}, "inventory_file": &hcldec.AttrSpec{Name: "inventory_file", Type: cty.String, Required: false}, "keep_inventory_file": &hcldec.AttrSpec{Name: "keep_inventory_file", Type: cty.Bool, Required: false}, "galaxy_file": &hcldec.AttrSpec{Name: "galaxy_file", Type: cty.String, Required: false}, diff --git a/website/pages/partials/provisioner/ansible/Config-not-required.mdx b/website/pages/partials/provisioner/ansible/Config-not-required.mdx index 816f73f64..e1b37071b 100644 --- a/website/pages/partials/provisioner/ansible/Config-not-required.mdx +++ b/website/pages/partials/provisioner/ansible/Config-not-required.mdx @@ -89,6 +89,15 @@ inventory directory with `host_vars` `group_vars` that you would like to use in the playbook that this provisioner will run. +- `inventory_file_template` (string) - This template represents the format for the lines added to the temporary + inventory file that Packer will create to run Ansible against your image. + The default for recent versions of Ansible is: + "{{ .HostAlias }} ansible_host={{ .Host }} ansible_user={{ .User }} ansible_port={{ .Port }}\n" + Available template engines are: This option is a template engine; + variables available to you include the examples in the default (Host, + HostAlias, User, Port) as well as any variables available to you via the + "build" template engine. + - `inventory_file` (string) - The inventory file to use during provisioning. When unspecified, Packer will create a temporary inventory file and will use the `host_alias`.