Skip to content

Commit

Permalink
kd: workaround for YAML -> JSON template reencoding
Browse files Browse the repository at this point in the history
Works around the following yaml issue:

    go-yaml/yaml#139
  • Loading branch information
rjeczalik committed Jan 6, 2017
1 parent 5424131 commit 045e42c
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
2 changes: 1 addition & 1 deletion go/src/koding/kites/kloud/stack/kloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func ReadProviders(template []byte) ([]string, error) {
return nil, err
}

providers := make([]string, len(v.Provider))
providers := make([]string, 0, len(v.Provider))

for p := range v.Provider {
providers = append(providers, p)
Expand Down
3 changes: 2 additions & 1 deletion go/src/koding/klientctl/endpoint/stack/export_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package stack

func FixHCL(v interface{}) { fixHCL(v) }
func FixHCL(v interface{}) { fixHCL(v) }
func FixYAML(v interface{}) interface{} { return fixYAML(v) }
42 changes: 35 additions & 7 deletions go/src/koding/klientctl/endpoint/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ import (
yaml "gopkg.in/yaml.v2"
)

// CreateOptions
type CreateOptions struct {
Team string
Title string
Credentials []string
Template []byte
}

// Valid
func (opts *CreateOptions) Valid() error {
if opts == nil {
return errors.New("stack: arguments are missing")
Expand All @@ -36,16 +34,13 @@ func (opts *CreateOptions) Valid() error {
return nil
}

// DefaultClient
var DefaultClient Client
var DefaultClient = &Client{}

// Client
type Client struct {
Kloud *kloud.Client
Credential *credential.Client
}

// Create
func (c *Client) Create(opts *CreateOptions) (*stack.ImportResponse, error) {
if err := opts.Valid(); err != nil {
return nil, err
Expand Down Expand Up @@ -135,7 +130,7 @@ func (c *Client) jsonReencode(data []byte) ([]byte, error) {
var ymlv interface{}

if err := yaml.Unmarshal(data, &ymlv); err == nil {
return json.Marshal(ymlv)
return json.Marshal(fixYAML(ymlv))
}

var hclv interface{}
Expand All @@ -154,6 +149,39 @@ func Create(opts *CreateOptions) (*stack.ImportResponse, error) {
return DefaultClient.Create(opts)
}

// fixYAML is a best-effort of fixing representation of
// YAML-encoded value, so it can be marshaled to a valid JSON.
//
// YAML creates types like map[interface{}]interface{}, which are
// not a valid JSON types.
//
// Related issue:
//
// https://github.com/go-yaml/yaml/issues/139
//
func fixYAML(v interface{}) interface{} {
switch v := v.(type) {
case map[interface{}]interface{}:
fixedV := make(map[string]interface{}, len(v))

for k, v := range v {
fixedV[fmt.Sprintf("%v", k)] = fixYAML(v)
}

return fixedV
case []interface{}:
fixedV := make([]interface{}, len(v))

for i := range v {
fixedV[i] = fixYAML(v[i])
}

return fixedV
default:
return v
}
}

// fixHCL is a best-effort method to "fix" value representation of
// HCL-encoded value, so it can be marshaled to a valid JSON.
//
Expand Down
58 changes: 58 additions & 0 deletions go/src/koding/klientctl/endpoint/stack/stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,64 @@ func TestFixHCL(t *testing.T) {
}
}

func TestFixYAML(t *testing.T) {
cases := map[string]struct {
yaml interface{}
want interface{}
}{
"fix map": {
map[interface{}]interface{}{
"abc": 1,
},
map[string]interface{}{
"abc": 1,
},
},
"fix slice of maps": {
[]interface{}{
"abc",
map[interface{}]interface{}{
"abc": 1,
},
1,
},
[]interface{}{
"abc",
map[string]interface{}{
"abc": 1,
},
1,
},
},
"fix nested maps": {
map[interface{}]interface{}{
"abc": map[interface{}]interface{}{
"abc": map[interface{}]interface{}{
"abc": 1,
},
},
},
map[string]interface{}{
"abc": map[string]interface{}{
"abc": map[string]interface{}{
"abc": 1,
},
},
},
},
}

for name, cas := range cases {
t.Run(name, func(t *testing.T) {
got := stack.FixYAML(cas.yaml)

if !reflect.DeepEqual(got, cas.want) {
t.Fatalf("got %#v, want %#v", got, cas.want)
}
})
}
}

func mustJSON(v interface{}) []byte {
p, err := json.MarshalIndent(v, "", "\t")
if err != nil {
Expand Down

0 comments on commit 045e42c

Please sign in to comment.