github.com/cilium/cilium@v1.16.2/cilium-health/launch/launcher.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package launch 5 6 import ( 7 "errors" 8 "fmt" 9 "net/http" 10 "os" 11 12 healthApi "github.com/cilium/cilium/api/v1/health/server" 13 "github.com/cilium/cilium/api/v1/models" 14 "github.com/cilium/cilium/pkg/api" 15 ciliumPkg "github.com/cilium/cilium/pkg/client" 16 "github.com/cilium/cilium/pkg/health/client" 17 "github.com/cilium/cilium/pkg/health/defaults" 18 "github.com/cilium/cilium/pkg/health/server" 19 "github.com/cilium/cilium/pkg/lock" 20 "github.com/cilium/cilium/pkg/logging" 21 "github.com/cilium/cilium/pkg/logging/logfields" 22 "github.com/cilium/cilium/pkg/option" 23 "github.com/cilium/cilium/pkg/time" 24 ) 25 26 // CiliumHealth launches and polls the cilium-health daemon 27 type CiliumHealth struct { 28 mutex lock.RWMutex 29 server *server.Server 30 client *client.Client 31 status *models.Status 32 } 33 34 var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "cilium-health-launcher") 35 36 const ( 37 serverProbeInterval = 60 * time.Second 38 serverProbeDeadline = 1 * time.Second 39 connectRetryInterval = 1 * time.Second 40 statusProbeInterval = 5 * time.Second 41 ) 42 43 // Launch starts the cilium-health server and returns a handle to obtain its status 44 func Launch(spec *healthApi.Spec, initialized <-chan struct{}) (*CiliumHealth, error) { 45 var ( 46 err error 47 ch = &CiliumHealth{} 48 ) 49 50 config := server.Config{ 51 Debug: option.Config.Opts.IsEnabled(option.Debug), 52 ProbeInterval: serverProbeInterval, 53 ProbeDeadline: serverProbeDeadline, 54 HTTPPathPort: option.Config.ClusterHealthPort, 55 HealthAPISpec: spec, 56 } 57 58 ch.server, err = server.NewServer(config) 59 if err != nil { 60 return nil, fmt.Errorf("failed to instantiate cilium-health server: %w", err) 61 } 62 63 ch.client, err = client.NewDefaultClient() 64 if err != nil { 65 return nil, fmt.Errorf("failed to instantiate cilium-health client: %w", err) 66 } 67 68 go ch.runServer(initialized) 69 70 return ch, nil 71 } 72 73 func (ch *CiliumHealth) runServer(initialized <-chan struct{}) { 74 // Wait until the agent has initialized sufficiently 75 <-initialized 76 77 // Wait until Cilium API is available 78 for { 79 cli, err := ciliumPkg.NewDefaultClient() 80 if err == nil { 81 // Making sure that we can talk with the daemon. 82 if _, err = cli.Daemon.GetHealthz(nil); err == nil { 83 break 84 } 85 } 86 log.WithError(err).Debugf("Cannot establish connection to local cilium instance") 87 time.Sleep(connectRetryInterval) 88 } 89 90 // Launch cilium-health API server 91 os.Remove(defaults.SockPath) 92 go func() { 93 defer ch.server.Shutdown() 94 if err := ch.server.Serve(); err != nil && !errors.Is(err, http.ErrServerClosed) { 95 log.WithError(err).Error("Failed to serve cilium-health API") 96 } 97 }() 98 99 // When the unix socket is made available, set its permissions. 100 scopedLog := log.WithField(logfields.Path, defaults.SockPath) 101 for { 102 _, err := os.Stat(defaults.SockPath) 103 if err == nil { 104 break 105 } 106 scopedLog.WithError(err).Debugf("Cannot find socket") 107 time.Sleep(1 * time.Second) 108 } 109 if err := api.SetDefaultPermissions(defaults.SockPath); err != nil { 110 scopedLog.WithError(err).Fatal("Cannot set default permissions on socket") 111 } 112 113 // Periodically fetch status from cilium-health server 114 for { 115 status := &models.Status{ 116 State: models.StatusStateOk, 117 } 118 119 _, err := ch.client.Restapi.GetHealthz(nil) 120 if err != nil { 121 status.Msg = err.Error() 122 status.State = models.StatusStateWarning 123 } 124 125 ch.setStatus(status) 126 time.Sleep(statusProbeInterval) 127 } 128 } 129 130 // GetStatus returns the status of the cilium-health daemon. 131 func (ch *CiliumHealth) GetStatus() *models.Status { 132 ch.mutex.RLock() 133 status := ch.status 134 ch.mutex.RUnlock() 135 return status 136 } 137 138 // setStatus updates the status of the cilium-health daemon. 139 func (ch *CiliumHealth) setStatus(status *models.Status) { 140 ch.mutex.Lock() 141 ch.status = status 142 ch.mutex.Unlock() 143 }