mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 18:38:40 +00:00
refactor: CLI oci commands (#8224)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
5c482646d1
commit
f8f9f4e628
8 changed files with 114 additions and 42 deletions
|
@ -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
|
||||
}
|
29
cmd/cli/kubectl-kyverno/oci/internal/annotations.go
Normal file
29
cmd/cli/kubectl-kyverno/oci/internal/annotations.go
Normal file
|
@ -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",
|
||||
}
|
||||
}
|
60
cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go
Normal file
60
cmd/cli/kubectl-kyverno/oci/internal/annotations_test.go
Normal file
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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 <imgref> -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 <imgref> -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
|
||||
}
|
|
@ -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 <imgref>`,
|
|||
}
|
||||
|
||||
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 <imgref>`,
|
|||
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 <imgref>`,
|
|||
},
|
||||
}
|
||||
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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -22,6 +22,7 @@ kyverno oci pull -i <imgref> -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 <imgref> -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)
|
||||
|
|
|
@ -24,6 +24,7 @@ kyverno oci push -p policies. -i <imgref>
|
|||
|
||||
```
|
||||
-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 <imgref>
|
|||
```
|
||||
--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)
|
||||
|
|
Loading…
Add table
Reference in a new issue