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 "+
|
||||
"alphanumeric characters, parentheses (()), square brackets ([]), spaces "+
|
||||
"( ), 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."))
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package common
|
|||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
|
||||
packertpl "github.com/hashicorp/packer/common/template"
|
||||
)
|
||||
|
||||
func isalphanumeric(b byte) bool {
|
||||
|
@ -36,5 +38,6 @@ func templateCleanAMIName(s string) string {
|
|||
}
|
||||
|
||||
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 (
|
||||
"bytes"
|
||||
"text/template"
|
||||
|
||||
packertpl "github.com/hashicorp/packer/common/template"
|
||||
)
|
||||
|
||||
func isValidByteValue(b byte) bool {
|
||||
|
@ -39,5 +41,6 @@ func templateCleanImageName(s string) string {
|
|||
}
|
||||
|
||||
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 (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
packertpl "github.com/hashicorp/packer/common/template"
|
||||
)
|
||||
|
||||
func isalphanumeric(b byte) bool {
|
||||
|
@ -34,5 +36,6 @@ func templateCleanImageName(s string) string {
|
|||
}
|
||||
|
||||
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-cpu-and-ram": new(FizerHypervCPUandRAM),
|
||||
"vmware-compaction": new(FixerVMwareCompaction),
|
||||
"clean-image-name": new(FixerCleanImageName),
|
||||
}
|
||||
|
||||
FixerOrder = []string{
|
||||
|
@ -65,5 +66,6 @@ func init() {
|
|||
"powershell-escapes",
|
||||
"vmware-compaction",
|
||||
"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
|
||||
`{{timestamp}}` function can be used in any string to generate the current
|
||||
timestamp. This is useful for configurations that require unique keys, such as
|
||||
AMI names. By setting the AMI name to something like
|
||||
`My Packer AMI {{timestamp}}`, the AMI name will be unique down to the second.
|
||||
If you need greater than one second granularity, you should use `{{uuid}}`, for
|
||||
example when you have multiple builders in the same template.
|
||||
AMI names. By setting the AMI name to something like `My Packer AMI
|
||||
{{timestamp}}`, the AMI name will be unique down to the second. If you need
|
||||
greater than one second granularity, you should use `{{uuid}}`, for example
|
||||
when you have multiple builders in the same template.
|
||||
|
||||
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.
|
||||
- `user` - Specifies a user variable.
|
||||
- `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:
|
||||
|
||||
- `clean_ami_name` - AMI names can only contain certain characters. This
|
||||
function will replace illegal characters with a '-" character. Example
|
||||
usage since ":" is not a legal AMI name is: `{{isotime | clean_ami_name}}`.
|
||||
- `clean_ami_name` - DEPRECATED use `clean_resource_name` instead - AMI names
|
||||
can only contain certain characters. This function will replace illegal
|
||||
characters with a '-" character. Example usage since ":" is not a legal AMI
|
||||
name is: `{{isotime | clean_ami_name}}`.
|
||||
|
||||
#### Specific to Google Compute builders:
|
||||
|
||||
- `clean_image_name` - GCE image names can only contain certain characters
|
||||
and the maximum length is 63. This function will convert upper cases to
|
||||
lower cases and replace illegal characters with a "-" character. Example:
|
||||
- `clean_image_name` - DEPRECATED use `clean_resource_name` instead - GCE
|
||||
image names can only contain certain characters and the maximum length is
|
||||
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-2017-10-18t02-06-30z`.
|
||||
|
@ -82,9 +105,10 @@ Here is a full list of the available functions for reference.
|
|||
|
||||
#### Specific to Azure builders:
|
||||
|
||||
- `clean_image_name` - Azure managed image names can only contain certain
|
||||
characters and the maximum length is 80. This function will replace illegal
|
||||
characters with a "-" character. Example:
|
||||
- `clean_image_name` - DEPRECATED use `clean_resource_name` instead - Azure
|
||||
managed image names can only contain certain characters and the maximum
|
||||
length is 80. This function will replace illegal characters with a "-"
|
||||
character. Example:
|
||||
|
||||
`"mybuild-{{isotime | clean_image_name}}"` will become
|
||||
`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
|
||||
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
|
||||
converting illegal characters. For example,
|
||||
`"managed_image_name: "My-Name::"` will be converted to
|
||||
`"managed_image_name: "My-Name"`
|
||||
converting illegal characters. For example, `"managed_image_name:
|
||||
"My-Name::"` will be converted to `"managed_image_name: "My-Name"`
|
||||
|
||||
## Template variables
|
||||
|
||||
|
|
Loading…
Reference in New Issue