ctr: add commands package with shared utility functions

Signed-off-by: Jess Valarezo <valarezo.jessica@gmail.com>
This commit is contained in:
Jess Valarezo 2017-10-23 17:40:18 -07:00
parent 04659d9405
commit a19a20303a
19 changed files with 123 additions and 128 deletions

View File

@ -0,0 +1,84 @@
package commands
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/containerd/containerd"
"github.com/urfave/cli"
)
var (
// SnapshotterFlags are cli flags specifying snapshotter names
SnapshotterFlags = []cli.Flag{
cli.StringFlag{
Name: "snapshotter",
Usage: "snapshotter name. Empty value stands for the daemon default value.",
Value: containerd.DefaultSnapshotter,
},
}
// LabelFlag is a cli flag specifying labels
LabelFlag = cli.StringSliceFlag{
Name: "label",
Usage: "labels to attach to the image",
}
// RegistryFlags are cli flags specifying registry options
RegistryFlags = []cli.Flag{
cli.BoolFlag{
Name: "skip-verify,k",
Usage: "skip SSL certificate validation",
},
cli.BoolFlag{
Name: "plain-http",
Usage: "allow connections using plain HTTP",
},
cli.StringFlag{
Name: "user,u",
Usage: "user[:password] Registry user and password",
},
cli.StringFlag{
Name: "refresh",
Usage: "refresh token for authorization server",
},
}
)
// ObjectWithLabelArgs returns the first arg and a LabelArgs object
func ObjectWithLabelArgs(clicontext *cli.Context) (string, map[string]string) {
var (
first = clicontext.Args().First()
labelStrings = clicontext.Args().Tail()
)
return first, LabelArgs(labelStrings)
}
// LabelArgs returns a map of label key,value pairs
func LabelArgs(labelStrings []string) map[string]string {
labels := make(map[string]string, len(labelStrings))
for _, label := range labelStrings {
parts := strings.SplitN(label, "=", 2)
key := parts[0]
value := "true"
if len(parts) > 1 {
value = parts[1]
}
labels[key] = value
}
return labels
}
// PrintAsJSON prints input in JSON format
func PrintAsJSON(x interface{}) {
b, err := json.MarshalIndent(x, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "can't marshal %+v as a JSON string: %v\n", x, err)
}
fmt.Println(string(b))
}

View File

@ -10,6 +10,7 @@ import (
"text/tabwriter" "text/tabwriter"
"time" "time"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
@ -212,7 +213,7 @@ var (
Description: `Labels blobs in the content store`, Description: `Labels blobs in the content store`,
Flags: []cli.Flag{}, Flags: []cli.Flag{},
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
object, labels := objectWithLabelArgs(context) object, labels := commands.ObjectWithLabelArgs(context)
client, ctx, cancel, err := newClient(context) client, ctx, cancel, err := newClient(context)
if err != nil { if err != nil {
return err return err

View File

@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
@ -39,7 +40,7 @@ not use this implementation as a guide. The end goal should be having metadata,
content and snapshots ready for a direct use via the 'ctr run'. content and snapshots ready for a direct use via the 'ctr run'.
Most of this is experimental and there are few leaps to make this work.`, Most of this is experimental and there are few leaps to make this work.`,
Flags: append(registryFlags, labelFlag), Flags: append(commands.RegistryFlags, commands.LabelFlag),
Action: func(clicontext *cli.Context) error { Action: func(clicontext *cli.Context) error {
var ( var (
ref = clicontext.Args().First() ref = clicontext.Args().First()
@ -82,7 +83,7 @@ func fetch(ref string, cliContext *cli.Context) (containerd.Image, error) {
}) })
log.G(pctx).WithField("image", ref).Debug("fetching") log.G(pctx).WithField("image", ref).Debug("fetching")
labels := labelArgs(cliContext.StringSlice("label")) labels := commands.LabelArgs(cliContext.StringSlice("label"))
img, err := client.Pull(pctx, ref, img, err := client.Pull(pctx, ref,
containerd.WithPullLabels(labels), containerd.WithPullLabels(labels),
containerd.WithResolver(resolver), containerd.WithResolver(resolver),

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"os" "os"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -17,7 +18,7 @@ var fetchObjectCommand = cli.Command{
Usage: "retrieve objects from a remote", Usage: "retrieve objects from a remote",
ArgsUsage: "[flags] <remote> <object> [<hint>, ...]", ArgsUsage: "[flags] <remote> <object> [<hint>, ...]",
Description: `Fetch objects by identifier from a remote.`, Description: `Fetch objects by identifier from a remote.`,
Flags: registryFlags, Flags: commands.RegistryFlags,
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
ref = context.Args().First() ref = context.Args().First()

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
@ -127,7 +128,7 @@ var imagesSetLabelsCommand = cli.Command{
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
replaceAll = context.Bool("replace-all") replaceAll = context.Bool("replace-all")
name, labels = objectWithLabelArgs(context) name, labels = commands.ObjectWithLabelArgs(context)
) )
client, ctx, cancel, err := newClient(context) client, ctx, cancel, err := newClient(context)
if err != nil { if err != nil {

View File

@ -6,6 +6,7 @@ import (
"os" "os"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -21,14 +22,14 @@ var imagesImportCommand = cli.Command{
Value: "", Value: "",
Usage: "reference object e.g. tag@digest (default: use the object specified in ref)", Usage: "reference object e.g. tag@digest (default: use the object specified in ref)",
}, },
labelFlag, commands.LabelFlag,
}, },
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
ref = context.Args().First() ref = context.Args().First()
in = context.Args().Get(1) in = context.Args().Get(1)
refObject = context.String("ref-object") refObject = context.String("ref-object")
labels = labelArgs(context.StringSlice("label")) labels = commands.LabelArgs(context.StringSlice("label"))
) )
client, ctx, cancel, err := newClient(context) client, ctx, cancel, err := newClient(context)
if err != nil { if err != nil {

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -27,7 +28,7 @@ var containerInfoCommand = cli.Command{
if err != nil { if err != nil {
return err return err
} }
printAsJSON(info) commands.PrintAsJSON(info)
return nil return nil
}, },

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -15,7 +16,7 @@ var containersSetLabelsCommand = cli.Command{
Description: "Set and clear labels for a container.", Description: "Set and clear labels for a container.",
Flags: []cli.Flag{}, Flags: []cli.Flag{},
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
containerID, labels := objectWithLabelArgs(context) containerID, labels := commands.ObjectWithLabelArgs(context)
if containerID == "" { if containerID == "" {
return errors.New("please specify a container") return errors.New("please specify a container")
} }

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -30,7 +31,7 @@ var namespacesCreateCommand = cli.Command{
ArgsUsage: "[flags] <name> [<key>=<value]", ArgsUsage: "[flags] <name> [<key>=<value]",
Description: "Create a new namespace. It must be unique.", Description: "Create a new namespace. It must be unique.",
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
namespace, labels := objectWithLabelArgs(context) namespace, labels := commands.ObjectWithLabelArgs(context)
if namespace == "" { if namespace == "" {
return errors.New("please specify a namespace") return errors.New("please specify a namespace")
} }
@ -51,7 +52,7 @@ var namespacesSetLabelsCommand = cli.Command{
Description: "Set and clear labels for a namespace.", Description: "Set and clear labels for a namespace.",
Flags: []cli.Flag{}, Flags: []cli.Flag{},
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
namespace, labels := objectWithLabelArgs(context) namespace, labels := commands.ObjectWithLabelArgs(context)
if namespace == "" { if namespace == "" {
return errors.New("please specify a namespace") return errors.New("please specify a namespace")
} }

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -20,7 +21,7 @@ command. As part of this process, we do the following:
2. Prepare the snapshot filesystem with the pulled resources. 2. Prepare the snapshot filesystem with the pulled resources.
3. Register metadata for the image. 3. Register metadata for the image.
`, `,
Flags: append(registryFlags, append(snapshotterFlags, labelFlag)...), Flags: append(commands.RegistryFlags, append(commands.SnapshotterFlags, commands.LabelFlag)...),
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
ref = context.Args().First() ref = context.Args().First()

View File

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/images" "github.com/containerd/containerd/images"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/containerd/containerd/progress" "github.com/containerd/containerd/progress"
@ -37,7 +38,7 @@ var pushCommand = cli.Command{
creating the associated configuration, and creating the manifest creating the associated configuration, and creating the manifest
which references those resources. which references those resources.
`, `,
Flags: append(registryFlags, cli.StringFlag{ Flags: append(commands.RegistryFlags, cli.StringFlag{
Name: "manifest", Name: "manifest",
Usage: "digest of manifest", Usage: "digest of manifest",
}, cli.StringFlag{ }, cli.StringFlag{

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
@ -15,7 +16,7 @@ var pushObjectCommand = cli.Command{
Usage: "push an object to a remote", Usage: "push an object to a remote",
ArgsUsage: "[flags] <remote> <object> <type>", ArgsUsage: "[flags] <remote> <object> <type>",
Description: `Push objects by identifier to a remote.`, Description: `Push objects by identifier to a remote.`,
Flags: registryFlags, Flags: commands.RegistryFlags,
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
ref = context.Args().Get(0) ref = context.Args().Get(0)

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -21,7 +22,7 @@ var rootfsUnpackCommand = cli.Command{
Name: "unpack", Name: "unpack",
Usage: "unpack applies layers from a manifest to a snapshot", Usage: "unpack applies layers from a manifest to a snapshot",
ArgsUsage: "[flags] <digest>", ArgsUsage: "[flags] <digest>",
Flags: snapshotterFlags, Flags: commands.SnapshotterFlags,
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
dgst, err := digest.Parse(context.Args().First()) dgst, err := digest.Parse(context.Args().First())
if err != nil { if err != nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -100,7 +101,7 @@ var runCommand = cli.Command{
Name: "detach,d", Name: "detach,d",
Usage: "detach from the task after it has started execution", Usage: "detach from the task after it has started execution",
}, },
}, snapshotterFlags...), }, commands.SnapshotterFlags...),
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
var ( var (
err error err error

View File

@ -11,6 +11,7 @@ import (
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -76,7 +77,7 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
opts []containerd.SpecOpts opts []containerd.SpecOpts
cOpts []containerd.NewContainerOpts cOpts []containerd.NewContainerOpts
) )
cOpts = append(cOpts, containerd.WithContainerLabels(labelArgs(context.StringSlice("label")))) cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
if context.Bool("rootfs") { if context.Bool("rootfs") {
opts = append(opts, containerd.WithRootFSPath(ref)) opts = append(opts, containerd.WithRootFSPath(ref))
} else { } else {

View File

@ -6,6 +6,7 @@ import (
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
@ -92,7 +93,7 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
labelStrings = context.StringSlice("label") labelStrings = context.StringSlice("label")
) )
labels := labelArgs(labelStrings) labels := commands.LabelArgs(labelStrings)
// TODO(mlaventure): get base image once we have a snapshotter // TODO(mlaventure): get base image once we have a snapshotter

View File

@ -13,6 +13,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd/cmd/ctr/commands"
shim "github.com/containerd/containerd/linux/shim/v1" shim "github.com/containerd/containerd/linux/shim/v1"
"github.com/containerd/typeurl" "github.com/containerd/typeurl"
protobuf "github.com/gogo/protobuf/types" protobuf "github.com/gogo/protobuf/types"
@ -182,7 +183,7 @@ var shimStateCommand = cli.Command{
if err != nil { if err != nil {
return err return err
} }
printAsJSON(r) commands.PrintAsJSON(r)
return nil return nil
}, },
} }

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
"text/tabwriter" "text/tabwriter"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/mount" "github.com/containerd/containerd/mount"
"github.com/containerd/containerd/progress" "github.com/containerd/containerd/progress"
"github.com/containerd/containerd/snapshot" "github.com/containerd/containerd/snapshot"
@ -17,7 +18,7 @@ import (
var snapshotCommand = cli.Command{ var snapshotCommand = cli.Command{
Name: "snapshot", Name: "snapshot",
Usage: "snapshot management", Usage: "snapshot management",
Flags: snapshotterFlags, Flags: commands.SnapshotterFlags,
Subcommands: cli.Commands{ Subcommands: cli.Commands{
listSnapshotCommand, listSnapshotCommand,
usageSnapshotCommand, usageSnapshotCommand,
@ -325,7 +326,7 @@ var infoSnapshotCommand = cli.Command{
return err return err
} }
printAsJSON(info) commands.PrintAsJSON(info)
return nil return nil
}, },
@ -338,7 +339,7 @@ var labelSnapshotCommand = cli.Command{
Description: `Labels snapshots in the snapshotter`, Description: `Labels snapshots in the snapshotter`,
Flags: []cli.Flag{}, Flags: []cli.Flag{},
Action: func(context *cli.Context) error { Action: func(context *cli.Context) error {
key, labels := objectWithLabelArgs(context) key, labels := commands.ObjectWithLabelArgs(context)
client, ctx, cancel, err := newClient(context) client, ctx, cancel, err := newClient(context)
if err != nil { if err != nil {
return err return err

View File

@ -5,7 +5,6 @@ import (
gocontext "context" gocontext "context"
"crypto/tls" "crypto/tls"
"encoding/csv" "encoding/csv"
"encoding/json"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -18,54 +17,15 @@ import (
"github.com/containerd/console" "github.com/containerd/console"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/rootfs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go" specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
var (
snapshotterFlags = []cli.Flag{
cli.StringFlag{
Name: "snapshotter",
Usage: "snapshotter name. Empty value stands for the daemon default value.",
Value: containerd.DefaultSnapshotter,
},
}
labelFlag = cli.StringSliceFlag{
Name: "label",
Usage: "labels to attach to the pulled image",
}
registryFlags = []cli.Flag{
cli.BoolFlag{
Name: "skip-verify,k",
Usage: "skip SSL certificate validation",
},
cli.BoolFlag{
Name: "plain-http",
Usage: "allow connections using plain HTTP",
},
cli.StringFlag{
Name: "user,u",
Usage: "user[:password] Registry user and password",
},
cli.StringFlag{
Name: "refresh",
Usage: "refresh token for authorization server",
},
}
)
// appContext returns the context for a command. Should only be called once per // appContext returns the context for a command. Should only be called once per
// command, near the start. // command, near the start.
// //
@ -114,39 +74,6 @@ func passwordPrompt() (string, error) {
return string(line), nil return string(line), nil
} }
func getImageLayers(ctx gocontext.Context, image images.Image, cs content.Store) ([]rootfs.Layer, error) {
p, err := content.ReadBlob(ctx, cs, image.Target.Digest)
if err != nil {
return nil, errors.Wrapf(err, "failed to read manifest blob")
}
var manifest ocispec.Manifest
if err := json.Unmarshal(p, &manifest); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal manifest")
}
diffIDs, err := image.RootFS(ctx, cs, platforms.Default())
if err != nil {
return nil, errors.Wrap(err, "failed to resolve rootfs")
}
if len(diffIDs) != len(manifest.Layers) {
return nil, errors.Errorf("mismatched image rootfs and manifest layers")
}
layers := make([]rootfs.Layer, len(diffIDs))
for i := range diffIDs {
layers[i].Diff = ocispec.Descriptor{
// TODO: derive media type from compressed type
MediaType: ocispec.MediaTypeImageLayer,
Digest: diffIDs[i],
}
layers[i].Blob = manifest.Layers[i]
}
return layers, nil
}
// getResolver prepares the resolver from the environment and options. // getResolver prepares the resolver from the environment and options.
func getResolver(ctx gocontext.Context, clicontext *cli.Context) (remotes.Resolver, error) { func getResolver(ctx gocontext.Context, clicontext *cli.Context) (remotes.Resolver, error) {
username := clicontext.String("user") username := clicontext.String("user")
@ -312,36 +239,3 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
return defaults return defaults
} }
func objectWithLabelArgs(clicontext *cli.Context) (string, map[string]string) {
var (
namespace = clicontext.Args().First()
labelStrings = clicontext.Args().Tail()
)
return namespace, labelArgs(labelStrings)
}
func labelArgs(labelStrings []string) map[string]string {
labels := make(map[string]string, len(labelStrings))
for _, label := range labelStrings {
parts := strings.SplitN(label, "=", 2)
key := parts[0]
value := "true"
if len(parts) > 1 {
value = parts[1]
}
labels[key] = value
}
return labels
}
func printAsJSON(x interface{}) {
b, err := json.MarshalIndent(x, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "can't marshal %+v as a JSON string: %v\n", x, err)
}
fmt.Println(string(b))
}