mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Parse metadata directly instead of struct serialization hack
This commit is contained in:
@@ -6,7 +6,6 @@ package yaml
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
@@ -70,6 +69,14 @@ func IsFieldEmpty(node *MapNode) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetValue returns underlying yaml.Node Value field
|
||||
func GetValue(node *RNode) string {
|
||||
if IsEmpty(node) {
|
||||
return ""
|
||||
}
|
||||
return node.YNode().Value
|
||||
}
|
||||
|
||||
func IsFieldNull(node *MapNode) bool {
|
||||
return node != nil && node.Value != nil && node.Value.YNode() != nil &&
|
||||
node.Value.YNode().Tag == NullNodeTag
|
||||
@@ -280,23 +287,79 @@ func (r *ResourceIdentifier) GetKind() string {
|
||||
|
||||
var ErrMissingMetadata = fmt.Errorf("missing Resource metadata")
|
||||
|
||||
// GetMeta returns the ResourceMeta for a RNode
|
||||
// Field names
|
||||
const (
|
||||
AnnotationsField = "annotations"
|
||||
APIVersionField = "apiVersion"
|
||||
KindField = "kind"
|
||||
MetadataField = "metadata"
|
||||
NameField = "name"
|
||||
NamespaceField = "namespace"
|
||||
LabelsField = "labels"
|
||||
)
|
||||
|
||||
// GetMeta returns the ResourceMeta for an RNode
|
||||
func (rn *RNode) GetMeta() (ResourceMeta, error) {
|
||||
if IsEmpty(rn) {
|
||||
return ResourceMeta{}, nil
|
||||
}
|
||||
missingMeta := true
|
||||
n := rn
|
||||
if n.YNode().Kind == DocumentNode {
|
||||
// get the content is this is the document node
|
||||
n = NewRNode(n.Content()[0])
|
||||
}
|
||||
|
||||
// don't decode into the struct directly or it will fail on UTF-8 issues
|
||||
// which appear in comments
|
||||
m := ResourceMeta{}
|
||||
b := &bytes.Buffer{}
|
||||
e := NewEncoder(b)
|
||||
if err := e.Encode(rn.YNode()); err != nil {
|
||||
return m, errors.Wrap(err)
|
||||
|
||||
// TODO: consider optimizing this parsing
|
||||
if f := n.Field(APIVersionField); !IsFieldEmpty(f) {
|
||||
m.APIVersion = GetValue(f.Value)
|
||||
missingMeta = false
|
||||
}
|
||||
if err := e.Close(); err != nil {
|
||||
return m, errors.Wrap(err)
|
||||
if f := n.Field(KindField); !IsFieldEmpty(f) {
|
||||
m.Kind = GetValue(f.Value)
|
||||
missingMeta = false
|
||||
}
|
||||
d := yaml.NewDecoder(b)
|
||||
d.KnownFields(false) // only want to parse the metadata
|
||||
if err := d.Decode(&m); err != nil {
|
||||
return m, errors.Wrap(err)
|
||||
|
||||
mf := n.Field(MetadataField)
|
||||
if IsFieldEmpty(mf) {
|
||||
if missingMeta {
|
||||
return m, ErrMissingMetadata
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
if reflect.DeepEqual(m, ResourceMeta{}) {
|
||||
meta := mf.Value
|
||||
|
||||
if f := meta.Field(NameField); !IsFieldEmpty(f) {
|
||||
m.Name = f.Value.YNode().Value
|
||||
missingMeta = false
|
||||
}
|
||||
if f := meta.Field(NamespaceField); !IsFieldEmpty(f) {
|
||||
m.Namespace = GetValue(f.Value)
|
||||
missingMeta = false
|
||||
}
|
||||
|
||||
if f := meta.Field(LabelsField); !IsFieldEmpty(f) {
|
||||
m.Labels = map[string]string{}
|
||||
_ = f.Value.VisitFields(func(node *MapNode) error {
|
||||
m.Labels[GetValue(node.Key)] = GetValue(node.Value)
|
||||
return nil
|
||||
})
|
||||
missingMeta = false
|
||||
}
|
||||
if f := meta.Field(AnnotationsField); !IsFieldEmpty(f) {
|
||||
m.Annotations = map[string]string{}
|
||||
_ = f.Value.VisitFields(func(node *MapNode) error {
|
||||
m.Annotations[GetValue(node.Key)] = GetValue(node.Value)
|
||||
return nil
|
||||
})
|
||||
missingMeta = false
|
||||
}
|
||||
|
||||
if missingMeta {
|
||||
return m, ErrMissingMetadata
|
||||
}
|
||||
return m, nil
|
||||
|
||||
49
kyaml/yaml/types_test.go
Normal file
49
kyaml/yaml/types_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Test that non-UTF8 characters in comments don't cause failures
|
||||
func TestRNode_GetMeta_UTF16(t *testing.T) {
|
||||
sr, err := Parse(`apiVersion: rbac.istio.io/v1alpha1
|
||||
kind: ServiceRole
|
||||
metadata:
|
||||
name: wildcard
|
||||
namespace: default
|
||||
# If set to [“*”], it refers to all services in the namespace
|
||||
annotations:
|
||||
foo: bar
|
||||
spec:
|
||||
rules:
|
||||
# There is one service in default namespace, should not result in a validation error
|
||||
# If set to [“*”], it refers to all services in the namespace
|
||||
- services: ["*"]
|
||||
methods: ["GET", "HEAD"]
|
||||
`)
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
actual, err := sr.GetMeta()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
expected := ResourceMeta{
|
||||
APIVersion: "rbac.istio.io/v1alpha1",
|
||||
Kind: "ServiceRole",
|
||||
ObjectMeta: ObjectMeta{
|
||||
Name: "wildcard",
|
||||
Namespace: "default",
|
||||
Annotations: map[string]string{"foo": "bar"},
|
||||
},
|
||||
}
|
||||
if !assert.Equal(t, expected, actual) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user