mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-15 12:17:56 +00:00
fix: Provide kind list hints to the fake dynamic client. (#9036)
* fix: Provide kind list hints to the fake dynamic client. If one uses the `cloneList` option of `generate` without this, a panic occurs. Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * Added test for `cloneList`. Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * fix: ttl cleanup not working with cluster wide resources (#9060) Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * Fix Helm chart to not error when replicas defined (#9066) Fixes #8941 Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * fix: add nodeSelector to the reports cleanup helm hook (#9065) Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * optimize JSON context processing using in-memory maps (#8322) * optimize JSON context processing using in memory maps Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix excessive logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate resource diff Signed-off-by: Jim Bugwadia <jim@nirmata.com> * uncomment tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * copy resource, as it can be modified Signed-off-by: Jim Bugwadia <jim@nirmata.com> * clear prior resource to prevent mutating original Signed-off-by: Jim Bugwadia <jim@nirmata.com> * linter fix Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix ImageInfo to unstructured conversion Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix custom image extractors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not update mutated resource in JSON context Signed-off-by: Jim Bugwadia <jim@nirmata.com> * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> --------- Signed-off-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: shuting <shuting@nirmata.com> Co-authored-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> Co-authored-by: shuting <shuting@nirmata.com> Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * Ran `gci` to silence a lint warning. Signed-off-by: Anton Chernev <anton.chernev@gmail.com> * Added a log message when an invalid or incomplete `cloneList` kind is supplied. Signed-off-by: Anton Chernev <anton.chernev@gmail.com> --------- Signed-off-by: Anton Chernev <anton.chernev@gmail.com> Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: shuting <shuting@nirmata.com> Co-authored-by: Anton Chernev <a-anchernov@expediagroup.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Co-authored-by: treydock <tdockendorf@osc.edu> Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Vishal Choudhary <sendtovishalchoudhary@gmail.com> Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
parent
f2561d0095
commit
4d2f7fa8d3
7 changed files with 143 additions and 14 deletions
|
@ -88,22 +88,31 @@ func runTest(out io.Writer, testCase test.TestCase, auditWarn bool) ([]engineapi
|
||||||
}
|
}
|
||||||
if rule.Name == res.Rule {
|
if rule.Name == res.Rule {
|
||||||
if rule.HasGenerate() {
|
if rule.HasGenerate() {
|
||||||
ruleUnstr, err := generate.GetUnstrRule(rule.Generation.DeepCopy())
|
if len(rule.Generation.CloneList.Kinds) != 0 { // cloneList
|
||||||
if err != nil {
|
// We cannot cast this to an unstructured object because it doesn't have a kind.
|
||||||
fmt.Fprintf(out, " Error: failed to get unstructured rule (%s)\n", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
genClone, _, err := unstructured.NestedMap(ruleUnstr.Object, "clone")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(out, " Error: failed to read data (%s)\n", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(genClone) != 0 {
|
|
||||||
if isGit {
|
if isGit {
|
||||||
ruleToCloneSourceResource[rule.Name] = res.CloneSourceResource
|
ruleToCloneSourceResource[rule.Name] = res.CloneSourceResource
|
||||||
} else {
|
} else {
|
||||||
ruleToCloneSourceResource[rule.Name] = path.GetFullPath(res.CloneSourceResource, testDir)
|
ruleToCloneSourceResource[rule.Name] = path.GetFullPath(res.CloneSourceResource, testDir)
|
||||||
}
|
}
|
||||||
|
} else { // clone or data
|
||||||
|
ruleUnstr, err := generate.GetUnstrRule(rule.Generation.DeepCopy())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(out, " Error: failed to get unstructured rule (%s)\n", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
genClone, _, err := unstructured.NestedMap(ruleUnstr.Object, "clone")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(out, " Error: failed to read data (%s)\n", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(genClone) != 0 {
|
||||||
|
if isGit {
|
||||||
|
ruleToCloneSourceResource[rule.Name] = res.CloneSourceResource
|
||||||
|
} else {
|
||||||
|
ruleToCloneSourceResource[rule.Name] = path.GetFullPath(res.CloneSourceResource, testDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/store"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/store"
|
||||||
|
"github.com/kyverno/kyverno/pkg/autogen"
|
||||||
"github.com/kyverno/kyverno/pkg/background/generate"
|
"github.com/kyverno/kyverno/pkg/background/generate"
|
||||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||||
"github.com/kyverno/kyverno/pkg/config"
|
"github.com/kyverno/kyverno/pkg/config"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||||
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
||||||
"github.com/kyverno/kyverno/pkg/imageverifycache"
|
"github.com/kyverno/kyverno/pkg/imageverifycache"
|
||||||
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
@ -43,7 +45,36 @@ func handleGeneratePolicy(out io.Writer, generateResponse *engineapi.EngineRespo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := initializeMockController(out, objects)
|
listKinds := map[schema.GroupVersionResource]string{}
|
||||||
|
|
||||||
|
// Collect items in a potential cloneList to provide list kinds to the fake dynamic client.
|
||||||
|
for _, rule := range autogen.ComputeRules(policyContext.Policy()) {
|
||||||
|
if !rule.HasGenerate() || len(rule.Generation.CloneList.Kinds) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, kind := range rule.Generation.CloneList.Kinds {
|
||||||
|
apiVersion, kind := kubeutils.GetKindFromGVK(kind)
|
||||||
|
|
||||||
|
if apiVersion == "" || kind == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
gv, err := schema.ParseGroupVersion(apiVersion)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(out, "failed to parse group and version from clone list kind %s: %v\n", apiVersion, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
listKinds[schema.GroupVersionResource{
|
||||||
|
Group: gv.Group,
|
||||||
|
Version: gv.Version,
|
||||||
|
Resource: strings.ToLower(kind) + "s",
|
||||||
|
}] = kind + "List"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := initializeMockController(out, listKinds, objects)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(out, "error at controller")
|
fmt.Fprintln(out, "error at controller")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -82,8 +113,8 @@ func handleGeneratePolicy(out io.Writer, generateResponse *engineapi.EngineRespo
|
||||||
return newRuleResponse, nil
|
return newRuleResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initializeMockController(out io.Writer, objects []runtime.Object) (*generate.GenerateController, error) {
|
func initializeMockController(out io.Writer, gvrToListKind map[schema.GroupVersionResource]string, objects []runtime.Object) (*generate.GenerateController, error) {
|
||||||
client, err := dclient.NewFakeClient(runtime.NewScheme(), nil, objects...)
|
client, err := dclient.NewFakeClient(runtime.NewScheme(), gvrToListKind, objects...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(out, "Failed to mock dynamic client")
|
fmt.Fprintf(out, "Failed to mock dynamic client")
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
20
test/cli/test-generate/clone-list/cloneSourceResources.yaml
Normal file
20
test/cli/test-generate/clone-list/cloneSourceResources.yaml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: regcred
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
allowedToBeCloned: "true"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
password: MWYyZDFlMmU2N2Rm
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: missing-label
|
||||||
|
namespace: default
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
password: MWYyZDFlMmU2N2Rm
|
10
test/cli/test-generate/clone-list/generatedResource.yaml
Normal file
10
test/cli/test-generate/clone-list/generatedResource.yaml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: regcred
|
||||||
|
namespace: hello-world-namespace
|
||||||
|
labels:
|
||||||
|
allowedToBeCloned: "true"
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
password: MWYyZDFlMmU2N2Rm
|
17
test/cli/test-generate/clone-list/kyverno-test.yaml
Normal file
17
test/cli/test-generate/clone-list/kyverno-test.yaml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
apiVersion: cli.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
name: kyverno-test.yaml
|
||||||
|
policies:
|
||||||
|
- policy.yaml
|
||||||
|
resources:
|
||||||
|
- resource.yaml
|
||||||
|
results:
|
||||||
|
- policy: clone-list-secrets
|
||||||
|
rule: clone-list-labelled-secrets
|
||||||
|
resources:
|
||||||
|
- hello-world-namespace
|
||||||
|
cloneSourceResource: cloneSourceResources.yaml
|
||||||
|
generatedResource: generatedResource.yaml
|
||||||
|
kind: Namespace
|
||||||
|
result: pass
|
37
test/cli/test-generate/clone-list/policy.yaml
Normal file
37
test/cli/test-generate/clone-list/policy.yaml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
policies.kyverno.io/category: Sample
|
||||||
|
policies.kyverno.io/description: 'Secrets like registry credentials often need
|
||||||
|
to exist in multiple Namespaces so Pods there have access. Manually duplicating
|
||||||
|
those Secrets is time consuming and error prone. This policy will copy all Secrets
|
||||||
|
with the appropriate label which exists in the `default` Namespace to new Namespaces
|
||||||
|
when they are created. It will also push updates to the copied Secrets should the
|
||||||
|
source Secret be changed.'
|
||||||
|
policies.kyverno.io/subject: Secret
|
||||||
|
policies.kyverno.io/title: Clone List Secrets
|
||||||
|
name: clone-list-secrets
|
||||||
|
spec:
|
||||||
|
admission: true
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- generate:
|
||||||
|
cloneList:
|
||||||
|
namespace: default
|
||||||
|
kinds:
|
||||||
|
- v1/Secret
|
||||||
|
- v1/ConfigMap
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
allowedToBeCloned: "true"
|
||||||
|
namespace: '{{request.object.metadata.name}}'
|
||||||
|
synchronize: true
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Namespace
|
||||||
|
name: clone-list-labelled-secrets
|
||||||
|
validationFailureAction: Audit
|
5
test/cli/test-generate/clone-list/resource.yaml
Normal file
5
test/cli/test-generate/clone-list/resource.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: hello-world-namespace
|
||||||
|
namespace: hello-world-namespace
|
Loading…
Add table
Reference in a new issue