<p>Im trying to parse a yaml file and update only one property,
the problem is that the type is <code>RAW</code> and when I update one field it update the whole object,</p>
<p>what I want is to <strong>update only</strong> <code>NatIPNames</code> from <code>test1</code> to <code>test2</code>,
but <strong>without changing</strong> the value of <code>minPortsPerVM</code>(10000) How can I do it?</p>
<p>This is the yaml</p>
<pre><code>apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
  name: test
  namespace: ns
spec:
  provider:
    type: aaa
    infrastructureConfig:
      apiVersion: gcp.provider.extensions.gardener.cloud/v1alpha1
      kind: InfrastructureConfig
      networks:
        cloudNAT:
          minPortsPerVM: 10000
          natIPNames:
            - name: test1
</code></pre>
<p>This is the code</p>
<pre><code>package main

import (
    &quot;encoding/json&quot;
    &quot;fmt&quot;
    gcpv1alpha1 &quot;github.com/gardener/gardener-extension-provider-gcp/pkg/apis/gcp/v1alpha1&quot;
    &quot;github.com/gardener/gardener/pkg/apis/core/v1beta1&quot;
    &quot;io/ioutil&quot;
    &quot;k8s.io/apimachinery/pkg/runtime&quot;
    &quot;k8s.io/apimachinery/pkg/util/yaml&quot;
)

func main() {
    shoot, e := parseShoot(&quot;test.yaml&quot;)
    if e != nil {
        fmt.Println(e)
    }

    shoot.Spec.Provider.InfrastructureConfig.Raw = encode(&amp;gcpv1alpha1.InfrastructureConfig{
        Networks: gcpv1alpha1.NetworkConfig{
            CloudNAT: &amp;gcpv1alpha1.CloudNAT{
                //MinPortsPerVM: ,
                NatIPNames: []gcpv1alpha1.NatIPName{
                    {Name: &quot;test2&quot;},
                },
            },
        },
    })
    fmt.Println(shoot.Spec.Provider.InfrastructureConfig)
}

func parseShoot(path string) (*v1beta1.Shoot, error) {
    var shootSpec *v1beta1.Shoot
    bytes, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    err = yaml.Unmarshal(bytes, &amp;shootSpec)
    if err != nil {
        return nil, err
    }
    return shootSpec, nil
}

func encode(obj runtime.Object) []byte {
    data, _ := json.Marshal(obj)
    return data
}
</code></pre>

<p>I am not well aware of the gardener properties. But what you can do is create a struct for the <code>InfrastructureConfig</code> like below</p>
<pre class="lang-golang prettyprint-override"><code>type InfraConfig struct {
    APIVersion string `json:&quot;apiVersion&quot;`
    Kind       string `json:&quot;kind&quot;`
    Networks   struct {
        CloudNAT struct {
            MinPortsPerVM int `json:&quot;minPortsPerVM&quot;`
            NatIPNames    []struct {
                Name string `json:&quot;name&quot;`
            } `json:&quot;natIPNames&quot;`
        } `json:&quot;cloudNAT&quot;`
    } `json:&quot;networks&quot;`
}
</code></pre>
<p>and create a variable referencing that struct and unmarshal the <code>Raw</code> object into that like below.</p>
<pre class="lang-golang prettyprint-override"><code>    var existingInfraConfig InfraConfig
    err := json.Unmarshal(shoot.Spec.Provider.InfrastructureConfig.Raw, &amp;existingInfraConfig)
</code></pre>
<p>then you can edit on the name (you might want to add some logic to validate the slice to update the right index) and marshal it and assign it back to the InfraConfig like below.</p>
<pre class="lang-golang prettyprint-override"><code>    existingInfraConfig.Networks.CloudNAT.NatIPNames[0].Name = &quot;test2&quot;
    byteData, _ := json.Marshal(existingInfraConfig)

    shoot.Spec.Provider.InfrastructureConfig = &amp;runtime.RawExtension{
        Raw:    byteData,
        Object: nil,
    }
</code></pre>
<p>On the whole, it would be like</p>
<pre class="lang-golang prettyprint-override"><code>package main

import (
    &quot;encoding/json&quot;
    &quot;fmt&quot;
    &quot;github.com/gardener/gardener/pkg/apis/core/v1beta1&quot;
    &quot;io/ioutil&quot;
    &quot;k8s.io/apimachinery/pkg/runtime&quot;
    &quot;k8s.io/apimachinery/pkg/util/yaml&quot;
)

type InfraConfig struct {
    APIVersion string `json:&quot;apiVersion&quot;`
    Kind       string `json:&quot;kind&quot;`
    Networks   struct {
        CloudNAT struct {
            MinPortsPerVM int `json:&quot;minPortsPerVM&quot;`
            NatIPNames    []struct {
                Name string `json:&quot;name&quot;`
            } `json:&quot;natIPNames&quot;`
        } `json:&quot;cloudNAT&quot;`
    } `json:&quot;networks&quot;`
}

func main() {
    shoot, e := parseShoot(&quot;test.yaml&quot;)
    if e != nil {
        fmt.Println(e)
    }

    var existingInfraConfig InfraConfig
    err := json.Unmarshal(shoot.Spec.Provider.InfrastructureConfig.Raw, &amp;existingInfraConfig)
    fmt.Println(err)

    existingInfraConfig.Networks.CloudNAT.NatIPNames[0].Name = &quot;test2&quot;
    byteData, _ := json.Marshal(existingInfraConfig)

    shoot.Spec.Provider.InfrastructureConfig = &amp;runtime.RawExtension{
        Raw:    byteData,
        Object: nil,
    }
    fmt.Println(string(shoot.Spec.Provider.InfrastructureConfig.Raw))

}

func parseShoot(path string) (*v1beta1.Shoot, error) {
    var shootSpec *v1beta1.Shoot
    bytes, err := ioutil.ReadFile(path)
    if err != nil {
        return nil, err
    }
    err = yaml.Unmarshal(bytes, &amp;shootSpec)
    if err != nil {
        return nil, err
    }
    return shootSpec, nil
}


</code></pre>
