chef-solo: json_string to HCL2 templates compatibility (#10655)

This commit is contained in:
Sylvia Moss 2021-02-23 11:17:32 +01:00 committed by GitHub
parent 95fb13209a
commit ff5b55b560
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 43 deletions

View File

@ -56,7 +56,12 @@ type Config struct {
ExecuteCommand string `mapstructure:"execute_command"`
InstallCommand string `mapstructure:"install_command"`
RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths"`
Json map[string]interface{}
// HCL cannot be decoded into an interface so for HCL templates you must use the JsonString option,
// To be used with https://www.packer.io/docs/templates/hcl_templates/functions/encoding/jsonencode
// ref: https://github.com/hashicorp/hcl/issues/291#issuecomment-496347585
JsonString string `mapstructure:"json_string"`
// For JSON templates we keep the map[string]interface{}
Json map[string]interface{} `mapstructure:"json" mapstructure-to-hcl2:",skip"`
PreventSudo bool `mapstructure:"prevent_sudo"`
RunList []string `mapstructure:"run_list"`
SkipInstall bool `mapstructure:"skip_install"`
@ -120,6 +125,12 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
return err
}
if p.config.JsonString != "" {
if err := json.Unmarshal([]byte(p.config.JsonString), &p.config.Json); err != nil {
return fmt.Errorf("Failed to unmarshal 'json_string': %s", err.Error())
}
}
if p.config.GuestOSType == "" {
p.config.GuestOSType = guestexec.DefaultOSType
}
@ -398,12 +409,10 @@ func (p *Provisioner) createJson(ui packersdk.Ui, comm packersdk.Communicator) (
ui.Message("Creating JSON attribute file")
jsonData := make(map[string]interface{})
// Copy the configured JSON
for k, v := range p.config.Json {
jsonData[k] = v
}
// Set the run list if it was specified
if len(p.config.RunList) > 0 {
jsonData["run_list"] = p.config.RunList

View File

@ -29,7 +29,7 @@ type FlatConfig struct {
ExecuteCommand *string `mapstructure:"execute_command" cty:"execute_command" hcl:"execute_command"`
InstallCommand *string `mapstructure:"install_command" cty:"install_command" hcl:"install_command"`
RemoteCookbookPaths []string `mapstructure:"remote_cookbook_paths" cty:"remote_cookbook_paths" hcl:"remote_cookbook_paths"`
Json map[string]interface{} `cty:"json" hcl:"json"`
JsonString *string `mapstructure:"json_string" cty:"json_string" hcl:"json_string"`
PreventSudo *bool `mapstructure:"prevent_sudo" cty:"prevent_sudo" hcl:"prevent_sudo"`
RunList []string `mapstructure:"run_list" cty:"run_list" hcl:"run_list"`
SkipInstall *bool `mapstructure:"skip_install" cty:"skip_install" hcl:"skip_install"`
@ -69,7 +69,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"execute_command": &hcldec.AttrSpec{Name: "execute_command", Type: cty.String, Required: false},
"install_command": &hcldec.AttrSpec{Name: "install_command", Type: cty.String, Required: false},
"remote_cookbook_paths": &hcldec.AttrSpec{Name: "remote_cookbook_paths", Type: cty.List(cty.String), Required: false},
"json": &hcldec.AttrSpec{Name: "json", Type: cty.Map(cty.String), Required: false},
"json_string": &hcldec.AttrSpec{Name: "json_string", Type: cty.String, Required: false},
"prevent_sudo": &hcldec.AttrSpec{Name: "prevent_sudo", Type: cty.Bool, Required: false},
"run_list": &hcldec.AttrSpec{Name: "run_list", Type: cty.List(cty.String), Required: false},
"skip_install": &hcldec.AttrSpec{Name: "skip_install", Type: cty.Bool, Required: false},

View File

@ -356,3 +356,35 @@ func TestProvisionerPrepare_jsonNested(t *testing.T) {
t.Fatalf("nope: %#v", fooMap["bar"])
}
}
func TestProvisionerPrepare_jsonstring(t *testing.T) {
config := testConfig()
config["json_string"] = `{
"foo": {
"bar": "baz"
},
"bar": {
"bar": "baz"
},
"bFalse": false,
"bTrue": true,
"bStr": "bar",
"bNil": null,
"bInt": 1,
"bFloat": 4.5
}`
var p Provisioner
err := p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
fooMap := p.config.Json["foo"].(map[string]interface{})
if fooMap["bar"] != "baz" {
t.Fatalf("nope: %#v", fooMap["bar"])
}
if p.config.Json["bStr"] != "bar" {
t.Fatalf("nope: %#v", fooMap["bar"])
}
}

View File

@ -26,13 +26,29 @@ installed, using the official Chef installers provided by Chef Inc.
The example below is fully functional and expects cookbooks in the "cookbooks"
directory relative to your working directory.
```json
{
"type": "chef-solo",
"cookbook_paths": ["cookbooks"]
<Tabs>
<Tab heading="HCL2">
```hcl
provisioner "chef-solo" {
cookbook_paths = ["cookbooks"]
}
```
</Tab>
<Tab heading="JSON">
```json
"provisioners":[{
"type": "chef-solo",
"cookbook_paths": ["cookbooks"]
}]
```
</Tab>
</Tabs>
## Configuration Reference
The reference of available configuration options is listed below. No
@ -83,9 +99,6 @@ configuration is actually required, but at least `run_list` is recommended.
various [configuration template variables](/docs/templates/legacy_json_templates/engine)
available. See below for more information.
- `json` (object) - An arbitrary mapping of JSON that will be available as
node attributes while running Chef.
- `prevent_sudo` (boolean) - By default, the configured commands that are
executed to install and run Chef are executed with `sudo`. If this is true,
then the sudo will be omitted. This has no effect when guest_os_type is
@ -115,11 +128,56 @@ configuration is actually required, but at least `run_list` is recommended.
able to create directories and write into this folder. If the permissions
are not correct, use a shell provisioner prior to this to configure it
properly.
- `version` (string) - The version of Chef to be installed. By default this
is empty which will install the latest version of Chef.
@include 'provisioners/common-config.mdx'
##### Node Attribute Mapping
An arbitrary mapping of JSON that will be available as node attributes while running Chef.
<Tabs>
<Tab heading="HCL2">
- `json_string` (string) - The JSON string can be encoded using the [jsonencode](/docs/templates/hcl_templates/functions/encoding/jsonencode)
template function.
```hcl
provisioner "chef-solo" {
json_string = jsonencode({
"a" = "b"
"foo" = {
"bar" = "val"
"number" = 1
}
})
}
```
</Tab>
<Tab heading="JSON">
- `json` (object) - This option is only available to old-style JSON templates.
```json
"provisioners":[{
"type": "chef-solo",
"json": {
"a": "b",
"foo": {
"bar": "val",
"number": 1
}
}
}]
```
</Tab>
</Tabs>
## Chef Configuration
By default, Packer uses a simple Chef configuration file in order to set the