YAML Unmarshal changes keys

119 views
Skip to first unread message

vika...@gmail.com

unread,
Apr 11, 2022, 12:53:57 AM4/11/22
to golang-nuts
I am new to GoLang and looking to join two keys (rules) from two different Yamls.

I have been able to join the keys but I found that Unmarshal changes the keys (example apiVersion to APIVersion, and kind to Kind).

Overall, my goal is to have a valid Kubernetes YAML manifest. This is what I have attempted so far https://goplay.tools/snippet/zWYDjnTeA0Q 

## 
package main

import (
"fmt"

)

type ClusterRole struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Metadata struct {
Name string `yaml:"name"`
} `yaml:"metadata"`
Rules []struct {
APIGroups []string `yaml:"apiGroups"`
Resources []string `yaml:"resources"`
Verbs []string `yaml:"verbs"`
} `yaml:"rules"`
}

func main() {

yaml1 := `
---
kind: ClusterRole
metadata:
name: role1
rules:
- apiGroups:
- ""
resources:
- services
verbs:
- create
- delete
- apiGroups:
resources:
- apiservices
verbs:
- create
- delete
`

yaml2 := `
---
kind: ClusterRole
metadata:
name: role2
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- list
- watch
- apiGroups:
resources:
- nodes
- bindings
verbs:
- get
`

var role1 ClusterRole
yaml.Unmarshal([]byte(yaml1), &role1)
fmt.Printf("\n## ROLE1\n %v", role1)

var role2 ClusterRole
yaml.Unmarshal([]byte(yaml2), &role2)
fmt.Printf("\n\n## ROLE2\n %v", role2)

conjungo.Merge(&role1, role2, nil)

// Struct to Marshal
y, err := yaml.Marshal(role1)
if err != nil {
fmt.Printf("\nerr: %v\n", err)
return
}
fmt.Printf("\n\n## MERGED ROLE\n %v", string(y))
}

Sam Hughes

unread,
Apr 11, 2022, 1:44:58 AM4/11/22
to golang-nuts
I skipped over to that package, and the doc says it converts from yaml to json, and the marshals/unmarshals. I tried changing your snippet to use struct tags with the key name as "json" instead of "yaml", and it immediately behaved as expected: https://goplay.tools/snippet/PSZtr1YErD8

While you're fine to use it like you are, the package you're using is a wrapper around another tool, pkg.go.dev/gopkg.in/yaml.v2, using that tool to convert to/from json, and then using encode/json to marshal/unmarshal. The benefit would be using common marshal/unmarshal handlers and one set of struct tags. Meanwhile, you're not interacting with both yaml and json, so I suggest actually changing the tool you're using to support yaml directly.

1. Simple fix: replace `yaml:"<fieldname>"` with `json:"<fieldname>"`
2. Better fix that might break some code: use gopkg.in/yaml.v2 instead of github.com/ghodss/yaml, to avoid unexpected behavior, such as what you observed.

vika...@gmail.com

unread,
Apr 11, 2022, 3:45:31 AM4/11/22
to golang-nuts
Thanks a ton for the explanation and for helping to fix the issue. I will keep the yaml library in mind.
Reply all
Reply to author
Forward
0 new messages