From f8f9f4e62851060a0ff4eca24d30e8d5806ff61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= Date: Sun, 3 Sep 2023 23:21:40 +0200 Subject: [PATCH] refactor: CLI oci commands (#8224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Charles-Edouard Brétéché --- .../oci/{oci.go => command.go} | 30 ++-------- .../oci/internal/annotations.go | 29 +++++++++ .../oci/internal/annotations_test.go | 60 +++++++++++++++++++ .../oci/{oci_pull.go => pull/command.go} | 13 ++-- .../oci/{oci_push.go => push/command.go} | 17 +++--- docs/user/cli/kyverno_oci.md | 3 +- docs/user/cli/kyverno_oci_pull.md | 2 +- docs/user/cli/kyverno_oci_push.md | 2 +- 8 files changed, 114 insertions(+), 42 deletions(-) rename cmd/cli/kubectl-kyverno/oci/{oci.go => command.go} (54%) create mode 100644 cmd/cli/kubectl-kyverno/oci/internal/annotations.go create mode 100644 cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go rename cmd/cli/kubectl-kyverno/oci/{oci_pull.go => pull/command.go} (89%) rename cmd/cli/kubectl-kyverno/oci/{oci_push.go => push/command.go} (85%) diff --git a/cmd/cli/kubectl-kyverno/oci/oci.go b/cmd/cli/kubectl-kyverno/oci/command.go similarity index 54% rename from cmd/cli/kubectl-kyverno/oci/oci.go rename to cmd/cli/kubectl-kyverno/oci/command.go index 22b366abc8..b0f08eadb4 100644 --- a/cmd/cli/kubectl-kyverno/oci/oci.go +++ b/cmd/cli/kubectl-kyverno/oci/command.go @@ -8,18 +8,11 @@ import ( "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn/github" "github.com/google/go-containerregistry/pkg/v1/google" - kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/oci/pull" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/oci/push" "github.com/spf13/cobra" ) -const ( - policyConfigMediaType = "application/vnd.cncf.kyverno.config.v1+json" - policyLayerMediaType = "application/vnd.cncf.kyverno.policy.layer.v1+yaml" - annotationKind = "io.kyverno.image.kind" - annotationName = "io.kyverno.image.name" - annotationApiVersion = "io.kyverno.image.apiVersion" -) - var ( amazonKeychain = authn.NewKeychainFromHelper(ecr.NewECRHelper(ecr.WithLogger(io.Discard))) azureKeychain = authn.NewKeychainFromHelper(credhelper.NewACRCredentialsHelper()) @@ -30,22 +23,8 @@ var ( amazonKeychain, azureKeychain, ) - imageRef string ) -func annotations(policy kyvernov1.PolicyInterface) map[string]string { - kind := "ClusterPolicy" - if policy.IsNamespaced() { - kind = "Policy" - } - return map[string]string{ - annotationKind: kind, - annotationName: policy.GetName(), - // TODO: we need a way to get apiVersion - annotationApiVersion: "kyverno.io/v1", - } -} - func Command() *cobra.Command { cmd := &cobra.Command{ Use: "oci", @@ -56,8 +35,7 @@ func Command() *cobra.Command { return cmd.Help() }, } - cmd.PersistentFlags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from") - cmd.AddCommand(ociPullCommand()) - cmd.AddCommand(ociPushCommand()) + cmd.AddCommand(pull.Command(keychain)) + cmd.AddCommand(push.Command(keychain)) return cmd } diff --git a/cmd/cli/kubectl-kyverno/oci/internal/annotations.go b/cmd/cli/kubectl-kyverno/oci/internal/annotations.go new file mode 100644 index 0000000000..d22a6f3f55 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/oci/internal/annotations.go @@ -0,0 +1,29 @@ +package internal + +import ( + kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" +) + +const ( + PolicyConfigMediaType = "application/vnd.cncf.kyverno.config.v1+json" + PolicyLayerMediaType = "application/vnd.cncf.kyverno.policy.layer.v1+yaml" + AnnotationKind = "io.kyverno.image.kind" + AnnotationName = "io.kyverno.image.name" + AnnotationApiVersion = "io.kyverno.image.apiVersion" +) + +func Annotations(policy kyvernov1.PolicyInterface) map[string]string { + if policy == nil { + return nil + } + kind := "ClusterPolicy" + if policy.IsNamespaced() { + kind = "Policy" + } + return map[string]string{ + AnnotationKind: kind, + AnnotationName: policy.GetName(), + // TODO: we need a way to get apiVersion + AnnotationApiVersion: "kyverno.io/v1", + } +} diff --git a/cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go b/cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go new file mode 100644 index 0000000000..4ee3ab4425 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go @@ -0,0 +1,60 @@ +package internal + +import ( + "reflect" + "testing" + + kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestAnnotations(t *testing.T) { + tests := []struct { + name string + policy kyvernov1.PolicyInterface + want map[string]string + }{{ + name: "nil", + policy: nil, + want: nil, + }, { + name: "cluster policy", + policy: &kyvernov1.ClusterPolicy{ + TypeMeta: metav1.TypeMeta{ + Kind: "kyverno.io/v1", + APIVersion: "ClusterPolicy", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + want: map[string]string{ + AnnotationKind: "ClusterPolicy", + AnnotationName: "test", + AnnotationApiVersion: "kyverno.io/v1", + }, + }, { + name: "policy", + policy: &kyvernov1.Policy{ + TypeMeta: metav1.TypeMeta{ + Kind: "kyverno.io/v1", + APIVersion: "Policy", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + want: map[string]string{ + AnnotationKind: "Policy", + AnnotationName: "test", + AnnotationApiVersion: "kyverno.io/v1", + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Annotations(tt.policy); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Annotations() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/cli/kubectl-kyverno/oci/oci_pull.go b/cmd/cli/kubectl-kyverno/oci/pull/command.go similarity index 89% rename from cmd/cli/kubectl-kyverno/oci/oci_pull.go rename to cmd/cli/kubectl-kyverno/oci/pull/command.go index add1efd331..60f983eb58 100644 --- a/cmd/cli/kubectl-kyverno/oci/oci_pull.go +++ b/cmd/cli/kubectl-kyverno/oci/pull/command.go @@ -1,4 +1,4 @@ -package oci +package pull import ( "errors" @@ -8,16 +8,18 @@ import ( "path/filepath" securejoin "github.com/cyphar/filepath-securejoin" + "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/oci/internal" policyutils "github.com/kyverno/kyverno/pkg/utils/policy" yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml" "github.com/spf13/cobra" ) -var dir string - -func ociPullCommand() *cobra.Command { +func Command(keychain authn.Keychain) *cobra.Command { + var dir string + var imageRef string cmd := &cobra.Command{ Use: "pull", Long: "This command is one of the supported experimental commands, and its behaviour might be changed any time", @@ -81,7 +83,7 @@ kyverno oci pull -i -d policies`, return fmt.Errorf("getting layer media type: %v", err) } - if lmt == policyLayerMediaType { + if lmt == internal.PolicyLayerMediaType { blob, err := layer.Compressed() if err != nil { return fmt.Errorf("getting layer blob: %v", err) @@ -114,5 +116,6 @@ kyverno oci pull -i -d policies`, }, } cmd.Flags().StringVarP(&dir, "directory", "d", ".", "path to a directory") + cmd.Flags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from") return cmd } diff --git a/cmd/cli/kubectl-kyverno/oci/oci_push.go b/cmd/cli/kubectl-kyverno/oci/push/command.go similarity index 85% rename from cmd/cli/kubectl-kyverno/oci/oci_push.go rename to cmd/cli/kubectl-kyverno/oci/push/command.go index 4dc37557ad..eabd0b33a9 100644 --- a/cmd/cli/kubectl-kyverno/oci/oci_push.go +++ b/cmd/cli/kubectl-kyverno/oci/push/command.go @@ -1,16 +1,18 @@ -package oci +package push import ( "errors" "fmt" "os" + "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/static" "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/oci/internal" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common" "github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/openapi" @@ -21,9 +23,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" ) -var policyRef string - -func ociPushCommand() *cobra.Command { +func Command(keychain authn.Keychain) *cobra.Command { + var policyRef string + var imageRef string cmd := &cobra.Command{ Use: "push", Long: "This command is one of the supported experimental commands in Kyverno CLI, and its behaviour might be changed any time.", @@ -54,7 +56,7 @@ kyverno oci push -p policies. -i `, } img := mutate.MediaType(empty.Image, types.OCIManifestSchema1) - img = mutate.ConfigMediaType(img, policyConfigMediaType) + img = mutate.ConfigMediaType(img, internal.PolicyConfigMediaType) ref, err := name.ParseReference(imageRef) if err != nil { return fmt.Errorf("parsing image reference: %v", err) @@ -70,10 +72,10 @@ kyverno oci push -p policies. -i `, if err != nil { return fmt.Errorf("converting policy to yaml: %v", err) } - policyLayer := static.NewLayer(policyBytes, policyLayerMediaType) + policyLayer := static.NewLayer(policyBytes, internal.PolicyLayerMediaType) img, err = mutate.Append(img, mutate.Addendum{ Layer: policyLayer, - Annotations: annotations(policy), + Annotations: internal.Annotations(policy), }) if err != nil { return fmt.Errorf("mutating image: %v", err) @@ -88,5 +90,6 @@ kyverno oci push -p policies. -i `, }, } cmd.Flags().StringVarP(&policyRef, "policy", "p", "", "path to policie(s)") + cmd.Flags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from") return cmd } diff --git a/docs/user/cli/kyverno_oci.md b/docs/user/cli/kyverno_oci.md index 3c223283cb..39a6613342 100644 --- a/docs/user/cli/kyverno_oci.md +++ b/docs/user/cli/kyverno_oci.md @@ -13,8 +13,7 @@ kyverno oci [flags] ### Options ``` - -h, --help help for oci - -i, --image string image reference to push to or pull from + -h, --help help for oci ``` ### Options inherited from parent commands diff --git a/docs/user/cli/kyverno_oci_pull.md b/docs/user/cli/kyverno_oci_pull.md index efbd4f70b1..84a1fc64fb 100644 --- a/docs/user/cli/kyverno_oci_pull.md +++ b/docs/user/cli/kyverno_oci_pull.md @@ -22,6 +22,7 @@ kyverno oci pull -i -d policies ``` -d, --directory string path to a directory (default ".") -h, --help help for pull + -i, --image string image reference to push to or pull from ``` ### Options inherited from parent commands @@ -29,7 +30,6 @@ kyverno oci pull -i -d policies ``` --add_dir_header If true, adds the file directory to the header of the log messages --alsologtostderr log to standard error as well as files (no effect when -logtostderr=true) - -i, --image string image reference to push to or pull from --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true) --log_file string If non-empty, use this log file (no effect when -logtostderr=true) diff --git a/docs/user/cli/kyverno_oci_push.md b/docs/user/cli/kyverno_oci_push.md index 93bb8438f9..639e01e31e 100644 --- a/docs/user/cli/kyverno_oci_push.md +++ b/docs/user/cli/kyverno_oci_push.md @@ -24,6 +24,7 @@ kyverno oci push -p policies. -i ``` -h, --help help for push + -i, --image string image reference to push to or pull from -p, --policy string path to policie(s) ``` @@ -32,7 +33,6 @@ kyverno oci push -p policies. -i ``` --add_dir_header If true, adds the file directory to the header of the log messages --alsologtostderr log to standard error as well as files (no effect when -logtostderr=true) - -i, --image string image reference to push to or pull from --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) --log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true) --log_file string If non-empty, use this log file (no effect when -logtostderr=true)