mirror of
https://github.com/slimtoolkit/slim.git
synced 2025-06-03 04:00:23 +00:00
basic registry image-index-create command to create multi-architecture images
Signed-off-by: Kyle Quest <kcq.public@gmail.com>
This commit is contained in:
parent
13e1e1a972
commit
7ee7762713
21
.vscode/launch.json
vendored
Normal file
21
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${fileDirname}",
|
||||
"args": ["registry",
|
||||
"image-index-create",
|
||||
"--image-index-name",
|
||||
"dslim/slim-multi-test:latest",
|
||||
"--image-name", "dslim/slim-arm:latest",
|
||||
"--image-name", "dslim/slim:latest" ]
|
||||
}
|
||||
]
|
||||
}
|
@ -152,7 +152,7 @@ func OnCommand(
|
||||
imageBuildArch string,
|
||||
) {
|
||||
printState := true
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -24,7 +24,7 @@ func OnCommand(
|
||||
gparams *commands.GenericParams,
|
||||
targetRef string) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -24,7 +24,7 @@ func OnCommand(
|
||||
gparams *commands.GenericParams,
|
||||
targetRef string) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -25,7 +25,7 @@ func OnCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams,
|
||||
commandParams *CommandParams) {
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -24,7 +24,7 @@ func OnCommand(
|
||||
gparams *commands.GenericParams,
|
||||
targetRef string) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -29,7 +29,7 @@ func OnCommand(
|
||||
isDSImage bool,
|
||||
binDir bool,
|
||||
dockerCLIPlugin bool) {
|
||||
logger := log.WithFields(log.Fields{"app": "slim", "command": "install"})
|
||||
logger := log.WithFields(log.Fields{"app": "slim", "cmd": "install"})
|
||||
|
||||
appPath, err := os.Executable()
|
||||
errutil.FailOn(err)
|
||||
|
@ -38,7 +38,7 @@ func OnCommand(
|
||||
doShowSnippet bool,
|
||||
doListChecks bool) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -35,7 +35,7 @@ func OnCommand(
|
||||
gparams *commands.GenericParams,
|
||||
cparams *CommandParams) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -25,7 +25,7 @@ func OnCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams,
|
||||
targetRef string) {
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
cmdName := fmt.Sprintf("cmd=%s", Name)
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
@ -82,7 +82,7 @@ func OnCommand(
|
||||
logLevel string,
|
||||
logFormat string) {
|
||||
printState := true
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
26
pkg/app/master/commands/registry/auth.go
Normal file
26
pkg/app/master/commands/registry/auth.go
Normal file
@ -0,0 +1,26 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
//log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ConfigureAuth(cparams *CommonCommandParams, remoteOpts []remote.Option) ([]remote.Option, error) {
|
||||
if cparams.UseDockerCreds {
|
||||
remoteOpts = append(remoteOpts, remote.WithAuthFromKeychain(authn.DefaultKeychain))
|
||||
return remoteOpts, nil
|
||||
}
|
||||
|
||||
if cparams.CredsAccount != "" && cparams.CredsSecret != "" {
|
||||
remoteOpts = append(remoteOpts, remote.WithAuth(&authn.Basic{
|
||||
Username: cparams.CredsAccount,
|
||||
Password: cparams.CredsSecret,
|
||||
}))
|
||||
|
||||
return remoteOpts, nil
|
||||
}
|
||||
|
||||
//it's authn.Anonymous by default, but good to be explicit
|
||||
return append(remoteOpts, remote.WithAuth(authn.Anonymous)), nil
|
||||
}
|
@ -16,25 +16,81 @@ const (
|
||||
|
||||
PullCmdName = "pull"
|
||||
PullCmdNameUsage = "Pull a container image from registry"
|
||||
|
||||
PushCmdName = "push"
|
||||
PushCmdNameUsage = "Push a container image to a registry"
|
||||
|
||||
CopyCmdName = "copy"
|
||||
CopyCmdNameUsage = "Copy a container image from one registry to another"
|
||||
|
||||
ImageIndexCreateCmdName = "image-index-create"
|
||||
ImageIndexCreateCmdNameUsage = "Create an image index (aka manifest list) with the referenced images (already in the target registry)"
|
||||
)
|
||||
|
||||
func fullCmdName(subCmdName string) string {
|
||||
return fmt.Sprintf("%s.%s", Name, subCmdName)
|
||||
}
|
||||
|
||||
type CommonCommandParams struct {
|
||||
UseDockerCreds bool
|
||||
CredsAccount string
|
||||
CredsSecret string
|
||||
}
|
||||
|
||||
func CommonCommandFlagValues(ctx *cli.Context) (*CommonCommandParams, error) {
|
||||
values := &CommonCommandParams{
|
||||
UseDockerCreds: ctx.Bool(FlagUseDockerCreds),
|
||||
CredsAccount: ctx.String(FlagCredsAccount),
|
||||
//prefer env var for secret (todo: add interactive and file read modes)
|
||||
CredsSecret: ctx.String(FlagCredsSecret),
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
type PullCommandParams struct {
|
||||
*CommonCommandParams
|
||||
TargetRef string
|
||||
SaveToDocker bool
|
||||
}
|
||||
|
||||
func PullCommandFlagValues(ctx *cli.Context) (*PullCommandParams, error) {
|
||||
common, err := CommonCommandFlagValues(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values := &PullCommandParams{
|
||||
TargetRef: ctx.String(commands.FlagTarget),
|
||||
SaveToDocker: ctx.Bool(FlagSaveToDocker),
|
||||
CommonCommandParams: common,
|
||||
TargetRef: ctx.String(commands.FlagTarget),
|
||||
SaveToDocker: ctx.Bool(FlagSaveToDocker),
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
type ImageIndexCreateCommandParams struct {
|
||||
*CommonCommandParams
|
||||
ImageIndexName string
|
||||
ImageNames []string
|
||||
AsManifestList bool
|
||||
InsecureRefs bool
|
||||
DumpRawManifest bool
|
||||
}
|
||||
|
||||
func ImageIndexCreateCommandFlagValues(ctx *cli.Context) (*ImageIndexCreateCommandParams, error) {
|
||||
common, err := CommonCommandFlagValues(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values := &ImageIndexCreateCommandParams{
|
||||
CommonCommandParams: common,
|
||||
ImageIndexName: ctx.String(FlagImageIndexName),
|
||||
ImageNames: ctx.StringSlice(FlagImageName),
|
||||
AsManifestList: ctx.Bool(FlagAsManifestList),
|
||||
InsecureRefs: ctx.Bool(FlagInsecureRefs),
|
||||
DumpRawManifest: ctx.Bool(FlagDumpRawManifest),
|
||||
}
|
||||
|
||||
return values, nil
|
||||
@ -44,6 +100,11 @@ var CLI = &cli.Command{
|
||||
Name: Name,
|
||||
Aliases: []string{Alias},
|
||||
Usage: Usage,
|
||||
Flags: []cli.Flag{
|
||||
cflag(FlagUseDockerCreds),
|
||||
cflag(FlagCredsAccount),
|
||||
cflag(FlagCredsSecret),
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: PullCmdName,
|
||||
@ -107,5 +168,31 @@ var CLI = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: ImageIndexCreateCmdName,
|
||||
Usage: ImageIndexCreateCmdNameUsage,
|
||||
Flags: []cli.Flag{
|
||||
cflag(FlagImageIndexName),
|
||||
cflag(FlagImageName),
|
||||
cflag(FlagAsManifestList),
|
||||
cflag(FlagInsecureRefs),
|
||||
cflag(FlagDumpRawManifest),
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
gcvalues, err := commands.GlobalFlagValues(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cparams, err := ImageIndexCreateCommandFlagValues(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xc := app.NewExecutionContext(fullCmdName(ImageIndexCreateCmdName), ctx.String(commands.FlagConsoleFormat))
|
||||
OnImageIndexCreateCommand(xc, gcvalues, cparams)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -7,21 +7,85 @@ import (
|
||||
|
||||
// Registry command flag names
|
||||
const (
|
||||
FlagSaveToDocker = "save-to-docker"
|
||||
FlagUseDockerCreds = "use-docker-credentials"
|
||||
FlagCredsAccount = "account"
|
||||
FlagCredsSecret = "secret"
|
||||
FlagSaveToDocker = "save-to-docker"
|
||||
FlagImageIndexName = "image-index-name"
|
||||
FlagImageName = "image-name"
|
||||
FlagAsManifestList = "as-manifest-list"
|
||||
FlagInsecureRefs = "insecure-refs"
|
||||
FlagDumpRawManifest = "dump-raw-manifest"
|
||||
)
|
||||
|
||||
// Registry command flag usage info
|
||||
const (
|
||||
FlagSaveToDockerUsage = "Save pulled image to docker"
|
||||
FlagUseDockerCredsUsage = "Use the registry credentials from the default Docker config file"
|
||||
FlagCredsAccountUsage = "Registry credentials account"
|
||||
FlagCredsSecretUsage = "Registry credentials secret"
|
||||
FlagSaveToDockerUsage = "Save pulled image to docker"
|
||||
FlagImageIndexNameUsage = "Image index name to use"
|
||||
FlagImageNameUsage = "Target image name to include in image index"
|
||||
FlagAsManifestListUsage = "Create image index with the manifest list media type instead of the default OCI image index type"
|
||||
FlagInsecureRefsUsage = "Allow the referenced images from insecure registry connections"
|
||||
FlagDumpRawManifestUsage = "Dump raw manifest for the created image index"
|
||||
)
|
||||
|
||||
var Flags = map[string]cli.Flag{
|
||||
FlagUseDockerCreds: &cli.BoolFlag{
|
||||
Name: FlagUseDockerCreds,
|
||||
Value: false, //defaults to false
|
||||
Usage: FlagUseDockerCredsUsage,
|
||||
EnvVars: []string{"DSLIM_REG_DOCKER_CREDS"},
|
||||
},
|
||||
FlagCredsAccount: &cli.StringFlag{
|
||||
Name: FlagCredsAccount,
|
||||
Value: "",
|
||||
Usage: FlagCredsAccountUsage,
|
||||
EnvVars: []string{"DSLIM_REG_ACCOUNT"},
|
||||
},
|
||||
FlagCredsSecret: &cli.StringFlag{
|
||||
Name: FlagCredsSecret,
|
||||
Value: "",
|
||||
Usage: FlagCredsSecretUsage,
|
||||
EnvVars: []string{"DSLIM_REG_SECRET"},
|
||||
},
|
||||
FlagSaveToDocker: &cli.BoolFlag{
|
||||
Name: FlagSaveToDocker,
|
||||
Value: true, //defaults to true
|
||||
Usage: FlagSaveToDockerUsage,
|
||||
EnvVars: []string{"DSLIM_REG_PULL_SAVE_TO_DOCKER"},
|
||||
},
|
||||
FlagImageIndexName: &cli.StringFlag{
|
||||
Name: FlagImageIndexName,
|
||||
Value: "",
|
||||
Usage: FlagImageIndexNameUsage,
|
||||
EnvVars: []string{"DSLIM_REG_IIC_INDEX_NAME"},
|
||||
},
|
||||
FlagImageName: &cli.StringSliceFlag{
|
||||
Name: FlagImageName,
|
||||
Value: cli.NewStringSlice(),
|
||||
Usage: FlagImageNameUsage,
|
||||
EnvVars: []string{"DSLIM_REG_IIC_IMAGE_NAME"},
|
||||
},
|
||||
FlagAsManifestList: &cli.BoolFlag{
|
||||
Name: FlagAsManifestList,
|
||||
Value: false, //defaults to false
|
||||
Usage: FlagAsManifestListUsage,
|
||||
EnvVars: []string{"DSLIM_REG_IIC_AS_MLIST"},
|
||||
},
|
||||
FlagInsecureRefs: &cli.BoolFlag{
|
||||
Name: FlagInsecureRefs,
|
||||
Value: false, //defaults to false
|
||||
Usage: FlagInsecureRefsUsage,
|
||||
EnvVars: []string{"DSLIM_REG_IIC_INSECURE_REFS"},
|
||||
},
|
||||
FlagDumpRawManifest: &cli.BoolFlag{
|
||||
Name: FlagDumpRawManifest,
|
||||
Value: false, //defaults to false
|
||||
Usage: FlagDumpRawManifestUsage,
|
||||
EnvVars: []string{"DSLIM_REG_IIC_DUMP_MANIFEST"},
|
||||
},
|
||||
}
|
||||
|
||||
func cflag(name string) cli.Flag {
|
||||
|
79
pkg/app/master/commands/registry/handler_copy.go
Normal file
79
pkg/app/master/commands/registry/handler_copy.go
Normal file
@ -0,0 +1,79 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
//"github.com/google/go-containerregistry/pkg/crane"
|
||||
//"github.com/google/go-containerregistry/pkg/name"
|
||||
//gocrv1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
//"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/slimtoolkit/slim/pkg/app"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/commands"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/version"
|
||||
"github.com/slimtoolkit/slim/pkg/command"
|
||||
"github.com/slimtoolkit/slim/pkg/docker/dockerclient"
|
||||
"github.com/slimtoolkit/slim/pkg/report"
|
||||
"github.com/slimtoolkit/slim/pkg/util/errutil"
|
||||
"github.com/slimtoolkit/slim/pkg/util/fsutil"
|
||||
v "github.com/slimtoolkit/slim/pkg/version"
|
||||
)
|
||||
|
||||
// OnCopyCommand implements the 'registry copy' command
|
||||
func OnCopyCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams) {
|
||||
cmdName := fullCmdName(CopyCmdName)
|
||||
logger := log.WithFields(log.Fields{
|
||||
"app": appName,
|
||||
"cmd": cmdName,
|
||||
"sub": CopyCmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
cmdReport := report.NewRegistryCommand(gparams.ReportLocation, gparams.InContainer)
|
||||
cmdReport.State = command.StateStarted
|
||||
|
||||
xc.Out.State("started")
|
||||
|
||||
client, err := dockerclient.New(gparams.ClientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
exitMsg := "missing Docker connection info"
|
||||
if gparams.InContainer && gparams.IsDSImage {
|
||||
exitMsg = "make sure to pass the Docker connect parameters to the docker-slim container"
|
||||
}
|
||||
|
||||
xc.Out.Info("docker.connect.error",
|
||||
ovars{
|
||||
"message": exitMsg,
|
||||
})
|
||||
|
||||
exitCode := commands.ECTCommon | commands.ECCNoDockerConnectInfo
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
"location": fsutil.ExeDir(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
}
|
||||
errutil.FailOn(err)
|
||||
|
||||
if gparams.Debug {
|
||||
version.Print(xc, cmdName, logger, client, false, gparams.InContainer, gparams.IsDSImage)
|
||||
}
|
||||
|
||||
xc.Out.State("completed")
|
||||
cmdReport.State = command.StateCompleted
|
||||
xc.Out.State("done")
|
||||
|
||||
vinfo := <-viChan
|
||||
version.PrintCheckVersion(xc, "", vinfo)
|
||||
|
||||
cmdReport.State = command.StateDone
|
||||
if cmdReport.Save() {
|
||||
xc.Out.Info("report",
|
||||
ovars{
|
||||
"file": cmdReport.ReportLocation(),
|
||||
})
|
||||
}
|
||||
}
|
255
pkg/app/master/commands/registry/handler_image_index.go
Normal file
255
pkg/app/master/commands/registry/handler_image_index.go
Normal file
@ -0,0 +1,255 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||
"github.com/google/go-containerregistry/pkg/v1/partial"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/slimtoolkit/slim/pkg/app"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/commands"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/version"
|
||||
"github.com/slimtoolkit/slim/pkg/command"
|
||||
"github.com/slimtoolkit/slim/pkg/docker/dockerclient"
|
||||
"github.com/slimtoolkit/slim/pkg/report"
|
||||
"github.com/slimtoolkit/slim/pkg/util/fsutil"
|
||||
v "github.com/slimtoolkit/slim/pkg/version"
|
||||
)
|
||||
|
||||
// OnImageIndexCreateCommand implements the 'registry image-index-create' command
|
||||
func OnImageIndexCreateCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams,
|
||||
cparams *ImageIndexCreateCommandParams) {
|
||||
cmdName := fullCmdName(CopyCmdName)
|
||||
logger := log.WithFields(log.Fields{
|
||||
"app": appName,
|
||||
"cmd": cmdName,
|
||||
"sub": ImageIndexCreateCmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
cmdReport := report.NewRegistryCommand(gparams.ReportLocation, gparams.InContainer)
|
||||
cmdReport.State = command.StateStarted
|
||||
|
||||
xc.Out.State("started")
|
||||
|
||||
client, err := dockerclient.New(gparams.ClientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
exitMsg := "missing Docker connection info"
|
||||
if gparams.InContainer && gparams.IsDSImage {
|
||||
exitMsg = "make sure to pass the Docker connect parameters to the docker-slim container"
|
||||
}
|
||||
|
||||
xc.Out.Info("docker.connect.error",
|
||||
ovars{
|
||||
"message": exitMsg,
|
||||
})
|
||||
|
||||
exitCode := commands.ECTCommon | commands.ECCNoDockerConnectInfo
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
"location": fsutil.ExeDir(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
}
|
||||
xc.FailOn(err)
|
||||
|
||||
if gparams.Debug {
|
||||
version.Print(xc, cmdName, logger, client, false, gparams.InContainer, gparams.IsDSImage)
|
||||
}
|
||||
|
||||
//========================================
|
||||
if len(cparams.ImageNames) == 0 {
|
||||
xc.FailOn(fmt.Errorf("no image references for image index"))
|
||||
}
|
||||
|
||||
if !cparams.UseDockerCreds &&
|
||||
!(cparams.CredsAccount != "" && cparams.CredsSecret != "") {
|
||||
xc.FailOn(fmt.Errorf("missing auth params"))
|
||||
}
|
||||
|
||||
remoteOpts := []remote.Option{
|
||||
remote.WithContext(context.Background()),
|
||||
}
|
||||
|
||||
remoteOpts, err = ConfigureAuth(cparams.CommonCommandParams, remoteOpts)
|
||||
xc.FailOn(err)
|
||||
|
||||
nameOpts := []name.Option{
|
||||
name.WeakValidation,
|
||||
}
|
||||
|
||||
if cparams.InsecureRefs {
|
||||
nameOpts = append(nameOpts, name.Insecure)
|
||||
}
|
||||
|
||||
imageIndexRef, err := name.ParseReference(cparams.ImageIndexName, nameOpts...)
|
||||
if err != nil {
|
||||
xc.FailOn(fmt.Errorf("malformed image index reference - %s (%v)", cparams.ImageIndexName, err))
|
||||
}
|
||||
|
||||
if _, err := remote.Head(imageIndexRef, remoteOpts...); err != nil {
|
||||
if _, ok := err.(*transport.Error); ok {
|
||||
logger.Debug("no image index in registry (ok)")
|
||||
} else {
|
||||
logger.Debugf("error checking image index in registry - %v", err)
|
||||
}
|
||||
} else {
|
||||
logger.Debug("image index is already in the registry")
|
||||
}
|
||||
|
||||
imageIndex := v1.ImageIndex(empty.Index)
|
||||
indexImageImgRefs := make([]mutate.IndexAddendum, 0, len(cparams.ImageNames))
|
||||
for _, imageName := range cparams.ImageNames {
|
||||
imgRef, err := name.ParseReference(imageName, nameOpts...)
|
||||
if err != nil {
|
||||
xc.FailOn(fmt.Errorf("malformed image reference - %s (%v)", imageName, err))
|
||||
}
|
||||
|
||||
meta, err := remote.Get(imgRef, remoteOpts...)
|
||||
if err != nil {
|
||||
xc.FailOn(fmt.Errorf("image reference metadata get error - %s (%v)", imageName, err))
|
||||
}
|
||||
|
||||
if meta.MediaType.IsImage() {
|
||||
imgMeta, err := meta.Image()
|
||||
xc.FailOn(err)
|
||||
|
||||
basicImageInfo(xc, imgMeta)
|
||||
|
||||
imgConfig, err := imgMeta.ConfigFile()
|
||||
if err != nil {
|
||||
xc.FailOn(err)
|
||||
}
|
||||
imgRefMeta, err := partial.Descriptor(imgMeta)
|
||||
if err != nil {
|
||||
xc.FailOn(err)
|
||||
}
|
||||
imgRefMeta.Platform = imgConfig.Platform()
|
||||
indexImageImgRefs = append(indexImageImgRefs,
|
||||
mutate.IndexAddendum{
|
||||
Add: imgMeta,
|
||||
Descriptor: *imgRefMeta,
|
||||
})
|
||||
} else {
|
||||
xc.FailOn(fmt.Errorf("unexpected target image type - %s (%v)", imageName, meta.MediaType))
|
||||
}
|
||||
}
|
||||
|
||||
if cparams.AsManifestList {
|
||||
imageIndex = mutate.IndexMediaType(imageIndex, types.DockerManifestList)
|
||||
}
|
||||
|
||||
imageIndex = mutate.AppendManifests(imageIndex, indexImageImgRefs...)
|
||||
|
||||
if err := remote.WriteIndex(imageIndexRef, imageIndex, remoteOpts...); err != nil {
|
||||
var terr *transport.Error
|
||||
if errors.As(err, &terr) && terr.StatusCode == http.StatusUnauthorized {
|
||||
xc.Out.Info("registry.auth.error",
|
||||
ovars{
|
||||
"message": "need to authenticate",
|
||||
})
|
||||
|
||||
exitCode := -111
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
} else {
|
||||
xc.FailOn(fmt.Errorf("saving image index error - %s (%v)", cparams.ImageIndexName, err))
|
||||
}
|
||||
}
|
||||
|
||||
indexMeta, err := remote.Index(imageIndexRef, remoteOpts...)
|
||||
if err != nil {
|
||||
xc.FailOn(fmt.Errorf("index reference metadata get error - %s (%v)", cparams.ImageIndexName, err))
|
||||
}
|
||||
|
||||
indexMediaType, err := indexMeta.MediaType()
|
||||
xc.FailOn(err)
|
||||
|
||||
if !indexMediaType.IsIndex() {
|
||||
xc.FailOn(fmt.Errorf("unexpected media type for index"))
|
||||
}
|
||||
|
||||
indexDigest, err := indexMeta.Digest()
|
||||
xc.FailOn(err)
|
||||
|
||||
indexManifest, err := indexMeta.IndexManifest()
|
||||
xc.FailOn(err)
|
||||
xc.Out.Info("index.info",
|
||||
ovars{
|
||||
"reference": imageIndexRef,
|
||||
"digest": indexDigest.String(),
|
||||
"manifest.schema": indexManifest.SchemaVersion,
|
||||
"manifest.media_type": indexManifest.MediaType,
|
||||
"manifest.image.ref.count": len(indexManifest.Manifests),
|
||||
})
|
||||
|
||||
if cparams.DumpRawManifest {
|
||||
if rm, err := indexMeta.RawManifest(); err == nil {
|
||||
//todo: reformat to pretty print
|
||||
fmt.Printf("\n\n%s\n\n", string(rm))
|
||||
}
|
||||
}
|
||||
|
||||
xc.Out.State("completed")
|
||||
cmdReport.State = command.StateCompleted
|
||||
xc.Out.State("done")
|
||||
|
||||
vinfo := <-viChan
|
||||
version.PrintCheckVersion(xc, "", vinfo)
|
||||
|
||||
cmdReport.State = command.StateDone
|
||||
if cmdReport.Save() {
|
||||
xc.Out.Info("report",
|
||||
ovars{
|
||||
"file": cmdReport.ReportLocation(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func basicImageInfo(
|
||||
xc *app.ExecutionContext,
|
||||
targetImage v1.Image) {
|
||||
cn, err := targetImage.ConfigName()
|
||||
xc.FailOn(err)
|
||||
|
||||
d, err := targetImage.Digest()
|
||||
xc.FailOn(err)
|
||||
|
||||
cf, err := targetImage.ConfigFile()
|
||||
xc.FailOn(err)
|
||||
|
||||
m, err := targetImage.Manifest()
|
||||
xc.FailOn(err)
|
||||
|
||||
xc.Out.Info("image.info",
|
||||
ovars{
|
||||
"id": fmt.Sprintf("%s:%s", cn.Algorithm, cn.Hex),
|
||||
"digest": fmt.Sprintf("%s:%s", d.Algorithm, d.Hex),
|
||||
"architecture": cf.Architecture,
|
||||
"os": cf.OS,
|
||||
"manifest.schema": m.SchemaVersion,
|
||||
"manifest.media_type": m.MediaType,
|
||||
"manifest.config.media_type": m.Config.MediaType,
|
||||
"manifest.config.size": fmt.Sprintf("%v", m.Config.Size),
|
||||
"manifest.config.digest": fmt.Sprintf("%s:%s", m.Config.Digest.Algorithm, m.Config.Digest.Hex),
|
||||
"manifest.layers.count": fmt.Sprintf("%v", len(m.Layers)),
|
||||
})
|
||||
}
|
@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/crane"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
gocrv1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@ -30,7 +30,10 @@ func OnPullCommand(
|
||||
gparams *commands.GenericParams,
|
||||
cparams *PullCommandParams) {
|
||||
cmdName := fullCmdName(PullCmdName)
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{
|
||||
"app": appName,
|
||||
"cmd": cmdName,
|
||||
"sub": PullCmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
@ -105,136 +108,20 @@ func OnPullCommand(
|
||||
}
|
||||
}
|
||||
|
||||
// OnPushCommand implements the 'registry push' docker-slim command
|
||||
func OnPushCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams) {
|
||||
cmdName := fullCmdName(PushCmdName)
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
Name := fmt.Sprintf("cmd=%s", cmdName)
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
cmdReport := report.NewRegistryCommand(gparams.ReportLocation, gparams.InContainer)
|
||||
cmdReport.State = command.StateStarted
|
||||
|
||||
xc.Out.State("started")
|
||||
|
||||
client, err := dockerclient.New(gparams.ClientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
exitMsg := "missing Docker connection info"
|
||||
if gparams.InContainer && gparams.IsDSImage {
|
||||
exitMsg = "make sure to pass the Docker connect parameters to the docker-slim container"
|
||||
}
|
||||
|
||||
xc.Out.Info("docker.connect.error",
|
||||
ovars{
|
||||
"message": exitMsg,
|
||||
})
|
||||
|
||||
exitCode := commands.ECTCommon | commands.ECCNoDockerConnectInfo
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
"location": fsutil.ExeDir(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
}
|
||||
errutil.FailOn(err)
|
||||
|
||||
if gparams.Debug {
|
||||
version.Print(xc, Name, logger, client, false, gparams.InContainer, gparams.IsDSImage)
|
||||
}
|
||||
|
||||
xc.Out.State("completed")
|
||||
cmdReport.State = command.StateCompleted
|
||||
xc.Out.State("done")
|
||||
|
||||
vinfo := <-viChan
|
||||
version.PrintCheckVersion(xc, "", vinfo)
|
||||
|
||||
cmdReport.State = command.StateDone
|
||||
if cmdReport.Save() {
|
||||
xc.Out.Info("report",
|
||||
ovars{
|
||||
"file": cmdReport.ReportLocation(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// OnCopyCommand implements the 'registry copy' docker-slim command
|
||||
func OnCopyCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams) {
|
||||
cmdName := fullCmdName(CopyCmdName)
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
Name := fmt.Sprintf("cmd=%s", cmdName)
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
cmdReport := report.NewRegistryCommand(gparams.ReportLocation, gparams.InContainer)
|
||||
cmdReport.State = command.StateStarted
|
||||
|
||||
xc.Out.State("started")
|
||||
|
||||
client, err := dockerclient.New(gparams.ClientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
exitMsg := "missing Docker connection info"
|
||||
if gparams.InContainer && gparams.IsDSImage {
|
||||
exitMsg = "make sure to pass the Docker connect parameters to the docker-slim container"
|
||||
}
|
||||
|
||||
xc.Out.Info("docker.connect.error",
|
||||
ovars{
|
||||
"message": exitMsg,
|
||||
})
|
||||
|
||||
exitCode := commands.ECTCommon | commands.ECCNoDockerConnectInfo
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
"location": fsutil.ExeDir(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
}
|
||||
errutil.FailOn(err)
|
||||
|
||||
if gparams.Debug {
|
||||
version.Print(xc, Name, logger, client, false, gparams.InContainer, gparams.IsDSImage)
|
||||
}
|
||||
|
||||
xc.Out.State("completed")
|
||||
cmdReport.State = command.StateCompleted
|
||||
xc.Out.State("done")
|
||||
|
||||
vinfo := <-viChan
|
||||
version.PrintCheckVersion(xc, "", vinfo)
|
||||
|
||||
cmdReport.State = command.StateDone
|
||||
if cmdReport.Save() {
|
||||
xc.Out.Info("report",
|
||||
ovars{
|
||||
"file": cmdReport.ReportLocation(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func outImageInfo(
|
||||
xc *app.ExecutionContext,
|
||||
targetImage gocrv1.Image) {
|
||||
targetImage v1.Image) {
|
||||
cn, err := targetImage.ConfigName()
|
||||
errutil.FailOn(err)
|
||||
xc.FailOn(err)
|
||||
|
||||
d, err := targetImage.Digest()
|
||||
errutil.FailOn(err)
|
||||
xc.FailOn(err)
|
||||
|
||||
cf, err := targetImage.ConfigFile()
|
||||
errutil.FailOn(err)
|
||||
xc.FailOn(err)
|
||||
|
||||
m, err := targetImage.Manifest()
|
||||
errutil.FailOn(err)
|
||||
xc.FailOn(err)
|
||||
|
||||
xc.Out.Info("image.info",
|
||||
ovars{
|
79
pkg/app/master/commands/registry/handler_push.go
Normal file
79
pkg/app/master/commands/registry/handler_push.go
Normal file
@ -0,0 +1,79 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
//"github.com/google/go-containerregistry/pkg/crane"
|
||||
//"github.com/google/go-containerregistry/pkg/name"
|
||||
//gocrv1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
//"github.com/google/go-containerregistry/pkg/v1/daemon"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/slimtoolkit/slim/pkg/app"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/commands"
|
||||
"github.com/slimtoolkit/slim/pkg/app/master/version"
|
||||
"github.com/slimtoolkit/slim/pkg/command"
|
||||
"github.com/slimtoolkit/slim/pkg/docker/dockerclient"
|
||||
"github.com/slimtoolkit/slim/pkg/report"
|
||||
"github.com/slimtoolkit/slim/pkg/util/errutil"
|
||||
"github.com/slimtoolkit/slim/pkg/util/fsutil"
|
||||
v "github.com/slimtoolkit/slim/pkg/version"
|
||||
)
|
||||
|
||||
// OnPushCommand implements the 'registry push' command
|
||||
func OnPushCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams) {
|
||||
cmdName := fullCmdName(PushCmdName)
|
||||
logger := log.WithFields(log.Fields{
|
||||
"app": appName,
|
||||
"cmd": cmdName,
|
||||
"sub": PushCmdName})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
cmdReport := report.NewRegistryCommand(gparams.ReportLocation, gparams.InContainer)
|
||||
cmdReport.State = command.StateStarted
|
||||
|
||||
xc.Out.State("started")
|
||||
|
||||
client, err := dockerclient.New(gparams.ClientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
exitMsg := "missing Docker connection info"
|
||||
if gparams.InContainer && gparams.IsDSImage {
|
||||
exitMsg = "make sure to pass the Docker connect parameters to the docker-slim container"
|
||||
}
|
||||
|
||||
xc.Out.Info("docker.connect.error",
|
||||
ovars{
|
||||
"message": exitMsg,
|
||||
})
|
||||
|
||||
exitCode := commands.ECTCommon | commands.ECCNoDockerConnectInfo
|
||||
xc.Out.State("exited",
|
||||
ovars{
|
||||
"exit.code": exitCode,
|
||||
"version": v.Current(),
|
||||
"location": fsutil.ExeDir(),
|
||||
})
|
||||
xc.Exit(exitCode)
|
||||
}
|
||||
errutil.FailOn(err)
|
||||
|
||||
if gparams.Debug {
|
||||
version.Print(xc, cmdName, logger, client, false, gparams.InContainer, gparams.IsDSImage)
|
||||
}
|
||||
|
||||
xc.Out.State("completed")
|
||||
cmdReport.State = command.StateCompleted
|
||||
xc.Out.State("done")
|
||||
|
||||
vinfo := <-viChan
|
||||
version.PrintCheckVersion(xc, "", vinfo)
|
||||
|
||||
cmdReport.State = command.StateDone
|
||||
if cmdReport.Save() {
|
||||
xc.Out.Info("report",
|
||||
ovars{
|
||||
"file": cmdReport.ReportLocation(),
|
||||
})
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ func OnCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams,
|
||||
cparams *CommandParams) {
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -22,7 +22,7 @@ type ovars = app.OutVars
|
||||
func OnCommand(
|
||||
xc *app.ExecutionContext,
|
||||
gparams *commands.GenericParams) {
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": Name})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": Name})
|
||||
|
||||
viChan := version.CheckAsync(gparams.CheckVersion, gparams.InContainer, gparams.IsDSImage)
|
||||
|
||||
|
@ -21,7 +21,7 @@ func OnCommand(
|
||||
xc *app.ExecutionContext,
|
||||
doDebug, inContainer, isDSImage bool,
|
||||
clientConfig *config.DockerClient) {
|
||||
logger := log.WithFields(log.Fields{"app": "slim", "command": command.Version})
|
||||
logger := log.WithFields(log.Fields{"app": "slim", "cmd": command.Version})
|
||||
|
||||
client, err := dockerclient.New(clientConfig)
|
||||
if err == dockerclient.ErrNoDockerInfo {
|
||||
|
@ -83,7 +83,7 @@ func OnCommand(
|
||||
xdArtifactsPath string,
|
||||
) {
|
||||
const cmdName = Name
|
||||
logger := log.WithFields(log.Fields{"app": appName, "command": cmdName})
|
||||
logger := log.WithFields(log.Fields{"app": appName, "cmd": cmdName})
|
||||
|
||||
changeDataMatchers := map[string]*dockerimage.ChangeDataMatcher{}
|
||||
for _, cdm := range changeDataMatcherList {
|
||||
|
Loading…
Reference in New Issue
Block a user