util.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package services
  14. import (
  15. "fmt"
  16. "k8s.io/klog"
  17. "net/http"
  18. "os"
  19. "os/signal"
  20. "syscall"
  21. "time"
  22. )
  23. // terminationSignals are signals that cause the program to exit in the
  24. // supported platforms (linux, darwin, windows).
  25. var terminationSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT}
  26. // waitForTerminationSignal waits for termination signal.
  27. func waitForTerminationSignal() {
  28. sig := make(chan os.Signal, 1)
  29. signal.Notify(sig, terminationSignals...)
  30. <-sig
  31. }
  32. // readinessCheck checks whether services are ready via the supplied health
  33. // check URLs. Once there is an error in errCh, the function will stop waiting
  34. // and return the error.
  35. func readinessCheck(name string, urls []string, errCh <-chan error) error {
  36. klog.Infof("Running readiness check for service %q", name)
  37. endTime := time.Now().Add(*serverStartTimeout)
  38. blockCh := make(chan error)
  39. defer close(blockCh)
  40. for endTime.After(time.Now()) {
  41. select {
  42. // We *always* want to run the health check if there is no error on the channel.
  43. // With systemd, reads from errCh report nil because cmd.Run() waits
  44. // on systemd-run, rather than the service process. systemd-run quickly
  45. // exits with status 0, causing the channel to be closed with no error. In
  46. // this case, you want to wait for the health check to complete, rather
  47. // than returning from readinessCheck as soon as the channel is closed.
  48. case err, ok := <-errCh:
  49. if ok { // The channel is not closed, this is a real error
  50. if err != nil { // If there is an error, return it
  51. return err
  52. }
  53. // If not, keep checking readiness.
  54. } else { // The channel is closed, this is only a zero value.
  55. // Replace the errCh with blockCh to avoid busy loop,
  56. // and keep checking readiness.
  57. errCh = blockCh
  58. }
  59. case <-time.After(time.Second):
  60. ready := true
  61. for _, url := range urls {
  62. resp, err := http.Head(url)
  63. if err != nil || resp.StatusCode != http.StatusOK {
  64. ready = false
  65. break
  66. }
  67. }
  68. if ready {
  69. return nil
  70. }
  71. }
  72. }
  73. return fmt.Errorf("e2e service %q readiness check timeout %v", name, *serverStartTimeout)
  74. }