diff options
-rwxr-xr-x | .tool/lint | 1 | ||||
-rw-r--r-- | Dockerfile | 6 | ||||
-rw-r--r-- | Dockerfile.centos | 6 | ||||
-rw-r--r-- | Dockerfile.fedora | 6 | ||||
-rw-r--r-- | cmd/podman/exec.go | 7 | ||||
-rw-r--r-- | cmd/podman/main_remote.go | 8 | ||||
-rw-r--r-- | libpod.conf | 4 | ||||
-rw-r--r-- | libpod/container.go | 4 | ||||
-rw-r--r-- | libpod/container_api.go | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 2 | ||||
-rw-r--r-- | libpod/errors.go | 3 | ||||
-rw-r--r-- | libpod/oci.go | 12 | ||||
-rw-r--r-- | libpod/oci_linux.go | 20 | ||||
-rw-r--r-- | libpod/pod.go | 6 | ||||
-rw-r--r-- | libpod/runtime.go | 13 | ||||
-rw-r--r-- | libpod/volume.go | 1 |
16 files changed, 63 insertions, 38 deletions
diff --git a/.tool/lint b/.tool/lint index 01f44311d..67dfd4b28 100755 --- a/.tool/lint +++ b/.tool/lint @@ -39,7 +39,6 @@ ${LINTER} \ --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$'\ --exclude='duplicate of.*_test.go.*\(dupl\)$'\ --exclude='cmd\/client\/.*\.go.*\(dupl\)$'\ - --exclude='libpod\/.*_easyjson.go:.*'\ --exclude='vendor\/.*'\ --exclude='podman\/.*'\ --exclude='server\/seccomp\/.*\.go.*$'\ diff --git a/Dockerfile b/Dockerfile index d729c00dc..0f2249dc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -90,12 +90,6 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install latest stable criu version RUN set -x \ && cd /tmp \ diff --git a/Dockerfile.centos b/Dockerfile.centos index c1d93d5d3..7f4cef963 100644 --- a/Dockerfile.centos +++ b/Dockerfile.centos @@ -49,12 +49,6 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install conmon ENV CONMON_COMMIT 59952292a3b07ac125575024ae21956efe0ecdfb RUN set -x \ diff --git a/Dockerfile.fedora b/Dockerfile.fedora index d7c2d07e1..5ea82c967 100644 --- a/Dockerfile.fedora +++ b/Dockerfile.fedora @@ -53,12 +53,6 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install conmon ENV CONMON_COMMIT 59952292a3b07ac125575024ae21956efe0ecdfb RUN set -x \ diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index deff44a92..0684da842 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -125,5 +125,10 @@ func execCmd(c *cliconfig.ExecValues) error { streams.AttachError = true streams.AttachInput = true - return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) + err = ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) + if errors.Cause(err) == libpod.ErrCtrStateInvalid { + exitCode = 126 + } + + return err } diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go index de6c2c760..1b9430e92 100644 --- a/cmd/podman/main_remote.go +++ b/cmd/podman/main_remote.go @@ -3,15 +3,21 @@ package main import ( + "os/user" + "github.com/spf13/cobra" ) const remote = true func init() { + var username string + if curruser, err := user.Current(); err == nil { + username = curruser.Username + } rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConnectionName, "connection", "", "remote connection name") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteConfigFilePath, "remote-config-path", "", "alternate path for configuration file") - rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host") + rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", username, "username on the remote host") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host") // TODO maybe we allow the altering of this for bridge connections? //rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket") diff --git a/libpod.conf b/libpod.conf index ce6b95cda..45e955c36 100644 --- a/libpod.conf +++ b/libpod.conf @@ -106,6 +106,10 @@ num_locks = 2048 # Default OCI runtime runtime = "runc" +# List of the OCI runtimes that support --format=json. When json is supported +# libpod will use it for reporting nicer errors. +runtime_supports_json = ["runc"] + # Paths to look for a valid OCI runtime (runc, runv, etc) [runtimes] runc = [ diff --git a/libpod/container.go b/libpod/container.go index c8ab42fc3..68c4cd6b0 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -135,7 +135,6 @@ const ( // assume that their callers handled this requirement. Generally speaking, if a // function takes the container lock and accesses any part of state, it should // syncContainer() immediately after locking. -// ffjson: skip type Container struct { config *ContainerConfig @@ -161,7 +160,6 @@ type Container struct { // ContainerState contains the current state of the container // It is stored on disk in a tmpfs and recreated on reboot -// easyjson:json type ContainerState struct { // The current state of the running container State ContainerStatus `json:"state"` @@ -222,7 +220,6 @@ type ContainerState struct { } // ExecSession contains information on an active exec session -// easyjson:json type ExecSession struct { ID string `json:"id"` Command []string `json:"command"` @@ -232,7 +229,6 @@ type ExecSession struct { // ContainerConfig contains all information that was used to create the // container. It may not be changed once created. // It is stored, read-only, on disk -// easyjson:json type ContainerConfig struct { Spec *spec.Spec `json:"spec"` ID string `json:"id"` diff --git a/libpod/container_api.go b/libpod/container_api.go index 1894780de..52d3afc0a 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -241,7 +241,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir // TODO can probably relax this once we track exec sessions if conState != ContainerStateRunning { - return errors.Errorf("cannot exec into container that is not running") + return errors.Wrapf(ErrCtrStateInvalid, "cannot exec into container that is not running") } if privileged || c.config.Privileged { capList = caps.GetAllCapabilities() diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 4acc77afa..0be5427d9 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1000,7 +1000,7 @@ func (c *Container) generateResolvConf() (string, error) { nameservers := resolvconf.GetNameservers(resolv.Content) // slirp4netns has a built in DNS server. if c.config.NetMode.IsSlirp4netns() { - nameservers = append(nameservers, "10.0.2.3") + nameservers = append([]string{"10.0.2.3"}, nameservers...) } if len(c.config.DNSServer) > 0 { // We store DNS servers as net.IP, so need to convert to string diff --git a/libpod/errors.go b/libpod/errors.go index dd82d0796..cca0935ec 100644 --- a/libpod/errors.go +++ b/libpod/errors.go @@ -96,4 +96,7 @@ var ( // ErrOSNotSupported indicates the function is not available on the particular // OS. ErrOSNotSupported = errors.New("No support for this OS yet") + + // ErrOCIRuntime indicates an error from the OCI runtime + ErrOCIRuntime = errors.New("OCI runtime error") ) diff --git a/libpod/oci.go b/libpod/oci.go index 7138108c5..dcb72fc1b 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -58,6 +58,7 @@ type OCIRuntime struct { logSizeMax int64 noPivot bool reservePorts bool + supportsJSON bool } // syncInfo is used to return data from monitor process to daemon @@ -66,8 +67,16 @@ type syncInfo struct { Message string `json:"message,omitempty"` } +// ociError is used to parse the OCI runtime JSON log. It is not part of the +// OCI runtime specifications, it follows what runc does +type ociError struct { + Level string `json:"level,omitempty"` + Time string `json:"time,omitempty"` + Msg string `json:"msg,omitempty"` +} + // Make a new OCI runtime with provided options -func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) { +func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool, supportsJSON bool) (*OCIRuntime, error) { runtime := new(OCIRuntime) runtime.name = oruntime.Name runtime.path = oruntime.Paths[0] @@ -78,6 +87,7 @@ func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []strin runtime.logSizeMax = logSizeMax runtime.noPivot = noPivotRoot runtime.reservePorts = reservePorts + runtime.supportsJSON = supportsJSON runtime.exitsDir = filepath.Join(runtime.tmpDir, "exits") runtime.socketsDir = filepath.Join(runtime.tmpDir, "socket") diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 7c1c18052..9bbefdb06 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -6,6 +6,7 @@ import ( "bufio" "bytes" "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -208,6 +209,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res defer parentPipe.Close() defer parentStartPipe.Close() + ociLog := filepath.Join(ctr.state.RunDir, "oci-log") + logLevel := logrus.GetLevel() + args := []string{} if r.cgroupManager == SystemdCgroupsManager { args = append(args, "-s") @@ -219,6 +223,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res args = append(args, "-b", ctr.bundlePath()) args = append(args, "-p", filepath.Join(ctr.state.RunDir, "pidfile")) args = append(args, "--exit-dir", r.exitsDir) + if logLevel != logrus.DebugLevel && r.supportsJSON { + args = append(args, "--runtime-arg", "--log-format=json", "--runtime-arg", "--log", fmt.Sprintf("--runtime-arg=%s", ociLog)) + } if ctr.config.ConmonPidFile != "" { args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile) } @@ -248,7 +255,6 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res args = append(args, "--no-pivot") } - logLevel := logrus.GetLevel() args = append(args, "--log-level", logLevel.String()) if logLevel == logrus.DebugLevel { @@ -417,8 +423,18 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res } logrus.Debugf("Received container pid: %d", ss.si.Pid) if ss.si.Pid == -1 { + if r.supportsJSON { + data, err := ioutil.ReadFile(ociLog) + if err == nil { + var ociErr ociError + if err := json.Unmarshal(data, &ociErr); err == nil { + return errors.Wrapf(ErrOCIRuntime, "%s", strings.Trim(ociErr.Msg, "\n")) + } + } + } + // If we failed to parse the JSON errors, then print the output as it is if ss.si.Message != "" { - return errors.Wrapf(ErrInternal, "container create failed: %s", ss.si.Message) + return errors.Wrapf(ErrOCIRuntime, "%s", ss.si.Message) } return errors.Wrapf(ErrInternal, "container create failed") } diff --git a/libpod/pod.go b/libpod/pod.go index 4ce697402..c319c449f 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -18,7 +18,6 @@ import ( // assume their callers handled this requirement. Generally speaking, if a // function takes the pod lock and accesses any part of state, it should // updatePod() immediately after locking. -// ffjson: skip // Pod represents a group of containers that may share namespaces type Pod struct { config *PodConfig @@ -30,7 +29,6 @@ type Pod struct { } // PodConfig represents a pod's static configuration -// easyjson:json type PodConfig struct { ID string `json:"id"` Name string `json:"name"` @@ -66,7 +64,6 @@ type PodConfig struct { } // podState represents a pod's state -// easyjson:json type podState struct { // CgroupPath is the path to the pod's CGroup CgroupPath string `json:"cgroupPath"` @@ -77,7 +74,6 @@ type podState struct { // PodInspect represents the data we want to display for // podman pod inspect -// easyjson:json type PodInspect struct { Config *PodConfig State *PodInspectState @@ -85,14 +81,12 @@ type PodInspect struct { } // PodInspectState contains inspect data on the pod's state -// easyjson:json type PodInspectState struct { CgroupPath string `json:"cgroupPath"` InfraContainerID string `json:"infraContainerID"` } // PodContainerInfo keeps information on a container in a pod -// easyjson:json type PodContainerInfo struct { ID string `json:"id"` State string `json:"state"` diff --git a/libpod/runtime.go b/libpod/runtime.go index 098607b63..24bb5f61c 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -151,6 +151,8 @@ type RuntimeConfig struct { OCIRuntime string `toml:"runtime"` // OCIRuntimes are the set of configured OCI runtimes (default is runc) OCIRuntimes map[string][]string `toml:"runtimes"` + // RuntimeSupportsJSON is the list of the OCI runtimes that support --format=json + RuntimeSupportsJSON []string `toml:"runtime_supports_json"` // RuntimePath is the path to OCI runtime binary for launching // containers. // The first path pointing to a valid file will be used @@ -830,12 +832,21 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) { } } + supportsJSON := false + for _, r := range runtime.config.RuntimeSupportsJSON { + if r == runtime.config.OCIRuntime { + supportsJSON = true + break + } + } + // Make an OCI runtime to perform container operations ociRuntime, err := newOCIRuntime(runtime.ociRuntimePath, runtime.conmonPath, runtime.config.ConmonEnvVars, runtime.config.CgroupManager, runtime.config.TmpDir, runtime.config.MaxLogSize, runtime.config.NoPivotRoot, - runtime.config.EnablePortReservation) + runtime.config.EnablePortReservation, + supportsJSON) if err != nil { return err } diff --git a/libpod/volume.go b/libpod/volume.go index 0b37d44ef..9ed2ff087 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -10,7 +10,6 @@ type Volume struct { } // VolumeConfig holds the volume's config information -//easyjson:json type VolumeConfig struct { // Name of the volume Name string `json:"name"` |