diff --git a/controllers/nginx/pkg/cmd/controller/main.go b/controllers/nginx/pkg/cmd/controller/main.go index 8086d413f..3b586ec3b 100644 --- a/controllers/nginx/pkg/cmd/controller/main.go +++ b/controllers/nginx/pkg/cmd/controller/main.go @@ -23,6 +23,7 @@ import ( "time" "github.com/golang/glog" + "k8s.io/ingress/core/pkg/ingress/controller" ) @@ -31,29 +32,32 @@ func main() { ngx := newNGINXController() // create a custom Ingress controller using NGINX as backend ic := controller.NewIngressController(ngx) - go handleSigterm(ic) - // start the controller - ic.Start() - // wait - glog.Infof("shutting down Ingress controller...") - for { - glog.Infof("Handled quit, awaiting pod deletion") - time.Sleep(30 * time.Second) - } -} -func handleSigterm(ic *controller.GenericController) { + // start the controller + go ic.Start() + signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGTERM) <-signalChan + glog.Infof("Received SIGTERM, shutting down") - exitCode := 0 if err := ic.Stop(); err != nil { - glog.Infof("Error during shutdown %v", err) - exitCode = 1 + glog.Errorf("unexpected error shutting down the ingress controller: %v", err) } - glog.Infof("Exiting with %v", exitCode) - os.Exit(exitCode) + glog.Infof("stopping nginx gracefully...") + ngx.Stop() + + timer := time.NewTicker(time.Second * 1) + for { + select { + case <-timer.C: + if !isNginxRunning(ngx.ports.Status) { + glog.Infof("nginx stopped...") + glog.Infof("Exiting with code 0") + os.Exit(0) + } + } + } } diff --git a/controllers/nginx/pkg/cmd/controller/nginx.go b/controllers/nginx/pkg/cmd/controller/nginx.go index 44e8e1c3b..95a519f42 100644 --- a/controllers/nginx/pkg/cmd/controller/nginx.go +++ b/controllers/nginx/pkg/cmd/controller/nginx.go @@ -71,7 +71,7 @@ var ( // newNGINXController creates a new NGINX Ingress controller. // If the environment variable NGINX_BINARY exists it will be used // as source for nginx commands -func newNGINXController() ingress.Controller { +func newNGINXController() *NGINXController { ngx := os.Getenv("NGINX_BINARY") if ngx == "" { ngx = binary @@ -88,6 +88,7 @@ func newNGINXController() ingress.Controller { isIPV6Enabled: isIPv6Enabled(), resolver: h, ports: &config.ListenPorts{}, + done: make(chan error), } fcgiListener, err := net.Listen("unix", fastCGISocket) @@ -134,11 +135,13 @@ Error loading new template : %v go n.Start() - return ingress.Controller(n) + return n } // NGINXController ... type NGINXController struct { + done chan error + t *ngx_template.Template configmap *api_v1.ConfigMap @@ -166,15 +169,16 @@ type NGINXController struct { ports *config.ListenPorts backendDefaults defaults.Backend + + isShuttingDown bool } // Start start a new NGINX master process running in foreground. func (n *NGINXController) Start() { glog.Info("starting NGINX process...") - done := make(chan error, 1) cmd := exec.Command(n.binary, "-c", cfgPath) - n.start(cmd, done) + start(cmd, n.done) // if the nginx master process dies the workers continue to process requests, // passing checks but in case of updates in ingress no updates will be @@ -182,7 +186,12 @@ func (n *NGINXController) Start() { // issues because of this behavior. // To avoid this issue we restart nginx in case of errors. for { - err := <-done + err := <-n.done + + if n.isShuttingDown { + break + } + if exitError, ok := err.(*exec.ExitError); ok { waitStatus := exitError.Sys().(syscall.WaitStatus) glog.Warningf(` @@ -195,19 +204,25 @@ NGINX master process died (%v): %v cmd = exec.Command(n.binary, "-c", cfgPath) // we wait until the workers are killed for { - conn, err := net.DialTimeout("tcp", "127.0.0.1:80", 1*time.Second) - if err != nil { + if !isNginxRunning(n.ports.Status) { break } - conn.Close() time.Sleep(1 * time.Second) } // start a new nginx master process - n.start(cmd, done) + start(cmd, n.done) } } -func (n *NGINXController) start(cmd *exec.Cmd, done chan error) { +func (n *NGINXController) Stop() error { + n.isShuttingDown = true + cmd := exec.Command(n.binary, "-c", cfgPath, "-s", "quit") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func start(cmd *exec.Cmd, done chan error) { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Start(); err != nil { @@ -216,8 +231,6 @@ func (n *NGINXController) start(cmd *exec.Cmd, done chan error) { return } - n.cmdArgs = cmd.Args - go func() { done <- cmd.Wait() }() @@ -230,7 +243,7 @@ func (n NGINXController) BackendDefaults() defaults.Backend { // printDiff returns the difference between the running configuration // and the new one -func (n NGINXController) printDiff(data []byte) { +func printDiff(data []byte) { if !glog.V(2) { return } @@ -655,7 +668,7 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { return err } - n.printDiff(content) + printDiff(content) err = ioutil.WriteFile(cfgPath, content, 0644) if err != nil { @@ -716,3 +729,12 @@ func isIPv6Enabled() bool { cmd := exec.Command("test", "-f", "/proc/net/if_inet6") return cmd.Run() == nil } + +func isNginxRunning(port int) bool { + conn, err := net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%v", port), 1*time.Second) + if err != nil { + return false + } + conn.Close() + return true +}