github.com/verrazzano/verrazzano@v1.7.0/tools/vz/cmd/helpers/operator_yaml.go (about) 1 // Copyright (c) 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 "bufio" 8 "fmt" 9 "io/fs" 10 "os" 11 "strings" 12 13 "github.com/verrazzano/verrazzano/pkg/k8sutil" 14 vzos "github.com/verrazzano/verrazzano/pkg/os" 15 vpoconst "github.com/verrazzano/verrazzano/platform-operator/constants" 16 "github.com/verrazzano/verrazzano/tools/vz/pkg/constants" 17 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 18 ) 19 20 // updateOperatorYAMLPrivateRegistry edits the operator yaml file after copying it to a new temp file 21 func updateOperatorYAMLPrivateRegistry(operatorFilename string, imageRegistry string, imagePrefix string) (string, error) { 22 var err error 23 24 fileObj, err := os.Open(operatorFilename) 25 defer func() { fileObj.Close() }() 26 if err != nil { 27 return operatorFilename, err 28 } 29 objectsInYAML, err := k8sutil.Unmarshall(bufio.NewReader(fileObj)) 30 if err != nil { 31 return "", err 32 } 33 vpoDeployIdx, vpoWebhookDeployIdx := findVPODeploymentIndices(objectsInYAML) 34 vpoDeploy := &objectsInYAML[vpoDeployIdx] 35 vpoWebhookDeploy := &objectsInYAML[vpoWebhookDeployIdx] 36 37 vpoDeployUpdated, err := updatePrivateRegistryVPODeploy(vpoDeploy, imageRegistry, imagePrefix, true) 38 if err != nil { 39 return "", err 40 } 41 vpoWebhookDeployUpdated, err := updatePrivateRegistryVPODeploy(vpoWebhookDeploy, imageRegistry, imagePrefix, false) 42 if err != nil { 43 return "", err 44 } 45 if !vpoDeployUpdated && !vpoWebhookDeployUpdated { 46 return operatorFilename, nil 47 } 48 objectsInYAML[vpoDeployIdx] = *vpoDeploy 49 objectsInYAML[vpoWebhookDeployIdx] = *vpoWebhookDeploy 50 bytesToWrite, err := k8sutil.Marshal(objectsInYAML) 51 if err != nil { 52 return "", err 53 } 54 55 var tempFile *os.File 56 if tempFile, err = vzos.CreateTempFile("vz-operator-file", nil); err != nil { 57 return "", err 58 } 59 editedOperatorFile := tempFile.Name() 60 if err := os.WriteFile(editedOperatorFile, bytesToWrite, fs.ModeAppend); err != nil { 61 return "", err 62 } 63 return editedOperatorFile, nil 64 } 65 66 func findVPODeploymentIndices(objectsInYAML []unstructured.Unstructured) (int, int) { 67 vpoDeployIdx := -1 68 vpoWebhookDeployIdx := -1 69 for idx, yamlObj := range objectsInYAML { 70 if yamlObj.GetObjectKind().GroupVersionKind().Kind == "Deployment" { 71 if yamlObj.GetName() == constants.VerrazzanoPlatformOperator { 72 vpoDeployIdx = idx 73 } else if yamlObj.GetName() == constants.VerrazzanoPlatformOperatorWebhook { 74 vpoWebhookDeployIdx = idx 75 } 76 } 77 } 78 return vpoDeployIdx, vpoWebhookDeployIdx 79 } 80 81 // updatePrivateRegistryVPODeploy updates the private registry information in the 82 // given verrazzano-platform-operator (or webhook) deployment YAML. Returns true if vpoDeploy was modified 83 func updatePrivateRegistryVPODeploy(vpoDeploy *unstructured.Unstructured, imageRegistry string, imagePrefix string, addRegistryEnvVars bool) (bool, error) { 84 vpoDeployObj := vpoDeploy.Object 85 containersFields := containersFields() 86 initContainersFields := initContainersFields() 87 88 containers, found, err := unstructured.NestedSlice(vpoDeployObj, containersFields...) 89 if err != nil || !found { 90 return false, fmt.Errorf("Failed to find containers in verrazzano-platform-operator deployment") 91 } 92 93 initContainers, found, err := unstructured.NestedSlice(vpoDeployObj, initContainersFields...) 94 if err != nil || !found { 95 return false, fmt.Errorf("Failed to find initContainers in verrazzano-platform-operator deployment") 96 } 97 98 updated := false 99 for idx := range initContainers { 100 // Use indexing on the slice to get a reference to the initCtr so we can edit it. By default 101 // range returns copies so our edits won't stick 102 initCtr := initContainers[idx].(map[string]interface{}) 103 ctrUpdated := updatePrivateRegistryOnContainer(initCtr, imageRegistry, imagePrefix) 104 updated = updated || ctrUpdated 105 } 106 107 for idx := range containers { 108 // Use indexing on the slice to get a reference to the container so we can edit it. By default 109 // range returns copies so our edits won't stick 110 container := containers[idx].(map[string]interface{}) 111 ctrUpdated := updatePrivateRegistryOnContainer(container, imageRegistry, imagePrefix) 112 updated = updated || ctrUpdated 113 if container["name"] == constants.VerrazzanoPlatformOperator { 114 envUpdated := addRegistryEnvVarsToContainer(container, imageRegistry, imagePrefix) 115 updated = updated || envUpdated 116 } 117 } 118 119 if updated { 120 if err := unstructured.SetNestedSlice(vpoDeployObj, containers, containersFields...); err != nil { 121 return false, err 122 } 123 if err := unstructured.SetNestedSlice(vpoDeployObj, initContainers, initContainersFields...); err != nil { 124 return false, err 125 } 126 vpoDeploy.SetUnstructuredContent(vpoDeployObj) 127 return true, nil 128 } 129 return false, nil 130 } 131 132 func addRegistryEnvVarsToContainer(container map[string]interface{}, imageRegistry string, imagePrefix string) bool { 133 foundRegistry := false 134 foundPrefix := false 135 updated := false 136 env := container["env"].([]interface{}) 137 if env == nil { 138 env = make([]interface{}, 2) 139 } 140 for idx := range env { 141 envVar := env[idx].(map[string]interface{}) 142 if envVar["name"] == vpoconst.RegistryOverrideEnvVar { 143 foundRegistry = true 144 if envVar["value"] != imageRegistry { 145 envVar["value"] = imageRegistry 146 updated = true 147 } 148 } 149 if envVar["name"] == vpoconst.ImageRepoOverrideEnvVar { 150 foundPrefix = true 151 if envVar["value"] != imagePrefix { 152 envVar["value"] = imagePrefix 153 updated = true 154 } 155 } 156 } 157 if !foundRegistry { 158 env = append(env, map[string]interface{}{ 159 "name": vpoconst.RegistryOverrideEnvVar, 160 "value": imageRegistry, 161 }) 162 updated = true 163 } 164 if !foundPrefix { 165 env = append(env, map[string]interface{}{ 166 "name": vpoconst.ImageRepoOverrideEnvVar, 167 "value": imagePrefix, 168 }) 169 updated = true 170 } 171 container["env"] = env 172 return updated 173 } 174 175 func updatePrivateRegistryOnContainer(container map[string]interface{}, imageRegistry string, imagePrefix string) bool { 176 curImage := container["image"].(string) 177 suffixPattern := fmt.Sprintf("/verrazzano/%s", constants.VerrazzanoPlatformOperator) 178 imageSuffix := curImage[strings.LastIndex(curImage, suffixPattern)+1:] 179 newImage := fmt.Sprintf("%s/%s/%s", imageRegistry, imagePrefix, imageSuffix) 180 if newImage == curImage { 181 // no update needed 182 return false 183 } 184 container["image"] = newImage 185 return true 186 } 187 188 func containersFields() []string { 189 return []string{"spec", "template", "spec", "containers"} 190 } 191 192 func initContainersFields() []string { 193 return []string{"spec", "template", "spec", "initContainers"} 194 }