Make the Chef `attributes` param also accept a raw JSON string

See the updated docs for more details and examples, but in short this
enables the `attributes` param from the Chef provisioner to accept a
raw JSON string.

Fixes #3074
Fixes #3572
This commit is contained in:
Sander van Harmelen 2016-01-29 18:41:14 +01:00
parent 2dca1ea9a0
commit da927fcd08
5 changed files with 85 additions and 14 deletions

View File

@ -236,7 +236,33 @@ func TestResourceProvider_linuxCreateConfigFiles(t *testing.T) {
},
},
"Attributes": {
"String Attributes": {
Config: testConfig(t, map[string]interface{}{
"attributes": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` +
`"subkey2b":{"subkey3":"value3"}}},"key2":"value2"}`,
"node_name": "nodename1",
"prevent_sudo": true,
"run_list": []interface{}{"cookbook::recipe"},
"secret_key_path": "test-fixtures/encrypted_data_bag_secret",
"server_url": "https://chef.local",
"validation_client_name": "validator",
"validation_key_path": "test-fixtures/validator.pem",
}),
Commands: map[string]bool{
"mkdir -p " + linuxConfDir: true,
},
Uploads: map[string]string{
linuxConfDir + "/client.rb": defaultLinuxClientConf,
linuxConfDir + "/encrypted_data_bag_secret": "SECRET-KEY-FILE",
linuxConfDir + "/validation.pem": "VALIDATOR-PEM-FILE",
linuxConfDir + "/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` +
`"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`,
},
},
"Map Attributes": {
Config: testConfig(t, map[string]interface{}{
"attributes": []map[string]interface{}{
map[string]interface{}{

View File

@ -222,6 +222,12 @@ func (r *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string
ws = append(ws, "secret_key_path is deprecated, please use "+
"secret_key instead and load the key contents via file()")
}
if attrs, ok := c.Config["attributes"]; ok {
if _, ok := attrs.(string); !ok {
ws = append(ws, "using map style attribute values is deprecated, "+
" please use a single raw JSON string instead")
}
}
return ws, es
}
@ -280,9 +286,18 @@ func (r *ResourceProvisioner) decodeConfig(c *terraform.ResourceConfig) (*Provis
}
if attrs, ok := c.Config["attributes"]; ok {
p.Attributes, err = rawToJSON(attrs)
if err != nil {
return nil, fmt.Errorf("Error parsing the attributes: %v", err)
switch attrs := attrs.(type) {
case string:
var m map[string]interface{}
if err := json.Unmarshal([]byte(attrs), &m); err != nil {
return nil, fmt.Errorf("Error parsing the attributes: %v", err)
}
p.Attributes = m
default:
p.Attributes, err = rawToJSON(attrs)
if err != nil {
return nil, fmt.Errorf("Error parsing the attributes: %v", err)
}
}
}
@ -306,7 +321,7 @@ func rawToJSON(raw interface{}) (interface{}, error) {
return s[0], nil
default:
return raw, nil
return s, nil
}
}

View File

@ -16,7 +16,6 @@ func TestResourceProvisioner_impl(t *testing.T) {
func TestResourceProvider_Validate_good(t *testing.T) {
c := testConfig(t, map[string]interface{}{
"attributes": []interface{}{"key1 { subkey1 = value1 }"},
"environment": "_default",
"node_name": "nodename1",
"run_list": []interface{}{"cookbook::recipe"},

View File

@ -153,7 +153,32 @@ func TestResourceProvider_windowsCreateConfigFiles(t *testing.T) {
},
},
"Attributes": {
"String Attributes": {
Config: testConfig(t, map[string]interface{}{
"attributes": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` +
`"subkey2b":{"subkey3":"value3"}}},"key2":"value2"}`,
"node_name": "nodename1",
"run_list": []interface{}{"cookbook::recipe"},
"secret_key_path": "test-fixtures/encrypted_data_bag_secret",
"server_url": "https://chef.local",
"validation_client_name": "validator",
"validation_key_path": "test-fixtures/validator.pem",
}),
Commands: map[string]bool{
fmt.Sprintf("cmd /c if not exist %q mkdir %q", windowsConfDir, windowsConfDir): true,
},
Uploads: map[string]string{
windowsConfDir + "/client.rb": defaultWindowsClientConf,
windowsConfDir + "/encrypted_data_bag_secret": "SECRET-KEY-FILE",
windowsConfDir + "/validation.pem": "VALIDATOR-PEM-FILE",
windowsConfDir + "/first-boot.json": `{"key1":{"subkey1":{"subkey2a":["val1","val2","val3"],` +
`"subkey2b":{"subkey3":"value3"}}},"key2":"value2","run_list":["cookbook::recipe"]}`,
},
},
"Map Attributes": {
Config: testConfig(t, map[string]interface{}{
"attributes": []map[string]interface{}{
map[string]interface{}{

View File

@ -25,14 +25,19 @@ available on the target machine.
resource "aws_instance" "web" {
...
provisioner "chef" {
attributes {
"key" = "value"
"app" {
"cluster1" {
"nodes" = ["webserver1", "webserver2"]
attributes = <<EOF
{
"key": "value",
"app": {
"cluster1": {
"nodes": [
"webserver1",
"webserver2"
]
}
}
}
EOF
environment = "_default"
run_list = ["cookbook::recipe"]
node_name = "webserver1"
@ -49,8 +54,9 @@ resource "aws_instance" "web" {
The following arguments are supported:
* `attributes (map)` - (Optional) A map with initial node attributes for the new node.
See example.
* `attributes (string)` - (Optional) A raw JSON string with initial node attributes
for the new node. These can also be loaded from a file on disk using the [`file()`
interpolation function](/docs/configuration/interpolation.html#file_path_).
* `client_options (array)` - (Optional) A list of optional Chef Client configuration
options. See the Chef Client [documentation](https://docs.chef.io/config_rb_client.html) for all available options.