diff options
56 files changed, 663 insertions, 230 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a813fcc35..308c7b197 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -361,9 +361,6 @@ All pull requests and branch-merges automatically run: * Integration Testing * Special testing (like running inside a container, or as a regular user) -For a more in-depth reference of the CI system, please [refer to it's dedicated -documentation.](contrib/cirrus/README.md) - There is always additional complexity added by automation, and so it sometimes can fail for any number of reasons. This includes post-merge testing on all branches, which you may occasionally see [red bars on the status graph @@ -10,7 +10,7 @@ Podman is based on libpod, a library for container lifecycle management that is * Latest Remote client for MacOs * Latest Static Remote client for Linux -* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/podman.svg)](https://cirrus-ci.com/github/containers/podman/master) +* Continuous Integration: [![Build Status](https://api.cirrus-ci.com/github/containers/podman.svg)](https://cirrus-ci.com/github/containers/podman/master) * [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/podman/libpod?status.svg)](https://godoc.org/github.com/containers/podman/libpod) ## Overview and scope diff --git a/cmd/podman/containers/commit.go b/cmd/podman/containers/commit.go index 1b33d221d..412dbf7a8 100644 --- a/cmd/podman/containers/commit.go +++ b/cmd/podman/containers/commit.go @@ -95,7 +95,7 @@ func commit(cmd *cobra.Command, args []string) error { } if len(iidFile) > 0 { if err = ioutil.WriteFile(iidFile, []byte(response.Id), 0644); err != nil { - return errors.Wrapf(err, "failed to write image ID to file %q", iidFile) + return errors.Wrap(err, "failed to write image ID") } } fmt.Println(response.Id) diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index 90f4db19c..7da430bc6 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -12,6 +12,7 @@ import ( tm "github.com/buger/goterm" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" @@ -40,9 +41,8 @@ var ( listOpts = entities.ContainerListOptions{ Filters: make(map[string][]string), } - filters []string - noTrunc bool - defaultHeaders = "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES" + filters []string + noTrunc bool ) func init() { @@ -91,10 +91,6 @@ func checkFlags(c *cobra.Command) error { if listOpts.Size || listOpts.Namespace { return errors.Errorf("quiet conflicts with size and namespace") } - if c.Flag("format").Changed && !report.IsJSON(listOpts.Format) { - // Quiet is overridden by Go template output. - listOpts.Quiet = false - } } // Size and namespace conflict with each other if listOpts.Size && listOpts.Namespace { @@ -155,7 +151,7 @@ func getResponses() ([]entities.ListContainer, error) { return responses, nil } -func ps(cmd *cobra.Command, args []string) error { +func ps(cmd *cobra.Command, _ []string) error { if err := checkFlags(cmd); err != nil { return err } @@ -180,24 +176,22 @@ func ps(cmd *cobra.Command, args []string) error { switch { case report.IsJSON(listOpts.Format): return jsonOut(listContainers) - case listOpts.Quiet: + case listOpts.Quiet && !cmd.Flags().Changed("format"): return quietOut(listContainers) } - // Output table Watch > 0 will refresh screen responses := make([]psReporter, 0, len(listContainers)) for _, r := range listContainers { responses = append(responses, psReporter{r}) } - var headers, format string + hdrs, format := createPsOut() if cmd.Flags().Changed("format") { - headers = "" format = report.NormalizeFormat(listOpts.Format) - } else { - headers, format = createPsOut() + format = parse.EnforceRange(format) } - format = headers + "{{range . }}" + format + "{{end}}" + ns := strings.NewReplacer(".Namespaces.", ".") + format = ns.Replace(format) tmpl, err := template.New("listContainers").Parse(format) if err != nil { @@ -206,13 +200,19 @@ func ps(cmd *cobra.Command, args []string) error { w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) defer w.Flush() - if listOpts.Watch > 0 { - for { - var responses []psReporter - tm.Clear() - tm.MoveCursor(1, 1) - tm.Flush() + headers := func() error { return nil } + if !(listOpts.Quiet || cmd.Flags().Changed("format")) { + headers = func() error { + return tmpl.Execute(w, hdrs) + } + } + switch { + // Output table Watch > 0 will refresh screen + case listOpts.Watch > 0: + // responses will grow to the largest number of processes reported on, but will not thrash the gc + var responses []psReporter + for ; ; responses = responses[:0] { if ctnrs, err := getResponses(); err != nil { return err } else { @@ -221,18 +221,27 @@ func ps(cmd *cobra.Command, args []string) error { } } + tm.Clear() + tm.MoveCursor(1, 1) + tm.Flush() + + if err := headers(); err != nil { + return err + } if err := tmpl.Execute(w, responses); err != nil { return err } if err := w.Flush(); err != nil { + // we usually do not care about Flush() failures but here do not loop if Flush() has failed return err } + time.Sleep(time.Duration(listOpts.Watch) * time.Second) - tm.Clear() - tm.MoveCursor(1, 1) - tm.Flush() } - } else if listOpts.Watch < 1 { + default: + if err := headers(); err != nil { + return err + } if err := tmpl.Execute(w, responses); err != nil { return err } @@ -241,30 +250,36 @@ func ps(cmd *cobra.Command, args []string) error { } // cannot use report.Headers() as it doesn't support structures as fields -func createPsOut() (string, string) { +func createPsOut() ([]map[string]string, string) { + hdrs := report.Headers(psReporter{}, map[string]string{ + "Cgroup": "cgroupns", + "CreatedHuman": "created", + "ID": "container id", + "IPC": "ipc", + "MNT": "mnt", + "NET": "net", + "PIDNS": "pidns", + "Pod": "pod id", + "PodName": "podname", // undo camelcase space break + "UTS": "uts", + "User": "userns", + }) + var row string if listOpts.Namespace { - headers := "CONTAINER ID\tNAMES\tPID\tCGROUPNS\tIPC\tMNT\tNET\tPIDNS\tUSERNS\tUTS\n" - row := "{{.ID}}\t{{.Names}}\t{{.Pid}}\t{{.Namespaces.Cgroup}}\t{{.Namespaces.IPC}}\t{{.Namespaces.MNT}}\t{{.Namespaces.NET}}\t{{.Namespaces.PIDNS}}\t{{.Namespaces.User}}\t{{.Namespaces.UTS}}\n" - return headers, row - } - headers := defaultHeaders - row += "{{.ID}}" - row += "\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}" + row = "{{.ID}}\t{{.Names}}\t{{.Pid}}\t{{.Namespaces.Cgroup}}\t{{.Namespaces.IPC}}\t{{.Namespaces.MNT}}\t{{.Namespaces.NET}}\t{{.Namespaces.PIDNS}}\t{{.Namespaces.User}}\t{{.Namespaces.UTS}}" + } else { + row = "{{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}" - if listOpts.Pod { - headers += "\tPOD ID\tPODNAME" - row += "\t{{.Pod}}\t{{.PodName}}" - } + if listOpts.Pod { + row += "\t{{.Pod}}\t{{.PodName}}" + } - if listOpts.Size { - headers += "\tSIZE" - row += "\t{{.Size}}" + if listOpts.Size { + row += "\t{{.Size}}" + } } - - headers = report.NormalizeFormat(headers) - row = report.NormalizeFormat(row) - return headers, row + return hdrs, "{{range .}}" + row + "\n{{end}}" } type psReporter struct { @@ -367,6 +382,41 @@ func (l psReporter) CreatedHuman() string { return units.HumanDuration(time.Since(time.Unix(l.Created, 0))) + " ago" } +// Cgroup exposes .Namespaces.Cgroup +func (l psReporter) Cgroup() string { + return l.Namespaces.Cgroup +} + +// IPC exposes .Namespaces.IPC +func (l psReporter) IPC() string { + return l.Namespaces.IPC +} + +// MNT exposes .Namespaces.MNT +func (l psReporter) MNT() string { + return l.Namespaces.MNT +} + +// NET exposes .Namespaces.NET +func (l psReporter) NET() string { + return l.Namespaces.NET +} + +// PIDNS exposes .Namespaces.PIDNS +func (l psReporter) PIDNS() string { + return l.Namespaces.PIDNS +} + +// User exposes .Namespaces.User +func (l psReporter) User() string { + return l.Namespaces.User +} + +// UTS exposes .Namespaces.UTS +func (l psReporter) UTS() string { + return l.Namespaces.UTS +} + // portsToString converts the ports used to a string of the from "port1, port2" // and also groups a continuous list of ports into a readable format. func portsToString(ports []ocicni.PortMapping) string { diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index 6cadbc7ec..780cd0c0d 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -108,7 +108,7 @@ func run(cmd *cobra.Command, args []string) error { if af := cliVals.Authfile; len(af) > 0 { if _, err := os.Stat(af); err != nil { - return errors.Wrapf(err, "error checking authfile path %s", af) + return err } } diff --git a/cmd/podman/containers/runlabel.go b/cmd/podman/containers/runlabel.go index b49af36ab..92581c26f 100644 --- a/cmd/podman/containers/runlabel.go +++ b/cmd/podman/containers/runlabel.go @@ -8,7 +8,6 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -75,7 +74,7 @@ func runlabel(cmd *cobra.Command, args []string) error { } if runlabelOptions.Authfile != "" { if _, err := os.Stat(runlabelOptions.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", runlabelOptions.Authfile) + return err } } return registry.ContainerEngine().ContainerRunlabel(context.Background(), args[0], args[1], args[2:], runlabelOptions.ContainerRunlabelOptions) diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go index 85e7a1e82..bfab469ca 100644 --- a/cmd/podman/containers/stats.go +++ b/cmd/podman/containers/stats.go @@ -8,6 +8,7 @@ import ( tm "github.com/buger/goterm" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/libpod/define" @@ -58,8 +59,7 @@ type statsOptionsCLI struct { } var ( - statsOptions statsOptionsCLI - defaultStatsRow = "{{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}\n" + statsOptions statsOptionsCLI ) func statFlags(flags *pflag.FlagSet) { @@ -159,19 +159,19 @@ func outputStats(reports []define.ContainerStats) error { if report.IsJSON(statsOptions.Format) { return outputJSON(stats) } - format := defaultStatsRow - + format := "{{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}\n" if len(statsOptions.Format) > 0 { format = report.NormalizeFormat(statsOptions.Format) - } else if len(statsOptions.Format) < 1 { - format = defaultStatsRow } - format = "{{range . }}" + format + "{{end}}" + format = parse.EnforceRange(format) + tmpl, err := template.New("stats").Parse(format) if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) + defer w.Flush() + if len(statsOptions.Format) < 1 { if err := tmpl.Execute(w, headers); err != nil { return err @@ -180,9 +180,6 @@ func outputStats(reports []define.ContainerStats) error { if err := tmpl.Execute(w, stats); err != nil { return err } - if err := w.Flush(); err != nil { - return err - } return nil } diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go index 4935fc60c..87f7501e3 100644 --- a/cmd/podman/generate/kube.go +++ b/cmd/podman/generate/kube.go @@ -55,7 +55,7 @@ func kube(cmd *cobra.Command, args []string) error { } if cmd.Flags().Changed("filename") { if _, err := os.Stat(kubeFile); err == nil { - return errors.Errorf("cannot write to %q", kubeFile) + return errors.Errorf("cannot write to %q; file exists", kubeFile) } if err := ioutil.WriteFile(kubeFile, content, 0644); err != nil { return errors.Wrapf(err, "cannot write to %q", kubeFile) diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go index 3075218d1..e9751b365 100644 --- a/cmd/podman/images/history.go +++ b/cmd/podman/images/history.go @@ -11,6 +11,7 @@ import ( "unicode" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/docker/go-units" @@ -119,7 +120,7 @@ func history(cmd *cobra.Command, args []string) error { case opts.quiet: row = "{{.ID}}\n" } - format := "{{range . }}" + row + "{{end}}" + format := parse.EnforceRange(row) tmpl, err := template.New("report").Parse(format) if err != nil { diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go index 489b15086..e24631b24 100644 --- a/cmd/podman/images/list.go +++ b/cmd/podman/images/list.go @@ -12,6 +12,7 @@ import ( "github.com/containers/common/pkg/report" "github.com/containers/image/v5/docker/reference" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/docker/go-units" @@ -105,10 +106,10 @@ func images(cmd *cobra.Command, args []string) error { return err } switch { - case listFlag.quiet: - return writeID(imgs) case report.IsJSON(listFlag.format): return writeJSON(imgs) + case listFlag.quiet: + return writeID(imgs) default: if cmd.Flag("format").Changed { listFlag.noHeading = true // V1 compatibility @@ -171,9 +172,13 @@ func writeTemplate(imgs []imageReporter) error { } else { row = report.NormalizeFormat(listFlag.format) } + format := parse.EnforceRange(row) + + tmpl, err := template.New("list").Parse(format) + if err != nil { + return err + } - format := "{{range . }}" + row + "{{end}}" - tmpl := template.Must(template.New("list").Parse(format)) w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) defer w.Flush() diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index 35ef80f3c..ab3b0a197 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -9,7 +9,6 @@ import ( "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/util" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -104,7 +103,7 @@ func imagePull(cmd *cobra.Command, args []string) error { } if pullOptions.Authfile != "" { if _, err := os.Stat(pullOptions.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", pullOptions.Authfile) + return err } } diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index 718bd4e8c..dd45a790f 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -8,7 +8,6 @@ import ( "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/util" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -110,7 +109,7 @@ func imagePush(cmd *cobra.Command, args []string) error { if pushOptions.Authfile != "" { if _, err := os.Stat(pushOptions.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", pushOptions.Authfile) + return err } } diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go index b1a1442a6..774b39d3a 100644 --- a/cmd/podman/images/search.go +++ b/cmd/podman/images/search.go @@ -8,6 +8,7 @@ import ( "github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/report" "github.com/containers/image/v5/types" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/pkg/errors" @@ -98,10 +99,6 @@ func imageSearch(cmd *cobra.Command, args []string) error { return errors.Errorf("search requires exactly one argument") } - if searchOptions.Limit > 100 { - return errors.Errorf("Limit %d is outside the range of [1, 100]", searchOptions.Limit) - } - if searchOptions.ListTags && len(searchOptions.Filters) != 0 { return errors.Errorf("filters are not applicable to list tags result") } @@ -116,7 +113,7 @@ func imageSearch(cmd *cobra.Command, args []string) error { if searchOptions.Authfile != "" { if _, err := os.Stat(searchOptions.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", searchOptions.Authfile) + return err } } @@ -130,26 +127,30 @@ func imageSearch(cmd *cobra.Command, args []string) error { } hdrs := report.Headers(entities.ImageSearchReport{}, nil) - row := "{{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\n" - if searchOptions.ListTags { + renderHeaders := true + var row string + switch { + case searchOptions.ListTags: if len(searchOptions.Filters) != 0 { return errors.Errorf("filters are not applicable to list tags result") } row = "{{.Name}}\t{{.Tag}}\n" - } - if cmd.Flags().Changed("format") { + case cmd.Flags().Changed("format"): + renderHeaders = parse.HasTable(searchOptions.Format) row = report.NormalizeFormat(searchOptions.Format) + default: + row = "{{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\n" } - row = "{{range .}}" + row + "{{end}}" + format := parse.EnforceRange(row) - tmpl, err := template.New("search").Parse(row) + tmpl, err := template.New("search").Parse(format) if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) defer w.Flush() - if !cmd.Flags().Changed("format") { + if renderHeaders { if err := tmpl.Execute(w, hdrs); err != nil { return errors.Wrapf(err, "failed to write search column headers") } diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go index 532af631e..f68e4ed75 100644 --- a/cmd/podman/networks/list.go +++ b/cmd/podman/networks/list.go @@ -8,6 +8,8 @@ import ( "text/tabwriter" "text/template" + "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/libpod/network" @@ -30,8 +32,6 @@ var ( var ( networkListOptions entities.NetworkListOptions - headers = "NAME\tVERSION\tPLUGINS\n" - defaultListRow = "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n" ) func networkListFlags(flags *pflag.FlagSet) { @@ -66,13 +66,12 @@ func networkList(cmd *cobra.Command, args []string) error { return err } - // quiet means we only print the network names - if networkListOptions.Quiet { - return quietOut(responses) - } - - if strings.ToLower(networkListOptions.Format) == "json" { + switch { + case report.IsJSON(networkListOptions.Format): return jsonOut(responses) + case networkListOptions.Quiet: + // quiet means we only print the network names + return quietOut(responses) } nlprs := make([]ListPrintReports, 0, len(responses)) @@ -80,27 +79,32 @@ func networkList(cmd *cobra.Command, args []string) error { nlprs = append(nlprs, ListPrintReports{r}) } - row := networkListOptions.Format - if len(row) < 1 { - row = defaultListRow - } - if !strings.HasSuffix(row, "\n") { - row += "\n" + headers := report.Headers(ListPrintReports{}, map[string]string{ + "CNIVersion": "version", + "Plugins": "plugins", + }) + renderHeaders := true + row := "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n" + if cmd.Flags().Changed("format") { + renderHeaders = parse.HasTable(networkListOptions.Format) + row = report.NormalizeFormat(networkListOptions.Format) } + format := parse.EnforceRange(row) - format := "{{range . }}" + row + "{{end}}" - if !cmd.Flag("format").Changed { - format = headers + format - } tmpl, err := template.New("listNetworks").Parse(format) if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) - if err := tmpl.Execute(w, nlprs); err != nil { - return err + defer w.Flush() + + if renderHeaders { + if err := tmpl.Execute(w, headers); err != nil { + return err + } + } - return w.Flush() + return tmpl.Execute(w, nlprs) } func quietOut(responses []*entities.NetworkListReport) error { diff --git a/cmd/podman/parse/template.go b/cmd/podman/parse/template.go new file mode 100644 index 000000000..0b80f1b3a --- /dev/null +++ b/cmd/podman/parse/template.go @@ -0,0 +1,22 @@ +package parse + +import ( + "regexp" + "strings" +) + +var rangeRegex = regexp.MustCompile(`{{\s*range\s*\.\s*}}.*{{\s*end\s*}}`) + +// TODO move to github.com/containers/common/pkg/report +// EnforceRange ensures that the format string contains a range +func EnforceRange(format string) string { + if !rangeRegex.MatchString(format) { + return "{{range .}}" + format + "{{end}}" + } + return format +} + +// EnforceRange ensures that the format string contains a range +func HasTable(format string) bool { + return strings.HasPrefix(format, "table ") +} diff --git a/cmd/podman/parse/template_test.go b/cmd/podman/parse/template_test.go new file mode 100644 index 000000000..7880d9bec --- /dev/null +++ b/cmd/podman/parse/template_test.go @@ -0,0 +1,30 @@ +package parse + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEnforceRange(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"{{range .}}{{.ID}}{{end}}", "{{range .}}{{.ID}}{{end}}"}, + {"{{.ID}}", "{{range .}}{{.ID}}{{end}}"}, + {"{{ range . }}{{ .ID }}{{ end }}", "{{ range . }}{{ .ID }}{{ end }}"}, + // EnforceRange does not verify syntax or semantics, that will happen later + {"{{range .}}{{.ID}}", "{{range .}}{{range .}}{{.ID}}{{end}}"}, + {".ID", "{{range .}}.ID{{end}}"}, + } + + for _, tc := range tests { + tc := tc + label := "TestEnforceRange_" + tc.input + t.Run(label, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tc.expected, EnforceRange(tc.input)) + }) + } +} diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go index 6072ea80c..feb112ad7 100644 --- a/cmd/podman/play/kube.go +++ b/cmd/podman/play/kube.go @@ -10,7 +10,6 @@ import ( "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/util" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -75,7 +74,7 @@ func kube(cmd *cobra.Command, args []string) error { } if kubeOptions.Authfile != "" { if _, err := os.Stat(kubeOptions.Authfile); err != nil { - return errors.Wrapf(err, "error getting authfile %s", kubeOptions.Authfile) + return err } } if kubeOptions.CredentialsCLI != "" { diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go index 688108c1a..40fc71780 100644 --- a/cmd/podman/pods/ps.go +++ b/cmd/podman/pods/ps.go @@ -11,6 +11,7 @@ import ( "time" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" @@ -113,20 +114,22 @@ func pods(cmd *cobra.Command, _ []string) error { "Created": "CREATED", "InfraID": "INFRA ID", }) + renderHeaders := true row := podPsFormat() if cmd.Flags().Changed("format") { + renderHeaders = parse.HasTable(psInput.Format) row = report.NormalizeFormat(psInput.Format) } - row = "{{range . }}" + row + "{{end}}" + format := parse.EnforceRange(row) - tmpl, err := template.New("listPods").Parse(row) + tmpl, err := template.New("listPods").Parse(format) if err != nil { return err } w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) defer w.Flush() - if !psInput.Quiet && !cmd.Flag("format").Changed { + if renderHeaders { if err := tmpl.Execute(w, headers); err != nil { return err } diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go index 338f13d3e..c5d1e7f07 100644 --- a/cmd/podman/pods/stats.go +++ b/cmd/podman/pods/stats.go @@ -10,6 +10,7 @@ import ( "github.com/buger/goterm" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" @@ -135,7 +136,7 @@ func printFormattedPodStatsLines(headerNames []map[string]string, row string, st return nil } - row = "{{range .}}" + row + "{{end}}" + row = parse.EnforceRange(row) tmpl, err := template.New("pod stats").Parse(row) if err != nil { diff --git a/cmd/podman/system/df.go b/cmd/podman/system/df.go index b11167938..fbdf274fb 100644 --- a/cmd/podman/system/df.go +++ b/cmd/podman/system/df.go @@ -9,6 +9,7 @@ import ( "time" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" @@ -55,7 +56,7 @@ func df(cmd *cobra.Command, args []string) error { w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) if dfOptions.Verbose { - return printVerbose(cmd, w, reports) + return printVerbose(w, cmd, reports) } return printSummary(w, cmd, reports) } @@ -131,20 +132,16 @@ func printSummary(w *tabwriter.Writer, cmd *cobra.Command, reports *entities.Sys "Size": "SIZE", "Reclaimable": "RECLAIMABLE", }) - row := "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n" if cmd.Flags().Changed("format") { row = report.NormalizeFormat(dfOptions.Format) } - row = "{{range . }}" + row + "{{end}}" - - return writeTemplate(cmd, w, hdrs, row, dfSummaries) + return writeTemplate(w, cmd, hdrs, row, dfSummaries) } -func printVerbose(cmd *cobra.Command, w *tabwriter.Writer, reports *entities.SystemDfReport) error { +func printVerbose(w *tabwriter.Writer, cmd *cobra.Command, reports *entities.SystemDfReport) error { defer w.Flush() - // Images fmt.Fprint(w, "Images space usage:\n\n") // convert to dfImage for output dfImages := make([]*dfImage, 0, len(reports.Images)) @@ -157,14 +154,11 @@ func printVerbose(cmd *cobra.Command, w *tabwriter.Writer, reports *entities.Sys "UniqueSize": "UNIQUE SIZE", }) imageRow := "{{.Repository}}\t{{.Tag}}\t{{.ImageID}}\t{{.Created}}\t{{.Size}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}\n" - format := "{{range . }}" + imageRow + "{{end}}" - if err := writeTemplate(cmd, w, hdrs, format, dfImages); err != nil { + if err := writeTemplate(w, cmd, hdrs, imageRow, dfImages); err != nil { return nil } - // Containers fmt.Fprint(w, "\nContainers space usage:\n\n") - // convert to dfContainers for output dfContainers := make([]*dfContainer, 0, len(reports.Containers)) for _, d := range reports.Containers { @@ -176,14 +170,11 @@ func printVerbose(cmd *cobra.Command, w *tabwriter.Writer, reports *entities.Sys "RWSize": "SIZE", }) containerRow := "{{.ContainerID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.RWSize}}\t{{.Created}}\t{{.Status}}\t{{.Names}}\n" - format = "{{range . }}" + containerRow + "{{end}}" - if err := writeTemplate(cmd, w, hdrs, format, dfContainers); err != nil { + if err := writeTemplate(w, cmd, hdrs, containerRow, dfContainers); err != nil { return nil } - // Volumes fmt.Fprint(w, "\nLocal Volumes space usage:\n\n") - dfVolumes := make([]*dfVolume, 0, len(reports.Volumes)) // convert to dfVolume for output for _, d := range reports.Volumes { @@ -193,14 +184,13 @@ func printVerbose(cmd *cobra.Command, w *tabwriter.Writer, reports *entities.Sys "VolumeName": "VOLUME NAME", }) volumeRow := "{{.VolumeName}}\t{{.Links}}\t{{.Size}}\n" - format = "{{range . }}" + volumeRow + "{{end}}" - return writeTemplate(cmd, w, hdrs, format, dfVolumes) + return writeTemplate(w, cmd, hdrs, volumeRow, dfVolumes) } -func writeTemplate(cmd *cobra.Command, w *tabwriter.Writer, hdrs []map[string]string, format string, - output interface{}) error { +func writeTemplate(w *tabwriter.Writer, cmd *cobra.Command, hdrs []map[string]string, format string, output interface{}) error { defer w.Flush() + format = parse.EnforceRange(format) tmpl, err := template.New("df").Parse(format) if err != nil { return err diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go index b3b2b8ea1..ce0b7997d 100644 --- a/cmd/podman/volumes/list.go +++ b/cmd/podman/volumes/list.go @@ -9,6 +9,7 @@ import ( "text/template" "github.com/containers/common/pkg/report" + "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/validate" "github.com/containers/podman/v2/pkg/domain/entities" @@ -91,9 +92,9 @@ func outputTemplate(cmd *cobra.Command, responses []*entities.VolumeListReport) if cliOpts.Quiet { row = "{{.Name}}\n" } - row = "{{range . }}" + row + "{{end}}" + format := parse.EnforceRange(row) - tmpl, err := template.New("list volume").Parse(row) + tmpl, err := template.New("list volume").Parse(format) if err != nil { return err } diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index a3840d7e6..8ccbd95d9 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -85,6 +85,16 @@ case "$CG_FS_TYPE" in *) die_unknown CG_FS_TYPE esac +if ((CONTAINER==0)); then # Not yet running inside a container + # Discovered reemergence of BFQ scheduler bug in kernel 5.8.12-200 + # which causes a kernel panic when system is under heavy I/O load. + # Previously discovered in F32beta and confirmed fixed. It's been + # observed in F31 kernels as well. Deploy workaround for all VMs + # to ensure a more stable I/O scheduler (elevator). + echo "mq-deadline" > /sys/block/sda/queue/scheduler + warn "I/O scheduler: $(cat /sys/block/sda/queue/scheduler)" +fi + # Which distribution are we testing on. case "$OS_RELEASE_ID" in ubuntu*) ;; diff --git a/docs/Readme.md b/docs/Readme.md index 12b78d48f..c517052b3 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -50,6 +50,5 @@ the following: If reloading the page, or clearing your local cache does not fix the problem, it is likely caused by broken metadata needed to protect clients from cross-site-scripting style attacks. Please [notify a maintainer](https://github.com/containers/podman#communications) -so they may investigate how/why the swagger.yaml file's CORS-metadata is incorrect. See -[the Cirrus-CI tasks documentation](../contrib/cirrus/README.md#docs-task) for -details regarding this situation. +so they may investigate how/why the `swagger.yaml` file's CORS-metadata is +incorrect, or the file isn't accessable for some other reason. diff --git a/docs/source/markdown/podman-search.1.md b/docs/source/markdown/podman-search.1.md index fc09d96ea..15a38383a 100644 --- a/docs/source/markdown/podman-search.1.md +++ b/docs/source/markdown/podman-search.1.md @@ -62,7 +62,7 @@ Note: use .Tag only if the --list-tags is set. **--limit**=*limit* -Limit the number of results. This value can be in the range between 1 and 100. The default number of results is 25. +Limit the number of results (default 25). Note: The results from each registry will be limited to this value. Example if limit is 10 and two registries are being searched, the total number of results will be 20, 10 from each (if there are at least 10 matches in each). @@ -10,7 +10,7 @@ require ( github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/containernetworking/cni v0.8.0 github.com/containernetworking/plugins v0.8.7 - github.com/containers/buildah v1.16.5 + github.com/containers/buildah v1.17.0 github.com/containers/common v0.26.3 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.7.0 @@ -72,5 +72,3 @@ require ( k8s.io/apimachinery v0.19.3 k8s.io/client-go v0.0.0-20190620085101-78d2af792bab ) - -replace github.com/containers/buildah => github.com/containers/buildah v1.16.1-0.20201028193114-3ac12986e8cf @@ -83,8 +83,8 @@ github.com/containernetworking/cni v0.8.0 h1:BT9lpgGoH4jw3lFC7Odz2prU5ruiYKcgAjM github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/plugins v0.8.7 h1:bU7QieuAp+sACI2vCzESJ3FoT860urYP+lThyZkb/2M= github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0= -github.com/containers/buildah v1.16.1-0.20201028193114-3ac12986e8cf h1:dFKJs8H7MAXnHTmzBjGDgRuyzLBnHitYNFLPcAuyW/E= -github.com/containers/buildah v1.16.1-0.20201028193114-3ac12986e8cf/go.mod h1:E6nOiMnF3uCAY3wAQK5lPR6w89SRp8iyIkjUfDKW+Eg= +github.com/containers/buildah v1.17.0 h1:oaBIxKtW4kJ06vj4l0C9MZfFVapksf6F4qdQGOvZ2J4= +github.com/containers/buildah v1.17.0/go.mod h1:E6nOiMnF3uCAY3wAQK5lPR6w89SRp8iyIkjUfDKW+Eg= github.com/containers/common v0.26.2/go.mod h1:igUeog5hx8rYhJk67rG6rGAh3zEcf0Uxuzm9KpXzo2E= github.com/containers/common v0.26.3 h1:5Kb5fMmJ7/xMiJ+iEbPA+5pQpl/FGxCgJex4nml4Slo= github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4= diff --git a/libpod/container_internal.go b/libpod/container_internal.go index cafe70b80..0aeaae43d 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -578,10 +578,10 @@ func (c *Container) refresh() error { if len(c.config.IDMappings.UIDMap) != 0 || len(c.config.IDMappings.GIDMap) != 0 { info, err := os.Stat(c.runtime.config.Engine.TmpDir) if err != nil { - return errors.Wrapf(err, "cannot stat `%s`", c.runtime.config.Engine.TmpDir) + return err } if err := os.Chmod(c.runtime.config.Engine.TmpDir, info.Mode()|0111); err != nil { - return errors.Wrapf(err, "cannot chmod `%s`", c.runtime.config.Engine.TmpDir) + return err } root := filepath.Join(c.runtime.config.Engine.TmpDir, "containers-root", c.ID()) if err := os.MkdirAll(root, 0755); err != nil { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 57d5100cf..bf74ca954 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -309,7 +309,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { fallthrough case "Z": if err := label.Relabel(m.Source, c.MountLabel(), label.IsShared(o)); err != nil { - return nil, errors.Wrapf(err, "relabel failed %q", m.Source) + return nil, err } default: @@ -360,11 +360,11 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { for _, overlayVol := range c.config.OverlayVolumes { contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID()) if err != nil { - return nil, errors.Wrapf(err, "failed to create TempDir in the %s directory", c.config.StaticDir) + return nil, err } overlayMount, err := overlay.Mount(contentDir, overlayVol.Source, overlayVol.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions()) if err != nil { - return nil, errors.Wrapf(err, "creating overlay failed %q", overlayVol.Source) + return nil, errors.Wrapf(err, "mounting overlay failed %q", overlayVol.Source) } g.AddMount(overlayMount) } @@ -698,11 +698,31 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro } g.AddMount(systemdMnt) } else { + mountOptions := []string{"bind", "rprivate"} + + var statfs unix.Statfs_t + if err := unix.Statfs("/sys/fs/cgroup/systemd", &statfs); err != nil { + mountOptions = append(mountOptions, "nodev", "noexec", "nosuid") + } else { + if statfs.Flags&unix.MS_NODEV == unix.MS_NODEV { + mountOptions = append(mountOptions, "nodev") + } + if statfs.Flags&unix.MS_NOEXEC == unix.MS_NOEXEC { + mountOptions = append(mountOptions, "noexec") + } + if statfs.Flags&unix.MS_NOSUID == unix.MS_NOSUID { + mountOptions = append(mountOptions, "nosuid") + } + if statfs.Flags&unix.MS_RDONLY == unix.MS_RDONLY { + mountOptions = append(mountOptions, "ro") + } + } + systemdMnt := spec.Mount{ Destination: "/sys/fs/cgroup/systemd", Type: "bind", Source: "/sys/fs/cgroup/systemd", - Options: []string{"bind", "nodev", "noexec", "nosuid", "rprivate"}, + Options: mountOptions, } g.AddMount(systemdMnt) g.AddLinuxMaskedPaths("/sys/fs/cgroup/systemd/release_agent") @@ -811,7 +831,7 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error { return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList) } if err := ioutil.WriteFile(deleteFilesList, formatJSON, 0600); err != nil { - return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList) + return errors.Wrap(err, "error creating delete files list file") } includeFiles = append(includeFiles, "deleted.files") @@ -835,7 +855,7 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error { defer outFile.Close() if err := os.Chmod(dest, 0600); err != nil { - return errors.Wrapf(err, "cannot chmod %q", dest) + return err } _, err = io.Copy(outFile, input) @@ -1059,7 +1079,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti if n.Sandbox != "" { MAC, err = net.ParseMAC(n.Mac) if err != nil { - return errors.Wrapf(err, "failed to parse MAC %v", n.Mac) + return err } break } @@ -1163,14 +1183,14 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti return errors.Wrapf(err, "failed to read deleted files file") } if err := json.Unmarshal(deletedFilesJSON, &deletedFiles); err != nil { - return errors.Wrapf(err, "failed to read deleted files file %s", deletedFilesPath) + return errors.Wrapf(err, "failed to unmarshal deleted files file %s", deletedFilesPath) } for _, deleteFile := range deletedFiles { // Using RemoveAll as deletedFiles, which is generated from 'podman diff' // lists completely deleted directories as a single entry: 'D /root'. err = os.RemoveAll(filepath.Join(c.state.Mountpoint, deleteFile)) if err != nil { - return errors.Wrapf(err, "failed to delete file %s from container %s during restore", deletedFilesPath, c.ID()) + return errors.Wrapf(err, "failed to delete files from container %s during restore", c.ID()) } } } @@ -1209,7 +1229,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti // Make standard bind mounts to include in the container func (c *Container) makeBindMounts() error { if err := os.Chown(c.state.RunDir, c.RootUID(), c.RootGID()); err != nil { - return errors.Wrapf(err, "cannot chown run directory %s", c.state.RunDir) + return errors.Wrap(err, "cannot chown run directory") } if c.state.BindMounts == nil { @@ -1227,13 +1247,13 @@ func (c *Container) makeBindMounts() error { if c.config.NetNsCtr == "" { if resolvePath, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { if err := os.Remove(resolvePath); err != nil && !os.IsNotExist(err) { - return errors.Wrapf(err, "error removing container %s resolv.conf", c.ID()) + return errors.Wrapf(err, "container %s", c.ID()) } delete(c.state.BindMounts, "/etc/resolv.conf") } if hostsPath, ok := c.state.BindMounts["/etc/hosts"]; ok { if err := os.Remove(hostsPath); err != nil && !os.IsNotExist(err) { - return errors.Wrapf(err, "error removing container %s hosts", c.ID()) + return errors.Wrapf(err, "container %s", c.ID()) } delete(c.state.BindMounts, "/etc/hosts") } @@ -1433,7 +1453,7 @@ func (c *Container) generateResolvConf() (string, error) { if err == nil { resolvConf = definedPath } else if !os.IsNotExist(err) { - return "", errors.Wrapf(err, "failed to stat %s", definedPath) + return "", err } } break @@ -1455,7 +1475,7 @@ func (c *Container) generateResolvConf() (string, error) { contents, err := ioutil.ReadFile(resolvPath) // resolv.conf doesn't have to exists if err != nil && !os.IsNotExist(err) { - return "", errors.Wrapf(err, "unable to read %s", resolvPath) + return "", err } // Ensure that the container's /etc/resolv.conf is compatible with its @@ -1524,7 +1544,7 @@ func (c *Container) generateResolvConf() (string, error) { destPath := filepath.Join(c.state.RunDir, "resolv.conf") if err := os.Remove(destPath); err != nil && !os.IsNotExist(err) { - return "", errors.Wrapf(err, "error removing resolv.conf for container %s", c.ID()) + return "", errors.Wrapf(err, "container %s", c.ID()) } // Build resolv.conf @@ -1544,7 +1564,7 @@ func (c *Container) generateResolvConf() (string, error) { func (c *Container) generateHosts(path string) (string, error) { orig, err := ioutil.ReadFile(path) if err != nil { - return "", errors.Wrapf(err, "unable to read %s", path) + return "", err } hosts := string(orig) hosts += c.getHosts() @@ -1947,7 +1967,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { } orig, err := ioutil.ReadFile(originPasswdFile) if err != nil && !os.IsNotExist(err) { - return "", "", errors.Wrapf(err, "unable to read passwd file %s", originPasswdFile) + return "", "", err } passwdFile, err := c.writeStringToStaticDir("passwd", string(orig)+passwdEntry) if err != nil { @@ -1966,7 +1986,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { f, err := os.OpenFile(containerPasswd, os.O_APPEND|os.O_WRONLY, 0600) if err != nil { - return "", "", errors.Wrapf(err, "error opening container %s /etc/passwd", c.ID()) + return "", "", errors.Wrapf(err, "container %s", c.ID()) } defer f.Close() @@ -1993,7 +2013,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { } orig, err := ioutil.ReadFile(originGroupFile) if err != nil && !os.IsNotExist(err) { - return "", "", errors.Wrapf(err, "unable to read group file %s", originGroupFile) + return "", "", err } groupFile, err := c.writeStringToStaticDir("group", string(orig)+groupEntry) if err != nil { @@ -2012,7 +2032,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { f, err := os.OpenFile(containerGroup, os.O_APPEND|os.O_WRONLY, 0600) if err != nil { - return "", "", errors.Wrapf(err, "error opening container %s /etc/group", c.ID()) + return "", "", errors.Wrapf(err, "container %s", c.ID()) } defer f.Close() @@ -2033,13 +2053,13 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error { if os.IsNotExist(err) { return nil } - return errors.Wrapf(err, "cannot stat `%s`", dest) + return err } if err := os.Chmod(dest, info.Mode()); err != nil { - return errors.Wrapf(err, "cannot chmod `%s`", dest) + return err } if err := os.Chown(dest, int(info.Sys().(*syscall.Stat_t).Uid), int(info.Sys().(*syscall.Stat_t).Gid)); err != nil { - return errors.Wrapf(err, "cannot chown `%s`", dest) + return err } return nil } @@ -2130,7 +2150,7 @@ func (c *Container) checkFileExistsInRootfs(file string) (bool, error) { if os.IsNotExist(err) { return false, nil } - return false, errors.Wrapf(err, "error accessing container %s file %q", c.ID(), file) + return false, errors.Wrapf(err, "container %s", c.ID()) } if stat.IsDir() { return false, nil diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go index bd55b852e..f77075893 100644 --- a/libpod/healthcheck.go +++ b/libpod/healthcheck.go @@ -223,7 +223,7 @@ func (c *Container) GetHealthCheckLog() (define.HealthCheckResults, error) { } b, err := ioutil.ReadFile(c.healthCheckLogPath()) if err != nil { - return healthCheck, errors.Wrapf(err, "failed to read health check log file %s", c.healthCheckLogPath()) + return healthCheck, errors.Wrap(err, "failed to read health check log file") } if err := json.Unmarshal(b, &healthCheck); err != nil { return healthCheck, errors.Wrapf(err, "failed to unmarshal existing healthcheck results in %s", c.healthCheckLogPath()) diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 9ff6e40b7..28dca8dd8 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -102,17 +102,7 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re requestedMAC = ctr.config.StaticMAC } - // If we are in a pod use the pod name for the network, otherwise the container name - var podName string - if ctr.PodID() != "" { - pod, err := r.GetPod(ctr.PodID()) - if err == nil { - podName = pod.Name() - } - } - if podName == "" { - podName = ctr.Name() - } + podName := getCNIPodName(ctr) podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC) diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 94630e57b..89d64537d 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -120,7 +120,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime if os.IsNotExist(err) { continue } - return nil, errors.Wrapf(err, "cannot stat OCI runtime %s path %q", name, path) + return nil, errors.Wrapf(err, "cannot stat OCI runtime %s path", name) } if !stat.Mode().IsRegular() { continue diff --git a/libpod/options.go b/libpod/options.go index 5d1ce8755..060887b7e 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1296,7 +1296,7 @@ func WithRootFS(rootfs string) CtrCreateOption { return define.ErrCtrFinalized } if _, err := os.Stat(rootfs); err != nil { - return errors.Wrapf(err, "error checking path %q", rootfs) + return err } ctr.config.Rootfs = rootfs return nil diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go index 21e43ebd0..3d4ff6e86 100644 --- a/libpod/rootless_cni_linux.go +++ b/libpod/rootless_cni_linux.go @@ -53,7 +53,7 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes. if err != nil { return nil, nil, err } - k8sPodName := getPodOrContainerName(c) // passed to CNI as K8S_POD_NAME + k8sPodName := getCNIPodName(c) // passed to CNI as K8S_POD_NAME cniResults := make([]*cnitypes.Result, len(c.config.Networks)) for i, nw := range c.config.Networks { cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName) @@ -115,12 +115,16 @@ func getRootlessCNIInfraLock(r *Runtime) (lockfile.Locker, error) { return lockfile.GetLockfile(fname) } -func getPodOrContainerName(c *Container) string { - pod, err := c.runtime.GetPod(c.PodID()) - if err != nil || pod.config.Name == "" { - return c.Name() +// getCNIPodName return the pod name (hostname) used by CNI and the dnsname plugin. +// If we are in the pod network namespace use the pod name otherwise the container name +func getCNIPodName(c *Container) string { + if c.config.NetMode.IsPod() || c.IsInfra() { + pod, err := c.runtime.GetPod(c.PodID()) + if err == nil { + return pod.Name() + } } - return pod.config.Name + return c.Name() } func rootlessCNIInfraCallAlloc(infra *Container, id, nw, k8sPodName string) (*cnitypes.Result, error) { diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go index 3dc38f442..1ad32fe9c 100644 --- a/libpod/runtime_migrate.go +++ b/libpod/runtime_migrate.go @@ -29,7 +29,7 @@ func stopPauseProcess() error { if os.IsNotExist(err) { return nil } - return errors.Wrapf(err, "cannot read pause process pid file %s", pausePidPath) + return errors.Wrap(err, "cannot read pause process pid file") } pausePid, err := strconv.Atoi(string(data)) if err != nil { diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 7f58e86d8..76419587a 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -131,6 +131,7 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm logrus.Debugf("Using %q as infra container entrypoint", entryCmd) + g.RemoveMount("/dev/shm") if isRootless { g.RemoveMount("/dev/pts") devPts := spec.Mount{ diff --git a/libpod/util.go b/libpod/util.go index 585b07aca..c26039c50 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -74,7 +74,7 @@ func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, e return false, nil } if !os.IsNotExist(err) { - return false, errors.Wrapf(err, "checking file %s", path) + return false, err } case <-time.After(25 * time.Millisecond): // Check periodically for the file existence. It is needed @@ -86,7 +86,7 @@ func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, e return false, nil } if !os.IsNotExist(err) { - return false, errors.Wrapf(err, "checking file %s", path) + return false, err } case <-timeoutChan: return false, errors.Wrapf(define.ErrInternal, "timed out waiting for file %s", path) @@ -184,11 +184,11 @@ func DefaultSeccompPath() (string, error) { return config.SeccompOverridePath, nil } if !os.IsNotExist(err) { - return "", errors.Wrapf(err, "can't check if %q exists", config.SeccompOverridePath) + return "", err } if _, err := os.Stat(config.SeccompDefaultPath); err != nil { if !os.IsNotExist(err) { - return "", errors.Wrapf(err, "can't check if %q exists", config.SeccompDefaultPath) + return "", err } return "", nil } diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go index ab90c8183..8f4f5d3d7 100644 --- a/pkg/domain/infra/abi/cp.go +++ b/pkg/domain/infra/abi/cp.go @@ -214,7 +214,7 @@ func getPathInfo(path string) (string, os.FileInfo, error) { } srcfi, err := os.Stat(path) if err != nil { - return "", nil, errors.Wrapf(err, "error reading path %q", path) + return "", nil, err } return path, srcfi, nil } @@ -245,7 +245,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID } _, err = os.Stat(destdir) if err != nil && !os.IsNotExist(err) { - return errors.Wrapf(err, "error checking directory %q", destdir) + return err } destDirIsExist := err == nil if err = os.MkdirAll(destdir, 0755); err != nil { @@ -292,7 +292,7 @@ func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.ID destfi, err := os.Stat(destPath) if err != nil { if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) { - return errors.Wrapf(err, "failed to get stat of dest path %s", destPath) + return err } } if destfi != nil && destfi.IsDir() { diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index 6c518e678..ad7128b42 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -25,6 +25,7 @@ import ( "github.com/containers/podman/v2/pkg/domain/entities" "github.com/opencontainers/go-digest" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sirupsen/logrus" "github.com/pkg/errors" ) @@ -90,10 +91,6 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte continue } - if !manifest.MIMETypeIsMultiImage(manifestType) { - appendErr(errors.Errorf("manifest is of type %s (not a list type)", manifestType)) - continue - } result = manifestBytes manType = manifestType break @@ -101,7 +98,18 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte if len(result) == 0 && latestErr != nil { return nil, latestErr } - if manType != manifest.DockerV2ListMediaType { + + switch manType { + case manifest.DockerV2Schema2MediaType: + logrus.Warnf("Warning! The manifest type %s is not a manifest list but a single image.", manType) + schema2Manifest, err := manifest.Schema2FromManifest(result) + if err != nil { + return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType) + } + if result, err = schema2Manifest.Serialize(); err != nil { + return nil, err + } + default: listBlob, err := manifest.ListFromBlob(result, manType) if err != nil { return nil, errors.Wrapf(err, "error parsing manifest blob %q as a %q", string(result), manType) @@ -113,10 +121,9 @@ func (ir *ImageEngine) ManifestInspect(ctx context.Context, name string) ([]byte if result, err = list.Serialize(); err != nil { return nil, err } - } - err = json.Indent(&b, result, "", " ") - if err != nil { + + if err = json.Indent(&b, result, "", " "); err != nil { return nil, errors.Wrapf(err, "error rendering manifest %s for display", name) } return b.Bytes(), nil diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 348570a20..57de0f3b1 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -251,7 +251,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY case v1.HostPathDirectoryOrCreate: if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil { - return nil, errors.Errorf("error creating HostPath %s", volume.Name) + return nil, err } } // Label a newly created volume @@ -262,7 +262,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission) if err != nil { - return nil, errors.Errorf("error creating HostPath %s", volume.Name) + return nil, errors.Wrap(err, "error creating HostPath") } if err := f.Close(); err != nil { logrus.Warnf("Error in closing newly created HostPath file: %v", err) diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go index 0c586cf5c..2aca8f22d 100644 --- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go +++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go @@ -5,8 +5,10 @@ import ( "syscall" "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/shutdown" "github.com/containers/podman/v2/pkg/signal" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -33,12 +35,16 @@ func ProxySignals(ctr *libpod.Container) { } if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil { + if errors.Cause(err) == define.ErrCtrStateInvalid { + logrus.Infof("Ceasing signal forwarding to container %s as it has stopped", ctr.ID()) + } else { + logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err) + } // If the container dies, and we find out here, // we need to forward that one signal to // ourselves so that it is not lost, and then // we terminate the proxy and let the defaults // play out. - logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err) signal.StopCatch(sigBuffer) if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil { logrus.Errorf("failed to kill pid %d", syscall.Getpid()) diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go index 38d93b87f..9ebcf8d29 100644 --- a/pkg/spec/parse.go +++ b/pkg/spec/parse.go @@ -173,7 +173,7 @@ func ParseDevice(device string) (string, string, string, error) { //nolint if IsValidDeviceMode(arr[1]) { permissions = arr[1] } else { - if arr[1][0] != '/' { + if len(arr[1]) == 0 || arr[1][0] != '/' { return "", "", "", fmt.Errorf("invalid device mode: %s", arr[1]) } dst = arr[1] diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go index fac02ad01..fcb7641d2 100644 --- a/pkg/specgen/generate/config_linux.go +++ b/pkg/specgen/generate/config_linux.go @@ -52,7 +52,7 @@ func addPrivilegedDevices(g *generate.Generator) error { if err == unix.EPERM { continue } - return errors.Wrapf(err, "stat %s", d.Path) + return err } // Skip devices that the user has not access to. if st.Mode()&0007 == 0 { @@ -90,7 +90,7 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error { } st, err := os.Stat(resolvedDevicePath) if err != nil { - return errors.Wrapf(err, "cannot stat device path %s", devicePath) + return err } if st.IsDir() { found := false @@ -231,10 +231,7 @@ func addDevice(g *generate.Generator, device string) error { } if rootless.IsRootless() { if _, err := os.Stat(src); err != nil { - if os.IsNotExist(err) { - return errors.Wrapf(err, "the specified device %s doesn't exist", src) - } - return errors.Wrapf(err, "stat device %s exist", src) + return err } perm := "ro" if strings.Contains(permissions, "w") { diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 7e4f09dc4..ddc73ca61 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -127,6 +127,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod. return nil, errNoInfra } toReturn = append(toReturn, libpod.WithIPCNSFrom(infraCtr)) + toReturn = append(toReturn, libpod.WithShmDir(infraCtr.ShmDir())) case specgen.FromContainer: ipcCtr, err := rt.LookupContainer(s.IpcNS.Value) if err != nil { @@ -278,7 +279,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.PidNS.NSMode { case specgen.Path: if _, err := os.Stat(s.PidNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified PID namespace path %q", s.PidNS.Value) + return errors.Wrap(err, "cannot find specified PID namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil { return err @@ -297,7 +298,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.IpcNS.NSMode { case specgen.Path: if _, err := os.Stat(s.IpcNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified IPC namespace path %q", s.IpcNS.Value) + return errors.Wrap(err, "cannot find specified IPC namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil { return err @@ -316,7 +317,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.UtsNS.NSMode { case specgen.Path: if _, err := os.Stat(s.UtsNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified UTS namespace path %q", s.UtsNS.Value) + return errors.Wrap(err, "cannot find specified UTS namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil { return err @@ -367,7 +368,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.UserNS.NSMode { case specgen.Path: if _, err := os.Stat(s.UserNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified user namespace path %s", s.UserNS.Value) + return errors.Wrap(err, "cannot find specified user namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.UserNamespace), s.UserNS.Value); err != nil { return err @@ -410,7 +411,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.CgroupNS.NSMode { case specgen.Path: if _, err := os.Stat(s.CgroupNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified cgroup namespace path %s", s.CgroupNS.Value) + return errors.Wrap(err, "cannot find specified cgroup namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil { return err @@ -429,7 +430,7 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt switch s.NetNS.NSMode { case specgen.Path: if _, err := os.Stat(s.NetNS.Value); err != nil { - return errors.Wrapf(err, "cannot find specified network namespace path %s", s.NetNS.Value) + return errors.Wrap(err, "cannot find specified network namespace path") } if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil { return err diff --git a/pkg/specgen/generate/validate.go b/pkg/specgen/generate/validate.go index 92fd12770..f0ab4b994 100644 --- a/pkg/specgen/generate/validate.go +++ b/pkg/specgen/generate/validate.go @@ -34,7 +34,7 @@ func verifyContainerResourcesCgroupV1(s *specgen.SpecGenerator) ([]string, error memory.Swap = nil } if memory.Limit != nil && memory.Swap != nil && !sysInfo.SwapLimit { - warnings = append(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.") + warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.") memory.Swap = nil } if memory.Limit != nil && memory.Swap != nil && *memory.Swap < *memory.Limit { diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index f984345f4..29a62e5bb 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -58,6 +58,11 @@ var _ = Describe("Podman manifest", func() { session = podmanTest.PodmanNoCache([]string{"manifest", "inspect", "quay.io/libpod/busybox"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + + // inspect manifest of single image + session = podmanTest.PodmanNoCache([]string{"manifest", "inspect", "quay.io/libpod/busybox@sha256:6655df04a3df853b029a5fac8836035ac4fab117800c9a6c4b69341bb5306c3d"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) }) It("podman manifest add", func() { diff --git a/test/e2e/pod_pod_namespaces.go b/test/e2e/pod_pod_namespaces.go index 41e9c5683..20b8bdb39 100644 --- a/test/e2e/pod_pod_namespaces.go +++ b/test/e2e/pod_pod_namespaces.go @@ -60,6 +60,25 @@ var _ = Describe("Podman pod create", func() { Expect(NAMESPACE1).To(Equal(NAMESPACE2)) }) + It("podman pod container share ipc && /dev/shm ", func() { + session := podmanTest.Podman([]string{"pod", "create"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podID := session.OutputToString() + + session = podmanTest.Podman([]string{"pod", "start", podID}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"run", "--rm", "--pod", podID, ALPINE, "touch", "/dev/shm/test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"run", "--rm", "--pod", podID, ALPINE, "ls", "/dev/shm/test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman pod container dontshare PIDNS", func() { session := podmanTest.Podman([]string{"pod", "create"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 9f6fd8602..a3cc352b1 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -594,4 +594,39 @@ var _ = Describe("Podman run networking", func() { Expect(run.ExitCode()).To(BeZero()) Expect(strings.Contains(run.OutputToString(), hostname)).To(BeTrue()) }) + + It("podman run check dnsname plugin", func() { + pod := "testpod" + session := podmanTest.Podman([]string{"pod", "create", "--name", pod}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + + net := "dnsNetTest" + session = podmanTest.Podman([]string{"network", "create", net}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(net) + + pod2 := "testpod2" + session = podmanTest.Podman([]string{"pod", "create", "--network", net, "--name", pod2}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + + session = podmanTest.Podman([]string{"run", "--name", "con1", "--network", net, ALPINE, "nslookup", "con1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + + session = podmanTest.Podman([]string{"run", "--name", "con2", "--pod", pod, "--network", net, ALPINE, "nslookup", "con2"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + + session = podmanTest.Podman([]string{"run", "--name", "con3", "--pod", pod2, ALPINE, "nslookup", "con3"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(1)) + Expect(session.ErrorToString()).To(ContainSubstring("can't resolve 'con3'")) + + session = podmanTest.Podman([]string{"run", "--name", "con4", "--network", net, ALPINE, "nslookup", pod2}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + }) }) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 4f2751099..424a191c5 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -460,4 +460,11 @@ registries = ['{{.Host}}:{{.Port}}']` search.WaitWithDefaultTimeout() Expect(len(search.OutputToStringArray()) == 0).To(BeTrue()) }) + + It("podman search with limit over 100", func() { + search := podmanTest.Podman([]string{"search", "--limit", "130", "registry.redhat.io/rhel"}) + search.WaitWithDefaultTimeout() + Expect(search.ExitCode()).To(Equal(0)) + Expect(len(search.OutputToStringArray())).To(Equal(131)) + }) }) diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats index a350c2173..6bf897790 100644 --- a/test/system/065-cp.bats +++ b/test/system/065-cp.bats @@ -148,7 +148,7 @@ load helpers is "$output" "" "output from podman cp 1" run_podman 125 cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/ - is "$output" "Error: failed to get stat of dest path .*stat.* no such file or directory" "cp will not create nonexistent destination directory" + is "$output" ".*stat.* no such file or directory" "cp will not create nonexistent destination directory" run_podman cp --pause=false $srcdir/$rand_filename3 cpcontainer:/tmp/d3/x is "$output" "" "output from podman cp 3" diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 1d17c8cad..b0f645c53 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -116,6 +116,30 @@ function teardown() { run_podman 1 pod exists $podname } +@test "podman pod - communicating via /dev/shm " { + if is_remote && is_rootless; then + skip "FIXME: pending #7139" + fi + + podname=pod$(random_string) + run_podman 1 pod exists $podname + run_podman pod create --infra=true --name=$podname + podid="$output" + run_podman pod exists $podname + run_podman pod exists $podid + + run_podman run --rm --pod $podname $IMAGE touch /dev/shm/test1 + run_podman run --rm --pod $podname $IMAGE ls /dev/shm/test1 + is "$output" "/dev/shm/test1" + + # ...then rm the pod, then rmi the pause image so we don't leave strays. + run_podman pod rm $podname + + # Pod no longer exists + run_podman 1 pod exists $podid + run_podman 1 pod exists $podname +} + # Random byte function octet() { echo $(( $RANDOM & 255 )) diff --git a/test/utils/utils.go b/test/utils/utils.go index cb76d4a54..dd836f258 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -14,7 +14,7 @@ import ( "github.com/containers/storage/pkg/parsers/kernel" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" + . "github.com/onsi/gomega/gexec" ) var ( @@ -48,7 +48,7 @@ type PodmanTest struct { // PodmanSession wraps the gexec.session so we can extend it type PodmanSession struct { - *gexec.Session + *Session } // HostOS is a simple struct for the test os @@ -96,7 +96,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string command.ExtraFiles = extraFiles - session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + session, err := Start(command, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("unable to run podman command: %s\n%v", strings.Join(podmanOptions, " "), err)) } @@ -125,7 +125,7 @@ func (p *PodmanTest) NumberOfContainersRunning() int { var containers []string ps := p.PodmanBase([]string{"ps", "-q"}, false, true) ps.WaitWithDefaultTimeout() - Expect(ps.ExitCode()).To(Equal(0)) + Expect(ps).Should(Exit(0)) for _, i := range ps.OutputToStringArray() { if i != "" { containers = append(containers, i) @@ -318,7 +318,7 @@ func (s *PodmanSession) IsJSONOutputValid() bool { // WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout func (s *PodmanSession) WaitWithDefaultTimeout() { - Eventually(s, defaultWaitTimeout).Should(gexec.Exit()) + Eventually(s, defaultWaitTimeout).Should(Exit()) os.Stdout.Sync() os.Stderr.Sync() fmt.Println("output:", s.OutputToString()) @@ -332,7 +332,7 @@ func CreateTempDirInTempDir() (string, error) { // SystemExec is used to exec a system command to check its exit code or output func SystemExec(command string, args []string) *PodmanSession { c := exec.Command(command, args...) - session, err := gexec.Start(c, GinkgoWriter, GinkgoWriter) + session, err := Start(c, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " "))) } @@ -343,7 +343,7 @@ func SystemExec(command string, args []string) *PodmanSession { // StartSystemExec is used to start exec a system command func StartSystemExec(command string, args []string) *PodmanSession { c := exec.Command(command, args...) - session, err := gexec.Start(c, GinkgoWriter, GinkgoWriter) + session, err := Start(c, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " "))) } diff --git a/vendor/github.com/containers/buildah/CHANGELOG.md b/vendor/github.com/containers/buildah/CHANGELOG.md index c68a8c5f3..e0a2671f7 100644 --- a/vendor/github.com/containers/buildah/CHANGELOG.md +++ b/vendor/github.com/containers/buildah/CHANGELOG.md @@ -2,6 +2,96 @@ # Changelog +## v1.17.0 (2020-10-29) + Handle cases where other tools mount/unmount containers + overlay.MountReadOnly: support RO overlay mounts + overlay: use fusermount for rootless umounts + overlay: fix umount + Switch default log level of Buildah to Warn. Users need to see these messages + Drop error messages about OCI/Docker format to Warning level + build(deps): bump github.com/containers/common from 0.26.0 to 0.26.2 + tests/testreport: adjust for API break in storage v1.23.6 + build(deps): bump github.com/containers/storage from 1.23.5 to 1.23.7 + build(deps): bump github.com/fsouza/go-dockerclient from 1.6.5 to 1.6.6 + copier: put: ignore Typeflag="g" + Use curl to get repo file (fix #2714) + build(deps): bump github.com/containers/common from 0.25.0 to 0.26.0 + build(deps): bump github.com/spf13/cobra from 1.0.0 to 1.1.1 + Remove docs that refer to bors, since we're not using it + Buildah bud should not use stdin by default + bump containerd, docker, and golang.org/x/sys + Makefile: cross: remove windows.386 target + copier.copierHandlerPut: don't check length when there are errors + Stop excessive wrapping + CI: require that conformance tests pass + bump(github.com/openshift/imagebuilder) to v1.1.8 + Skip tlsVerify insecure BUILD_REGISTRY_SOURCES + Fix build path wrong https://github.com/containers/podman/issues/7993 + refactor pullpolicy to avoid deps + build(deps): bump github.com/containers/common from 0.24.0 to 0.25.0 + CI: run gating tasks with a lot more memory + ADD and COPY: descend into excluded directories, sometimes + copier: add more context to a couple of error messages + copier: check an error earlier + copier: log stderr output as debug on success + Update nix pin with `make nixpkgs` + Set directory ownership when copied with ID mapping + build(deps): bump github.com/sirupsen/logrus from 1.6.0 to 1.7.0 + build(deps): bump github.com/containers/common from 0.23.0 to 0.24.0 + Cirrus: Remove bors artifacts + Sort build flag definitions alphabetically + ADD: only expand archives at the right time + Remove configuration for bors + Shell Completion for podman build flags + Bump c/common to v0.24.0 + New CI check: xref --help vs man pages + CI: re-enable several linters + Move --userns-uid-map/--userns-gid-map description into buildah man page + add: preserve ownerships and permissions on ADDed archives + Makefile: tweak the cross-compile target + Bump containers/common to v0.23.0 + chroot: create bind mount targets 0755 instead of 0700 + Change call to Split() to safer SplitN() + chroot: fix handling of errno seccomp rules + build(deps): bump github.com/containers/image/v5 from 5.5.2 to 5.6.0 + Add In Progress section to contributing + integration tests: make sure tests run in ${topdir}/tests + Run(): ignore containers.conf's environment configuration + Warn when setting healthcheck in OCI format + Cirrus: Skip git-validate on branches + tools: update git-validation to the latest commit + tools: update golangci-lint to v1.18.0 + Add a few tests of push command + Add(): fix handling of relative paths with no ContextDir + build(deps): bump github.com/containers/common from 0.21.0 to 0.22.0 + Lint: Use same linters as podman + Validate: reference HEAD + Fix buildah mount to display container names not ids + Update nix pin with `make nixpkgs` + Add missing --format option in buildah from man page + Fix up code based on codespell + build(deps): bump github.com/openshift/imagebuilder from 1.1.6 to 1.1.7 + build(deps): bump github.com/containers/storage from 1.23.4 to 1.23.5 + Improve buildah completions + Cirrus: Fix validate commit epoch + Fix bash completion of manifest flags + Uniform some man pages + Update Buildah Tutorial to address BZ1867426 + Update bash completion of `manifest add` sub command + copier.Get(): hard link targets shouldn't be relative paths + build(deps): bump github.com/onsi/gomega from 1.10.1 to 1.10.2 + Pass timestamp down to history lines + Timestamp gets updated everytime you inspect an image + bud.bats: use absolute paths in newly-added tests + contrib/cirrus/lib.sh: don't use CN for the hostname + tests: Add some tests + Update `manifest add` man page + Extend flags of `manifest add` + build(deps): bump github.com/containers/storage from 1.23.3 to 1.23.4 + build(deps): bump github.com/onsi/ginkgo from 1.14.0 to 1.14.1 + Bump to v1.17.0-dev + CI: expand cross-compile checks + ## v1.16.0 (2020-09-03) fix build on 32bit arches containerImageRef.NewImageSource(): don't always force timestamps diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 90941878a..86695508c 100644 --- a/vendor/github.com/containers/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -28,7 +28,7 @@ const ( Package = "buildah" // Version for the Package. Bump version in contrib/rpm/buildah.spec // too. - Version = "1.17.0-dev" + Version = "1.17.0" // The value we use to identify what type of information, currently a // serialized Builder structure, we are using as per-container state. // This should only be changed when we make incompatible changes to diff --git a/vendor/github.com/containers/buildah/changelog.txt b/vendor/github.com/containers/buildah/changelog.txt index 6aa90f288..df19d0746 100644 --- a/vendor/github.com/containers/buildah/changelog.txt +++ b/vendor/github.com/containers/buildah/changelog.txt @@ -1,3 +1,93 @@ +- Changelog for v1.17.0 (2020-10-29) + * Handle cases where other tools mount/unmount containers + * overlay.MountReadOnly: support RO overlay mounts + * overlay: use fusermount for rootless umounts + * overlay: fix umount + * Switch default log level of Buildah to Warn. Users need to see these messages + * Drop error messages about OCI/Docker format to Warning level + * build(deps): bump github.com/containers/common from 0.26.0 to 0.26.2 + * tests/testreport: adjust for API break in storage v1.23.6 + * build(deps): bump github.com/containers/storage from 1.23.5 to 1.23.7 + * build(deps): bump github.com/fsouza/go-dockerclient from 1.6.5 to 1.6.6 + * copier: put: ignore Typeflag="g" + * Use curl to get repo file (fix #2714) + * build(deps): bump github.com/containers/common from 0.25.0 to 0.26.0 + * build(deps): bump github.com/spf13/cobra from 1.0.0 to 1.1.1 + * Remove docs that refer to bors, since we're not using it + * Buildah bud should not use stdin by default + * bump containerd, docker, and golang.org/x/sys + * Makefile: cross: remove windows.386 target + * copier.copierHandlerPut: don't check length when there are errors + * Stop excessive wrapping + * CI: require that conformance tests pass + * bump(github.com/openshift/imagebuilder) to v1.1.8 + * Skip tlsVerify insecure BUILD_REGISTRY_SOURCES + * Fix build path wrong https://github.com/containers/podman/issues/7993 + * refactor pullpolicy to avoid deps + * build(deps): bump github.com/containers/common from 0.24.0 to 0.25.0 + * CI: run gating tasks with a lot more memory + * ADD and COPY: descend into excluded directories, sometimes + * copier: add more context to a couple of error messages + * copier: check an error earlier + * copier: log stderr output as debug on success + * Update nix pin with `make nixpkgs` + * Set directory ownership when copied with ID mapping + * build(deps): bump github.com/sirupsen/logrus from 1.6.0 to 1.7.0 + * build(deps): bump github.com/containers/common from 0.23.0 to 0.24.0 + * Cirrus: Remove bors artifacts + * Sort build flag definitions alphabetically + * ADD: only expand archives at the right time + * Remove configuration for bors + * Shell Completion for podman build flags + * Bump c/common to v0.24.0 + * New CI check: xref --help vs man pages + * CI: re-enable several linters + * Move --userns-uid-map/--userns-gid-map description into buildah man page + * add: preserve ownerships and permissions on ADDed archives + * Makefile: tweak the cross-compile target + * Bump containers/common to v0.23.0 + * chroot: create bind mount targets 0755 instead of 0700 + * Change call to Split() to safer SplitN() + * chroot: fix handling of errno seccomp rules + * build(deps): bump github.com/containers/image/v5 from 5.5.2 to 5.6.0 + * Add In Progress section to contributing + * integration tests: make sure tests run in ${topdir}/tests + * Run(): ignore containers.conf's environment configuration + * Warn when setting healthcheck in OCI format + * Cirrus: Skip git-validate on branches + * tools: update git-validation to the latest commit + * tools: update golangci-lint to v1.18.0 + * Add a few tests of push command + * Add(): fix handling of relative paths with no ContextDir + * build(deps): bump github.com/containers/common from 0.21.0 to 0.22.0 + * Lint: Use same linters as podman + * Validate: reference HEAD + * Fix buildah mount to display container names not ids + * Update nix pin with `make nixpkgs` + * Add missing --format option in buildah from man page + * Fix up code based on codespell + * build(deps): bump github.com/openshift/imagebuilder from 1.1.6 to 1.1.7 + * build(deps): bump github.com/containers/storage from 1.23.4 to 1.23.5 + * Improve buildah completions + * Cirrus: Fix validate commit epoch + * Fix bash completion of manifest flags + * Uniform some man pages + * Update Buildah Tutorial to address BZ1867426 + * Update bash completion of `manifest add` sub command + * copier.Get(): hard link targets shouldn't be relative paths + * build(deps): bump github.com/onsi/gomega from 1.10.1 to 1.10.2 + * Pass timestamp down to history lines + * Timestamp gets updated everytime you inspect an image + * bud.bats: use absolute paths in newly-added tests + * contrib/cirrus/lib.sh: don't use CN for the hostname + * tests: Add some tests + * Update `manifest add` man page + * Extend flags of `manifest add` + * build(deps): bump github.com/containers/storage from 1.23.3 to 1.23.4 + * build(deps): bump github.com/onsi/ginkgo from 1.14.0 to 1.14.1 + * Bump to v1.17.0-dev + * CI: expand cross-compile checks + - Changelog for v1.16.0 (2020-09-03) * fix build on 32bit arches * containerImageRef.NewImageSource(): don't always force timestamps diff --git a/vendor/github.com/containers/buildah/mount.go b/vendor/github.com/containers/buildah/mount.go index 0eb9cbcea..8c7a23f8c 100644 --- a/vendor/github.com/containers/buildah/mount.go +++ b/vendor/github.com/containers/buildah/mount.go @@ -19,3 +19,35 @@ func (b *Builder) Mount(label string) (string, error) { } return mountpoint, nil } + +func (b *Builder) setMountPoint(mountPoint string) error { + b.MountPoint = mountPoint + if err := b.Save(); err != nil { + return errors.Wrapf(err, "error saving updated state for build container %q", b.ContainerID) + } + return nil +} + +// Mounted returns whether the container is mounted or not +func (b *Builder) Mounted() (bool, error) { + mountCnt, err := b.store.Mounted(b.ContainerID) + if err != nil { + return false, errors.Wrapf(err, "error determining if mounting build container %q is mounted", b.ContainerID) + } + mounted := mountCnt > 0 + if mounted && b.MountPoint == "" { + ctr, err := b.store.Container(b.ContainerID) + if err != nil { + return mountCnt > 0, errors.Wrapf(err, "error determining if mounting build container %q is mounted", b.ContainerID) + } + layer, err := b.store.Layer(ctr.LayerID) + if err != nil { + return mountCnt > 0, errors.Wrapf(err, "error determining if mounting build container %q is mounted", b.ContainerID) + } + return mounted, b.setMountPoint(layer.MountPoint) + } + if !mounted && b.MountPoint != "" { + return mounted, b.setMountPoint("") + } + return mounted, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4ed3bbcda..d0b50aceb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -66,7 +66,7 @@ github.com/containernetworking/plugins/pkg/utils/hwaddr github.com/containernetworking/plugins/pkg/utils/sysctl github.com/containernetworking/plugins/plugins/ipam/host-local/backend github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator -# github.com/containers/buildah v1.16.5 => github.com/containers/buildah v1.16.1-0.20201028193114-3ac12986e8cf +# github.com/containers/buildah v1.17.0 github.com/containers/buildah github.com/containers/buildah/bind github.com/containers/buildah/chroot |