Merge pull request #7456 from hashicorp/do_5770
introduce the clean_resource_name to clean image/var names
This commit is contained in:
commit
3e72e65a6c
|
@ -101,7 +101,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||||
errs = append(errs, fmt.Errorf("AMIName should only contain "+
|
errs = append(errs, fmt.Errorf("AMIName should only contain "+
|
||||||
"alphanumeric characters, parentheses (()), square brackets ([]), spaces "+
|
"alphanumeric characters, parentheses (()), square brackets ([]), spaces "+
|
||||||
"( ), periods (.), slashes (/), dashes (-), single quotes ('), at-signs "+
|
"( ), periods (.), slashes (/), dashes (-), single quotes ('), at-signs "+
|
||||||
"(@), or underscores(_). You can use the `clean_ami_name` template "+
|
"(@), or underscores(_). You can use the `clean_resource_name` template "+
|
||||||
"filter to automatically clean your ami name."))
|
"filter to automatically clean your ami name."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ package common
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
packertpl "github.com/hashicorp/packer/common/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isalphanumeric(b byte) bool {
|
func isalphanumeric(b byte) bool {
|
||||||
|
@ -36,5 +38,6 @@ func templateCleanAMIName(s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var TemplateFuncs = template.FuncMap{
|
var TemplateFuncs = template.FuncMap{
|
||||||
"clean_ami_name": templateCleanAMIName,
|
"clean_resource_name": templateCleanAMIName,
|
||||||
|
"clean_ami_name": packertpl.DeprecatedTemplateFunc("clean_ami_name", "clean_resource_name", templateCleanAMIName),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package arm
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
packertpl "github.com/hashicorp/packer/common/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isValidByteValue(b byte) bool {
|
func isValidByteValue(b byte) bool {
|
||||||
|
@ -39,5 +41,6 @@ func templateCleanImageName(s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var TemplateFuncs = template.FuncMap{
|
var TemplateFuncs = template.FuncMap{
|
||||||
"clean_image_name": templateCleanImageName,
|
"clean_resource_name": templateCleanImageName,
|
||||||
|
"clean_image_name": packertpl.DeprecatedTemplateFunc("clean_image_name", "clean_resource_name", templateCleanImageName),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package googlecompute
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
packertpl "github.com/hashicorp/packer/common/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isalphanumeric(b byte) bool {
|
func isalphanumeric(b byte) bool {
|
||||||
|
@ -34,5 +36,6 @@ func templateCleanImageName(s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var TemplateFuncs = template.FuncMap{
|
var TemplateFuncs = template.FuncMap{
|
||||||
"clean_image_name": templateCleanImageName,
|
"clean_resource_name": templateCleanImageName,
|
||||||
|
"clean_image_name": packertpl.DeprecatedTemplateFunc("clean_image_name", "clean_resource_name", templateCleanImageName),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeprecatedTemplateFunc wraps a template func to warn users that it's
|
||||||
|
// deprecated. The deprecation warning is called only once.
|
||||||
|
func DeprecatedTemplateFunc(funcName, useInstead string, deprecated func(string) string) func(string) string {
|
||||||
|
once := sync.Once{}
|
||||||
|
return func(in string) string {
|
||||||
|
once.Do(func() {
|
||||||
|
log.Printf("[WARN]: the `%s` template func is deprecated, please use %s instead",
|
||||||
|
funcName, useInstead)
|
||||||
|
})
|
||||||
|
return deprecated(in)
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ func init() {
|
||||||
"hyperv-vmxc-typo": new(FixerHypervVmxcTypo),
|
"hyperv-vmxc-typo": new(FixerHypervVmxcTypo),
|
||||||
"hyperv-cpu-and-ram": new(FizerHypervCPUandRAM),
|
"hyperv-cpu-and-ram": new(FizerHypervCPUandRAM),
|
||||||
"vmware-compaction": new(FixerVMwareCompaction),
|
"vmware-compaction": new(FixerVMwareCompaction),
|
||||||
|
"clean-image-name": new(FixerCleanImageName),
|
||||||
}
|
}
|
||||||
|
|
||||||
FixerOrder = []string{
|
FixerOrder = []string{
|
||||||
|
@ -65,5 +66,6 @@ func init() {
|
||||||
"powershell-escapes",
|
"powershell-escapes",
|
||||||
"vmware-compaction",
|
"vmware-compaction",
|
||||||
"hyperv-cpu-and-ram",
|
"hyperv-cpu-and-ram",
|
||||||
|
"clean-image-name",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package fix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FixerCleanImageName is a Fixer that replaces the "clean_(image|ami)_name" template
|
||||||
|
// calls with "clean_resource_name"
|
||||||
|
type FixerCleanImageName struct{}
|
||||||
|
|
||||||
|
func (FixerCleanImageName) Fix(input map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
// Our template type we'll use for this fixer only
|
||||||
|
type template struct {
|
||||||
|
Builders []map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the input into our structure, if we can
|
||||||
|
var tpl template
|
||||||
|
if err := mapstructure.Decode(input, &tpl); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`clean_(image|ami)_name`)
|
||||||
|
|
||||||
|
// Go through each builder and replace CreateTime if we can
|
||||||
|
for _, builder := range tpl.Builders {
|
||||||
|
for key, value := range builder {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
changed := re.ReplaceAllString(v, "clean_resource_name")
|
||||||
|
builder[key] = changed
|
||||||
|
case map[string]string:
|
||||||
|
for k := range v {
|
||||||
|
v[k] = re.ReplaceAllString(v[k], "clean_resource_name")
|
||||||
|
}
|
||||||
|
builder[key] = v
|
||||||
|
case map[string]interface{}:
|
||||||
|
for k := range v {
|
||||||
|
if s, ok := v[k].(string); ok {
|
||||||
|
v[k] = re.ReplaceAllString(s, "clean_resource_name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder[key] = v
|
||||||
|
default:
|
||||||
|
if key == "image_labels" {
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("value: %#v", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input["builders"] = tpl.Builders
|
||||||
|
return input, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (FixerCleanImageName) Synopsis() string {
|
||||||
|
return `Replaces /clean_(image|ami)_name/ in builder configs with "clean_resource_name"`
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package fix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFixerCleanImageName_Impl(t *testing.T) {
|
||||||
|
var raw interface{}
|
||||||
|
raw = new(FixerCleanImageName)
|
||||||
|
if _, ok := raw.(Fixer); !ok {
|
||||||
|
t.Fatalf("must be a Fixer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFixerCleanImageName_Fix(t *testing.T) {
|
||||||
|
var f FixerCleanImageName
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"builders": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"type": "foo",
|
||||||
|
"ami_name": "heyo clean_image_name",
|
||||||
|
"image_labels": map[string]interface{}{
|
||||||
|
"name": "test-packer-{{packer_version | clean_image_name}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[string]interface{}{
|
||||||
|
"builders": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"type": "foo",
|
||||||
|
"ami_name": "heyo clean_resource_name",
|
||||||
|
"image_labels": map[string]interface{}{
|
||||||
|
"name": "test-packer-{{packer_version | clean_resource_name}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := f.Fix(input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(expected, output); diff != "" {
|
||||||
|
t.Fatalf("unexpected output: %s", diff)
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,10 +27,10 @@ The syntax of templates uses the following conventions:
|
||||||
Functions perform operations on and within strings, for example the
|
Functions perform operations on and within strings, for example the
|
||||||
`{{timestamp}}` function can be used in any string to generate the current
|
`{{timestamp}}` function can be used in any string to generate the current
|
||||||
timestamp. This is useful for configurations that require unique keys, such as
|
timestamp. This is useful for configurations that require unique keys, such as
|
||||||
AMI names. By setting the AMI name to something like
|
AMI names. By setting the AMI name to something like `My Packer AMI
|
||||||
`My Packer AMI {{timestamp}}`, the AMI name will be unique down to the second.
|
{{timestamp}}`, the AMI name will be unique down to the second. If you need
|
||||||
If you need greater than one second granularity, you should use `{{uuid}}`, for
|
greater than one second granularity, you should use `{{uuid}}`, for example
|
||||||
example when you have multiple builders in the same template.
|
when you have multiple builders in the same template.
|
||||||
|
|
||||||
Here is a full list of the available functions for reference.
|
Here is a full list of the available functions for reference.
|
||||||
|
|
||||||
|
@ -54,18 +54,41 @@ Here is a full list of the available functions for reference.
|
||||||
- `upper` - Uppercases the string.
|
- `upper` - Uppercases the string.
|
||||||
- `user` - Specifies a user variable.
|
- `user` - Specifies a user variable.
|
||||||
- `packer_version` - Returns Packer version.
|
- `packer_version` - Returns Packer version.
|
||||||
|
- `clean_resource_name` - Image names can only contain certain characters and
|
||||||
|
have a maximum length, eg 63 on GCE & 80 on Azure. `clean_resource_name`
|
||||||
|
will convert upper cases to lower cases and replace illegal characters with
|
||||||
|
a "-" character. Example:
|
||||||
|
|
||||||
|
`"mybuild-{{isotime | clean_image_name}}"` will become
|
||||||
|
`mybuild-2017-10-18t02-06-30z`.
|
||||||
|
|
||||||
|
Note: Valid Azure image names must match the regex
|
||||||
|
`^[^_\\W][\\w-._)]{0,79}$`
|
||||||
|
|
||||||
|
Note: Valid GCE image names must match the regex
|
||||||
|
`(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)`
|
||||||
|
|
||||||
|
This engine does not guarantee that the final image name will match the
|
||||||
|
regex; it will not truncate your name if it exceeds the maximum number of
|
||||||
|
allowed characters, and it will not validate that the beginning and end of
|
||||||
|
the engine's output are valid. For example, `"image_name": {{isotime |
|
||||||
|
clean_resource_name}}"` will cause your build to fail because the image
|
||||||
|
name will start with a number, which is why in the above example we prepend
|
||||||
|
the isotime with "mybuild".
|
||||||
|
|
||||||
#### Specific to Amazon builders:
|
#### Specific to Amazon builders:
|
||||||
|
|
||||||
- `clean_ami_name` - AMI names can only contain certain characters. This
|
- `clean_ami_name` - DEPRECATED use `clean_resource_name` instead - AMI names
|
||||||
function will replace illegal characters with a '-" character. Example
|
can only contain certain characters. This function will replace illegal
|
||||||
usage since ":" is not a legal AMI name is: `{{isotime | clean_ami_name}}`.
|
characters with a '-" character. Example usage since ":" is not a legal AMI
|
||||||
|
name is: `{{isotime | clean_ami_name}}`.
|
||||||
|
|
||||||
#### Specific to Google Compute builders:
|
#### Specific to Google Compute builders:
|
||||||
|
|
||||||
- `clean_image_name` - GCE image names can only contain certain characters
|
- `clean_image_name` - DEPRECATED use `clean_resource_name` instead - GCE
|
||||||
and the maximum length is 63. This function will convert upper cases to
|
image names can only contain certain characters and the maximum length is
|
||||||
lower cases and replace illegal characters with a "-" character. Example:
|
63. This function will convert upper cases to lower cases and replace
|
||||||
|
illegal characters with a "-" character. Example:
|
||||||
|
|
||||||
`"mybuild-{{isotime | clean_image_name}}"` will become
|
`"mybuild-{{isotime | clean_image_name}}"` will become
|
||||||
`mybuild-2017-10-18t02-06-30z`.
|
`mybuild-2017-10-18t02-06-30z`.
|
||||||
|
@ -82,9 +105,10 @@ Here is a full list of the available functions for reference.
|
||||||
|
|
||||||
#### Specific to Azure builders:
|
#### Specific to Azure builders:
|
||||||
|
|
||||||
- `clean_image_name` - Azure managed image names can only contain certain
|
- `clean_image_name` - DEPRECATED use `clean_resource_name` instead - Azure
|
||||||
characters and the maximum length is 80. This function will replace illegal
|
managed image names can only contain certain characters and the maximum
|
||||||
characters with a "-" character. Example:
|
length is 80. This function will replace illegal characters with a "-"
|
||||||
|
character. Example:
|
||||||
|
|
||||||
`"mybuild-{{isotime | clean_image_name}}"` will become
|
`"mybuild-{{isotime | clean_image_name}}"` will become
|
||||||
`mybuild-2017-10-18t02-06-30z`.
|
`mybuild-2017-10-18t02-06-30z`.
|
||||||
|
@ -96,9 +120,8 @@ Here is a full list of the available functions for reference.
|
||||||
regex; it will not truncate your name if it exceeds 80 characters, and it
|
regex; it will not truncate your name if it exceeds 80 characters, and it
|
||||||
will not validate that the beginning and end of the engine's output are
|
will not validate that the beginning and end of the engine's output are
|
||||||
valid. It will truncate invalid characters from the end of the name when
|
valid. It will truncate invalid characters from the end of the name when
|
||||||
converting illegal characters. For example,
|
converting illegal characters. For example, `"managed_image_name:
|
||||||
`"managed_image_name: "My-Name::"` will be converted to
|
"My-Name::"` will be converted to `"managed_image_name: "My-Name"`
|
||||||
`"managed_image_name: "My-Name"`
|
|
||||||
|
|
||||||
## Template variables
|
## Template variables
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue