Browse Source

Global alias support

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal 9 years ago
parent
commit
2db863e5d7

+ 8 - 0
libnetwork/api/api.go

@@ -379,6 +379,10 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string,
 		setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping))
 	}
 
+	for _, str := range ec.MyAliases {
+		setFctList = append(setFctList, libnetwork.CreateOptionMyAlias(str))
+	}
+
 	ep, err := n.CreateEndpoint(ec.Name, setFctList...)
 	if err != nil {
 		return "", convertNetworkError(err)
@@ -624,6 +628,10 @@ func procPublishService(c libnetwork.NetworkController, vars map[string]string,
 		setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(sp.PortMapping))
 	}
 
+	for _, str := range sp.MyAliases {
+		setFctList = append(setFctList, libnetwork.CreateOptionMyAlias(str))
+	}
+
 	ep, err := n.CreateEndpoint(sp.Name, setFctList...)
 	if err != nil {
 		return "", endpointToService(convertNetworkError(err))

+ 2 - 0
libnetwork/api/types.go

@@ -43,6 +43,7 @@ type networkCreate struct {
 // endpointCreate represents the body of the "create endpoint" http request message
 type endpointCreate struct {
 	Name         string                `json:"name"`
+	MyAliases    []string              `json:"my_aliases"`
 	ExposedPorts []types.TransportPort `json:"exposed_ports"`
 	PortMapping  []types.PortBinding   `json:"port_mapping"`
 }
@@ -69,6 +70,7 @@ type endpointJoin struct {
 // servicePublish represents the body of the "publish service" http request message
 type servicePublish struct {
 	Name         string                `json:"name"`
+	MyAliases    []string              `json:"my_aliases"`
 	Network      string                `json:"network_name"`
 	ExposedPorts []types.TransportPort `json:"exposed_ports"`
 	PortMapping  []types.PortBinding   `json:"port_mapping"`

+ 3 - 1
libnetwork/client/service.go

@@ -163,6 +163,8 @@ func parseServiceName(name string) (string, string) {
 // CmdServicePublish handles service create UI
 func (cli *NetworkCli) CmdServicePublish(chain string, args ...string) error {
 	cmd := cli.Subcmd(chain, "publish", "SERVICE[.NETWORK]", "Publish a new service on a network", false)
+	flAlias := opts.NewListOpts(netutils.ValidateAlias)
+	cmd.Var(&flAlias, []string{"-alias"}, "Add alias to self")
 	cmd.Require(flag.Exact, 1)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
@@ -170,7 +172,7 @@ func (cli *NetworkCli) CmdServicePublish(chain string, args ...string) error {
 	}
 
 	sn, nn := parseServiceName(cmd.Arg(0))
-	sc := serviceCreate{Name: sn, Network: nn}
+	sc := serviceCreate{Name: sn, Network: nn, MyAliases: flAlias.GetAll()}
 	obj, _, err := readBody(cli.call("POST", "/services", sc, nil))
 	if err != nil {
 		return err

+ 1 - 0
libnetwork/client/types.go

@@ -43,6 +43,7 @@ type networkCreate struct {
 // serviceCreate represents the body of the "publish service" http request message
 type serviceCreate struct {
 	Name         string                `json:"name"`
+	MyAliases    []string              `json:"my_aliases"`
 	Network      string                `json:"network_name"`
 	ExposedPorts []types.TransportPort `json:"exposed_ports"`
 	PortMapping  []types.PortBinding   `json:"port_mapping"`

+ 23 - 0
libnetwork/endpoint.go

@@ -65,6 +65,7 @@ type endpoint struct {
 	prefAddressV6     net.IP
 	ipamOptions       map[string]string
 	aliases           map[string]string
+	myAliases         []string
 	dbIndex           uint64
 	dbExists          bool
 	sync.Mutex
@@ -85,6 +86,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
 	epMap["sandbox"] = ep.sandboxID
 	epMap["anonymous"] = ep.anonymous
 	epMap["disableResolution"] = ep.disableResolution
+	epMap["myAliases"] = ep.myAliases
 	return json.Marshal(epMap)
 }
 
@@ -165,6 +167,10 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 	if v, ok := epMap["disableResolution"]; ok {
 		ep.disableResolution = v.(bool)
 	}
+	ma, _ := json.Marshal(epMap["myAliases"])
+	var myAliases []string
+	json.Unmarshal(ma, &myAliases)
+	ep.myAliases = myAliases
 	return nil
 }
 
@@ -193,6 +199,9 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
 	dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts))
 	copy(dstEp.exposedPorts, ep.exposedPorts)
 
+	dstEp.myAliases = make([]string, len(ep.myAliases))
+	copy(dstEp.myAliases, ep.myAliases)
+
 	dstEp.generic = options.Generic{}
 	for k, v := range ep.generic {
 		dstEp.generic[k] = v
@@ -215,6 +224,13 @@ func (ep *endpoint) Name() string {
 	return ep.name
 }
 
+func (ep *endpoint) MyAliases() []string {
+	ep.Lock()
+	defer ep.Unlock()
+
+	return ep.myAliases
+}
+
 func (ep *endpoint) Network() string {
 	if ep.network == nil {
 		return ""
@@ -759,6 +775,13 @@ func CreateOptionAlias(name string, alias string) EndpointOption {
 	}
 }
 
+//CreateOptionMyAlias function returns an option setter for setting endpoint's self alias
+func CreateOptionMyAlias(alias string) EndpointOption {
+	return func(ep *endpoint) {
+		ep.myAliases = append(ep.myAliases, alias)
+	}
+}
+
 // JoinOptionPriority function returns an option setter for priority option to
 // be passed to the endpoint.Join() method.
 func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {

+ 62 - 21
libnetwork/network.go

@@ -70,7 +70,7 @@ type NetworkInfo interface {
 type EndpointWalker func(ep Endpoint) bool
 
 type svcInfo struct {
-	svcMap map[string]net.IP
+	svcMap map[string][]net.IP
 	ipMap  map[string]string
 }
 
@@ -831,36 +831,77 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
 		return
 	}
 
+	epName := ep.Name()
+	if iface := ep.Iface(); iface.Address() != nil {
+		myAliases := ep.MyAliases()
+		if isAdd {
+			n.addSvcRecords(epName, iface.Address().IP, true)
+			for _, alias := range myAliases {
+				n.addSvcRecords(alias, iface.Address().IP, false)
+			}
+		} else {
+			n.deleteSvcRecords(epName, iface.Address().IP, true)
+			for _, alias := range myAliases {
+				n.deleteSvcRecords(alias, iface.Address().IP, false)
+			}
+		}
+	}
+}
+
+func (n *network) addSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
 	c := n.getController()
+	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcDb[n.ID()]
 	if !ok {
-		c.svcDb[n.ID()] = svcInfo{
-			svcMap: make(map[string]net.IP),
+		sr = svcInfo{
+			svcMap: make(map[string][]net.IP),
 			ipMap:  make(map[string]string),
 		}
-		sr = c.svcDb[n.ID()]
+		c.svcDb[n.ID()] = sr
 	}
 
-	epName := ep.Name()
-	n.Lock()
-	if iface := ep.Iface(); iface.Address() != nil {
+	if ipMapUpdate {
+		reverseIP := netutils.ReverseIP(epIP.String())
+		if _, ok := sr.ipMap[reverseIP]; !ok {
+			sr.ipMap[reverseIP] = name
+		}
+	}
 
-		reverseIP := netutils.ReverseIP(iface.Address().IP.String())
-		if isAdd {
-			// If we already have this endpoint in service db just return
-			if _, ok := sr.svcMap[epName]; ok {
-				n.Unlock()
-				return
-			}
+	ipList := sr.svcMap[name]
+	for _, ip := range ipList {
+		if ip.Equal(epIP) {
+			return
+		}
+	}
+	sr.svcMap[name] = append(sr.svcMap[name], epIP)
+}
 
-			sr.svcMap[epName] = iface.Address().IP
-			sr.ipMap[reverseIP] = epName
-		} else {
-			delete(sr.svcMap, epName)
-			delete(sr.ipMap, reverseIP)
+func (n *network) deleteSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
+	c := n.getController()
+	c.Lock()
+	defer c.Unlock()
+	sr, ok := c.svcDb[n.ID()]
+	if !ok {
+		return
+	}
+
+	if ipMapUpdate {
+		delete(sr.ipMap, netutils.ReverseIP(epIP.String()))
+	}
+
+	ipList := sr.svcMap[name]
+	for i, ip := range ipList {
+		if ip.Equal(epIP) {
+			ipList = append(ipList[:i], ipList[i+1:]...)
+			break
 		}
 	}
-	n.Unlock()
+	sr.svcMap[name] = ipList
+
+	if len(ipList) == 0 {
+		delete(sr.svcMap, name)
+	}
 }
 
 func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record {
@@ -877,7 +918,7 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record {
 
 		recs = append(recs, etchosts.Record{
 			Hosts: h,
-			IP:    ip.String(),
+			IP:    ip[0].String(),
 		})
 	}
 

+ 1 - 1
libnetwork/sandbox.go

@@ -481,7 +481,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
 		ip, ok := sr.svcMap[name]
 		n.Unlock()
 		if ok {
-			return ip
+			return ip[0]
 		}
 	}
 	return nil

+ 30 - 0
libnetwork/test/integration/dnet/bridge.bats

@@ -249,3 +249,33 @@ function test_single_network_connectivity() {
     dnet_cmd $(inst_id2port 1) container rm container_2
     dnet_cmd $(inst_id2port 1) network rm br1
 }
+
+@test "Test bridge network global alias support" {
+    skip_for_circleci
+    dnet_cmd $(inst_id2port 1) network create -d bridge br1
+    dnet_cmd $(inst_id2port 1) network create -d bridge br2
+    dnet_cmd $(inst_id2port 1) container create container_1
+    net_connect 1 container_1 br1 : c1
+    dnet_cmd $(inst_id2port 1) container create container_2
+    net_connect 1 container_2 br1 : shared
+    dnet_cmd $(inst_id2port 1) container create container_3
+    net_connect 1 container_3 br1 : shared
+
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_2) "ping -c 1 container_1"
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_2) "ping -c 1 c1"
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 container_2"
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 shared"
+
+    net_disconnect 1 container_2 br1
+    dnet_cmd $(inst_id2port 1) container rm container_2
+
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 container_3"
+    runc $(dnet_container_name 1 bridge) $(get_sbox_id 1 container_1) "ping -c 1 shared"
+
+    net_disconnect 1 container_1 br1
+    dnet_cmd $(inst_id2port 1) container rm container_1
+    net_disconnect 1 container_3 br1
+    dnet_cmd $(inst_id2port 1) container rm container_3
+
+    dnet_cmd $(inst_id2port 1) network rm br1
+}

+ 9 - 4
libnetwork/test/integration/dnet/helpers.bash

@@ -18,12 +18,17 @@ function get_sbox_id() {
 }
 
 function net_connect() {
-        local al
+        local al gl
         if [ -n "$4" ]; then
-            al="--alias=${4}"
+            if [ "${4}" != ":" ]; then
+                al="--alias=${4}"
+            fi
         fi
-	dnet_cmd $(inst_id2port ${1}) service publish ${2}.${3}
-	dnet_cmd $(inst_id2port ${1}) service attach $al ${2} ${2}.${3}
+        if [ -n "$5" ]; then
+            gl="--alias=${5}"
+        fi
+        dnet_cmd $(inst_id2port ${1}) service publish $gl ${2}.${3}
+        dnet_cmd $(inst_id2port ${1}) service attach $al ${2} ${2}.${3}
 }
 
 function net_disconnect() {