aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-01-04 12:59:33 -0600
committerAtomic Bot <atomic-devel@projectatomic.io>2018-01-20 18:51:21 +0000
commit946b4ced544e5988a971da12c7e34a684ab0e39d (patch)
tree026fa6619b6b98a9cf08ec66b8cd6dd27a714736 /cmd
parent67f06cf1cfda17387bd094f671672c6b51b2c5cd (diff)
downloadpodman-946b4ced544e5988a971da12c7e34a684ab0e39d.tar.gz
podman-946b4ced544e5988a971da12c7e34a684ab0e39d.tar.bz2
podman-946b4ced544e5988a971da12c7e34a684ab0e39d.zip
Enable port bindings
Set up nbetworking ports for the following use cases: * bind the same port between host and container * bind a specific host port to a different container port * bind a random host port to a specific container port Signed-off-by: baude <bbaude@redhat.com> Closes: #214 Approved by: baude
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/create.go48
-rw-r--r--cmd/podman/spec.go57
2 files changed, 99 insertions, 6 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 55425638f..28bd0a60e 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "net"
"os"
"strconv"
"strings"
@@ -287,15 +288,25 @@ func parseSecurityOpt(config *createConfig, securityOpts []string) error {
return err
}
+// isPortInPortBindings determines if an exposed host port is in user
+// provided ports
+func isPortInPortBindings(pb map[nat.Port][]nat.PortBinding, port nat.Port) bool {
+ var hostPorts []string
+ for _, i := range pb {
+ hostPorts = append(hostPorts, i[0].HostPort)
+ }
+ return libpod.StringInSlice(port.Port(), hostPorts)
+}
+
func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[nat.Port]struct{}, map[nat.Port][]nat.PortBinding, error) {
// TODO Handle exposed ports from image
// Currently ignoring imageExposedPorts
-
- ports, portBindings, err := nat.ParsePortSpecs(c.StringSlice("publish"))
+ var ports map[nat.Port]struct{}
+ ports = make(map[nat.Port]struct{})
+ _, portBindings, err := nat.ParsePortSpecs(c.StringSlice("publish"))
if err != nil {
return nil, nil, err
}
-
for _, e := range c.StringSlice("expose") {
// Merge in exposed ports to the map of published ports
if strings.Contains(e, ":") {
@@ -314,6 +325,28 @@ func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[na
if err != nil {
return nil, nil, err
}
+ // check if the port in question is already being used
+ if isPortInPortBindings(portBindings, p) {
+ return nil, nil, errors.Errorf("host port %s already used in --publish option", p.Port())
+ }
+
+ if c.Bool("publish-all") {
+ l, err := net.Listen("tcp", ":0")
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "unable to get free port")
+ }
+ _, randomPort, err := net.SplitHostPort(l.Addr().String())
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "unable to determine free port")
+ }
+ rp, err := strconv.Atoi(randomPort)
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "unable to convert random port to int")
+ }
+ logrus.Debug(fmt.Sprintf("Using random host port %s with container port %d", randomPort, p.Int()))
+ portBindings[p] = CreatePortBinding(rp, "")
+ continue
+ }
if _, exists := ports[p]; !exists {
ports[p] = struct{}{}
}
@@ -669,3 +702,12 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string,
}
return config, nil
}
+
+//CreatePortBinding takes port (int) and IP (string) and creates an array of portbinding structs
+func CreatePortBinding(hostPort int, hostIP string) []nat.PortBinding {
+ pb := nat.PortBinding{
+ HostPort: strconv.Itoa(hostPort),
+ }
+ pb.HostIP = hostIP
+ return []nat.PortBinding{pb}
+}
diff --git a/cmd/podman/spec.go b/cmd/podman/spec.go
index 152d1740c..cb9efdcb2 100644
--- a/cmd/podman/spec.go
+++ b/cmd/podman/spec.go
@@ -2,6 +2,7 @@ package main
import (
"io/ioutil"
+ "strconv"
"strings"
"github.com/cri-o/ocicni/pkg/ocicni"
@@ -543,6 +544,8 @@ func (c *createConfig) GetTmpfsMounts() []spec.Mount {
func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
+ var portBindings []ocicni.PortMapping
+ var err error
// Uncomment after talking to mheon about unimplemented funcs
// options = append(options, libpod.WithLabels(c.labels))
@@ -554,17 +557,25 @@ func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, er
logrus.Debugf("appending name %s", c.Name)
options = append(options, libpod.WithName(c.Name))
}
- // TODO parse ports into libpod format and include
+
+ // TODO deal with ports defined in image metadata
+ if len(c.PortBindings) > 0 || len(c.ExposedPorts) > 0 {
+ portBindings, err = c.CreatePortBindings()
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to create port bindings")
+ }
+ }
+
if c.NetMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.ConnectedContainer())
if err != nil {
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer())
}
-
options = append(options, libpod.WithNetNSFrom(connectedCtr))
} else if !c.NetMode.IsHost() {
- options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}))
+ options = append(options, libpod.WithNetNS(portBindings))
}
+
if c.PidMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.PidMode.Container())
if err != nil {
@@ -622,3 +633,43 @@ func makeThrottleArray(throttleInput []string) ([]spec.LinuxThrottleDevice, erro
}
return ltds, nil
}
+
+// CreatePortBindings iterates ports mappings and exposed ports into a format CNI understands
+func (c *createConfig) CreatePortBindings() ([]ocicni.PortMapping, error) {
+ var portBindings []ocicni.PortMapping
+ for containerPb, hostPb := range c.PortBindings {
+ 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)
+ // CNI requires us to make both udp and tcp structs
+ pm.Protocol = "udp"
+ portBindings = append(portBindings, pm)
+ pm.Protocol = "tcp"
+ portBindings = append(portBindings, pm)
+ }
+ }
+ for j := range c.ExposedPorts {
+ var expose ocicni.PortMapping
+ expose.HostPort = int32(j.Int())
+ expose.ContainerPort = int32(j.Int())
+ // CNI requires us to make both udp and tcp structs
+ expose.Protocol = "udp"
+ portBindings = append(portBindings, expose)
+ expose.Protocol = "tcp"
+ portBindings = append(portBindings, expose)
+ }
+ return portBindings, nil
+}