Unverified Commit eb8e3029 authored by Adrien Delorme's avatar Adrien Delorme Committed by GitHub
Browse files

hcl2_upgrade: special case: vsphere fix (#11216)

* fix typo

* hcl2_upgrade: special case linux_options and network_interface to block instead of maps

* Update hcl2_upgrade_test.go

* Update hcl2_upgrade_test.go

remove unused code

* hcl2_upgrade: support strftime too (#11220)

* hcl2_upgrade strftime function
* create legacy_strftime.mdx
parent 1d915ada
Showing with 178 additions and 7 deletions
+178 -7
......@@ -123,6 +123,7 @@ var (
localsVariableMap = map[string]string{}
timestamp = false
isotime = false
strftime = false
)
type BlockParser interface {
......@@ -192,7 +193,7 @@ func (c *HCL2UpgradeCommand) RunContext(_ context.Context, cla *HCL2UpgradeArgs)
builders := []*template.Builder{}
{
// sort builders to avoid map's randomnes
// sort builders to avoid map's randomness
for _, builder := range tpl.Builders {
builders = append(builders, builder)
}
......@@ -349,6 +350,14 @@ func transposeTemplatingCalls(s []byte) []byte {
return fmt.Sprintf("${legacy_isotime(\"%s\")}", a[0])
},
"strftime": func(a ...string) string {
if len(a) == 0 {
// returns rfc3339 formatted string.
return "${timestamp()}"
}
strftime = true
return fmt.Sprintf("${legacy_strftime(\"%s\")}", a[0])
},
"user": func(in string) string {
if _, ok := localsVariableMap[in]; ok {
// variable is now a local
......@@ -491,6 +500,7 @@ func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
"aws_secretsmanager": setIsLocal,
"timestamp": setIsLocal,
"isotime": setIsLocal,
"strftime": setIsLocal,
"user": setIsLocal,
"env": func(in string) string {
return fmt.Sprintf("${env(%q)}", in)
......@@ -562,6 +572,9 @@ func jsonBodyToHCL2Body(out *hclwrite.Body, kvs map[string]interface{}) {
case map[string]interface{}:
var mostComplexElem interface{}
for _, randomElem := range value {
if k == "linux_options" || k == "network_interface" {
break
}
// HACK: we take the most complex element of that map because
// in HCL2, map of objects can be bodies, for example:
// map containing object: source_ami_filter {} ( body )
......@@ -830,6 +843,9 @@ func (p *LocalsParser) Write(out *bytes.Buffer) {
if isotime {
fmt.Fprintln(out, `# The "legacy_isotime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.`)
}
if strftime {
fmt.Fprintln(out, `# The "legacy_strftime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.`)
}
if len(p.LocalsOut) > 0 {
if p.WithAnnotations {
out.Write([]byte(localsVarHeader))
......
......@@ -10,11 +10,6 @@ import (
)
func Test_hcl2_upgrade(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("Getwd: %v", err)
}
_ = cwd
tc := []struct {
folder string
......@@ -33,6 +28,7 @@ func Test_hcl2_upgrade(t *testing.T) {
{folder: "variables-with-variables", flags: []string{}},
{folder: "complete-variables-with-template-engine", flags: []string{}},
{folder: "escaping", flags: []string{}},
{folder: "vsphere_linux_options_and_network_interface", exitCode: 1, flags: []string{}},
{folder: "inexistent", flags: []string{}, exitCode: 1, exitEarly: true},
}
......
......@@ -34,6 +34,7 @@ data "amazon-secretsmanager" "autogenerated_2" {
key = "api_key"
name = "sample/app/passwords"
}
# The "legacy_strftime" function has been provided for backwards compatability, but we recommend switching to the timestamp and formatdate functions.
local "password" {
sensitive = true
......@@ -41,5 +42,6 @@ local "password" {
}
locals {
password_key = "MY_KEY_${data.amazon-secretsmanager.autogenerated_2.value}"
ami_description = "AMI ${legacy_strftime("%Y-%m")}"
password_key = "MY_KEY_${data.amazon-secretsmanager.autogenerated_2.value}"
}
......@@ -6,6 +6,7 @@
"aws_secret_key": "",
"aws_access_key": "",
"password": "{{ aws_secretsmanager `sample/app/password` }}",
"ami_description": "AMI {{strftime \"%Y-%m\"}}",
"password_key": "MY_KEY_{{ aws_secretsmanager `sample/app/passwords` `api_key` }}"
},
"sensitive-variables": [
......
source "vsphere-clone" "autogenerated_1" {
RAM_reserve_all = false
cluster = "USER_VALUE"
convert_to_template = false
customize {
dns_server_list = ["192.168.254.1", "192.168.254.2"]
ipv4_gateway = "172.15.102.254"
linux_options {
domain = "test.internal"
host_name = "packer-test"
}
network_interface {
ipv4_address = "172.15.102.202"
ipv4_netmask = "24"
}
}
datacenter = "USER_VALUE"
datastore = "USER_VALUE"
disable_shutdown = true
disk_controller_type = ["pvscsi", "pvscsi"]
insecure_connection = "true"
network = "USER_VALUE"
notes = "Build via Packer"
password = "USER_VALUE"
ssh_password = "Aa123456"
ssh_username = "root"
storage {
disk_controller_index = 0
disk_size = 100000
}
template = "erez's template"
username = "USER_VALUE"
vcenter_server = "USER_VALUE"
vm_name = "USER_VALUE"
}
build {
sources = ["source.vsphere-clone.autogenerated_1"]
}
{
"builders": [
{
"disable_shutdown": true,
"type": "vsphere-clone",
"vcenter_server": "USER_VALUE",
"username": "USER_VALUE",
"password": "USER_VALUE",
"insecure_connection": "true",
"datacenter": "USER_VALUE",
"cluster": "USER_VALUE",
"network": "USER_VALUE",
"datastore": "USER_VALUE",
"vm_name": "USER_VALUE",
"notes": "Build via Packer",
"ssh_username": "root",
"ssh_password": "Aa123456",
"template": "erez's template",
"RAM_reserve_all": false,
"convert_to_template": false,
"disk_controller_type": [
"pvscsi",
"pvscsi"
],
"storage": [
{
"disk_controller_index": 0,
"disk_size": 100000
}
],
"customize": {
"linux_options": {
"host_name": "packer-test",
"domain": "test.internal"
},
"network_interface": {
"ipv4_address": "172.15.102.202",
"ipv4_netmask": "24"
},
"ipv4_gateway": "172.15.102.254",
"dns_server_list": [
"192.168.254.1",
"192.168.254.2"
]
}
}
]
}
\ No newline at end of file
......@@ -57,6 +57,7 @@ require (
github.com/hashicorp/packer-plugin-vmware v1.0.0
github.com/hashicorp/packer-plugin-vsphere v1.0.0
github.com/hashicorp/packer-plugin-yandex v1.0.0
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec
github.com/masterzen/winrm v0.0.0-20210504160029-28ed956f5227
github.com/mattn/go-tty v0.0.0-20191112051231-74040eebce08
......
......@@ -4,6 +4,7 @@ import (
"fmt"
"time"
"github.com/jehiah/go-strftime"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
)
......@@ -55,6 +56,26 @@ var LegacyIsotimeFunc = function.New(&function.Spec{
},
})
// LegacyStrftimeFunc constructs a function that returns a string representation
// of the current date and time using golang's strftime datetime formatting.
var LegacyStrftimeFunc = function.New(&function.Spec{
Params: []function.Parameter{},
VarParam: &function.Parameter{
Name: "format",
Type: cty.String,
},
Type: function.StaticReturnType(cty.String),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
if len(args) > 1 {
return cty.StringVal(""), fmt.Errorf("too many values, 1 needed: %v", args)
} else if len(args) == 0 {
return cty.StringVal(InitTime.Format(time.RFC3339)), nil
}
format := args[0].AsString()
return cty.StringVal(strftime.Format(format, InitTime)), nil
},
})
// LegacyIsotimeFunc returns a string representation of the current date and
// time using the given format string. The format string follows golang's
// datetime formatting. See
......
......@@ -69,6 +69,7 @@ func Functions(basedir string) map[string]function.Function {
"jsonencode": stdlib.JSONEncodeFunc,
"keys": stdlib.KeysFunc,
"legacy_isotime": pkrfunction.LegacyIsotimeFunc,
"legacy_strftime": pkrfunction.LegacyStrftimeFunc,
"length": pkrfunction.LengthFunc,
"log": stdlib.LogFunc,
"lookup": stdlib.LookupFunc,
......
---
page_title: legacy_strftime - Functions - Configuration Language
description: |-
The legacy_strftime function returns a string representation of the current date
and time.
---
# `legacy_strftime` — UTC time, formated using the ISO C standard format
The `legacy_strftime` function returns the current date and time using the given
format string. The format string follows strftime's datetime formatting.
This function has been provided to create backwards compatibility with Packer's
legacy JSON templates. However, we recommend that you upgrade your HCL Packer
template to use
[`timestamp`](/docs/templates/hcl_templates/functions/datetime/timestamp) and
[`formatdate`](/docs/templates/hcl_templates/functions/datetime/formatdate)
together as soon as is convenient.
-> **Note:** If you are using a large number of builders, provisioners or
post-processors, the strftime may be slightly different for each one because it
is from when the plugin is launched not the initial Packer process. In order to
avoid this and make the timestamp consistent across all plugins, set it as a
user variable and then access the user variable within your plugins.
## Examples
```shell-session
> legacy_strftime("%Y-%m")
2021-08
```
## Related Functions
- [`format`](/docs/templates/hcl_templates/functions/string/format) is a more general formatting function for arbitrary
data.
- [`timestamp`](/docs/templates/hcl_templates/functions/datetime/timestamp) returns the current date and time in a format
suitable for input to `formatdate`.
- [`formatdate`](/docs/templates/hcl_templates/functions/datetime/formatdate) can convert the resulting timestamp to
other date and time formats.
......@@ -482,6 +482,10 @@
{
"title": "legacy_isotime",
"path": "templates/hcl_templates/functions/datetime/legacy_isotime"
},
{
"title": "legacy_strftime",
"path": "templates/hcl_templates/functions/datetime/legacy_strftime"
}
]
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment