From 4c12f8aa6a34cf678e8a952d061a813614286195 Mon Sep 17 00:00:00 2001 From: zhangyue Date: Sat, 8 Dec 2018 19:26:12 +0800 Subject: [PATCH] feature: addd publish-all cli flag Signed-off-by: zhangyue --- cli/common_flags.go | 1 + cli/container.go | 35 +++++++++---------- daemon/mgr/container.go | 11 +++++- daemon/mgr/network.go | 65 +++++++++++++++++++++++++++++++++++- test/cli_inspect_test.go | 2 +- test/cli_run_network_test.go | 41 +++++++++++++++++++++++ 6 files changed, 135 insertions(+), 20 deletions(-) diff --git a/cli/common_flags.go b/cli/common_flags.go index d94b4b5c2..c50562546 100644 --- a/cli/common_flags.go +++ b/cli/common_flags.go @@ -71,6 +71,7 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container { flagSet.StringSliceVar(&c.networks, "net", nil, "Set networks to container") flagSet.StringSliceVarP(&c.ports, "publish", "p", nil, "Set container ports mapping") flagSet.StringSliceVar(&c.expose, "expose", nil, "Set expose container's ports") + flagSet.BoolVarP(&c.publishAll, "publish-all", "P", false, "Publish all exposed ports to random ports") flagSet.StringVar(&c.pidMode, "pid", "", "PID namespace to use") flagSet.BoolVar(&c.privileged, "privileged", false, "Give extended privileges to the container") diff --git a/cli/container.go b/cli/container.go index b5f9cba0b..2f3a36457 100644 --- a/cli/container.go +++ b/cli/container.go @@ -239,23 +239,24 @@ func (c *container) config() (*types.ContainerCreateConfig, error) { Ulimits: c.ulimit.Value(), PidsLimit: c.pidsLimit, }, - DNS: c.dns, - DNSOptions: c.dnsOptions, - DNSSearch: c.dnsSearch, - EnableLxcfs: c.enableLxcfs, - Privileged: c.privileged, - RestartPolicy: restartPolicy, - IpcMode: c.ipcMode, - PidMode: c.pidMode, - UTSMode: c.utsMode, - GroupAdd: c.groupAdd, - Sysctls: sysctls, - SecurityOpt: c.securityOpt, - NetworkMode: networkMode, - CapAdd: c.capAdd, - CapDrop: c.capDrop, - PortBindings: portBindings, - OomScoreAdj: c.oomScoreAdj, + DNS: c.dns, + DNSOptions: c.dnsOptions, + DNSSearch: c.dnsSearch, + EnableLxcfs: c.enableLxcfs, + Privileged: c.privileged, + RestartPolicy: restartPolicy, + IpcMode: c.ipcMode, + PidMode: c.pidMode, + UTSMode: c.utsMode, + GroupAdd: c.groupAdd, + Sysctls: sysctls, + SecurityOpt: c.securityOpt, + NetworkMode: networkMode, + PublishAllPorts: c.publishAll, + CapAdd: c.capAdd, + CapDrop: c.capDrop, + PortBindings: portBindings, + OomScoreAdj: c.oomScoreAdj, LogConfig: &types.LogConfig{ LogDriver: c.logDriver, LogOpts: logOpts, diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index fdc298202..43cccaef1 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -650,6 +650,15 @@ func (mgr *ContainerManager) prepareContainerNetwork(ctx context.Context, c *Con } } + sb, err := mgr.NetworkMgr.Controller().SandboxByID(c.NetworkSettings.SandboxID) + if err != nil { + // sandbox not found, maybe caused by disconnect network or no endpoint + logrus.Warnf("failed to get sandbox by id(%s), err(%v)", c.NetworkSettings.SandboxID, err) + c.NetworkSettings.Ports = types.PortMap{} + return nil + } + + c.NetworkSettings.Ports = getSandboxPortMapInfo(sb) return nil } @@ -1461,7 +1470,7 @@ func (mgr *ContainerManager) Disconnect(ctx context.Context, containerName, netw c.Unlock() endpoint.EndpointConfig = epConfig if err := mgr.NetworkMgr.EndpointRemove(ctx, endpoint); err != nil { - // TODO(ziren): it is a trick, we should wrapper sanbox + // TODO(ziren): it is a trick, we should wrapper sandbox // not found as an error type if !strings.Contains(err.Error(), "not found") { logrus.Errorf("failed to remove endpoint: %v", err) diff --git a/daemon/mgr/network.go b/daemon/mgr/network.go index 3c40e0166..866611bac 100644 --- a/daemon/mgr/network.go +++ b/daemon/mgr/network.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "path" + "strconv" "strings" apitypes "github.com/alibaba/pouch/apis/types" @@ -662,7 +663,6 @@ func buildSandboxOptions(config network.Config, endpoint *types.Endpoint) ([]lib // TODO: secondary ip address // TODO: parse extra hosts - // TODO: port mapping var bindings = make(nat.PortMap) if endpoint.PortBindings != nil { for p, b := range endpoint.PortBindings { @@ -744,3 +744,66 @@ func joinOptions(endpoint *types.Endpoint) ([]libnetwork.EndpointOption, error) joinOptions = append(joinOptions, libnetwork.JoinOptionPriority(nil, endpoint.Priority)) return joinOptions, nil } + +// getSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox. +func getSandboxPortMapInfo(sb libnetwork.Sandbox) apitypes.PortMap { + pm := apitypes.PortMap{} + if sb == nil { + return pm + } + + for _, ep := range sb.Endpoints() { + pm, _ = getEndpointPortMapInfo(ep) + if len(pm) > 0 { + break + } + } + return pm +} + +func getEndpointPortMapInfo(ep libnetwork.Endpoint) (apitypes.PortMap, error) { + pm := apitypes.PortMap{} + driverInfo, err := ep.DriverInfo() + if err != nil { + return pm, err + } + + if driverInfo == nil { + return pm, nil + } + + // get exposedPorts from driverInfo, which was open by --expose and so on + if expData, ok := driverInfo[netlabel.ExposedPorts]; ok { + if exposedPorts, ok := expData.([]networktypes.TransportPort); ok { + for _, tp := range exposedPorts { + natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) + if err != nil { + return pm, fmt.Errorf("failed to parse Port value(%v):%v", tp.Port, err) + } + pm[string(natPort)] = nil + } + } + } + + mapData, ok := driverInfo[netlabel.PortMap] + if !ok { + return pm, nil + } + + // get the port-mapping from driverInfo, which was open by -p HostPort:port + portMapping, ok := mapData.([]networktypes.PortBinding) + if !ok { + return pm, nil + } + + for _, pp := range portMapping { + natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) + if err != nil { + return pm, err + } + natBndg := apitypes.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))} + pm[string(natPort)] = append(pm[string(natPort)], natBndg) + } + + return pm, nil +} diff --git a/test/cli_inspect_test.go b/test/cli_inspect_test.go index ef2c96487..b102cf200 100644 --- a/test/cli_inspect_test.go +++ b/test/cli_inspect_test.go @@ -205,5 +205,5 @@ func (suite *PouchInspectSuite) TestContainerInspectPorts(c *check.C) { c.Fatal("fail to format container json") } data, _ := json.Marshal(containers[0].NetworkSettings.Ports) - c.Assert(string(data), check.Equals, "{\"80/tcp\":[{\"HostPort\":\"8080\"}]}") + c.Assert(string(data), check.Equals, "{\"80/tcp\":[{\"HostIp\":\"0.0.0.0\",\"HostPort\":\"8080\"}]}") } diff --git a/test/cli_run_network_test.go b/test/cli_run_network_test.go index 1c4ddedff..2dc90a6ae 100644 --- a/test/cli_run_network_test.go +++ b/test/cli_run_network_test.go @@ -1,6 +1,9 @@ package main import ( + "encoding/json" + + "github.com/alibaba/pouch/apis/types" "github.com/alibaba/pouch/test/command" "github.com/alibaba/pouch/test/environment" @@ -33,3 +36,41 @@ func (suite *PouchRunNetworkSuite) TestRunWithPing(c *check.C) { defer DelContainerForceMultyTime(c, name) res.Assert(c, icmd.Success) } + +// TestRunWithPublicAll is to verify run container with publish-all flag +func (suite *PouchRunNetworkSuite) TestRunWithPublishAll(c *check.C) { + name := "TestRunWithPublishAll" + + command.PouchRun("run", "--name", name, "--expose", "8080", "-P", busyboxImage).Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, name) + + output := command.PouchRun("inspect", name).Stdout() + containers := make([]types.ContainerJSON, 1) + err := json.Unmarshal([]byte(output), &containers) + if err != nil || len(containers) == 0 { + c.Fatal("fail to format container json") + } + c.Assert(len(containers[0].NetworkSettings.Ports), check.Equals, 1) + checkPortMapExists(c, containers[0].NetworkSettings.Ports, "8080/tcp") + + // multiple expose port case + name1 := "TestRunMultipleWithPublishAll" + command.PouchRun("run", "--name", name1, "--expose", "8081", "--expose", "8082", "-P", busyboxImage).Assert(c, icmd.Success) + defer DelContainerForceMultyTime(c, name1) + + output = command.PouchRun("inspect", name1).Stdout() + containers = make([]types.ContainerJSON, 1) + err = json.Unmarshal([]byte(output), &containers) + if err != nil || len(containers) == 0 { + c.Fatal("fail to format container json") + } + c.Assert(len(containers[0].NetworkSettings.Ports), check.Equals, 2) + checkPortMapExists(c, containers[0].NetworkSettings.Ports, "8081/tcp") + checkPortMapExists(c, containers[0].NetworkSettings.Ports, "8082/tcp") +} + +func checkPortMapExists(c *check.C, portMap types.PortMap, port string) { + portBs, ok := portMap[port] + c.Assert(ok, check.Equals, true) + c.Assert(len(portBs), check.Equals, 1) +}