Commit 8fc46aaa authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

provisioner/chef-solo: deeploy nested JSON works properly

parent 3ac246d6
......@@ -52,6 +52,7 @@ BUG FIXES:
Windows [GH-963]
* provisioner/ansible: set cwd to staging directory [GH-1016]
* provisioners/chef-client: Don't chown directory with Ubuntu. [GH-939]
* provisioners/chef-solo: Deeply nested JSON works properly. [GH-1076]
* provisioners/shell: Env var values can have equal signs. [GH-1045]
* provisioners/shell: chmod the uploaded script file to 0777. [GH-994]
* post-processor/docker-push: Allow repositories with ports. [GH-923]
......
......@@ -203,12 +203,24 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}
}
// Process the user variables within the JSON and set the JSON.
// Do this early so that we can validate and show errors.
p.config.Json, err = p.processJsonUserVars()
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing user variables in JSON: %s", err))
jsonValid := true
for k, v := range p.config.Json {
p.config.Json[k], err = p.deepJsonFix(k, v)
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing JSON: %s", err))
jsonValid = false
}
}
if jsonValid {
// Process the user variables within the JSON and set the JSON.
// Do this early so that we can validate and show errors.
p.config.Json, err = p.processJsonUserVars()
if err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing user variables in JSON: %s", err))
}
}
if errs != nil && len(errs.Errors) > 0 {
......@@ -470,6 +482,57 @@ func (p *Provisioner) installChef(ui packer.Ui, comm packer.Communicator) error
return nil
}
func (p *Provisioner) deepJsonFix(key string, current interface{}) (interface{}, error) {
if current == nil {
return nil, nil
}
switch c := current.(type) {
case []interface{}:
val := make([]interface{}, len(c))
for i, v := range c {
var err error
val[i], err = p.deepJsonFix(fmt.Sprintf("%s[%d]", key, i), v)
if err != nil {
return nil, err
}
}
return val, nil
case bool:
return c, nil
case int:
return c, nil
case uint:
return c, nil
case float32:
return c, nil
case float64:
return c, nil
case map[interface{}]interface{}:
val := make(map[string]interface{})
for k, v := range c {
ks, ok := k.(string)
if !ok {
return nil, fmt.Errorf("%s: key is not string", key)
}
var err error
val[ks], err = p.deepJsonFix(
fmt.Sprintf("%s.%s", key, ks), v)
if err != nil {
return nil, err
}
}
return val, nil
case string:
return c, nil
default:
return nil, fmt.Errorf("Unknown type for key: '%s'", key)
}
}
func (p *Provisioner) processJsonUserVars() (map[string]interface{}, error) {
jsonBytes, err := json.Marshal(p.config.Json)
if err != nil {
......
......@@ -262,3 +262,33 @@ func TestProvisionerPrepare_json(t *testing.T) {
t.Fatalf("bad: %#v", p.config.Json)
}
}
func TestProvisionerPrepare_jsonNested(t *testing.T) {
config := testConfig()
config["json"] = map[string]interface{}{
"foo": map[interface{}]interface{}{
"bar": "baz",
},
"bar": []interface{}{
"foo",
map[interface{}]interface{}{
"bar": "baz",
},
},
"bFalse": false,
"bTrue": true,
"bNil": nil,
"bInt": 1,
"bFloat": 4.5,
}
var p Provisioner
err := p.Prepare(config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
Markdown is supported
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