|
4 | 4 | "fmt" |
5 | 5 | "log" |
6 | 6 | "net" |
| 7 | + "net/http" |
7 | 8 | "regexp" |
8 | 9 | "strconv" |
9 | 10 | "sync" |
@@ -115,6 +116,24 @@ func (s *Server) publishContainer(container *docker.APIContainers, ttl time.Dura |
115 | 116 | port := strconv.Itoa(int(p.PublicPort)) |
116 | 117 | hostAndPort := s.host + ":" + port |
117 | 118 | if s.IsPublishableApp(containerName) && s.IsPortOpen(hostAndPort) { |
| 119 | + configKey := fmt.Sprintf("/deis/config/%s/", appName) |
| 120 | + // check if the user specified a healthcheck URL |
| 121 | + healthcheckURL := s.getEtcd(configKey + "healthcheck_url") |
| 122 | + delay, err := strconv.Atoi(s.getEtcd(configKey + "healthcheck_initial_delay")) |
| 123 | + if err != nil { |
| 124 | + log.Println(err) |
| 125 | + delay = 0 |
| 126 | + } |
| 127 | + timeout, err := strconv.Atoi(s.getEtcd(configKey + "healthcheck_timeout")) |
| 128 | + if err != nil { |
| 129 | + log.Println(err) |
| 130 | + timeout = 1 |
| 131 | + } |
| 132 | + if healthcheckURL != "" { |
| 133 | + if !s.HealthCheckOK("http://"+hostAndPort+healthcheckURL, delay, timeout) { |
| 134 | + continue |
| 135 | + } |
| 136 | + } |
118 | 137 | s.setEtcd(keyPath, hostAndPort, uint64(ttl.Seconds())) |
119 | 138 | safeMap.Lock() |
120 | 139 | safeMap.data[container.ID] = appPath |
@@ -169,6 +188,23 @@ func (s *Server) IsPortOpen(hostAndPort string) bool { |
169 | 188 | return portOpen |
170 | 189 | } |
171 | 190 |
|
| 191 | +func (s *Server) HealthCheckOK(url string, delay, timeout int) bool { |
| 192 | + // sleep for the initial delay |
| 193 | + time.Sleep(time.Duration(delay) * time.Second) |
| 194 | + client := http.Client{ |
| 195 | + Timeout: time.Duration(timeout) * time.Second, |
| 196 | + } |
| 197 | + resp, err := client.Get(url) |
| 198 | + if err != nil { |
| 199 | + log.Printf("an error occurred while performing a health check at %s (%v)\n", url, err) |
| 200 | + return false |
| 201 | + } |
| 202 | + if resp.StatusCode != http.StatusOK { |
| 203 | + log.Printf("healthcheck failed for %s (expected %d, got %d)\n", url, http.StatusOK, resp.StatusCode) |
| 204 | + } |
| 205 | + return resp.StatusCode == http.StatusOK |
| 206 | +} |
| 207 | + |
172 | 208 | // latestRunningVersion retrieves the highest version of the application published |
173 | 209 | // to etcd. If no app has been published, returns 0. |
174 | 210 | func latestRunningVersion(client *etcd.Client, appName string) int { |
@@ -213,6 +249,21 @@ func max(n []int) int { |
213 | 249 | return val |
214 | 250 | } |
215 | 251 |
|
| 252 | +// getEtcd retrieves the etcd key's value. Returns an empty string if the key was not found. |
| 253 | +func (s *Server) getEtcd(key string) string { |
| 254 | + if s.logLevel == "debug" { |
| 255 | + log.Println("get", key) |
| 256 | + } |
| 257 | + resp, err := s.EtcdClient.Get(key, false, false) |
| 258 | + if err != nil { |
| 259 | + return "" |
| 260 | + } |
| 261 | + if resp != nil && resp.Node != nil { |
| 262 | + return resp.Node.Value |
| 263 | + } |
| 264 | + return "" |
| 265 | +} |
| 266 | + |
216 | 267 | // setEtcd sets the corresponding etcd key with the value and ttl |
217 | 268 | func (s *Server) setEtcd(key, value string, ttl uint64) { |
218 | 269 | if _, err := s.EtcdClient.Set(key, value, ttl); err != nil { |
|
0 commit comments