diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/commands.go | 11 | ||||
-rw-r--r-- | cmd/podman/commit.go | 12 | ||||
-rw-r--r-- | cmd/podman/common.go | 4 | ||||
-rw-r--r-- | cmd/podman/images.go | 59 | ||||
-rw-r--r-- | cmd/podman/libpodruntime/runtime.go | 58 | ||||
-rw-r--r-- | cmd/podman/ps.go | 10 | ||||
-rw-r--r-- | cmd/podman/pull.go | 111 | ||||
-rw-r--r-- | cmd/podman/shared/container.go | 5 | ||||
-rw-r--r-- | cmd/podman/shared/create.go | 24 | ||||
-rw-r--r-- | cmd/podman/shared/intermediate.go | 1 |
10 files changed, 165 insertions, 130 deletions
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index ebd7aeb0c..d6018a6f4 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -26,9 +26,6 @@ func getMainCommands() []*cobra.Command { if len(_varlinkCommand.Use) > 0 { rootCommands = append(rootCommands, _varlinkCommand) } - if len(_serviceCommand.Use) > 0 { - rootCommands = append(rootCommands, _serviceCommand) - } return rootCommands } @@ -71,9 +68,15 @@ func getTrustSubCommands() []*cobra.Command { // Commands that the local client implements func getSystemSubCommands() []*cobra.Command { - return []*cobra.Command{ + systemCommands := []*cobra.Command{ _renumberCommand, _dfSystemCommand, _migrateCommand, } + + if len(_serviceCommand.Use) > 0 { + systemCommands = append(systemCommands, _serviceCommand) + } + + return systemCommands } diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go index 604e8d31c..b4d249c66 100644 --- a/cmd/podman/commit.go +++ b/cmd/podman/commit.go @@ -6,7 +6,6 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/pkg/adapter" - "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -65,17 +64,6 @@ func commitCmd(c *cliconfig.CommitValues) error { if len(args) > 1 { reference = args[1] } - if c.Flag("change").Changed { - for _, change := range c.Change { - splitChange := strings.Split(strings.ToUpper(change), "=") - if len(splitChange) == 1 { - splitChange = strings.Split(strings.ToUpper(change), " ") - } - if !util.StringInSlice(splitChange[0], ChangeCmds) { - return errors.Errorf("invalid syntax for --change: %s", change) - } - } - } iid, err := runtime.Commit(getContext(), c, container, reference) if err != nil { diff --git a/cmd/podman/common.go b/cmd/podman/common.go index 7610edbc0..6fa2b3c71 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -257,6 +257,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) { "Add a host device to the container (default [])", ) createFlags.StringSlice( + "device-cgroup-rule", []string{}, + "Add a rule to the cgroup allowed devices list", + ) + createFlags.StringSlice( "device-read-bps", []string{}, "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)", ) diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 115f30d9b..de61690ae 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -21,16 +21,16 @@ import ( ) type imagesTemplateParams struct { - Repository string - Tag string - ID string - Digest digest.Digest - Digests []digest.Digest - Created string - CreatedTime time.Time - Size string - ReadOnly bool - History string + Repository string + Tag string + ID string + Digest digest.Digest + Digests []digest.Digest + CreatedAt time.Time + CreatedSince string + Size string + ReadOnly bool + History string } type imagesJSONParams struct { @@ -65,7 +65,7 @@ func (a imagesSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type imagesSortedCreated struct{ imagesSorted } func (a imagesSortedCreated) Less(i, j int) bool { - return a.imagesSorted[i].CreatedTime.After(a.imagesSorted[j].CreatedTime) + return a.imagesSorted[i].CreatedAt.After(a.imagesSorted[j].CreatedAt) } type imagesSortedID struct{ imagesSorted } @@ -185,7 +185,17 @@ func imagesCmd(c *cliconfig.ImagesValues) error { history: c.History, } - opts.outputformat = opts.setOutputFormat() + outputformat := opts.setOutputFormat() + // These fields were renamed, so we need to provide backward compat for + // the old names. + if strings.Contains(outputformat, "{{.Created}}") { + outputformat = strings.Replace(outputformat, "{{.Created}}", "{{.CreatedSince}}", -1) + } + if strings.Contains(outputformat, "{{.CreatedTime}}") { + outputformat = strings.Replace(outputformat, "{{.CreatedTime}}", "{{.CreatedAt}}", -1) + } + opts.outputformat = outputformat + filteredImages, err := runtime.GetFilteredImages(filters, false) if err != nil { return errors.Wrapf(err, "unable to get images") @@ -216,7 +226,7 @@ func (i imagesOptions) setOutputFormat() string { if i.digests { format += "{{.Digest}}\t" } - format += "{{.ID}}\t{{.Created}}\t{{.Size}}\t" + format += "{{.ID}}\t{{.CreatedSince}}\t{{.Size}}\t" if i.history { format += "{{if .History}}{{.History}}{{else}}<none>{{end}}\t" } @@ -301,16 +311,16 @@ func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerIma imageDigest = img.Digest() } params := imagesTemplateParams{ - Repository: repo, - Tag: tag, - ID: imageID, - Digest: imageDigest, - Digests: img.Digests(), - CreatedTime: createdTime, - Created: units.HumanDuration(time.Since(createdTime)) + " ago", - Size: sizeStr, - ReadOnly: img.IsReadOnly(), - History: strings.Join(img.NamesHistory(), ", "), + Repository: repo, + Tag: tag, + ID: imageID, + Digest: imageDigest, + Digests: img.Digests(), + CreatedAt: createdTime, + CreatedSince: units.HumanDuration(time.Since(createdTime)) + " ago", + Size: sizeStr, + ReadOnly: img.IsReadOnly(), + History: strings.Join(img.NamesHistory(), ", "), } imagesOutput = append(imagesOutput, params) if opts.quiet { // Show only one image ID when quiet @@ -384,6 +394,9 @@ func GenImageOutputMap() map[string]string { values[key] = "R/O" continue } + if value == "CreatedSince" { + value = "created" + } values[key] = strings.ToUpper(splitCamelCase(value)) } return values diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index 9425cfb9c..e9dc87de1 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -13,32 +13,66 @@ import ( "github.com/pkg/errors" ) +type runtimeOptions struct { + name string + renumber bool + migrate bool + noStore bool + withFDS bool +} + // GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand, newRuntime string) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, true, false, true, newRuntime) + return getRuntime(ctx, c, &runtimeOptions{ + name: newRuntime, + renumber: false, + migrate: true, + noStore: false, + withFDS: true, + }) } // GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify func GetRuntimeDisableFDs(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, false, false, "") + return getRuntime(ctx, c, &runtimeOptions{ + renumber: false, + migrate: false, + noStore: false, + withFDS: false, + }) } // GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, true, false, false, true, "") + return getRuntime(ctx, c, &runtimeOptions{ + renumber: true, + migrate: false, + noStore: false, + withFDS: true, + }) } // GetRuntime generates a new libpod runtime configured by command line options func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, false, true, "") + return getRuntime(ctx, c, &runtimeOptions{ + renumber: false, + migrate: false, + noStore: false, + withFDS: true, + }) } // GetRuntimeNoStore generates a new libpod runtime configured by command line options func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, true, true, "") + return getRuntime(ctx, c, &runtimeOptions{ + renumber: false, + migrate: false, + noStore: true, + withFDS: true, + }) } -func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore, withFDS bool, newRuntime string) (*libpod.Runtime, error) { +func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, opts *runtimeOptions) (*libpod.Runtime, error) { options := []libpod.RuntimeOption{} storageOpts := storage.StoreOptions{} storageSet := false @@ -86,14 +120,14 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migra storageSet = true storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts } - if migrate { + if opts.migrate { options = append(options, libpod.WithMigrate()) - if newRuntime != "" { - options = append(options, libpod.WithMigrateRuntime(newRuntime)) + if opts.name != "" { + options = append(options, libpod.WithMigrateRuntime(opts.name)) } } - if renumber { + if opts.renumber { options = append(options, libpod.WithRenumber()) } @@ -102,7 +136,7 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migra options = append(options, libpod.WithStorageConfig(storageOpts)) } - if !storageSet && noStore { + if !storageSet && opts.noStore { options = append(options, libpod.WithNoStore()) } // TODO CLI flags for image config? @@ -174,7 +208,7 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migra options = append(options, libpod.WithDefaultInfraCommand(infraCommand)) } - if !withFDS { + if !opts.withFDS { options = append(options, libpod.WithEnableSDNotify()) } if c.Flags().Changed("config") { diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index d93ccc24c..accd5b51a 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -205,9 +205,15 @@ func checkFlagsPassed(c *cliconfig.PsValues) error { if c.Last >= 0 && c.Latest { return errors.Errorf("last and latest are mutually exclusive") } - // Filter forces all + // Filter on status forces all if len(c.Filter) > 0 { - c.All = true + for _, filter := range c.Filter { + splitFilter := strings.SplitN(filter, "=", 2) + if strings.ToLower(splitFilter[0]) == "status" { + c.All = true + break + } + } } // Quiet conflicts with size and namespace and is overridden by a Go // template. diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 1cbb3f45e..f800d68fe 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "os" - "strings" buildahcli "github.com/containers/buildah/pkg/cli" "github.com/containers/image/v5/docker" @@ -15,6 +14,7 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" + "github.com/docker/distribution/reference" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -101,18 +101,32 @@ func pullCmd(c *cliconfig.PullValues) (retError error) { } } - arr := strings.SplitN(args[0], ":", 2) - if len(arr) == 2 { - if c.Bool("all-tags") { - return errors.Errorf("tag can't be used with --all-tags") + ctx := getContext() + imageName := args[0] + + imageRef, err := alltransports.ParseImageName(imageName) + if err != nil { + imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s://%s", docker.Transport.Name(), imageName)) + if err != nil { + return errors.Errorf("invalid image reference %q", imageName) } } - ctx := getContext() - imgArg := args[0] + var writer io.Writer + if !c.Quiet { + writer = os.Stderr + } + // Special-case for docker-archive which allows multiple tags. + if imageRef.Transport().Name() == dockerarchive.Transport.Name() { + newImage, err := runtime.LoadFromArchiveReference(getContext(), imageRef, c.SignaturePolicy, writer) + if err != nil { + return errors.Wrapf(err, "error pulling image %q", imageName) + } + fmt.Println(newImage[0].ID()) + return nil + } var registryCreds *types.DockerAuthConfig - if c.Flag("creds").Changed { creds, err := util.ParseRegistryCreds(c.Creds) if err != nil { @@ -120,14 +134,6 @@ func pullCmd(c *cliconfig.PullValues) (retError error) { } registryCreds = creds } - - var ( - writer io.Writer - ) - if !c.Quiet { - writer = os.Stderr - } - dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: registryCreds, DockerCertPath: c.CertDir, @@ -138,79 +144,52 @@ func pullCmd(c *cliconfig.PullValues) (retError error) { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) } - // Special-case for docker-archive which allows multiple tags. - if strings.HasPrefix(imgArg, dockerarchive.Transport.Name()+":") { - srcRef, err := alltransports.ParseImageName(imgArg) - if err != nil { - return errors.Wrapf(err, "error parsing %q", imgArg) - } - newImage, err := runtime.LoadFromArchiveReference(getContext(), srcRef, c.SignaturePolicy, writer) - if err != nil { - return errors.Wrapf(err, "error pulling image from %q", imgArg) - } - fmt.Println(newImage[0].ID()) - - return nil - } - - // FIXME: the default pull consults the registries.conf's search registries - // while the all-tags pull does not. This behavior must be fixed in the - // future and span across c/buildah, c/image and c/libpod to avoid redundant - // and error prone code. - // - // See https://bugzilla.redhat.com/show_bug.cgi?id=1701922 for background - // information. if !c.Bool("all-tags") { - newImage, err := runtime.New(getContext(), imgArg, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) + newImage, err := runtime.New(getContext(), imageName, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) if err != nil { - return errors.Wrapf(err, "error pulling image %q", imgArg) + return errors.Wrapf(err, "error pulling image %q", imageName) } fmt.Println(newImage.ID()) return nil } - // FIXME: all-tags should use the libpod backend instead of baking its own bread. - spec := imgArg - systemContext := image.GetSystemContext("", c.Authfile, false) - srcRef, err := alltransports.ParseImageName(spec) + // --all-tags requires the docker transport + if imageRef.Transport().Name() != docker.Transport.Name() { + return errors.New("--all-tags requires docker transport") + } + + // all-tags doesn't work with a tagged reference, so let's check early + namedRef, err := reference.Parse(imageName) if err != nil { - dockerTransport := "docker://" - logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, dockerTransport, err) - spec = dockerTransport + spec - srcRef2, err2 := alltransports.ParseImageName(spec) - if err2 != nil { - return errors.Wrapf(err2, "error parsing image name %q", imgArg) - } - srcRef = srcRef2 + return errors.Wrapf(err, "error parsing %q", imageName) } - var names []string - if srcRef.DockerReference() == nil { - return errors.New("Non-docker transport is currently not supported") + if _, isTagged := namedRef.(reference.Tagged); isTagged { + return errors.New("--all-tags requires a reference without a tag") + } - tags, err := docker.GetRepositoryTags(ctx, systemContext, srcRef) + + systemContext := image.GetSystemContext("", c.Authfile, false) + tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef) if err != nil { return errors.Wrapf(err, "error getting repository tags") } - for _, tag := range tags { - name := spec + ":" + tag - names = append(names, name) - } var foundIDs []string - foundImage := true - for _, name := range names { + for _, tag := range tags { + name := imageName + ":" + tag newImage, err := runtime.New(getContext(), name, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) if err != nil { logrus.Errorf("error pulling image %q", name) - foundImage = false continue } foundIDs = append(foundIDs, newImage.ID()) } - if len(names) == 1 && !foundImage { - return errors.Wrapf(err, "error pulling image %q", imgArg) + + if len(tags) != len(foundIDs) { + return errors.Errorf("error pulling image %q", imageName) } - if len(names) > 1 { + + if len(foundIDs) > 1 { fmt.Println("Pulled Images:") } for _, id := range foundIDs { diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index 9459247ed..ff3846e70 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -640,6 +640,11 @@ func GetNamespaces(pid int) *Namespace { } } +// GetNamespaceInfo is an exported wrapper for getNamespaceInfo +func GetNamespaceInfo(path string) (string, error) { + return getNamespaceInfo(path) +} + func getNamespaceInfo(path string) (string, error) { val, err := os.Readlink(path) if err != nil { diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 2f637694b..be5adcccb 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -22,6 +22,7 @@ import ( "github.com/containers/libpod/pkg/inspect" ns "github.com/containers/libpod/pkg/namespaces" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/seccomp" cc "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/util" "github.com/docker/go-connections/nat" @@ -31,10 +32,6 @@ import ( "github.com/sirupsen/logrus" ) -// seccompLabelKey is the key of the image annotation embedding a seccomp -// profile. -const seccompLabelKey = "io.containers.seccomp.profile" - func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) { var ( healthCheck *manifest.Schema2HealthConfig @@ -109,11 +106,11 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. } if overrideOS == "" && imageData.Os != goruntime.GOOS { - return nil, nil, errors.Errorf("incompatible image OS %q on %q host", imageData.Os, goruntime.GOOS) + logrus.Infof("Using %q (OS) image on %q host", imageData.Os, goruntime.GOOS) } if overrideArch == "" && imageData.Architecture != goruntime.GOARCH { - return nil, nil, errors.Errorf("incompatible image architecture %q on %q host", imageData.Architecture, goruntime.GOARCH) + logrus.Infof("Using %q (architecture) on %q host", imageData.Architecture, goruntime.GOARCH) } names := newImage.Names() @@ -309,9 +306,13 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. } } if c.String("memory-swap") != "" { - memorySwap, err = units.RAMInBytes(c.String("memory-swap")) - if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory-swap") + if c.String("memory-swap") == "-1" { + memorySwap = -1 + } else { + memorySwap, err = units.RAMInBytes(c.String("memory-swap")) + if err != nil { + return nil, errors.Wrapf(err, "invalid value for memory-swap") + } } } if c.String("kernel-memory") != "" { @@ -709,11 +710,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. // SECCOMP if data != nil { - if value, exists := labels[seccompLabelKey]; exists { + if value, exists := labels[seccomp.ContainerImageLabel]; exists { secConfig.SeccompProfileFromImage = value } } - if policy, err := cc.LookupSeccompPolicy(c.String("seccomp-policy")); err != nil { + if policy, err := seccomp.LookupPolicy(c.String("seccomp-policy")); err != nil { return nil, err } else { secConfig.SeccompPolicy = policy @@ -757,6 +758,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. CPURtPeriod: c.Uint64("cpu-rt-period"), CPURtRuntime: c.Int64("cpu-rt-runtime"), CPUs: c.Float64("cpus"), + DeviceCgroupRules: c.StringSlice("device-cgroup-rule"), DeviceReadBps: c.StringSlice("device-read-bps"), DeviceReadIOps: c.StringSlice("device-read-iops"), DeviceWriteBps: c.StringSlice("device-write-bps"), diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go index cfb3f612c..ee212234f 100644 --- a/cmd/podman/shared/intermediate.go +++ b/cmd/podman/shared/intermediate.go @@ -386,6 +386,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes m["detach"] = newCRBool(c, "detach") m["detach-keys"] = newCRString(c, "detach-keys") m["device"] = newCRStringSlice(c, "device") + m["device-cgroup-rule"] = newCRStringSlice(c, "device-cgroup-rule") m["device-read-bps"] = newCRStringSlice(c, "device-read-bps") m["device-read-iops"] = newCRStringSlice(c, "device-read-iops") m["device-write-bps"] = newCRStringSlice(c, "device-write-bps") |