provisioner/chef-solo: deeploy nested JSON works properly

This commit is contained in:
Mitchell Hashimoto 2014-04-28 21:56:32 -07:00
parent 3ac246d611
commit 8fc46aaa82
3 changed files with 100 additions and 6 deletions

View File

@ -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]

View File

@ -203,6 +203,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
}
}
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()
@ -210,6 +221,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("Error processing user variables in JSON: %s", err))
}
}
if errs != nil && len(errs.Errors) > 0 {
return errs
@ -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 {

View File

@ -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)
}
}