func ports(c *config.ServiceConfig) (map[nat.Port]struct{}, nat.PortMap, error) { ports, binding, err := nat.ParsePortSpecs(c.Ports) if err != nil { return nil, nil, err } exPorts, _, err := nat.ParsePortSpecs(c.Expose) if err != nil { return nil, nil, err } for k, v := range exPorts { ports[k] = v } exposedPorts := map[nat.Port]struct{}{} for k, v := range ports { exposedPorts[nat.Port(k)] = v } portBindings := nat.PortMap{} for k, bv := range binding { dcbs := make([]nat.PortBinding, len(bv)) for k, v := range bv { dcbs[k] = nat.PortBinding{HostIP: v.HostIP, HostPort: v.HostPort} } portBindings[nat.Port(k)] = dcbs } return exposedPorts, portBindings, nil }
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) { if flags.Changed(flagPublishAdd) { values := flags.Lookup(flagPublishAdd).Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) for port := range ports { *portConfig = append(*portConfig, convertPortToPortConfig(port, portBindings)...) } } if !flags.Changed(flagPublishRemove) { return } toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll() newPorts := []swarm.PortConfig{} portLoop: for _, port := range *portConfig { for _, rawTargetPort := range toRemove { targetPort := nat.Port(rawTargetPort) if equalPort(targetPort, port) { continue portLoop } } newPorts = append(newPorts, port) } *portConfig = newPorts }
func makeBinding(ip, port string) nat.PortMap { binding := nat.PortBinding{ HostIP: ip, HostPort: port, } bindingMap := map[nat.Port][]nat.PortBinding{nat.Port(fmt.Sprintf("%s/tcp", port)): {binding}} return nat.PortMap(bindingMap) }
func tranformPorts(in map[docker.Port]struct{}) map[nat.Port]struct{} { result := make(map[nat.Port]struct{}) for k, v := range in { result[nat.Port(k)] = v } return result }
func TestPortFilterForHostMode(t *testing.T) { var ( p = PortFilter{} nodes = []*node.Node{ { ID: "node-1-id", Name: "node-1-name", Addr: "node-1", }, { ID: "node-2-id", Name: "node-2-name", Addr: "node-2", }, { ID: "node-3-id", Name: "node-3-name", Addr: "node-3", }, } result []*node.Node err error ) // Add a container taking away port 80 in the host mode to nodes[0]. container := &cluster.Container{ Container: types.Container{ID: "c1"}, Info: types.ContainerJSON{ Config: &containertypes.Config{ ExposedPorts: map[nat.Port]struct{}{nat.Port("80"): {}}, }, ContainerJSONBase: &types.ContainerJSONBase{ HostConfig: &containertypes.HostConfig{ NetworkMode: containertypes.NetworkMode("host"), }, }, }} assert.NoError(t, nodes[0].AddContainer(container)) // Request port 80 in the host mode config := &cluster.ContainerConfig{Config: containertypes.Config{ ExposedPorts: map[nat.Port]struct{}{nat.Port("80"): {}}, }, HostConfig: containertypes.HostConfig{ NetworkMode: containertypes.NetworkMode("host"), }, NetworkingConfig: networktypes.NetworkingConfig{}} // nodes[0] should be excluded since port 80 is taken away result, err = p.Filter(config, nodes, true) assert.NoError(t, err) assert.Equal(t, 2, len(result)) assert.NotContains(t, result, nodes[0]) }
// Port returns the host port the specified port is mapped on. func (c *Container) Port(ctx context.Context, port string) (string, error) { if bindings, ok := c.container.NetworkSettings.Ports[nat.Port(port)]; ok { result := []string{} for _, binding := range bindings { result = append(result, binding.HostIP+":"+binding.HostPort) } return strings.Join(result, "\n"), nil } return "", nil }
// Port returns the host port the specified port is mapped on. func (c *Container) Port(port string) (string, error) { info, err := c.findInfo() if err != nil { return "", err } if bindings, ok := info.NetworkSettings.Ports[nat.Port(port)]; ok { result := []string{} for _, binding := range bindings { result = append(result, binding.HostIP+":"+binding.HostPort) } return strings.Join(result, "\n"), nil } return "", nil }
func (c *containerConfig) exposedPorts() map[nat.Port]struct{} { exposedPorts := make(map[nat.Port]struct{}) if c.task.Endpoint == nil { return exposedPorts } for _, portConfig := range c.task.Endpoint.Ports { if portConfig.PublishMode != api.PublishModeHost { continue } port := nat.Port(fmt.Sprintf("%d/%s", portConfig.TargetPort, strings.ToLower(portConfig.Protocol.String()))) exposedPorts[port] = struct{}{} } return exposedPorts }
func makePortsAndBindings(pm []*runtimeApi.PortMapping) (map[dockernat.Port]struct{}, map[dockernat.Port][]dockernat.PortBinding) { exposedPorts := map[dockernat.Port]struct{}{} portBindings := map[dockernat.Port][]dockernat.PortBinding{} for _, port := range pm { exteriorPort := port.GetHostPort() if exteriorPort == 0 { // No need to do port binding when HostPort is not specified continue } interiorPort := port.GetContainerPort() // Some of this port stuff is under-documented voodoo. // See http://stackoverflow.com/questions/20428302/binding-a-port-to-a-host-interface-using-the-rest-api var protocol string switch strings.ToUpper(string(port.GetProtocol())) { case "UDP": protocol = "/udp" case "TCP": protocol = "/tcp" default: glog.Warningf("Unknown protocol %q: defaulting to TCP", port.Protocol) protocol = "/tcp" } dockerPort := dockernat.Port(strconv.Itoa(int(interiorPort)) + protocol) exposedPorts[dockerPort] = struct{}{} hostBinding := dockernat.PortBinding{ HostPort: strconv.Itoa(int(exteriorPort)), HostIP: port.GetHostIp(), } // Allow multiple host ports bind to same docker port if existedBindings, ok := portBindings[dockerPort]; ok { // If a docker port already map to a host port, just append the host ports portBindings[dockerPort] = append(existedBindings, hostBinding) } else { // Otherwise, it's fresh new port binding portBindings[dockerPort] = []dockernat.PortBinding{ hostBinding, } } } return exposedPorts, portBindings }
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error { // The key of the map is `port/protocol`, e.g., `80/tcp` portSet := map[string]swarm.PortConfig{} // Check to see if there are any conflict in flags. if flags.Changed(flagPublishAdd) { values := flags.Lookup(flagPublishAdd).Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) for port := range ports { newConfigs := convertPortToPortConfig(port, portBindings) for _, entry := range newConfigs { if v, ok := portSet[portConfigToString(&entry)]; ok && v != entry { return fmt.Errorf("conflicting port mapping between %v:%v/%s and %v:%v/%s", entry.PublishedPort, entry.TargetPort, entry.Protocol, v.PublishedPort, v.TargetPort, v.Protocol) } portSet[portConfigToString(&entry)] = entry } } } // Override previous PortConfig in service if there is any duplicate for _, entry := range *portConfig { if _, ok := portSet[portConfigToString(&entry)]; !ok { portSet[portConfigToString(&entry)] = entry } } toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll() newPorts := []swarm.PortConfig{} portLoop: for _, port := range portSet { for _, rawTargetPort := range toRemove { targetPort := nat.Port(rawTargetPort) if equalPort(targetPort, port) { continue portLoop } } newPorts = append(newPorts, port) } // Sort the PortConfig to avoid unnecessary updates sort.Sort(byPortConfig(newPorts)) *portConfig = newPorts return nil }
func (c *containerConfig) portBindings() nat.PortMap { portBindings := nat.PortMap{} if c.task.Endpoint == nil { return portBindings } for _, portConfig := range c.task.Endpoint.Ports { if portConfig.PublishMode != api.PublishModeHost { continue } port := nat.Port(fmt.Sprintf("%d/%s", portConfig.TargetPort, strings.ToLower(portConfig.Protocol.String()))) binding := []nat.PortBinding{ {}, } if portConfig.PublishedPort != 0 { binding[0].HostPort = strconv.Itoa(int(portConfig.PublishedPort)) } portBindings[port] = binding } return portBindings }
// Addr returns the host and port from the node in the format HOST:PORT. func (l *LocalCluster) Addr(ctx context.Context, i int, port string) string { return l.Nodes[i].Addr(ctx, nat.Port(port+"/tcp")).String() }
func TestPortFilterRandomAssignment(t *testing.T) { var ( p = PortFilter{} nodes = []*node.Node{ { ID: "node-0-id", Name: "node-0-name", Addr: "node-0", }, { ID: "node-1-id", Name: "node-1-name", Addr: "node-1", }, { ID: "node-2-id", Name: "node-2-name", Addr: "node-2", }, } result []*node.Node err error ) // Simulate a container that requested to map 80 to a random port. // In this case, HostConfig.PortBindings should contain a binding with no // HostPort defined and NetworkSettings.Ports should contain the actual // mapped port. container := &cluster.Container{ Container: types.Container{ID: "c1"}, Info: types.ContainerJSON{ ContainerJSONBase: &types.ContainerJSONBase{ HostConfig: &containertypes.HostConfig{ PortBindings: nat.PortMap( map[nat.Port][]nat.PortBinding{ nat.Port("80/tcp"): { { HostIP: "", HostPort: "", }, }, }, ), }}}} container.Info.NetworkSettings = &types.NetworkSettings{ NetworkSettingsBase: types.NetworkSettingsBase{ Ports: nat.PortMap( map[nat.Port][]nat.PortBinding{ nat.Port("80/tcp"): { { HostIP: "127.0.0.1", HostPort: "1234", }, }, }, ), }} assert.NoError(t, nodes[0].AddContainer(container)) // Request port 80. config := &cluster.ContainerConfig{Config: containertypes.Config{}, HostConfig: containertypes.HostConfig{ PortBindings: makeBinding("", "80"), }, NetworkingConfig: networktypes.NetworkingConfig{}} // Since port "80" has been mapped to "1234", we should be able to request "80". result, err = p.Filter(config, nodes, true) assert.NoError(t, err) assert.Equal(t, result, nodes) // However, we should not be able to request "1234" since it has been used for a random assignment. config = &cluster.ContainerConfig{Config: containertypes.Config{}, HostConfig: containertypes.HostConfig{ PortBindings: makeBinding("", "1234"), }, NetworkingConfig: networktypes.NetworkingConfig{}} result, err = p.Filter(config, nodes, true) assert.NoError(t, err) assert.NotContains(t, result, nodes[0]) }
// Addr returns the host and port from the node in the format HOST:PORT. func (l *LocalCluster) Addr(i int, port string) string { return l.Nodes[i].Addr(nat.Port(port + "/tcp")).String() }
func portSpec(port uint32, protocol api.PortConfig_Protocol) nat.Port { return nat.Port(fmt.Sprintf("%d/%s", port, strings.ToLower(protocol.String()))) }