From: Yolanda Robla Date: Fri, 16 Aug 2019 14:18:45 +0000 (+0200) Subject: Retrieve original source for kustomize X-Git-Tag: akraino_r2~21^2~1 X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F21%2F1421%2F9;p=kni%2Finstaller.git Retrieve original source for kustomize When patching content that is dynamically generated and not being in kustomize, it cannot be done as it misses the original source. Add a pre-processing in apply_workloads, so it will retrieve all the original data from cluster deploy, to make it available to kustomize. Signed-off-by: Yolanda Robla Change-Id: Ibd37801768fa2c45b89bdfa161838d843dd2c436 --- diff --git a/pkg/site/site.go b/pkg/site/site.go index 39f98a1..d0d8fc6 100644 --- a/pkg/site/site.go +++ b/pkg/site/site.go @@ -406,25 +406,31 @@ func (s Site) ApplyWorkloads(kubeconfigFile string) { } } binariesPath := fmt.Sprintf("%s/requirements", siteBuildPath) + ocPath := fmt.Sprintf("%s/oc", binariesPath) + kustomizePath := fmt.Sprintf("%s/kustomize", binariesPath) // retrieve profile path and clone the repo _, profileLayerPath, profileRef := s.GetProfileFromSite() s.DownloadRepo(siteBuildPath, profileLayerPath, profileRef) - log.Println(fmt.Sprintf("Applying workloads from %s/blueprint/sites/site/02_cluster-addons", siteBuildPath)) - out := utils.ApplyKustomize(fmt.Sprintf("%s/kustomize", binariesPath), fmt.Sprintf("%s/blueprint/sites/site/02_cluster-addons", siteBuildPath)) + addonsPath := fmt.Sprintf("%s/blueprint/sites/site/02_cluster-addons", siteBuildPath) + log.Println(fmt.Sprintf("Applying workloads from %s", addonsPath)) + utils.PrepareKustomize(ocPath, addonsPath, kubeconfigFile) + out := utils.ApplyKustomize(kustomizePath, addonsPath) if string(out) != "" { // now we can apply it utils.ApplyOc(fmt.Sprintf("%s/oc", binariesPath), out, kubeconfigFile) } else { - log.Println(fmt.Sprintf("No manifests found for %s/blueprint/sites/site/02_cluster-addons", siteBuildPath)) + log.Println(fmt.Sprintf("No manifests found for %s", addonsPath)) } - log.Println(fmt.Sprintf("Applying workloads from %s/blueprint/sites/site/03_services", siteBuildPath)) - out = utils.ApplyKustomize(fmt.Sprintf("%s/kustomize", binariesPath), fmt.Sprintf("%s/blueprint/sites/site/03_services", siteBuildPath)) + servicesPath := fmt.Sprintf("%s/blueprint/sites/site/03_services", siteBuildPath) + log.Println(fmt.Sprintf("Applying workloads from %s", servicesPath)) + utils.PrepareKustomize(ocPath, servicesPath, kubeconfigFile) + out = utils.ApplyKustomize(kustomizePath, servicesPath) if string(out) != "" { // now we can apply it - utils.ApplyOc(fmt.Sprintf("%s/oc", binariesPath), out, kubeconfigFile) + utils.ApplyOc(ocPath, out, kubeconfigFile) } else { - log.Println(fmt.Sprintf("No manifests found for %s/blueprint/sites/site/03_services", siteBuildPath)) + log.Println(fmt.Sprintf("No manifests found for %s", servicesPath)) } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index cd11002..58cbdca 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -7,8 +7,12 @@ import ( "log" "os" "os/exec" + "path" "path/filepath" + "reflect" "time" + + "gopkg.in/yaml.v2" ) // utility to validate pre-requisites for deploying @@ -36,6 +40,130 @@ func ValidateRequirements(buildPath string, siteName string) { } +// utility to get all kustomize dependencies before applying them +func PrepareKustomize(kubectlBinary string, kustomizePath string, kubeconfigPath string) { + kustomizationContent, err := ioutil.ReadFile(fmt.Sprintf("%s/kustomization.yaml", kustomizePath)) + if err != nil { + log.Println(fmt.Sprintf("Error reading kustomization content: %s", err)) + os.Exit(1) + } + var kustomizationContentObj map[interface{}]interface{} + err = yaml.Unmarshal(kustomizationContent, &kustomizationContentObj) + + // check if we have patchesjson entry + var patchesOutput [][]byte + if jsonPatches, ok := kustomizationContentObj["patchesJson6902"]; ok { + jsonList := reflect.ValueOf(jsonPatches) + var targetPatch map[interface{}]interface{} + var kindPatch interface{} + var namePatch interface{} + var namespacePatch interface{} + var groupPatch interface{} + var namespaceContent string + + for i := 0; i < jsonList.Len(); i++ { + currentPatch := jsonList.Index(i).Interface().(map[interface{}]interface{}) + targetPatch, ok = currentPatch["target"].(map[interface{}]interface{}) + if !ok { + log.Fatal("Error parsing json patch, target not found") + os.Exit(1) + } + if kindPatch, ok = targetPatch["kind"]; !ok { + log.Fatal("Error parsing json patch, kind not found") + os.Exit(1) + } + if namePatch, ok = targetPatch["name"]; !ok { + log.Fatal("Error parsing json patch, name not found") + os.Exit(1) + } + if namespacePatch, ok = targetPatch["namespace"]; !ok { + namespaceContent = "" + } else { + namespaceContent = fmt.Sprintf("--namespace %s", namespacePatch) + } + + if groupPatch, ok = targetPatch["group"]; ok { + kindPatch = fmt.Sprintf("%s.%s", kindPatch, groupPatch) + } + + // we have the signature of the patch, let's get the content + var envVars[] string + if len(kubeconfigPath)>0 { + envVars = append(envVars, fmt.Sprintf("KUBECONFIG=%s", kubeconfigPath)) + } + finalCommand := fmt.Sprintf("%s get %s/%s -o yaml %s", kubectlBinary, kindPatch, namePatch, namespaceContent) + out, err := ExecuteCommand("", envVars, false, false, "/bin/bash", "-c", finalCommand) + + if len(err) > 0 { + log.Println(fmt.Sprintf("Error extracting content from %s/%s", kindPatch, namePatch)) + } else { + // if there is output, append to contents + if out != nil { + patchesOutput = append(patchesOutput, out) + } + } + } + } + + // if patchesOutput has content, create an entry in resources to inject the patches bit + if len(patchesOutput) > 0 { + resourcesPath := fmt.Sprintf("%s/patches_objects.yaml", kustomizePath) + os.Remove(resourcesPath) + f, err := os.Create(resourcesPath) + defer f.Close() + if err != nil { + log.Fatal(fmt.Sprintf("Error creating patches file: %s", resourcesPath)) + os.Exit(1) + } + + for _, patch := range patchesOutput { + f.WriteString("---\n") + f.Write(patch) + } + + // if there is no resources entry, add it + if _, ok := kustomizationContentObj["resources"]; !ok { + kustomizationContentObj["resources"] = make([]interface{}, 0) + } + resources := kustomizationContentObj["resources"] + + // if entry does not exist, append it + found := false + for _, resourceValue := range resources.([]interface{}) { + if resourceValue == resourcesPath { + found = true + break + } + } + if !found { + resources = append(resources.([]interface{}), resourcesPath) + kustomizationContentObj["resources"] = resources + } + final, err := yaml.Marshal(&kustomizationContentObj) + if err != nil { + log.Fatal("Error manipulating kustomization file") + os.Exit(1) + } + // overwrite the original kustomization file + err = ioutil.WriteFile(fmt.Sprintf("%s/kustomization.yaml", kustomizePath), final, 0644) + if err != nil { + log.Fatal(fmt.Sprintf("Error writing final kustomization file: %s", err)) + os.Exit(1) + } + } + + //var basesOutput [][]byte + if bases, ok := kustomizationContentObj["bases"]; ok { + for _, baseValue := range bases.([]interface{}) { + // convert to an absolute path + absoluteBaseValue := path.Join(kustomizePath, baseValue.(string)) + + // recursively call prepare kustomize + PrepareKustomize(kubectlBinary, absoluteBaseValue, kubeconfigPath) + } + } +} + // utility to apply kustomize on a given directory func ApplyKustomize(kustomizeBinary string, kustomizePath string) []byte { // retrieve executable path to inject env var