11package server
22
33import (
4- "errors"
54 "fmt"
65 "log"
76 "net"
87 "os"
98 "regexp"
109 "strconv"
10+ "sync"
1111 "time"
1212
1313 "github.com/coreos/go-etcd/etcd"
@@ -25,6 +25,11 @@ type Server struct {
2525 EtcdClient * etcd.Client
2626}
2727
28+ var safeMap = struct {
29+ sync.RWMutex
30+ data map [string ]string
31+ }{data : make (map [string ]string )}
32+
2833// Listen adds an event listener to the docker client and publishes containers that were started.
2934func (s * Server ) Listen (ttl time.Duration ) {
3035 listener := make (chan * docker.APIEvents )
@@ -44,6 +49,8 @@ func (s *Server) Listen(ttl time.Duration) {
4449 continue
4550 }
4651 s .publishContainer (container , ttl )
52+ } else if event .Status == "stop" {
53+ s .removeContainer (event .ID )
4754 }
4855 }
4956 }
@@ -73,7 +80,7 @@ func (s *Server) getContainer(id string) (*docker.APIContainers, error) {
7380 return & container , nil
7481 }
7582 }
76- return nil , errors . New ("could not find container" )
83+ return nil , fmt . Errorf ("could not find container with id %v" , id )
7784}
7885
7986// publishContainer publishes the docker container to etcd.
@@ -89,19 +96,36 @@ func (s *Server) publishContainer(container *docker.APIContainers, ttl time.Dura
8996 continue
9097 }
9198 appName := match [1 ]
92- keyPath := fmt .Sprintf ("/deis/services/%s/%s" , appName , containerName )
99+ appPath := fmt .Sprintf ("%s/%s" , appName , containerName )
100+ keyPath := fmt .Sprintf ("/deis/services/%s" , appPath )
93101 for _ , p := range container .Ports {
94102 port := strconv .Itoa (int (p .PublicPort ))
95103 hostAndPort := host + ":" + port
96104 if s .IsPublishableApp (containerName ) && s .IsPortOpen (hostAndPort ) {
97105 s .setEtcd (keyPath , hostAndPort , uint64 (ttl .Seconds ()))
106+ safeMap .Lock ()
107+ safeMap .data [container .ID ] = appPath
108+ safeMap .Unlock ()
98109 }
99110 // TODO: support multiple exposed ports
100111 break
101112 }
102113 }
103114}
104115
116+ // removeContainer remove a container published by this component
117+ func (s * Server ) removeContainer (event string ) {
118+ safeMap .RLock ()
119+ appPath := safeMap .data [event ]
120+ safeMap .RUnlock ()
121+
122+ if appPath != "" {
123+ keyPath := fmt .Sprintf ("/deis/services/%s" , appPath )
124+ log .Printf ("stopped %s\n " , keyPath )
125+ s .removeEtcd (keyPath , false )
126+ }
127+ }
128+
105129// IsPublishableApp determines if the application should be published to etcd.
106130func (s * Server ) IsPublishableApp (name string ) bool {
107131 r := regexp .MustCompile (appNameRegex )
@@ -183,3 +207,11 @@ func (s *Server) setEtcd(key, value string, ttl uint64) {
183207 }
184208 log .Println ("set" , key , "->" , value )
185209}
210+
211+ // removeEtcd removes the corresponding etcd key
212+ func (s * Server ) removeEtcd (key string , recursive bool ) {
213+ if _ , err := s .EtcdClient .Delete (key , recursive ); err != nil {
214+ log .Println (err )
215+ }
216+ log .Println ("del" , key )
217+ }
0 commit comments