summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/build.go15
-rw-r--r--cmd/podman/checkpoint.go11
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/exists.go83
-rw-r--r--cmd/podman/image.go1
-rw-r--r--cmd/podman/kube.go22
-rw-r--r--cmd/podman/kube_generate.go93
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/pod_create.go59
-rw-r--r--cmd/podman/shared/funcs.go8
-rw-r--r--cmd/podman/shared/funcs_test.go9
-rw-r--r--cmd/podman/version.go33
12 files changed, 319 insertions, 17 deletions
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 14bf226f9..880cb892f 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -1,6 +1,11 @@
package main
import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
buildahcli "github.com/containers/buildah/pkg/cli"
@@ -10,15 +15,15 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
)
var (
layerFlags = []cli.Flag{
cli.BoolTFlag{
+ Name: "force-rm",
+ Usage: "Always remove intermediate containers after a build, even if the build is unsuccessful. (default true)",
+ },
+ cli.BoolTFlag{
Name: "layers",
Usage: "cache intermediate layers during build. Use BUILDAH_LAYERS environment variable to override. ",
},
@@ -230,7 +235,7 @@ func buildCmd(c *cli.Context) error {
Layers: layers,
NoCache: c.Bool("no-cache"),
RemoveIntermediateCtrs: c.BoolT("rm"),
- ForceRmIntermediateCtrs: c.Bool("force-rm"),
+ ForceRmIntermediateCtrs: c.BoolT("force-rm"),
}
if c.Bool("quiet") {
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index bf280920d..ddfd12bc3 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -24,6 +24,10 @@ var (
Usage: "keep all temporary checkpoint files",
},
cli.BoolFlag{
+ Name: "leave-running, R",
+ Usage: "leave the container running after writing checkpoint to disk",
+ },
+ cli.BoolFlag{
Name: "all, a",
Usage: "checkpoint all running containers",
},
@@ -50,7 +54,10 @@ func checkpointCmd(c *cli.Context) error {
}
defer runtime.Shutdown(false)
- keep := c.Bool("keep")
+ options := libpod.ContainerCheckpointOptions{
+ Keep: c.Bool("keep"),
+ KeepRunning: c.Bool("leave-running"),
+ }
if err := checkAllAndLatest(c); err != nil {
return err
@@ -59,7 +66,7 @@ func checkpointCmd(c *cli.Context) error {
containers, lastError := getAllOrLatestContainers(c, runtime, libpod.ContainerStateRunning, "running")
for _, ctr := range containers {
- if err = ctr.Checkpoint(context.TODO(), keep); err != nil {
+ if err = ctr.Checkpoint(context.TODO(), options); err != nil {
if lastError != nil {
fmt.Fprintln(os.Stderr, lastError)
}
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index ff634278f..b6262f890 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -9,6 +9,7 @@ var (
attachCommand,
checkpointCommand,
cleanupCommand,
+ containerExistsCommand,
commitCommand,
createCommand,
diffCommand,
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
new file mode 100644
index 000000000..2f7b7c185
--- /dev/null
+++ b/cmd/podman/exists.go
@@ -0,0 +1,83 @@
+package main
+
+import (
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/pkg/errors"
+ "github.com/urfave/cli"
+)
+
+var (
+ imageExistsDescription = `
+ podman image exists
+
+ Check if an image exists in local storage
+`
+
+ imageExistsCommand = cli.Command{
+ Name: "exists",
+ Usage: "Check if an image exists in local storage",
+ Description: imageExistsDescription,
+ Action: imageExistsCmd,
+ ArgsUsage: "IMAGE-NAME",
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+var (
+ containerExistsDescription = `
+ podman container exists
+
+ Check if a container exists in local storage
+`
+
+ containerExistsCommand = cli.Command{
+ Name: "exists",
+ Usage: "Check if a container exists in local storage",
+ Description: containerExistsDescription,
+ Action: containerExistsCmd,
+ ArgsUsage: "CONTAINER-NAME",
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+func imageExistsCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) > 1 || len(args) < 1 {
+ return errors.New("you may only check for the existence of one image at a time")
+ }
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+ if _, err := runtime.ImageRuntime().NewFromLocal(args[0]); err != nil {
+ if errors.Cause(err) == image.ErrNoSuchImage {
+ os.Exit(1)
+ }
+ return err
+ }
+ return nil
+}
+
+func containerExistsCmd(c *cli.Context) error {
+ args := c.Args()
+ if len(args) > 1 || len(args) < 1 {
+ return errors.New("you may only check for the existence of one container at a time")
+ }
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+ if _, err := runtime.LookupContainer(args[0]); err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ os.Exit(1)
+ }
+ return err
+ }
+ return nil
+}
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index e67f61799..418b442e3 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -9,6 +9,7 @@ var (
buildCommand,
historyCommand,
importCommand,
+ imageExistsCommand,
inspectCommand,
loadCommand,
lsImagesCommand,
diff --git a/cmd/podman/kube.go b/cmd/podman/kube.go
new file mode 100644
index 000000000..ced87e2bd
--- /dev/null
+++ b/cmd/podman/kube.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "github.com/urfave/cli"
+)
+
+var (
+ kubeSubCommands = []cli.Command{
+ containerKubeCommand,
+ }
+
+ kubeDescription = "Work with Kubernetes objects"
+ kubeCommand = cli.Command{
+ Name: "kube",
+ Usage: "Import and export Kubernetes objections from and to Podman",
+ Description: containerDescription,
+ ArgsUsage: "",
+ Subcommands: kubeSubCommands,
+ UseShortOptionHandling: true,
+ OnUsageError: usageErrorHandler,
+ }
+)
diff --git a/cmd/podman/kube_generate.go b/cmd/podman/kube_generate.go
new file mode 100644
index 000000000..a18912668
--- /dev/null
+++ b/cmd/podman/kube_generate.go
@@ -0,0 +1,93 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/ghodss/yaml"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/urfave/cli"
+)
+
+var (
+ containerKubeFlags = []cli.Flag{
+ cli.BoolFlag{
+ Name: "service, s",
+ Usage: "only generate YAML for kubernetes service object",
+ },
+ LatestFlag,
+ }
+ containerKubeDescription = "Generate Kubernetes Pod YAML"
+ containerKubeCommand = cli.Command{
+ Name: "generate",
+ Usage: "Generate Kubernetes pod YAML for a container",
+ Description: containerKubeDescription,
+ Flags: sortFlags(containerKubeFlags),
+ Action: generateKubeYAMLCmd,
+ ArgsUsage: "CONTAINER-NAME",
+ UseShortOptionHandling: true,
+ OnUsageError: usageErrorHandler,
+ }
+)
+
+// generateKubeYAMLCmdgenerates or replays kube
+func generateKubeYAMLCmd(c *cli.Context) error {
+ var (
+ container *libpod.Container
+ err error
+ output []byte
+ )
+
+ if rootless.IsRootless() {
+ return errors.Wrapf(libpod.ErrNotImplemented, "rootless users")
+ }
+ args := c.Args()
+ if len(args) > 1 || (len(args) < 1 && !c.Bool("latest")) {
+ return errors.Errorf("you must provide one container ID or name or --latest")
+ }
+ if c.Bool("service") {
+ return errors.Wrapf(libpod.ErrNotImplemented, "service generation")
+ }
+
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ // Get the container in question
+ if c.Bool("latest") {
+ container, err = runtime.GetLatestContainer()
+ } else {
+ container, err = runtime.LookupContainer(args[0])
+ }
+ if err != nil {
+ return err
+ }
+
+ if len(container.Dependencies()) > 0 {
+ return errors.Wrapf(libpod.ErrNotImplemented, "containers with dependencies")
+ }
+
+ podYAML, err := container.InspectForKube()
+ if err != nil {
+ return err
+ }
+
+ developmentComment := []byte("# Generation of Kubenetes YAML is still under development!\n")
+ logrus.Warn("This function is still under heavy development.")
+ // Marshall the results
+ b, err := yaml.Marshal(podYAML)
+ if err != nil {
+ return err
+ }
+ output = append(output, developmentComment...)
+ output = append(output, b...)
+ // Output the v1.Pod with the v1.Container
+ fmt.Println(string(output))
+
+ return nil
+}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 38eac4504..6be192593 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -77,6 +77,7 @@ func main() {
infoCommand,
inspectCommand,
killCommand,
+ kubeCommand,
loadCommand,
loginCommand,
logoutCommand,
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 63fa6b294..a3364ac4b 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -3,11 +3,15 @@ package main
import (
"fmt"
"os"
+ "strconv"
"strings"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/cri-o/ocicni/pkg/ocicni"
+ "github.com/docker/go-connections/nat"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@@ -58,6 +62,10 @@ var podCreateFlags = []cli.Flag{
Name: "pod-id-file",
Usage: "Write the pod ID to the file",
},
+ cli.StringSliceFlag{
+ Name: "publish, p",
+ Usage: "Publish a container's port, or a range of ports, to the host (default [])",
+ },
cli.StringFlag{
Name: "share",
Usage: "A comma delimited list of kernel namespaces the pod will share",
@@ -102,6 +110,16 @@ func podCreateCmd(c *cli.Context) error {
defer podIdFile.Close()
defer podIdFile.Sync()
}
+
+ if len(c.StringSlice("publish")) > 0 {
+ if !c.BoolT("infra") {
+ return errors.Errorf("you must have an infra container to publish port bindings to the host")
+ }
+ if rootless.IsRootless() {
+ return errors.Errorf("rootless networking does not allow port binding to the host")
+ }
+ }
+
if !c.BoolT("infra") && c.IsSet("share") && c.String("share") != "none" && c.String("share") != "" {
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
}
@@ -131,6 +149,14 @@ func podCreateCmd(c *cli.Context) error {
options = append(options, nsOptions...)
}
+ if len(c.StringSlice("publish")) > 0 {
+ portBindings, err := CreatePortBindings(c.StringSlice("publish"))
+ if err != nil {
+ return err
+ }
+ options = append(options, libpod.WithInfraContainerPorts(portBindings))
+
+ }
// always have containers use pod cgroups
// User Opt out is not yet supported
options = append(options, libpod.WithPodCgroups())
@@ -152,3 +178,36 @@ func podCreateCmd(c *cli.Context) error {
return nil
}
+
+// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
+func CreatePortBindings(ports []string) ([]ocicni.PortMapping, error) {
+ var portBindings []ocicni.PortMapping
+ // The conversion from []string to natBindings is temporary while mheon reworks the port
+ // deduplication code. Eventually that step will not be required.
+ _, natBindings, err := nat.ParsePortSpecs(ports)
+ if err != nil {
+ return nil, err
+ }
+ for containerPb, hostPb := range natBindings {
+ var pm ocicni.PortMapping
+ pm.ContainerPort = int32(containerPb.Int())
+ for _, i := range hostPb {
+ var hostPort int
+ var err error
+ pm.HostIP = i.HostIP
+ if i.HostPort == "" {
+ hostPort = containerPb.Int()
+ } else {
+ hostPort, err = strconv.Atoi(i.HostPort)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to convert host port to integer")
+ }
+ }
+
+ pm.HostPort = int32(hostPort)
+ pm.Protocol = containerPb.Proto()
+ portBindings = append(portBindings, pm)
+ }
+ }
+ return portBindings, nil
+}
diff --git a/cmd/podman/shared/funcs.go b/cmd/podman/shared/funcs.go
index a92e0d547..8520c0616 100644
--- a/cmd/podman/shared/funcs.go
+++ b/cmd/podman/shared/funcs.go
@@ -5,6 +5,8 @@ import (
"os"
"path/filepath"
"strings"
+
+ "github.com/google/shlex"
)
func substituteCommand(cmd string) (string, error) {
@@ -42,7 +44,11 @@ func GenerateCommand(command, imageName, name string) ([]string, error) {
if name == "" {
name = imageName
}
- cmd := strings.Split(command, " ")
+
+ cmd, err := shlex.Split(command)
+ if err != nil {
+ return nil, err
+ }
prog, err := substituteCommand(cmd[0])
if err != nil {
diff --git a/cmd/podman/shared/funcs_test.go b/cmd/podman/shared/funcs_test.go
index 596df84e8..7506b9d9c 100644
--- a/cmd/podman/shared/funcs_test.go
+++ b/cmd/podman/shared/funcs_test.go
@@ -18,10 +18,11 @@ var (
)
func TestGenerateCommand(t *testing.T) {
- inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
+ inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo \"hello world\""
+ correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo hello world"
newCommand, err := GenerateCommand(inputCommand, "foo", "bar")
assert.Nil(t, err)
+ assert.Equal(t, "hello world", newCommand[11])
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
}
@@ -108,8 +109,8 @@ func TestGenerateCommandNoSetName(t *testing.T) {
}
func TestGenerateCommandNoName(t *testing.T) {
- inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
- correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo echo install"
+ inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
+ correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo echo install"
newCommand, err := GenerateCommand(inputCommand, "foo", "")
assert.Nil(t, err)
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index d80f24a14..d81deb696 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -4,6 +4,7 @@ import (
"fmt"
"time"
+ "github.com/containers/libpod/cmd/podman/formats"
"github.com/containers/libpod/libpod"
"github.com/pkg/errors"
"github.com/urfave/cli"
@@ -15,6 +16,19 @@ func versionCmd(c *cli.Context) error {
if err != nil {
errors.Wrapf(err, "unable to determine version")
}
+
+ versionOutputFormat := c.String("format")
+ if versionOutputFormat != "" {
+ var out formats.Writer
+ switch versionOutputFormat {
+ case formats.JSONString:
+ out = formats.JSONStruct{Output: output}
+ default:
+ out = formats.StdoutTemplate{Output: output, Template: versionOutputFormat}
+ }
+ formats.Writer(out).Out()
+ return nil
+ }
fmt.Println("Version: ", output.Version)
fmt.Println("Go Version: ", output.GoVersion)
if output.GitCommit != "" {
@@ -30,8 +44,17 @@ func versionCmd(c *cli.Context) error {
}
// Cli command to print out the full version of podman
-var versionCommand = cli.Command{
- Name: "version",
- Usage: "Display the PODMAN Version Information",
- Action: versionCmd,
-}
+var (
+ versionCommand = cli.Command{
+ Name: "version",
+ Usage: "Display the Podman Version Information",
+ Action: versionCmd,
+ Flags: versionFlags,
+ }
+ versionFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "format",
+ Usage: "Change the output format to JSON or a Go template",
+ },
+ }
+)