mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
c9055ac2ff
* fix(autogen): only generate rule for request kind Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * feat(autogen): use jsoniter instead of std for json Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * chore(atogen): use sets instead of manipulating strings Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * fix(autogen): formatting linter Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * fix(autogen): backwards compatability Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * revert(autogen): old behavior Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> * fix: builds error Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: ShutingZhao <shuting@nirmata.com>
140 lines
4.6 KiB
Go
140 lines
4.6 KiB
Go
package processor
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
|
"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/store"
|
|
"github.com/kyverno/kyverno/pkg/autogen"
|
|
"github.com/kyverno/kyverno/pkg/background/generate"
|
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
|
"github.com/kyverno/kyverno/pkg/config"
|
|
"github.com/kyverno/kyverno/pkg/engine"
|
|
"github.com/kyverno/kyverno/pkg/engine/adapters"
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
|
"github.com/kyverno/kyverno/pkg/imageverifycache"
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
)
|
|
|
|
func handleGeneratePolicy(out io.Writer, store *store.Store, generateResponse *engineapi.EngineResponse, policyContext engine.PolicyContext, ruleToCloneSourceResource map[string]string) ([]engineapi.RuleResponse, error) {
|
|
newResource := policyContext.NewResource()
|
|
objects := []runtime.Object{&newResource}
|
|
for _, rule := range generateResponse.PolicyResponse.Rules {
|
|
if path, ok := ruleToCloneSourceResource[rule.Name()]; ok {
|
|
resourceBytes, err := resource.GetFileBytes(path)
|
|
if err != nil {
|
|
fmt.Fprintf(out, "failed to get resource bytes\n")
|
|
} else {
|
|
r, err := resource.GetUnstructuredResources(resourceBytes)
|
|
if err != nil {
|
|
fmt.Fprintf(out, "failed to convert resource bytes to unstructured format\n")
|
|
}
|
|
for _, res := range r {
|
|
objects = append(objects, res)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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, store, listKinds, objects)
|
|
if err != nil {
|
|
fmt.Fprintln(out, "error at controller")
|
|
return nil, err
|
|
}
|
|
|
|
gr := kyvernov1beta1.UpdateRequest{
|
|
Spec: kyvernov1beta1.UpdateRequestSpec{
|
|
Type: kyvernov1beta1.Generate,
|
|
Policy: generateResponse.Policy().GetName(),
|
|
Resource: kyvernov1.ResourceSpec{
|
|
Kind: generateResponse.Resource.GetKind(),
|
|
Namespace: generateResponse.Resource.GetNamespace(),
|
|
Name: generateResponse.Resource.GetName(),
|
|
APIVersion: generateResponse.Resource.GetAPIVersion(),
|
|
},
|
|
},
|
|
}
|
|
|
|
var newRuleResponse []engineapi.RuleResponse
|
|
|
|
for _, rule := range generateResponse.PolicyResponse.Rules {
|
|
genResource, err := c.ApplyGeneratePolicy(log.Log.V(2), &policyContext, gr, []string{rule.Name()})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if genResource != nil {
|
|
unstrGenResource, err := c.GetUnstrResource(genResource[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
newRuleResponse = append(newRuleResponse, *rule.WithGeneratedResource(*unstrGenResource))
|
|
}
|
|
}
|
|
|
|
return newRuleResponse, nil
|
|
}
|
|
|
|
func initializeMockController(out io.Writer, s *store.Store, gvrToListKind map[schema.GroupVersionResource]string, objects []runtime.Object) (*generate.GenerateController, error) {
|
|
client, err := dclient.NewFakeClient(runtime.NewScheme(), gvrToListKind, objects...)
|
|
if err != nil {
|
|
fmt.Fprintf(out, "Failed to mock dynamic client")
|
|
return nil, err
|
|
}
|
|
gvrs := sets.New[schema.GroupVersionResource]()
|
|
for _, object := range objects {
|
|
gvk := object.GetObjectKind().GroupVersionKind()
|
|
gvrs.Insert(gvk.GroupVersion().WithResource(strings.ToLower(gvk.Kind) + "s"))
|
|
}
|
|
client.SetDiscovery(dclient.NewFakeDiscoveryClient(gvrs.UnsortedList()))
|
|
cfg := config.NewDefaultConfiguration(false)
|
|
c := generate.NewGenerateControllerWithOnlyClient(client, engine.NewEngine(
|
|
cfg,
|
|
config.NewDefaultMetricsConfiguration(),
|
|
jmespath.New(cfg),
|
|
adapters.Client(client),
|
|
nil,
|
|
imageverifycache.DisabledImageVerifyCache(),
|
|
store.ContextLoaderFactory(s, nil),
|
|
nil,
|
|
))
|
|
return c, nil
|
|
}
|