Merge pull request #1155 from mrjana/agent

Add service support
This commit is contained in:
Santhosh Manohar 2016-05-07 11:51:15 -07:00
commit 3ec7568121
8 changed files with 174 additions and 38 deletions

View File

@ -165,7 +165,12 @@ func (ep *endpoint) addToCluster() error {
c := n.getController() c := n.getController()
if !ep.isAnonymous() && ep.Iface().Address() != nil { if !ep.isAnonymous() && ep.Iface().Address() != nil {
if err := c.agent.networkDB.CreateEntry("endpoint_table", n.ID(), ep.ID(), []byte(fmt.Sprintf("%s=%s", ep.Name(), ep.Iface().Address().IP))); err != nil { if err := c.addServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), ep.Iface().Address().IP); err != nil {
return err
}
if err := c.agent.networkDB.CreateEntry("endpoint_table", n.ID(), ep.ID(), []byte(fmt.Sprintf("%s,%s,%s,%s", ep.Name(), ep.svcName,
ep.svcID, ep.Iface().Address().IP))); err != nil {
return err return err
} }
} }
@ -187,6 +192,12 @@ func (ep *endpoint) deleteFromCluster() error {
c := n.getController() c := n.getController()
if !ep.isAnonymous() { if !ep.isAnonymous() {
if ep.Iface().Address() != nil {
if err := c.rmServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), ep.Iface().Address().IP); err != nil {
return err
}
}
if err := c.agent.networkDB.DeleteEntry("endpoint_table", n.ID(), ep.ID()); err != nil { if err := c.agent.networkDB.DeleteEntry("endpoint_table", n.ID(), ep.ID()); err != nil {
return err return err
} }
@ -297,38 +308,43 @@ func (n *network) handleDriverTableEvent(ev events.Event) {
func (c *controller) handleEpTableEvent(ev events.Event) { func (c *controller) handleEpTableEvent(ev events.Event) {
var ( var (
id string nid string
eid string
value string value string
isAdd bool isAdd bool
) )
switch event := ev.(type) { switch event := ev.(type) {
case networkdb.CreateEvent: case networkdb.CreateEvent:
id = event.NetworkID nid = event.NetworkID
eid = event.Key
value = string(event.Value) value = string(event.Value)
isAdd = true isAdd = true
case networkdb.DeleteEvent: case networkdb.DeleteEvent:
id = event.NetworkID nid = event.NetworkID
eid = event.Key
value = string(event.Value) value = string(event.Value)
case networkdb.UpdateEvent: case networkdb.UpdateEvent:
logrus.Errorf("Unexpected update service table event = %#v", event) logrus.Errorf("Unexpected update service table event = %#v", event)
} }
nw, err := c.NetworkByID(id) nw, err := c.NetworkByID(nid)
if err != nil { if err != nil {
logrus.Errorf("Could not find network %s while handling service table event: %v", id, err) logrus.Errorf("Could not find network %s while handling service table event: %v", nid, err)
return return
} }
n := nw.(*network) n := nw.(*network)
pair := strings.Split(value, "=") vals := strings.Split(value, ",")
if len(pair) < 2 { if len(vals) < 4 {
logrus.Errorf("Incorrect service table value = %s", value) logrus.Errorf("Incorrect service table value = %s", value)
return return
} }
name := pair[0] name := vals[0]
ip := net.ParseIP(pair[1]) svcName := vals[1]
svcID := vals[2]
ip := net.ParseIP(vals[3])
if name == "" || ip == nil { if name == "" || ip == nil {
logrus.Errorf("Invalid endpoint name/ip received while handling service table event %s", value) logrus.Errorf("Invalid endpoint name/ip received while handling service table event %s", value)
@ -336,8 +352,18 @@ func (c *controller) handleEpTableEvent(ev events.Event) {
} }
if isAdd { if isAdd {
if err := c.addServiceBinding(svcName, svcID, nid, eid, ip); err != nil {
logrus.Errorf("Failed adding service binding for value %s: %v", value, err)
return
}
n.addSvcRecords(name, ip, nil, true) n.addSvcRecords(name, ip, nil, true)
} else { } else {
if err := c.rmServiceBinding(svcName, svcID, nid, eid, ip); err != nil {
logrus.Errorf("Failed adding service binding for value %s: %v", value, err)
return
}
n.deleteSvcRecords(name, ip, nil, true) n.deleteSvcRecords(name, ip, nil, true)
} }
} }

View File

@ -123,20 +123,21 @@ type SandboxWalker func(sb Sandbox) bool
type sandboxTable map[string]*sandbox type sandboxTable map[string]*sandbox
type controller struct { type controller struct {
id string id string
drvRegistry *drvregistry.DrvRegistry drvRegistry *drvregistry.DrvRegistry
sandboxes sandboxTable sandboxes sandboxTable
cfg *config.Config cfg *config.Config
stores []datastore.DataStore stores []datastore.DataStore
discovery hostdiscovery.HostDiscovery discovery hostdiscovery.HostDiscovery
extKeyListener net.Listener extKeyListener net.Listener
watchCh chan *endpoint watchCh chan *endpoint
unWatchCh chan *endpoint unWatchCh chan *endpoint
svcDb map[string]svcInfo svcRecords map[string]svcInfo
nmap map[string]*netWatch nmap map[string]*netWatch
defOsSbox osl.Sandbox serviceBindings map[string]*service
sboxOnce sync.Once defOsSbox osl.Sandbox
agent *agent sboxOnce sync.Once
agent *agent
sync.Mutex sync.Mutex
} }
@ -148,10 +149,11 @@ type initializer struct {
// New creates a new instance of network controller. // New creates a new instance of network controller.
func New(cfgOptions ...config.Option) (NetworkController, error) { func New(cfgOptions ...config.Option) (NetworkController, error) {
c := &controller{ c := &controller{
id: stringid.GenerateRandomID(), id: stringid.GenerateRandomID(),
cfg: config.ParseConfigOptions(cfgOptions...), cfg: config.ParseConfigOptions(cfgOptions...),
sandboxes: sandboxTable{}, sandboxes: sandboxTable{},
svcDb: make(map[string]svcInfo), svcRecords: make(map[string]svcInfo),
serviceBindings: make(map[string]*service),
} }
if err := c.agentInit(c.cfg.Daemon.Bind); err != nil { if err := c.agentInit(c.cfg.Daemon.Bind); err != nil {

View File

@ -67,6 +67,8 @@ type endpoint struct {
ipamOptions map[string]string ipamOptions map[string]string
aliases map[string]string aliases map[string]string
myAliases []string myAliases []string
svcID string
svcName string
dbIndex uint64 dbIndex uint64
dbExists bool dbExists bool
sync.Mutex sync.Mutex
@ -89,6 +91,9 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
epMap["anonymous"] = ep.anonymous epMap["anonymous"] = ep.anonymous
epMap["disableResolution"] = ep.disableResolution epMap["disableResolution"] = ep.disableResolution
epMap["myAliases"] = ep.myAliases epMap["myAliases"] = ep.myAliases
epMap["svcName"] = ep.svcName
epMap["svcID"] = ep.svcID
return json.Marshal(epMap) return json.Marshal(epMap)
} }
@ -172,6 +177,15 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
if l, ok := epMap["locator"]; ok { if l, ok := epMap["locator"]; ok {
ep.locator = l.(string) ep.locator = l.(string)
} }
if sn, ok := epMap["svcName"]; ok {
ep.svcName = sn.(string)
}
if si, ok := epMap["svcID"]; ok {
ep.svcID = si.(string)
}
ma, _ := json.Marshal(epMap["myAliases"]) ma, _ := json.Marshal(epMap["myAliases"])
var myAliases []string var myAliases []string
json.Unmarshal(ma, &myAliases) json.Unmarshal(ma, &myAliases)
@ -196,6 +210,8 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
dstEp.dbExists = ep.dbExists dstEp.dbExists = ep.dbExists
dstEp.anonymous = ep.anonymous dstEp.anonymous = ep.anonymous
dstEp.disableResolution = ep.disableResolution dstEp.disableResolution = ep.disableResolution
dstEp.svcName = ep.svcName
dstEp.svcID = ep.svcID
if ep.iface != nil { if ep.iface != nil {
dstEp.iface = &endpointInterface{} dstEp.iface = &endpointInterface{}
@ -413,7 +429,9 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
}() }()
// Watch for service records // Watch for service records
n.getController().watchSvcRecord(ep) if !n.getController().cfg.Daemon.IsAgent {
n.getController().watchSvcRecord(ep)
}
address := "" address := ""
if ip := ep.getFirstInterfaceAddress(); ip != nil { if ip := ep.getFirstInterfaceAddress(); ip != nil {
@ -738,7 +756,9 @@ func (ep *endpoint) Delete(force bool) error {
}() }()
// unwatch for service records // unwatch for service records
n.getController().unWatchSvcRecord(ep) if !n.getController().cfg.Daemon.IsAgent {
n.getController().unWatchSvcRecord(ep)
}
if err = ep.deleteEndpoint(force); err != nil && !force { if err = ep.deleteEndpoint(force); err != nil && !force {
return err return err
@ -871,6 +891,14 @@ func CreateOptionAlias(name string, alias string) EndpointOption {
} }
} }
// CreateOptionService function returns an option setter for setting service binding configuration
func CreateOptionService(name, id string) EndpointOption {
return func(ep *endpoint) {
ep.svcName = name
ep.svcID = id
}
}
//CreateOptionMyAlias function returns an option setter for setting endpoint's self alias //CreateOptionMyAlias function returns an option setter for setting endpoint's self alias
func CreateOptionMyAlias(alias string) EndpointOption { func CreateOptionMyAlias(alias string) EndpointOption {
return func(ep *endpoint) { return func(ep *endpoint) {

View File

@ -1002,14 +1002,14 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp
c := n.getController() c := n.getController()
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
sr, ok := c.svcDb[n.ID()] sr, ok := c.svcRecords[n.ID()]
if !ok { if !ok {
sr = svcInfo{ sr = svcInfo{
svcMap: make(map[string][]net.IP), svcMap: make(map[string][]net.IP),
svcIPv6Map: make(map[string][]net.IP), svcIPv6Map: make(map[string][]net.IP),
ipMap: make(map[string]string), ipMap: make(map[string]string),
} }
c.svcDb[n.ID()] = sr c.svcRecords[n.ID()] = sr
} }
if ipMapUpdate { if ipMapUpdate {
@ -1029,7 +1029,7 @@ func (n *network) deleteSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMa
c := n.getController() c := n.getController()
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
sr, ok := c.svcDb[n.ID()] sr, ok := c.svcRecords[n.ID()]
if !ok { if !ok {
return return
} }
@ -1054,7 +1054,7 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record {
defer n.Unlock() defer n.Unlock()
var recs []etchosts.Record var recs []etchosts.Record
sr, _ := n.ctrlr.svcDb[n.id] sr, _ := n.ctrlr.svcRecords[n.id]
for h, ip := range sr.svcMap { for h, ip := range sr.svcMap {
if ep != nil && strings.Split(h, ".")[0] == ep.Name() { if ep != nil && strings.Split(h, ".")[0] == ep.Name() {

View File

@ -405,7 +405,7 @@ func (sb *sandbox) ResolveIP(ip string) string {
for _, ep := range sb.getConnectedEndpoints() { for _, ep := range sb.getConnectedEndpoints() {
n := ep.getNetwork() n := ep.getNetwork()
sr, ok := n.getController().svcDb[n.ID()] sr, ok := n.getController().svcRecords[n.ID()]
if !ok { if !ok {
continue continue
} }
@ -512,7 +512,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
ep.Unlock() ep.Unlock()
} }
sr, ok := n.getController().svcDb[n.ID()] sr, ok := n.getController().svcRecords[n.ID()]
if !ok { if !ok {
continue continue
} }

80
libnetwork/service.go Normal file
View File

@ -0,0 +1,80 @@
package libnetwork
import "net"
type service struct {
name string
id string
backEnds map[string]map[string]net.IP
}
func newService(name string, id string) *service {
return &service{
name: name,
id: id,
backEnds: make(map[string]map[string]net.IP),
}
}
func (c *controller) addServiceBinding(name, sid, nid, eid string, ip net.IP) error {
var s *service
n, err := c.NetworkByID(nid)
if err != nil {
return err
}
c.Lock()
s, ok := c.serviceBindings[sid]
if !ok {
s = newService(name, sid)
}
netBackEnds, ok := s.backEnds[nid]
if !ok {
netBackEnds = make(map[string]net.IP)
s.backEnds[nid] = netBackEnds
}
netBackEnds[eid] = ip
c.serviceBindings[sid] = s
c.Unlock()
n.(*network).addSvcRecords(name, ip, nil, false)
return nil
}
func (c *controller) rmServiceBinding(name, sid, nid, eid string, ip net.IP) error {
n, err := c.NetworkByID(nid)
if err != nil {
return err
}
c.Lock()
s, ok := c.serviceBindings[sid]
if !ok {
c.Unlock()
return nil
}
netBackEnds, ok := s.backEnds[nid]
if !ok {
c.Unlock()
return nil
}
delete(netBackEnds, eid)
if len(netBackEnds) == 0 {
delete(s.backEnds, nid)
}
if len(s.backEnds) == 0 {
delete(c.serviceBindings, sid)
}
c.Unlock()
n.(*network).deleteSvcRecords(name, ip, nil, false)
return err
}

View File

@ -420,7 +420,7 @@ func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoi
// This is the last container going away for the network. Destroy // This is the last container going away for the network. Destroy
// this network's svc db entry // this network's svc db entry
delete(c.svcDb, ep.getNetwork().ID()) delete(c.svcRecords, ep.getNetwork().ID())
delete(nmap, ep.getNetwork().ID()) delete(nmap, ep.getNetwork().ID())
} }

View File

@ -199,7 +199,7 @@ EOF
cat ${tomlfile} cat ${tomlfile}
docker run \ docker run \
-d \ -d \
--hostname=${name} \ --hostname=$(echo ${name} | sed s/_/-/g) \
--name=${name} \ --name=${name} \
--privileged \ --privileged \
-p ${hport}:${cport} \ -p ${hport}:${cport} \