aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2020-03-27 16:25:30 +0100
committerGitHub <noreply@github.com>2020-03-27 16:25:30 +0100
commit4233250c430a8f769048548b6ad6affd0d9e65e0 (patch)
tree0cf0c3dc86ccf85be3d5098f278021798c3f6b6c /cmd
parent3ddb5b10d53df54346a6d795047124fc4e995699 (diff)
parente56d5295614b745115abf0198f7b67ae157aae1e (diff)
downloadpodman-4233250c430a8f769048548b6ad6affd0d9e65e0.tar.gz
podman-4233250c430a8f769048548b6ad6affd0d9e65e0.tar.bz2
podman-4233250c430a8f769048548b6ad6affd0d9e65e0.zip
Merge pull request #5611 from baude/v2podcreate
podmanv2 pod create using podspecgen
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podmanV2/Makefile2
-rw-r--r--cmd/podmanV2/common/netflags.go108
-rw-r--r--cmd/podmanV2/common/types.go3
-rw-r--r--cmd/podmanV2/common/util.go43
-rw-r--r--cmd/podmanV2/pods/create.go132
5 files changed, 288 insertions, 0 deletions
diff --git a/cmd/podmanV2/Makefile b/cmd/podmanV2/Makefile
new file mode 100644
index 000000000..147a78d9c
--- /dev/null
+++ b/cmd/podmanV2/Makefile
@@ -0,0 +1,2 @@
+all:
+ GO111MODULE=off go build -tags 'ABISupport'
diff --git a/cmd/podmanV2/common/netflags.go b/cmd/podmanV2/common/netflags.go
new file mode 100644
index 000000000..758f155c8
--- /dev/null
+++ b/cmd/podmanV2/common/netflags.go
@@ -0,0 +1,108 @@
+package common
+
+import (
+ "net"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+)
+
+func getDefaultNetwork() string {
+ if rootless.IsRootless() {
+ return "slirp4netns"
+ }
+ return "bridge"
+}
+
+func GetNetFlags() *pflag.FlagSet {
+ netFlags := pflag.FlagSet{}
+ netFlags.StringSlice(
+ "add-host", []string{},
+ "Add a custom host-to-IP mapping (host:ip) (default [])",
+ )
+ netFlags.StringSlice(
+ "dns", []string{},
+ "Set custom DNS servers",
+ )
+ netFlags.StringSlice(
+ "dns-opt", []string{},
+ "Set custom DNS options",
+ )
+ netFlags.StringSlice(
+ "dns-search", []string{},
+ "Set custom DNS search domains",
+ )
+ netFlags.String(
+ "ip", "",
+ "Specify a static IPv4 address for the container",
+ )
+ netFlags.String(
+ "mac-address", "",
+ "Container MAC address (e.g. 92:d0:c6:0a:29:33)",
+ )
+ netFlags.String(
+ "network", getDefaultNetwork(),
+ "Connect a container to a network",
+ )
+ netFlags.StringSliceP(
+ "publish", "p", []string{},
+ "Publish a container's port, or a range of ports, to the host (default [])",
+ )
+ netFlags.Bool(
+ "no-hosts", false,
+ "Do not create /etc/hosts within the container, instead use the version from the image",
+ )
+ return &netFlags
+}
+
+func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
+ var (
+ err error
+ )
+ opts := entities.NetOptions{}
+ opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host")
+ if err != nil {
+ return nil, err
+ }
+ servers, err := cmd.Flags().GetStringSlice("dns")
+ if err != nil {
+ return nil, err
+ }
+ for _, d := range servers {
+ if d == "none" {
+ opts.DNSHost = true
+ break
+ }
+ opts.DNSServers = append(opts.DNSServers, net.ParseIP(d))
+ }
+ opts.DNSSearch, err = cmd.Flags().GetStringSlice("dns-search")
+ if err != nil {
+ return nil, err
+ }
+
+ m, err := cmd.Flags().GetString("mac-address")
+ if err != nil {
+ return nil, err
+ }
+ if len(m) > 0 {
+ mac, err := net.ParseMAC(m)
+ if err != nil {
+ return nil, err
+ }
+ opts.StaticMAC = &mac
+ }
+ inputPorts, err := cmd.Flags().GetStringSlice("publish")
+ if err != nil {
+ return nil, err
+ }
+ if len(inputPorts) > 0 {
+ opts.PublishPorts, err = createPortBindings(inputPorts)
+ if err != nil {
+ return nil, err
+ }
+ }
+ opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
+ return &opts, err
+}
diff --git a/cmd/podmanV2/common/types.go b/cmd/podmanV2/common/types.go
new file mode 100644
index 000000000..2427ae975
--- /dev/null
+++ b/cmd/podmanV2/common/types.go
@@ -0,0 +1,3 @@
+package common
+
+var DefaultKernelNamespaces = "cgroup,ipc,net,uts"
diff --git a/cmd/podmanV2/common/util.go b/cmd/podmanV2/common/util.go
new file mode 100644
index 000000000..47bbe12fa
--- /dev/null
+++ b/cmd/podmanV2/common/util.go
@@ -0,0 +1,43 @@
+package common
+
+import (
+ "strconv"
+
+ "github.com/cri-o/ocicni/pkg/ocicni"
+ "github.com/docker/go-connections/nat"
+ "github.com/pkg/errors"
+)
+
+// createPortBindings iterates ports mappings and exposed ports into a format CNI understands
+func createPortBindings(ports []string) ([]ocicni.PortMapping, error) {
+ // TODO wants someone to rewrite this code in the future
+ 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/podmanV2/pods/create.go b/cmd/podmanV2/pods/create.go
new file mode 100644
index 000000000..ab8957ee3
--- /dev/null
+++ b/cmd/podmanV2/pods/create.go
@@ -0,0 +1,132 @@
+package pods
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/cmd/podmanV2/common"
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/errorhandling"
+ "github.com/containers/libpod/pkg/specgen"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ podCreateDescription = `After creating the pod, the pod ID is printed to stdout.
+
+ You can then start it at any time with the podman pod start <pod_id> command. The pod will be created with the initial state 'created'.`
+
+ createCommand = &cobra.Command{
+ Use: "create",
+ Args: cobra.NoArgs,
+ Short: "Create a new empty pod",
+ Long: podCreateDescription,
+ RunE: create,
+ }
+)
+
+var (
+ createOptions entities.PodCreateOptions
+ labels, labelFile []string
+ podIDFile string
+ share string
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: createCommand,
+ Parent: podCmd,
+ })
+ flags := createCommand.Flags()
+ flags.SetInterspersed(false)
+ flags.AddFlagSet(common.GetNetFlags())
+ flags.StringVar(&createOptions.CGroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
+ flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
+ flags.StringVar(&createOptions.InfraImage, "infra-image", define.DefaultInfraImage, "The image of the infra container to associate with the pod")
+ flags.StringVar(&createOptions.InfraCommand, "infra-command", define.DefaultInfraCommand, "The command to run on the infra container when the pod is started")
+ flags.StringSliceVar(&labelFile, "label-file", []string{}, "Read in a line delimited file of labels")
+ flags.StringSliceVarP(&labels, "label", "l", []string{}, "Set metadata on pod (default [])")
+ flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
+ flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod")
+ flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file")
+ flags.StringVar(&share, "share", common.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
+}
+
+func create(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ podIdFile *os.File
+ )
+ createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
+ if err != nil {
+ return errors.Wrapf(err, "unable to process labels")
+ }
+
+ if !createOptions.Infra && cmd.Flag("share").Changed && share != "none" && share != "" {
+ return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
+ }
+ createOptions.Share = strings.Split(share, ",")
+ if cmd.Flag("pod-id-file").Changed {
+ podIdFile, err = util.OpenExclusiveFile(podIDFile)
+ if err != nil && os.IsExist(err) {
+ return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", podIDFile)
+ }
+ if err != nil {
+ return errors.Errorf("error opening pod-id-file %s", podIDFile)
+ }
+ defer errorhandling.CloseQuiet(podIdFile)
+ defer errorhandling.SyncQuiet(podIdFile)
+ }
+
+ createOptions.Net, err = common.NetFlagsToNetOptions(cmd)
+ if err != nil {
+ return err
+ }
+ netInput, err := cmd.Flags().GetString("network")
+ if err != nil {
+ return err
+ }
+ n := specgen.Namespace{}
+ switch netInput {
+ case "bridge":
+ n.NSMode = specgen.Bridge
+ case "host":
+ n.NSMode = specgen.Host
+ case "slip4netns":
+ n.NSMode = specgen.Slirp
+ default:
+ if strings.HasPrefix(netInput, "container:") { //nolint
+ split := strings.Split(netInput, ":")
+ if len(split) != 2 {
+ return errors.Errorf("invalid network paramater: %q", netInput)
+ }
+ n.NSMode = specgen.FromContainer
+ n.Value = split[1]
+ } else if strings.HasPrefix(netInput, "ns:") {
+ return errors.New("the ns: network option is not supported for pods")
+ } else {
+ n.NSMode = specgen.Bridge
+ createOptions.Net.CNINetworks = strings.Split(netInput, ",")
+ }
+ }
+ if len(createOptions.Net.PublishPorts) > 0 {
+ if !createOptions.Infra {
+ return errors.Errorf("you must have an infra container to publish port bindings to the host")
+ }
+ }
+
+ response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
+ if err != nil {
+ return err
+ }
+ fmt.Println(response.Id)
+ return nil
+}