github.imxd.top/operator-framework/operator-sdk@v0.8.2/pkg/helm/engine/ownerref.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package engine 16 17 import ( 18 "bytes" 19 "fmt" 20 "sort" 21 "strings" 22 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/helm/pkg/chartutil" 27 "k8s.io/helm/pkg/proto/hapi/chart" 28 "k8s.io/helm/pkg/releaseutil" 29 "k8s.io/helm/pkg/tiller/environment" 30 ) 31 32 // OwnerRefEngine wraps a tiller Render engine, adding ownerrefs to rendered assets 33 type OwnerRefEngine struct { 34 environment.Engine 35 refs []metav1.OwnerReference 36 } 37 38 // assert interface 39 var _ environment.Engine = &OwnerRefEngine{} 40 41 // Render proxies to the wrapped Render engine and then adds ownerRefs to each rendered file 42 func (o *OwnerRefEngine) Render(chart *chart.Chart, values chartutil.Values) (map[string]string, error) { 43 rendered, err := o.Engine.Render(chart, values) 44 if err != nil { 45 return nil, err 46 } 47 48 ownedRenderedFiles := map[string]string{} 49 for fileName, renderedFile := range rendered { 50 if !strings.HasSuffix(fileName, ".yaml") { 51 // Pass non-YAML files through untouched. 52 // This is required for NOTES.txt 53 ownedRenderedFiles[fileName] = renderedFile 54 continue 55 } 56 withOwner, err := o.addOwnerRefs(renderedFile) 57 if err != nil { 58 return nil, err 59 } 60 if withOwner == "" { 61 continue 62 } 63 ownedRenderedFiles[fileName] = withOwner 64 } 65 return ownedRenderedFiles, nil 66 } 67 68 // addOwnerRefs adds the configured ownerRefs to a single rendered file 69 // Adds the ownerrefs to all the documents in a YAML file 70 func (o *OwnerRefEngine) addOwnerRefs(fileContents string) (string, error) { 71 const documentSeparator = "---\n" 72 var outBuf bytes.Buffer 73 74 manifests := releaseutil.SplitManifests(fileContents) 75 for _, manifest := range sortManifests(manifests) { 76 manifestMap := chartutil.FromYaml(manifest) 77 if errors, ok := manifestMap["Error"]; ok { 78 return "", fmt.Errorf("error parsing rendered template to add ownerrefs: %v", errors) 79 } 80 81 // Check if the document is empty 82 if len(manifestMap) == 0 { 83 continue 84 } 85 86 unst, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&manifestMap) 87 if err != nil { 88 return "", err 89 } 90 91 unstructured := &unstructured.Unstructured{Object: unst} 92 unstructured.SetOwnerReferences(o.refs) 93 94 // Write the document with owner ref to the buffer 95 // Also add document start marker 96 _, err = outBuf.WriteString(documentSeparator + chartutil.ToYaml(unstructured.Object)) 97 if err != nil { 98 return "", fmt.Errorf("error writing the document to buffer: %v", err) 99 } 100 } 101 102 return outBuf.String(), nil 103 } 104 105 // NewOwnerRefEngine creates a new OwnerRef engine with a set of metav1.OwnerReferences to be added to assets 106 func NewOwnerRefEngine(baseEngine environment.Engine, refs []metav1.OwnerReference) environment.Engine { 107 return &OwnerRefEngine{ 108 Engine: baseEngine, 109 refs: refs, 110 } 111 } 112 113 func sortManifests(in map[string]string) []string { 114 var keys []string 115 for k := range in { 116 keys = append(keys, k) 117 } 118 sort.Strings(keys) 119 120 var manifests []string 121 for _, k := range keys { 122 manifests = append(manifests, in[k]) 123 } 124 return manifests 125 }