Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Commit

Permalink
Use Docker's port parser, separate PortMap converter into a function
Browse files Browse the repository at this point in the history
  • Loading branch information
twelho committed Aug 8, 2019
1 parent 74c82c8 commit a182160
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 64 deletions.
70 changes: 31 additions & 39 deletions pkg/apis/meta/v1alpha1/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"net"
"strconv"
"strings"

"github.com/docker/go-connections/nat"
)

// PortMapping defines a port mapping between the VM and the host
Expand Down Expand Up @@ -41,65 +43,59 @@ type PortMappings []PortMapping

var _ fmt.Stringer = PortMappings{}

var errInvalidPortMappingFormat = fmt.Errorf("port mappings must be of form [<bind address>:]<host port>:<VM port>[/<protocol>]")

func ParsePortMappings(input []string) (PortMappings, error) {
result := make(PortMappings, 0, len(input))

for _, portMapping := range input {
ports := strings.Split(portMapping, ":")
if len(ports) > 3 || len(ports) < 2 {
return nil, errInvalidPortMappingFormat
_, bindings, err := nat.ParsePortSpecs(input)
if err != nil {
return nil, err
}

for port, bindings := range bindings {
if len(bindings) > 1 {
// TODO: For now only support mapping a VM port to a single host IP/port
return nil, fmt.Errorf("only one host binding per VM binding supported for now, received %d", len(bindings))
}

binding := bindings[0]
var err error
var bindAddress net.IP
var hostPort uint64
var vmPort uint64
var protocol Protocol
offset := 0

if len(ports) == 3 {
offset = 1

if bindAddress = net.ParseIP(ports[0]); bindAddress == nil {
return nil, errInvalidPortMappingFormat
if len(binding.HostIP) > 0 {
if bindAddress = net.ParseIP(binding.HostIP); bindAddress == nil {
return nil, fmt.Errorf("invalid bind address: %q", binding.HostIP)
}
}

hostPort, err := strconv.ParseUint(ports[0+offset], 10, 64)
if err != nil {
return nil, err
if hostPort, err = strconv.ParseUint(binding.HostPort, 10, 64); err != nil {
return nil, fmt.Errorf("invalid host port: %q", binding.HostPort)
}

proto := strings.Split(ports[1+offset], "/")

if len(proto) > 2 {
return nil, errInvalidPortMappingFormat
if vmPort, err = strconv.ParseUint(port.Port(), 10, 64); err != nil {
return nil, fmt.Errorf("invalid VM port: %q", port.Port())
}

if len(proto) == 2 {
if protocol, err = protocolFromString(proto[1]); err != nil {
return nil, err
}
if protocol, err = protocolFromString(port.Proto()); err != nil {
return nil, err
}

vmPort, err := strconv.ParseUint(proto[0], 10, 64)
if err != nil {
return nil, err
mapping := PortMapping{
BindAddress: bindAddress,
HostPort: hostPort,
VMPort: vmPort,
Protocol: protocol,
}

for _, portMapping := range result {
if portMapping.HostPort == hostPort && portMapping.Protocol == protocol {
if portMapping.HostPort == mapping.HostPort && portMapping.Protocol == mapping.Protocol {
return nil, fmt.Errorf("cannot use a port/protocol combination on the host twice")
}
}

// TODO: Check for duplicate VM ports

result = append(result, PortMapping{
BindAddress: bindAddress,
HostPort: hostPort,
VMPort: vmPort,
Protocol: protocol,
})
result = append(result, mapping)
}

return result, nil
Expand Down Expand Up @@ -145,10 +141,6 @@ func (p Protocol) String() string {
return string(p)
}

func (p Protocol) MarshalJSON() ([]byte, error) {
return json.Marshal(p)
}

func (p *Protocol) UnmarshalJSON(b []byte) (err error) {
var s string
if err = json.Unmarshal(b, &s); err != nil {
Expand Down
26 changes: 1 addition & 25 deletions pkg/runtime/docker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@ import (
"github.com/docker/docker/api/types/container"
cont "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1"
"github.com/weaveworks/ignite/pkg/runtime"
"github.com/weaveworks/ignite/pkg/util"
)

const (
dockerNetNSFmt = "/proc/%v/ns/net"
portFormat = "%d/tcp" // TODO: Support protocols other than TCP
)

// dockerClient is a runtime.Interface
Expand Down Expand Up @@ -104,27 +101,6 @@ func (dc *dockerClient) AttachContainer(container string) (err error) {
}

func (dc *dockerClient) RunContainer(image string, config *runtime.ContainerConfig, name string) (string, error) {
portBindings := make(nat.PortMap)
for _, portMapping := range config.PortBindings {
var hostIP string
if portMapping.BindAddress != nil {
hostIP = portMapping.BindAddress.String()
}

protocol := portMapping.Protocol
if len(protocol) == 0 {
// Docker uses TCP by default
protocol = meta.ProtocolTCP
}

portBindings[nat.Port(fmt.Sprintf("%d/%s", portMapping.VMPort, protocol.String()))] = []nat.PortBinding{
{
HostIP: hostIP,
HostPort: fmt.Sprintf(portFormat, portMapping.HostPort),
},
}
}

binds := make([]string, 0, len(config.Binds))
for _, bind := range config.Binds {
binds = append(binds, fmt.Sprintf("%s:%s", bind.HostPath, bind.ContainerPath))
Expand Down Expand Up @@ -152,7 +128,7 @@ func (dc *dockerClient) RunContainer(image string, config *runtime.ContainerConf
}, &container.HostConfig{
Binds: binds,
NetworkMode: container.NetworkMode(config.NetworkMode),
PortBindings: portBindings,
PortBindings: portBindingsToPortMap(config.PortBindings),
AutoRemove: config.AutoRemove,
CapAdd: config.CapAdds,
Resources: container.Resources{
Expand Down
35 changes: 35 additions & 0 deletions pkg/runtime/docker/port.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package docker

import (
"fmt"
"strconv"

"github.com/docker/go-connections/nat"
meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1"
)

func portBindingsToPortMap(portMappings meta.PortMappings) nat.PortMap {
portMap := make(nat.PortMap)

for _, portMapping := range portMappings {
var hostIP string
if portMapping.BindAddress != nil {
hostIP = portMapping.BindAddress.String()
}

protocol := portMapping.Protocol
if len(protocol) == 0 {
// Docker uses TCP by default
protocol = meta.ProtocolTCP
}

portMap[nat.Port(fmt.Sprintf("%d/%s", portMapping.VMPort, protocol.String()))] = []nat.PortBinding{
{
HostIP: hostIP,
HostPort: strconv.FormatUint(portMapping.HostPort, 10),
},
}
}

return portMap
}

0 comments on commit a182160

Please sign in to comment.