teleport/lib/service/supervisor.go

514 lines
13 KiB
Go
Raw Normal View History

2015-10-31 18:56:49 +00:00
/*
Copyright 2015 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
2016-03-29 23:33:11 +00:00
package service
import (
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
"context"
"fmt"
"sync"
External events and sessions storage. Updates #1755 Design ------ This commit adds support for pluggable events and sessions recordings and adds several plugins. In case if external sessions recording storage is used, nodes or proxies depending on configuration store the session recordings locally and then upload the recordings in the background. Non-print session events are always sent to the remote auth server as usual. In case if remote events storage is used, auth servers download recordings from it during playbacks. DynamoDB event backend ---------------------- Transient DynamoDB backend is added for events storage. Events are stored with default TTL of 1 year. External lambda functions should be used to forward events from DynamoDB. Parameter audit_table_name in storage section turns on dynamodb backend. The table will be auto created. S3 sessions backend ------------------- If audit_sessions_uri is specified to s3://bucket-name node or proxy depending on recording mode will start uploading the recorded sessions to the bucket. If the bucket does not exist, teleport will attempt to create a bucket with versioning and encryption turned on by default. Teleport will turn on bucket-side encryption for the tarballs using aws:kms key. File sessions backend --------------------- If audit_sessions_uri is specified to file:///folder teleport will start writing tarballs to this folder instead of sending records to the file server. This is helpful for plugin writers who can use fuse or NFS mounted storage to handle the data. Working dynamic configuration.
2018-03-04 02:26:44 +00:00
"github.com/gravitational/teleport"
2016-01-20 15:52:25 +00:00
"github.com/gravitational/trace"
"github.com/sirupsen/logrus"
)
// Supervisor implements the simple service logic - registering
// service functions and de-registering the service goroutines
type Supervisor interface {
// Register adds the service to the pool, if supervisor is in
// the started state, the service will be started immediately
// otherwise, it will be started after Start() has been called
Register(srv Service)
// RegisterFunc creates a service from function spec and registers
// it within the system
RegisterFunc(name string, fn Func)
// RegisterCriticalFunc creates a critical service from function spec and registers
// it within the system, if this service exits with error,
// the process shuts down.
RegisterCriticalFunc(name string, fn Func)
// ServiceCount returns the number of registered and actively running
// services
ServiceCount() int
// Start starts all unstarted services
Start() error
// Wait waits until all services exit
Wait() error
// Run starts and waits for the service to complete
// it's a combinatioin Start() and Wait()
Run() error
2016-03-29 23:33:11 +00:00
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
// Services returns list of running services
Services() []string
2016-03-29 23:33:11 +00:00
// BroadcastEvent generates event and broadcasts it to all
// subscribed parties.
2016-03-29 23:33:11 +00:00
BroadcastEvent(Event)
// WaitForEvent waits for event to be broadcasted, if the event
// was already broadcasted, eventC will receive current event immediately.
WaitForEvent(ctx context.Context, name string, eventC chan Event)
// RegisterEventMapping registers event mapping -
// when the sequence in the event mapping triggers, the
// outbound event will be generated.
RegisterEventMapping(EventMapping)
// ExitContext returns context that will be closed when
2021-09-20 17:35:51 +00:00
// a hard TeleportExitEvent is broadcasted.
ExitContext() context.Context
2021-09-20 17:35:51 +00:00
// GracefulExitContext returns context that will be closed when
// a graceful or hard TeleportExitEvent is broadcast.
GracefulExitContext() context.Context
// ReloadContext returns context that will be closed when
// TeleportReloadEvent is broadcasted.
ReloadContext() context.Context
}
// EventMapping maps a sequence of incoming
// events and if triggered, generates an out event.
type EventMapping struct {
// In is the incoming event sequence.
In []string
// Out is the outbound event to generate.
Out string
}
// String returns user-friendly representation of the mapping.
func (e EventMapping) String() string {
return fmt.Sprintf("EventMapping(in=%v, out=%v)", e.In, e.Out)
}
func (e EventMapping) matches(currentEvent string, m map[string]Event) bool {
// existing events that have been fired should match
for _, in := range e.In {
if _, ok := m[in]; !ok {
return false
}
}
// current event that is firing should match one of the expected events
for _, in := range e.In {
if currentEvent == in {
return true
}
}
return false
}
// LocalSupervisor is a Teleport's implementation of the Supervisor interface.
type LocalSupervisor struct {
state int
sync.Mutex
2016-03-29 23:33:11 +00:00
wg *sync.WaitGroup
services []Service
2016-03-29 23:33:11 +00:00
events map[string]Event
eventsC chan Event
eventWaiters map[string][]*waiter
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
closeContext context.Context
signalClose context.CancelFunc
2021-09-20 17:35:51 +00:00
// exitContext is closed when someone emits a hard Exit event
exitContext context.Context
signalExit context.CancelFunc
2021-09-20 17:35:51 +00:00
// gracefulExitContext is closed when someone emits a graceful or hard Exit event
gracefulExitContext context.Context
signalGracefulExit context.CancelFunc
reloadContext context.Context
signalReload context.CancelFunc
eventMappings []EventMapping
id string
// log specifies the logger
log logrus.FieldLogger
}
// NewSupervisor returns new instance of initialized supervisor
func NewSupervisor(id string, parentLog logrus.FieldLogger) Supervisor {
2021-09-20 17:35:51 +00:00
ctx := context.TODO()
closeContext, cancel := context.WithCancel(ctx)
exitContext, signalExit := context.WithCancel(ctx)
2021-09-20 17:35:51 +00:00
// graceful exit context is a subcontext of exit context since any work that terminates
// in the event of graceful exit must also terminate in the event of an immediate exit.
gracefulExitContext, signalGracefulExit := context.WithCancel(exitContext)
reloadContext, signalReload := context.WithCancel(ctx)
srv := &LocalSupervisor{
state: stateCreated,
id: id,
services: []Service{},
wg: &sync.WaitGroup{},
events: map[string]Event{},
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
eventsC: make(chan Event, 1024),
eventWaiters: make(map[string][]*waiter),
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
closeContext: closeContext,
signalClose: cancel,
2021-09-20 17:35:51 +00:00
exitContext: exitContext,
signalExit: signalExit,
gracefulExitContext: gracefulExitContext,
signalGracefulExit: signalGracefulExit,
reloadContext: reloadContext,
signalReload: signalReload,
log: parentLog.WithField(trace.Component, teleport.Component(teleport.ComponentProcess, id)),
}
go srv.fanOut()
return srv
2016-03-29 23:33:11 +00:00
}
// Event is a special service event that can be generated
// by various goroutines in the supervisor
type Event struct {
Name string
Payload interface{}
}
func (e *Event) String() string {
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
return e.Name
}
func (s *LocalSupervisor) Register(srv Service) {
s.log.WithField("service", srv.Name()).Debug("Adding service to supervisor.")
s.Lock()
defer s.Unlock()
s.services = append(s.services, srv)
if s.state == stateStarted {
s.serve(srv)
}
}
// ServiceCount returns the number of registered and actively running services
func (s *LocalSupervisor) ServiceCount() int {
s.Lock()
defer s.Unlock()
return len(s.services)
}
// RegisterFunc creates a service from function spec and registers
// it within the system
func (s *LocalSupervisor) RegisterFunc(name string, fn Func) {
s.Register(&LocalService{Function: fn, ServiceName: name})
}
// RegisterCriticalFunc creates a critical service from function spec and registers
// it within the system, if this service exits with error,
// the process shuts down.
func (s *LocalSupervisor) RegisterCriticalFunc(name string, fn Func) {
s.Register(&LocalService{Function: fn, ServiceName: name, Critical: true})
}
// RemoveService removes service from supervisor tracking list
func (s *LocalSupervisor) RemoveService(srv Service) error {
l := s.log.WithField("service", srv.Name())
s.Lock()
defer s.Unlock()
for i, el := range s.services {
if el == srv {
s.services = append(s.services[:i], s.services[i+1:]...)
l.Debug("Service is completed and removed.")
return nil
}
}
l.Warning("Service is completed but not found.")
return trace.NotFound("service %v is not found", srv)
}
// ExitEventPayload contains information about service
// name, and service error if it exited with error
type ExitEventPayload struct {
// Service is the service that exited
Service Service
// Error is the error of the service exit
Error error
}
func (s *LocalSupervisor) serve(srv Service) {
s.wg.Add(1)
go func() {
defer s.wg.Done()
defer s.RemoveService(srv)
l := s.log.WithField("service", srv.Name())
l.Debug("Service has started.")
err := srv.Serve()
2016-02-07 21:33:33 +00:00
if err != nil {
if err == ErrTeleportExited {
l.Info("Teleport process has shut down.")
} else {
l.WithError(err).Warning("Teleport process has exited with error.")
s.BroadcastEvent(Event{
Name: ServiceExitedWithErrorEvent,
Payload: ExitEventPayload{Service: srv, Error: err},
})
}
2016-02-07 21:33:33 +00:00
}
}()
}
func (s *LocalSupervisor) Start() error {
s.Lock()
defer s.Unlock()
s.state = stateStarted
if len(s.services) == 0 {
s.log.Warning("Supervisor has no services to run. Exiting.")
return nil
}
for _, srv := range s.services {
s.serve(srv)
}
return nil
}
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
func (s *LocalSupervisor) Services() []string {
s.Lock()
defer s.Unlock()
out := make([]string, len(s.services))
for i, srv := range s.services {
out[i] = srv.Name()
}
return out
}
func (s *LocalSupervisor) Wait() error {
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
defer s.signalClose()
s.wg.Wait()
return nil
}
func (s *LocalSupervisor) Run() error {
if err := s.Start(); err != nil {
return trace.Wrap(err)
}
return s.Wait()
}
// ExitContext returns context that will be closed when
2021-09-20 17:35:51 +00:00
// a hard TeleportExitEvent is broadcasted.
func (s *LocalSupervisor) ExitContext() context.Context {
return s.exitContext
}
2021-09-20 17:35:51 +00:00
// GracefulExitContext returns context that will be closed when
// a hard or graceful TeleportExitEvent is broadcasted.
func (s *LocalSupervisor) GracefulExitContext() context.Context {
return s.gracefulExitContext
}
// ReloadContext returns context that will be closed when
// TeleportReloadEvent is broadcasted.
func (s *LocalSupervisor) ReloadContext() context.Context {
return s.reloadContext
}
// BroadcastEvent generates event and broadcasts it to all
// subscribed parties.
2016-03-29 23:33:11 +00:00
func (s *LocalSupervisor) BroadcastEvent(event Event) {
s.Lock()
defer s.Unlock()
switch event.Name {
case TeleportExitEvent:
2021-09-20 17:35:51 +00:00
// if exit event includes a context payload, it is a "graceful" exit, and
// we need to hold off closing the supervisor's exit context until after
// the graceful context has closed. If not, it is an immediate exit.
if ctx, ok := event.Payload.(context.Context); ok {
s.signalGracefulExit()
go func() {
select {
case <-s.exitContext.Done():
case <-ctx.Done():
s.signalExit()
}
}()
} else {
s.signalExit()
}
case TeleportReloadEvent:
s.signalReload()
}
2016-03-29 23:33:11 +00:00
s.events[event.Name] = event
2018-10-26 22:20:02 +00:00
// Log all events other than recovered events to prevent the logs from
// being flooded.
if event.String() != TeleportOKEvent {
s.log.WithField("event", event.String()).Debug("Broadcasting event.")
2018-10-26 22:20:02 +00:00
}
2016-03-29 23:33:11 +00:00
go func() {
select {
case s.eventsC <- event:
case <-s.closeContext.Done():
return
}
2016-03-29 23:33:11 +00:00
}()
for _, m := range s.eventMappings {
if m.matches(event.Name, s.events) {
mappedEvent := Event{Name: m.Out}
s.events[mappedEvent.Name] = mappedEvent
go func(e Event) {
select {
case s.eventsC <- e:
case <-s.closeContext.Done():
return
}
}(mappedEvent)
s.log.WithFields(logrus.Fields{
"in": event.String(),
"out": m.String(),
}).Debug("Broadcasting mapped event.")
}
}
}
// RegisterEventMapping registers event mapping -
// when the sequence in the event mapping triggers, the
// outbound event will be generated.
func (s *LocalSupervisor) RegisterEventMapping(m EventMapping) {
s.Lock()
defer s.Unlock()
s.eventMappings = append(s.eventMappings, m)
2016-03-29 23:33:11 +00:00
}
// WaitForEvent waits for event to be broadcasted, if the event
// was already broadcasted, eventC will receive current event immediately.
func (s *LocalSupervisor) WaitForEvent(ctx context.Context, name string, eventC chan Event) {
2016-03-29 23:33:11 +00:00
s.Lock()
defer s.Unlock()
waiter := &waiter{eventC: eventC, context: ctx}
2016-03-29 23:33:11 +00:00
event, ok := s.events[name]
if ok {
go s.notifyWaiter(waiter, event)
return
}
s.eventWaiters[name] = append(s.eventWaiters[name], waiter)
}
func (s *LocalSupervisor) getWaiters(name string) []*waiter {
s.Lock()
defer s.Unlock()
waiters := s.eventWaiters[name]
out := make([]*waiter, len(waiters))
Fix remaining gosimple findings List of fixed items: ``` integration/helpers.go:1279:2 gosimple S1000: should use for range instead of for { select {} } integration/integration_test.go:144:5 gosimple S1009: should omit nil check; len() for nil slices is defined as zero integration/integration_test.go:173:5 gosimple S1009: should omit nil check; len() for nil slices is defined as zero integration/integration_test.go:296:28 gosimple S1019: should use make(chan error) instead integration/integration_test.go:570:41 gosimple S1019: should use make(chan interface{}) instead integration/integration_test.go:685:40 gosimple S1019: should use make(chan interface{}) instead integration/integration_test.go:759:33 gosimple S1019: should use make(chan string) instead lib/auth/init_test.go:62:2 gosimple S1021: should merge variable declaration with assignment on next line lib/auth/tls_test.go:1658:22 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/backend/dynamo/dynamodbbk.go:420:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/dynamo/dynamodbbk.go:656:12 gosimple S1039: unnecessary use of fmt.Sprintf lib/backend/etcdbk/etcd.go:458:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/firestore/firestorebk.go:407:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/lite/lite.go:317:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/lite/lite.go:336:6 gosimple S1004: should use !bytes.Equal(value, expected.Value) instead lib/backend/memory/memory.go:365:5 gosimple S1004: should use !bytes.Equal(expected.Key, replaceWith.Key) instead lib/backend/memory/memory.go:376:5 gosimple S1004: should use !bytes.Equal(existingItem.Value, expected.Value) instead lib/backend/test/suite.go:327:10 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/client/api.go:1410:9 gosimple S1003: should use strings.ContainsRune(name, ':') instead lib/client/api.go:2355:32 gosimple S1019: should use make([]ForwardedPort, len(spec)) instead lib/client/keyagent_test.go:85:2 gosimple S1021: should merge variable declaration with assignment on next line lib/client/player.go:54:33 gosimple S1019: should use make(chan int) instead lib/config/configuration.go:1024:52 gosimple S1019: should use make(services.CommandLabels) instead lib/config/configuration.go:1025:44 gosimple S1019: should use make(map[string]string) instead lib/config/configuration.go:930:21 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleNode) instead lib/config/configuration.go:931:22 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleAuthService) instead lib/config/configuration.go:932:23 gosimple S1003: should use strings.Contains(clf.Roles, defaults.RoleProxy) instead lib/service/supervisor.go:387:2 gosimple S1001: should use copy() instead of a loop lib/tlsca/parsegen.go:140:9 gosimple S1034: assigning the result of this type assertion to a variable (switch generalKey := generalKey.(type)) could eliminate type assertions in switch cases lib/utils/certs.go:140:9 gosimple S1034: assigning the result of this type assertion to a variable (switch generalKey := generalKey.(type)) could eliminate type assertions in switch cases lib/utils/certs.go:167:40 gosimple S1010: should omit second index in slice, s[a:len(s)] is identical to s[a:] lib/utils/certs.go:204:5 gosimple S1004: should use !bytes.Equal(certificateChain[0].SubjectKeyId, certificateChain[0].AuthorityKeyId) instead lib/utils/parse/parse.go:116:45 gosimple S1003: should use strings.Contains(variable, "}}") instead lib/utils/parse/parse.go:116:6 gosimple S1003: should use strings.Contains(variable, "{{") instead lib/utils/socks/socks.go:192:10 gosimple S1025: should use String() instead of fmt.Sprintf lib/utils/socks/socks.go:199:10 gosimple S1025: should use String() instead of fmt.Sprintf lib/web/apiserver.go:1054:18 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) lib/web/apiserver.go:1954:9 gosimple S1039: unnecessary use of fmt.Sprintf tool/tsh/tsh.go:1193:14 gosimple S1024: should use time.Until instead of t.Sub(time.Now()) ```
2020-05-20 18:38:32 +00:00
copy(out, waiters)
2016-03-29 23:33:11 +00:00
return out
}
func (s *LocalSupervisor) notifyWaiter(w *waiter, event Event) {
select {
case w.eventC <- event:
case <-w.context.Done():
2016-03-29 23:33:11 +00:00
}
}
func (s *LocalSupervisor) fanOut() {
for {
select {
case event := <-s.eventsC:
waiters := s.getWaiters(event.Name)
for _, waiter := range waiters {
go s.notifyWaiter(waiter, event)
}
Teleport signal handling and live reload. This commit introduces signal handling. Parent teleport process is now capable of forking the child process and passing listeners file descriptors to the child. Parent process then can gracefully shutdown by tracking the amount of current connections and closing listeners once the amount goes to 0. Here are the signals handled: * USR2 signal will cause the parent to fork a child process and pass listener file descriptors to it. Child process will close unused file descriptors and will bind to the used ones. At this moment two processes - the parent and the forked child process will be serving requests. After looking at the traffic and the log files, administrator can either shut down the parent process or the child process if the child process is not functioning as expected. * TERM, INT signals will trigger graceful process shutdown. Auth, node and proxy processes will wait until the amount of active connections goes down to 0 and will exit after that. * KILL, QUIT signals will cause immediate non-graceful shutdown. * HUP signal combines USR2 and TERM signals in a convenient way: parent process will fork a child process and self-initate graceful shutdown. This is a more convenient than USR2/TERM sequence, but less agile and robust as if the connection to the parent process drops, but the new process exits with error, administrators can lock themselves out of the environment. Additionally, boltdb backend has to be phased out, as it does not support read/writes by two concurrent processes. This had required refactoring of the dir backend to use file locking to allow inter-process collaboration on read/write operations.
2018-02-08 02:32:50 +00:00
case <-s.closeContext.Done():
return
2016-03-29 23:33:11 +00:00
}
}
}
type waiter struct {
eventC chan Event
context context.Context
}
// Service is a running teleport service function
type Service interface {
// Serve starts the function
Serve() error
// String returns user-friendly description of service
String() string
// Name returns service name
Name() string
// IsCritical returns true if the service is critical
// and program can't continue without it
IsCritical() bool
}
// LocalService is a locally defined service
type LocalService struct {
// Function is a function to call
Function Func
// ServiceName is a service name
ServiceName string
// Critical is set to true
// when the service is critical and program can't continue
// without it
Critical bool
}
// IsCritical returns true if the service is critical
// and program can't continue without it
func (l *LocalService) IsCritical() bool {
return l.Critical
}
// Serve starts the function
func (l *LocalService) Serve() error {
return l.Function()
}
// String returns user-friendly service name
func (l *LocalService) String() string {
return l.ServiceName
}
// Name returns unique service name
func (l *LocalService) Name() string {
return l.ServiceName
}
// Func is a service function
type Func func() error
const (
stateCreated = iota
stateStarted
)