Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mapping a range of host ports to a single container port #1102

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions cli/command/container/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,24 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
entrypoint = []string{""}
}

ports, portBindings, err := nat.ParsePortSpecs(copts.publish.GetAll())
publishOpts := copts.publish.GetAll()
var ports map[nat.Port]struct{}
var portBindings map[nat.Port][]nat.PortBinding

ports, portBindings, err = nat.ParsePortSpecs(publishOpts)

// If simple port parsing fails try to parse as long format
if err != nil {
return nil, err
publishOpts, err = parsePortOpts(publishOpts)
if err != nil {
return nil, err
}

ports, portBindings, err = nat.ParsePortSpecs(publishOpts)

if err != nil {
return nil, err
}
}

// Merge in exposed ports to the map of published ports
Expand Down Expand Up @@ -661,6 +676,23 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
}, nil
}

func parsePortOpts(publishOpts []string) ([]string, error) {
optsList := []string{}
for _, publish := range publishOpts {
params := map[string]string{"protocol": "tcp"}
for _, param := range strings.Split(publish, ",") {
opt := strings.Split(param, "=")
if len(opt) < 2 {
return optsList, errors.Errorf("invalid publish opts format (should be name=value but got '%s')", param)
}

params[opt[0]] = opt[1]
}
optsList = append(optsList, fmt.Sprintf("%s:%s/%s", params["target"], params["published"], params["protocol"]))
}
return optsList, nil
}

func parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]string, error) {
loggingOptsMap := opts.ConvertKVStringsToMap(loggingOpts)
if loggingDriver == "none" && len(loggingOpts) > 0 {
Expand Down
21 changes: 13 additions & 8 deletions opts/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,22 @@ func ConvertPortToPortConfig(
if binding.HostIP != "" && binding.HostIP != "0.0.0.0" {
logrus.Warnf("ignoring IP-address (%s:%s:%s) service will listen on '0.0.0.0'", binding.HostIP, binding.HostPort, port)
}
hostPort, err := strconv.ParseUint(binding.HostPort, 10, 16)

startHostPort, endHostPort, err := nat.ParsePortRange(binding.HostPort)

if err != nil && binding.HostPort != "" {
return nil, fmt.Errorf("invalid hostport binding (%s) for port (%s)", binding.HostPort, port.Port())
}
ports = append(ports, swarm.PortConfig{
//TODO Name: ?
Protocol: swarm.PortConfigProtocol(strings.ToLower(port.Proto())),
TargetPort: uint32(port.Int()),
PublishedPort: uint32(hostPort),
PublishMode: swarm.PortConfigPublishModeIngress,
})

for i := startHostPort; i <= endHostPort; i++ {
ports = append(ports, swarm.PortConfig{
//TODO Name: ?
Protocol: swarm.PortConfigProtocol(strings.ToLower(port.Proto())),
TargetPort: uint32(port.Int()),
PublishedPort: uint32(i),
PublishMode: swarm.PortConfigPublishModeIngress,
})
}
}
return ports, nil
}
34 changes: 34 additions & 0 deletions opts/port_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ func TestPortOptValidSimpleSyntax(t *testing.T) {
},
},
},
{
value: "80-82:8080/udp",
expected: []swarm.PortConfig{
{
Protocol: "udp",
TargetPort: 8080,
PublishedPort: 80,
PublishMode: swarm.PortConfigPublishModeIngress,
},
{
Protocol: "udp",
TargetPort: 8080,
PublishedPort: 81,
PublishMode: swarm.PortConfigPublishModeIngress,
},
{
Protocol: "udp",
TargetPort: 8080,
PublishedPort: 82,
PublishMode: swarm.PortConfigPublishModeIngress,
},
},
},
{
value: "80-80:8080/tcp",
expected: []swarm.PortConfig{
{
Protocol: "tcp",
TargetPort: 8080,
PublishedPort: 80,
PublishMode: swarm.PortConfigPublishModeIngress,
},
},
},
}
for _, tc := range testCases {
var port PortOpt
Expand Down