diff --git a/examples/set-namespace-imperative/.expected/config.yaml b/examples/set-namespace-imperative/.expected/config.yaml index 55abb6c2e..ba791dff5 100644 --- a/examples/set-namespace-imperative/.expected/config.yaml +++ b/examples/set-namespace-imperative/.expected/config.yaml @@ -1,4 +1,4 @@ testType: eval image: gcr.io/kpt-fn/set-namespace:unstable args: - namespace: example-ns + namespace: new-ns diff --git a/examples/set-namespace-imperative/.expected/diff.patch b/examples/set-namespace-imperative/.expected/diff.patch index 6f0e0d736..8fe95f062 100644 --- a/examples/set-namespace-imperative/.expected/diff.patch +++ b/examples/set-namespace-imperative/.expected/diff.patch @@ -1,19 +1,19 @@ diff --git a/app.yaml b/app.yaml -index 1f8aeee..33e42da 100644 +index d67a0d2..bf55161 100644 --- a/app.yaml +++ b/app.yaml @@ -9,7 +9,7 @@ apiVersion: v1 kind: Service metadata: name: the-service -- namespace: the-namespace -+ namespace: example-ns +- namespace: example ++ namespace: new-ns spec: ports: - name: etcd-server-ssl -@@ -21,4 +21,4 @@ spec: +@@ -34,4 +34,4 @@ spec: apiVersion: v1 kind: Namespace metadata: - name: example -+ name: example-ns ++ name: new-ns \ No newline at end of file diff --git a/examples/set-namespace-imperative/README.md b/examples/set-namespace-imperative/README.md index 93925024d..1bd5637bc 100644 --- a/examples/set-namespace-imperative/README.md +++ b/examples/set-namespace-imperative/README.md @@ -2,9 +2,9 @@ ### Overview -This examples shows how to set namespace in the `.metadata.namespace` field on -all resources by running [`set-namespace`] function imperatively. Resources that -are known to be cluster-scoped will be skipped. +This examples shows how to replace KRM resources' namespace fields by matching +the namespace with the namespace object's `metadata.name`. +The example uses `kpt fn eval` to run the function imperatively. ### Fetch the example package @@ -27,6 +27,7 @@ The desired namespace is provided after `--` and it will be converted to ### Expected result -Check all resources have `metadata.namespace` set to `example-ns`: +Only the namespace fields which match the `namespace` "example" object has the value updated to +`new-ns`: [`set-namespace`]: https://catalog.kpt.dev/set-namespace/v0.1/ diff --git a/examples/set-namespace-imperative/app.yaml b/examples/set-namespace-imperative/app.yaml index 1f8aeeead..d67a0d24a 100644 --- a/examples/set-namespace-imperative/app.yaml +++ b/examples/set-namespace-imperative/app.yaml @@ -9,7 +9,20 @@ apiVersion: v1 kind: Service metadata: name: the-service - namespace: the-namespace + namespace: example +spec: + ports: + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 + publishNotReadyAddresses: true +--- +apiVersion: v1 +kind: Service +metadata: + name: the-service + namespace: not-match-example spec: ports: - name: etcd-server-ssl diff --git a/functions/go/set-namespace/README.md b/functions/go/set-namespace/README.md index 762475272..848f3592c 100644 --- a/functions/go/set-namespace/README.md +++ b/functions/go/set-namespace/README.md @@ -17,68 +17,114 @@ Namespaces are often used in the following scenarios: ## Usage -This function can be used with any KRM function orchestrators (e.g. kpt). - -- If the resource is `Namespace`, `set-namespace` updates the `metadata.name` field. -- If the resource is `RoleBinding` or `ClusterRoleBinding` resource, the function updates - the namespace field in the `subjects` element whose name is `default`. -- If the resource is `CustomResourceDefinition` (CRD), `set-namespace` updates the - `spec/conversion/webhook/clientConfig/service/namespace` field. -- If the resource is `APIService`, `set-namespace` updates the - `spec/service/namespace` field. -- If there is a [`depends-on`] annotation for a namespaced resource, the namespace - section of the annotation will be updated if the referenced resource is also - declared in the package. +This function replaces the KRM resources existing namespace to a new value. +### Target KRM resources + +- This function updates all namespace-scoped KRM resources `metadata.namespace` fields. + We determine whether a KRM resource is namespace scoped by checking if it has `metadata.namespace` set and matches the "oldNamespace" + If not, this function won't add new namespace. +- This function updates `RoleBinding` and `ClusterRoleBinding` resources `subjects` element whose kind is `ServiceAccount` + and the subject's `namespace` is set and matches the "oldNamespace". +- This function updates `CustomResourceDefinition` (CRD) `spec/conversion/webhook/clientConfig/service/namespace` field + if the field is set and matches the "oldNamespace" +- This function updates `APIService` `spec/service/namespace` field if the field is set and matches the "oldNamespace" +- This function updates the KRM resources annotation `config.kubernetes.io/depends-on` if this annotation contains the + matching namespace. + +### FunctionConfig + +This function supports the default `ConfigMap` as function config and a custom `SetNamespace`. See below examples + +`ConfigMap` as functionConfig ```yaml apiVersion: v1 -kind: ServiceAccount -metadata: - name: sa - namespace: example - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/foo # <= this will NOT be updated (resource not declared) ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - ... - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/sa # <== this will be updated (resource declared) -subjects: - - kind: ServiceAccount - name: default # <================== name default is used - namespace: example # <================== this will be updated -roleRef: - kind: Role - name: confluent-operator - apiGroup: rbac.authorization.k8s.io +kind: ConfigMap +data: + namespace: newNamespace # required + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` -This function can be used both declaratively and imperatively. +`SetNamespace` as functionConfig +```yaml +apiVersion: fn.kpt.dev/v1alpha1 +kind: SetNamespace +namespace: newNamespace # required +namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" +``` -### FunctionConfig -There are 2 kinds of `functionConfig` supported by this function: +### Three updating modes -- `ConfigMap` -- A custom resource of kind `SetNamespace` +This function supports three modes to flexibly choose and update the target namespaces. -To use a `ConfigMap` as the `functionConfig`, the desired namespace must be -specified in the `data.namespace` field. +##### Restrict Mode +All target KRM resources namespace has to have the same value. All namespace will be updated to the new value. -To add a namespace `staging` to all resources, we use the -following `functionConfig`: +`ConfigMap` as functionConfig +```yaml +apiVersion: v1 +kind: ConfigMap +data: + namespace: newNamespace # update all namespace fields to "newNamespace" +``` + +##### DefaultNamespace Mode + +The input `resourcelist.items` contains one and only one `Namespace` object. The function matches the namespace `metadata.name` +with all other KRM resources, and only update the namespace if it matches the `Namespace` object. +If more than one `Namespace` objects are found, raise errors; +```yaml +kind: ResourceList +functionConfig: + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNs +items: +- apiVersion: v1 + kind: Namespace + metadata: + name: example # updated to "newNs" +- apiVersion: v1 + kind: Service + metadata: + name: the-service1 + namespace: example # updated to "newNs" +- apiVersion: v1 + kind: Service + metadata: + name: the-service2 + namespace: irrelevant # skip since namespace does not match "example". +``` + +##### Matcher Mode + +Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig + +`ConfigMap` as functionConfig ```yaml apiVersion: v1 kind: ConfigMap -metadata: - name: my-config data: - namespace: staging + namespace: newNamespace + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" +``` + +`SetNamespace` as functionConfig +```yaml +apiVersion: fn.kpt.dev/v1alpha1 +kind: SetNamespace +namespace: newNamespace +namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` +### DependsOn annotation + +DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the +namespace segment in a depends-on annotation if the namespace matches the `Namespace` object or `namespaceMatcher` field. + [namespace]: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ diff --git a/functions/go/set-namespace/generated/docs.go b/functions/go/set-namespace/generated/docs.go index 489ae77e0..f2f87c540 100644 --- a/functions/go/set-namespace/generated/docs.go +++ b/functions/go/set-namespace/generated/docs.go @@ -1,5 +1,3 @@ - - // Code generated by "mdtogo"; DO NOT EDIT. package generated @@ -8,61 +6,99 @@ of KRM resources.` var SetNamespaceLong = ` ## Usage -This function can be used with any KRM function orchestrators (e.g. kpt). +This function replaces the KRM resources existing namespace to a new value. -- If the resource is ` + "`" + `Namespace` + "`" + `, ` + "`" + `set-namespace` + "`" + ` updates the ` + "`" + `metadata.name` + "`" + ` field. -- If the resource is ` + "`" + `RoleBinding` + "`" + ` or ` + "`" + `ClusterRoleBinding` + "`" + ` resource, the function updates - the namespace field in the ` + "`" + `subjects` + "`" + ` element whose name is ` + "`" + `default` + "`" + `. -- If the resource is ` + "`" + `CustomResourceDefinition` + "`" + ` (CRD), ` + "`" + `set-namespace` + "`" + ` updates the - ` + "`" + `spec/conversion/webhook/clientConfig/service/namespace` + "`" + ` field. -- If the resource is ` + "`" + `APIService` + "`" + `, ` + "`" + `set-namespace` + "`" + ` updates the - ` + "`" + `spec/service/namespace` + "`" + ` field. -- If there is a [` + "`" + `depends-on` + "`" + `] annotation for a namespaced resource, the namespace - section of the annotation will be updated if the referenced resource is also - declared in the package. +### Target KRM resources - apiVersion: v1 - kind: ServiceAccount - metadata: - name: sa - namespace: example - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/foo # <= this will NOT be updated (resource not declared) - --- - kind: RoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - ... - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/sa # <== this will be updated (resource declared) - subjects: - - kind: ServiceAccount - name: default # <================== name default is used - namespace: example # <================== this will be updated - roleRef: - kind: Role - name: confluent-operator - apiGroup: rbac.authorization.k8s.io - -This function can be used both declaratively and imperatively. +- This function updates all namespace-scoped KRM resources ` + "`" + `metadata.namespace` + "`" + ` fields. + We determine whether a KRM resource is namespace scoped by checking if it has ` + "`" + `metadata.namespace` + "`" + ` set and matches the "oldNamespace" + If not, this function won't add new namespace. +- This function updates ` + "`" + `RoleBinding` + "`" + ` and ` + "`" + `ClusterRoleBinding` + "`" + ` resources ` + "`" + `subjects` + "`" + ` element whose kind is ` + "`" + `ServiceAccount` + "`" + ` + and the subject's ` + "`" + `namespace` + "`" + ` is set and matches the "oldNamespace". +- This function updates ` + "`" + `CustomResourceDefinition` + "`" + ` (CRD) ` + "`" + `spec/conversion/webhook/clientConfig/service/namespace` + "`" + ` field + if the field is set and matches the "oldNamespace" +- This function updates ` + "`" + `APIService` + "`" + ` ` + "`" + `spec/service/namespace` + "`" + ` field if the field is set and matches the "oldNamespace" +- This function updates the KRM resources annotation ` + "`" + `config.kubernetes.io/depends-on` + "`" + ` if this annotation contains the + matching namespace. ### FunctionConfig -There are 2 kinds of ` + "`" + `functionConfig` + "`" + ` supported by this function: +This function supports the default ` + "`" + `ConfigMap` + "`" + ` as function config and a custom ` + "`" + `SetNamespace` + "`" + `. See below examples -- ` + "`" + `ConfigMap` + "`" + ` -- A custom resource of kind ` + "`" + `SetNamespace` + "`" + ` +ConfigMap as functionConfig + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNamespace # required + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" -To use a ` + "`" + `ConfigMap` + "`" + ` as the ` + "`" + `functionConfig` + "`" + `, the desired namespace must be -specified in the ` + "`" + `data.namespace` + "`" + ` field. +SetNamespace as functionConfig + apiVersion: fn.kpt.dev/v1alpha1 + kind: SetNamespace + namespace: newNamespace # required + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" -To add a namespace ` + "`" + `staging` + "`" + ` to all resources, we use the -following ` + "`" + `functionConfig` + "`" + `: +### Three updating modes + +This function supports three modes to flexibly choose and update the target namespaces. + +# Restrict Mode: +All target KRM resources namespace has to have the same value. All namespace will be updated to the new value. + +ConfigMap as functionConfig apiVersion: v1 kind: ConfigMap - metadata: - name: my-config data: - namespace: staging + namespace: newNamespace # update all namespace fields to "newNamespace" + +# DefaultNamespace Mode: + +The input ` + "`" + `resourcelist.items` + "`" + ` contains one and only one namespace object. The function matches the namespace ` + "`" + `metadata.name` + "`" + ` +with all other KRM resources, and only update the namespace if it matches the namespace object. +If more than one namespace objects are found, raise errors; + + kind: ResourceList + functionConfig: + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNs + items: + - apiVersion: v1 + kind: Namespace + metadata: + name: example # updated to "newNs" + - apiVersion: v1 + kind: Service + metadata: + name: the-service1 + namespace: example # updated to "newNs" + - apiVersion: v1 + kind: Service + metadata: + name: the-service2 + namespace: irrelevant # skip since namespace does not match "example". + +# Selector Mode: + +Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig + +ConfigMap as functionConfig + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNamespace + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" + +SetNamespace as functionConfig + apiVersion: fn.kpt.dev/v1alpha1 + kind: SetNamespace + namespace: newNamespace + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" + +### DependsOn annotation + +DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the +namespace segment in a depends-on annotation if matches oldNs ` diff --git a/functions/go/set-namespace/go.mod b/functions/go/set-namespace/go.mod index 63baef15e..9c21e60a8 100644 --- a/functions/go/set-namespace/go.mod +++ b/functions/go/set-namespace/go.mod @@ -2,17 +2,22 @@ module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-na go 1.17 -require github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd +require ( + github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014 + k8s.io/apimachinery v0.23.5 +) require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect github.com/go-openapi/swag v0.21.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.6.7 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -20,10 +25,12 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.7.1 // indirect github.com/xlab/treeprint v1.1.0 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b // indirect golang.org/x/text v0.3.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.3 // indirect + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect ) diff --git a/functions/go/set-namespace/go.sum b/functions/go/set-namespace/go.sum index c1072cdd7..3ec64c97f 100644 --- a/functions/go/set-namespace/go.sum +++ b/functions/go/set-namespace/go.sum @@ -39,9 +39,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd h1:PzlNXoJTvlzct3n2hw3gmM6C9S/W4wmeaA3qqkM4TTQ= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014 h1:NAhq6yh7qg7FE6ijZH3yTXDPHwyvg/5n7gg19w9fhFo= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -53,7 +54,9 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -61,6 +64,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -77,9 +81,11 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= @@ -92,8 +98,9 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -134,9 +141,13 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.7 h1:+Y1YRZcjCfWkTYgH4Xq2+SL4DmkE2s84REwd3O2gnlU= +github.com/google/gnostic v0.6.7/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -147,9 +158,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -279,6 +289,7 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -300,6 +311,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= @@ -318,6 +332,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -404,9 +419,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -552,6 +568,7 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -624,6 +641,7 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -644,6 +662,7 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -657,6 +676,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -689,17 +710,20 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E= k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI= -k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 h1:nqYOUleKLC/0P1zbU29F5q6aoezM6MOAVz+iyfQbZ5M= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -708,8 +732,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/kustomize/kyaml v0.13.3 h1:tNNQIC+8cc+aXFTVg+RtQAOsjwUdYBZRAgYOVI3RBc4= sigs.k8s.io/kustomize/kyaml v0.13.3/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc= +sigs.k8s.io/kustomize/kyaml v0.13.6 h1:eF+wsn4J7GOAXlvajv6OknSunxpcOBQQqsnPxObtkGs= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= diff --git a/functions/go/set-namespace/transformer/consts.go b/functions/go/set-namespace/transformer/consts.go new file mode 100644 index 000000000..55404a542 --- /dev/null +++ b/functions/go/set-namespace/transformer/consts.go @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package transformer + +import ( + "fmt" + "regexp" +) + +const ( + fnConfigAPIVersion = "fn.kpt.dev/v1alpha1" + fnConfigKind = "SetNamespace" + dependsOnAnnotation = "config.kubernetes.io/depends-on" + groupIdx = 0 + namespaceIdx = 2 + kindIdx = 3 + nameIdx = 4 +) + +var ( + // /namespaces/// + namespacedResourcePattern = regexp.MustCompile(`\A([-.\w]*)/namespaces/([-.\w]*)/([-.\w]*)/([-.\w]*)\z`) + dependsOnKeyPattern = func(group, kind, name string) string { + return fmt.Sprintf("%s/%s/%s", group, kind, name) + } +) diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 25e90b325..afd2fe8c2 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -15,45 +15,20 @@ package transformer import ( "fmt" - "regexp" + "reflect" "strings" "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" + "k8s.io/apimachinery/pkg/util/sets" ) -const ( - fnConfigAPIVersion = "fn.kpt.dev/v1alpha1" - fnConfigKind = "SetNamespace" - dependsOnAnnotation = "config.kubernetes.io/depends-on" - groupIdx = 0 - namespaceIdx = 2 - kindIdx = 3 - nameIdx = 4 -) - -var ( - // /namespaces/// - namespacedResourcePattern = regexp.MustCompile(`\A([-.\w]*)/namespaces/([-.\w]*)/([-.\w]*)/([-.\w]*)\z`) - dependsOnKeyPattern = func(group, kind, name string) string { - return fmt.Sprintf("%s/%s/%s", group, kind, name) - } -) - -type Subject struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - ApiGroup string `json:"apiGroup,omitempty" yaml:"apiGroup,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` -} - - -func SetNamespace(rl *fn.ResourceList) error { +func SetNamespace(rl *fn.ResourceList) (bool, error) { tc := NamespaceTransformer{} // Get "namespace" arguments from FunctionConfig err := tc.Config(rl.FunctionConfig) if err != nil { rl.Results = append(rl.Results, fn.ErrorConfigObjectResult(err, rl.FunctionConfig)) - return nil + return true, nil } // Update "namespace" to the proper resources. tc.Transform(rl.Items) @@ -65,32 +40,31 @@ func SetNamespace(rl *fn.ResourceList) error { result = fn.GeneralResult("namespace updated", fn.Info) } rl.Results = append(rl.Results, result) - return nil -} - -type NamespaceTransformer struct { - Namespace string - DependsOnMap map[string]bool - Errors []string + return true, nil } +// Config gets the attributes from different FunctionConfig formats. func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { switch { case o.IsGVK("v1", "ConfigMap"): - p.Namespace = o.GetStringOrDie("data", "namespace") - if p.Namespace == "" { - return fmt.Errorf("`data.namespace` should not be empty") + p.NewNamespace = o.GetStringOrDie("data", "namespace") + if p.NewNamespace == "" { + if o.GetName() == "kptfile.kpt.dev" { + p.NewNamespace = o.GetStringOrDie("data", "name") + if p.NewNamespace == "" { + return fmt.Errorf("`data.name` should not be empty") + } + } else { + return fmt.Errorf("`data.namespace` should not be empty") + } } + p.NamespaceMatcher = o.GetStringOrDie("data", "namespaceMatcher") case o.IsGVK(fnConfigAPIVersion, fnConfigKind): - p.Namespace = o.GetStringOrDie("namespace") - if p.Namespace == "" { + p.NewNamespace = o.GetStringOrDie("namespace") + if p.NewNamespace == "" { return fmt.Errorf("`namespace` should not be empty") } - case o.IsGVK("v1", "ConfigMap") && o.GetName() == "kptfile.kpt.dev": - p.Namespace = o.GetStringOrDie("data", "name") - if p.Namespace == "" { - return fmt.Errorf("`data.name` should not be empty") - } + p.NamespaceMatcher = o.GetStringOrDie("data", "namespaceMatcher") default: return fmt.Errorf("unknown functionConfig Kind=%v ApiVersion=%v, expect `%v` or `ConfigMap`", o.GetKind(), o.GetAPIVersion(), fnConfigKind) @@ -98,70 +72,197 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { return nil } +// Transform replace the existing Namespace object, namespace-scoped resources' `metadata.name` and +// other namespace reference fields to the new value. func (p *NamespaceTransformer) Transform(objects []*fn.KubeObject) { - p.SetDependsOnMap(objects) + namespaces, nsObjCounter := FindAllNamespaces(objects) + if oldNs, ok := p.GetOldNamespace(namespaces, nsObjCounter); ok { + ReplaceNamespace(objects, oldNs, p.NewNamespace) + // Update the resources annotation "config.kubernetes.io/depends-on" which may contain old namespace value. + dependsOnMap := GetDependsOnMap(objects) + UpdateAnnotation(objects, oldNs, p.NewNamespace, dependsOnMap) + } +} + +// VisitNamespaces iterates the `objects` to execute the `visitor` function on each corresponding namespace field. +func VisitNamespaces(objects []*fn.KubeObject, visitor func(namespace *Namespace)) { for _, o := range objects { switch { + // Skip local resource which `kpt live apply` skips. + case o.IsLocalConfig(): + continue case o.IsGVK("v1", "Namespace"): - o.SetName(p.Namespace) + namespace := o.GetStringOrDie("metadata", "name") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "metadata", "name") case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): - err := o.Set(p.Namespace, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") - if err != nil { - p.Errors = append(p.Errors, err.Error()) - } + namespace := o.GetStringOrDie("spec", "conversion", "webhook", "clientConfig", "service", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): - err := o.Set(p.Namespace, "spec", "service", "namespace") - if err != nil { - p.Errors = append(p.Errors, err.Error()) - } - case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": - var subjects []*Subject - o.GetOrDie(&subjects, "subjects") + namespace := o.GetStringOrDie("spec", "service", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "spec", "service", "namespace") + case o.GetKind() == "ClusterRoleBinding": + subjects := o.GetSlice("subjects") for _, s := range subjects { - if s.Name == "default" { - s.Namespace = p.Namespace + var ns string + found, _ := s.Get(&ns, "namespace") + if found { + visitor(NewNamespace(o, &ns)) + _ = s.Set(&ns, "namespace") } } o.SetOrDie(&subjects, "subjects") case o.HasNamespace(): // Only update the namespace scoped resource. To determine if a resource is namespace scoped, // we assume its namespace should have been set. - o.SetNamespace(p.Namespace) + namespace := o.GetStringOrDie("metadata", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "metadata", "namespace") default: // skip the cluster scoped resource. We determine if a resource is cluster scoped by // checking if the metadata.namespace is configured. } - // Shall we accept custom fieldspec? - // p.SetCustomFieldSpec(o) - p.UpdateAnnotation(o) } } -func (p *NamespaceTransformer) SetDependsOnMap(objects []*fn.KubeObject) { - p.DependsOnMap = map[string]bool{} - for _, o := range objects { - group := o.GetAPIVersion() - if i := strings.Index(o.GetAPIVersion(), "/"); i > -1 { - group = group[:i] +// FindAllNamespaces iterates the `objects` to list all namespaces and count the number of Namespace objects. +func FindAllNamespaces(objects []*fn.KubeObject) ([]string, map[string]int) { + nsObjCounter := map[string]int{} + namespaces := sets.NewString() + VisitNamespaces(objects, func(ns *Namespace) { + if *ns.Ptr == "" { + return + } + if ns.IsNamespace { + nsObjCounter[*ns.Ptr] += 1 + } + namespaces.Insert(*ns.Ptr) + }) + return namespaces.List(), nsObjCounter +} + +// ReplaceNamespace iterates the `objects` to replace the `OldNs` with `newNs` on namespace field. +func ReplaceNamespace(objects []*fn.KubeObject, oldNs, newNs string) { + VisitNamespaces(objects, func(ns *Namespace) { + if *ns.Ptr == "" { + return } - key := dependsOnKeyPattern(group, o.GetKind(), o.GetName()) - p.DependsOnMap[key] = true + if *ns.Ptr == oldNs { + *ns.Ptr = newNs + } + }) +} + +// GetDependsOnMap iterates `objects` to get the annotation which contains namespace value. +func GetDependsOnMap(objects []*fn.KubeObject) map[string]bool { + dependsOnMap := map[string]bool{} + VisitNamespaces(objects, func(ns *Namespace) { + key := ns.GetDependsOnAnnotation() + dependsOnMap[key] = true + }) + return dependsOnMap +} + +// UpdateAnnotation updates the `objects`'s "config.kubernetes.io/depends-on" annotation which contains namespace value. +func UpdateAnnotation(objects []*fn.KubeObject, oldNs, newNs string, dependsOnMap map[string]bool) { + VisitNamespaces(objects, func(ns *Namespace) { + if ns.DependsOnAnnotation == "" || !namespacedResourcePattern.MatchString(ns.DependsOnAnnotation) { + return + } + segments := strings.Split(ns.DependsOnAnnotation, "/") + dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) + if ok := dependsOnMap[dependsOnkey]; ok { + if segments[namespaceIdx] == oldNs { + segments[namespaceIdx] = newNs + newAnnotation := strings.Join(segments, "/") + ns.SetDependsOnAnnotation(newAnnotation) + } + } + }) +} + +// GetOldNamespace finds the existing namespace and make sure the input resourceList.items satisfy the requirements. +// - no more than one Namespace Object can exist in the input resource.items +// - If Namespace object exists, its name is the `oldNs` +// - If `namespaceMatcher` is given, its value is the `oldNs` +// - If neither Namespace object nor `namespaceMatcher` found, all resources should have the same namespace value and +// this value is teh `oldNs` +func (p *NamespaceTransformer) GetOldNamespace(fromResources []string, nsCount map[string]int) (string, bool) { + if p.NamespaceMatcher != "" { + if len(nsCount) == 0 { + return p.NamespaceMatcher, true + } + p.Errors = append(p.Errors, + "found Namespace objects from the input resources, "+ + "you cannot use `namespaceMatcher` in FunctionConfig together with Namespace objects") + return "", false + } + if len(nsCount) > 1 { + msg := fmt.Sprintf("cannot accept more than one Namespace objects from the input resources, found %v", + nsCount) + p.Errors = append(p.Errors, msg) + return "", false + } + if len(nsCount) == 1 { + // Use the namespace object as the matching namespace if `namespaceMatcher` is not given. + oldNs := reflect.ValueOf(nsCount).MapKeys()[0].String() + if nsCount[oldNs] > 1 { + msg := fmt.Sprintf("found more than one Namespace objects of the same name %v", oldNs) + p.Errors = append(p.Errors, msg) + return "", false + } + return oldNs, true + } + if len(fromResources) > 1 { + msg := fmt.Sprintf("all input namespace-scoped resources should be under the same namespace "+ + "but found different namespaces: %v ", strings.Join(fromResources, ",")) + p.Errors = append(p.Errors, msg) + return "", false } + return fromResources[0], true } -func (p *NamespaceTransformer) UpdateAnnotation(o *fn.KubeObject) { - anno, ok := o.GetAnnotations()[dependsOnAnnotation] - if !ok { - return +type NamespaceTransformer struct { + NewNamespace string + NamespaceMatcher string + DependsOnMap map[string]bool + Errors []string +} + +func NewNamespace(obj *fn.KubeObject, namespacePtr *string) *Namespace { + annotationSetter := func(newAnnotation string) { + obj.SetAnnotation(dependsOnAnnotation, newAnnotation) } - if !namespacedResourcePattern.MatchString(anno) { - return + annotationGetter := func() string { + group := obj.GetAPIVersion() + if i := strings.Index(obj.GetAPIVersion(), "/"); i > -1 { + group = group[:i] + } + return dependsOnKeyPattern(group, obj.GetKind(), obj.GetName()) } - segments := strings.Split(anno, "/") - dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) - if ok := p.DependsOnMap[dependsOnkey]; ok { - segments[namespaceIdx] = p.Namespace - newAnno := strings.Join(segments, "/") - o.SetAnnotation(dependsOnAnnotation, newAnno) + return &Namespace{ + Ptr: namespacePtr, // obj.GetStringOrDie(path...), + IsNamespace: obj.IsGVK("v1", "Namespace"), + DependsOnAnnotation: obj.GetAnnotations()[dependsOnAnnotation], + annotationGetter: annotationGetter, + annotationSetter: annotationSetter, } } + +type Namespace struct { + Ptr *string + IsNamespace bool + DependsOnAnnotation string + annotationGetter func() string + annotationSetter func(newDependsOnAnnotation string) +} + +func (n *Namespace) SetDependsOnAnnotation(newDependsOn string) { + n.annotationSetter(newDependsOn) +} + +func (n *Namespace) GetDependsOnAnnotation() string { + return n.annotationGetter() +}