HCL2: allow calling env as input var default value (#10240)
* HCL2: allow to use env in default value of input variables
This commit is contained in:
parent
17ec88246f
commit
deba1484ff
|
@ -78,7 +78,9 @@ local.fruit: "banana"
|
|||
|
||||
> input-variables:
|
||||
|
||||
var.default_from_env: ""
|
||||
var.fruit: "peach"
|
||||
var.other_default_from_env: ""
|
||||
var.unknown_list_of_string: "[\n \"first_peach\",\n \"second_peach\",\n]"
|
||||
var.unknown_string: "also_peach"
|
||||
var.unknown_unknown: "[\"peach_too\"]"
|
||||
|
@ -89,11 +91,13 @@ var.unknown_unknown: "[\"peach_too\"]"
|
|||
> builds:
|
||||
|
||||
`},
|
||||
{[]string{"inspect", "-var=fruit=peach", filepath.Join(testFixture("hcl"), "inspect")}, nil, `Packer Inspect: HCL2 mode
|
||||
{[]string{"inspect", "-var=fruit=peach", "-var=other_default_from_env=apple", filepath.Join(testFixture("hcl"), "inspect")}, []string{"DEFAULT_FROM_ENV=cherry"}, `Packer Inspect: HCL2 mode
|
||||
|
||||
> input-variables:
|
||||
|
||||
var.default_from_env: "cherry"
|
||||
var.fruit: "peach"
|
||||
var.other_default_from_env: "apple"
|
||||
var.unknown_list_of_string: "<unknown>"
|
||||
var.unknown_string: "<unknown>"
|
||||
var.unknown_unknown: "<unknown>"
|
||||
|
|
|
@ -15,3 +15,11 @@ variable "unknown_list_of_string" {
|
|||
|
||||
variable "unknown_unknown" {
|
||||
}
|
||||
|
||||
variable "default_from_env" {
|
||||
default = env("DEFAULT_FROM_ENV")
|
||||
}
|
||||
|
||||
variable "other_default_from_env" {
|
||||
default = env("OTHER_DEFAULT_FROM_ENV")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package function
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
)
|
||||
|
||||
// EnvFunc constructs a function that returns a string representation of the
|
||||
// env var behind a value
|
||||
var EnvFunc = function.New(&function.Spec{
|
||||
Params: []function.Parameter{
|
||||
{
|
||||
Name: "key",
|
||||
Type: cty.String,
|
||||
AllowNull: false,
|
||||
AllowUnknown: false,
|
||||
},
|
||||
},
|
||||
Type: function.StaticReturnType(cty.String),
|
||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||
key := args[0].AsString()
|
||||
value := os.Getenv(key)
|
||||
return cty.StringVal(value), nil
|
||||
},
|
||||
})
|
||||
|
||||
// Env returns a string representation of the env var behind key.
|
||||
func Env(key cty.Value) (cty.Value, error) {
|
||||
return EnvFunc.Call([]cty.Value{key})
|
||||
}
|
|
@ -8,9 +8,11 @@ import (
|
|||
"github.com/gobwas/glob"
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
pkrfunction "github.com/hashicorp/packer/hcl2template/function"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/version"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
"github.com/zclconf/go-cty/cty/function"
|
||||
)
|
||||
|
||||
// PackerConfig represents a loaded Packer HCL config. It will contain
|
||||
|
@ -107,16 +109,23 @@ func (c *PackerConfig) decodeInputVariables(f *hcl.File) hcl.Diagnostics {
|
|||
content, moreDiags := f.Body.Content(configSchema)
|
||||
diags = append(diags, moreDiags...)
|
||||
|
||||
// for input variables we allow to use env in the default value section.
|
||||
ectx := &hcl.EvalContext{
|
||||
Functions: map[string]function.Function{
|
||||
"env": pkrfunction.EnvFunc,
|
||||
},
|
||||
}
|
||||
|
||||
for _, block := range content.Blocks {
|
||||
switch block.Type {
|
||||
case variableLabel:
|
||||
moreDiags := c.InputVariables.decodeVariableBlock(block, nil)
|
||||
moreDiags := c.InputVariables.decodeVariableBlock(block, ectx)
|
||||
diags = append(diags, moreDiags...)
|
||||
case variablesLabel:
|
||||
attrs, moreDiags := block.Body.JustAttributes()
|
||||
diags = append(diags, moreDiags...)
|
||||
for key, attr := range attrs {
|
||||
moreDiags = c.InputVariables.decodeVariable(key, attr, nil)
|
||||
moreDiags = c.InputVariables.decodeVariable(key, attr, ectx)
|
||||
diags = append(diags, moreDiags...)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,7 +246,8 @@ var variableBlockSchema = &hcl.BodySchema{
|
|||
},
|
||||
}
|
||||
|
||||
// decodeVariableBlock decodes a "variables" section the way packer 1 used to
|
||||
// decodeVariableBlock decodes a "variable" block
|
||||
// ectx is passed only in the evaluation of the default value.
|
||||
func (variables *Variables) decodeVariableBlock(block *hcl.Block, ectx *hcl.EvalContext) hcl.Diagnostics {
|
||||
if (*variables) == nil {
|
||||
(*variables) = Variables{}
|
||||
|
@ -473,6 +474,7 @@ func decodeVariableValidationBlock(varName string, block *hcl.Block) (*VariableV
|
|||
// Packer's specific style, rather than that they are going to try to work
|
||||
// around these rules to write a lower-quality message.
|
||||
func looksLikeSentences(s string) bool {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) < 1 {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ export default [
|
|||
content: [
|
||||
'aws_secretsmanager',
|
||||
'consul',
|
||||
'env',
|
||||
'vault',
|
||||
],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
layout: docs
|
||||
page_title: env - Functions - Configuration Language
|
||||
sidebar_title: env
|
||||
description: The env function retrieves environment values for input variables.
|
||||
---
|
||||
|
||||
# `env` Function
|
||||
|
||||
```hcl
|
||||
variable "aws_region" {
|
||||
default = env("AWS_DEFAULT_REGION")
|
||||
}
|
||||
```
|
||||
|
||||
`env` allows you to get the value for an environment variable inside input
|
||||
variables _only_. This is the only function that is callable from a variable
|
||||
block and it can only be used in the default input. `env` cannot be called from
|
||||
other places.
|
||||
|
||||
In the previous example, the value of `aws_region` will be what's stored in the
|
||||
`AWS_DEFAULT_REGION` env var, unless aws_region is also set in a [manner that takes
|
||||
precedence](/docs/from-1.5/variables#variable-definition-precedence).
|
||||
|
||||
|
||||
-> **Why can't I use environment variables elsewhere?** User variables are the
|
||||
single source of configurable input. We felt that having environment variables
|
||||
used _anywhere_ in a configuration would confuse the user about the possible inputs
|
||||
to a template. By allowing environment variables only within default values for
|
||||
input variables, input variables remain as the single source of input to a
|
||||
template that a user can easily discover using `packer inspect`.
|
||||
|
||||
When the environment variable is not set at all -- not even with the empty
|
||||
string -- the value returned by `env` will be an an empty string. It will still
|
||||
be possible to set it using other means but you could use [custom validation
|
||||
rules](/docs/from-1.5/variables#custom-validation-rules) to error in that case
|
||||
to make sure it is set, for example:
|
||||
|
||||
```hcl
|
||||
variable "aws_region" {
|
||||
default = env("AWS_DEFAULT_REGION")
|
||||
|
||||
validation {
|
||||
condition = length(var.aws_region) > 0
|
||||
error_message = <<EOF
|
||||
The aws_region var is not set: make sure to at least set the AWS_DEFAULT_REGION env var.
|
||||
To fix this you could also set the aws_region variable from the arguments, for example:
|
||||
$ packer build -var=aws_region=us-something-1...
|
||||
EOF
|
||||
}
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue