summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/client.go3
-rw-r--r--pkg/adapter/containers.go46
-rw-r--r--pkg/adapter/pods.go14
-rw-r--r--pkg/adapter/runtime.go26
-rw-r--r--pkg/adapter/runtime_remote.go31
-rw-r--r--pkg/namespaces/namespaces.go87
-rw-r--r--pkg/spec/createconfig.go12
-rw-r--r--pkg/spec/spec.go37
-rw-r--r--pkg/spec/storage.go137
-rw-r--r--pkg/util/utils.go6
-rw-r--r--pkg/util/utils_supported.go36
-rw-r--r--pkg/util/utils_windows.go15
-rw-r--r--pkg/varlinkapi/images.go9
-rw-r--r--pkg/varlinkapi/system.go1
14 files changed, 254 insertions, 206 deletions
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
index 694d9f961..da6ff5fd0 100644
--- a/pkg/adapter/client.go
+++ b/pkg/adapter/client.go
@@ -16,7 +16,7 @@ var remoteEndpoint *Endpoint
func (r RemoteRuntime) RemoteEndpoint() (remoteEndpoint *Endpoint, err error) {
remoteConfigConnections, err := remoteclientconfig.ReadRemoteConfig(r.config)
- if errors.Cause(err) != remoteclientconfig.ErrNoConfigationFile {
+ if err != nil && errors.Cause(err) != remoteclientconfig.ErrNoConfigationFile {
return nil, err
}
// If the user defines an env variable for podman_varlink_bridge
@@ -68,7 +68,6 @@ func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
if err != nil {
return nil, err
}
-
switch ep.Type {
case DirectConnection:
return varlink.NewConnection(ep.Connection)
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index faaef3e60..b712bd9aa 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -9,7 +9,6 @@ import (
"io"
"io/ioutil"
"os"
- "path/filepath"
"strconv"
"strings"
"sync"
@@ -23,6 +22,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/adapter/shortcuts"
@@ -418,14 +418,13 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
- // The container may have been removed
- // Go looking for an exit file
- ctrExitCode, err := ReadExitFile(config.TmpDir, ctr.ID())
+ // Check events
+ event, err := r.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited)
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = 127
} else {
- exitCode = ctrExitCode
+ exitCode = event.ContainerExitCode
}
}
} else {
@@ -441,31 +440,6 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
return exitCode, nil
}
-// ReadExitFile reads a container's exit file
-func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
- exitFile := filepath.Join(runtimeTmp, "exits", fmt.Sprintf("%s-old", ctrID))
-
- logrus.Debugf("Attempting to read container %s exit code from file %s", ctrID, exitFile)
-
- // Check if it exists
- if _, err := os.Stat(exitFile); err != nil {
- return 0, errors.Wrapf(err, "error getting exit file for container %s", ctrID)
- }
-
- // File exists, read it in and convert to int
- statusStr, err := ioutil.ReadFile(exitFile)
- if err != nil {
- return 0, errors.Wrapf(err, "error reading exit file for container %s", ctrID)
- }
-
- exitCode, err := strconv.Atoi(string(statusStr))
- if err != nil {
- return 0, errors.Wrapf(err, "error parsing exit code for container %s", ctrID)
- }
-
- return exitCode, nil
-}
-
// Ps ...
func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) {
maxWorkers := shared.Parallelize("ps")
@@ -565,6 +539,7 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
TargetFile: c.Import,
Name: c.Name,
IgnoreRootfs: c.IgnoreRootfs,
+ IgnoreStaticIP: c.IgnoreStaticIP,
}
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
@@ -655,18 +630,13 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP
if ecode, err := ctr.Wait(); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
- // The container may have been removed
- // Go looking for an exit file
- rtc, err := r.GetConfig()
- if err != nil {
- return 0, err
- }
- ctrExitCode, err := ReadExitFile(rtc.TmpDir, ctr.ID())
+ // Check events
+ event, err := r.Runtime.GetLastContainerEvent(ctr.ID(), events.Exited)
if err != nil {
logrus.Errorf("Cannot get exit code: %v", err)
exitCode = 127
} else {
- exitCode = ctrExitCode
+ exitCode = event.ContainerExitCode
}
}
} else {
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index b9d7fcd9b..e25238956 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -10,6 +10,7 @@ import (
"os"
"strings"
+ "github.com/containers/buildah/pkg/parse"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
@@ -570,7 +571,7 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa
}
}
- if err := createconfig.ValidateVolumeHostDir(hostPath.Path); err != nil {
+ if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
return nil, errors.Wrapf(err, "Error in parsing HostPath in YAML")
}
volumes[volume.Name] = hostPath.Path
@@ -682,6 +683,15 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
}
+
+ }
+ if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
+ for _, capability := range caps.Add {
+ containerConfig.CapAdd = append(containerConfig.CapAdd, string(capability))
+ }
+ for _, capability := range caps.Drop {
+ containerConfig.CapDrop = append(containerConfig.CapDrop, string(capability))
+ }
}
containerConfig.Command = []string{}
@@ -728,7 +738,7 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
if !exists {
return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
}
- if err := createconfig.ValidateVolumeCtrDir(volume.MountPath); err != nil {
+ if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil {
return nil, errors.Wrapf(err, "error in parsing MountPath")
}
containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", hostPath, volume.MountPath))
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index ee6913cc0..4a3b41297 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -5,22 +5,22 @@ package adapter
import (
"bufio"
"context"
- "github.com/containers/libpod/libpod/define"
"io"
"io/ioutil"
"os"
"text/template"
- "github.com/containers/libpod/cmd/podman/shared"
-
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/formats"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
@@ -351,9 +351,13 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
fromStart bool
eventsError error
)
- tmpl, err := template.New("events").Parse(c.Format)
- if err != nil {
- return err
+ var tmpl *template.Template
+ if c.Format != formats.JSONString {
+ template, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+ tmpl = template
}
if len(c.Since) > 0 || len(c.Until) > 0 {
fromStart = true
@@ -369,7 +373,15 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
}
w := bufio.NewWriter(os.Stdout)
for event := range eventChannel {
- if len(c.Format) > 0 {
+ if c.Format == formats.JSONString {
+ jsonStr, err := event.ToJSONString()
+ if err != nil {
+ return errors.Wrapf(err, "unable to format json")
+ }
+ if _, err := w.Write([]byte(jsonStr)); err != nil {
+ return err
+ }
+ } else if len(c.Format) > 0 {
if err := tmpl.Execute(w, event); err != nil {
return err
}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 9fae39df0..0cafbb2aa 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -10,13 +10,13 @@ import (
"io"
"io/ioutil"
"os"
+ "path/filepath"
"strings"
"text/template"
"time"
- v1 "k8s.io/api/core/v1"
-
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/formats"
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
@@ -32,6 +32,7 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/varlink/go/varlink"
+ v1 "k8s.io/api/core/v1"
)
// ImageRuntime is wrapper for image runtime
@@ -68,6 +69,12 @@ func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime,
cmd: c.GlobalFlags,
}
configPath := remoteclientconfig.GetConfigFilePath()
+ // Check if the basedir for configPath exists and if not, create it.
+ if _, err := os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) {
+ if mkdirErr := os.MkdirAll(filepath.Dir(configPath), 0750); mkdirErr != nil {
+ return nil, mkdirErr
+ }
+ }
if len(c.GlobalFlags.RemoteConfigFilePath) > 0 {
configPath = c.GlobalFlags.RemoteConfigFilePath
customConfig = true
@@ -820,9 +827,13 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
}
w := bufio.NewWriter(os.Stdout)
- tmpl, err := template.New("events").Parse(c.Format)
- if err != nil {
- return err
+ var tmpl *template.Template
+ if c.Format != formats.JSONString {
+ template, err := template.New("events").Parse(c.Format)
+ if err != nil {
+ return err
+ }
+ tmpl = template
}
for {
@@ -856,7 +867,15 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
Time: eTime,
Type: eType,
}
- if len(c.Format) > 0 {
+ if c.Format == formats.JSONString {
+ jsonStr, err := event.ToJSONString()
+ if err != nil {
+ return errors.Wrapf(err, "unable to format json")
+ }
+ if _, err := w.Write([]byte(jsonStr)); err != nil {
+ return err
+ }
+ } else if len(c.Format) > 0 {
if err := tmpl.Execute(w, event); err != nil {
return err
}
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
index 35298796f..9d1033b93 100644
--- a/pkg/namespaces/namespaces.go
+++ b/pkg/namespaces/namespaces.go
@@ -4,17 +4,30 @@ import (
"strings"
)
+const (
+ bridgeType = "bridge"
+ containerType = "container"
+ defaultType = "default"
+ hostType = "host"
+ noneType = "none"
+ nsType = "ns"
+ podType = "pod"
+ privateType = "private"
+ shareableType = "shareable"
+ slirpType = "slirp4netns"
+)
+
// CgroupMode represents cgroup mode in the container.
type CgroupMode string
// IsHost indicates whether the container uses the host's cgroup.
func (n CgroupMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsNS indicates a cgroup namespace passed in by path (ns:<path>)
func (n CgroupMode) IsNS() bool {
- return strings.HasPrefix(string(n), "ns:")
+ return strings.HasPrefix(string(n), nsType)
}
// NS gets the path associated with a ns:<path> cgroup ns
@@ -29,13 +42,13 @@ func (n CgroupMode) NS() string {
// IsContainer indicates whether the container uses a new cgroup namespace.
func (n CgroupMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container returns the name of the container whose cgroup namespace is going to be used.
func (n CgroupMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -43,15 +56,15 @@ func (n CgroupMode) Container() string {
// IsPrivate indicates whether the container uses the a private cgroup.
func (n CgroupMode) IsPrivate() bool {
- return n == "private"
+ return n == privateType
}
// Valid indicates whether the Cgroup namespace is valid.
func (n CgroupMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host", "private", "ns":
- case "container":
+ case "", hostType, privateType, nsType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -66,7 +79,7 @@ type UsernsMode string
// IsHost indicates whether the container uses the host's userns.
func (n UsernsMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is lept inside of the namespace.
@@ -83,8 +96,8 @@ func (n UsernsMode) IsPrivate() bool {
func (n UsernsMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host", "keep-id", "ns":
- case "container":
+ case "", hostType, "keep-id", nsType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -111,13 +124,13 @@ func (n UsernsMode) NS() string {
// IsContainer indicates whether container uses a container userns.
func (n UsernsMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container is the id of the container which network this container is connected to.
func (n UsernsMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -133,19 +146,19 @@ func (n UTSMode) IsPrivate() bool {
// IsHost indicates whether the container uses the host's UTS namespace.
func (n UTSMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsContainer indicates whether the container uses a container's UTS namespace.
func (n UTSMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container returns the name of the container whose uts namespace is going to be used.
func (n UTSMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -155,8 +168,8 @@ func (n UTSMode) Container() string {
func (n UTSMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host":
- case "container":
+ case "", hostType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -171,28 +184,28 @@ type IpcMode string
// IsPrivate indicates whether the container uses its own private ipc namespace which cannot be shared.
func (n IpcMode) IsPrivate() bool {
- return n == "private"
+ return n == privateType
}
// IsHost indicates whether the container shares the host's ipc namespace.
func (n IpcMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsShareable indicates whether the container's ipc namespace can be shared with another container.
func (n IpcMode) IsShareable() bool {
- return n == "shareable"
+ return n == shareableType
}
// IsContainer indicates whether the container uses another container's ipc namespace.
func (n IpcMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// IsNone indicates whether container IpcMode is set to "none".
func (n IpcMode) IsNone() bool {
- return n == "none"
+ return n == noneType
}
// IsEmpty indicates whether container IpcMode is empty
@@ -208,7 +221,7 @@ func (n IpcMode) Valid() bool {
// Container returns the name of the container ipc stack is going to be used.
func (n IpcMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 && parts[0] == "container" {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -224,21 +237,21 @@ func (n PidMode) IsPrivate() bool {
// IsHost indicates whether the container uses the host's pid namespace.
func (n PidMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsContainer indicates whether the container uses a container's pid namespace.
func (n PidMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Valid indicates whether the pid namespace is valid.
func (n PidMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
- case "", "host":
- case "container":
+ case "", hostType:
+ case containerType:
if len(parts) != 2 || parts[1] == "" {
return false
}
@@ -251,7 +264,7 @@ func (n PidMode) Valid() bool {
// Container returns the name of the container whose pid namespace is going to be used.
func (n PidMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -262,17 +275,17 @@ type NetworkMode string
// IsNone indicates whether container isn't using a network stack.
func (n NetworkMode) IsNone() bool {
- return n == "none"
+ return n == noneType
}
// IsHost indicates whether the container uses the host's network stack.
func (n NetworkMode) IsHost() bool {
- return n == "host"
+ return n == hostType
}
// IsDefault indicates whether container uses the default network stack.
func (n NetworkMode) IsDefault() bool {
- return n == "default"
+ return n == defaultType
}
// IsPrivate indicates whether container uses its private network stack.
@@ -283,13 +296,13 @@ func (n NetworkMode) IsPrivate() bool {
// IsContainer indicates whether container uses a container network stack.
func (n NetworkMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
+ return len(parts) > 1 && parts[0] == containerType
}
// Container is the id of the container which network this container is connected to.
func (n NetworkMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
+ if len(parts) > 1 && parts[0] == containerType {
return parts[1]
}
return ""
@@ -305,17 +318,17 @@ func (n NetworkMode) UserDefined() string {
// IsBridge indicates whether container uses the bridge network stack
func (n NetworkMode) IsBridge() bool {
- return n == "bridge"
+ return n == bridgeType
}
// IsSlirp4netns indicates if we are running a rootless network stack
func (n NetworkMode) IsSlirp4netns() bool {
- return n == "slirp4netns"
+ return n == slirpType
}
// IsNS indicates a network namespace passed in by path (ns:<path>)
func (n NetworkMode) IsNS() bool {
- return strings.HasPrefix(string(n), "ns:")
+ return strings.HasPrefix(string(n), nsType)
}
// NS gets the path associated with a ns:<path> network ns
@@ -329,7 +342,7 @@ func (n NetworkMode) NS() string {
// IsPod returns whether the network refers to pod networking
func (n NetworkMode) IsPod() bool {
- return n == "pod"
+ return n == podType
}
// IsUserDefined indicates user-created network
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 214a3c5ed..3f70e5935 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -64,8 +64,9 @@ type CreateConfig struct {
CidFile string
ConmonPidFile string
Cgroupns string
- CgroupParent string // cgroup-parent
- Command []string
+ CgroupParent string // cgroup-parent
+ Command []string // Full command that will be used
+ UserCommand []string // User-entered command (or image CMD)
Detach bool // detach
Devices []string // device
DNSOpt []string //dns-opt
@@ -168,6 +169,9 @@ func (c *CreateConfig) createExitCommand(runtime *libpod.Runtime) ([]string, err
for _, opt := range config.StorageConfig.GraphDriverOptions {
command = append(command, []string{"--storage-opt", opt}...)
}
+ if config.EventsLogger != "" {
+ command = append(command, []string{"--events-backend", config.EventsLogger}...)
+ }
if c.Syslog {
command = append(command, "--syslog", "true")
@@ -227,8 +231,8 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
options = append(options, libpod.WithNamedVolumes(namedVolumes))
}
- if len(c.Command) != 0 {
- options = append(options, libpod.WithCommand(c.Command))
+ if len(c.UserCommand) != 0 {
+ options = append(options, libpod.WithCommand(c.UserCommand))
}
// Add entrypoint unconditionally
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index c94746767..156d6849d 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -174,10 +174,20 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
}
hostname := config.Hostname
- if hostname == "" && (config.NetMode.IsHost() || config.UtsMode.IsHost()) {
- hostname, err = os.Hostname()
- if err != nil {
- return nil, errors.Wrap(err, "unable to retrieve hostname")
+ if hostname == "" {
+ if utsCtrID := config.UtsMode.Container(); utsCtrID != "" {
+ utsCtr, err := runtime.GetContainer(utsCtrID)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID)
+ }
+ hostname = utsCtr.Hostname()
+ } else if config.NetMode.IsHost() || config.UtsMode.IsHost() {
+ hostname, err = os.Hostname()
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to retrieve hostname of the host")
+ }
+ } else {
+ logrus.Debug("No hostname set; container's hostname will default to runtime default")
}
}
g.RemoveHostname()
@@ -541,8 +551,8 @@ func addPidNS(config *CreateConfig, g *generate.Generator) error {
if pidMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.PIDNamespace))
}
- if pidMode.IsContainer() {
- logrus.Debug("using container pidmode")
+ if pidCtr := pidMode.Container(); pidCtr != "" {
+ logrus.Debugf("using container %s pidmode", pidCtr)
}
if IsPod(string(pidMode)) {
logrus.Debug("using pod pidmode")
@@ -579,8 +589,8 @@ func addNetNS(config *CreateConfig, g *generate.Generator) error {
} else if netMode.IsBridge() {
logrus.Debug("Using bridge netmode")
return nil
- } else if netMode.IsContainer() {
- logrus.Debug("Using container netmode")
+ } else if netCtr := netMode.Container(); netCtr != "" {
+ logrus.Debugf("using container %s netmode", netCtr)
return nil
} else if IsNS(string(netMode)) {
logrus.Debug("Using ns netmode")
@@ -606,6 +616,9 @@ func addUTSNS(config *CreateConfig, g *generate.Generator) error {
if utsMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.UTSNamespace))
}
+ if utsCtr := utsMode.Container(); utsCtr != "" {
+ logrus.Debugf("using container %s utsmode", utsCtr)
+ }
return nil
}
@@ -617,8 +630,8 @@ func addIpcNS(config *CreateConfig, g *generate.Generator) error {
if ipcMode.IsHost() {
return g.RemoveLinuxNamespace(string(spec.IPCNamespace))
}
- if ipcMode.IsContainer() {
- logrus.Debug("Using container ipcmode")
+ if ipcCtr := ipcMode.Container(); ipcCtr != "" {
+ logrus.Debugf("Using container %s ipcmode", ipcCtr)
}
return nil
@@ -635,8 +648,8 @@ func addCgroupNS(config *CreateConfig, g *generate.Generator) error {
if cgroupMode.IsPrivate() {
return g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), "")
}
- if cgroupMode.IsContainer() {
- logrus.Debug("Using container cgroup mode")
+ if cgCtr := cgroupMode.Container(); cgCtr != "" {
+ logrus.Debugf("Using container %s cgroup mode", cgCtr)
}
return nil
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index 88f1f6dc1..e0bb48a9c 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
+ "github.com/containers/buildah/pkg/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage/pkg/stringid"
@@ -248,8 +249,11 @@ func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]
finalNamedVolumes := make(map[string]*libpod.ContainerNamedVolume)
for _, vol := range config.VolumesFrom {
- options := []string{}
- splitVol := strings.SplitN(vol, ":", 2)
+ var (
+ options = []string{}
+ err error
+ splitVol = strings.SplitN(vol, ":", 2)
+ )
if len(splitVol) == 2 {
if strings.Contains(splitVol[1], "Z") ||
strings.Contains(splitVol[1], "private") ||
@@ -257,12 +261,10 @@ func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]
strings.Contains(splitVol[1], "shared") {
return nil, nil, errors.Errorf("invalid options %q, can only specify 'ro', 'rw', and 'z", splitVol[1])
}
- options = strings.Split(splitVol[1], ",")
- opts, err := ValidateVolumeOpts(options)
- if err != nil {
+
+ if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[1], ",")); err != nil {
return nil, nil, err
}
- options = opts
}
ctr, err := runtime.LookupContainer(splitVol[0])
if err != nil {
@@ -408,13 +410,42 @@ func getBindMount(args []string) (spec.Mount, error) {
setSource := false
setDest := false
+ setRORW := false
for _, val := range args {
kv := strings.Split(val, "=")
switch kv[0] {
case "bind-nonrecursive":
newMount.Options = append(newMount.Options, "bind")
- case "ro", "nosuid", "nodev", "noexec":
+ case "ro", "rw":
+ if setRORW {
+ return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' or 'rw' options more than once")
+ }
+ setRORW = true
+ // Can be formatted as one of:
+ // ro
+ // ro=[true|false]
+ // rw
+ // rw=[true|false]
+ if len(kv) == 1 {
+ newMount.Options = append(newMount.Options, kv[0])
+ } else if len(kv) == 2 {
+ switch strings.ToLower(kv[1]) {
+ case "true":
+ newMount.Options = append(newMount.Options, kv[0])
+ case "false":
+ // Set the opposite only for rw
+ // ro's opposite is the default
+ if kv[0] == "rw" {
+ newMount.Options = append(newMount.Options, "ro")
+ }
+ default:
+ return newMount, errors.Wrapf(optionArgError, "%s must be set to true or false, instead received %q", kv[0], kv[1])
+ }
+ } else {
+ return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
+ }
+ case "nosuid", "nodev", "noexec":
// TODO: detect duplication of these options.
// (Is this necessary?)
newMount.Options = append(newMount.Options, kv[0])
@@ -429,7 +460,7 @@ func getBindMount(args []string) (spec.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeHostDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeHostDir(kv[1]); err != nil {
return newMount, err
}
newMount.Source = kv[1]
@@ -438,7 +469,7 @@ func getBindMount(args []string) (spec.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err
}
newMount.Destination = kv[1]
@@ -456,12 +487,11 @@ func getBindMount(args []string) (spec.Mount, error) {
newMount.Source = newMount.Destination
}
- opts, err := ValidateVolumeOpts(newMount.Options)
+ options, err := parse.ValidateVolumeOpts(newMount.Options)
if err != nil {
return newMount, err
}
- newMount.Options = opts
-
+ newMount.Options = options
return newMount, nil
}
@@ -495,7 +525,7 @@ func getTmpfsMount(args []string) (spec.Mount, error) {
if len(kv) == 1 {
return newMount, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return newMount, err
}
newMount.Destination = kv[1]
@@ -539,7 +569,7 @@ func getNamedVolume(args []string) (*libpod.ContainerNamedVolume, error) {
if len(kv) == 1 {
return nil, errors.Wrapf(optionArgError, kv[0])
}
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
+ if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil {
return nil, err
}
newVolume.Dest = kv[1]
@@ -559,75 +589,6 @@ func getNamedVolume(args []string) (*libpod.ContainerNamedVolume, error) {
return newVolume, nil
}
-// ValidateVolumeHostDir validates a volume mount's source directory
-func ValidateVolumeHostDir(hostDir string) error {
- if len(hostDir) == 0 {
- return errors.Errorf("host directory cannot be empty")
- }
- if filepath.IsAbs(hostDir) {
- if _, err := os.Stat(hostDir); err != nil {
- return errors.Wrapf(err, "error checking path %q", hostDir)
- }
- }
- // If hostDir is not an absolute path, that means the user wants to create a
- // named volume. This will be done later on in the code.
- return nil
-}
-
-// ValidateVolumeCtrDir validates a volume mount's destination directory.
-func ValidateVolumeCtrDir(ctrDir string) error {
- if len(ctrDir) == 0 {
- return errors.Errorf("container directory cannot be empty")
- }
- if !filepath.IsAbs(ctrDir) {
- return errors.Errorf("invalid container path %q, must be an absolute path", ctrDir)
- }
- return nil
-}
-
-// ValidateVolumeOpts validates a volume's options
-func ValidateVolumeOpts(options []string) ([]string, error) {
- var foundRootPropagation, foundRWRO, foundLabelChange, bindType int
- finalOpts := make([]string, 0, len(options))
- for _, opt := range options {
- switch opt {
- case "rw", "ro":
- foundRWRO++
- if foundRWRO > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", strings.Join(options, ", "))
- }
- case "z", "Z":
- foundLabelChange++
- if foundLabelChange > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", strings.Join(options, ", "))
- }
- case "private", "rprivate", "shared", "rshared", "slave", "rslave":
- foundRootPropagation++
- if foundRootPropagation > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", strings.Join(options, ", "))
- }
- case "bind", "rbind":
- bindType++
- if bindType > 1 {
- return nil, errors.Errorf("invalid options %q, can only specify 1 '[r]bind' option", strings.Join(options, ", "))
- }
- case "cached", "delegated":
- // The discarded ops are OS X specific volume options
- // introduced in a recent Docker version.
- // They have no meaning on Linux, so here we silently
- // drop them. This matches Docker's behavior (the options
- // are intended to be always safe to use, even not on OS
- // X).
- continue
- default:
- return nil, errors.Errorf("invalid mount option %q", opt)
- }
- finalOpts = append(finalOpts, opt)
- }
- return finalOpts, nil
-}
-
-// GetVolumeMounts takes user provided input for bind mounts and creates Mount structs
func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) {
mounts := make(map[string]spec.Mount)
volumes := make(map[string]*libpod.ContainerNamedVolume)
@@ -639,6 +600,7 @@ func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string
options []string
src string
dest string
+ err error
)
splitVol := strings.Split(vol, ":")
@@ -653,18 +615,15 @@ func (config *CreateConfig) getVolumeMounts() (map[string]spec.Mount, map[string
dest = splitVol[1]
}
if len(splitVol) > 2 {
- options = strings.Split(splitVol[2], ",")
- opts, err := ValidateVolumeOpts(options)
- if err != nil {
+ if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
return nil, nil, err
}
- options = opts
}
- if err := ValidateVolumeHostDir(src); err != nil {
+ if err := parse.ValidateVolumeHostDir(src); err != nil {
return nil, nil, err
}
- if err := ValidateVolumeCtrDir(dest); err != nil {
+ if err := parse.ValidateVolumeCtrDir(dest); err != nil {
return nil, nil, err
}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index fba34a337..520e41438 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -239,8 +239,10 @@ func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []strin
}
var (
- rootlessRuntimeDirOnce sync.Once
- rootlessRuntimeDir string
+ rootlessConfigHomeDirOnce sync.Once
+ rootlessConfigHomeDir string
+ rootlessRuntimeDirOnce sync.Once
+ rootlessRuntimeDir string
)
type tomlOptionsConfig struct {
diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go
index af55689a6..c7c8787a0 100644
--- a/pkg/util/utils_supported.go
+++ b/pkg/util/utils_supported.go
@@ -26,7 +26,7 @@ func GetRootlessRuntimeDir() (string, error) {
if runtimeDir == "" {
tmpDir := filepath.Join("/run", "user", uid)
if err := os.MkdirAll(tmpDir, 0700); err != nil {
- logrus.Errorf("unable to make temp dir %s", tmpDir)
+ logrus.Debugf("unable to make temp dir %s", tmpDir)
}
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
@@ -36,7 +36,7 @@ func GetRootlessRuntimeDir() (string, error) {
if runtimeDir == "" {
tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("run-%s", uid))
if err := os.MkdirAll(tmpDir, 0700); err != nil {
- logrus.Errorf("unable to make temp dir %s", tmpDir)
+ logrus.Debugf("unable to make temp dir %s", tmpDir)
}
st, err := os.Stat(tmpDir)
if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0700 {
@@ -65,6 +65,38 @@ func GetRootlessRuntimeDir() (string, error) {
return rootlessRuntimeDir, nil
}
+// GetRootlessConfigHomeDir returns the config home directory when running as non root
+func GetRootlessConfigHomeDir() (string, error) {
+ var rootlessConfigHomeDirError error
+
+ rootlessConfigHomeDirOnce.Do(func() {
+ cfgHomeDir := os.Getenv("XDG_CONFIG_HOME")
+ if cfgHomeDir == "" {
+ home := os.Getenv("HOME")
+ resolvedHome, err := filepath.EvalSymlinks(home)
+ if err != nil {
+ rootlessConfigHomeDirError = errors.Wrapf(err, "cannot resolve %s", home)
+ return
+ }
+ tmpDir := filepath.Join(resolvedHome, ".config")
+ if err := os.MkdirAll(tmpDir, 0755); err != nil {
+ logrus.Errorf("unable to make temp dir %s", tmpDir)
+ }
+ st, err := os.Stat(tmpDir)
+ if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() == 0755 {
+ cfgHomeDir = tmpDir
+ }
+ }
+ rootlessConfigHomeDir = cfgHomeDir
+ })
+
+ if rootlessConfigHomeDirError != nil {
+ return "", rootlessConfigHomeDirError
+ }
+
+ return rootlessConfigHomeDir, nil
+}
+
// GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for
// the pause process
func GetRootlessPauseProcessPidPath() (string, error) {
diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go
index 635558bf7..e781e6717 100644
--- a/pkg/util/utils_windows.go
+++ b/pkg/util/utils_windows.go
@@ -6,24 +6,31 @@ import (
"github.com/pkg/errors"
)
+var errNotImplemented = errors.New("not yet implemented")
+
// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode.
func IsCgroup2UnifiedMode() (bool, error) {
- return false, errors.New("this function is not implemented for windows")
+ return false, errors.Wrap(errNotImplemented, "IsCgroup2Unified")
}
// GetContainerPidInformationDescriptors returns a string slice of all supported
// format descriptors of GetContainerPidInformation.
func GetContainerPidInformationDescriptors() ([]string, error) {
- return nil, errors.New("this function is not implemented for windows")
+ return nil, errors.Wrap(errNotImplemented, "GetContainerPidInformationDescriptors")
}
// GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for
// the pause process
func GetRootlessPauseProcessPidPath() (string, error) {
- return "", errors.New("this function is not implemented for windows")
+ return "", errors.Wrap(errNotImplemented, "GetRootlessPauseProcessPidPath")
}
// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir() (string, error) {
- return "", errors.New("this function is not implemented for windows")
+ return "", errors.Wrap(errNotImplemented, "GetRootlessRuntimeDir")
+}
+
+// GetRootlessConfigHomeDir returns the config home directory when running as non root
+func GetRootlessConfigHomeDir() (string, error) {
+ return "", errors.Wrap(errNotImplemented, "GetRootlessConfigHomeDir")
}
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 338499bd4..b5a711dfd 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -198,6 +198,8 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
if call.WantsMore() {
call.Continues = true
+ } else {
+ return call.ReplyErrorOccurred("endpoint requires a more connection")
}
var newPathDockerFiles []string
@@ -642,6 +644,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
defer close(c)
go func() {
+ var foundError bool
if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
srcRef, err := alltransports.ParseImageName(name)
if err != nil {
@@ -649,6 +652,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
}
newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, "", output)
if err != nil {
+ foundError = true
c <- errors.Wrapf(err, "error pulling image from %q", name)
} else {
imageID = newImage[0].ID()
@@ -656,12 +660,15 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string) error {
} else {
newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, "", "", output, &dockerRegistryOptions, so, false, nil)
if err != nil {
+ foundError = true
c <- errors.Wrapf(err, "unable to pull %s", name)
} else {
imageID = newImage.ID()
}
}
- c <- nil
+ if !foundError {
+ c <- nil
+ }
}()
var log []string
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 9b5b3a5b1..2de785b79 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -61,6 +61,7 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error {
Kernel: host["kernel"].(string),
Os: host["os"].(string),
Uptime: host["uptime"].(string),
+ Eventlogger: host["eventlogger"].(string),
}
podmanInfo.Host = infoHost
store := info[1].Data