diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index a9b9ab658..16079f0d2 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -21,10 +21,13 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" + "os/signal" "reflect" "sort" "strings" "sync" + "syscall" "time" "github.com/heptio/ark/pkg/buildinfo" @@ -221,6 +224,9 @@ func newServer(namespace, baseName, pluginDir string, logger *logrus.Logger) (*s } func (s *server) run() error { + defer s.pluginManager.CleanupClients() + s.handleShutdownSignals() + if err := s.ensureArkNamespace(); err != nil { return err } @@ -364,6 +370,17 @@ func (s *server) watchConfig(config *api.Config) { }) } +func (s *server) handleShutdownSignals() { + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + go func() { + sig := <-sigs + s.logger.Infof("Received signal %s, gracefully shutting down", sig) + s.cancelFunc() + }() +} + func (s *server) initBackupService(config *api.Config) error { s.logger.Info("Configuring cloud provider for backup service") objectStore, err := getObjectStore(config.BackupStorageProvider.CloudProviderConfig, s.pluginManager) diff --git a/pkg/controller/backup_controller_test.go b/pkg/controller/backup_controller_test.go index fbab58ce9..3956a8911 100644 --- a/pkg/controller/backup_controller_test.go +++ b/pkg/controller/backup_controller_test.go @@ -415,3 +415,9 @@ func (_m *MockManager) GetObjectStore(name string) (cloudprovider.ObjectStore, e return r0, r1 } + +// CleanupClients provides a mock function +func (_m *MockManager) CleanupClients() { + _ = _m.Called() + return +} diff --git a/pkg/plugin/manager.go b/pkg/plugin/manager.go index 3136bb9ed..334579f35 100644 --- a/pkg/plugin/manager.go +++ b/pkg/plugin/manager.go @@ -44,6 +44,7 @@ func baseConfig() *plugin.ClientConfig { return &plugin.ClientConfig{ HandshakeConfig: Handshake, AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, + Managed: true, } } @@ -123,6 +124,9 @@ type Manager interface { // CloseRestoreItemActions terminates the plugin sub-processes that // are hosting RestoreItemAction plugins for the given restore name. CloseRestoreItemActions(restoreName string) error + + // CleanupClients kills all plugin subprocesses. + CleanupClients() } type manager struct { @@ -411,3 +415,7 @@ func closeAll(store *clientStore, kind PluginKind, scope string) error { return nil } + +func (m *manager) CleanupClients() { + plugin.CleanupClients() +}