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()
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
}
}
@ -187,6 +192,12 @@ func (ep *endpoint) deleteFromCluster() error {
c := n.getController()
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 {
return err
}
@ -297,38 +308,43 @@ func (n *network) handleDriverTableEvent(ev events.Event) {
func (c *controller) handleEpTableEvent(ev events.Event) {
var (
id string
nid string
eid string
value string
isAdd bool
)
switch event := ev.(type) {
case networkdb.CreateEvent:
id = event.NetworkID
nid = event.NetworkID
eid = event.Key
value = string(event.Value)
isAdd = true
case networkdb.DeleteEvent:
id = event.NetworkID
nid = event.NetworkID
eid = event.Key
value = string(event.Value)
case networkdb.UpdateEvent:
logrus.Errorf("Unexpected update service table event = %#v", event)
}
nw, err := c.NetworkByID(id)
nw, err := c.NetworkByID(nid)
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
}
n := nw.(*network)
pair := strings.Split(value, "=")
if len(pair) < 2 {
vals := strings.Split(value, ",")
if len(vals) < 4 {
logrus.Errorf("Incorrect service table value = %s", value)
return
}
name := pair[0]
ip := net.ParseIP(pair[1])
name := vals[0]
svcName := vals[1]
svcID := vals[2]
ip := net.ParseIP(vals[3])
if name == "" || ip == nil {
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 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)
} 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)
}
}

View File

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

View File

@ -67,6 +67,8 @@ type endpoint struct {
ipamOptions map[string]string
aliases map[string]string
myAliases []string
svcID string
svcName string
dbIndex uint64
dbExists bool
sync.Mutex
@ -89,6 +91,9 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
epMap["anonymous"] = ep.anonymous
epMap["disableResolution"] = ep.disableResolution
epMap["myAliases"] = ep.myAliases
epMap["svcName"] = ep.svcName
epMap["svcID"] = ep.svcID
return json.Marshal(epMap)
}
@ -172,6 +177,15 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
if l, ok := epMap["locator"]; ok {
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"])
var myAliases []string
json.Unmarshal(ma, &myAliases)
@ -196,6 +210,8 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
dstEp.dbExists = ep.dbExists
dstEp.anonymous = ep.anonymous
dstEp.disableResolution = ep.disableResolution
dstEp.svcName = ep.svcName
dstEp.svcID = ep.svcID
if ep.iface != nil {
dstEp.iface = &endpointInterface{}
@ -413,7 +429,9 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
}()
// Watch for service records
n.getController().watchSvcRecord(ep)
if !n.getController().cfg.Daemon.IsAgent {
n.getController().watchSvcRecord(ep)
}
address := ""
if ip := ep.getFirstInterfaceAddress(); ip != nil {
@ -738,7 +756,9 @@ func (ep *endpoint) Delete(force bool) error {
}()
// 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 {
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
func CreateOptionMyAlias(alias string) EndpointOption {
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.Lock()
defer c.Unlock()
sr, ok := c.svcDb[n.ID()]
sr, ok := c.svcRecords[n.ID()]
if !ok {
sr = svcInfo{
svcMap: make(map[string][]net.IP),
svcIPv6Map: make(map[string][]net.IP),
ipMap: make(map[string]string),
}
c.svcDb[n.ID()] = sr
c.svcRecords[n.ID()] = sr
}
if ipMapUpdate {
@ -1029,7 +1029,7 @@ func (n *network) deleteSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMa
c := n.getController()
c.Lock()
defer c.Unlock()
sr, ok := c.svcDb[n.ID()]
sr, ok := c.svcRecords[n.ID()]
if !ok {
return
}
@ -1054,7 +1054,7 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record {
defer n.Unlock()
var recs []etchosts.Record
sr, _ := n.ctrlr.svcDb[n.id]
sr, _ := n.ctrlr.svcRecords[n.id]
for h, ip := range sr.svcMap {
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() {
n := ep.getNetwork()
sr, ok := n.getController().svcDb[n.ID()]
sr, ok := n.getController().svcRecords[n.ID()]
if !ok {
continue
}
@ -512,7 +512,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
ep.Unlock()
}
sr, ok := n.getController().svcDb[n.ID()]
sr, ok := n.getController().svcRecords[n.ID()]
if !ok {
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 network's svc db entry
delete(c.svcDb, ep.getNetwork().ID())
delete(c.svcRecords, ep.getNetwork().ID())
delete(nmap, ep.getNetwork().ID())
}

View File

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