You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中更新YAML文件指定字段后写入新文件时Raw数据异常及空字段过多的问题求助

How to Update Specific YAML Fields Without Empty Outputs & Fix Raw Data Display Issues in Go

Let's break down your two issues and fix them step by step:

Issue 1: Raw Data Shows as Numbers

The Raw field in runtime.RawExtension is a byte slice. When you use gyaml.Marshal directly on the Shoot struct, it serializes this byte slice as a list of integers (each byte's ASCII value) instead of parsing it as structured YAML content. This happens because you were converting the InfraConfig to JSON first— the YAML serializer doesn't recognize those bytes as valid structured data.

Issue 2: Empty Fields Flooding the Output

The v1beta1.Shoot struct relies mostly on JSON tags, not YAML tags. Generic YAML marshalers like gyaml.Marshal don't respect the omitempty flags from JSON tags, so they output every zero-value field (empty strings, nil pointers, empty slices, etc.). You need to use Kubernetes' dedicated YAML utilities that handle their struct conventions correctly.


Fixed Solution

Here's the revised code that addresses both problems:

package main

import (
	"fmt"
	"github.com/gardener/gardener/pkg/apis/core/v1beta1"
	gyaml "github.com/go-yaml/yaml/v3"
	"io/ioutil"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/yaml"
)

type InfraConfig struct {
	APIVersion string `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"`
	Kind       string `yaml:"kind,omitempty" json:"kind,omitempty"`
	Networks   struct {
		CloudNAT struct {
			MinPortsPerVM int `yaml:"minPortsPerVM,omitempty" json:"minPortsPerVM,omitempty"`
			NatIPNames    []struct {
				Name string `yaml:"name,omitempty" json:"name,omitempty"`
			} `yaml:"natIPNames,omitempty" json:"natIPNames,omitempty"`
		} `yaml:"cloudNAT,omitempty" json:"cloudNAT,omitempty"`
	} `yaml:"networks,omitempty" json:"networks,omitempty"`
}

func main() {
	shoot, err := parseShoot("test.yaml")
	if err != nil {
		fmt.Printf("Failed to parse shoot: %v\n", err)
		return
	}

	// Parse InfrastructureConfig directly from YAML (no JSON conversion)
	var existingInfraConfig InfraConfig
	if err := yaml.Unmarshal(shoot.Spec.Provider.InfrastructureConfig.Raw, &existingInfraConfig); err != nil {
		fmt.Printf("Failed to unmarshal infra config: %v\n", err)
		return
	}

	// Update the target field
	existingInfraConfig.Networks.CloudNAT.NatIPNames[0].Name = "test2"

	// Marshal updated config back to YAML bytes
	updatedInfraBytes, err := gyaml.Marshal(existingInfraConfig)
	if err != nil {
		fmt.Printf("Failed to marshal updated infra config: %v\n", err)
		return
	}

	// Update RawExtension with valid YAML bytes
	shoot.Spec.Provider.InfrastructureConfig = &runtime.RawExtension{
		Raw: updatedInfraBytes,
	}

	// Use Kubernetes' YAML marshaler to avoid empty fields
	outputBytes, err := yaml.Marshal(shoot)
	if err != nil {
		fmt.Printf("Failed to marshal shoot: %v\n", err)
		return
	}

	// Write the final cleaned-up YAML file
	if err := ioutil.WriteFile("test2.yaml", outputBytes, 0644); err != nil {
		fmt.Printf("Failed to write file: %v\n", err)
		return
	}

	fmt.Println("Successfully updated YAML file!")
}

func parseShoot(path string) (*v1beta1.Shoot, error) {
	var shootSpec *v1beta1.Shoot
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	// Use Kubernetes' YAML unmarshaler for correct struct tag handling
	err = yaml.Unmarshal(bytes, &shootSpec)
	if err != nil {
		return nil, err
	}
	return shootSpec, nil
}

Key Changes Explained:

  1. Added YAML tags to InfraConfig: The struct now supports both JSON and YAML serialization, matching the input format instead of relying on JSON conversion.
  2. Worked directly with YAML for InfraConfig: We parse the raw YAML bytes directly and marshal the updated config back to YAML. This ensures the Raw field contains valid YAML that the final marshaler will interpret correctly (not as a list of numbers).
  3. Used Kubernetes' yaml.Marshal: This utility understands Kubernetes struct conventions— it respects omitempty flags even for fields with only JSON tags, uses correct YAML field names (like apiVersion instead of apiversion), and omits all zero-value fields from the output.

Expected Output

The generated test2.yaml will mirror your input exactly, with only the target field updated, no empty fields:

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: test2

内容的提问来源于stack exchange,提问作者PJEM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 17:17:40