mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Merge pull request #4187 from monopole/deanchorCall
Do YAML anchor expansion shortly after reading YAML.
This commit is contained in:
@@ -143,7 +143,7 @@ func (rf *Factory) resourcesFromRNodes(
|
||||
return
|
||||
}
|
||||
|
||||
func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
||||
func (rf *Factory) RNodesFromBytes(b []byte) ([]*yaml.RNode, error) {
|
||||
nodes, err := kio.FromBytes(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -152,9 +152,17 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rf.inlineAnyEmbeddedLists(nodes)
|
||||
}
|
||||
|
||||
// inlineAnyEmbeddedLists scans the RNode slice for nodes named FooList.
|
||||
// Such nodes are expected to be lists of resources, each of type Foo.
|
||||
// These lists are replaced in the result by their inlined resources.
|
||||
func (rf *Factory) inlineAnyEmbeddedLists(
|
||||
nodes []*yaml.RNode) (result []*yaml.RNode, err error) {
|
||||
var n0 *yaml.RNode
|
||||
for len(nodes) > 0 {
|
||||
n0 := nodes[0]
|
||||
nodes = nodes[1:]
|
||||
n0, nodes = nodes[0], nodes[1:]
|
||||
kind := n0.GetKind()
|
||||
if !strings.HasSuffix(kind, "List") {
|
||||
result = append(result, n0)
|
||||
@@ -164,7 +172,7 @@ func (rf *Factory) RNodesFromBytes(b []byte) (result []*yaml.RNode, err error) {
|
||||
var m map[string]interface{}
|
||||
m, err = n0.Map()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("trouble expanding list of %s; %w", kind, err)
|
||||
}
|
||||
items, ok := m["items"]
|
||||
if !ok {
|
||||
|
||||
@@ -639,17 +639,14 @@ data:
|
||||
feeling: *color-used
|
||||
`),
|
||||
exp: expected{
|
||||
// TODO(#3675) : the anchor should be replaced.
|
||||
// Anchors are replaced in the List above due to a different code path
|
||||
// (when the list is inlined).
|
||||
out: []string{`
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: wildcard
|
||||
data:
|
||||
color: &color-used blue
|
||||
feeling: *color-used
|
||||
color: blue
|
||||
feeling: blue
|
||||
`},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -102,6 +102,7 @@ func ParseAll(inputs ...string) ([]*yaml.RNode, error) {
|
||||
func FromBytes(bs []byte) ([]*yaml.RNode, error) {
|
||||
return (&ByteReader{
|
||||
OmitReaderAnnotations: true,
|
||||
AnchorsAweigh: true,
|
||||
Reader: bytes.NewBuffer(bs),
|
||||
}).Read()
|
||||
}
|
||||
@@ -152,6 +153,10 @@ type ByteReader struct {
|
||||
// sequence nodes into map node with key yaml.BareSeqNodeWrappingKey
|
||||
// note that this wrapping is different and not related to ResourceList wrapping
|
||||
WrapBareSeqNode bool
|
||||
|
||||
// AnchorsAweigh set to true attempts to replace all YAML anchor aliases
|
||||
// with their definitions (anchor values) immediately after the read.
|
||||
AnchorsAweigh bool
|
||||
}
|
||||
|
||||
var _ Reader = &ByteReader{}
|
||||
@@ -269,6 +274,13 @@ func (r *ByteReader) Read() ([]*yaml.RNode, error) {
|
||||
// increment the index annotation value
|
||||
index++
|
||||
}
|
||||
if r.AnchorsAweigh {
|
||||
for _, n := range output {
|
||||
if err = n.DeAnchor(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -758,7 +758,7 @@ items:
|
||||
metadata:
|
||||
name: deployment-b
|
||||
spec:
|
||||
<<: *hostAliases
|
||||
*hostAliases
|
||||
`),
|
||||
exp: expected{
|
||||
sOut: []string{`
|
||||
@@ -769,7 +769,7 @@ items:
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-a
|
||||
spec: &hostAliases
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
hostAliases:
|
||||
@@ -781,7 +781,12 @@ items:
|
||||
metadata:
|
||||
name: deployment-b
|
||||
spec:
|
||||
!!merge <<: *hostAliases
|
||||
template:
|
||||
spec:
|
||||
hostAliases:
|
||||
- hostnames:
|
||||
- a.example.com
|
||||
ip: 8.8.8.8
|
||||
`},
|
||||
},
|
||||
},
|
||||
@@ -808,27 +813,21 @@ items:
|
||||
}
|
||||
}
|
||||
|
||||
// This test shows the lower level (go-yaml) representation of a small doc
|
||||
// with an anchor. The anchor structure is there, in the sense that an
|
||||
// alias pointer is readily available when a node's kind is an AliasNode.
|
||||
// I.e. the anchor mapping name -> object was noted during unmarshalling.
|
||||
// However, at the time of writing github.com/go-yaml/yaml/encoder.go
|
||||
// doesn't appear to have an option to perform anchor replacements when
|
||||
// encoding. It emits anchor definitions and references (aliases) intact.
|
||||
func TestByteReader_AnchorBehavior(t *testing.T) {
|
||||
// Show the low level (go-yaml) representation of a small doc with a
|
||||
// YAML anchor and alias after reading it with anchor expansion on or off.
|
||||
func TestByteReader_AnchorsAweigh(t *testing.T) {
|
||||
const input = `
|
||||
data:
|
||||
color: &color-used blue
|
||||
feeling: *color-used
|
||||
`
|
||||
expected := strings.TrimSpace(`
|
||||
data:
|
||||
color: &color-used blue
|
||||
feeling: *color-used
|
||||
`)
|
||||
var rNode *yaml.RNode
|
||||
{
|
||||
rNodes, err := FromBytes([]byte(input))
|
||||
rNodes, err := (&ByteReader{
|
||||
OmitReaderAnnotations: true,
|
||||
AnchorsAweigh: false,
|
||||
Reader: bytes.NewBuffer([]byte(input)),
|
||||
}).Read()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(rNodes))
|
||||
rNode = rNodes[0]
|
||||
@@ -857,7 +856,7 @@ data:
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[0].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||
assert.Equal(t, "color", yNodes[0].Value)
|
||||
assert.Equal(t, "", yNodes[0].Anchor)
|
||||
assert.Empty(t, yNodes[0].Anchor)
|
||||
assert.Nil(t, yNodes[0].Alias)
|
||||
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[1].Kind)
|
||||
@@ -869,19 +868,82 @@ data:
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[2].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[2].Tag)
|
||||
assert.Equal(t, "feeling", yNodes[2].Value)
|
||||
assert.Equal(t, "", yNodes[2].Anchor)
|
||||
assert.Empty(t, yNodes[2].Anchor)
|
||||
assert.Nil(t, yNodes[2].Alias)
|
||||
|
||||
assert.Equal(t, yaml.AliasNode, yNodes[3].Kind)
|
||||
assert.Equal(t, "", yNodes[3].Tag)
|
||||
assert.Empty(t, yNodes[3].Tag)
|
||||
assert.Equal(t, "color-used", yNodes[3].Value)
|
||||
assert.Equal(t, "", yNodes[3].Anchor)
|
||||
assert.Empty(t, yNodes[3].Anchor)
|
||||
assert.NotNil(t, yNodes[3].Alias)
|
||||
}
|
||||
|
||||
yaml, err := rNode.String()
|
||||
str, err := rNode.String()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, strings.TrimSpace(yaml))
|
||||
// The string version matches the input (it still has anchors and aliases).
|
||||
assert.Equal(t, strings.TrimSpace(input), strings.TrimSpace(str))
|
||||
|
||||
// Now do same thing again, but this time set AnchorsAweigh = true.
|
||||
{
|
||||
rNodes, err := (&ByteReader{
|
||||
OmitReaderAnnotations: true,
|
||||
AnchorsAweigh: true,
|
||||
Reader: bytes.NewBuffer([]byte(input)),
|
||||
}).Read()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(rNodes))
|
||||
rNode = rNodes[0]
|
||||
}
|
||||
// Again make assertions on the internals.
|
||||
{
|
||||
yNode := rNode.YNode()
|
||||
|
||||
assert.Equal(t, yaml.NodeTagMap, yNode.Tag)
|
||||
|
||||
yNodes := yNode.Content
|
||||
assert.Equal(t, 2, len(yNodes))
|
||||
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||
assert.Equal(t, "data", yNodes[0].Value)
|
||||
|
||||
assert.Equal(t, yaml.NodeTagMap, yNodes[1].Tag)
|
||||
|
||||
yNodes = yNodes[1].Content
|
||||
assert.Equal(t, 4, len(yNodes))
|
||||
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[0].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[0].Tag)
|
||||
assert.Equal(t, "color", yNodes[0].Value)
|
||||
assert.Empty(t, yNodes[0].Anchor)
|
||||
assert.Nil(t, yNodes[0].Alias)
|
||||
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[1].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[1].Tag)
|
||||
assert.Equal(t, "blue", yNodes[1].Value)
|
||||
assert.Empty(t, yNodes[1].Anchor)
|
||||
assert.Nil(t, yNodes[1].Alias)
|
||||
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[2].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[2].Tag)
|
||||
assert.Equal(t, "feeling", yNodes[2].Value)
|
||||
assert.Empty(t, yNodes[2].Anchor)
|
||||
assert.Nil(t, yNodes[2].Alias)
|
||||
|
||||
assert.Equal(t, yaml.ScalarNode, yNodes[3].Kind)
|
||||
assert.Equal(t, yaml.NodeTagString, yNodes[3].Tag)
|
||||
assert.Equal(t, "blue", yNodes[3].Value)
|
||||
assert.Empty(t, yNodes[3].Anchor)
|
||||
assert.Nil(t, yNodes[3].Alias)
|
||||
}
|
||||
|
||||
str, err = rNode.String()
|
||||
assert.NoError(t, err)
|
||||
// This time, the alias has been replaced with the anchor definition.
|
||||
assert.Equal(t, strings.TrimSpace(`
|
||||
data:
|
||||
color: blue
|
||||
feeling: blue
|
||||
`), strings.TrimSpace(str))
|
||||
}
|
||||
|
||||
// TestByteReader_AddSeqIndentAnnotation tests if the internal.config.kubernetes.io/seqindent
|
||||
|
||||
Reference in New Issue
Block a user