github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/pkg/live/rgpath.go (about) 1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package live 16 17 import ( 18 "encoding/json" 19 20 "github.com/GoogleContainerTools/kpt/internal/util/pathutil" 21 rgfilev1alpha1 "github.com/GoogleContainerTools/kpt/pkg/api/resourcegroup/v1alpha1" 22 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 23 "sigs.k8s.io/cli-utils/pkg/manifestreader" 24 "sigs.k8s.io/kustomize/kyaml/kio" 25 "sigs.k8s.io/kustomize/kyaml/kio/filters" 26 "sigs.k8s.io/kustomize/kyaml/kio/kioutil" 27 "sigs.k8s.io/kustomize/kyaml/yaml" 28 ) 29 30 // ResourceGroupPathManifestReader encapsulates the default path 31 // manifest reader. 32 type ResourceGroupPathManifestReader struct { 33 PkgPath string 34 35 manifestreader.ReaderOptions 36 } 37 38 // Read reads the manifests and returns them as Info objects. 39 // Generates and adds a ResourceGroup inventory object from 40 // Kptfile data. If unable to generate the ResourceGroup inventory 41 // object from the Kptfile, it is NOT an error. 42 func (r *ResourceGroupPathManifestReader) Read() ([]*unstructured.Unstructured, error) { 43 absPkgPath, _, err := pathutil.ResolveAbsAndRelPaths(r.PkgPath) 44 if err != nil { 45 return nil, err 46 } 47 48 var objs []*unstructured.Unstructured 49 nodes, err := (&kio.LocalPackageReader{ 50 PackagePath: absPkgPath, 51 WrapBareSeqNode: true, 52 }).Read() 53 if err != nil { 54 return objs, err 55 } 56 57 for _, n := range nodes { 58 if err := removeAnnotations(n, kioutil.IndexAnnotation, kioutil.LegacyIndexAnnotation); err != nil { // nolint:staticcheck 59 return objs, err 60 } 61 u, err := kyamlNodeToUnstructured(n) 62 if err != nil { 63 return objs, err 64 } 65 66 // Skip if current file is a ResourceGroup resource. We do not want to apply/delete any ResourceGroup CRs when we 67 // run any `kpt live` commands on a package. Instead, we have specific logic in place for handling ResourceGroups in 68 // the live cluster. 69 if u.GroupVersionKind() == rgfilev1alpha1.ResourceGroupGVK() { 70 continue 71 } 72 objs = append(objs, u) 73 } 74 75 objs = filterLocalConfig(objs) 76 err = manifestreader.SetNamespaces(r.Mapper, objs, r.Namespace, r.EnforceNamespace) 77 return objs, err 78 } 79 80 // removeAnnotations removes the specified kioutil annotations from the resource. 81 func removeAnnotations(n *yaml.RNode, annotations ...kioutil.AnnotationKey) error { 82 for _, a := range annotations { 83 err := n.PipeE(yaml.ClearAnnotation(a)) 84 if err != nil { 85 return err 86 } 87 } 88 return nil 89 } 90 91 // kyamlNodeToUnstructured take a resource represented as a kyaml RNode and 92 // turns it into an Unstructured object. 93 //nolint:interfacer 94 func kyamlNodeToUnstructured(n *yaml.RNode) (*unstructured.Unstructured, error) { 95 b, err := n.MarshalJSON() 96 if err != nil { 97 return nil, err 98 } 99 100 var m map[string]interface{} 101 err = json.Unmarshal(b, &m) 102 if err != nil { 103 return nil, err 104 } 105 106 return &unstructured.Unstructured{ 107 Object: m, 108 }, nil 109 } 110 111 const NoLocalConfigAnnoVal = "false" 112 113 // filterLocalConfig returns a new slice of Unstructured where all resources 114 // that are designated as local config have been filtered out. It does this 115 // by looking at the config.kubernetes.io/local-config annotation. Any value 116 // except "false" is considered to mean the resource is local config. 117 // Note(droot): Since we stopped giving special treatment to functionConfigs 118 // "false" value for the local-config annotation doesn't make much sense. 119 // With that we can probably enable just presence of local-config annotation 120 // as a way to mark that config is local. Can get rid of confusion as pointed out in the 121 // issue --> https://github.com/GoogleContainerTools/kpt/issues/2767 122 func filterLocalConfig(objs []*unstructured.Unstructured) []*unstructured.Unstructured { 123 var filteredObjs []*unstructured.Unstructured 124 for _, obj := range objs { 125 annoVal, found := obj.GetAnnotations()[filters.LocalConfigAnnotation] 126 if found && annoVal != NoLocalConfigAnnoVal { 127 continue 128 } 129 filteredObjs = append(filteredObjs, obj) 130 } 131 return filteredObjs 132 }