2023-09-03 23:21:40 +02:00
|
|
|
package pull
|
2022-10-24 21:47:20 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
securejoin "github.com/cyphar/filepath-securejoin"
|
2023-09-03 23:21:40 +02:00
|
|
|
"github.com/google/go-containerregistry/pkg/authn"
|
2022-10-24 21:47:20 +03:00
|
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
|
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
2023-09-04 17:15:55 +02:00
|
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci/internal"
|
2023-09-05 04:14:28 +02:00
|
|
|
cobrautils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/cobra"
|
2022-11-25 13:46:02 +01:00
|
|
|
policyutils "github.com/kyverno/kyverno/pkg/utils/policy"
|
2022-11-24 16:54:56 +01:00
|
|
|
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
|
2022-10-24 21:47:20 +03:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
2023-09-03 23:21:40 +02:00
|
|
|
func Command(keychain authn.Keychain) *cobra.Command {
|
|
|
|
var dir string
|
|
|
|
var imageRef string
|
2022-10-24 21:47:20 +03:00
|
|
|
cmd := &cobra.Command{
|
2023-09-05 04:14:28 +02:00
|
|
|
Use: "pull",
|
|
|
|
Short: cobrautils.FormatDescription(true, websiteUrl, true, description...),
|
|
|
|
Long: cobrautils.FormatDescription(false, websiteUrl, true, description...),
|
|
|
|
Example: cobrautils.FormatExamples(examples...),
|
2022-10-24 21:47:20 +03:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
if imageRef == "" {
|
|
|
|
return errors.New("image reference is required")
|
|
|
|
}
|
|
|
|
|
|
|
|
dir = filepath.Clean(dir)
|
|
|
|
if !filepath.IsAbs(dir) {
|
|
|
|
cwd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
dir, err = securejoin.SecureJoin(cwd, dir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fi, err := os.Lstat(dir)
|
|
|
|
// Dir does not need to exist, as it can later be created.
|
|
|
|
if err != nil && errors.Is(err, os.ErrNotExist) {
|
|
|
|
if err := os.MkdirAll(dir, 0o750); err != nil {
|
|
|
|
return fmt.Errorf("unable to create directory %s: %w", dir, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil && !fi.IsDir() {
|
|
|
|
return fmt.Errorf("dir '%s' must be a directory", dir)
|
|
|
|
}
|
|
|
|
|
|
|
|
ref, err := name.ParseReference(imageRef)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("parsing image reference: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-12-28 12:58:51 +03:00
|
|
|
fmt.Fprintf(os.Stderr, "Downloading policies from an image [%s]...\n", ref.Name())
|
2022-11-24 16:54:56 +01:00
|
|
|
rmt, err := remote.Get(ref, remote.WithContext(cmd.Context()), remote.WithAuthFromKeychain(keychain))
|
2022-10-24 21:47:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("getting image: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
img, err := rmt.Image()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("getting image: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
l, err := img.Layers()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("getting image layers: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, layer := range l {
|
|
|
|
lmt, err := layer.MediaType()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("getting layer media type: %v", err)
|
|
|
|
}
|
|
|
|
|
2023-09-03 23:21:40 +02:00
|
|
|
if lmt == internal.PolicyLayerMediaType {
|
2022-10-24 21:47:20 +03:00
|
|
|
blob, err := layer.Compressed()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("getting layer blob: %v", err)
|
|
|
|
}
|
|
|
|
defer blob.Close()
|
|
|
|
|
2022-11-24 16:54:56 +01:00
|
|
|
layerBytes, err := io.ReadAll(blob)
|
2022-10-24 21:47:20 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("reading layer blob: %v", err)
|
|
|
|
}
|
2023-05-10 11:12:53 +03:00
|
|
|
policies, _, err := yamlutils.GetPolicy(layerBytes)
|
2022-11-24 16:54:56 +01:00
|
|
|
if err != nil {
|
2022-10-24 21:47:20 +03:00
|
|
|
return fmt.Errorf("unmarshaling layer blob: %v", err)
|
|
|
|
}
|
2022-11-24 16:54:56 +01:00
|
|
|
for _, policy := range policies {
|
2022-11-25 13:46:02 +01:00
|
|
|
policyBytes, err := policyutils.ToYaml(policy)
|
2022-11-24 16:54:56 +01:00
|
|
|
if err != nil {
|
2022-11-25 13:46:02 +01:00
|
|
|
return fmt.Errorf("converting policy to yaml: %v", err)
|
2022-11-24 16:54:56 +01:00
|
|
|
}
|
2022-12-28 12:58:51 +03:00
|
|
|
pp := filepath.Join(dir, policy.GetName()+".yaml")
|
|
|
|
fmt.Fprintf(os.Stderr, "Saving policy into disk [%s]...\n", pp)
|
|
|
|
if err := os.WriteFile(pp, policyBytes, 0o600); err != nil {
|
2022-11-24 16:54:56 +01:00
|
|
|
return fmt.Errorf("creating file: %v", err)
|
|
|
|
}
|
2022-10-24 21:47:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-28 12:58:51 +03:00
|
|
|
fmt.Fprintf(os.Stderr, "Done.")
|
2022-10-24 21:47:20 +03:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
cmd.Flags().StringVarP(&dir, "directory", "d", ".", "path to a directory")
|
2023-09-03 23:21:40 +02:00
|
|
|
cmd.Flags().StringVarP(&imageRef, "image", "i", "", "image reference to push to or pull from")
|
2022-10-24 21:47:20 +03:00
|
|
|
return cmd
|
|
|
|
}
|