github.com/verrazzano/verrazzano@v1.7.0/tools/vz/cmd/helpers/overlay.go (about) 1 // Copyright (c) 2022, 2023, 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 helpers 5 6 import ( 7 "fmt" 8 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1" 9 "github.com/verrazzano/verrazzano/tools/vz/pkg/helpers" 10 "io" 11 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 12 "k8s.io/apimachinery/pkg/runtime/schema" 13 "os" 14 clipkg "sigs.k8s.io/controller-runtime/pkg/client" 15 "strings" 16 17 "k8s.io/apimachinery/pkg/util/strategicpatch" 18 "sigs.k8s.io/yaml" 19 ) 20 21 // MergeYAMLFiles parses the given slice of filenames containing yaml and 22 // merges them into a single verrazzano yaml and then returned as a vz resource. 23 func MergeYAMLFiles(filenames []string, stdinReader io.Reader) (*unstructured.Unstructured, error) { 24 var vzYAML string 25 var stdin bool 26 var gv = &schema.GroupVersion{} 27 for _, filename := range filenames { 28 var readBytes []byte 29 var err error 30 // filename of "-" is for reading from stdin 31 if filename == "-" { 32 if stdin { 33 continue 34 } 35 stdin = true 36 readBytes, err = io.ReadAll(stdinReader) 37 } else { 38 readBytes, err = os.ReadFile(strings.TrimSpace(filename)) 39 } 40 if err != nil { 41 return nil, err 42 } 43 if err := checkGroupVersion(readBytes, gv); err != nil { 44 return nil, err 45 } 46 vzYAML, err = overlayVerrazzano(*gv, vzYAML, string(readBytes)) 47 if err != nil { 48 return nil, err 49 } 50 } 51 52 vz := &unstructured.Unstructured{} 53 err := yaml.Unmarshal([]byte(vzYAML), &vz) 54 if err != nil { 55 return nil, fmt.Errorf("Failed to create a verrazzano install resource: %s", err.Error()) 56 } 57 if vz.GetNamespace() == "" { 58 vz.SetNamespace("default") 59 } 60 if vz.GetName() == "" { 61 vz.SetName("verrazzano") 62 } 63 64 return vz, nil 65 } 66 67 // MergeSetFlags merges yaml representing a set flag passed on the command line with a 68 // verrazano install resource. A merged verrazzano install resource is returned. 69 func MergeSetFlags(gv schema.GroupVersion, vz clipkg.Object, overlayYAML string) (clipkg.Object, *unstructured.Unstructured, error) { 70 baseYAML, err := yaml.Marshal(vz) 71 if err != nil { 72 return vz, nil, err 73 } 74 vzYAML, err := overlayVerrazzano(gv, string(baseYAML), overlayYAML) 75 if err != nil { 76 return vz, nil, err 77 } 78 79 obj := &unstructured.Unstructured{} 80 err = yaml.Unmarshal([]byte(vzYAML), obj) 81 if err != nil { 82 return obj, nil, fmt.Errorf("Failed to create a verrazzano install resource: %s", err.Error()) 83 } 84 return obj, obj, nil 85 } 86 87 // MergeSetFlagsUpgrade takes the existing Verrazzano resource and merges yaml representing a set flag passed on the command line with a 88 // A merged verrazzano install resource is returned. 89 func MergeSetFlagsUpgrade(gv schema.GroupVersion, vz *v1beta1.Verrazzano, overlayYAML string) (clipkg.Object, *unstructured.Unstructured, error) { 90 vz.APIVersion = "install.verrazzano.io/v1beta1" 91 vz.Kind = "Verrazzano" 92 baseYAML, err := yaml.Marshal(vz) 93 if err != nil { 94 return vz, nil, err 95 } 96 97 vzYAML, err := overlayVerrazzano(gv, string(baseYAML), overlayYAML) 98 if err != nil { 99 return vz, nil, err 100 } 101 102 obj := &unstructured.Unstructured{} 103 err = yaml.Unmarshal([]byte(vzYAML), obj) 104 if err != nil { 105 return obj, nil, fmt.Errorf("Failed to create a verrazzano install resource: %s", err.Error()) 106 } 107 return obj, obj, nil 108 } 109 110 // overlayVerrazzano overlays over base using JSON strategic merge. 111 func overlayVerrazzano(gv schema.GroupVersion, baseYAML string, overlayYAML string) (string, error) { 112 if strings.TrimSpace(baseYAML) == "" { 113 return overlayYAML, nil 114 } 115 if strings.TrimSpace(overlayYAML) == "" { 116 return baseYAML, nil 117 } 118 baseJSON, err := yaml.YAMLToJSON([]byte(baseYAML)) 119 if err != nil { 120 return "", fmt.Errorf("Failed to create a verrazzano install resource: %s\n%s", err.Error(), baseYAML) 121 } 122 overlayJSON, err := yaml.YAMLToJSON([]byte(overlayYAML)) 123 if err != nil { 124 return "", fmt.Errorf("Failed to create a verrazzano install resource: %s\n%s", err.Error(), overlayYAML) 125 } 126 127 // Merge the two json representations 128 mergedJSON, err := strategicpatch.StrategicMergePatch(baseJSON, overlayJSON, helpers.NewVerrazzanoForGroupVersion(gv)()) 129 if err != nil { 130 return "", fmt.Errorf("Failed to merge yaml: %s\n base object:\n%s\n override object:\n%s", err.Error(), baseJSON, overlayJSON) 131 } 132 133 mergedYAML, err := yaml.JSONToYAML(mergedJSON) 134 if err != nil { 135 return "", fmt.Errorf("Failed to create a verrazzano install resource: %s\n%s", err.Error(), mergedJSON) 136 } 137 138 return string(mergedYAML), nil 139 } 140 141 func checkGroupVersion(readBytes []byte, gv *schema.GroupVersion) error { 142 obj := &unstructured.Unstructured{} 143 if err := yaml.Unmarshal(readBytes, obj); err != nil { 144 // allow merge of unknown objects 145 return nil 146 } 147 ogv := obj.GroupVersionKind().GroupVersion() 148 if gv.Version == "" { 149 *gv = ogv 150 } else { 151 if ogv != *gv { 152 return fmt.Errorf("cannot merge objects with different group versions: %v != %v", *gv, ogv) 153 } 154 } 155 return nil 156 }