Im trying to parse a yaml file and update only one property,
the problem is that the type is RAW
and when I update one field it update the whole object,
what I want is to update only NatIPNames
from test1
to test2
,
but without changing the value of minPortsPerVM
(10000) How can I do it?
This is the yaml
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
This is the code
package main
import (
"encoding/json"
"fmt"
gcpv1alpha1 "github.com/gardener/gardener-extension-provider-gcp/pkg/apis/gcp/v1alpha1"
"github.com/gardener/gardener/pkg/apis/core/v1beta1"
"io/ioutil"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
)
func main() {
shoot, e := parseShoot("test.yaml")
if e != nil {
fmt.Println(e)
}
shoot.Spec.Provider.InfrastructureConfig.Raw = encode(&gcpv1alpha1.InfrastructureConfig{
Networks: gcpv1alpha1.NetworkConfig{
CloudNAT: &gcpv1alpha1.CloudNAT{
//MinPortsPerVM: ,
NatIPNames: []gcpv1alpha1.NatIPName{
{Name: "test2"},
},
},
},
})
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, &shootSpec)
if err != nil {
return nil, err
}
return shootSpec, nil
}
func encode(obj runtime.Object) []byte {
data, _ := json.Marshal(obj)
return data
}
CodePudding user response:
I am not well aware of the gardener properties. But what you can do is create a struct for the InfrastructureConfig
like below
type InfraConfig struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Networks struct {
CloudNAT struct {
MinPortsPerVM int `json:"minPortsPerVM"`
NatIPNames []struct {
Name string `json:"name"`
} `json:"natIPNames"`
} `json:"cloudNAT"`
} `json:"networks"`
}
and create a variable referencing that struct and unmarshal the Raw
object into that like below.
var existingInfraConfig InfraConfig
err := json.Unmarshal(shoot.Spec.Provider.InfrastructureConfig.Raw, &existingInfraConfig)
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.
existingInfraConfig.Networks.CloudNAT.NatIPNames[0].Name = "test2"
byteData, _ := json.Marshal(existingInfraConfig)
shoot.Spec.Provider.InfrastructureConfig = &runtime.RawExtension{
Raw: byteData,
Object: nil,
}
On the whole, it would be like
package main
import (
"encoding/json"
"fmt"
"github.com/gardener/gardener/pkg/apis/core/v1beta1"
"io/ioutil"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/yaml"
)
type InfraConfig struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Networks struct {
CloudNAT struct {
MinPortsPerVM int `json:"minPortsPerVM"`
NatIPNames []struct {
Name string `json:"name"`
} `json:"natIPNames"`
} `json:"cloudNAT"`
} `json:"networks"`
}
func main() {
shoot, e := parseShoot("test.yaml")
if e != nil {
fmt.Println(e)
}
var existingInfraConfig InfraConfig
err := json.Unmarshal(shoot.Spec.Provider.InfrastructureConfig.Raw, &existingInfraConfig)
fmt.Println(err)
existingInfraConfig.Networks.CloudNAT.NatIPNames[0].Name = "test2"
byteData, _ := json.Marshal(existingInfraConfig)
shoot.Spec.Provider.InfrastructureConfig = &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, &shootSpec)
if err != nil {
return nil, err
}
return shootSpec, nil
}