github.com/grafana/tanka@v0.26.1-0.20240506093700-c22cfc35c21a/pkg/process/process.go (about) 1 package process 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/grafana/tanka/pkg/kubernetes/manifest" 8 "github.com/grafana/tanka/pkg/spec/v1alpha1" 9 ) 10 11 const ( 12 MetadataPrefix = "tanka.dev" 13 LabelEnvironment = MetadataPrefix + "/environment" 14 ) 15 16 // Process converts the raw Jsonnet evaluation result (JSON tree) into a flat 17 // list of Kubernetes objects, also applying some transformations: 18 // - tanka.dev/** labels 19 // - filtering 20 // - best-effort sorting 21 func Process(cfg v1alpha1.Environment, exprs Matchers) (manifest.List, error) { 22 raw := cfg.Data 23 24 if raw == nil { 25 return manifest.List{}, nil 26 } 27 28 // Scan for everything that looks like a Kubernetes object 29 extracted, err := Extract(raw) 30 if err != nil { 31 return nil, fmt.Errorf("got an error while extracting env `%s`: %w", cfg.Metadata.Name, err) 32 } 33 34 // Unwrap *List types 35 if err := Unwrap(extracted); err != nil { 36 return nil, err 37 } 38 39 out := make(manifest.List, 0, len(extracted)) 40 for _, m := range extracted { 41 out = append(out, m) 42 } 43 44 // set default namespace 45 out = Namespace(out, cfg.Spec.Namespace) 46 47 // tanka.dev/** labels 48 out = Label(out, cfg) 49 50 // arbitrary labels and annotations from spec 51 out = ResourceDefaults(out, cfg) 52 53 // Perhaps filter for kind/name expressions 54 if len(exprs) > 0 { 55 out = Filter(out, exprs) 56 } 57 58 // Best-effort dependency sort 59 Sort(out) 60 61 return out, nil 62 } 63 64 // Label conditionally adds tanka.dev/** labels to each manifest in the List 65 func Label(list manifest.List, cfg v1alpha1.Environment) manifest.List { 66 for i, m := range list { 67 // inject tanka.dev/environment label 68 if cfg.Spec.InjectLabels { 69 m.Metadata().Labels()[LabelEnvironment] = cfg.Metadata.NameLabel() 70 } 71 list[i] = m 72 } 73 74 return list 75 } 76 77 func ResourceDefaults(list manifest.List, cfg v1alpha1.Environment) manifest.List { 78 for i, m := range list { 79 for k, v := range cfg.Spec.ResourceDefaults.Annotations { 80 annotations := m.Metadata().Annotations() 81 if _, ok := annotations[k]; !ok { 82 annotations[k] = v 83 } 84 } 85 86 for k, v := range cfg.Spec.ResourceDefaults.Labels { 87 labels := m.Metadata().Labels() 88 if _, ok := labels[k]; !ok { 89 labels[k] = v 90 } 91 } 92 93 list[i] = m 94 } 95 return list 96 } 97 98 // Unwrap returns all Kubernetes objects in the manifest. If m is not a List 99 // type, a one item List is returned 100 func Unwrap(manifests map[string]manifest.Manifest) error { 101 for path, m := range manifests { 102 if !m.IsList() { 103 continue 104 } 105 106 items, err := m.Items() 107 if err != nil { 108 return err 109 } 110 111 for index, i := range items { 112 name := fmt.Sprintf("%s.items[%v]", path, index) 113 114 var e *manifest.SchemaError 115 if errors.As(i.Verify(), &e) { 116 e.Name = name 117 return e 118 } 119 120 manifests[name] = i 121 } 122 123 delete(manifests, path) 124 } 125 126 return nil 127 }