This is the right way to call for a clean shutdown
Return application/json as content-type when appropriate
Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
| ... | ... |
@@ -1306,19 +1306,19 @@ func (c *controller) Stop() {
|
| 1306 | 1306 |
// StartDiagnose start the network diagnose mode |
| 1307 | 1307 |
func (c *controller) StartDiagnose(port int) {
|
| 1308 | 1308 |
c.Lock() |
| 1309 |
- defer c.Unlock() |
|
| 1310 | 1309 |
if !c.DiagnoseServer.IsDebugEnable() {
|
| 1311 | 1310 |
c.DiagnoseServer.EnableDebug("127.0.0.1", port)
|
| 1312 | 1311 |
} |
| 1312 |
+ c.Unlock() |
|
| 1313 | 1313 |
} |
| 1314 | 1314 |
|
| 1315 | 1315 |
// StopDiagnose start the network diagnose mode |
| 1316 | 1316 |
func (c *controller) StopDiagnose() {
|
| 1317 | 1317 |
c.Lock() |
| 1318 |
- defer c.Unlock() |
|
| 1319 | 1318 |
if c.DiagnoseServer.IsDebugEnable() {
|
| 1320 | 1319 |
c.DiagnoseServer.DisableDebug() |
| 1321 | 1320 |
} |
| 1321 |
+ c.Unlock() |
|
| 1322 | 1322 |
} |
| 1323 | 1323 |
|
| 1324 | 1324 |
// IsDiagnoseEnabled returns true if the diagnose is enabled |
| ... | ... |
@@ -1,12 +1,12 @@ |
| 1 | 1 |
package diagnose |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "context" |
|
| 4 | 5 |
"encoding/json" |
| 5 | 6 |
"fmt" |
| 6 |
- "log" |
|
| 7 |
- "net" |
|
| 8 | 7 |
"net/http" |
| 9 | 8 |
"sync" |
| 9 |
+ "sync/atomic" |
|
| 10 | 10 |
|
| 11 | 11 |
stackdump "github.com/docker/docker/pkg/signal" |
| 12 | 12 |
"github.com/docker/libnetwork/common" |
| ... | ... |
@@ -36,7 +36,8 @@ var diagPaths2Func = map[string]HTTPHandlerFunc{
|
| 36 | 36 |
// Server when the debug is enabled exposes a |
| 37 | 37 |
// This data structure is protected by the Agent mutex so does not require and additional mutex here |
| 38 | 38 |
type Server struct {
|
| 39 |
- sk net.Listener |
|
| 39 |
+ enable int32 |
|
| 40 |
+ srv *http.Server |
|
| 40 | 41 |
port int |
| 41 | 42 |
mux *http.ServeMux |
| 42 | 43 |
registeredHanders map[string]bool |
| ... | ... |
@@ -71,6 +72,10 @@ func (n *Server) RegisterHandler(ctx interface{}, hdlrs map[string]HTTPHandlerFu
|
| 71 | 71 |
} |
| 72 | 72 |
} |
| 73 | 73 |
|
| 74 |
+func (n *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
| 75 |
+ n.mux.ServeHTTP(w, r) |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 74 | 78 |
// EnableDebug opens a TCP socket to debug the passed network DB |
| 75 | 79 |
func (n *Server) EnableDebug(ip string, port int) {
|
| 76 | 80 |
n.Lock() |
| ... | ... |
@@ -78,37 +83,41 @@ func (n *Server) EnableDebug(ip string, port int) {
|
| 78 | 78 |
|
| 79 | 79 |
n.port = port |
| 80 | 80 |
|
| 81 |
- if n.sk != nil {
|
|
| 81 |
+ if n.enable == 1 {
|
|
| 82 | 82 |
logrus.Info("The server is already up and running")
|
| 83 | 83 |
return |
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 |
- logrus.Infof("Starting the server listening on %d for commands", port)
|
|
| 87 |
- // Create the socket |
|
| 88 |
- var err error |
|
| 89 |
- n.sk, err = net.Listen("tcp", fmt.Sprintf("%s:%d", ip, port))
|
|
| 90 |
- if err != nil {
|
|
| 91 |
- log.Fatal(err) |
|
| 92 |
- } |
|
| 86 |
+ logrus.Infof("Starting the diagnose server listening on %d for commands", port)
|
|
| 87 |
+ srv := &http.Server{Addr: fmt.Sprintf("127.0.0.1:%d", port), Handler: n}
|
|
| 88 |
+ n.srv = srv |
|
| 89 |
+ n.enable = 1 |
|
| 90 |
+ go func(n *Server) {
|
|
| 91 |
+ // Ingore ErrServerClosed that is returned on the Shutdown call |
|
| 92 |
+ if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
| 93 |
+ logrus.Errorf("ListenAndServe error: %s", err)
|
|
| 94 |
+ atomic.SwapInt32(&n.enable, 0) |
|
| 95 |
+ } |
|
| 96 |
+ }(n) |
|
| 93 | 97 |
|
| 94 |
- go func() {
|
|
| 95 |
- http.Serve(n.sk, n.mux) |
|
| 96 |
- }() |
|
| 97 | 98 |
} |
| 98 | 99 |
|
| 99 | 100 |
// DisableDebug stop the dubug and closes the tcp socket |
| 100 | 101 |
func (n *Server) DisableDebug() {
|
| 101 | 102 |
n.Lock() |
| 102 | 103 |
defer n.Unlock() |
| 103 |
- n.sk.Close() |
|
| 104 |
- n.sk = nil |
|
| 104 |
+ |
|
| 105 |
+ n.srv.Shutdown(context.Background()) |
|
| 106 |
+ n.srv = nil |
|
| 107 |
+ n.enable = 0 |
|
| 108 |
+ logrus.Info("Disabling the diagnose server")
|
|
| 105 | 109 |
} |
| 106 | 110 |
|
| 107 | 111 |
// IsDebugEnable returns true when the debug is enabled |
| 108 | 112 |
func (n *Server) IsDebugEnable() bool {
|
| 109 | 113 |
n.Lock() |
| 110 | 114 |
defer n.Unlock() |
| 111 |
- return n.sk != nil |
|
| 115 |
+ return n.enable == 1 |
|
| 112 | 116 |
} |
| 113 | 117 |
|
| 114 | 118 |
func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) {
|
| ... | ... |
@@ -197,6 +206,7 @@ func ParseHTTPFormOptions(r *http.Request) (bool, *JSONOutput) {
|
| 197 | 197 |
func HTTPReply(w http.ResponseWriter, r *HTTPResult, j *JSONOutput) (int, error) {
|
| 198 | 198 |
var response []byte |
| 199 | 199 |
if j.enable {
|
| 200 |
+ w.Header().Set("Content-Type", "application/json")
|
|
| 200 | 201 |
var err error |
| 201 | 202 |
if j.prettyPrint {
|
| 202 | 203 |
response, err = json.MarshalIndent(r, "", " ") |