summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xAPI.md94
-rw-r--r--README.md2
-rw-r--r--cmd/podman/cliconfig/commands.go4
-rw-r--r--cmd/podman/cliconfig/config.go13
-rw-r--r--cmd/podman/commands.go7
-rw-r--r--cmd/podman/commit.go17
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/generate.go7
-rw-r--r--cmd/podman/generate_kube.go40
-rw-r--r--cmd/podman/imagefilters/filters.go7
-rw-r--r--cmd/podman/images.go17
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/pull.go9
-rw-r--r--cmd/podman/run.go2
-rw-r--r--cmd/podman/run_test.go2
-rw-r--r--cmd/podman/shared/container.go35
-rw-r--r--cmd/podman/shared/intermediate.go8
-rw-r--r--cmd/podman/varlink/io.podman.varlink15
-rw-r--r--docs/podman-commit.1.md4
-rw-r--r--install.md1
-rw-r--r--libpod/container.go2
-rw-r--r--libpod/container_commit.go17
-rw-r--r--libpod/container_internal.go10
-rw-r--r--libpod/kube.go2
-rw-r--r--libpod/oci_linux.go53
-rw-r--r--libpod/runtime_ctr.go17
-rw-r--r--pkg/adapter/containers.go9
-rw-r--r--pkg/adapter/containers_remote.go24
-rw-r--r--pkg/adapter/runtime.go29
-rw-r--r--pkg/adapter/runtime_remote.go19
-rw-r--r--pkg/rootless/rootless_linux.c7
-rw-r--r--pkg/rootless/rootless_linux.go14
-rw-r--r--pkg/spec/spec.go3
-rw-r--r--pkg/varlinkapi/attach.go76
-rw-r--r--pkg/varlinkapi/generate.go30
-rw-r--r--test/e2e/commit_test.go19
-rw-r--r--test/e2e/create_test.go11
-rw-r--r--test/e2e/images_test.go11
-rw-r--r--test/e2e/prune_test.go4
-rw-r--r--test/e2e/pull_test.go6
-rw-r--r--test/e2e/rmi_test.go2
-rw-r--r--test/system/005-info.bats4
-rw-r--r--test/system/010-images.bats3
-rw-r--r--test/system/015-help.bats2
-rw-r--r--test/system/030-run.bats14
-rw-r--r--test/system/035-logs.bats2
-rw-r--r--test/system/060-mount.bats1
-rw-r--r--test/system/070-build.bats2
-rw-r--r--test/system/075-exec.bats2
-rw-r--r--test/system/110-history.bats2
-rw-r--r--test/system/400-unprivileged-access.bats1
-rw-r--r--test/system/helpers.bash10
52 files changed, 520 insertions, 175 deletions
diff --git a/API.md b/API.md
index 95507d189..738449f43 100755
--- a/API.md
+++ b/API.md
@@ -3,7 +3,7 @@ Podman Service Interface and API description. The master version of this docume
in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in the upstream libpod repository.
## Index
-[func Attach(name: string) ](#Attach)
+[func Attach(name: string, detachKeys: string, start: bool) ](#Attach)
[func AttachControl(name: string) ](#AttachControl)
@@ -119,6 +119,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func PodStateData(name: string) string](#PodStateData)
+[func Ps(opts: PsOpts) PsContainer](#Ps)
+
[func PullImage(name: string, certDir: string, creds: string, signaturePolicy: string, tlsVerify: ) MoreResponse](#PullImage)
[func PushImage(name: string, tag: string, tlsverify: , signaturePolicy: string, creds: string, certDir: string, compress: bool, format: string, removeSignatures: bool, signBy: string) MoreResponse](#PushImage)
@@ -225,6 +227,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type PodmanInfo](#PodmanInfo)
+[type PsContainer](#PsContainer)
+
+[type PsOpts](#PsOpts)
+
[type Runlabel](#Runlabel)
[type Sockets](#Sockets)
@@ -261,8 +267,9 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
### <a name="Attach"></a>func Attach
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method Attach(name: [string](https://godoc.org/builtin#string)) </div>
-
+method Attach(name: [string](https://godoc.org/builtin#string), detachKeys: [string](https://godoc.org/builtin#string), start: [bool](https://godoc.org/builtin#bool)) </div>
+Attach takes the name or ID of a container and sets up a the ability to remotely attach to its console. The start
+bool is whether you wish to start the container in question first.
### <a name="AttachControl"></a>func AttachControl
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -857,6 +864,11 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.PausePod '{"name": "fooba
method PodStateData(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
PodStateData returns inspectr level information of a given pod in string form. This call is for
development of Podman only and generally should not be used.
+### <a name="Ps"></a>func Ps
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method Ps(opts: [PsOpts](#PsOpts)) [PsContainer](#PsContainer)</div>
+
### <a name="PullImage"></a>func PullImage
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1749,6 +1761,82 @@ insecure_registries [[]string](#[]string)
store [InfoStore](#InfoStore)
podman [InfoPodmanBinary](#InfoPodmanBinary)
+### <a name="PsContainer"></a>type PsContainer
+
+
+
+id [string](https://godoc.org/builtin#string)
+
+image [string](https://godoc.org/builtin#string)
+
+command [string](https://godoc.org/builtin#string)
+
+created [string](https://godoc.org/builtin#string)
+
+ports [string](https://godoc.org/builtin#string)
+
+names [string](https://godoc.org/builtin#string)
+
+isInfra [bool](https://godoc.org/builtin#bool)
+
+status [string](https://godoc.org/builtin#string)
+
+state [string](https://godoc.org/builtin#string)
+
+pidNum [int](https://godoc.org/builtin#int)
+
+rootFsSize [int](https://godoc.org/builtin#int)
+
+rwSize [int](https://godoc.org/builtin#int)
+
+pod [string](https://godoc.org/builtin#string)
+
+createdAt [string](https://godoc.org/builtin#string)
+
+exitedAt [string](https://godoc.org/builtin#string)
+
+startedAt [string](https://godoc.org/builtin#string)
+
+labels [map[string]](#map[string])
+
+nsPid [string](https://godoc.org/builtin#string)
+
+cgroup [string](https://godoc.org/builtin#string)
+
+ipc [string](https://godoc.org/builtin#string)
+
+mnt [string](https://godoc.org/builtin#string)
+
+net [string](https://godoc.org/builtin#string)
+
+pidNs [string](https://godoc.org/builtin#string)
+
+user [string](https://godoc.org/builtin#string)
+
+uts [string](https://godoc.org/builtin#string)
+
+mounts [string](https://godoc.org/builtin#string)
+### <a name="PsOpts"></a>type PsOpts
+
+
+
+all [bool](https://godoc.org/builtin#bool)
+
+filters [](#)
+
+last [](#)
+
+latest [](#)
+
+noTrunc [](#)
+
+pod [](#)
+
+quiet [](#)
+
+sort [](#)
+
+sync [](#)
### <a name="Runlabel"></a>type Runlabel
Runlabel describes the required input for container runlabel
diff --git a/README.md b/README.md
index 742c6238c..73a7057ea 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ This project tests all builds against each supported version of Fedora, the late
1. Further work on the podman pod command
1. Further improvements on rootless containers
-## [Shortcomings of Rootless Podman](https://github.com/containers/libpod/blob/master/docs/rootless.md)
+## [Shortcomings of Rootless Podman](https://github.com/containers/libpod/blob/master/rootless.md)
## Out of scope
diff --git a/cmd/podman/cliconfig/commands.go b/cmd/podman/cliconfig/commands.go
index 3361c14b8..00b66e32a 100644
--- a/cmd/podman/cliconfig/commands.go
+++ b/cmd/podman/cliconfig/commands.go
@@ -1,6 +1,8 @@
package cliconfig
-import "github.com/sirupsen/logrus"
+import (
+ "github.com/sirupsen/logrus"
+)
// GlobalIsSet is a compatibility method for urfave
func (p *PodmanCommand) GlobalIsSet(opt string) bool {
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index f7ac0de6c..2692ace36 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -88,12 +88,13 @@ type CheckpointValues struct {
type CommitValues struct {
PodmanCommand
- Change []string
- Format string
- Message string
- Author string
- Pause bool
- Quiet bool
+ Change []string
+ Format string
+ Message string
+ Author string
+ Pause bool
+ Quiet bool
+ IncludeVolumes bool
}
type ContainersPrune struct {
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 9fea1494b..6156fc2f8 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -13,7 +13,6 @@ func getMainCommands() []*cobra.Command {
rootCommands := []*cobra.Command{
_commitCommand,
_execCommand,
- _generateCommand,
_playCommand,
_loginCommand,
_logoutCommand,
@@ -71,12 +70,6 @@ func getContainerSubCommands() []*cobra.Command {
}
}
-func getGenerateSubCommands() []*cobra.Command {
- return []*cobra.Command{
- _containerKubeCommand,
- }
-}
-
// Commands that the local client implements
func getPlaySubCommands() []*cobra.Command {
return []*cobra.Command{
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index f7e206856..0077ff297 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -2,19 +2,19 @@ package main
import (
"fmt"
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/spf13/cobra"
"io"
"os"
"strings"
"github.com/containers/buildah"
"github.com/containers/image/manifest"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
+ "github.com/spf13/cobra"
)
var (
@@ -47,7 +47,7 @@ func init() {
flags.StringVarP(&commitCommand.Author, "author", "a", "", "Set the author for the image committed")
flags.BoolVarP(&commitCommand.Pause, "pause", "p", false, "Pause container during commit")
flags.BoolVarP(&commitCommand.Quiet, "quiet", "q", false, "Suppress output")
-
+ flags.BoolVar(&commitCommand.IncludeVolumes, "include-volumes", false, "Include container volumes as image volumes")
}
func commitCmd(c *cliconfig.CommitValues) error {
@@ -109,11 +109,12 @@ func commitCmd(c *cliconfig.CommitValues) error {
PreferredManifestType: mimeType,
}
options := libpod.ContainerCommitOptions{
- CommitOptions: coptions,
- Pause: c.Pause,
- Message: c.Message,
- Changes: c.Change,
- Author: c.Author,
+ CommitOptions: coptions,
+ Pause: c.Pause,
+ IncludeVolumes: c.IncludeVolumes,
+ Message: c.Message,
+ Changes: c.Change,
+ Author: c.Author,
}
newImage, err := ctr.Commit(getContext(), reference, options)
if err != nil {
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 1af3920dd..3267e5b7b 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -66,7 +66,7 @@ func createCmd(c *cliconfig.CreateValues) error {
}
func createInit(c *cliconfig.PodmanCommand) error {
- if c.Bool("trace") {
+ if !remote && c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "createInit")
defer span.Finish()
}
diff --git a/cmd/podman/generate.go b/cmd/podman/generate.go
index 197fd26a6..a0637ecb2 100644
--- a/cmd/podman/generate.go
+++ b/cmd/podman/generate.go
@@ -14,10 +14,15 @@ var (
Long: generateDescription,
RunE: commandRunE(),
}
+
+ // Commands that are universally implemented
+ generateCommands = []*cobra.Command{
+ _containerKubeCommand,
+ }
)
func init() {
generateCommand.Command = _generateCommand
- generateCommand.AddCommand(getGenerateSubCommands()...)
+ generateCommand.AddCommand(generateCommands...)
generateCommand.SetUsageTemplate(UsageTemplate())
}
diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go
index c58372899..30818403b 100644
--- a/cmd/podman/generate_kube.go
+++ b/cmd/podman/generate_kube.go
@@ -3,13 +3,11 @@ package main
import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
podmanVersion "github.com/containers/libpod/version"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/spf13/cobra"
- "k8s.io/api/core/v1"
)
var (
@@ -42,14 +40,12 @@ func init() {
func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
var (
- podYAML *v1.Pod
- container *libpod.Container
- err error
- output []byte
- pod *libpod.Pod
+ //podYAML *v1.Pod
+ err error
+ output []byte
+ //pod *libpod.Pod
marshalledPod []byte
marshalledService []byte
- servicePorts []v1.ServicePort
)
args := c.InputArgs
@@ -57,43 +53,27 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error {
return errors.Errorf("you must provide exactly one container|pod ID or name")
}
- runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
- // Get the container in question
- container, err = runtime.LookupContainer(args[0])
+ podYAML, serviceYAML, err := runtime.GenerateKube(c)
if err != nil {
- pod, err = runtime.LookupPod(args[0])
- if err != nil {
- return err
- }
- podYAML, servicePorts, err = pod.GenerateForKube()
- } else {
- if len(container.Dependencies()) > 0 {
- return errors.Wrapf(libpod.ErrNotImplemented, "containers with dependencies")
- }
- podYAML, err = container.GenerateForKube()
+ return err
}
+ // Marshall the results
+ marshalledPod, err = yaml.Marshal(podYAML)
if err != nil {
return err
}
-
if c.Service {
- serviceYAML := libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
marshalledService, err = yaml.Marshal(serviceYAML)
if err != nil {
return err
}
}
- // Marshall the results
- marshalledPod, err = yaml.Marshal(podYAML)
- if err != nil {
- return err
- }
-
header := `# Generation of Kubernetes YAML is still under development!
#
# Save the output of this file and use kubectl create -f to import
diff --git a/cmd/podman/imagefilters/filters.go b/cmd/podman/imagefilters/filters.go
index 2932d61c0..aa5776599 100644
--- a/cmd/podman/imagefilters/filters.go
+++ b/cmd/podman/imagefilters/filters.go
@@ -37,9 +37,12 @@ func CreatedAfterFilter(createTime time.Time) ResultFilter {
}
// DanglingFilter allows you to filter images for dangling images
-func DanglingFilter() ResultFilter {
+func DanglingFilter(danglingImages bool) ResultFilter {
return func(i *adapter.ContainerImage) bool {
- return i.Dangling()
+ if danglingImages {
+ return i.Dangling()
+ }
+ return !i.Dangling()
}
}
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 6133450be..c38d7035d 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"sort"
+ "strconv"
"strings"
"time"
"unicode"
@@ -318,13 +319,14 @@ func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage)
func generateImagesOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) error {
templateMap := GenImageOutputMap()
- if len(images) == 0 {
- return nil
- }
var out formats.Writer
switch opts.format {
case formats.JSONString:
+ // If 0 images are present, print nothing for JSON
+ if len(images) == 0 {
+ return nil
+ }
imagesOutput := getImagesJSONOutput(ctx, images)
out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
default:
@@ -359,6 +361,9 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s
var filterFuncs []imagefilters.ResultFilter
for _, filter := range filters {
splitFilter := strings.Split(filter, "=")
+ if len(splitFilter) != 2 {
+ return nil, errors.Errorf("invalid filter syntax %s", filter)
+ }
switch splitFilter[0] {
case "before":
before, err := r.NewImageFromLocal(splitFilter[1])
@@ -373,7 +378,11 @@ func CreateFilterFuncs(ctx context.Context, r *adapter.LocalRuntime, filters []s
}
filterFuncs = append(filterFuncs, imagefilters.CreatedAfterFilter(after.Created()))
case "dangling":
- filterFuncs = append(filterFuncs, imagefilters.DanglingFilter())
+ danglingImages, err := strconv.ParseBool(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter dangling=%s", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, imagefilters.DanglingFilter(danglingImages))
case "label":
labelFilter := strings.Join(splitFilter[1:], "=")
filterFuncs = append(filterFuncs, imagefilters.LabelFilter(ctx, labelFilter))
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 35a94b3db..e8c3e14ea 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -36,6 +36,7 @@ var mainCommands = []*cobra.Command{
_createCommand,
_eventsCommand,
_exportCommand,
+ _generateCommand,
_historyCommand,
&_imagesCommand,
_importCommand,
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 491d3a8c2..7cc7b65b3 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -61,7 +61,12 @@ func init() {
// pullCmd gets the data from the command line and calls pullImage
// to copy an image from a registry to a local machine
-func pullCmd(c *cliconfig.PullValues) error {
+func pullCmd(c *cliconfig.PullValues) (retError error) {
+ defer func() {
+ if retError != nil && exitCode == 0 {
+ exitCode = 1
+ }
+ }()
if c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "pullCmd")
defer span.Finish()
@@ -163,7 +168,7 @@ func pullCmd(c *cliconfig.PullValues) error {
for _, name := range names {
newImage, err := runtime.New(getContext(), name, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, true, nil)
if err != nil {
- println(errors.Wrapf(err, "error pulling image %q", name))
+ logrus.Errorf("error pulling image %q", name)
foundImage = false
continue
}
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index bac5c3c18..d3158de6b 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -38,7 +38,7 @@ func init() {
}
func runCmd(c *cliconfig.RunValues) error {
- if c.Bool("trace") {
+ if !remote && c.Bool("trace") {
span, _ := opentracing.StartSpanFromContext(Ctx, "runCmd")
defer span.Finish()
}
diff --git a/cmd/podman/run_test.go b/cmd/podman/run_test.go
index 27b34c323..af9e6923c 100644
--- a/cmd/podman/run_test.go
+++ b/cmd/podman/run_test.go
@@ -83,7 +83,7 @@ func getRuntimeSpec(c *cliconfig.PodmanCommand) (*spec.Spec, error) {
createConfig, err := parseCreateOpts(c, runtime, "alpine", generateAlpineImageData())
*/
ctx := getContext()
- genericResults := shared.NewIntermediateLayer(c)
+ genericResults := shared.NewIntermediateLayer(c, false)
createConfig, err := shared.ParseCreateOpts(ctx, &genericResults, nil, "alpine", generateAlpineImageData())
if err != nil {
return nil, err
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 7bef62355..e14276bdf 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"io"
+ v1 "k8s.io/api/core/v1"
"os"
"path/filepath"
"regexp"
@@ -938,3 +939,37 @@ func envSliceToMap(env []string) map[string]string {
}
return m
}
+
+// GenerateKube generates kubernetes yaml based on a pod or container
+func GenerateKube(name string, service bool, r *libpod.Runtime) (*v1.Pod, *v1.Service, error) {
+ var (
+ pod *libpod.Pod
+ podYAML *v1.Pod
+ err error
+ container *libpod.Container
+ servicePorts []v1.ServicePort
+ serviceYAML v1.Service
+ )
+ // Get the container in question
+ container, err = r.LookupContainer(name)
+ if err != nil {
+ pod, err = r.LookupPod(name)
+ if err != nil {
+ return nil, nil, err
+ }
+ podYAML, servicePorts, err = pod.GenerateForKube()
+ } else {
+ if len(container.Dependencies()) > 0 {
+ return nil, nil, errors.Wrapf(libpod.ErrNotImplemented, "containers with dependencies")
+ }
+ podYAML, err = container.GenerateForKube()
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if service {
+ serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
+ }
+ return podYAML, &serviceYAML, nil
+}
diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go
index 9afbd68c8..2e1827561 100644
--- a/cmd/podman/shared/intermediate.go
+++ b/cmd/podman/shared/intermediate.go
@@ -360,7 +360,7 @@ func newCRStringArray(c *cliconfig.PodmanCommand, flag string) CRStringArray {
}
// NewIntermediateLayer creates a GenericCLIResults from a create or run cli-command
-func NewIntermediateLayer(c *cliconfig.PodmanCommand) GenericCLIResults {
+func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIResults {
m := make(map[string]GenericCLIResult)
m["add-host"] = newCRStringSlice(c, "add-host")
@@ -458,8 +458,10 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand) GenericCLIResults {
m["volumes-from"] = newCRStringSlice(c, "volumes-from")
m["workdir"] = newCRString(c, "workdir")
// global flag
- m["trace"] = newCRBool(c, "trace")
- m["syslog"] = newCRBool(c, "syslog")
+ if !remote {
+ m["trace"] = newCRBool(c, "trace")
+ m["syslog"] = newCRBool(c, "syslog")
+ }
return GenericCLIResults{m, c.InputArgs}
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index ae830f3e6..b5295273a 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -98,6 +98,11 @@ type ImageSearchFilter (
star_count: int
)
+type KubePodService (
+ pod: string,
+ service: string
+)
+
type Container (
id: string,
image: string,
@@ -658,7 +663,9 @@ method PauseContainer(name: string) -> (container: string)
# See also [PauseContainer](#PauseContainer).
method UnpauseContainer(name: string) -> (container: string)
-method Attach(name: string) -> ()
+# Attach takes the name or ID of a container and sets up a the ability to remotely attach to its console. The start
+# bool is whether you wish to start the container in question first.
+method Attach(name: string, detachKeys: string, start: bool) -> ()
method AttachControl(name: string) -> ()
@@ -1122,11 +1129,7 @@ method ImagesPrune(all: bool) -> (pruned: []string)
# GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
# and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
-# method GenerateKube() -> (notimplemented: NotImplemented)
-
-# GenerateKubeService generates a Kubernetes v1 Service description of a Podman container or pod
-# and its containers. The description is in YAML. See also [GenerateKube](GenerateKube).
-# method GenerateKubeService() -> (notimplemented: NotImplemented)
+method GenerateKube(name: string, service: bool) -> (pod: KubePodService)
# ReplayKube recreates a pod and its containers based on a Kubernetes v1 Pod description (in YAML)
# like that created by GenerateKube. See also [GenerateKube](GenerateKube).
diff --git a/docs/podman-commit.1.md b/docs/podman-commit.1.md
index acde51859..7c74d7a33 100644
--- a/docs/podman-commit.1.md
+++ b/docs/podman-commit.1.md
@@ -39,6 +39,10 @@ not specifically set, the default format used is _oci_.
Write the image ID to the file.
+**--include-volumes**
+
+Include in the committed image any volumes added to the container by the `--volume` or `--mount` options to the `podman create` and `podman run` commands.
+
**--message, -m**
Set commit message for committed image. The message field is not supported in _oci_ format.
diff --git a/install.md b/install.md
index 5fe150db2..80ae03208 100644
--- a/install.md
+++ b/install.md
@@ -57,6 +57,7 @@ sudo yum module install -y container-tools:1.0
sudo apt-get update -qq
sudo apt-get install -qq -y software-properties-common
sudo add-apt-repository -y ppa:projectatomic/ppa
+sudo apt-get update -qq
sudo apt-get -qq -y install podman
```
diff --git a/libpod/container.go b/libpod/container.go
index de4674222..4bf9a1ba9 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -614,7 +614,7 @@ func (c *Container) NewNetNS() bool {
func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
// First check if the container belongs to a network namespace (like a pod)
if len(c.config.NetNsCtr) > 0 {
- netNsCtr, err := c.runtime.LookupContainer(c.config.NetNsCtr)
+ netNsCtr, err := c.runtime.GetContainer(c.config.NetNsCtr)
if err != nil {
return nil, errors.Wrapf(err, "unable to lookup network namespace for container %s", c.ID())
}
diff --git a/libpod/container_commit.go b/libpod/container_commit.go
index 0604a550b..db67f7a30 100644
--- a/libpod/container_commit.go
+++ b/libpod/container_commit.go
@@ -20,10 +20,11 @@ import (
//libpod
type ContainerCommitOptions struct {
buildah.CommitOptions
- Pause bool
- Author string
- Message string
- Changes []string
+ Pause bool
+ IncludeVolumes bool
+ Author string
+ Message string
+ Changes []string
}
// ChangeCmds is the list of valid Changes commands to passed to the Commit call
@@ -113,9 +114,11 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
// User
importBuilder.SetUser(c.User())
// Volumes
- for _, v := range c.config.UserVolumes {
- if v != "" {
- importBuilder.AddVolume(v)
+ if options.IncludeVolumes {
+ for _, v := range c.config.UserVolumes {
+ if v != "" {
+ importBuilder.AddVolume(v)
+ }
}
}
// Workdir
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 3c7319963..aa6448f4a 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -350,7 +350,7 @@ func (c *Container) teardownStorage() error {
artifacts := filepath.Join(c.config.StaticDir, artifactsDir)
if err := os.RemoveAll(artifacts); err != nil {
- return errors.Wrapf(err, "error removing artifacts %q", artifacts)
+ return errors.Wrapf(err, "error removing container %s artifacts %q", c.ID(), artifacts)
}
if err := c.cleanupStorage(); err != nil {
@@ -676,7 +676,7 @@ func (c *Container) getAllDependencies(visited map[string]*Container) error {
}
for _, depID := range depIDs {
if _, ok := visited[depID]; !ok {
- dep, err := c.runtime.state.LookupContainer(depID)
+ dep, err := c.runtime.state.Container(depID)
if err != nil {
return err
}
@@ -1113,13 +1113,13 @@ func (c *Container) cleanup(ctx context.Context) error {
// Remove healthcheck unit/timer file if it execs
if c.config.HealthCheckConfig != nil {
if err := c.removeTimer(); err != nil {
- logrus.Error(err)
+ logrus.Errorf("Error removing timer for container %s healthcheck: %v", c.ID(), err)
}
}
// Clean up network namespace, if present
if err := c.cleanupNetwork(); err != nil {
- lastError = err
+ lastError = errors.Wrapf(err, "error removing container %s network", c.ID())
}
// Unmount storage
@@ -1127,7 +1127,7 @@ func (c *Container) cleanup(ctx context.Context) error {
if lastError != nil {
logrus.Errorf("Error unmounting container %s storage: %v", c.ID(), err)
} else {
- lastError = err
+ lastError = errors.Wrapf(err, "error unmounting container %s storage", c.ID())
}
}
diff --git a/libpod/kube.go b/libpod/kube.go
index 484127870..260269b2e 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -69,7 +69,7 @@ func (p *Pod) getInfraContainer() (*Container, error) {
if err != nil {
return nil, err
}
- return p.runtime.LookupContainer(infraID)
+ return p.runtime.GetContainer(infraID)
}
// GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 8c0abad80..01f7c3649 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -3,15 +3,20 @@
package libpod
import (
+ "fmt"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"syscall"
"github.com/containerd/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/utils"
+ pmount "github.com/containers/storage/pkg/mount"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -91,6 +96,54 @@ func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string, restor
return err
}
}
+
+ // if we are running a non privileged container, be sure to umount some kernel paths so they are not
+ // bind mounted inside the container at all.
+ if !ctr.config.Privileged && !rootless.IsRootless() {
+ ch := make(chan error)
+ go func() {
+ runtime.LockOSThread()
+ err := func() error {
+ fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+
+ // create a new mountns on the current thread
+ if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
+ return err
+ }
+ defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS)
+
+ // don't spread our mounts around. We are setting only /sys to be slave
+ // so that the cleanup process is still able to umount the storage and the
+ // changes are propagated to the host.
+ err = unix.Mount("/sys", "/sys", "none", unix.MS_REC|unix.MS_SLAVE, "")
+ if err != nil {
+ return errors.Wrapf(err, "cannot make /sys slave")
+ }
+
+ mounts, err := pmount.GetMounts()
+ if err != nil {
+ return err
+ }
+ for _, m := range mounts {
+ if !strings.HasPrefix(m.Mountpoint, "/sys/kernel") {
+ continue
+ }
+ err = unix.Unmount(m.Mountpoint, 0)
+ if err != nil {
+ return errors.Wrapf(err, "cannot unmount %s", m.Mountpoint)
+ }
+ }
+ return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
+ }()
+ ch <- err
+ }()
+ err := <-ch
+ return err
+ }
}
return r.createOCIContainer(ctr, cgroupParent, restoreOptions)
}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 800b42851..48c254c0f 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -372,7 +372,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// Clean up network namespace, cgroups, mounts
if err := c.cleanup(ctx); err != nil {
if cleanupErr == nil {
- cleanupErr = err
+ cleanupErr = errors.Wrapf(err, "error cleaning up container %s", c.ID())
} else {
logrus.Errorf("cleanup network, cgroups, mounts: %v", err)
}
@@ -404,12 +404,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
// Deallocate the container's lock
if err := c.lock.Free(); err != nil {
if cleanupErr == nil {
- cleanupErr = err
+ cleanupErr = errors.Wrapf(err, "error freeing lock for container %s", c.ID())
} else {
logrus.Errorf("free container lock: %v", err)
}
}
+ c.newContainerEvent(events.Remove)
+
if !removeVolume {
return cleanupErr
}
@@ -425,7 +427,6 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- c.newContainerEvent(events.Remove)
return cleanupErr
}
@@ -547,16 +548,6 @@ func (r *Runtime) GetLatestContainer() (*Container, error) {
return ctrs[lastCreatedIndex], nil
}
-// Export is the libpod portion of exporting a container to a tar file
-func (r *Runtime) Export(name string, path string) error {
- ctr, err := r.LookupContainer(name)
- if err != nil {
- return err
- }
- return ctr.Export(path)
-
-}
-
// RemoveContainersFromStorage attempt to remove containers from storage that do not exist in libpod database
func (r *Runtime) RemoveContainersFromStorage(ctrs []string) {
for _, i := range ctrs {
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 1bb1aab87..931c55a57 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -255,14 +255,17 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions)
// CreateContainer creates a libpod container
func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) {
- results := shared.NewIntermediateLayer(&c.PodmanCommand)
+ results := shared.NewIntermediateLayer(&c.PodmanCommand, false)
ctr, _, err := shared.CreateContainer(ctx, &results, r.Runtime)
- return ctr.ID(), err
+ if err != nil {
+ return "", err
+ }
+ return ctr.ID(), nil
}
// Run a libpod container
func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) {
- results := shared.NewIntermediateLayer(&c.PodmanCommand)
+ results := shared.NewIntermediateLayer(&c.PodmanCommand, false)
ctr, createConfig, err := shared.CreateContainer(ctx, &results, r.Runtime)
if err != nil {
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 31727fd0e..50cff9fa0 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -331,7 +331,7 @@ func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateV
// TODO need to add attach when that function becomes available
return "", errors.New("the remote client only supports detached containers")
}
- results := shared.NewIntermediateLayer(&c.PodmanCommand)
+ results := shared.NewIntermediateLayer(&c.PodmanCommand, true)
return iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
}
@@ -344,23 +344,21 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
// being run.
// TODO the exit codes for run need to be figured out for remote connections
- results := shared.NewIntermediateLayer(&c.PodmanCommand)
+ results := shared.NewIntermediateLayer(&c.PodmanCommand, true)
cid, err := iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink())
if err != nil {
return 0, err
}
- _, err = iopodman.StartContainer().Call(r.Conn, cid)
- if err != nil {
+ if c.Bool("detach") {
+ _, err := iopodman.StartContainer().Call(r.Conn, cid)
+ fmt.Println(cid)
return 0, err
}
- errChan, err := r.attach(ctx, os.Stdin, os.Stdout, cid)
+
+ errChan, err := r.attach(ctx, os.Stdin, os.Stdout, cid, true)
if err != nil {
return 0, err
}
- if c.Bool("detach") {
- fmt.Println(cid)
- return 0, err
- }
finalError := <-errChan
return 0, finalError
}
@@ -441,7 +439,7 @@ func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]share
return psContainers, nil
}
-func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid string) (chan error, error) {
+func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid string, start bool) (chan error, error) {
var (
oldTermState *term.State
)
@@ -471,8 +469,8 @@ func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid s
term.SetRawTerminal(os.Stdin.Fd())
}
-
- _, err = iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid)
+ // TODO add detach keys support
+ _, err = iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, "", start)
if err != nil {
restoreTerminal(oldTermState)
return nil, err
@@ -533,7 +531,7 @@ func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) er
if c.NoStdin {
inputStream = nil
}
- errChan, err := r.attach(ctx, inputStream, os.Stdout, c.InputArgs[0])
+ errChan, err := r.attach(ctx, inputStream, os.Stdout, c.InputArgs[0], false)
if err != nil {
return err
}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index d45bdb56d..6aafed550 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -7,6 +7,7 @@ import (
"context"
"io"
"io/ioutil"
+ "k8s.io/api/core/v1"
"os"
"text/template"
@@ -404,27 +405,7 @@ func (r *LocalRuntime) Diff(c *cliconfig.DiffValues, to string) ([]archive.Chang
return r.Runtime.GetDiff("", to)
}
-// func (r *LocalRuntime) joinContainerOrCreateRootlessUserNS(ctr *libpod.Container) (bool, int, error) {
-// if os.Geteuid() == 0 {
-// return false, 0, nil
-// }
-// s, err := ctr.State()
-// if err != nil {
-// return false, -1, err
-// }
-// opts := rootless.Opts{
-// Argument: ctr.ID(),
-// }
-// if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused {
-// data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
-// if err != nil {
-// return false, -1, errors.Wrapf(err, "Container %s cannot read conmon PID file %q", ctr.ID(), ctr.Config().ConmonPidFile)
-// }
-// conmonPid, err := strconv.Atoi(string(data))
-// if err != nil {
-// return false, -1, errors.Wrapf(err, "Container %s cannot parse PID %q", ctr.ID(), data)
-// }
-// return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
-// }
-// return rootless.BecomeRootInUserNSWithOpts(&opts)
-// }
+// GenerateKube creates kubernetes email from containers and pods
+func (r *LocalRuntime) GenerateKube(c *cliconfig.GenerateKubeValues) (*v1.Pod, *v1.Service, error) {
+ return shared.GenerateKube(c.InputArgs[0], c.Service, r.Runtime)
+}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 807a9ad8f..71f7380db 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -5,9 +5,11 @@ package adapter
import (
"bufio"
"context"
+ "encoding/json"
"fmt"
"io"
"io/ioutil"
+ v1 "k8s.io/api/core/v1"
"os"
"strings"
"text/template"
@@ -858,3 +860,20 @@ func stringToChangeType(change string) archive.ChangeType {
return archive.ChangeModify
}
}
+
+// GenerateKube creates kubernetes email from containers and pods
+func (r *LocalRuntime) GenerateKube(c *cliconfig.GenerateKubeValues) (*v1.Pod, *v1.Service, error) {
+ var (
+ pod v1.Pod
+ service v1.Service
+ )
+ reply, err := iopodman.GenerateKube().Call(r.Conn, c.InputArgs[0], c.Service)
+ if err != nil {
+ return nil, nil, errors.Wrap(err, "unable to create kubernetes YAML")
+ }
+ if err := json.Unmarshal([]byte(reply.Pod), &pod); err != nil {
+ return nil, nil, err
+ }
+ err = json.Unmarshal([]byte(reply.Service), &service)
+ return &pod, &service, err
+}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 9cb79ed4d..d6a2793a7 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -16,6 +16,8 @@
#include <sys/types.h>
#include <sys/prctl.h>
#include <dirent.h>
+#include <termios.h>
+#include <sys/ioctl.h>
static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
@@ -178,6 +180,11 @@ reexec_userns_join (int userns, int mountns)
_exit (EXIT_FAILURE);
}
+ if (isatty (1) && ioctl (1, TIOCSCTTY, 0) == -1) {
+ fprintf (stderr, "cannot ioctl(TIOCSCTTY): %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
if (setns (userns, 0) < 0)
{
fprintf (stderr, "cannot setns: %s\n", strerror (errno));
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 1d1b1713d..2c99f41a4 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -28,6 +28,10 @@ extern int reexec_userns_join(int userns, int mountns);
*/
import "C"
+const (
+ numSig = 65 // max number of signals
+)
+
func runInUser() error {
os.Setenv("_CONTAINERS_USERNS_CONFIGURED", "done")
return nil
@@ -283,7 +287,15 @@ func BecomeRootInUserNS() (bool, int, error) {
c := make(chan os.Signal, 1)
- gosignal.Notify(c)
+ signals := []os.Signal{}
+ for sig := 0; sig < numSig; sig++ {
+ if sig == int(syscall.SIGTSTP) {
+ continue
+ }
+ signals = append(signals, syscall.Signal(sig))
+ }
+
+ gosignal.Notify(c, signals...)
defer gosignal.Reset()
go func() {
for s := range c {
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 9b6bd089e..0371b6d4d 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -132,6 +132,9 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
Options: []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
}
g.AddMount(sysMnt)
+ if !config.Privileged && isRootless {
+ g.AddLinuxMaskedPaths("/sys/kernel")
+ }
}
if isRootless {
nGids, err := getAvailableGids()
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 53c4d1ff6..9e2a265be 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -3,29 +3,17 @@
package varlinkapi
import (
+ "bufio"
"io"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/varlinkapi/virtwriter"
+ "github.com/sirupsen/logrus"
"k8s.io/client-go/tools/remotecommand"
)
-// Close is method to close the writer
-
-// Attach ...
-func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string) error {
- var finalErr error
- resize := make(chan remotecommand.TerminalSize)
- errChan := make(chan error)
-
- if !call.WantsUpgrade() {
- return call.ReplyErrorOccurred("client must use upgraded connection to attach")
- }
- ctr, err := i.Runtime.LookupContainer(name)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
+func setupStreams(call iopodman.VarlinkCall) (*bufio.Reader, *bufio.Writer, *io.PipeReader, *io.PipeWriter, *libpod.AttachStreams) {
// These are the varlink sockets
reader := call.Call.Reader
@@ -49,6 +37,24 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string) error {
// Runc eats the error stream
AttachError: true,
}
+ return reader, writer, pr, pw, &streams
+}
+
+// Attach connects to a containers console
+func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys string, start bool) error {
+ var finalErr error
+ resize := make(chan remotecommand.TerminalSize)
+ errChan := make(chan error)
+
+ if !call.WantsUpgrade() {
+ return call.ReplyErrorOccurred("client must use upgraded connection to attach")
+ }
+ ctr, err := i.Runtime.LookupContainer(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ reader, writer, _, pw, streams := setupStreams(call)
go func() {
if err := virtwriter.Reader(reader, nil, nil, pw, resize); err != nil {
@@ -56,20 +62,42 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string) error {
}
}()
+ if start {
+ finalErr = startAndAttach(ctr, streams, detachKeys, resize, errChan)
+ } else {
+ finalErr = attach(ctr, streams, detachKeys, resize, errChan)
+ }
+
+ if finalErr != libpod.ErrDetach && finalErr != nil {
+ logrus.Error(finalErr)
+ }
+ quitWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.Quit)
+ _, err = quitWriter.Write([]byte("HANG-UP"))
+ // TODO error handling is not quite right here yet
+ return call.Writer.Flush()
+}
+
+func attach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
go func() {
- // TODO allow for customizable detach keys
- if err := ctr.Attach(&streams, "", resize); err != nil {
+ if err := ctr.Attach(streams, detachKeys, resize); err != nil {
errChan <- err
}
}()
+ attachError := <-errChan
+ return attachError
+}
+func startAndAttach(ctr *libpod.Container, streams *libpod.AttachStreams, detachKeys string, resize chan remotecommand.TerminalSize, errChan chan error) error {
+ var finalErr error
+ attachChan, err := ctr.StartAndAttach(getContext(), streams, detachKeys, resize, false)
+ if err != nil {
+ return err
+ }
select {
- // Blocking on an error
- case finalErr = <-errChan:
- // Need to close up shop
- _ = finalErr
+ case attachChanErr := <-attachChan:
+ finalErr = attachChanErr
+ case chanError := <-errChan:
+ finalErr = chanError
}
- quitWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.Quit)
- _, err = quitWriter.Write([]byte("HANG-UP"))
- return call.Writer.Flush()
+ return finalErr
}
diff --git a/pkg/varlinkapi/generate.go b/pkg/varlinkapi/generate.go
new file mode 100644
index 000000000..bc600c397
--- /dev/null
+++ b/pkg/varlinkapi/generate.go
@@ -0,0 +1,30 @@
+// +build varlink
+
+package varlinkapi
+
+import (
+ "encoding/json"
+ "github.com/containers/libpod/cmd/podman/shared"
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
+)
+
+// GenerateKube ...
+func (i *LibpodAPI) GenerateKube(call iopodman.VarlinkCall, name string, service bool) error {
+ pod, serv, err := shared.GenerateKube(name, service, i.Runtime)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ podB, err := json.Marshal(pod)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ servB, err := json.Marshal(serv)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ return call.ReplyGenerateKube(iopodman.KubePodService{
+ Pod: string(podB),
+ Service: string(servB),
+ })
+}
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index fe4ae64cf..93e1ea7af 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -131,7 +131,7 @@ var _ = Describe("Podman commit", func() {
Expect(check.ExitCode()).To(Equal(0))
})
- It("podman commit with volume mounts", func() {
+ It("podman commit with volumes mounts and no include-volumes", func() {
s := podmanTest.Podman([]string{"run", "--name", "test1", "-v", "/tmp:/foo", "alpine", "date"})
s.WaitWithDefaultTimeout()
Expect(s.ExitCode()).To(Equal(0))
@@ -145,6 +145,23 @@ var _ = Describe("Podman commit", func() {
Expect(inspect.ExitCode()).To(Equal(0))
image := inspect.InspectImageJSON()
_, ok := image[0].Config.Volumes["/foo"]
+ Expect(ok).To(BeFalse())
+ })
+
+ It("podman commit with volume mounts and --include-volumes", func() {
+ s := podmanTest.Podman([]string{"run", "--name", "test1", "-v", "/tmp:/foo", "alpine", "date"})
+ s.WaitWithDefaultTimeout()
+ Expect(s.ExitCode()).To(Equal(0))
+
+ c := podmanTest.Podman([]string{"commit", "--include-volumes", "test1", "newimage"})
+ c.WaitWithDefaultTimeout()
+ Expect(c.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", "newimage"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ image := inspect.InspectImageJSON()
+ _, ok := image[0].Config.Volumes["/foo"]
Expect(ok).To(BeTrue())
r := podmanTest.Podman([]string{"run", "newimage"})
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 6ed5ad2d8..105cba37c 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -70,6 +70,17 @@ var _ = Describe("Podman create", func() {
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
})
+ It("podman create using existing name", func() {
+ session := podmanTest.Podman([]string{"create", "--name=foo", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ session = podmanTest.Podman([]string{"create", "--name=foo", ALPINE, "ls"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ })
+
It("podman create adds annotation", func() {
session := podmanTest.Podman([]string{"create", "--annotation", "HELLO=WORLD", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index a253dff63..48a964db4 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -43,6 +43,17 @@ var _ = Describe("Podman images", func() {
Expect(session.LineInOuputStartsWith("docker.io/library/busybox")).To(BeTrue())
})
+ It("podman images with no images prints header", func() {
+ rmi := podmanTest.Podman([]string{"rmi", "-a"})
+ rmi.WaitWithDefaultTimeout()
+ Expect(rmi.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"images"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(len(session.OutputToStringArray())).To(Equal(1))
+ })
+
It("podman image List", func() {
session := podmanTest.Podman([]string{"image", "list"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index 869ca3289..682f7ff2b 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -82,7 +82,7 @@ var _ = Describe("Podman rm", func() {
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))
- images := podmanTest.Podman([]string{"images", "-a"})
+ images := podmanTest.Podman([]string{"images", "-aq"})
images.WaitWithDefaultTimeout()
// all images are unused, so they all should be deleted!
Expect(len(images.OutputToStringArray())).To(Equal(0))
@@ -95,7 +95,7 @@ var _ = Describe("Podman rm", func() {
prune.WaitWithDefaultTimeout()
Expect(prune.ExitCode()).To(Equal(0))
- images := podmanTest.Podman([]string{"images", "-a"})
+ images := podmanTest.Podman([]string{"images", "-aq"})
images.WaitWithDefaultTimeout()
// all images are unused, so they all should be deleted!
Expect(len(images.OutputToStringArray())).To(Equal(0))
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index de6d4ea09..4e4e80d56 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -38,6 +38,12 @@ var _ = Describe("Podman pull", func() {
})
+ It("podman pull from docker a not existing image", func() {
+ session := podmanTest.Podman([]string{"pull", "ibetthisdoesntexistthere:foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+
It("podman pull from docker with tag", func() {
session := podmanTest.Podman([]string{"pull", "busybox:glibc"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index 78d175637..e034f24cf 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -270,7 +270,7 @@ RUN find $LOCAL
fmt.Println(session.OutputToString())
Expect(session.ExitCode()).To(Equal(0))
- images := podmanTest.Podman([]string{"images", "--all"})
+ images := podmanTest.Podman([]string{"images", "-aq"})
images.WaitWithDefaultTimeout()
Expect(images.ExitCode()).To(Equal(0))
Expect(len(images.OutputToStringArray())).To(Equal(0))
diff --git a/test/system/005-info.bats b/test/system/005-info.bats
index 7dcc78838..c64b011bd 100644
--- a/test/system/005-info.bats
+++ b/test/system/005-info.bats
@@ -3,6 +3,8 @@
load helpers
@test "podman info - basic test" {
+ skip_if_remote
+
run_podman info
expected_keys="
@@ -26,6 +28,8 @@ RunRoot:
}
@test "podman info - json" {
+ skip_if_remote
+
run_podman info --format=json
expr_nvr="[a-z0-9-]\\\+-[a-z0-9.]\\\+-[a-z0-9]\\\+\."
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
index 1c9577e34..380623078 100644
--- a/test/system/010-images.bats
+++ b/test/system/010-images.bats
@@ -25,11 +25,12 @@ load helpers
@test "podman images - json" {
+ # 'created': podman includes fractional seconds, podman-remote does not
tests="
names[0] | $PODMAN_TEST_IMAGE_FQN
id | [0-9a-f]\\\{64\\\}
digest | sha256:[0-9a-f]\\\{64\\\}
-created | [0-9-]\\\+T[0-9:]\\\+\\\.[0-9]\\\+Z
+created | [0-9-]\\\+T[0-9:.]\\\+Z
size | [0-9]\\\+
"
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
index 8e07b8822..a987f04bc 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -87,6 +87,8 @@ function check_help() {
@test "podman help - basic tests" {
+ skip_if_remote
+
# Called with no args -- start with 'podman --help'. check_help() will
# recurse for any subcommands.
check_help
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 8ae68f33d..bdbe724ef 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -3,6 +3,8 @@
load helpers
@test "podman run - basic tests" {
+ skip_if_remote
+
rand=$(random_string 30)
tests="
true | 0 |
@@ -31,4 +33,16 @@ echo $rand | 0 | $rand
done < <(parse_table "$tests")
}
+@test "podman run - uidmapping has no /sys/kernel mounts" {
+ skip_if_rootless "cannot umount as rootless"
+
+ run_podman run --rm --uidmap 0:100:10000 $IMAGE mount
+ run grep /sys/kernel <(echo "$output")
+ is "$output" "" "unwanted /sys/kernel in 'mount' output"
+
+ run_podman run --rm --net host --uidmap 0:100:10000 $IMAGE mount
+ run grep /sys/kernel <(echo "$output")
+ is "$output" "" "unwanted /sys/kernel in 'mount' output (with --net=host)"
+}
+
# vim: filetype=sh
diff --git a/test/system/035-logs.bats b/test/system/035-logs.bats
index 055865c8d..5736e0939 100644
--- a/test/system/035-logs.bats
+++ b/test/system/035-logs.bats
@@ -6,6 +6,8 @@
load helpers
@test "podman logs - basic test" {
+ skip_if_remote
+
rand_string=$(random_string 40)
run_podman create $IMAGE echo $rand_string
diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats
index e249b2883..7570f3ac4 100644
--- a/test/system/060-mount.bats
+++ b/test/system/060-mount.bats
@@ -6,6 +6,7 @@ load helpers
@test "podman mount - basic test" {
# Only works with root (FIXME: does it work with rootless + vfs?)
skip_if_rootless "mount does not work rootless"
+ skip_if_remote
f_path=/tmp/tmpfile_$(random_string 8)
f_content=$(random_string 30)
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 25eb36c58..c6a25093f 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -6,6 +6,8 @@
load helpers
@test "podman build - basic test" {
+ skip_if_remote
+
rand_filename=$(random_string 20)
rand_content=$(random_string 50)
diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats
index a12d28b32..11cb98269 100644
--- a/test/system/075-exec.bats
+++ b/test/system/075-exec.bats
@@ -6,6 +6,8 @@
load helpers
@test "podman exec - basic test" {
+ skip_if_remote
+
rand_filename=$(random_string 20)
rand_content=$(random_string 50)
diff --git a/test/system/110-history.bats b/test/system/110-history.bats
index 84a1e42b4..5dc221d61 100644
--- a/test/system/110-history.bats
+++ b/test/system/110-history.bats
@@ -24,7 +24,7 @@ load helpers
@test "podman history - json" {
tests="
id | [0-9a-f]\\\{64\\\}
-created | [0-9-]\\\+T[0-9:]\\\+\\\.[0-9]\\\+Z
+created | [0-9-]\\\+T[0-9:.]\\\+Z
size | -\\\?[0-9]\\\+
"
diff --git a/test/system/400-unprivileged-access.bats b/test/system/400-unprivileged-access.bats
index c195d71eb..0358b3beb 100644
--- a/test/system/400-unprivileged-access.bats
+++ b/test/system/400-unprivileged-access.bats
@@ -7,6 +7,7 @@ load helpers
@test "podman container storage is not accessible by unprivileged users" {
skip_if_rootless "test meaningless without suid"
+ skip_if_remote
run_podman run --name c_uidmap --uidmap 0:10000:10000 $IMAGE true
run_podman run --name c_uidmap_v --uidmap 0:10000:10000 -v foo:/foo $IMAGE true
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 431228498..29ef19ecc 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -225,6 +225,16 @@ function skip_if_rootless() {
skip "${1:-not applicable under rootless podman}"
}
+####################
+# skip_if_remote # ...with an optional message
+####################
+function skip_if_remote() {
+ if [[ ! "$PODMAN" =~ -remote ]]; then
+ return
+ fi
+
+ skip "${1:-test does not work with podman-remote}"
+}
#########
# die # Abort with helpful message