diff options
32 files changed, 287 insertions, 154 deletions
diff --git a/.gitignore b/.gitignore index d5d1206b5..e60b8c03a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,33 @@ /.artifacts/ -/_output/ +/bin/ /brew +/build/ +/cmd/podman/varlink/iopodman.go +/cmd/podman/varlink/ioprojectatomicpodman.go /conmon/ +contrib/spec/podman.spec +*.coverprofile /docs/*.[158] /docs/*.[158].gz -/docs/remote /docs/build/ +/docs/remote +.gopathok +.idea* +.nfs* *.o *.orig +/_output/ /pause/pause.o -/bin/ +pkg/api/swagger.yaml +/pkg/varlink/iopodman.go +podman-remote*.zip +podman*.tar.gz +__pycache__ +release.txt +.ropeproject +*.rpm /test/bin2img/bin2img /test/checkseccomp/checkseccomp /test/copyimg/copyimg /test/goecho/goecho -/build/ -.nfs* -.ropeproject -__pycache__ -/cmd/podman/varlink/ioprojectatomicpodman.go -/cmd/podman/varlink/iopodman.go -/pkg/varlink/iopodman.go -.gopathok -release.txt -podman-remote*.zip -podman*.tar.gz -.idea* .vscode* -contrib/spec/podman.spec -*.rpm -*.coverprofile diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index abec1213c..488843f41 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -209,10 +209,15 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string } } - s.IDMappings, err = util.ParseIDMapping(ns.UsernsMode(c.UserNS), c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) + userNS := ns.UsernsMode(c.UserNS) + s.IDMappings, err = util.ParseIDMapping(userNS, c.UIDMap, c.GIDMap, c.SubUIDName, c.SubGIDName) if err != nil { return err } + // If some mappings are specified, assume a private user namespace + if userNS.IsDefaultValue() && (!s.IDMappings.HostUIDMapping || !s.IDMappings.HostGIDMapping) { + s.UserNS.NSMode = specgen.Private + } s.Terminal = c.TTY ep, err := ExposedPorts(c.Expose, c.Net.PublishPorts, c.PublishAll, nil) @@ -246,20 +251,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.NetNS = c.Net.Network } - // TODO this is going to have to be done the libpod/server end of things - // USER - //user := c.String("user") - //if user == "" { - // switch { - // case usernsMode.IsKeepID(): - // user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID()) - // case data == nil: - // user = "0" - // default: - // user = data.Config.User - // } - //} - // STOP SIGNAL signalString := "TERM" if sig := c.StopSignal; len(sig) > 0 { diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go index 73f37e51f..381bf8e26 100644 --- a/cmd/podman/containers/start.go +++ b/cmd/podman/containers/start.go @@ -20,7 +20,6 @@ var ( Short: "Start one or more containers", Long: startDescription, RunE: start, - Args: cobra.MinimumNArgs(1), Example: `podman start --latest podman start 860a4b231279 5421ab43b45 podman start --interactive --attach imageID`, @@ -72,6 +71,9 @@ func init() { func start(cmd *cobra.Command, args []string) error { var errs utils.OutputErrors + if len(args) == 0 && !startOptions.Latest { + return errors.New("start requires at least one argument") + } if len(args) > 1 && startOptions.Attach { return errors.Errorf("you cannot start and attach multiple containers at once") } diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go index 808980eff..6d0d9cf7f 100644 --- a/cmd/podman/pods/ps.go +++ b/cmd/podman/pods/ps.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "sort" "strings" "text/tabwriter" "text/template" @@ -32,7 +33,7 @@ var ( var ( defaultHeaders string = "POD ID\tNAME\tSTATUS\tCREATED" - inputFilters string + inputFilters []string noTrunc bool psInput entities.PodPSOptions ) @@ -48,7 +49,7 @@ func init() { flags.BoolVar(&psInput.CtrIds, "ctr-ids", false, "Display the container UUIDs. If no-trunc is not set they will be truncated") flags.BoolVar(&psInput.CtrStatus, "ctr-status", false, "Display the container status") // TODO should we make this a [] ? - flags.StringVarP(&inputFilters, "filter", "f", "", "Filter output based on conditions given") + flags.StringSliceVarP(&inputFilters, "filter", "f", []string{}, "Filter output based on conditions given") flags.StringVar(&psInput.Format, "format", "", "Pretty-print pods to JSON or using a Go template") flags.BoolVarP(&psInput.Latest, "latest", "l", false, "Act on the latest pod podman is aware of") flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod") @@ -67,8 +68,13 @@ func pods(cmd *cobra.Command, args []string) error { row string lpr []ListPodReporter ) + + if psInput.Quiet && len(psInput.Format) > 0 { + return errors.New("quiet and format cannot be used together") + } if cmd.Flag("filter").Changed { - for _, f := range strings.Split(inputFilters, ",") { + psInput.Filters = make(map[string][]string) + for _, f := range inputFilters { split := strings.Split(f, "=") if len(split) < 2 { return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) @@ -81,6 +87,10 @@ func pods(cmd *cobra.Command, args []string) error { return err } + if err := sortPodPsOutput(psInput.Sort, responses); err != nil { + return err + } + if psInput.Format == "json" { b, err := json.MarshalIndent(responses, "", " ") if err != nil { @@ -95,11 +105,7 @@ func pods(cmd *cobra.Command, args []string) error { } headers, row := createPodPsOut() if psInput.Quiet { - if noTrunc { - row = "{{.Id}}\n" - } else { - row = "{{slice .Id 0 12}}\n" - } + row = "{{.Id}}\n" } if cmd.Flag("format").Changed { row = psInput.Format @@ -130,11 +136,7 @@ func pods(cmd *cobra.Command, args []string) error { func createPodPsOut() (string, string) { var row string headers := defaultHeaders - if noTrunc { - row += "{{.Id}}" - } else { - row += "{{slice .Id 0 12}}" - } + row += "{{.Id}}" row += "\t{{.Name}}\t{{.Status}}\t{{.Created}}" @@ -160,11 +162,7 @@ func createPodPsOut() (string, string) { } headers += "\tINFRA ID\n" - if noTrunc { - row += "\t{{.InfraId}}\n" - } else { - row += "\t{{slice .InfraId 0 12}}\n" - } + row += "\t{{.InfraId}}\n" return headers, row } @@ -184,6 +182,19 @@ func (l ListPodReporter) NumberOfContainers() int { return len(l.Containers) } +// ID is a wrapper to Id for compat, typos +func (l ListPodReporter) ID() string { + return l.Id() +} + +// Id returns the Pod id +func (l ListPodReporter) Id() string { + if noTrunc { + return l.ListPodsReport.Id + } + return l.ListPodsReport.Id[0:12] +} + // Added for backwards compatibility with podmanv1 func (l ListPodReporter) InfraID() string { return l.InfraId() @@ -192,6 +203,9 @@ func (l ListPodReporter) InfraID() string { // InfraId returns the infra container id for the pod // depending on trunc func (l ListPodReporter) InfraId() string { + if len(l.ListPodsReport.InfraId) == 0 { + return "" + } if noTrunc { return l.ListPodsReport.InfraId } @@ -225,3 +239,52 @@ func (l ListPodReporter) ContainerStatuses() string { } return strings.Join(statuses, ",") } + +func sortPodPsOutput(sortBy string, lprs []*entities.ListPodsReport) error { + switch sortBy { + case "created": + sort.Sort(podPsSortedCreated{lprs}) + case "id": + sort.Sort(podPsSortedId{lprs}) + case "name": + sort.Sort(podPsSortedName{lprs}) + case "number": + sort.Sort(podPsSortedNumber{lprs}) + case "status": + sort.Sort(podPsSortedStatus{lprs}) + default: + return errors.Errorf("invalid option for --sort, options are: id, names, or number") + } + return nil +} + +type lprSort []*entities.ListPodsReport + +func (a lprSort) Len() int { return len(a) } +func (a lprSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +type podPsSortedCreated struct{ lprSort } + +func (a podPsSortedCreated) Less(i, j int) bool { + return a.lprSort[i].Created.After(a.lprSort[j].Created) +} + +type podPsSortedId struct{ lprSort } + +func (a podPsSortedId) Less(i, j int) bool { return a.lprSort[i].Id < a.lprSort[j].Id } + +type podPsSortedNumber struct{ lprSort } + +func (a podPsSortedNumber) Less(i, j int) bool { + return len(a.lprSort[i].Containers) < len(a.lprSort[j].Containers) +} + +type podPsSortedName struct{ lprSort } + +func (a podPsSortedName) Less(i, j int) bool { return a.lprSort[i].Name < a.lprSort[j].Name } + +type podPsSortedStatus struct{ lprSort } + +func (a podPsSortedStatus) Less(i, j int) bool { + return a.lprSort[i].Status < a.lprSort[j].Status +} @@ -45,7 +45,7 @@ require ( github.com/opentracing/opentracing-go v1.1.0 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 - github.com/rootless-containers/rootlesskit v0.9.3 + github.com/rootless-containers/rootlesskit v0.9.4 github.com/seccomp/containers-golang v0.0.0-20190312124753-8ca8945ccf5f github.com/sirupsen/logrus v1.5.0 github.com/spf13/cobra v0.0.7 @@ -373,8 +373,8 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rootless-containers/rootlesskit v0.9.3 h1:hrkZzBZT5vEnhAso6H1jHAcc4DT8h6/hp2z4yL0xu/8= -github.com/rootless-containers/rootlesskit v0.9.3/go.mod h1:fx5DhInDgnR0Upj+2cOVacKuZJYSNKV5P/bCwGa+quQ= +github.com/rootless-containers/rootlesskit v0.9.4 h1:6ogX7l3r3nlS7eTB8ePbLSQ6TZR1aVQzRjTy2SIBOzk= +github.com/rootless-containers/rootlesskit v0.9.4/go.mod h1:fx5DhInDgnR0Upj+2cOVacKuZJYSNKV5P/bCwGa+quQ= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= diff --git a/libpod/pod.go b/libpod/pod.go index 4cdeb1033..b5a14c165 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -76,27 +76,6 @@ type podState struct { InfraContainerID string } -// PodInspect represents the data we want to display for -// podman pod inspect -type PodInspect struct { - Config *PodConfig - State *PodInspectState - Containers []PodContainerInfo -} - -// PodInspectState contains inspect data on the pod's state -type PodInspectState struct { - CgroupPath string `json:"cgroupPath"` - InfraContainerID string `json:"infraContainerID"` - Status string `json:"status"` -} - -// PodContainerInfo keeps information on a container in a pod -type PodContainerInfo struct { - ID string `json:"id"` - State string `json:"state"` -} - // InfraContainerConfig is the configuration for the pod's infra container type InfraContainerConfig struct { HasInfraContainer bool `json:"makeInfraContainer"` diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go index 87891d4a8..7d8932f56 100644 --- a/pkg/api/handlers/swagger/swagger.go +++ b/pkg/api/handlers/swagger/swagger.go @@ -143,7 +143,7 @@ type swagListPodsResponse struct { type swagInspectPodResponse struct { // in:body Body struct { - libpod.PodInspect + define.InspectPodData } } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index a77b18ce1..9844d1d96 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -837,7 +837,13 @@ func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []strin } for _, ctr := range ctrs { report := entities.ContainerInitReport{Id: ctr.ID()} - report.Err = ctr.Init(ctx) + err := ctr.Init(ctx) + + // If we're initializing all containers, ignore invalid state errors + if options.All && errors.Cause(err) == define.ErrCtrStateInvalid { + err = nil + } + report.Err = err reports = append(reports, &report) } return reports, nil diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index c4ae9efbf..7732d5aa3 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -292,9 +292,12 @@ func (ic *ContainerEngine) PodTop(ctx context.Context, options entities.PodTopOp func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOptions) ([]*entities.ListPodsReport, error) { var ( + err error filters []libpod.PodFilter + pds []*libpod.Pod reports []*entities.ListPodsReport ) + for k, v := range options.Filters { for _, filter := range v { f, err := lpfilters.GeneratePodFilterFunc(k, filter) @@ -305,10 +308,19 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti } } - pds, err := ic.Libpod.Pods(filters...) - if err != nil { - return nil, err + if options.Latest { + pod, err := ic.Libpod.GetLatestPod() + if err != nil { + return nil, err + } + pds = append(pds, pod) + } else { + pds, err = ic.Libpod.Pods(filters...) + if err != nil { + return nil, err + } } + for _, p := range pds { var lpcs []*entities.ListPodContainer status, err := p.GetPodStatus() diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go index 2cb3c3f20..2ffbde977 100644 --- a/pkg/namespaces/namespaces.go +++ b/pkg/namespaces/namespaces.go @@ -31,7 +31,7 @@ func (n CgroupMode) IsHost() bool { // IsDefaultValue indicates whether the cgroup namespace has the default value. func (n CgroupMode) IsDefaultValue() bool { - return n == "" + return n == "" || n == defaultType } // IsNS indicates a cgroup namespace passed in by path (ns:<path>) @@ -102,6 +102,11 @@ func (n UsernsMode) IsAuto() bool { return parts[0] == "auto" } +// IsDefaultValue indicates whether the user namespace has the default value. +func (n UsernsMode) IsDefaultValue() bool { + return n == "" || n == defaultType +} + // GetAutoOptions returns a AutoUserNsOptions with the settings to setup automatically // a user namespace. func (n UsernsMode) GetAutoOptions() (*storage.AutoUserNsOptions, error) { diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 2e0e088bf..a8b74b504 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -10,6 +10,7 @@ import ( "github.com/containers/libpod/pkg/cgroups" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/specgen" + "github.com/containers/libpod/pkg/util" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" @@ -175,6 +176,13 @@ func GenerateNamespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod // User switch s.UserNS.NSMode { + case specgen.KeepID: + if rootless.IsRootless() { + s.User = "" + } else { + // keep-id as root doesn't need a user namespace + s.UserNS.NSMode = specgen.Host + } case specgen.FromPod: if pod == nil || infraCtr == nil { return nil, errNoInfra @@ -378,6 +386,18 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt if err := g.RemoveLinuxNamespace(string(spec.UserNamespace)); err != nil { return err } + case specgen.KeepID: + var ( + err error + uid, gid int + ) + s.IDMappings, uid, gid, err = util.GetKeepIDMapping() + if err != nil { + return err + } + g.SetProcessUID(uint32(uid)) + g.SetProcessGID(uint32(gid)) + fallthrough case specgen.Private: if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), ""); err != nil { return err diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go index fffbd6d9e..cee49ff51 100644 --- a/pkg/specgen/namespaces.go +++ b/pkg/specgen/namespaces.go @@ -76,6 +76,17 @@ func (n *Namespace) IsPod() bool { func (n *Namespace) IsPrivate() bool { return n.NSMode == Private } + +// IsAuto indicates the namespace is auto +func (n *Namespace) IsAuto() bool { + return n.NSMode == Auto +} + +// IsKeepID indicates the namespace is KeepID +func (n *Namespace) IsKeepID() bool { + return n.NSMode == KeepID +} + func validateUserNS(n *Namespace) error { if n == nil { return nil @@ -186,12 +197,11 @@ func ParseUserNamespace(ns string) (Namespace, error) { if len(split) != 2 { return toReturn, errors.Errorf("invalid setting for auto: mode") } - toReturn.NSMode = KeepID + toReturn.NSMode = Auto toReturn.Value = split[1] return toReturn, nil case ns == "keep-id": toReturn.NSMode = KeepID - toReturn.NSMode = FromContainer return toReturn, nil } return ParseNamespace(ns) diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 64331cf66..917f57742 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -330,6 +330,58 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { return sig, nil } +// GetKeepIDMapping returns the mappings and the user to use when keep-id is used +func GetKeepIDMapping() (*storage.IDMappingOptions, int, int, error) { + options := storage.IDMappingOptions{ + HostUIDMapping: true, + HostGIDMapping: true, + } + uid, gid := 0, 0 + if rootless.IsRootless() { + min := func(a, b int) int { + if a < b { + return a + } + return b + } + + uid = rootless.GetRootlessUID() + gid = rootless.GetRootlessGID() + + uids, gids, err := rootless.GetConfiguredMappings() + if err != nil { + return nil, -1, -1, errors.Wrapf(err, "cannot read mappings") + } + maxUID, maxGID := 0, 0 + for _, u := range uids { + maxUID += u.Size + } + for _, g := range gids { + maxGID += g.Size + } + + options.UIDMap, options.GIDMap = nil, nil + + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) + if maxUID > uid { + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) + } + + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) + if maxGID > gid { + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) + } + + options.HostUIDMapping = false + options.HostGIDMapping = false + + } + // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op + return &options, uid, gid, nil +} + // ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) { options := storage.IDMappingOptions{ @@ -350,53 +402,8 @@ func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []strin return &options, nil } if mode.IsKeepID() { - if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 { - return nil, errors.New("cannot specify custom mappings with --userns=keep-id") - } - if len(subUIDMap) > 0 || len(subGIDMap) > 0 { - return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id") - } - if rootless.IsRootless() { - min := func(a, b int) int { - if a < b { - return a - } - return b - } - - uid := rootless.GetRootlessUID() - gid := rootless.GetRootlessGID() - - uids, gids, err := rootless.GetConfiguredMappings() - if err != nil { - return nil, errors.Wrapf(err, "cannot read mappings") - } - maxUID, maxGID := 0, 0 - for _, u := range uids { - maxUID += u.Size - } - for _, g := range gids { - maxGID += g.Size - } - - options.UIDMap, options.GIDMap = nil, nil - - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) - if maxUID > uid { - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) - } - - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) - if maxGID > gid { - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) - } - - options.HostUIDMapping = false - options.HostGIDMapping = false - } - // Simply ignore the setting and do not setup an inner namespace for root as it is a no-op + options.HostUIDMapping = false + options.HostGIDMapping = false return &options, nil } diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go index ceb656a01..72387ed8c 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -18,7 +18,6 @@ var _ = Describe("Podman commit", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index d93ee8d3a..160af1bd5 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -14,7 +14,6 @@ import ( "testing" "time" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/inspect" "github.com/containers/libpod/pkg/rootless" @@ -501,8 +500,8 @@ func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectCont } // InspectPodToJSON takes the sessions output from a pod inspect and returns json -func (s *PodmanSessionIntegration) InspectPodToJSON() libpod.PodInspect { - var i libpod.PodInspect +func (s *PodmanSessionIntegration) InspectPodToJSON() define.InspectPodData { + var i define.InspectPodData err := json.Unmarshal(s.Out.Contents(), &i) Expect(err).To(BeNil()) return i diff --git a/test/e2e/container_inspect_test.go b/test/e2e/container_inspect_test.go index cc986f1a8..91c025197 100644 --- a/test/e2e/container_inspect_test.go +++ b/test/e2e/container_inspect_test.go @@ -17,7 +17,6 @@ var _ = Describe("Podman container inspect", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/init_test.go b/test/e2e/init_test.go index 6241f813f..919fe4abf 100644 --- a/test/e2e/init_test.go +++ b/test/e2e/init_test.go @@ -16,7 +16,6 @@ var _ = Describe("Podman init", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index 66b888803..39e08e2e8 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -21,7 +21,6 @@ var _ = Describe("Podman pause", func() { createdState := "Created" BeforeEach(func() { - Skip(v2fail) SkipIfRootless() tempdir, err = CreateTempDirInTempDir() if err != nil { diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go index 06f36c751..f87bbe047 100644 --- a/test/e2e/pod_inspect_test.go +++ b/test/e2e/pod_inspect_test.go @@ -16,7 +16,6 @@ var _ = Describe("Podman pod inspect", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -55,8 +54,7 @@ var _ = Describe("Podman pod inspect", func() { inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) Expect(inspect.IsJSONOutputValid()).To(BeTrue()) - // FIXME sujil, disabled for now - //podData := inspect.InspectPodToJSON() - //Expect(podData.Config.ID).To(Equal(podid)) + podData := inspect.InspectPodToJSON() + Expect(podData.ID).To(Equal(podid)) }) }) diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go index 29d7664df..a3efec46c 100644 --- a/test/e2e/pod_kill_test.go +++ b/test/e2e/pod_kill_test.go @@ -17,7 +17,6 @@ var _ = Describe("Podman pod kill", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/pod_prune_test.go b/test/e2e/pod_prune_test.go index d0725883c..d98383331 100644 --- a/test/e2e/pod_prune_test.go +++ b/test/e2e/pod_prune_test.go @@ -16,7 +16,6 @@ var _ = Describe("Podman pod prune", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go index ea9118f37..5f8712a7a 100644 --- a/test/e2e/pod_ps_test.go +++ b/test/e2e/pod_ps_test.go @@ -18,7 +18,6 @@ var _ = Describe("Podman ps", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) @@ -96,6 +95,7 @@ var _ = Describe("Podman ps", func() { Expect(result.OutputToString()).To(ContainSubstring(podid2)) Expect(result.OutputToString()).To(Not(ContainSubstring(podid1))) }) + It("podman pod ps id filter flag", func() { _, ec, podid := podmanTest.CreatePod("") Expect(ec).To(Equal(0)) @@ -143,7 +143,7 @@ var _ = Describe("Podman ps", func() { _, ec, _ = podmanTest.RunLsContainerInPod("test2", podid) Expect(ec).To(Equal(0)) - session = podmanTest.Podman([]string{"pod", "ps", "--format={{.ContainerInfo}}", "--ctr-names"}) + session = podmanTest.Podman([]string{"pod", "ps", "--format={{.ContainerNames}}", "--ctr-names"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("test1")) @@ -228,4 +228,18 @@ var _ = Describe("Podman ps", func() { Expect(session.OutputToString()).To(ContainSubstring(podid2)) Expect(session.OutputToString()).To(Not(ContainSubstring(podid3))) }) + + It("pod no infra should ps", func() { + session := podmanTest.Podman([]string{"pod", "create", "--infra=false"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + ps := podmanTest.Podman([]string{"pod", "ps"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + + infra := podmanTest.Podman([]string{"pod", "ps", "--format", "{{.InfraId}}"}) + infra.WaitWithDefaultTimeout() + Expect(len(infra.OutputToString())).To(BeZero()) + }) }) diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go index 2f75aaf30..c313b0675 100644 --- a/test/e2e/pod_top_test.go +++ b/test/e2e/pod_top_test.go @@ -20,7 +20,6 @@ var _ = Describe("Podman top", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go index 749047b76..02b9ff8d1 100644 --- a/test/e2e/run_dns_test.go +++ b/test/e2e/run_dns_test.go @@ -18,7 +18,6 @@ var _ = Describe("Podman run dns", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index 9c914188a..c8ba68efc 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -19,7 +19,6 @@ var _ = Describe("Podman run ns", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go index 0868bce4f..bd6a0e036 100644 --- a/test/e2e/run_passwd_test.go +++ b/test/e2e/run_passwd_test.go @@ -18,7 +18,6 @@ var _ = Describe("Podman run passwd", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_restart_test.go b/test/e2e/run_restart_test.go index 28ab23ab0..8bbdf2056 100644 --- a/test/e2e/run_restart_test.go +++ b/test/e2e/run_restart_test.go @@ -18,7 +18,6 @@ var _ = Describe("Podman run restart containers", func() { ) BeforeEach(func() { - Skip(v2fail) tempdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go index 58dde62da..fbdd3acec 100644 --- a/test/e2e/run_signal_test.go +++ b/test/e2e/run_signal_test.go @@ -29,7 +29,6 @@ var _ = Describe("Podman run with --sig-proxy", func() { ) BeforeEach(func() { - Skip(v2fail) tmpdir, err = CreateTempDirInTempDir() if err != nil { os.Exit(1) diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index a4e99ab71..25f12ec2e 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -22,7 +22,6 @@ var _ = Describe("Podman UserNS support", func() { ) BeforeEach(func() { - Skip(v2fail) if os.Getenv("SKIP_USERNS") != "" { Skip("Skip userns tests.") } diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go index 893bf1da9..8ffadd859 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go @@ -2,11 +2,14 @@ package parent import ( "context" + "fmt" "io" "io/ioutil" "net" "os" "path/filepath" + "strconv" + "strings" "sync" "syscall" @@ -84,6 +87,39 @@ func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{ return nil } +func isEPERM(err error) bool { + k := "permission denied" + // As of Go 1.14, errors.Is(err, syscall.EPERM) does not seem to work for + // "listen tcp 0.0.0.0:80: bind: permission denied" error from net.ListenTCP(). + return errors.Is(err, syscall.EPERM) || strings.Contains(err.Error(), k) +} + +// annotateEPERM annotates origErr for human-readability +func annotateEPERM(origErr error, spec port.Spec) error { + // Read "net.ipv4.ip_unprivileged_port_start" value (typically 1024) + // TODO: what for IPv6? + // NOTE: sync.Once should not be used here + b, e := ioutil.ReadFile("/proc/sys/net/ipv4/ip_unprivileged_port_start") + if e != nil { + return origErr + } + start, e := strconv.Atoi(strings.TrimSpace(string(b))) + if e != nil { + return origErr + } + if spec.ParentPort >= start { + // origErr is unrelated to ip_unprivileged_port_start + return origErr + } + text := fmt.Sprintf("cannot expose privileged port %d, you might need to add \"net.ipv4.ip_unprivileged_port_start=0\" (currently %d) to /etc/sysctl.conf", spec.ParentPort, start) + if filepath.Base(os.Args[0]) == "rootlesskit" { + // NOTE: The following sentence is appended only if Args[0] == "rootlesskit", because it does not apply to Podman (as of Podman v1.9). + // Podman launches the parent driver in the child user namespace (but in the parent network namespace), which disables the file capability. + text += ", or set CAP_NET_BIND_SERVICE on rootlesskit binary" + } + return errors.Wrap(origErr, text) +} + func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { d.mu.Lock() err := portutil.ValidatePortSpec(spec, d.ports) @@ -106,6 +142,9 @@ func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, err return nil, errors.New("spec was not validated?") } if err != nil { + if isEPERM(err) { + err = annotateEPERM(err, spec) + } return nil, err } d.mu.Lock() diff --git a/vendor/modules.txt b/vendor/modules.txt index 782a905a1..0a6d8ccd5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -454,7 +454,7 @@ github.com/prometheus/common/model github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util -# github.com/rootless-containers/rootlesskit v0.9.3 +# github.com/rootless-containers/rootlesskit v0.9.4 github.com/rootless-containers/rootlesskit/pkg/msgutil github.com/rootless-containers/rootlesskit/pkg/port github.com/rootless-containers/rootlesskit/pkg/port/builtin |