github.com/verrazzano/verrazzano@v1.7.1/application-operator/controllers/template/template.go (about) 1 // Copyright (c) 2021, 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package template 5 6 import ( 7 "bytes" 8 "context" 9 "crypto/sha256" 10 "encoding/base64" 11 "errors" 12 "fmt" 13 k8score "k8s.io/api/core/v1" 14 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 15 "sigs.k8s.io/controller-runtime/pkg/client" 16 "text/template" 17 ) 18 19 // Processor contains the references required to populate a golang template 20 type Processor struct { 21 template string 22 client client.Client 23 } 24 25 // NewProcessor creates a new template processor that can read values from kubernetes resources and provided structs 26 func NewProcessor(client client.Client, template string) *Processor { 27 return &Processor{ 28 client: client, 29 template: template, 30 } 31 } 32 33 // get fetches a resources from the processor's client and returns the resulting map 34 func (p *Processor) get(apiversion string, kind string, namespace string, name string) (map[string]interface{}, error) { 35 u := &unstructured.Unstructured{} 36 u.SetAPIVersion(apiversion) 37 u.SetKind(kind) 38 err := p.client.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: name}, u) 39 if err != nil { 40 return nil, err 41 } 42 return u.Object, nil 43 } 44 45 // configmap populates template values from a kubernetes configmap 46 func (p *Processor) configmap(namespace string, name string, key string) (string, error) { 47 cm := &k8score.ConfigMap{} 48 err := p.client.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: name}, cm) 49 if err != nil { 50 return "", err 51 } 52 value, ok := cm.Data[key] 53 if !ok { 54 return "", errors.New("missing value for key " + key) 55 } 56 57 return value, nil 58 } 59 60 // secret populates template values from a kubernetes secret 61 func (p *Processor) secret(namespace string, name string, key string) (string, error) { 62 secret := &k8score.Secret{} 63 err := p.client.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: name}, secret) 64 if err != nil { 65 return "", err 66 } 67 value, ok := secret.Data[key] 68 if !ok { 69 return "", errors.New("missing value for key " + key) 70 } 71 72 return string(value), nil 73 } 74 75 // Process leverages kubernetes and the provided inputs to populate a template 76 func (p *Processor) Process(inputs map[string]interface{}) (string, error) { 77 h := sha256.New() 78 h.Write([]byte(p.template)) 79 n := base64.URLEncoding.EncodeToString(h.Sum(nil)) 80 t, err := template.New(n). 81 Option("missingkey=error"). 82 Funcs(template.FuncMap{ 83 "get": p.get, 84 "configmap": p.configmap, 85 "secret": p.secret}). 86 Parse(p.template) 87 if err != nil { 88 return "", fmt.Errorf("error parsing template: %v", err) 89 } 90 91 var v bytes.Buffer 92 err = t.Execute(&v, inputs) 93 if err != nil { 94 return "", fmt.Errorf("error executing template: %v", err) 95 } 96 97 return v.String(), nil 98 }