diff options
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/kube.go | 22 | ||||
-rw-r--r-- | cmd/podman/kube_generate.go | 93 | ||||
-rw-r--r-- | cmd/podman/main.go | 1 | ||||
-rw-r--r-- | cmd/podman/pod_create.go | 59 |
4 files changed, 175 insertions, 0 deletions
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 +} |