summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cmd/podman/common/specgen.go52
-rw-r--r--cmd/podman/containers/create.go30
-rw-r--r--cmd/podman/containers/diff.go6
-rw-r--r--cmd/podman/containers/run.go21
-rw-r--r--cmd/podman/diff.go14
-rw-r--r--cmd/podman/images/diff.go12
-rw-r--r--cmd/podman/images/inspect.go26
-rw-r--r--cmd/podman/images/tree.go40
-rw-r--r--cmd/podman/inspect.go31
-rw-r--r--cmd/podman/system/service.go27
-rw-r--r--libpod/define/pod_inspect.go2
-rw-r--r--libpod/image/image.go61
-rw-r--r--libpod/pod_api.go7
-rw-r--r--pkg/api/server/server.go5
-rw-r--r--pkg/bindings/connection.go2
-rw-r--r--pkg/bindings/images/images.go2
-rw-r--r--pkg/bindings/test/pods_test.go29
-rw-r--r--pkg/domain/entities/engine_image.go1
-rw-r--r--pkg/domain/entities/images.go10
-rw-r--r--pkg/domain/entities/types.go1
-rw-r--r--pkg/domain/infra/abi/images.go12
-rw-r--r--pkg/domain/infra/abi/system.go11
-rw-r--r--pkg/domain/infra/tunnel/images.go4
-rw-r--r--pkg/rootless/rootless_linux.c45
-rw-r--r--pkg/rootless/rootless_linux.go113
-rw-r--r--pkg/specgen/generate/container.go83
-rw-r--r--pkg/specgen/generate/namespaces.go62
-rw-r--r--pkg/specgen/generate/security.go110
-rw-r--r--pkg/systemd/activation.go29
30 files changed, 455 insertions, 395 deletions
diff --git a/Makefile b/Makefile
index 5b6bcc42f..d4edbd5f7 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ PKG_MANAGER ?= $(shell command -v dnf yum|head -n1)
# ~/.local/bin is not in PATH on all systems
PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit pre-commit | head -n1)
-SOURCES = $(shell find . -name "*.go")
+SOURCES = $(shell find . -path './.*' -prune -o -name "*.go")
GO_BUILD=$(GO) build
# Go module support: set `-mod=vendor` to use the vendored sources
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 85b344b3c..7550bf784 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -47,6 +47,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if err != nil {
return err
}
+ if s.ResourceLimits == nil {
+ s.ResourceLimits = &specs.LinuxResources{}
+ }
+ if s.ResourceLimits.Memory == nil {
+ s.ResourceLimits.Memory = &specs.LinuxMemory{}
+ }
if m := c.Memory; len(m) > 0 {
ml, err := units.RAMInBytes(m)
if err != nil {
@@ -81,6 +87,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
s.ResourceLimits.Memory.Kernel = &mk
}
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &specs.LinuxBlockIO{}
+ }
if b := c.BlkIOWeight; len(b) > 0 {
u, err := strconv.ParseUint(b, 10, 16)
if err != nil {
@@ -313,14 +322,16 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.StopSignal = &stopSignal
}
}
- swappiness := uint64(c.MemorySwappiness)
if s.ResourceLimits == nil {
s.ResourceLimits = &specs.LinuxResources{}
}
if s.ResourceLimits.Memory == nil {
s.ResourceLimits.Memory = &specs.LinuxMemory{}
}
- s.ResourceLimits.Memory.Swappiness = &swappiness
+ if c.MemorySwappiness >= 0 {
+ swappiness := uint64(c.MemorySwappiness)
+ s.ResourceLimits.Memory.Swappiness = &swappiness
+ }
if s.LogConfiguration == nil {
s.LogConfiguration = &specgen.LogConfig{}
@@ -332,7 +343,9 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if s.ResourceLimits.Pids == nil {
s.ResourceLimits.Pids = &specs.LinuxPids{}
}
- s.ResourceLimits.Pids.Limit = c.PIDsLimit
+ if c.PIDsLimit > 0 {
+ s.ResourceLimits.Pids.Limit = c.PIDsLimit
+ }
if c.CGroups == "disabled" && c.PIDsLimit > 0 {
s.ResourceLimits.Pids.Limit = -1
}
@@ -411,6 +424,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
}
+ s.SeccompPolicy = c.SeccompPolicy
// TODO any idea why this was done
// storage.go from spec/
// grab it
@@ -507,18 +521,28 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if s.ResourceLimits.CPU == nil {
s.ResourceLimits.CPU = &specs.LinuxCPU{}
}
- s.ResourceLimits.CPU.Shares = &c.CPUShares
- s.ResourceLimits.CPU.Period = &c.CPUPeriod
-
- // TODO research these
- //s.ResourceLimits.CPU.Cpus = c.CPUS
- //s.ResourceLimits.CPU.Cpus = c.CPUSetCPUs
+ if c.CPUShares > 0 {
+ s.ResourceLimits.CPU.Shares = &c.CPUShares
+ }
+ if c.CPUPeriod > 0 {
+ s.ResourceLimits.CPU.Period = &c.CPUPeriod
+ }
- //s.ResourceLimits.CPU. = c.CPUSetCPUs
- s.ResourceLimits.CPU.Mems = c.CPUSetMems
- s.ResourceLimits.CPU.Quota = &c.CPUQuota
- s.ResourceLimits.CPU.RealtimePeriod = &c.CPURTPeriod
- s.ResourceLimits.CPU.RealtimeRuntime = &c.CPURTRuntime
+ if c.CPUSetCPUs != "" {
+ s.ResourceLimits.CPU.Cpus = c.CPUSetCPUs
+ }
+ if c.CPUSetMems != "" {
+ s.ResourceLimits.CPU.Mems = c.CPUSetMems
+ }
+ if c.CPUQuota > 0 {
+ s.ResourceLimits.CPU.Quota = &c.CPUQuota
+ }
+ if c.CPURTPeriod > 0 {
+ s.ResourceLimits.CPU.RealtimePeriod = &c.CPURTPeriod
+ }
+ if c.CPURTRuntime > 0 {
+ s.ResourceLimits.CPU.RealtimeRuntime = &c.CPURTRuntime
+ }
s.OOMScoreAdj = &c.OOMScoreAdj
s.RestartPolicy = c.Restart
s.Remove = c.Rm
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 292d5c1ad..0843789eb 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -3,6 +3,7 @@ package containers
import (
"fmt"
+ "github.com/containers/common/pkg/config"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/pkg/domain/entities"
@@ -61,6 +62,11 @@ func create(cmd *cobra.Command, args []string) error {
if err := createInit(cmd); err != nil {
return err
}
+
+ if err := pullImage(args[0]); err != nil {
+ return err
+ }
+
//TODO rootfs still
s := specgen.NewSpecGenerator(rawImageInput)
if err := common.FillOutSpecGen(s, &cliVals, args); err != nil {
@@ -100,3 +106,27 @@ func createInit(c *cobra.Command) error {
return nil
}
+
+func pullImage(imageName string) error {
+ br, err := registry.ImageEngine().Exists(registry.GetContext(), imageName)
+ if err != nil {
+ return err
+ }
+ pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
+ if err != nil {
+ return err
+ }
+ if !br.Value || pullPolicy == config.PullImageAlways {
+ if pullPolicy == config.PullImageNever {
+ return errors.New("unable to find a name and tag match for busybox in repotags: no such image")
+ }
+ _, pullErr := registry.ImageEngine().Pull(registry.GetContext(), imageName, entities.ImagePullOptions{
+ Authfile: cliVals.Authfile,
+ Quiet: cliVals.Quiet,
+ })
+ if pullErr != nil {
+ return pullErr
+ }
+ }
+ return nil
+}
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index ebc0d8ea1..046dac53e 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -45,7 +45,11 @@ func diff(cmd *cobra.Command, args []string) error {
return errors.New("container must be specified: podman container diff [options [...]] ID-NAME")
}
- results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), args[0], entities.DiffOptions{})
+ var id string
+ if len(args) > 0 {
+ id = args[0]
+ }
+ results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), id, *diffOpts)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 151f71885..9d222e44d 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -5,7 +5,6 @@ import (
"os"
"strings"
- "github.com/containers/common/pkg/config"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/libpod/define"
@@ -72,26 +71,10 @@ func run(cmd *cobra.Command, args []string) error {
return err
}
- br, err := registry.ImageEngine().Exists(registry.GetContext(), args[0])
- if err != nil {
- return err
- }
- pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
- if err != nil {
+ if err := pullImage(args[0]); err != nil {
return err
}
- if !br.Value || pullPolicy == config.PullImageAlways {
- if pullPolicy == config.PullImageNever {
- return errors.New("unable to find a name and tag match for busybox in repotags: no such image")
- }
- _, pullErr := registry.ImageEngine().Pull(registry.GetContext(), args[0], entities.ImagePullOptions{
- Authfile: cliVals.Authfile,
- Quiet: cliVals.Quiet,
- })
- if pullErr != nil {
- return pullErr
- }
- }
+
// If -i is not set, clear stdin
if !cliVals.Interactive {
runOpts.InputStream = nil
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 8db76e8af..ec94c0918 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -46,10 +46,9 @@ func init() {
}
func diff(cmd *cobra.Command, args []string) error {
- if found, err := registry.ImageEngine().Exists(registry.GetContext(), args[0]); err != nil {
- return err
- } else if found.Value {
- return images.Diff(cmd, args, diffOpts)
+ // Latest implies looking for a container
+ if diffOpts.Latest {
+ return containers.Diff(cmd, args, diffOpts)
}
if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0]); err != nil {
@@ -57,5 +56,12 @@ func diff(cmd *cobra.Command, args []string) error {
} else if found.Value {
return containers.Diff(cmd, args, diffOpts)
}
+
+ if found, err := registry.ImageEngine().Exists(registry.GetContext(), args[0]); err != nil {
+ return err
+ } else if found.Value {
+ return images.Diff(cmd, args, diffOpts)
+ }
+
return fmt.Errorf("%s not found on system", args[0])
}
diff --git a/cmd/podman/images/diff.go b/cmd/podman/images/diff.go
index dd98dc4d6..7cfacfc6c 100644
--- a/cmd/podman/images/diff.go
+++ b/cmd/podman/images/diff.go
@@ -11,8 +11,8 @@ import (
var (
// podman container _inspect_
diffCmd = &cobra.Command{
- Use: "diff [flags] CONTAINER",
- Args: registry.IdOrLatestArgs,
+ Use: "diff [flags] IMAGE",
+ Args: cobra.ExactArgs(1),
Short: "Inspect changes on image's file systems",
Long: `Displays changes on a image's filesystem. The image will be compared to its parent layer.`,
RunE: diff,
@@ -32,16 +32,16 @@ func init() {
diffOpts = &entities.DiffOptions{}
flags := diffCmd.Flags()
flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
- _ = flags.MarkHidden("archive")
+ _ = flags.MarkDeprecated("archive", "Provided for backwards compatibility, has no impact on output.")
flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
}
func diff(cmd *cobra.Command, args []string) error {
- if len(args) == 0 && !diffOpts.Latest {
- return errors.New("image must be specified: podman image diff [options [...]] ID-NAME")
+ if diffOpts.Latest {
+ return errors.New("image diff does not support --latest")
}
- results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], entities.DiffOptions{})
+ results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], *diffOpts)
if err != nil {
return err
}
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index 4482ceee5..11bef02ba 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -20,11 +20,13 @@ import (
var (
// Command: podman image _inspect_
inspectCmd = &cobra.Command{
- Use: "inspect [flags] IMAGE",
- Short: "Display the configuration of an image",
- Long: `Displays the low-level information on an image identified by name or ID.`,
- RunE: inspect,
- Example: `podman image inspect alpine`,
+ Use: "inspect [flags] IMAGE",
+ Short: "Display the configuration of an image",
+ Long: `Displays the low-level information on an image identified by name or ID.`,
+ RunE: inspect,
+ Example: `podman inspect alpine
+ podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine
+ podman inspect --format "image: {{.ImageName}} driver: {{.Driver}}" myctr`,
}
inspectOpts *entities.InspectOptions
)
@@ -39,14 +41,14 @@ func init() {
}
func inspect(cmd *cobra.Command, args []string) error {
- latestContainer := inspectOpts.Latest
-
- if len(args) == 0 && !latestContainer {
- return errors.Errorf("container or image name must be specified: podman inspect [options [...]] name")
+ if inspectOpts.Size {
+ return fmt.Errorf("--size can only be used for containers")
}
-
- if len(args) > 0 && latestContainer {
- return errors.Errorf("you cannot provide additional arguments with --latest")
+ if inspectOpts.Latest {
+ return fmt.Errorf("--latest can only be used for containers")
+ }
+ if len(args) == 0 {
+ return errors.Errorf("image name must be specified: podman image inspect [options [...]] name")
}
results, err := registry.ImageEngine().Inspect(context.Background(), args, *inspectOpts)
diff --git a/cmd/podman/images/tree.go b/cmd/podman/images/tree.go
new file mode 100644
index 000000000..5e82e9dea
--- /dev/null
+++ b/cmd/podman/images/tree.go
@@ -0,0 +1,40 @@
+package images
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ treeDescription = "Prints layer hierarchy of an image in a tree format"
+ treeCmd = &cobra.Command{
+ Use: "tree [flags] IMAGE",
+ Args: cobra.ExactArgs(1),
+ Short: treeDescription,
+ Long: treeDescription,
+ RunE: tree,
+ Example: "podman image tree alpine:latest",
+ }
+ treeOpts entities.ImageTreeOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: treeCmd,
+ Parent: imageCmd,
+ })
+ treeCmd.Flags().BoolVar(&treeOpts.WhatRequires, "whatrequires", false, "Show all child images and layers of the specified image")
+}
+
+func tree(_ *cobra.Command, args []string) error {
+ results, err := registry.ImageEngine().Tree(registry.Context(), args[0], treeOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println(results.Tree)
+ return nil
+}
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index e67bc326b..93bf58bdd 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -1,10 +1,8 @@
package main
import (
- "context"
"fmt"
- "github.com/containers/image/v5/docker/reference"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/containers"
"github.com/containers/libpod/cmd/podman/images"
@@ -21,11 +19,12 @@ var (
// Command: podman _inspect_ Object_ID
inspectCmd = &cobra.Command{
Use: "inspect [flags] {CONTAINER_ID | IMAGE_ID}",
- Args: cobra.ExactArgs(1),
Short: "Display the configuration of object denoted by ID",
Long: "Displays the low-level information on an object identified by name or ID",
TraverseChildren: true,
RunE: inspect,
+ Example: `podman inspect alpine
+ podman inspect --format "imageId: {{.Id}} size: {{.Size}}" alpine`,
}
)
@@ -35,21 +34,25 @@ func init() {
Command: inspectCmd,
})
inspectOpts = common.AddInspectFlagSet(inspectCmd)
+ flags := inspectCmd.Flags()
+ flags.StringVarP(&inspectOpts.Type, "type", "t", "", "Return JSON for specified type, (image or container) (default \"all\")")
+ if !registry.IsRemote() {
+ flags.BoolVarP(&inspectOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of (containers only)")
+ }
}
func inspect(cmd *cobra.Command, args []string) error {
- // First check if the input is even valid for an image
- if _, err := reference.Parse(args[0]); err == nil {
- if found, err := registry.ImageEngine().Exists(context.Background(), args[0]); err != nil {
- return err
- } else if found.Value {
- return images.Inspect(cmd, args, inspectOpts)
+ switch inspectOpts.Type {
+ case "image":
+ return images.Inspect(cmd, args, inspectOpts)
+ case "container":
+ return containers.Inspect(cmd, args, inspectOpts)
+ case "":
+ if err := images.Inspect(cmd, args, inspectOpts); err == nil {
+ return nil
}
- }
- if found, err := registry.ContainerEngine().ContainerExists(context.Background(), args[0]); err != nil {
- return err
- } else if found.Value {
return containers.Inspect(cmd, args, inspectOpts)
+ default:
+ return fmt.Errorf("invalid type %q is must be 'container' or 'image'", inspectOpts.Type)
}
- return fmt.Errorf("%s not found on system", args[0])
}
diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go
index fa1a33faa..e09107b53 100644
--- a/cmd/podman/system/service.go
+++ b/cmd/podman/system/service.go
@@ -2,8 +2,10 @@ package system
import (
"fmt"
+ "net/url"
"os"
"path/filepath"
+ "syscall"
"time"
"github.com/containers/libpod/cmd/podman/registry"
@@ -57,7 +59,24 @@ func service(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- logrus.Infof("using API endpoint: \"%s\"", apiURI)
+ logrus.Infof("using API endpoint: '%s'", apiURI)
+
+ // Clean up any old existing unix domain socket
+ if len(apiURI) > 0 {
+ uri, err := url.Parse(apiURI)
+ if err != nil {
+ return err
+ }
+
+ // socket activation uses a unix:// socket in the shipped unit files but apiURI is coded as "" at this layer.
+ if "unix" == uri.Scheme && !registry.IsRemote() {
+ if err := syscall.Unlink(uri.Path); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ mask := syscall.Umask(0177)
+ defer syscall.Umask(mask)
+ }
+ }
opts := entities.ServiceOptions{
URI: apiURI,
@@ -75,7 +94,6 @@ func service(cmd *cobra.Command, args []string) error {
}
func resolveApiURI(_url []string) (string, error) {
-
// When determining _*THE*_ listening endpoint --
// 1) User input wins always
// 2) systemd socket activation
@@ -83,14 +101,15 @@ func resolveApiURI(_url []string) (string, error) {
// 4) if varlink -- adapter.DefaultVarlinkAddress
// 5) lastly adapter.DefaultAPIAddress
- if _url == nil {
+ if len(_url) == 0 {
if v, found := os.LookupEnv("PODMAN_SOCKET"); found {
+ logrus.Debugf("PODMAN_SOCKET='%s' used to determine API endpoint", v)
_url = []string{v}
}
}
switch {
- case len(_url) > 0:
+ case len(_url) > 0 && _url[0] != "":
return _url[0], nil
case systemd.SocketActivated():
logrus.Info("using systemd socket activation to determine API endpoint")
diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go
index 8558c149b..26fd2cab4 100644
--- a/libpod/define/pod_inspect.go
+++ b/libpod/define/pod_inspect.go
@@ -18,6 +18,8 @@ type InspectPodData struct {
Namespace string `json:"Namespace,omitempty"`
// Created is the time when the pod was created.
Created time.Time
+ // State represents the current state of the pod.
+ State string `json:"State"`
// Hostname is the hostname that the pod will set.
Hostname string
// Labels is a set of key-value labels that have been applied to the
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 7198a42a3..bbf803056 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -867,22 +867,77 @@ func (i *Image) Intermediate(ctx context.Context) (bool, error) {
return false, nil
}
+// User returns the image's user
+func (i *Image) User(ctx context.Context) (string, error) {
+ imgInspect, err := i.inspect(ctx, false)
+ if err != nil {
+ return "", err
+ }
+ return imgInspect.Config.User, nil
+}
+
+// StopSignal returns the image's StopSignal
+func (i *Image) StopSignal(ctx context.Context) (string, error) {
+ imgInspect, err := i.inspect(ctx, false)
+ if err != nil {
+ return "", err
+ }
+ return imgInspect.Config.StopSignal, nil
+}
+
+// WorkingDir returns the image's WorkingDir
+func (i *Image) WorkingDir(ctx context.Context) (string, error) {
+ imgInspect, err := i.inspect(ctx, false)
+ if err != nil {
+ return "", err
+ }
+ return imgInspect.Config.WorkingDir, nil
+}
+
+// Cmd returns the image's cmd
+func (i *Image) Cmd(ctx context.Context) ([]string, error) {
+ imgInspect, err := i.inspect(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+ return imgInspect.Config.Cmd, nil
+}
+
+// Entrypoint returns the image's entrypoint
+func (i *Image) Entrypoint(ctx context.Context) ([]string, error) {
+ imgInspect, err := i.inspect(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+ return imgInspect.Config.Entrypoint, nil
+}
+
+// Env returns the image's env
+func (i *Image) Env(ctx context.Context) ([]string, error) {
+ imgInspect, err := i.imageInspectInfo(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return imgInspect.Env, nil
+}
+
// Labels returns the image's labels
func (i *Image) Labels(ctx context.Context) (map[string]string, error) {
imgInspect, err := i.imageInspectInfo(ctx)
if err != nil {
- return nil, nil
+ return nil, err
}
return imgInspect.Labels, nil
}
// GetLabel Returns a case-insensitive match of a given label
func (i *Image) GetLabel(ctx context.Context, label string) (string, error) {
- imageLabels, err := i.Labels(ctx)
+ labels, err := i.Labels(ctx)
if err != nil {
return "", err
}
- for k, v := range imageLabels {
+
+ for k, v := range labels {
if strings.ToLower(k) == strings.ToLower(label) {
return v, nil
}
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index ed4dc0727..45aa5cb8d 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -446,6 +446,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
if err != nil {
return nil, err
}
+ ctrStatuses := make(map[string]define.ContainerStatus, len(containers))
for _, c := range containers {
containerStatus := "unknown"
// Ignoring possible errors here because we don't want this to be
@@ -459,12 +460,18 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
Name: c.Name(),
State: containerStatus,
})
+ ctrStatuses[c.ID()] = c.state.State
+ }
+ podState, err := CreatePodStatusResults(ctrStatuses)
+ if err != nil {
+ return nil, err
}
inspectData := define.InspectPodData{
ID: p.ID(),
Name: p.Name(),
Namespace: p.Namespace(),
Created: p.CreatedTime(),
+ State: podState,
Hostname: "",
Labels: p.Labels(),
CreateCgroup: false,
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 5f1a86183..9576fd437 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -51,7 +51,7 @@ func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, list
func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
// If listener not provided try socket activation protocol
if listener == nil {
- if _, found := os.LookupEnv("LISTEN_FDS"); !found {
+ if _, found := os.LookupEnv("LISTEN_PID"); !found {
return nil, errors.Errorf("Cannot create API Server, no listener provided and socket activation protocol is not active.")
}
@@ -125,7 +125,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
if err != nil {
methods = []string{"<N/A>"}
}
- logrus.Debugf("Methods: %s Path: %s", strings.Join(methods, ", "), path)
+ logrus.Debugf("Methods: %6s Path: %s", strings.Join(methods, ", "), path)
return nil
})
}
@@ -179,6 +179,7 @@ func (s *APIServer) Shutdown() error {
}
// Gracefully shutdown server, duration of wait same as idle window
+ // TODO: Should we really wait the idle window for shutdown?
ctx, cancel := context.WithTimeout(context.Background(), s.idleTracker.Duration)
defer cancel()
go func() {
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index 4fe4dd72d..29b6f04ec 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -126,7 +126,7 @@ func tcpClient(_url *url.URL) (*http.Client, error) {
return &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
- return net.Dial("tcp", _url.Path)
+ return net.Dial("tcp", _url.Host)
},
DisableCompression: true,
},
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 3550c3968..e0f523ebd 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -74,7 +74,7 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
return &inspectedData, response.Process(&inspectedData)
}
-func ImageTree(ctx context.Context, nameOrId string) error {
+func Tree(ctx context.Context, nameOrId string) error {
return bindings.ErrNotImplemented
}
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 4d682a522..8a0b9c7a6 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -174,8 +174,7 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
response, err := pods.Inspect(bt.conn, newpod)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.Status).To(Equal(define.PodStatePaused))
+ Expect(response.State).To(Equal(define.PodStatePaused))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStatePaused))
@@ -186,8 +185,7 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
response, err = pods.Inspect(bt.conn, newpod)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateRunning))
+ Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateRunning))
@@ -219,8 +217,7 @@ var _ = Describe("Podman pods", func() {
response, err := pods.Inspect(bt.conn, newpod)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateRunning))
+ Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateRunning))
@@ -234,8 +231,7 @@ var _ = Describe("Podman pods", func() {
_, err = pods.Stop(bt.conn, newpod, nil)
Expect(err).To(BeNil())
response, _ = pods.Inspect(bt.conn, newpod)
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateExited))
+ Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateStopped))
@@ -248,8 +244,7 @@ var _ = Describe("Podman pods", func() {
_, err = pods.Restart(bt.conn, newpod)
Expect(err).To(BeNil())
response, _ = pods.Inspect(bt.conn, newpod)
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateRunning))
+ Expect(response.State).To(Equal(define.PodStateRunning))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateRunning))
@@ -277,15 +272,15 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
response, err := pods.Inspect(bt.conn, newpod)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateExited))
+ Expect(response.State).To(Equal(define.PodStateExited))
pruneResponse, err = pods.Prune(bt.conn)
Expect(err).To(BeNil())
// Validate status and record pod id of pod to be pruned
- //Expect(response.State.Status).To(Equal(define.PodStateExited))
- //podID := response.Config.ID
+ Expect(response.State).To(Equal(define.PodStateExited))
+ podID := response.ID
// Check if right pod was pruned
Expect(len(pruneResponse)).To(Equal(1))
+ Expect(pruneResponse[0].Id).To(Equal(podID))
// One pod is pruned hence only one pod should be active.
podSummary, err = pods.List(bt.conn, nil)
Expect(err).To(BeNil())
@@ -301,8 +296,7 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
response, err = pods.Inspect(bt.conn, newpod)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateExited))
+ Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateStopped))
@@ -311,8 +305,7 @@ var _ = Describe("Podman pods", func() {
Expect(err).To(BeNil())
response, err = pods.Inspect(bt.conn, newpod2)
Expect(err).To(BeNil())
- // FIXME sujil please fix this
- //Expect(response.State.Status).To(Equal(define.PodStateExited))
+ Expect(response.State).To(Equal(define.PodStateExited))
for _, i := range response.Containers {
Expect(define.StringToContainerStatus(i.State)).
To(Equal(define.ContainerStateStopped))
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index 052e7bee5..b6283b6ad 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -23,5 +23,6 @@ type ImageEngine interface {
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error)
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
+ Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error
}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 3a6d159e4..56c4c0ac5 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -273,3 +273,13 @@ type ImageSaveOptions struct {
Output string
Quiet bool
}
+
+// ImageTreeOptions provides options for ImageEngine.Tree()
+type ImageTreeOptions struct {
+ WhatRequires bool // Show all child images and layers of the specified image
+}
+
+// ImageTreeReport provides results from ImageEngine.Tree()
+type ImageTreeReport struct {
+ Tree string // TODO: Refactor move presentation work out of server
+}
diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go
index b89aa869a..096af2df2 100644
--- a/pkg/domain/entities/types.go
+++ b/pkg/domain/entities/types.go
@@ -50,6 +50,7 @@ type InspectOptions struct {
Format string `json:",omitempty"`
Latest bool `json:",omitempty"`
Size bool `json:",omitempty"`
+ Type string `json:",omitempty"`
}
// All API and CLI diff commands and diff sub-commands use the same options
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 0f710ad28..4353e0798 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -476,3 +476,15 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
}
return &entities.BuildReport{ID: id}, nil
}
+
+func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
+ img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ results, err := img.GenerateTree(opts.WhatRequires)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.ImageTreeReport{Tree: results}, nil
+}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 67593b2dd..078f5404d 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -35,7 +35,7 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error {
var (
- listener net.Listener
+ listener *net.Listener
err error
)
@@ -45,13 +45,14 @@ func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceO
return errors.Errorf("%s is an invalid socket destination", opts.URI)
}
address := strings.Join(fields[1:], ":")
- listener, err = net.Listen(fields[0], address)
+ l, err := net.Listen(fields[0], address)
if err != nil {
return errors.Wrapf(err, "unable to create socket %s", opts.URI)
}
+ listener = &l
}
- server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, &listener)
+ server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, listener)
if err != nil {
return err
}
@@ -62,7 +63,9 @@ func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceO
}()
err = server.Serve()
- _ = listener.Close()
+ if listener != nil {
+ _ = (*listener).Close()
+ }
return err
}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index 6ea2bd9f2..2decd605d 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -263,3 +263,7 @@ func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) {
func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) {
return nil, errors.New("not implemented yet")
}
+
+func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
+ return nil, errors.New("not implemented yet")
+}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index da52a7217..72d461cdc 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -535,8 +535,36 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
}
}
+static void
+join_namespace_or_die (int pid_to_join, const char *ns_file)
+{
+ char ns_path[PATH_MAX];
+ int ret;
+ int fd;
+
+ ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file);
+ if (ret == PATH_MAX)
+ {
+ fprintf (stderr, "internal error: namespace path too long\n");
+ _exit (EXIT_FAILURE);
+ }
+
+ fd = open (ns_path, O_CLOEXEC | O_RDONLY);
+ if (fd < 0)
+ {
+ fprintf (stderr, "cannot open: %s\n", ns_path);
+ _exit (EXIT_FAILURE);
+ }
+ if (setns (fd, 0) < 0)
+ {
+ fprintf (stderr, "cannot set namespace to %s: %s\n", ns_path, strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ close (fd);
+}
+
int
-reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
+reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
{
char uid[16];
char gid[16];
@@ -606,19 +634,8 @@ reexec_userns_join (int userns, int mountns, char *pause_pid_file_path)
_exit (EXIT_FAILURE);
}
- if (setns (userns, 0) < 0)
- {
- fprintf (stderr, "cannot setns: %s\n", strerror (errno));
- _exit (EXIT_FAILURE);
- }
- close (userns);
-
- if (mountns >= 0 && setns (mountns, 0) < 0)
- {
- fprintf (stderr, "cannot setns: %s\n", strerror (errno));
- _exit (EXIT_FAILURE);
- }
- close (mountns);
+ join_namespace_or_die (pid_to_join, "user");
+ join_namespace_or_die (pid_to_join, "mnt");
if (syscall_setresgid (0, 0, 0) < 0)
{
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 5ddfab7ad..3de136f12 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -31,7 +31,7 @@ extern uid_t rootless_uid();
extern uid_t rootless_gid();
extern int reexec_in_user_namespace(int ready, char *pause_pid_file_path, char *file_to_read, int fd);
extern int reexec_in_user_namespace_wait(int pid, int options);
-extern int reexec_userns_join(int userns, int mountns, char *pause_pid_file_path);
+extern int reexec_userns_join(int pid, char *pause_pid_file_path);
*/
import "C"
@@ -124,91 +124,6 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
return nil
}
-func readUserNs(path string) (string, error) {
- b := make([]byte, 256)
- _, err := unix.Readlink(path, b)
- if err != nil {
- return "", err
- }
- return string(b), nil
-}
-
-func readUserNsFd(fd uintptr) (string, error) {
- return readUserNs(fmt.Sprintf("/proc/self/fd/%d", fd))
-}
-
-func getParentUserNs(fd uintptr) (uintptr, error) {
- const nsGetParent = 0xb702
- ret, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(nsGetParent), 0)
- if errno != 0 {
- return 0, errno
- }
- return (uintptr)(unsafe.Pointer(ret)), nil
-}
-
-// getUserNSFirstChild returns an open FD for the first direct child user namespace that created the process
-// Each container creates a new user namespace where the runtime runs. The current process in the container
-// might have created new user namespaces that are child of the initial namespace we created.
-// This function finds the initial namespace created for the container that is a child of the current namespace.
-//
-// current ns
-// / \
-// TARGET -> a [other containers]
-// /
-// b
-// /
-// NS READ USING THE PID -> c
-func getUserNSFirstChild(fd uintptr) (*os.File, error) {
- currentNS, err := readUserNs("/proc/self/ns/user")
- if err != nil {
- return nil, err
- }
-
- ns, err := readUserNsFd(fd)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot read user namespace")
- }
- if ns == currentNS {
- return nil, errors.New("process running in the same user namespace")
- }
-
- for {
- nextFd, err := getParentUserNs(fd)
- if err != nil {
- if err == unix.ENOTTY {
- return os.NewFile(fd, "userns child"), nil
- }
- return nil, errors.Wrapf(err, "cannot get parent user namespace")
- }
-
- ns, err = readUserNsFd(nextFd)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot read user namespace")
- }
-
- if ns == currentNS {
- if err := unix.Close(int(nextFd)); err != nil {
- return nil, err
- }
-
- // Drop O_CLOEXEC for the fd.
- _, _, errno := unix.Syscall(unix.SYS_FCNTL, fd, unix.F_SETFD, 0)
- if errno != 0 {
- if err := unix.Close(int(fd)); err != nil {
- logrus.Errorf("failed to close file descriptor %d", fd)
- }
- return nil, errno
- }
-
- return os.NewFile(fd, "userns child"), nil
- }
- if err := unix.Close(int(fd)); err != nil {
- return nil, err
- }
- fd = nextFd
- }
-}
-
// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount
// namespace of the specified PID without looking up its parent. Useful to join directly
// the conmon process.
@@ -220,31 +135,7 @@ func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
cPausePid := C.CString(pausePid)
defer C.free(unsafe.Pointer(cPausePid))
- userNS, err := os.Open(fmt.Sprintf("/proc/%d/ns/user", pid))
- if err != nil {
- return false, -1, err
- }
- defer func() {
- if err := userNS.Close(); err != nil {
- logrus.Errorf("unable to close namespace: %q", err)
- }
- }()
-
- mountNS, err := os.Open(fmt.Sprintf("/proc/%d/ns/mnt", pid))
- if err != nil {
- return false, -1, err
- }
- defer func() {
- if err := mountNS.Close(); err != nil {
- logrus.Errorf("unable to close namespace: %q", err)
- }
- }()
-
- fd, err := getUserNSFirstChild(userNS.Fd())
- if err != nil {
- return false, -1, err
- }
- pidC := C.reexec_userns_join(C.int(fd.Fd()), C.int(mountNS.Fd()), cPausePid)
+ pidC := C.reexec_userns_join(C.int(pid), cPausePid)
if int(pidC) < 0 {
return false, -1, errors.Errorf("cannot re-exec process")
}
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 7233acb8a..31465d8bf 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -20,17 +20,27 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
// Image stop signal
- if s.StopSignal == nil && newImage.Config != nil {
- sig, err := signal.ParseSignalNameOrNumber(newImage.Config.StopSignal)
+ if s.StopSignal == nil {
+ stopSignal, err := newImage.StopSignal(ctx)
+ if err != nil {
+ return err
+ }
+ sig, err := signal.ParseSignalNameOrNumber(stopSignal)
if err != nil {
return err
}
s.StopSignal = &sig
}
+
// Image envs from the image if they don't exist
// already
- if newImage.Config != nil && len(newImage.Config.Env) > 0 {
- envs, err := envLib.ParseSlice(newImage.Config.Env)
+ env, err := newImage.Env(ctx)
+ if err != nil {
+ return err
+ }
+
+ if len(env) > 0 {
+ envs, err := envLib.ParseSlice(env)
if err != nil {
return err
}
@@ -41,12 +51,15 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
}
+ labels, err := newImage.Labels(ctx)
+ if err != nil {
+ return err
+ }
+
// labels from the image that dont exist already
- if config := newImage.Config; config != nil {
- for k, v := range config.Labels {
- if _, exists := s.Labels[k]; !exists {
- s.Labels[k] = v
- }
+ for k, v := range labels {
+ if _, exists := s.Labels[k]; !exists {
+ s.Labels[k] = v
}
}
@@ -75,20 +88,30 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
// entrypoint
- if config := newImage.Config; config != nil {
- if len(s.Entrypoint) < 1 && len(config.Entrypoint) > 0 {
- s.Entrypoint = config.Entrypoint
- }
- if len(s.Command) < 1 && len(config.Cmd) > 0 {
- s.Command = config.Cmd
- }
- if len(s.Command) < 1 && len(s.Entrypoint) < 1 {
- return errors.Errorf("No command provided or as CMD or ENTRYPOINT in this image")
- }
- // workdir
- if len(s.WorkDir) < 1 && len(config.WorkingDir) > 1 {
- s.WorkDir = config.WorkingDir
- }
+ entrypoint, err := newImage.Entrypoint(ctx)
+ if err != nil {
+ return err
+ }
+ if len(s.Entrypoint) < 1 && len(entrypoint) > 0 {
+ s.Entrypoint = entrypoint
+ }
+ command, err := newImage.Cmd(ctx)
+ if err != nil {
+ return err
+ }
+ if len(s.Command) < 1 && len(command) > 0 {
+ s.Command = command
+ }
+ if len(s.Command) < 1 && len(s.Entrypoint) < 1 {
+ return errors.Errorf("No command provided or as CMD or ENTRYPOINT in this image")
+ }
+ // workdir
+ workingDir, err := newImage.WorkingDir(ctx)
+ if err != nil {
+ return err
+ }
+ if len(s.WorkDir) < 1 && len(workingDir) > 1 {
+ s.WorkDir = workingDir
}
if len(s.SeccompProfilePath) < 1 {
@@ -99,15 +122,17 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
s.SeccompProfilePath = p
}
- if user := s.User; len(user) == 0 {
- switch {
+ if len(s.User) == 0 {
+ s.User, err = newImage.User(ctx)
+ if err != nil {
+ return err
+ }
+
// TODO This should be enabled when namespaces actually work
//case usernsMode.IsKeepID():
// user = fmt.Sprintf("%d:%d", rootless.GetRootlessUID(), rootless.GetRootlessGID())
- case newImage.Config == nil || (newImage.Config != nil && len(newImage.Config.User) == 0):
+ if len(s.User) == 0 {
s.User = "0"
- default:
- s.User = newImage.Config.User
}
}
if err := finishThrottleDevices(s); err != nil {
@@ -116,7 +141,7 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
// Unless already set via the CLI, check if we need to disable process
// labels or set the defaults.
if len(s.SelinuxOpts) == 0 {
- if err := SetLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil {
+ if err := setLabelOpts(s, r, s.PidNS, s.IpcNS); err != nil {
return err
}
}
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index cdd7d86da..53ae335c3 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -3,9 +3,7 @@ package generate
import (
"os"
- "github.com/containers/common/pkg/capabilities"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -324,66 +322,6 @@ func userConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator) err
return nil
}
-func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image) error {
- // HANDLE CAPABILITIES
- // NOTE: Must happen before SECCOMP
- if s.Privileged {
- g.SetupPrivileged(true)
- }
-
- useNotRoot := func(user string) bool {
- if user == "" || user == "root" || user == "0" {
- return false
- }
- return true
- }
- configSpec := g.Config
- var err error
- var caplist []string
- bounding := configSpec.Process.Capabilities.Bounding
- if useNotRoot(s.User) {
- configSpec.Process.Capabilities.Bounding = caplist
- }
- caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop)
- if err != nil {
- return err
- }
-
- configSpec.Process.Capabilities.Bounding = caplist
- configSpec.Process.Capabilities.Permitted = caplist
- configSpec.Process.Capabilities.Inheritable = caplist
- configSpec.Process.Capabilities.Effective = caplist
- configSpec.Process.Capabilities.Ambient = caplist
- if useNotRoot(s.User) {
- caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop)
- if err != nil {
- return err
- }
- }
- configSpec.Process.Capabilities.Bounding = caplist
-
- // HANDLE SECCOMP
- if s.SeccompProfilePath != "unconfined" {
- seccompConfig, err := getSeccompConfig(s, configSpec, newImage)
- if err != nil {
- return err
- }
- configSpec.Linux.Seccomp = seccompConfig
- }
-
- // Clear default Seccomp profile from Generator for privileged containers
- if s.SeccompProfilePath == "unconfined" || s.Privileged {
- configSpec.Linux.Seccomp = nil
- }
-
- g.SetRootReadonly(s.ReadOnlyFilesystem)
- for sysctlKey, sysctlVal := range s.Sysctl {
- g.AddLinuxSysctl(sysctlKey, sysctlVal)
- }
-
- return nil
-}
-
// GetNamespaceOptions transforms a slice of kernel namespaces
// into a slice of pod create options. Currently, not all
// kernel namespaces are supported, and they will be returned in an error
diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
index ef4b3b47a..e2da9e976 100644
--- a/pkg/specgen/generate/security.go
+++ b/pkg/specgen/generate/security.go
@@ -1,15 +1,22 @@
package generate
import (
+ "strings"
+
+ "github.com/containers/common/pkg/capabilities"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
-// SetLabelOpts sets the label options of the SecurityConfig according to the
+// setLabelOpts sets the label options of the SecurityConfig according to the
// input.
-func SetLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
if !runtime.EnableLabeling() || s.Privileged {
s.SelinuxOpts = label.DisableSecOpt()
return nil
@@ -48,12 +55,10 @@ func SetLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig s
return nil
}
-// ConfigureGenerator configures the generator according to the input.
-/*
-func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserConfig) error {
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image) error {
// HANDLE CAPABILITIES
// NOTE: Must happen before SECCOMP
- if c.Privileged {
+ if s.Privileged {
g.SetupPrivileged(true)
}
@@ -63,56 +68,66 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon
}
return true
}
-
configSpec := g.Config
var err error
- var defaultCaplist []string
+ var caplist []string
bounding := configSpec.Process.Capabilities.Bounding
- if useNotRoot(user.User) {
- configSpec.Process.Capabilities.Bounding = defaultCaplist
+ if useNotRoot(s.User) {
+ configSpec.Process.Capabilities.Bounding = caplist
}
- defaultCaplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop)
+ caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, s.CapAdd, s.CapDrop)
if err != nil {
return err
}
+ privCapsRequired := []string{}
+
+ // If the container image specifies an label with a
+ // capabilities.ContainerImageLabel then split the comma separated list
+ // of capabilities and record them. This list indicates the only
+ // capabilities, required to run the container.
+ var capsRequiredRequested []string
+ for key, val := range s.Labels {
+ if util.StringInSlice(key, capabilities.ContainerImageLabels) {
+ capsRequiredRequested = strings.Split(val, ",")
+ }
+ }
+ if !s.Privileged && len(capsRequiredRequested) > 0 {
- privCapRequired := []string{}
-
- if !c.Privileged && len(c.CapRequired) > 0 {
- // Pass CapRequired in CapAdd field to normalize capabilities names
- capRequired, err := capabilities.MergeCapabilities(nil, c.CapRequired, nil)
+ // Pass capRequiredRequested in CapAdd field to normalize capabilities names
+ capsRequired, err := capabilities.MergeCapabilities(nil, capsRequiredRequested, nil)
if err != nil {
- logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(c.CapRequired, ","))
+ logrus.Errorf("capabilities requested by user or image are not valid: %q", strings.Join(capsRequired, ","))
} else {
- // Verify all capRequiered are in the defaultCapList
- for _, cap := range capRequired {
- if !util.StringInSlice(cap, defaultCaplist) {
- privCapRequired = append(privCapRequired, cap)
+ // Verify all capRequiered are in the capList
+ for _, cap := range capsRequired {
+ if !util.StringInSlice(cap, caplist) {
+ privCapsRequired = append(privCapsRequired, cap)
}
}
}
- if len(privCapRequired) == 0 {
- defaultCaplist = capRequired
+ if len(privCapsRequired) == 0 {
+ caplist = capsRequired
} else {
- logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapRequired, ","))
+ logrus.Errorf("capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ","))
}
}
- configSpec.Process.Capabilities.Bounding = defaultCaplist
- configSpec.Process.Capabilities.Permitted = defaultCaplist
- configSpec.Process.Capabilities.Inheritable = defaultCaplist
- configSpec.Process.Capabilities.Effective = defaultCaplist
- configSpec.Process.Capabilities.Ambient = defaultCaplist
- if useNotRoot(user.User) {
- defaultCaplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop)
+
+ configSpec.Process.Capabilities.Bounding = caplist
+ configSpec.Process.Capabilities.Permitted = caplist
+ configSpec.Process.Capabilities.Inheritable = caplist
+ configSpec.Process.Capabilities.Effective = caplist
+ configSpec.Process.Capabilities.Ambient = caplist
+ if useNotRoot(s.User) {
+ caplist, err = capabilities.MergeCapabilities(bounding, s.CapAdd, s.CapDrop)
if err != nil {
return err
}
}
- configSpec.Process.Capabilities.Bounding = defaultCaplist
+ configSpec.Process.Capabilities.Bounding = caplist
// HANDLE SECCOMP
- if c.SeccompProfilePath != "unconfined" {
- seccompConfig, err := getSeccompConfig(c, configSpec)
+ if s.SeccompProfilePath != "unconfined" {
+ seccompConfig, err := getSeccompConfig(s, configSpec, newImage)
if err != nil {
return err
}
@@ -120,35 +135,14 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon
}
// Clear default Seccomp profile from Generator for privileged containers
- if c.SeccompProfilePath == "unconfined" || c.Privileged {
+ if s.SeccompProfilePath == "unconfined" || s.Privileged {
configSpec.Linux.Seccomp = nil
}
- for _, opt := range c.SecurityOpts {
- // Split on both : and =
- splitOpt := strings.Split(opt, "=")
- if len(splitOpt) == 1 {
- splitOpt = strings.Split(opt, ":")
- }
- if len(splitOpt) < 2 {
- continue
- }
- switch splitOpt[0] {
- case "label":
- configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
- case "seccomp":
- configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
- case "apparmor":
- configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
- }
- }
-
- g.SetRootReadonly(c.ReadOnlyRootfs)
- for sysctlKey, sysctlVal := range c.Sysctl {
+ g.SetRootReadonly(s.ReadOnlyFilesystem)
+ for sysctlKey, sysctlVal := range s.Sysctl {
g.AddLinuxSysctl(sysctlKey, sysctlVal)
}
return nil
}
-
-*/
diff --git a/pkg/systemd/activation.go b/pkg/systemd/activation.go
index c8b2389dc..8f75f9cca 100644
--- a/pkg/systemd/activation.go
+++ b/pkg/systemd/activation.go
@@ -3,38 +3,33 @@ package systemd
import (
"os"
"strconv"
- "strings"
)
// SocketActivated determine if podman is running under the socket activation protocol
+// Criteria is based on the expectations of "github.com/coreos/go-systemd/v22/activation"
func SocketActivated() bool {
- pid, pid_found := os.LookupEnv("LISTEN_PID")
- fds, fds_found := os.LookupEnv("LISTEN_FDS")
- fdnames, fdnames_found := os.LookupEnv("LISTEN_FDNAMES")
-
- if !(pid_found && fds_found && fdnames_found) {
+ pid, found := os.LookupEnv("LISTEN_PID")
+ if !found {
return false
}
-
p, err := strconv.Atoi(pid)
if err != nil || p != os.Getpid() {
return false
}
+ fds, found := os.LookupEnv("LISTEN_FDS")
+ if !found {
+ return false
+ }
nfds, err := strconv.Atoi(fds)
- if err != nil || nfds < 1 {
+ if err != nil || nfds == 0 {
return false
}
- // First available file descriptor is always 3.
- if nfds > 1 {
- names := strings.Split(fdnames, ":")
- for _, n := range names {
- if strings.Contains(n, "podman") {
- return true
- }
- }
+ // "github.com/coreos/go-systemd/v22/activation" will use and validate this variable's
+ // value. We're just providing a fast fail
+ if _, found = os.LookupEnv("LISTEN_FDNAMES"); !found {
+ return false
}
-
return true
}