Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: anchors support for extra annotations and labels post-renderer
Current post-renderer will preserve yaml-comments, sort order of all field and support yaml-anchors (including the case when anchor used in annotations labels itself).

Signed-off-by: Timofey Kirillov <timofey.kirillov@flant.com>
  • Loading branch information
distorhead committed May 4, 2022
1 parent a31e54b commit b8211a9
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 47 deletions.
8 changes: 2 additions & 6 deletions integration/suites/helm/render/secret_test.go
Expand Up @@ -21,12 +21,8 @@ var _ = Describe("helm render with secrets", func() {

for _, substr := range []string{
"int: MTc=",
`json:
web:
id: "220821453116"
redirect_uris:
- https://test.ru`,
"quoted: '''password'''",
`json: {"web": {"id": "220821453116", "redirect_uris": ["https://test.ru"]}}`,
`quoted: "'password'"`,
"secret_file: TUlJSktBSUJBQUtDQWdFQXFQMEFDcHZKNmUrSFJjdndDMUlFM201TzJNQXo4ci90QU1RZldwK2w3L0g1TE1zTgpGTzJKSVJPUis1VE95R2VWc1dzekRZMTEzcFhhRTJoaDZjam16Qkhvc1h6azZSenpVd1B4TlZzUy9MN3ZkRy9iClZxTnB1UGhyRllMdVNWcFgzZC9Cc0wzUmZXVnpxS1JlYVpnb05SQnpUN044UWNFVHdCMEEzbExvYy9TcGxNY0UKOTJ5QUJJMUNwcEt4b1RWVnlGZ09vMVNhSlFBRlRwOUtLbDY4K2tkTTFhcUlhV1Y0eWxKbXB2Umo3bVR2eGlmYwp3SVdLc1FLQ0FRQmo4c05RTHl3bnJIY2pJSnpwemRKZVArTUlCN1BaUFFIVDQzWDBpZzRFaC9kS3BIVHlWb21ECituWjZLWktqRUcySmY1NnNKUysxa202cWNhYjU1MnIxTGtNcXNoRVZWb2s2K2ovanNidHROOHVCVGliMkRyUksKbFlWMmI5TTh2RnF6LzNxQmM2VkxISWNkZ29pRGlOdWl3QlhlZFdsRHBnNUN2V3BIRWx1anRKVjNMNmNpQjFRNwpqeG9lMGNtUXY5TGJYWUNCRjBBNVZVNWZqeHdJN0tQVmRCSm1rWE9RS3EvZ1ZuVGFQOG9DSlN0dk95Lzd6bm05CjgwemhRQUtJMkgzVjZMOG9ONG5vTm16TW50bkNUWUl5UWFpMlRlUVgyckswbGlpeXNjVWQxaGJGaWE5bUZMNWEKd2g2Y3EyVElNcDNpK1h2MWw4VU5pTXZOM0JGWEhKR3hBb0lCQUMrajZZY2wxRVZuMjJCOFk3bHd1Mmp1SFFuYQpiZEpTR2QrMk5mUnp3TGcxaGxDc3pmL3JPNzZkUlYyVkFnR0NTM1NUWE9iQ2s2UHR5RTJHLy9TeG5pTG1nNCtyCklkLzF6SVNFZERUdkg1TG1OejNqNmJKNXFBTUttdkYyVjRoeHhtMmYwQ2xZSjJBWFFZdGNrL2N1bzQrWUxjVkQKOTRqNXowZkd4Y0xhSVkxVVpDUXZpbHZzVmdFaEV0cEQ0enpaTGFuOXNqRVVLLzAwV2E3NG8vVzBKWmpUS3Q3RAoxaDAwbUJxcTJDN1J0OElnNitreE9QSVdCUGxTNk1CQkJuS2Q1L1VqeS9hanJERnlHVjZjNjRtRFJHR1FFKy8rCk5JcDcwZjcxaWFBQVFQSVBkaFJUdk9zaEhna2RNQTFqRlBOWUNUVlVmWk56NllCSVpzajhBTktqNnNFPQo=",
} {
Ω(output).Should(ContainSubstring(substr))
Expand Down
155 changes: 114 additions & 41 deletions pkg/deploy/helm/extra_annotations_and_labels_post_renderer.go
Expand Up @@ -4,11 +4,10 @@ import (
"bytes"
"fmt"
"os"
"regexp"
"sort"
"strings"

orig_yaml "gopkg.in/yaml.v2"
yaml_v3 "gopkg.in/yaml.v3"
"helm.sh/helm/v3/pkg/releaseutil"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
Expand All @@ -35,37 +34,73 @@ type ExtraAnnotationsAndLabelsPostRenderer struct {
ExtraLabels map[string]string
}

func findMapByKey(mapSlice orig_yaml.MapSlice, key string) orig_yaml.MapSlice {
for _, item := range mapSlice {
if itemKey, ok := item.Key.(string); ok {
if itemKey == key {
if itemValue, ok := item.Value.(orig_yaml.MapSlice); ok {
return itemValue
}
}
func replaceNodeByKey(node *yaml_v3.Node, key string, value *yaml_v3.Node) {
content := node.Content
end := len(content)

for pos := 0; pos < end; pos += 2 {
keyNode := content[pos]

if keyNode.Tag != "!!str" {
continue
}

var k string
if err := keyNode.Decode(&k); err != nil {
continue
}

if k == key {
content[pos+1] = value
return
}
}
}

func findNodeByKey(node *yaml_v3.Node, key string) *yaml_v3.Node {
content := node.Content
end := len(content)

for pos := 0; pos < end; pos += 2 {
keyNode := content[pos]
valueNode := content[pos+1]

if keyNode.Tag != "!!str" {
continue
}

var k string
if err := keyNode.Decode(&k); err != nil {
continue
}

if k == key {
return valueNode
}
}

return nil
}

func setMapValueByKey(mapSlice orig_yaml.MapSlice, key string, value interface{}) (res orig_yaml.MapSlice) {
var found bool
for _, item := range mapSlice {
if itemKey, ok := item.Key.(string); ok {
if itemKey == key {
res = append(res, orig_yaml.MapItem{Key: key, Value: value})
found = true
continue
func getMapNode(docNode *yaml_v3.Node) *yaml_v3.Node {
if docNode.Kind == yaml_v3.DocumentNode {
if len(docNode.Content) > 0 {
n := docNode.Content[0]
if n.Tag == "!!map" {
return n
}
}
res = append(res, item)
}
return nil
}

if !found {
res = append(res, orig_yaml.MapItem{Key: key, Value: value})
func createNode(v interface{}) *yaml_v3.Node {
newNode := &yaml_v3.Node{}
if err := newNode.Encode(v); err != nil {
logboek.Warn().LogF("Unable to encode map %#v into yaml node: %s\n", v, err)
return nil
}
return
return newNode
}

func (pr *ExtraAnnotationsAndLabelsPostRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
Expand Down Expand Up @@ -95,10 +130,8 @@ func (pr *ExtraAnnotationsAndLabelsPostRenderer) Run(renderedManifests *bytes.Bu

splitModifiedManifests := make([]string, 0)

manifestNameRegex := regexp.MustCompile("# Source: .*")
for _, manifestKey := range manifestsKeys {
manifestContent := splitManifestsByKeys[manifestKey]
manifestSource := manifestNameRegex.FindString(manifestContent)

if os.Getenv("WERF_HELM_V3_EXTRA_ANNOTATIONS_AND_LABELS_DEBUG") == "1" {
fmt.Printf("ExtraAnnotationsAndLabelsPostRenderer -- original manifest BEGIN\n")
Expand All @@ -117,8 +150,8 @@ func (pr *ExtraAnnotationsAndLabelsPostRenderer) Run(renderedManifests *bytes.Bu
continue
}

var objMapSlice orig_yaml.MapSlice
if err := orig_yaml.Unmarshal([]byte(manifestContent), &objMapSlice); err != nil {
var objNode yaml_v3.Node
if err := yaml_v3.Unmarshal([]byte(manifestContent), &objNode); err != nil {
logboek.Warn().LogF("Unable to decode yaml manifest as map slice: %s: will not add extra annotations and labels to this object:\n%s\n---\n", err, manifestContent)
splitModifiedManifests = append(splitModifiedManifests, manifestContent)
continue
Expand All @@ -131,37 +164,77 @@ func (pr *ExtraAnnotationsAndLabelsPostRenderer) Run(renderedManifests *bytes.Bu
if obj.IsList() && len(extraAnnotations) > 0 {
logboek.Warn().LogF("werf annotations won't be applied to *List resource Kinds, including %s. We advise to replace *List resources with multiple separate resources of the same Kind\n", obj.GetKind())
} else if len(extraAnnotations) > 0 {
if metadata := findMapByKey(objMapSlice, "metadata"); metadata != nil {
annotations := findMapByKey(metadata, "annotations")
for k, v := range extraAnnotations {
annotations = append(annotations, orig_yaml.MapItem{Key: k, Value: v})
if objMapNode := getMapNode(&objNode); objMapNode != nil {
if metadataNode := findNodeByKey(objMapNode, "metadata"); metadataNode != nil {
if annotationsNode := findNodeByKey(metadataNode, "annotations"); annotationsNode != nil {
if annotationsNode.Kind == yaml_v3.AliasNode {
if newMetadataAnnotationsNode := createNode(map[string]interface{}{"annotations": map[string]string{}}); newMetadataAnnotationsNode != nil {
if newAnnotationsNode := findNodeByKey(newMetadataAnnotationsNode, "annotations"); newAnnotationsNode != nil {
newAnnotationsNode.Content = append(newAnnotationsNode.Content, annotationsNode.Alias.Content...)

if newExtraAnnotationsNode := createNode(extraAnnotations); newExtraAnnotationsNode != nil {
newAnnotationsNode.Content = append(newAnnotationsNode.Content, newExtraAnnotationsNode.Content...)
}
}
replaceNodeByKey(metadataNode, "annotations", newMetadataAnnotationsNode)
}
} else {
if newExtraAnnotationsNode := createNode(extraAnnotations); newExtraAnnotationsNode != nil {
annotationsNode.Content = append(annotationsNode.Content, newExtraAnnotationsNode.Content...)
}
}
} else {
if newMetadataAnnotationsNode := createNode(map[string]interface{}{"annotations": extraAnnotations}); newMetadataAnnotationsNode != nil {
metadataNode.Content = append(metadataNode.Content, newMetadataAnnotationsNode.Content...)
}
}
}
metadata = setMapValueByKey(metadata, "annotations", annotations)
objMapSlice = setMapValueByKey(objMapSlice, "metadata", metadata)
}
}

if obj.IsList() && len(extraLabels) > 0 {
logboek.Warn().LogF("werf labels won't be applied to *List resource Kinds, including %s. We advise to replace *List resources with multiple separate resources of the same Kind\n", obj.GetKind())
} else if len(extraLabels) > 0 {
if metadata := findMapByKey(objMapSlice, "metadata"); metadata != nil {
labels := findMapByKey(metadata, "labels")
for k, v := range extraLabels {
labels = append(labels, orig_yaml.MapItem{Key: k, Value: v})
if objMapNode := getMapNode(&objNode); objMapNode != nil {
if metadataNode := findNodeByKey(objMapNode, "metadata"); metadataNode != nil {
if labelsNode := findNodeByKey(metadataNode, "labels"); labelsNode != nil {
if labelsNode.Kind == yaml_v3.AliasNode {
if newMetadataLabelsNode := createNode(map[string]interface{}{"labels": map[string]string{}}); newMetadataLabelsNode != nil {
if newLabelsNode := findNodeByKey(newMetadataLabelsNode, "labels"); newLabelsNode != nil {
newLabelsNode.Content = append(newLabelsNode.Content, labelsNode.Alias.Content...)

if newExtraLabelsNode := createNode(extraLabels); newExtraLabelsNode != nil {
newLabelsNode.Content = append(newLabelsNode.Content, newExtraLabelsNode.Content...)
}
}
replaceNodeByKey(metadataNode, "labels", newMetadataLabelsNode)
}
} else {
if newExtraLabelsNode := createNode(extraLabels); newExtraLabelsNode != nil {
labelsNode.Content = append(labelsNode.Content, newExtraLabelsNode.Content...)
}
}
} else {
if newMetadataLabelsNode := createNode(map[string]interface{}{"labels": extraLabels}); newMetadataLabelsNode != nil {
metadataNode.Content = append(metadataNode.Content, newMetadataLabelsNode.Content...)
}
}
}
metadata = setMapValueByKey(metadata, "labels", labels)
objMapSlice = setMapValueByKey(objMapSlice, "metadata", metadata)
}
}

if modifiedManifestContent, err := orig_yaml.Marshal(objMapSlice); err != nil {
var modifiedManifestContent bytes.Buffer
yamlEncoder := yaml_v3.NewEncoder(&modifiedManifestContent)
yamlEncoder.SetIndent(2)

if err := yamlEncoder.Encode(&objNode); err != nil {
return nil, fmt.Errorf("unable to modify manifest: %w\n%s\n---\n", err, manifestContent)
} else {
splitModifiedManifests = append(splitModifiedManifests, manifestSource+"\n"+string(modifiedManifestContent))
splitModifiedManifests = append(splitModifiedManifests, modifiedManifestContent.String())

if os.Getenv("WERF_HELM_V3_EXTRA_ANNOTATIONS_AND_LABELS_DEBUG") == "1" {
fmt.Printf("ExtraAnnotationsAndLabelsPostRenderer -- modified manifest BEGIN\n")
fmt.Printf("%s\n", modifiedManifestContent)
fmt.Printf("%s\n", modifiedManifestContent.String())
fmt.Printf("ExtraAnnotationsAndLabelsPostRenderer -- modified manifest END\n")
}
}
Expand Down

0 comments on commit b8211a9

Please sign in to comment.