packer: allow environmental variables within user vars [GH-633]
This commit is contained in:
parent
8aabe01bad
commit
e38c0424b9
|
@ -26,6 +26,9 @@ FEATURES:
|
|||
an existing OVF or OVA. [GH-201]
|
||||
* **New builder:** "vmware-vmx" can build VMware images from an existing
|
||||
VMX. [GH-201]
|
||||
* Environmental variables can now be accessed as default values for
|
||||
user variables using the "env" function. See the documentation for more
|
||||
information.
|
||||
* "description" field in templates: write a human-readable description
|
||||
of what a template does. This will be shown in `packer inspect`.
|
||||
* Vagrant post-processor now accepts a list of files to include in the
|
||||
|
|
|
@ -37,6 +37,7 @@ func NewConfigTemplate() (*ConfigTemplate, error) {
|
|||
|
||||
result.root = template.New("configTemplateRoot")
|
||||
result.root.Funcs(template.FuncMap{
|
||||
"env": templateDisableEnv,
|
||||
"pwd": templatePwd,
|
||||
"isotime": templateISOTime,
|
||||
"timestamp": templateTimestamp,
|
||||
|
@ -95,6 +96,20 @@ func (t *ConfigTemplate) templateUser(n string) (string, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func templateDisableEnv(n string) (string, error) {
|
||||
return "", fmt.Errorf(
|
||||
"Environmental variables can only be used as default values for user variables.")
|
||||
}
|
||||
|
||||
func templateDisableUser(n string) (string, error) {
|
||||
return "", fmt.Errorf(
|
||||
"User variable can't be used within a default value for a user variable: %s", n)
|
||||
}
|
||||
|
||||
func templateEnv(n string) string {
|
||||
return os.Getenv(n)
|
||||
}
|
||||
|
||||
func templateISOTime() string {
|
||||
return time.Now().UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,18 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func TestConfigTemplateProcess_env(t *testing.T) {
|
||||
tpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
_, err = tpl.Process(`{{env "foo"}}`, nil)
|
||||
if err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigTemplateProcess_isotime(t *testing.T) {
|
||||
tpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -450,6 +451,18 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
return
|
||||
}
|
||||
|
||||
// Prepare the variable template processor, which is a bit unique
|
||||
// because we don't allow user variable usage and we add a function
|
||||
// to read from the environment.
|
||||
varTpl, err := NewConfigTemplate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
varTpl.Funcs(template.FuncMap{
|
||||
"env": templateEnv,
|
||||
"user": templateDisableUser,
|
||||
})
|
||||
|
||||
// Prepare the variables
|
||||
var varErrors []error
|
||||
variables := make(map[string]string)
|
||||
|
@ -459,9 +472,15 @@ func (t *Template) Build(name string, components *ComponentFinder) (b Build, err
|
|||
fmt.Errorf("Required user variable '%s' not set", k))
|
||||
}
|
||||
|
||||
var val string = v.Default
|
||||
var val string
|
||||
if v.HasValue {
|
||||
val = v.Value
|
||||
} else {
|
||||
val, err = varTpl.Process(v.Default, nil)
|
||||
if err != nil {
|
||||
varErrors = append(varErrors,
|
||||
fmt.Errorf("Error processing user variable '%s': %s'", k, err))
|
||||
}
|
||||
}
|
||||
|
||||
variables[k] = val
|
||||
|
|
|
@ -688,6 +688,47 @@ func TestTemplate_BuildUnknownBuilder(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_envInVars(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"variables": {
|
||||
"foo": "{{env \"foo\"}}"
|
||||
},
|
||||
|
||||
"builders": [
|
||||
{
|
||||
"name": "test1",
|
||||
"type": "test-builder"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
defer os.Setenv("foo", os.Getenv("foo"))
|
||||
if err := os.Setenv("foo", "bar"); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
template, err := ParseTemplate([]byte(data), map[string]string{})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
b, err := template.Build("test1", testComponentFinder())
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
coreBuild, ok := b.(*coreBuild)
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
|
||||
if coreBuild.variables["foo"] != "bar" {
|
||||
t.Fatalf("bad: %#v", coreBuild.variables)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateBuild_names(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
|
|
|
@ -58,6 +58,36 @@ This function can be used in _any value_ within the template, in
|
|||
builders, provisioners, _anything_. The user variable is available globally
|
||||
within the template.
|
||||
|
||||
## Environmental Variables
|
||||
|
||||
Environmental variables can be used within your template using user
|
||||
variables. The `env` function is available _only_ within the default value
|
||||
of a user variable, allowing you to default a user variable to an
|
||||
environmental variable. An example is shown below:
|
||||
|
||||
<pre class="prettyprint">
|
||||
{
|
||||
"variables": {
|
||||
"my_secret": "{{env `MY_SECRET`}}",
|
||||
},
|
||||
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
This will default "my\_secret" to be the value of the "MY\_SECRET"
|
||||
environmental variable (or the empty string if it does not exist).
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Why can't I use environmental variables elsewhere?</strong>
|
||||
User variables are the single source of configurable input to a template.
|
||||
We felt that having environmental variables used <em>anywhere</em> in a
|
||||
template would confuse the user about the possible inputs to a template.
|
||||
By allowing environmental variables only within default values for user
|
||||
variables, user variables remain as the single source of input to a template
|
||||
that a user can easily discover using <code>packer inspect</code>.
|
||||
</div>
|
||||
|
||||
## Setting Variables
|
||||
|
||||
Now that we covered how to define and use variables within a template,
|
||||
|
|
Loading…
Reference in New Issue