Errors on unmarshal yaml in go

3/17/2020

i'm new in go, i can't find a way to unmarshal a yaml using "gopkg.in/yaml.v2" I suppose the error is in the way i define the struct.

I need to parse a kubernetes job yaml and edit in go to generate an update yaml. The structure is almost static but have two lists in wich the keys could have different things inside.

I reduced the yaml to one listes (volumes) to simplify the example.

apiVersion: batch/v1
kind: Job
metadata:
  name: jobname
  namespace: namespace
spec:
  ttlSecondsAfterFinished: 86400
  template:
    spec:
      containers:
      - name: container-name
        image: containerimage:tag
        command:
        - php
        - cli/migrations.php
        - up
      restartPolicy: Never
      volumes:
      - name: filestore
        persistentVolumeClaim:
          claimName: data-pvc
          readOnly: false
      - name: stackdriver
        secret:
          secretName: stackdriver-prod
  backoffLimit: 1

those are my structs definitions:

type PersistentVolumeClaims struct {
                ClaimName string `yaml:"claimName,omitempty"`
                ReadOnly bool `yaml:"readOnly,omitempty"`

            }
type Secrets  struct {
                SecretName string `yaml:"secretName,omitempty"`

    }

type Names struct {
    Name     string `yaml:"name"`
    PersistentVolumeClaim PersistentVolumeClaims `yaml:"persistentVolumeClaim,omitempty"`
    Secret Secrets `yaml:"secret,omitempty"`
}


type Jobs struct {
    ApiVersion string `yaml:"apiVersion"`
    Kind string `yaml:"kind"`
    Metadata struct {
      Name string `yaml:"name"`
      Namespace string `yaml:"namespace"`
    }
    Spec struct {
      TtlSecondsAfterFinished int `yaml:"ttlSecondsAfterFinished"`
      Template struct {
        Spec struct {
          Containers []struct {
            Name string
            Image string `yaml:"image"`
            Command []string `yaml:"command"`
            VolumeMounts []struct {
                    Name string 
                    SubPath string `yaml:"subPath"`
                    MountPath string `yaml:"mountPath"`
                    ReadOnly bool `yaml:"readOnly"`
          }
          RestartPolicy string `yaml:"restartPolicy"`
        }
        Volumes map[string][]Names
      }
      BackoffLimit int `yaml:"backoffLimit"`
    }
  }
}

i tried different structures but i don't get the solution. Any help will be appreciated.

--- SOLVED

I have redone the tool using the official go-client https://github.com/kubernetes/client-go as suggested by Jonas. Now everything work!

-- Hughen
go
kubernetes

3 Answers

3/17/2020

I need to parse a kubernetes job yaml and edit in go to generate an update yaml. The structure is almost static but have two lists in wich the keys could have different things inside.

It sound like your application is running in a cluster, want to retrieve a Job, modify it and then update it.

I would recommend the official Kubernetes client-go for this. It has libraries for Kubernetes resources like Job. See the example using a Deployment

-- Jonas
Source: StackOverflow

3/17/2020

You can use the official structs from the Kubernetes APIs. If you still want to declare the structs: Your yaml tags are incomplete. You do not have tags for nested structs:

type Jobs struct {
    Metadata struct {
      Name string `yaml:"name"`
      Namespace string `yaml:"namespace"`
    } `yaml:"metadata"` // Here is one
    Spec struct {
      TtlSecondsAfterFinished int `yaml:"ttlSecondsAfterFinished"`
      Template struct {
        Spec struct {
          Containers []struct {
            VolumeMounts []struct {
                    Name string 
                    SubPath string `yaml:"subPath"`
                    MountPath string `yaml:"mountPath"`
                    ReadOnly bool `yaml:"readOnly"`
          } `yaml:"volumeMounts"` // Here is another
        } `yaml:"containers"` // Here is another
        Volumes map[string][]Names `yaml:"volumes"` // This is missin as well
      } `yaml:"spec"` //
    } `yaml:"template"` //
  } `yaml:"spec"` //
}
-- Burak Serdar
Source: StackOverflow

3/17/2020

Suppose that your data is in the file example.yaml; you can unmarshall into a struct using gopkg.in/yaml.v2 like

package main

import (
    "fmt"
    "log"
    "io/ioutil"
    "gopkg.in/yaml.v2"
)

type item struct {
    ItemA string `yaml:"item_a"`
    ItemB string `yaml:"item_b"`
}

func read(filename string) (item, error) {
    var output item
    content, err := ioutil.ReadFile(filename)
    if err != nil {
        return item{}, err
    }
    err = yaml.Unmarshal(content, output)
    if err != nil {
        return item{}, err
    }
    return output, nil
}

func main() {
    output, err := read("example.yaml")
    if err != nil {
            log.Fatal(err)
    }
    fmt.Println("output: ", output)
}
-- Maddo
Source: StackOverflow