Merge pull request #1190 from stevvooe/remove-dist-command

cmd/dist: completely remove dist command
This commit is contained in:
Derek McGowan 2017-07-14 16:19:50 -07:00 committed by GitHub
commit e48ef84b20
12 changed files with 155 additions and 285 deletions

View File

@ -28,7 +28,7 @@ INTEGRATION_PACKAGE=${PKG}
TEST_REQUIRES_ROOT_PACKAGES=$(shell for f in $$(git grep -l testutil.RequiresRoot | grep -v Makefile);do echo "${PKG}/$$(dirname $$f)"; done)
# Project binaries.
COMMANDS=ctr containerd protoc-gen-gogoctrd dist
COMMANDS=ctr containerd protoc-gen-gogoctrd
ifneq ("$(GOOS)", "windows")
COMMANDS += containerd-shim
endif

View File

@ -54,7 +54,7 @@ Most of this is experimental and there are few leaps to make this work.`,
}
func fetch(ctx context.Context, ref string, clicontext *cli.Context) (containerd.Image, error) {
client, err := getClient(clicontext)
client, err := newClient(clicontext)
if err != nil {
return nil, err
}

View File

@ -59,6 +59,11 @@ containerd CLI
}
app.Commands = append([]cli.Command{
imageCommand,
pullCommand,
fetchCommand,
fetchObjectCommand,
pushCommand,
pushObjectCommand,
containersCommand,
checkpointCommand,
runCommand,
@ -76,6 +81,8 @@ containerd CLI
snapshotCommand,
versionCommand,
psCommand,
applyCommand,
rootfsCommand,
}, extraCmds...)
app.Before = func(context *cli.Context) error {
if context.GlobalBool("debug") {

View File

@ -55,7 +55,7 @@ var pushCommand = cli.Command{
ctx, cancel := appContext(clicontext)
defer cancel()
client, err := getClient(clicontext)
client, err := newClient(clicontext)
if err != nil {
return err
}

View File

@ -43,7 +43,7 @@ var pushObjectCommand = cli.Command{
return err
}
cs, err := resolveContentStore(clicontext)
cs, err := getContentStore(clicontext)
if err != nil {
return err
}

View File

@ -33,7 +33,7 @@ var rootfsUnpackCommand = cli.Command{
log.G(ctx).Debugf("unpacking layers from manifest %s", dgst.String())
client, err := getClient(clicontext)
client, err := newClient(clicontext)
if err != nil {
return err
}

View File

@ -1,16 +1,23 @@
package main
import (
"bufio"
gocontext "context"
"crypto/tls"
"encoding/csv"
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
"github.com/Sirupsen/logrus"
"github.com/containerd/console"
"github.com/containerd/containerd"
containersapi "github.com/containerd/containerd/api/services/containers/v1"
contentapi "github.com/containerd/containerd/api/services/content/v1"
@ -24,23 +31,49 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/rootfs"
contentservice "github.com/containerd/containerd/services/content"
"github.com/containerd/containerd/services/diff"
imagesservice "github.com/containerd/containerd/services/images"
namespacesservice "github.com/containerd/containerd/services/namespaces"
snapshotservice "github.com/containerd/containerd/services/snapshot"
"github.com/containerd/containerd/snapshot"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/urfave/cli"
"google.golang.org/grpc"
)
var snapshotterFlags = []cli.Flag{
cli.StringFlag{
Name: "snapshotter",
Usage: "Snapshotter name. Empty value stands for the daemon default value.",
},
}
var (
snapshotterFlags = []cli.Flag{
cli.StringFlag{
Name: "snapshotter",
Usage: "Snapshotter name. Empty value stands for the daemon default value.",
},
}
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",
},
}
)
var grpcConn *grpc.ClientConn
@ -145,6 +178,110 @@ func getVersionService(context *cli.Context) (versionservice.VersionClient, erro
return versionservice.NewVersionClient(conn), nil
}
func passwordPrompt() (string, error) {
c := console.Current()
defer c.Reset()
if err := c.DisableEcho(); err != nil {
return "", errors.Wrap(err, "failed to disable echo")
}
line, _, err := bufio.NewReader(c).ReadLine()
if err != nil {
return "", errors.Wrap(err, "failed to read line")
}
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)
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.
func getResolver(ctx gocontext.Context, clicontext *cli.Context) (remotes.Resolver, error) {
username := clicontext.String("user")
var secret string
if i := strings.IndexByte(username, ':'); i > 0 {
secret = username[i+1:]
username = username[0:i]
}
options := docker.ResolverOptions{
PlainHTTP: clicontext.Bool("plain-http"),
Tracker: pushTracker,
}
if username != "" {
if secret == "" {
fmt.Printf("Password: ")
var err error
secret, err = passwordPrompt()
if err != nil {
return nil, err
}
fmt.Print("\n")
}
} else if rt := clicontext.String("refresh"); rt != "" {
secret = rt
}
options.Credentials = func(host string) (string, string, error) {
// Only one host
return username, secret, nil
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: clicontext.Bool("insecure"),
},
ExpectContinueTimeout: 5 * time.Second,
}
options.Client = &http.Client{
Transport: tr,
}
return docker.NewResolver(options), nil
}
func forwardAllSignals(ctx gocontext.Context, task killer) chan os.Signal {
sigc := make(chan os.Signal, 128)
signal.Notify(sigc)

195
cmd/dist/common.go vendored
View File

@ -1,195 +0,0 @@
package main
import (
"bufio"
"context"
contextpkg "context"
"crypto/tls"
"encoding/json"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/containerd/console"
"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/containerd/containerd/rootfs"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var 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",
},
}
var snapshotterFlags = []cli.Flag{
cli.StringFlag{
Name: "snapshotter",
Usage: "Snapshotter name. Empty value stands for the daemon default value.",
},
}
func getClient(context *cli.Context) (*containerd.Client, error) {
address := context.GlobalString("address")
//timeout := context.GlobalDuration("connect-timeout")
return containerd.New(address)
}
// appContext returns the context for a command. Should only be called once per
// command, near the start.
//
// This will ensure the namespace is picked up and set the timeout, if one is
// defined.
func appContext(clicontext *cli.Context) (contextpkg.Context, contextpkg.CancelFunc) {
var (
ctx = contextpkg.Background()
timeout = clicontext.GlobalDuration("timeout")
namespace = clicontext.GlobalString("namespace")
cancel = func() {}
)
ctx = namespaces.WithNamespace(ctx, namespace)
if timeout > 0 {
ctx, cancel = contextpkg.WithTimeout(ctx, timeout)
} else {
ctx, cancel = contextpkg.WithCancel(ctx)
}
return ctx, cancel
}
func resolveContentStore(context *cli.Context) (content.Store, error) {
client, err := getClient(context)
if err != nil {
return nil, err
}
return client.ContentStore(), nil
}
// getResolver prepares the resolver from the environment and options.
func getResolver(ctx context.Context, clicontext *cli.Context) (remotes.Resolver, error) {
username := clicontext.String("user")
var secret string
if i := strings.IndexByte(username, ':'); i > 0 {
secret = username[i+1:]
username = username[0:i]
}
options := docker.ResolverOptions{
PlainHTTP: clicontext.Bool("plain-http"),
Tracker: pushTracker,
}
if username != "" {
if secret == "" {
fmt.Printf("Password: ")
var err error
secret, err = passwordPrompt()
if err != nil {
return nil, err
}
fmt.Print("\n")
}
} else if rt := clicontext.String("refresh"); rt != "" {
secret = rt
}
options.Credentials = func(host string) (string, string, error) {
// Only one host
return username, secret, nil
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: clicontext.Bool("insecure"),
},
ExpectContinueTimeout: 5 * time.Second,
}
options.Client = &http.Client{
Transport: tr,
}
return docker.NewResolver(options), nil
}
func passwordPrompt() (string, error) {
c := console.Current()
defer c.Reset()
if err := c.DisableEcho(); err != nil {
return "", errors.Wrap(err, "failed to disable echo")
}
line, _, err := bufio.NewReader(c).ReadLine()
if err != nil {
return "", errors.Wrap(err, "failed to read line")
}
return string(line), nil
}
func getImageLayers(ctx context.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)
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
}

79
cmd/dist/main.go vendored
View File

@ -1,79 +0,0 @@
package main
import (
"fmt"
"os"
"time"
"github.com/Sirupsen/logrus"
"github.com/containerd/containerd"
namespaces2 "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/version"
"github.com/urfave/cli"
)
var (
timeout time.Duration
)
func init() {
cli.VersionPrinter = func(c *cli.Context) {
fmt.Println(c.App.Name, version.Package, c.App.Version)
}
}
func main() {
app := cli.NewApp()
app.Name = "dist"
app.Version = version.Version
app.Usage = `
___ __
____/ (_)____/ /_
/ __ / / ___/ __/
/ /_/ / (__ ) /_
\__,_/_/____/\__/
distribution tool
`
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "debug",
Usage: "enable debug output in logs",
},
cli.DurationFlag{
Name: "timeout",
Usage: "total timeout for dist commands",
},
cli.StringFlag{
Name: "address, a",
Usage: "address for containerd's GRPC server",
Value: containerd.DefaultAddress,
},
cli.StringFlag{
Name: "namespace, n",
Usage: "namespace to use with commands",
Value: namespaces2.Default,
EnvVar: namespaces2.NamespaceEnvVar,
},
}
app.Commands = []cli.Command{
pullCommand,
fetchCommand,
fetchObjectCommand,
applyCommand,
rootfsCommand,
pushCommand,
pushObjectCommand,
}
app.Before = func(context *cli.Context) error {
if context.GlobalBool("debug") {
logrus.SetLevel(logrus.DebugLevel)
}
return nil
}
if err := app.Run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "dist: %s\n", err)
os.Exit(1)
}
}