diff --git a/Makefile b/Makefile index 7b8c93a47..6bb59ea96 100644 --- a/Makefile +++ b/Makefile @@ -20,16 +20,15 @@ PROJECT := github.com/containerd/cri BINDIR := ${DESTDIR}/usr/local/bin BUILD_DIR := _output # VERSION is derived from the current tag for HEAD plus amends. Version is used -# to set/overide the CRIContainerdVersion variable in the verison package for -# cri plugin. +# to set/overide the containerd version in vendor/github.com/containerd/containerd/version. VERSION := $(shell git describe --tags --dirty --always) # strip the first char of the tag if it's a `v` VERSION := $(VERSION:v%=%) TARBALL_PREFIX := cri-containerd TARBALL := $(TARBALL_PREFIX)-$(VERSION).$(GOOS)-$(GOARCH).tar.gz BUILD_TAGS := seccomp apparmor -GO_LDFLAGS := -X $(PROJECT)/pkg/version.CRIContainerdVersion=$(VERSION) \ - -X $(PROJECT)/vendor/github.com/containerd/containerd/version.Version=$(VERSION)-TEST +# Add `-TEST` suffix to indicate that all binaries built from this repo are for test. +GO_LDFLAGS := -X $(PROJECT)/vendor/github.com/containerd/containerd/version.Version=$(VERSION)-TEST SOURCES := $(shell find cmd/ pkg/ vendor/ -name '*.go') PLUGIN_SOURCES := $(shell ls *.go) INTEGRATION_SOURCES := $(shell find integration/ -name '*.go') @@ -42,10 +41,10 @@ help: @echo "Usage: make " @echo @echo " * 'install' - Install binaries to system locations" - @echo " * 'binaries' - Build containerd and ctrcri" - @echo " * 'static-binaries - Build static containerd and ctrcri" - @echo " * 'ctrcri' - Build ctrcri" - @echo " * 'install-ctrcri' - Install ctrcri" + @echo " * 'binaries' - Build containerd and ctr" + @echo " * 'static-binaries - Build static containerd and ctr" + @echo " * 'ctr' - Build ctr" + @echo " * 'install-ctr' - Install ctr" @echo " * 'containerd' - Build a customized containerd with CRI plugin for testing" @echo " * 'install-containerd' - Install customized containerd to system location" @echo " * 'release' - Build release tarball" @@ -92,12 +91,12 @@ sync-vendor: update-vendor: sync-vendor sort-vendor -$(BUILD_DIR)/ctrcri: $(SOURCES) +$(BUILD_DIR)/ctr: $(SOURCES) $(GO) build -o $@ \ -tags '$(BUILD_TAGS)' \ -ldflags '$(GO_LDFLAGS)' \ -gcflags '$(GO_GCFLAGS)' \ - $(PROJECT)/cmd/ctrcri + $(PROJECT)/cmd/ctr $(BUILD_DIR)/containerd: $(SOURCES) $(PLUGIN_SOURCES) $(GO) build -o $@ \ @@ -127,26 +126,26 @@ test-e2e-node: binaries clean: rm -rf $(BUILD_DIR)/* -binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctrcri +binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctr static-binaries: GO_LDFLAGS += -extldflags "-fno-PIC -static" -static-binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctrcri +static-binaries: $(BUILD_DIR)/containerd $(BUILD_DIR)/ctr -ctrcri: $(BUILD_DIR)/ctrcri +ctr: $(BUILD_DIR)/ctr -install-ctrcri: ctrcri - install -D -m 755 $(BUILD_DIR)/ctrcri $(BINDIR)/ctrcri +install-ctr: ctr + install -D -m 755 $(BUILD_DIR)/ctr $(BINDIR)/ctr containerd: $(BUILD_DIR)/containerd install-containerd: containerd install -D -m 755 $(BUILD_DIR)/containerd $(BINDIR)/containerd -install: install-ctrcri install-containerd +install: install-ctr install-containerd uninstall: rm -f $(BINDIR)/containerd - rm -f $(BINDIR)/ctrcri + rm -f $(BINDIR)/ctr $(BUILD_DIR)/$(TARBALL): static-binaries vendor.conf @BUILD_DIR=$(BUILD_DIR) TARBALL=$(TARBALL) ./hack/release.sh @@ -188,8 +187,8 @@ install.tools: .install.gitvalidation .install.gometalinter .PHONY: \ binaries \ static-binaries \ - ctrcri \ - install-ctrcri \ + ctr \ + install-ctr \ containerd \ install-containerd \ release \ diff --git a/cluster/gce/env b/cluster/gce/env index 231d1c914..203f714c2 100644 --- a/cluster/gce/env +++ b/cluster/gce/env @@ -13,7 +13,7 @@ export KUBE_MASTER_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/master.yaml,c export KUBE_NODE_EXTRA_METADATA="user-data=${GCE_DIR}/cloud-init/node.yaml,containerd-configure-sh=${GCE_DIR}/configure.sh,version=${version_file}" export KUBE_CONTAINER_RUNTIME="remote" export KUBE_CONTAINER_RUNTIME_ENDPOINT="/run/containerd/containerd.sock" -export KUBE_LOAD_IMAGE_COMMAND="/home/containerd/usr/local/bin/ctrcri load" +export KUBE_LOAD_IMAGE_COMMAND="/home/containerd/usr/local/bin/ctr cri load" export NETWORK_POLICY_PROVIDER="calico" export NON_MASQUERADE_CIDR="0.0.0.0/0" export KUBE_KUBELET_EXTRA_ARGS="--runtime-cgroups=/runtime" diff --git a/pkg/version/version_test.go b/cmd/ctr/main.go similarity index 61% rename from pkg/version/version_test.go rename to cmd/ctr/main.go index a494a8841..e001e4300 100644 --- a/pkg/version/version_test.go +++ b/cmd/ctr/main.go @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright 2018 The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,18 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -package version +package main import ( - "testing" + "fmt" + "os" - "github.com/stretchr/testify/assert" + "github.com/containerd/containerd/cmd/ctr/command" + + cricli "github.com/containerd/cri/cli" ) -func TestValidateSemver(t *testing.T) { - err := validateSemver("UNKNOWN") - assert := assert.New(t) - assert.NotNil(err) - err = validateSemver("0.0.0-1-gdf6a1cc-dirty") - assert.Nil(err) +func main() { + app := command.App() + app.Commands = append(app.Commands, cricli.Command) + if err := app.Run(os.Args); err != nil { + fmt.Fprintf(os.Stderr, "ctr: %s\n", err) + os.Exit(1) + } } diff --git a/cmd/ctrcri/ctrcri.go b/cmd/ctrcri/ctrcri.go deleted file mode 100644 index f9e4a1d7c..000000000 --- a/cmd/ctrcri/ctrcri.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2018 The Containerd Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "os" - "time" - - "github.com/containerd/containerd/defaults" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - - "github.com/containerd/cri/pkg/version" -) - -const ( - // Add \u200B to avoid the space trimming. - desc = "\u200B" + ` __ _ - _____/ /________________(_) - / ___/ __/ ___/ ___/ ___/ / -/ /__/ /_/ / / /__/ / / / -\___/\__/_/ \___/_/ /_/ - -containerd CRI plugin CLI -` - command = "ctrcri" -) - -var cmd = &cobra.Command{ - Use: command, - Short: "A CLI for containerd CRI plugin.", - Long: desc, -} - -var ( - // address is the address for containerd's GRPC server. - address string - // timeout is the timeout for containerd grpc connection. - timeout time.Duration - // defaultTimeout is the default timeout for containerd grpc connection. - defaultTimeout = 10 * time.Second -) - -func addGlobalFlags(fs *pflag.FlagSet) { - fs.StringVar(&address, "address", defaults.DefaultAddress, "address for containerd's GRPC server.") - fs.DurationVar(&timeout, "timeout", defaultTimeout, "timeout for containerd grpc connection.") -} - -func versionCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Print " + command + " version information.", - Run: func(cmd *cobra.Command, args []string) { - version.PrintVersion() - }, - } -} - -func main() { - addGlobalFlags(cmd.PersistentFlags()) - - cmd.AddCommand(versionCommand()) - cmd.AddCommand(loadImageCommand()) - if err := cmd.Execute(); err != nil { - // Error should have been reported. - os.Exit(1) - } -} diff --git a/cmd/ctrcri/load.go b/cmd/ctrcri/load.go deleted file mode 100644 index 372f240eb..000000000 --- a/cmd/ctrcri/load.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "path/filepath" - "strings" - - dedentutil "github.com/renstrom/dedent" - "github.com/spf13/cobra" - "golang.org/x/net/context" - - api "github.com/containerd/cri/pkg/api/v1" - "github.com/containerd/cri/pkg/client" -) - -func dedent(s string) string { - return strings.TrimLeft(dedentutil.Dedent(s), "\n") -} - -var ( - loadLong = dedent(` - Help for "load TAR" command - - TAR - The path to a tar archive containing a container image. - - Requirement: - Containerd and its cri plugin must already be up and running before the load - command is used. - - Description: - Running as a client, ` + command + ` implements the load command by sending the - load request to the already running containerd daemon/server, which in - turn loads the image into containerd's image storage.`) - - loadExample = dedent(` - - use docker to pull the latest busybox image and save it as a tar archive: - $ docker pull busybox:latest - $ docker save busybox:latest -o busybox.tar - - use ` + command + ` to load the image into containerd's image storage: - $ ` + command + ` load busybox.tar`) -) - -func loadImageCommand() *cobra.Command { - c := &cobra.Command{ - Use: "load TAR", - Long: loadLong, - Short: "Load an image from a tar archive.", - Args: cobra.ExactArgs(1), - Example: loadExample, - } - c.SetUsageTemplate(strings.Replace(c.UsageTemplate(), "Examples:", "Example:", 1)) - c.RunE = func(cmd *cobra.Command, args []string) error { - cl, err := client.NewCRIContainerdClient(address, timeout) - if err != nil { - return fmt.Errorf("failed to create grpc client: %v", err) - } - path, err := filepath.Abs(args[0]) - if err != nil { - return fmt.Errorf("failed to get absolute path: %v", err) - } - res, err := cl.LoadImage(context.Background(), &api.LoadImageRequest{FilePath: path}) - if err != nil { - return fmt.Errorf("failed to load image: %v", err) - } - images := res.GetImages() - for _, image := range images { - fmt.Println("Loaded image:", image) - } - return nil - } - return c -} diff --git a/docs/crictl.md b/docs/crictl.md index 488d409ac..0db5d9177 100644 --- a/docs/crictl.md +++ b/docs/crictl.md @@ -54,7 +54,7 @@ $ docker save k8s.gcr.io/pause-amd64:3.1 -o pause.tar ``` Then load the container image into the container runtime: ```console -$ sudo ctrcri load pause.tar +$ sudo ctr cri load pause.tar Loaded image: k8s.gcr.io/pause-amd64:3.1 ``` List images and inspect the pause image: diff --git a/hack/release.sh b/hack/release.sh index bf14945c7..7976febae 100755 --- a/hack/release.sh +++ b/hack/release.sh @@ -40,11 +40,8 @@ rm -rf ${destdir} # Install dependencies into release stage. NOSUDO=true INSTALL_CNI=${INCLUDE_CNI} DESTDIR=${destdir} ./hack/install-deps.sh -# Install ctrcri into release stage. -make install-ctrcri -e DESTDIR=${destdir} - if ${CUSTOM_CONTAINERD}; then - make install-containerd -e DESTDIR=${destdir} + make install -e DESTDIR=${destdir} fi # Install systemd units into release stage. diff --git a/pkg/version/version.go b/pkg/version/version.go deleted file mode 100644 index ca95133d1..000000000 --- a/pkg/version/version.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 2017 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package version - -import ( - "fmt" - - "github.com/blang/semver" -) - -// CRIContainerdVersion is the version of the cri plugin. -var CRIContainerdVersion = "UNKNOWN" - -func validateSemver(sv string) error { - _, err := semver.Parse(sv) - if err != nil { - return fmt.Errorf("couldn't parse version %q: %v", sv, err) - } - return nil -} - -// PrintVersion outputs the release version of containerd/cri -func PrintVersion() { - err := validateSemver(CRIContainerdVersion) - if err != nil { - fmt.Println(err) - } - fmt.Println(CRIContainerdVersion) -} diff --git a/vendor.conf b/vendor.conf index 73d63e523..eb5cfe90e 100644 --- a/vendor.conf +++ b/vendor.conf @@ -4,7 +4,7 @@ github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130 github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e -github.com/containerd/containerd 3013762fc58941e33ba70e8f8d9256911f134124 +github.com/containerd/containerd 3c1ef1a714cf5b0104f340f76d539802fc24c75f github.com/containerd/continuity d8fb8589b0e8e85b8c8bbaa8840226d0dfeb7371 github.com/containerd/fifo fbfb6a11ec671efbe94ad1c12c2e98773f19e1e6 github.com/containerd/go-runc 4f6e87ae043f859a38255247b49c9abc262d002f @@ -31,7 +31,6 @@ github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 github.com/json-iterator/go 1.0.4 github.com/matttproud/golang_protobuf_extensions v1.0.0 github.com/Microsoft/go-winio v0.4.5 @@ -48,10 +47,8 @@ github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823 github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563 github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd -github.com/renstrom/dedent 020d11c3b9c0c7a3c2efcc8e5cf5b9ef7bcea21f github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 github.com/sirupsen/logrus v1.0.0 -github.com/spf13/cobra v0.0.1 github.com/spf13/pflag v1.0.0 github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577 github.com/stretchr/testify v1.1.4 diff --git a/vendor/github.com/containerd/containerd/client.go b/vendor/github.com/containerd/containerd/client.go index 1ec0eb549..7aebd1ced 100644 --- a/vendor/github.com/containerd/containerd/client.go +++ b/vendor/github.com/containerd/containerd/client.go @@ -43,7 +43,6 @@ import ( "github.com/containerd/containerd/events" "github.com/containerd/containerd/images" "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" @@ -236,6 +235,10 @@ type RemoteContext struct { // If no resolver is provided, defaults to Docker registry resolver. Resolver remotes.Resolver + // Platforms defines which platforms to handle when doing the image operation. + // If this field is empty, content for all platforms will be pulled. + Platforms []string + // Unpack is done after an image is pulled to extract into a snapshotter. // If an image is not unpacked on pull, it can be unpacked any time // afterwards. Unpacking is required to run an image. @@ -287,6 +290,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image if err != nil { return nil, errors.Wrapf(err, "failed to resolve reference %q", ref) } + fetcher, err := pullCtx.Resolver.Fetcher(ctx, name) if err != nil { return nil, errors.Wrapf(err, "failed to get fetcher for %q", name) @@ -304,8 +308,8 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image childrenHandler := images.ChildrenHandler(store) // Set any children labels for that content childrenHandler = images.SetChildrenLabels(store, childrenHandler) - // Filter the childen by the platform - childrenHandler = images.FilterPlatform(platforms.Default(), childrenHandler) + // Filter childen by platforms + childrenHandler = images.FilterPlatforms(childrenHandler, pullCtx.Platforms...) handler = images.Handlers(append(pullCtx.BaseHandlers, remotes.FetchHandler(store, fetcher), @@ -371,7 +375,7 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, return err } - return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.BaseHandlers...) + return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.Platforms, pushCtx.BaseHandlers...) } // GetImage returns an existing image diff --git a/vendor/github.com/containerd/containerd/client_opts.go b/vendor/github.com/containerd/containerd/client_opts.go index 1859c4865..52f670d75 100644 --- a/vendor/github.com/containerd/containerd/client_opts.go +++ b/vendor/github.com/containerd/containerd/client_opts.go @@ -64,6 +64,21 @@ func WithServices(opts ...ServicesOpt) ClientOpt { // RemoteOpt allows the caller to set distribution options for a remote type RemoteOpt func(*Client, *RemoteContext) error +// WithPlatform allows the caller to specify a platform to retrieve +// content for +func WithPlatform(platform string) RemoteOpt { + return func(_ *Client, c *RemoteContext) error { + for _, p := range c.Platforms { + if p == platform { + return nil + } + } + + c.Platforms = append(c.Platforms, platform) + return nil + } +} + // WithPullUnpack is used to unpack an image after pull. This // uses the snapshotter, content store, and diff service // configured for the client. diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/command/main.go b/vendor/github.com/containerd/containerd/cmd/ctr/command/main.go new file mode 100644 index 000000000..8fd1a5a51 --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/command/main.go @@ -0,0 +1,113 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import ( + "fmt" + "io/ioutil" + "log" + + "github.com/containerd/containerd/cmd/ctr/commands/containers" + "github.com/containerd/containerd/cmd/ctr/commands/content" + "github.com/containerd/containerd/cmd/ctr/commands/events" + "github.com/containerd/containerd/cmd/ctr/commands/images" + namespacesCmd "github.com/containerd/containerd/cmd/ctr/commands/namespaces" + "github.com/containerd/containerd/cmd/ctr/commands/plugins" + "github.com/containerd/containerd/cmd/ctr/commands/pprof" + "github.com/containerd/containerd/cmd/ctr/commands/run" + "github.com/containerd/containerd/cmd/ctr/commands/snapshots" + "github.com/containerd/containerd/cmd/ctr/commands/tasks" + versionCmd "github.com/containerd/containerd/cmd/ctr/commands/version" + "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/version" + "github.com/sirupsen/logrus" + "github.com/urfave/cli" + "google.golang.org/grpc/grpclog" +) + +var extraCmds = []cli.Command{} + +func init() { + // Discard grpc logs so that they don't mess with our stdio + grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags)) + + cli.VersionPrinter = func(c *cli.Context) { + fmt.Println(c.App.Name, version.Package, c.App.Version) + } +} + +// App returns a *cli.App instance. +func App() *cli.App { + app := cli.NewApp() + app.Name = "ctr" + app.Version = version.Version + app.Usage = ` + __ + _____/ /______ + / ___/ __/ ___/ +/ /__/ /_/ / +\___/\__/_/ + +containerd CLI +` + app.Flags = []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + Usage: "enable debug output in logs", + }, + cli.StringFlag{ + Name: "address, a", + Usage: "address for containerd's GRPC server", + Value: defaults.DefaultAddress, + }, + cli.DurationFlag{ + Name: "timeout", + Usage: "total timeout for ctr commands", + }, + cli.DurationFlag{ + Name: "connect-timeout", + Usage: "timeout for connecting to containerd", + }, + cli.StringFlag{ + Name: "namespace, n", + Usage: "namespace to use with commands", + Value: namespaces.Default, + EnvVar: namespaces.NamespaceEnvVar, + }, + } + app.Commands = append([]cli.Command{ + plugins.Command, + versionCmd.Command, + containers.Command, + content.Command, + events.Command, + images.Command, + namespacesCmd.Command, + pprof.Command, + run.Command, + snapshots.Command, + tasks.Command, + }, extraCmds...) + app.Before = func(context *cli.Context) error { + if context.GlobalBool("debug") { + logrus.SetLevel(logrus.DebugLevel) + } + return nil + } + return app +} diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/command/main_unix.go b/vendor/github.com/containerd/containerd/cmd/ctr/command/main_unix.go new file mode 100644 index 000000000..80f2f41dc --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/command/main_unix.go @@ -0,0 +1,25 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package command + +import "github.com/containerd/containerd/cmd/ctr/commands/shim" + +func init() { + extraCmds = append(extraCmds, shim.Command) +} diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go new file mode 100644 index 000000000..e940aea66 --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/client.go @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +import ( + gocontext "context" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/namespaces" + "github.com/urfave/cli" +) + +// 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(context *cli.Context) (gocontext.Context, gocontext.CancelFunc) { + var ( + ctx = gocontext.Background() + timeout = context.GlobalDuration("timeout") + namespace = context.GlobalString("namespace") + cancel gocontext.CancelFunc + ) + ctx = namespaces.WithNamespace(ctx, namespace) + if timeout > 0 { + ctx, cancel = gocontext.WithTimeout(ctx, timeout) + } else { + ctx, cancel = gocontext.WithCancel(ctx) + } + return ctx, cancel +} + +// NewClient returns a new containerd client +func NewClient(context *cli.Context) (*containerd.Client, gocontext.Context, gocontext.CancelFunc, error) { + client, err := containerd.New(context.GlobalString("address")) + if err != nil { + return nil, nil, nil, err + } + ctx, cancel := AppContext(context) + return client, ctx, cancel, nil +} diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go new file mode 100644 index 000000000..1a0c3b6b3 --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/commands.go @@ -0,0 +1,121 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package commands + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "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 default value.", + Value: containerd.DefaultSnapshotter, + EnvVar: "CONTAINERD_SNAPSHOTTER", + }, + } + + // 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)) +} + +// WritePidFile writes the pid atomically to a file +func WritePidFile(path string, pid int) error { + path, err := filepath.Abs(path) + if err != nil { + return err + } + tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) + f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666) + if err != nil { + return err + } + _, err = fmt.Fprintf(f, "%d", pid) + f.Close() + if err != nil { + return err + } + return os.Rename(tempPath, path) +} diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/containers/containers.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/containers/containers.go new file mode 100644 index 000000000..05d0d7e2f --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/containers/containers.go @@ -0,0 +1,257 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containers + +import ( + "context" + "errors" + "fmt" + "os" + "strings" + "text/tabwriter" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/cmd/ctr/commands/run" + "github.com/containerd/containerd/log" + "github.com/urfave/cli" +) + +// Command is the cli command for managing containers +var Command = cli.Command{ + Name: "containers", + Usage: "manage containers", + Aliases: []string{"c", "container"}, + Subcommands: []cli.Command{ + createCommand, + deleteCommand, + infoCommand, + listCommand, + setLabelsCommand, + }, +} + +var createCommand = cli.Command{ + Name: "create", + Usage: "create container", + ArgsUsage: "[flags] Image|RootFS CONTAINER", + Flags: append(commands.SnapshotterFlags, run.ContainerFlags...), + Action: func(context *cli.Context) error { + var ( + id = context.Args().Get(1) + ref = context.Args().First() + ) + if ref == "" { + return errors.New("image ref must be provided") + } + if id == "" { + return errors.New("container id must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + _, err = run.NewContainer(ctx, client, context) + if err != nil { + return err + } + return nil + }, +} + +var listCommand = cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "list containers", + ArgsUsage: "[flags] [, ...]", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "quiet, q", + Usage: "print only the container id", + }, + }, + Action: func(context *cli.Context) error { + var ( + filters = context.Args() + quiet = context.Bool("quiet") + ) + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + containers, err := client.Containers(ctx, filters...) + if err != nil { + return err + } + if quiet { + for _, c := range containers { + fmt.Printf("%s\n", c.ID()) + } + return nil + } + w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) + fmt.Fprintln(w, "CONTAINER\tIMAGE\tRUNTIME\t") + for _, c := range containers { + info, err := c.Info(ctx) + if err != nil { + return err + } + imageName := info.Image + if imageName == "" { + imageName = "-" + } + if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t\n", + c.ID(), + imageName, + info.Runtime.Name, + ); err != nil { + return err + } + } + return w.Flush() + }, +} + +var deleteCommand = cli.Command{ + Name: "delete", + Usage: "delete one or more existing containers", + ArgsUsage: "[flags] CONTAINER [CONTAINER, ...]", + Aliases: []string{"del", "rm"}, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "keep-snapshot", + Usage: "do not clean up snapshot with container", + }, + }, + Action: func(context *cli.Context) error { + var exitErr error + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + deleteOpts := []containerd.DeleteOpts{} + if !context.Bool("keep-snapshot") { + deleteOpts = append(deleteOpts, containerd.WithSnapshotCleanup) + } + + if context.NArg() == 0 { + return errors.New("must specify at least one container to delete") + } + for _, arg := range context.Args() { + if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil { + if exitErr == nil { + exitErr = err + } + log.G(ctx).WithError(err).Errorf("failed to delete container %q", arg) + } + } + + return exitErr + }, +} + +func deleteContainer(ctx context.Context, client *containerd.Client, id string, opts ...containerd.DeleteOpts) error { + container, err := client.LoadContainer(ctx, id) + if err != nil { + return err + } + task, err := container.Task(ctx, nil) + if err != nil { + return container.Delete(ctx, opts...) + } + status, err := task.Status(ctx) + if err != nil { + return err + } + if status.Status == containerd.Stopped || status.Status == containerd.Created { + if _, err := task.Delete(ctx); err != nil { + return err + } + return container.Delete(ctx, opts...) + } + return fmt.Errorf("cannot delete a non stopped container: %v", status) + +} + +var setLabelsCommand = cli.Command{ + Name: "label", + Usage: "set and clear labels for a container", + ArgsUsage: "[flags] CONTAINER [=, ...]", + Description: "set and clear labels for a container", + Flags: []cli.Flag{}, + Action: func(context *cli.Context) error { + containerID, labels := commands.ObjectWithLabelArgs(context) + if containerID == "" { + return errors.New("container id must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + container, err := client.LoadContainer(ctx, containerID) + if err != nil { + return err + } + + setlabels, err := container.SetLabels(ctx, labels) + if err != nil { + return err + } + + var labelStrings []string + for k, v := range setlabels { + labelStrings = append(labelStrings, fmt.Sprintf("%s=%s", k, v)) + } + + fmt.Println(strings.Join(labelStrings, ",")) + + return nil + }, +} + +var infoCommand = cli.Command{ + Name: "info", + Usage: "get info about a container", + ArgsUsage: "CONTAINER", + Action: func(context *cli.Context) error { + id := context.Args().First() + if id == "" { + return errors.New("container id must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + container, err := client.LoadContainer(ctx, id) + if err != nil { + return err + } + info, err := container.Info(ctx) + if err != nil { + return err + } + commands.PrintAsJSON(info) + + return nil + }, +} diff --git a/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go new file mode 100644 index 000000000..6e4b26a14 --- /dev/null +++ b/vendor/github.com/containerd/containerd/cmd/ctr/commands/content/content.go @@ -0,0 +1,560 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package content + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "strings" + "text/tabwriter" + "time" + + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + units "github.com/docker/go-units" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var ( + // Command is the cli command for managing content + Command = cli.Command{ + Name: "content", + Usage: "manage content", + Subcommands: cli.Commands{ + activeIngestCommand, + deleteCommand, + editCommand, + fetchCommand, + fetchObjectCommand, + getCommand, + ingestCommand, + listCommand, + pushObjectCommand, + setLabelsCommand, + }, + } + + getCommand = cli.Command{ + Name: "get", + Usage: "get the data for an object", + ArgsUsage: "[, ...]", + Description: "display the image object", + Action: func(context *cli.Context) error { + dgst, err := digest.Parse(context.Args().First()) + if err != nil { + return err + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + cs := client.ContentStore() + ra, err := cs.ReaderAt(ctx, dgst) + if err != nil { + return err + } + defer ra.Close() + + _, err = io.Copy(os.Stdout, content.NewReader(ra)) + return err + }, + } + + ingestCommand = cli.Command{ + Name: "ingest", + Usage: "accept content into the store", + ArgsUsage: "[flags] ", + Description: "ingest objects into the local content store", + Flags: []cli.Flag{ + cli.Int64Flag{ + Name: "expected-size", + Usage: "validate against provided size", + }, + cli.StringFlag{ + Name: "expected-digest", + Usage: "verify content against expected digest", + }, + }, + Action: func(context *cli.Context) error { + var ( + ref = context.Args().First() + expectedSize = context.Int64("expected-size") + expectedDigest = digest.Digest(context.String("expected-digest")) + ) + if err := expectedDigest.Validate(); expectedDigest != "" && err != nil { + return err + } + if ref == "" { + return errors.New("must specify a transaction reference") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + cs := client.ContentStore() + + // TODO(stevvooe): Allow ingest to be reentrant. Currently, we expect + // all data to be written in a single invocation. Allow multiple writes + // to the same transaction key followed by a commit. + return content.WriteBlob(ctx, cs, ref, os.Stdin, expectedSize, expectedDigest) + }, + } + + activeIngestCommand = cli.Command{ + Name: "active", + Usage: "display active transfers", + ArgsUsage: "[flags] []", + Description: "display the ongoing transfers", + Flags: []cli.Flag{ + cli.DurationFlag{ + Name: "timeout, t", + Usage: "total timeout for fetch", + EnvVar: "CONTAINERD_FETCH_TIMEOUT", + }, + cli.StringFlag{ + Name: "root", + Usage: "path to content store root", + Value: "/tmp/content", // TODO(stevvooe): for now, just use the PWD/.content + }, + }, + Action: func(context *cli.Context) error { + match := context.Args().First() + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + cs := client.ContentStore() + active, err := cs.ListStatuses(ctx, match) + if err != nil { + return err + } + tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0) + fmt.Fprintln(tw, "REF\tSIZE\tAGE\t") + for _, active := range active { + fmt.Fprintf(tw, "%s\t%s\t%s\t\n", + active.Ref, + units.HumanSize(float64(active.Offset)), + units.HumanDuration(time.Since(active.StartedAt))) + } + + return tw.Flush() + }, + } + + listCommand = cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "list all blobs in the store", + ArgsUsage: "[flags]", + Description: "list blobs in the content store", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "quiet, q", + Usage: "print only the blob digest", + }, + }, + Action: func(context *cli.Context) error { + var ( + quiet = context.Bool("quiet") + args = []string(context.Args()) + ) + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + cs := client.ContentStore() + + var walkFn content.WalkFunc + if quiet { + walkFn = func(info content.Info) error { + fmt.Println(info.Digest) + return nil + } + } else { + tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0) + defer tw.Flush() + + fmt.Fprintln(tw, "DIGEST\tSIZE\tAGE\tLABELS") + walkFn = func(info content.Info) error { + var labelStrings []string + for k, v := range info.Labels { + labelStrings = append(labelStrings, strings.Join([]string{k, v}, "=")) + } + labels := strings.Join(labelStrings, ",") + if labels == "" { + labels = "-" + } + + fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", + info.Digest, + units.HumanSize(float64(info.Size)), + units.HumanDuration(time.Since(info.CreatedAt)), + labels) + return nil + } + + } + + return cs.Walk(ctx, walkFn, args...) + }, + } + + setLabelsCommand = cli.Command{ + Name: "label", + Usage: "add labels to content", + ArgsUsage: " [