diff options
-rw-r--r-- | cmd/podman/common/specgen.go | 4 | ||||
-rw-r--r-- | cmd/podman/inspect/inspect.go | 56 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 6 | ||||
-rw-r--r-- | libpod/image/image.go | 2 | ||||
-rw-r--r-- | pkg/api/server/register_ping.go | 1 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/engine_image.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 51 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 14 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 31 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 17 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 2 | ||||
-rw-r--r-- | pkg/specgen/generate/storage.go | 4 | ||||
-rw-r--r-- | test/e2e/inspect_test.go | 40 | ||||
-rw-r--r-- | test/e2e/run_test.go | 24 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/config.go | 192 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/containers.conf | 10 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
19 files changed, 341 insertions, 121 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 2a070710a..e6a524358 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -563,6 +563,8 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string // we dont think these are in the spec // init - initbinary // initpath + s.Init = c.Init + s.InitPath = c.InitPath s.Stdin = c.Interactive // quiet // DeviceCgroupRules: c.StringSlice("device-cgroup-rule"), @@ -625,7 +627,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string if retries < 0 { return errors.Errorf("must specify restart policy retry count as a number greater than 0") } - var retriesUint uint = uint(retries) + var retriesUint = uint(retries) s.RestartRetries = &retriesUint default: return errors.Errorf("invalid restart policy: may specify retries at most once") diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index 1ed033ec3..d80bbffdd 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -3,12 +3,14 @@ package inspect import ( "context" "fmt" + "os" "strings" "github.com/containers/buildah/pkg/formats" "github.com/containers/libpod/cmd/podman/registry" "github.com/containers/libpod/pkg/domain/entities" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -78,6 +80,7 @@ func newInspector(options entities.InspectOptions) (*inspector, error) { func (i *inspector) inspect(namesOrIDs []string) error { // data - dumping place for inspection results. var data []interface{} //nolint + var errs []error ctx := context.Background() if len(namesOrIDs) == 0 { @@ -97,24 +100,27 @@ func (i *inspector) inspect(namesOrIDs []string) error { // Inspect - note that AllType requires us to expensively query one-by-one. switch tmpType { case AllType: - all, err := i.inspectAll(ctx, namesOrIDs) + allData, allErrs, err := i.inspectAll(ctx, namesOrIDs) if err != nil { return err } - data = all + data = allData + errs = allErrs case ImageType: - imgData, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options) + imgData, allErrs, err := i.imageEngine.Inspect(ctx, namesOrIDs, i.options) if err != nil { return err } + errs = allErrs for i := range imgData { data = append(data, imgData[i]) } case ContainerType: - ctrData, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options) + ctrData, allErrs, err := i.containerEngine.ContainerInspect(ctx, namesOrIDs, i.options) if err != nil { return err } + errs = allErrs for i := range ctrData { data = append(data, ctrData[i]) } @@ -122,30 +128,54 @@ func (i *inspector) inspect(namesOrIDs []string) error { return errors.Errorf("invalid type %q: must be %q, %q or %q", i.options.Type, ImageType, ContainerType, AllType) } + // Always print an empty array + if data == nil { + data = []interface{}{} + } + var out formats.Writer if i.options.Format == "json" || i.options.Format == "" { // "" for backwards compat out = formats.JSONStructArray{Output: data} } else { out = formats.StdoutTemplateArray{Output: data, Template: inspectFormat(i.options.Format)} } - return out.Out() + if err := out.Out(); err != nil { + logrus.Errorf("Error printing inspect output: %v", err) + } + if len(errs) > 0 { + if len(errs) > 1 { + for _, err := range errs[1:] { + fmt.Fprintf(os.Stderr, "error inspecting object: %v\n", err) + } + } + return errors.Errorf("error inspecting object: %v", errs[0]) + } + return nil } -func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, error) { +func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]interface{}, []error, error) { var data []interface{} //nolint + allErrs := []error{} for _, name := range namesOrIDs { - imgData, err := i.imageEngine.Inspect(ctx, []string{name}, i.options) - if err == nil { - data = append(data, imgData[0]) + ctrData, errs, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options) + if err != nil { + return nil, nil, err + } + if len(errs) == 0 { + data = append(data, ctrData[0]) continue } - ctrData, err := i.containerEngine.ContainerInspect(ctx, []string{name}, i.options) + imgData, errs, err := i.imageEngine.Inspect(ctx, []string{name}, i.options) if err != nil { - return nil, err + return nil, nil, err + } + if len(errs) > 0 { + allErrs = append(allErrs, errors.Errorf("no such object: %q", name)) + continue } - data = append(data, ctrData[0]) + data = append(data, imgData[0]) } - return data, nil + return data, allErrs, nil } func inspectFormat(row string) string { @@ -11,7 +11,7 @@ require ( github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921 github.com/containernetworking/plugins v0.8.6 github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224 - github.com/containers/common v0.13.1 + github.com/containers/common v0.14.0 github.com/containers/conmon v2.0.18+incompatible github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0 github.com/containers/psgo v1.5.1 @@ -70,8 +70,8 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224 h1:EqwBZRqyUYvU7JOmmSSPviSaAoUP1wN0cefXXDZ9ATo= github.com/containers/buildah v1.14.9-0.20200523094741-de0f541d9224/go.mod h1:5ZkWjOuK90yl55L5R+purJNLfUo0VUr8pstJazNtYck= github.com/containers/common v0.11.2/go.mod h1:2w3QE6VUmhltGYW4wV00h4okq1Crs7hNI1ZD2I0QRUY= -github.com/containers/common v0.13.1 h1:6aE/IIxPPQk8DmND87tsWU1Aop/7mCC0T3dk/fZdm3k= -github.com/containers/common v0.13.1/go.mod h1:Kg9Enw+WOUa9pwx47fzxEdzOn5+ofYXjBJdCyaCeSSA= +github.com/containers/common v0.14.0 h1:hiZFDPf6ajKiDmojN5f5X3gboKPO73NLrYb0RXfrQiA= +github.com/containers/common v0.14.0/go.mod h1:9olhlE+WhYof1npnMJdyRMX14/yIUint6zyHzcyRVAg= github.com/containers/conmon v2.0.18+incompatible h1:rjwjNnE756NuXcdE/uUmj4kDbrykslPuBMHI31wh43E= github.com/containers/conmon v2.0.18+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.4.3/go.mod h1:pN0tvp3YbDd7BWavK2aE0mvJUqVd2HmhPjekyWSFm0U= @@ -318,8 +318,6 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ= -github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= diff --git a/libpod/image/image.go b/libpod/image/image.go index 1101e35dc..d81f7e911 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -478,7 +478,7 @@ func (ir *Runtime) getImages(rwOnly bool) ([]*Image, error) { if err != nil { return nil, err } - newImages := make([]*Image, 0, len(images)) + newImages := []*Image{} for _, i := range images { if rwOnly && i.ReadOnly { continue diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go index 8a1cda3d4..bf7763029 100644 --- a/pkg/api/server/register_ping.go +++ b/pkg/api/server/register_ping.go @@ -19,6 +19,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error { // Return protocol information in response headers. // `HEAD /libpod/_ping` is also supported. // `/_ping` is available for compatibility with other engines. + // The '_ping' endpoints are not versioned. // tags: // - system (compat) // - system diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 979df7581..837550a2e 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -24,7 +24,7 @@ type ContainerEngine interface { ContainerExists(ctx context.Context, nameOrID string) (*BoolReport, error) ContainerExport(ctx context.Context, nameOrID string, options ContainerExportOptions) error ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error) - ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error) + ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, []error, error) ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error) ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error) ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index 60fb20b6e..7ece24c60 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -13,7 +13,7 @@ type ImageEngine interface { Exists(ctx context.Context, nameOrID string) (*BoolReport, error) History(ctx context.Context, nameOrID string, opts ImageHistoryOptions) (*ImageHistoryReport, error) Import(ctx context.Context, opts ImageImportOptions) (*ImageImportReport, error) - Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, error) + Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, []error, error) List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error) Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error) Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index da9be0946..8e0ffc075 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -338,20 +338,51 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, return reports, nil } -func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) { - ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod) - if err != nil { - return nil, err +func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) { + if options.Latest { + ctr, err := ic.Libpod.GetLatestContainer() + if err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr { + return nil, []error{errors.Wrapf(err, "no containers to inspect")}, nil + } + return nil, nil, err + } + + inspect, err := ctr.Inspect(options.Size) + if err != nil { + return nil, nil, err + } + + return []*entities.ContainerInspectReport{ + { + InspectContainerData: inspect, + }, + }, nil, nil } - reports := make([]*entities.ContainerInspectReport, 0, len(ctrs)) - for _, c := range ctrs { - data, err := c.Inspect(options.Size) + var ( + reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds)) + errs = []error{} + ) + for _, name := range namesOrIds { + ctr, err := ic.Libpod.LookupContainer(name) if err != nil { - return nil, err + // ErrNoSuchCtr is non-fatal, other errors will be + // treated as fatal. + if errors.Cause(err) == define.ErrNoSuchCtr { + errs = append(errs, errors.Errorf("no such container %s", name)) + continue + } + return nil, nil, err } - reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data}) + + inspect, err := ctr.Inspect(options.Size) + if err != nil { + return nil, nil, err + } + + reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect}) } - return reports, nil + return reports, errs, nil } func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index e630d9bc8..0f9ddfec4 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -184,24 +184,28 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti return &entities.ImagePullReport{Images: foundIDs}, nil } -func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) { +func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) { reports := []*entities.ImageInspectReport{} + errs := []error{} for _, i := range namesOrIDs { img, err := ir.Libpod.ImageRuntime().NewFromLocal(i) if err != nil { - return nil, err + // This is probably a no such image, treat as nonfatal. + errs = append(errs, err) + continue } result, err := img.Inspect(ctx) if err != nil { - return nil, err + // This is more likely to be fatal. + return nil, nil, err } report := entities.ImageInspectReport{} if err := domainUtils.DeepCopy(&report, result); err != nil { - return nil, err + return nil, nil, err } reports = append(reports, &report) } - return reports, nil + return reports, errs, nil } func (ir *ImageEngine) Push(ctx context.Context, source string, destination string, options entities.ImagePushOptions) error { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index a69c6548c..45fbc64f8 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -185,20 +185,27 @@ func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities. return containers.Prune(ic.ClientCxt, options.Filters) } -func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) { - ctrs, err := getContainersByContext(ic.ClientCxt, false, namesOrIds) - if err != nil { - return nil, err - } - reports := make([]*entities.ContainerInspectReport, 0, len(ctrs)) - for _, con := range ctrs { - data, err := containers.Inspect(ic.ClientCxt, con.ID, &options.Size) +func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) { + var ( + reports = make([]*entities.ContainerInspectReport, 0, len(namesOrIds)) + errs = []error{} + ) + for _, name := range namesOrIds { + inspect, err := containers.Inspect(ic.ClientCxt, name, &options.Size) if err != nil { - return nil, err + errModel, ok := err.(entities.ErrorModel) + if !ok { + return nil, nil, err + } + if errModel.ResponseCode == 404 { + errs = append(errs, errors.Errorf("no such container %q", name)) + continue + } + return nil, nil, err } - reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data}) + reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: inspect}) } - return reports, nil + return reports, errs, nil } func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) { @@ -373,7 +380,7 @@ func (ic *ContainerEngine) ContainerLogs(_ context.Context, nameOrIDs []string, case <-ctx.Done(): return err case line := <-outCh: - _, _ = io.WriteString(options.Writer, line) + _, _ = io.WriteString(options.Writer, line+"\n") } } } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index ec2c53c4f..9ddc5f1a9 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -39,7 +39,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) return nil, err } - is := make([]*entities.ImageSummary, 0, len(images)) + is := make([]*entities.ImageSummary, len(images)) for i, img := range images { hold := entities.ImageSummary{} if err := utils.DeepCopy(&hold, img); err != nil { @@ -157,16 +157,25 @@ func (ir *ImageEngine) Untag(ctx context.Context, nameOrID string, tags []string return nil } -func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, error) { +func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts entities.InspectOptions) ([]*entities.ImageInspectReport, []error, error) { reports := []*entities.ImageInspectReport{} + errs := []error{} for _, i := range namesOrIDs { r, err := images.GetImage(ir.ClientCxt, i, &opts.Size) if err != nil { - return nil, err + errModel, ok := err.(entities.ErrorModel) + if !ok { + return nil, nil, err + } + if errModel.ResponseCode == 404 { + errs = append(errs, errors.Wrapf(err, "unable to inspect %q", i)) + continue + } + return nil, nil, err } reports = append(reports, r) } - return reports, nil + return reports, errs, nil } func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) (*entities.ImageLoadReport, error) { diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 266abd28d..1c34f622b 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -112,7 +112,7 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image if initPath == "" { return nil, errors.Errorf("no path to init binary found but container requested an init") } - finalCommand = append([]string{initPath, "--"}, finalCommand...) + finalCommand = append([]string{"/dev/init", "--"}, finalCommand...) } return finalCommand, nil diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go index 241c9adeb..0d78421a6 100644 --- a/pkg/specgen/generate/storage.go +++ b/pkg/specgen/generate/storage.go @@ -314,8 +314,8 @@ func addContainerInitBinary(s *specgen.SpecGenerator, path string) (spec.Mount, if !s.PidNS.IsPrivate() { return mount, fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)") } - if s.Systemd == "true" || s.Systemd == "always" { - return mount, fmt.Errorf("cannot use container-init binary with systemd") + if s.Systemd == "always" { + return mount, fmt.Errorf("cannot use container-init binary with systemd=always") } if _, err := os.Stat(path); os.IsNotExist(err) { return mount, errors.Wrap(err, "container-init binary not found on the host") diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 62f69f1c1..2fad38a36 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -223,4 +223,44 @@ var _ = Describe("Podman inspect", func() { Expect(baseJSON[0].ID).To(Equal(ctrJSON[0].ID)) }) + + It("podman inspect always produces a valid array", func() { + baseInspect := podmanTest.Podman([]string{"inspect", "doesNotExist"}) + baseInspect.WaitWithDefaultTimeout() + Expect(baseInspect.ExitCode()).To(Not(Equal(0))) + emptyJSON := baseInspect.InspectContainerToJSON() + Expect(len(emptyJSON)).To(Equal(0)) + }) + + It("podman inspect one container with not exist returns 1-length valid array", func() { + ctrName := "testCtr" + create := podmanTest.Podman([]string{"create", "--name", ctrName, ALPINE, "sh"}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + baseInspect := podmanTest.Podman([]string{"inspect", ctrName, "doesNotExist"}) + baseInspect.WaitWithDefaultTimeout() + Expect(baseInspect.ExitCode()).To(Not(Equal(0))) + baseJSON := baseInspect.InspectContainerToJSON() + Expect(len(baseJSON)).To(Equal(1)) + Expect(baseJSON[0].Name).To(Equal(ctrName)) + }) + + It("podman inspect container + image with same name gives container", func() { + ctrName := "testcontainer" + create := podmanTest.PodmanNoCache([]string{"create", "--name", ctrName, ALPINE, "sh"}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + tag := podmanTest.PodmanNoCache([]string{"tag", ALPINE, ctrName + ":latest"}) + tag.WaitWithDefaultTimeout() + Expect(tag.ExitCode()).To(Equal(0)) + + baseInspect := podmanTest.Podman([]string{"inspect", ctrName}) + baseInspect.WaitWithDefaultTimeout() + Expect(baseInspect.ExitCode()).To(Equal(0)) + baseJSON := baseInspect.InspectContainerToJSON() + Expect(len(baseJSON)).To(Equal(1)) + Expect(baseJSON[0].Name).To(Equal(ctrName)) + }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 76944b3db..6dce0b48d 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -151,12 +151,36 @@ var _ = Describe("Podman run", func() { session := podmanTest.Podman([]string{"run", "--init", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + result := podmanTest.Podman([]string{"inspect", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + conData := result.InspectContainerToJSON() + Expect(conData[0].Path).To(Equal("/dev/init")) + Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("TRUE")) }) It("podman run a container with --init and --init-path", func() { session := podmanTest.Podman([]string{"run", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + result := podmanTest.Podman([]string{"inspect", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + conData := result.InspectContainerToJSON() + Expect(conData[0].Path).To(Equal("/dev/init")) + Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("TRUE")) + }) + + It("podman run a container without --init", func() { + session := podmanTest.Podman([]string{"run", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + result := podmanTest.Podman([]string{"inspect", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + conData := result.InspectContainerToJSON() + Expect(conData[0].Path).To(Equal("ls")) + Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("FALSE")) }) It("podman run seccomp test", func() { diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index 9657ecb69..ce479088e 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -74,105 +74,105 @@ type Config struct { type ContainersConfig struct { // Devices to add to all containers - Devices []string `toml:"devices"` + Devices []string `toml:"devices,omitempty"` // Volumes to add to all containers - Volumes []string `toml:"volumes"` + Volumes []string `toml:"volumes,omitempty"` // ApparmorProfile is the apparmor profile name which is used as the // default for the runtime. - ApparmorProfile string `toml:"apparmor_profile"` + ApparmorProfile string `toml:"apparmor_profile,omitempty"` // Annotation to add to all containers - Annotations []string `toml:"annotations"` + Annotations []string `toml:"annotations,omitempty"` // Default way to create a cgroup namespace for the container - CgroupNS string `toml:"cgroupns"` + CgroupNS string `toml:"cgroupns,omitempty"` // Default cgroup configuration - Cgroups string `toml:"cgroups"` + Cgroups string `toml:"cgroups,omitempty"` // Capabilities to add to all containers. - DefaultCapabilities []string `toml:"default_capabilities"` + DefaultCapabilities []string `toml:"default_capabilities,omitempty"` // Sysctls to add to all containers. - DefaultSysctls []string `toml:"default_sysctls"` + DefaultSysctls []string `toml:"default_sysctls,omitempty"` // DefaultUlimits specifies the default ulimits to apply to containers - DefaultUlimits []string `toml:"default_ulimits"` + DefaultUlimits []string `toml:"default_ulimits,omitempty"` // DefaultMountsFile is the path to the default mounts file for testing DefaultMountsFile string `toml:"-"` // DNSServers set default DNS servers. - DNSServers []string `toml:"dns_servers"` + DNSServers []string `toml:"dns_servers,omitempty"` // DNSOptions set default DNS options. - DNSOptions []string `toml:"dns_options"` + DNSOptions []string `toml:"dns_options,omitempty"` // DNSSearches set default DNS search domains. - DNSSearches []string `toml:"dns_searches"` + DNSSearches []string `toml:"dns_searches,omitempty"` // EnableLabeling tells the container engines whether to use MAC // Labeling to separate containers (SELinux) - EnableLabeling bool `toml:"label"` + EnableLabeling bool `toml:"label,omitempty"` // Env is the environment variable list for container process. - Env []string `toml:"env"` + Env []string `toml:"env,omitempty"` // EnvHost Pass all host environment variables into the container. - EnvHost bool `toml:"env_host"` + EnvHost bool `toml:"env_host,omitempty"` // HTTPProxy is the proxy environment variable list to apply to container process - HTTPProxy bool `toml:"http_proxy"` + HTTPProxy bool `toml:"http_proxy,omitempty"` // Init tells container runtimes whether to run init inside the // container that forwards signals and reaps processes. - Init bool `toml:"init"` + Init bool `toml:"init,omitempty"` // InitPath is the path for init to run if the Init bool is enabled - InitPath string `toml:"init_path"` + InitPath string `toml:"init_path,omitempty"` // IPCNS way to to create a ipc namespace for the container - IPCNS string `toml:"ipcns"` + IPCNS string `toml:"ipcns,omitempty"` // LogDriver for the container. For example: k8s-file and journald - LogDriver string `toml:"log_driver"` + LogDriver string `toml:"log_driver,omitempty"` // LogSizeMax is the maximum number of bytes after which the log file // will be truncated. It can be expressed as a human-friendly string // that is parsed to bytes. // Negative values indicate that the log file won't be truncated. - LogSizeMax int64 `toml:"log_size_max"` + LogSizeMax int64 `toml:"log_size_max,omitempty"` // NetNS indicates how to create a network namespace for the container - NetNS string `toml:"netns"` + NetNS string `toml:"netns,omitempty"` // NoHosts tells container engine whether to create its own /etc/hosts - NoHosts bool `toml:"no_hosts"` + NoHosts bool `toml:"no_hosts,omitempty"` // PidsLimit is the number of processes each container is restricted to // by the cgroup process number controller. - PidsLimit int64 `toml:"pids_limit"` + PidsLimit int64 `toml:"pids_limit,omitempty"` // PidNS indicates how to create a pid namespace for the container - PidNS string `toml:"pidns"` + PidNS string `toml:"pidns,omitempty"` // SeccompProfile is the seccomp.json profile path which is used as the // default for the runtime. - SeccompProfile string `toml:"seccomp_profile"` + SeccompProfile string `toml:"seccomp_profile,omitempty"` // ShmSize holds the size of /dev/shm. - ShmSize string `toml:"shm_size"` + ShmSize string `toml:"shm_size,omitempty"` // UTSNS indicates how to create a UTS namespace for the container - UTSNS string `toml:"utsns"` + UTSNS string `toml:"utsns,omitempty"` // UserNS indicates how to create a User namespace for the container - UserNS string `toml:"userns"` + UserNS string `toml:"userns,omitempty"` // UserNSSize how many UIDs to allocate for automatically created UserNS - UserNSSize int `toml:"userns_size"` + UserNSSize int `toml:"userns_size,omitempty"` } // EngineConfig contains configuration options used to set up a engine runtime @@ -183,20 +183,20 @@ type EngineConfig struct { // CGroupManager is the CGroup Manager to use Valid values are "cgroupfs" // and "systemd". - CgroupManager string `toml:"cgroup_manager"` + CgroupManager string `toml:"cgroup_manager,omitempty"` // NOTE: when changing this struct, make sure to update (*Config).Merge(). // ConmonEnvVars are environment variables to pass to the Conmon binary // when it is launched. - ConmonEnvVars []string `toml:"conmon_env_vars"` + ConmonEnvVars []string `toml:"conmon_env_vars,omitempty"` // ConmonPath is the path to the Conmon binary used for managing containers. // The first path pointing to a valid file will be used. - ConmonPath []string `toml:"conmon_path"` + ConmonPath []string `toml:"conmon_path,omitempty"` //DetachKeys is the sequence of keys used to detach a container. - DetachKeys string `toml:"detach_keys"` + DetachKeys string `toml:"detach_keys,omitempty"` // EnablePortReservation determines whether engine will reserve ports on the // host when they are forwarded to containers. When enabled, when ports are @@ -205,32 +205,32 @@ type EngineConfig struct { // programs on the host. However, this can cause significant memory usage if // a container has many ports forwarded to it. Disabling this can save // memory. - EnablePortReservation bool `toml:"enable_port_reservation"` + EnablePortReservation bool `toml:"enable_port_reservation,omitempty"` // EventsLogFilePath is where the events log is stored. - EventsLogFilePath string `toml:"events_logfile_path"` + EventsLogFilePath string `toml:"events_logfile_path,omitempty"` // EventsLogger determines where events should be logged. - EventsLogger string `toml:"events_logger"` + EventsLogger string `toml:"events_logger,omitempty"` // configuration files. When the same filename is present in in // multiple directories, the file in the directory listed last in // this slice takes precedence. - HooksDir []string `toml:"hooks_dir"` + HooksDir []string `toml:"hooks_dir,omitempty"` // ImageDefaultTransport is the default transport method used to fetch // images. - ImageDefaultTransport string `toml:"image_default_transport"` + ImageDefaultTransport string `toml:"image_default_transport,omitempty"` // InfraCommand is the command run to start up a pod infra container. - InfraCommand string `toml:"infra_command"` + InfraCommand string `toml:"infra_command,omitempty"` // InfraImage is the image a pod infra container will use to manage // namespaces. - InfraImage string `toml:"infra_image"` + InfraImage string `toml:"infra_image,omitempty"` // InitPath is the path to the container-init binary. - InitPath string `toml:"init_path"` + InitPath string `toml:"init_path,omitempty"` // LockType is the type of locking to use. LockType string `toml:"lock_type,omitempty"` @@ -244,27 +244,27 @@ type EngineConfig struct { Namespace string `toml:"namespace,omitempty"` // NetworkCmdPath is the path to the slirp4netns binary. - NetworkCmdPath string `toml:"network_cmd_path"` + NetworkCmdPath string `toml:"network_cmd_path,omitempty"` // NoPivotRoot sets whether to set no-pivot-root in the OCI runtime. - NoPivotRoot bool `toml:"no_pivot_root"` + NoPivotRoot bool `toml:"no_pivot_root,omitempty"` // NumLocks is the number of locks to make available for containers and // pods. NumLocks uint32 `toml:"num_locks,omitempty"` // OCIRuntime is the OCI runtime to use. - OCIRuntime string `toml:"runtime"` + OCIRuntime string `toml:"runtime,omitempty"` // OCIRuntimes are the set of configured OCI runtimes (default is runc). - OCIRuntimes map[string][]string `toml:"runtimes"` + OCIRuntimes map[string][]string `toml:"runtimes,omitempty"` // PullPolicy determines whether to pull image before creating or running a container // default is "missing" - PullPolicy string `toml:"pull_policy"` + PullPolicy string `toml:"pull_policy,omitempty"` // Indicates whether the application should be running in Remote mode - Remote bool `toml:"_"` + Remote bool `toml:"-"` // RemoteURI containers connection information used to connect to remote system. RemoteURI string `toml:"remote_uri,omitempty"` @@ -280,15 +280,15 @@ type EngineConfig struct { // RuntimeSupportsJSON is the list of the OCI runtimes that support // --format=json. - RuntimeSupportsJSON []string `toml:"runtime_supports_json"` + RuntimeSupportsJSON []string `toml:"runtime_supports_json,omitempty"` // RuntimeSupportsNoCgroups is a list of OCI runtimes that support // running containers without CGroups. - RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2"` + RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2,omitempty"` // RuntimeSupportsKVM is a list of OCI runtimes that support // KVM separation for conatainers. - RuntimeSupportsKVM []string `toml:"runtime_supports_kvm"` + RuntimeSupportsKVM []string `toml:"runtime_supports_kvm,omitempty"` // SetOptions contains a subset of config options. It's used to indicate if // a given option has either been set by the user or by the parsed @@ -300,11 +300,11 @@ type EngineConfig struct { // SignaturePolicyPath is the path to a signature policy to use for // validating images. If left empty, the containers/image default signature // policy will be used. - SignaturePolicyPath string `toml:"_"` + SignaturePolicyPath string `toml:"-"` // SDNotify tells container engine to allow containers to notify the host systemd of // readiness using the SD_NOTIFY mechanism. - SDNotify bool + SDNotify bool `toml:"-"` // StateType is the type of the backing state store. Avoid using multiple // values for this with the same containers/storage configuration on the @@ -315,20 +315,20 @@ type EngineConfig struct { // StaticDir is the path to a persistent directory to store container // files. - StaticDir string `toml:"static_dir"` + StaticDir string `toml:"static_dir,omitempty"` // StopTimeout is the number of seconds to wait for container to exit // before sending kill signal. - StopTimeout uint `toml:"stop_timeout"` + StopTimeout uint `toml:"stop_timeout,omitempty"` // TmpDir is the path to a temporary directory to store per-boot container // files. Must be stored in a tmpfs. - TmpDir string `toml:"tmp_dir"` + TmpDir string `toml:"tmp_dir,omitempty"` // VolumePath is the default location that named volumes will be created // under. This convention is followed by the default volume driver, but // may not be by other drivers. - VolumePath string `toml:"volume_path"` + VolumePath string `toml:"volume_path,omitempty"` } // SetOptions contains a subset of options in a Config. It's used to indicate if @@ -377,14 +377,14 @@ type SetOptions struct { // NetworkConfig represents the "network" TOML config table type NetworkConfig struct { // CNIPluginDirs is where CNI plugin binaries are stored. - CNIPluginDirs []string `toml:"cni_plugin_dirs"` + CNIPluginDirs []string `toml:"cni_plugin_dirs,omitempty"` // DefaultNetwork is the network name of the default CNI network // to attach pods to. DefaultNetwork string `toml:"default_network,omitempty"` // NetworkConfigDir is where CNI network configuration files are stored. - NetworkConfigDir string `toml:"network_config_dir"` + NetworkConfigDir string `toml:"network_config_dir,omitempty"` } // NewConfig creates a new Config. It starts with an empty config and, if @@ -856,3 +856,77 @@ func Path() string { } return OverrideContainersConfig } + +func customConfigFile() (string, error) { + path := os.Getenv("CONTAINERS_CONF") + if path != "" { + return path, nil + } + if unshare.IsRootless() { + path, err := rootlessConfigPath() + if err != nil { + return "", err + } + return path, nil + } + return OverrideContainersConfig, nil +} + +//ReadCustomConfig reads the custom config and only generates a config based on it +//If the custom config file does not exists, function will return an empty config +func ReadCustomConfig() (*Config, error) { + path, err := customConfigFile() + if err != nil { + return nil, err + } + // hack since Ommitempty does not seem to work with Write + c, err := Default() + if err != nil { + if os.IsNotExist(errors.Cause(err)) { + c, err = DefaultConfig() + } + if err != nil { + return nil, err + } + } + + newConfig := &Config{} + if _, err := os.Stat(path); err == nil { + newConfig, err = readConfigFromFile(path, newConfig) + if err != nil { + return nil, err + } + } else { + if !os.IsNotExist(err) { + return nil, err + } + } + newConfig.Containers.LogSizeMax = c.Containers.LogSizeMax + newConfig.Containers.PidsLimit = c.Containers.PidsLimit + newConfig.Containers.UserNSSize = c.Containers.UserNSSize + newConfig.Engine.NumLocks = c.Engine.NumLocks + newConfig.Engine.StopTimeout = c.Engine.StopTimeout + return newConfig, nil +} + +// Write writes the configuration to the default file +func (c *Config) Write() error { + var err error + path, err := customConfigFile() + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + configFile, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600) + if err != nil { + return errors.Wrapf(err, "cannot open %s", path) + } + defer configFile.Close() + enc := toml.NewEncoder(configFile) + if err := enc.Encode(c); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index a029aedeb..389479fa5 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -92,7 +92,7 @@ # Ulimits has limits for non privileged container engines. # # default_ulimits = [ -# “nofile”=”1280:2560”, +# "nofile"="1280:2560", # ] # List of default DNS options to be added to /etc/resolv.conf inside of the container. @@ -105,7 +105,7 @@ # Set default DNS servers. # This option can be used to override the DNS configuration passed to the -# container. The special value “none” can be specified to disable creation of +# container. The special value "none" can be specified to disable creation of # /etc/resolv.conf in the container. # The /etc/resolv.conf file in the image will be used without changes. # @@ -125,7 +125,7 @@ # Path to OCI hooks directories for automatically executed hooks. # # hooks_dir = [ -# “/usr/share/containers/oci/hooks.d”, +# "/usr/share/containers/oci/hooks.d", # ] # Default proxy environment variables passed into the container. @@ -220,7 +220,7 @@ # userns = "host" # Number of UIDs to allocate for the automatic container creation. -# UIDs are allocated from the “container” UIDs listed in +# UIDs are allocated from the "container" UIDs listed in # /etc/subuid & /etc/subgid # # userns_size=65536 @@ -241,7 +241,7 @@ [engine] # Cgroup management implementation used for the runtime. -# Valid options “systemd” or “cgroupfs” +# Valid options "systemd" or "cgroupfs" # # cgroup_manager = "systemd" diff --git a/vendor/modules.txt b/vendor/modules.txt index 59cf7a2ad..92d25f428 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -84,7 +84,7 @@ github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented github.com/containers/buildah/pkg/umask github.com/containers/buildah/util -# github.com/containers/common v0.13.1 +# github.com/containers/common v0.14.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/auth github.com/containers/common/pkg/capabilities |