github.com/noironetworks/cilium-net@v1.6.12/cilium-health/launch/launcher.go (about)

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