diff --git a/cmd/notary-server/config.go b/cmd/notary-server/config.go index 91eb6c0c6..daff08550 100644 --- a/cmd/notary-server/config.go +++ b/cmd/notary-server/config.go @@ -3,12 +3,9 @@ package main import ( "crypto/tls" "fmt" - "os" - "os/signal" "path" "strconv" "strings" - "syscall" "time" "github.com/Sirupsen/logrus" @@ -293,31 +290,3 @@ func parseServerConfig(configFilePath string, hRegister healthRegister, doBootst ConsistentCacheControlConfig: consistentCache, }, nil } - -func setupSignalTrap() { - c := make(chan os.Signal, 1) - signal.Notify(c, notary.NotarySupportedSignals...) - go func() { - for { - signalHandle(<-c) - } - }() -} - -// signalHandle will increase/decrease the logging level via the signal we get. -func signalHandle(sig os.Signal) { - switch sig { - case syscall.SIGUSR1: - if err := utils.AdjustLogLevel(true); err != nil { - fmt.Printf("Attempt to increase log level failed, will remain at %s level, error: %s\n", logrus.GetLevel(), err) - return - } - case syscall.SIGUSR2: - if err := utils.AdjustLogLevel(false); err != nil { - fmt.Printf("Attempt to decrease log level failed, will remain at %s level, error: %s\n", logrus.GetLevel(), err) - return - } - } - - fmt.Println("Successfully setting log level to ", logrus.GetLevel()) -} diff --git a/cmd/notary-server/main.go b/cmd/notary-server/main.go index c2cdf56e7..232e486c7 100644 --- a/cmd/notary-server/main.go +++ b/cmd/notary-server/main.go @@ -7,10 +7,12 @@ import ( "net/http" _ "net/http/pprof" "os" + "os/signal" "github.com/Sirupsen/logrus" "github.com/docker/distribution/health" "github.com/docker/notary/server" + "github.com/docker/notary/utils" "github.com/docker/notary/version" ) @@ -61,7 +63,10 @@ func main() { logrus.Fatal(err.Error()) } - setupSignalTrap() + c := utils.SetupSignalTrap(utils.LogLevelSignalHandle) + if c != nil { + defer signal.Stop(c) + } if flagStorage.doBootstrap { err = bootstrap(ctx) diff --git a/cmd/notary-server/main_test.go b/cmd/notary-server/main_test.go index 14fbd69bc..4bcc0c3fb 100644 --- a/cmd/notary-server/main_test.go +++ b/cmd/notary-server/main_test.go @@ -6,14 +6,11 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" "reflect" "strings" - "syscall" "testing" "time" - "github.com/Sirupsen/logrus" "github.com/docker/distribution/health" "github.com/docker/notary" "github.com/docker/notary/server/storage" @@ -416,30 +413,3 @@ func TestSampleConfig(t *testing.T) { // once for the DB, once for the trust service require.Equal(t, registerCalled, 2) } - -func TestSignalHandle(t *testing.T) { - tempdir, err := ioutil.TempDir("", "test-signal-handle") - require.NoError(t, err) - defer os.RemoveAll(tempdir) - f, err := os.Create(filepath.Join(tempdir, "testSignalHandle.json")) - require.NoError(t, err) - - f.WriteString(`{"logging": {"level": "info"}}`) - - v := viper.New() - utils.SetupViper(v, "envPrefix") - err = utils.ParseViper(v, f.Name()) - require.NoError(t, err) - - // Info + SIGUSR1 -> Debug - signalHandle(syscall.SIGUSR1) - require.Equal(t, logrus.GetLevel(), logrus.DebugLevel) - - // Debug + SIGUSR1 -> Debug - signalHandle(syscall.SIGUSR1) - require.Equal(t, logrus.GetLevel(), logrus.DebugLevel) - - // Debug + SIGUSR2-> Info - signalHandle(syscall.SIGUSR2) - require.Equal(t, logrus.GetLevel(), logrus.InfoLevel) -} diff --git a/cmd/notary-signer/main.go b/cmd/notary-signer/main.go index d15f124ae..d7459fc62 100644 --- a/cmd/notary-signer/main.go +++ b/cmd/notary-signer/main.go @@ -6,8 +6,10 @@ import ( "log" "net/http" "os" + "os/signal" "github.com/Sirupsen/logrus" + "github.com/docker/notary/utils" "github.com/docker/notary/version" _ "github.com/go-sql-driver/mysql" ) @@ -66,6 +68,11 @@ func main() { log.Println("RPC server listening on", signerConfig.GRPCAddr) } + c := utils.SetupSignalTrap(utils.LogLevelSignalHandle) + if c != nil { + defer signal.Stop(c) + } + grpcServer.Serve(lis) } diff --git a/const.go b/const.go index 19752072b..0c4d4037b 100644 --- a/const.go +++ b/const.go @@ -1,10 +1,6 @@ package notary -import ( - "os" - "syscall" - "time" -) +import "time" // application wide constants const ( @@ -72,11 +68,3 @@ var NotaryDefaultExpiries = map[string]time.Duration{ "snapshot": NotarySnapshotExpiry, "timestamp": NotaryTimestampExpiry, } - -// NotarySupportedSignals contains the signals we would like to capture: -// - SIGUSR1, indicates a increment of the log level. -// - SIGUSR2, indicates a decrement of the log level. -var NotarySupportedSignals = []os.Signal{ - syscall.SIGUSR1, - syscall.SIGUSR2, -} diff --git a/const_nowindows.go b/const_nowindows.go new file mode 100644 index 000000000..67551717a --- /dev/null +++ b/const_nowindows.go @@ -0,0 +1,16 @@ +// +build !windows + +package notary + +import ( + "os" + "syscall" +) + +// NotarySupportedSignals contains the signals we would like to capture: +// - SIGUSR1, indicates a increment of the log level. +// - SIGUSR2, indicates a decrement of the log level. +var NotarySupportedSignals = []os.Signal{ + syscall.SIGUSR1, + syscall.SIGUSR2, +} diff --git a/const_windows.go b/const_windows.go new file mode 100644 index 000000000..e2dff0e4b --- /dev/null +++ b/const_windows.go @@ -0,0 +1,8 @@ +// +build windows + +package notary + +import "os" + +// NotarySupportedSignals does not contain any signals, because SIGUSR1/2 are not supported on windows +var NotarySupportedSignals = []os.Signal{} diff --git a/docs/reference/server-config.md b/docs/reference/server-config.md index 2143bbe5f..d1cab23b9 100644 --- a/docs/reference/server-config.md +++ b/docs/reference/server-config.md @@ -362,10 +362,12 @@ Example: ## Hot logging level reload -We don't support completely reloading notary configuration files yet at present. What we support for now is: +We don't support completely reloading notary configuration files yet at present. What we support for Linux and OSX now is: - increase logging level by signaling `SIGUSR1` - decrease logging level by signaling `SIGUSR2` +No signals and no dynamic logging level changes are supported for Windows yet. + Example: To increase logging level diff --git a/docs/reference/signer-config.md b/docs/reference/signer-config.md index 7ced28e17..f5c35e0ae 100644 --- a/docs/reference/signer-config.md +++ b/docs/reference/signer-config.md @@ -210,6 +210,44 @@ The environment variables for the older passwords are optional, but Notary Signer will not be able to decrypt older keys if they are not provided, and attempts to sign data using those keys will fail. +## Hot logging level reload +We don't support completely reloading notary signer configuration files yet at present. What we support for Linux and OSX now is: +- increase logging level by signaling `SIGUSR1` +- decrease logging level by signaling `SIGUSR2` + +No signals and no dynamic logging level changes are supported for Windows yet. + +Example: + +To increase logging level +``` +$ kill -s SIGUSR1 PID + +or + +$ docker exec -i CONTAINER_ID kill -s SIGUSR1 PID +``` + +To decrease logging level +``` +$ kill -s SIGUSR2 PID + +or + +$ docker exec -i CONTAINER_ID kill -s SIGUSR2 PID +``` +PID is the process id of `notary-signer` and it may not the PID 1 process if you are running +the container with some kind of wrapper startup script or something. + +You can get the PID of `notary-signer` through +``` +$ docker exec CONTAINER_ID ps aux + +or + +$ ps aux | grep "notary-signer -config" | grep -v "grep" +``` + ## Related information diff --git a/utils/configuration.go b/utils/configuration.go index f94b73a27..cc97810da 100644 --- a/utils/configuration.go +++ b/utils/configuration.go @@ -5,6 +5,8 @@ package utils import ( "crypto/tls" "fmt" + "os" + "os/signal" "path/filepath" "strings" @@ -244,3 +246,20 @@ func AdjustLogLevel(increment bool) error { logrus.SetLevel(lvl) return nil } + +// SetupSignalTrap is a utility to trap supported signals hand handle them (currently by increasing logging) +func SetupSignalTrap(handler func(os.Signal)) chan os.Signal { + if len(notary.NotarySupportedSignals) == 0 { + return nil + + } + c := make(chan os.Signal, 1) + signal.Notify(c, notary.NotarySupportedSignals...) + go func() { + for { + handler(<-c) + } + }() + + return c +} diff --git a/utils/configuration_nowindows.go b/utils/configuration_nowindows.go new file mode 100644 index 000000000..22c7528dd --- /dev/null +++ b/utils/configuration_nowindows.go @@ -0,0 +1,29 @@ +// +build !windows + +package utils + +import ( + "fmt" + "os" + "syscall" + + "github.com/Sirupsen/logrus" +) + +// LogLevelSignalHandle will increase/decrease the logging level via the signal we get. +func LogLevelSignalHandle(sig os.Signal) { + switch sig { + case syscall.SIGUSR1: + if err := AdjustLogLevel(true); err != nil { + fmt.Printf("Attempt to increase log level failed, will remain at %s level, error: %s\n", logrus.GetLevel(), err) + return + } + case syscall.SIGUSR2: + if err := AdjustLogLevel(false); err != nil { + fmt.Printf("Attempt to decrease log level failed, will remain at %s level, error: %s\n", logrus.GetLevel(), err) + return + } + } + + fmt.Println("Successfully setting log level to ", logrus.GetLevel()) +} diff --git a/utils/configuration_nowindows_test.go b/utils/configuration_nowindows_test.go new file mode 100644 index 000000000..d414af8fc --- /dev/null +++ b/utils/configuration_nowindows_test.go @@ -0,0 +1,33 @@ +// +build !windows + +package utils + +import ( + "io/ioutil" + "os" + "syscall" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/stretchr/testify/require" +) + +func TestLogLevelSignalHandle(t *testing.T) { + tempdir, err := ioutil.TempDir("", "test-signal-handle") + require.NoError(t, err) + defer os.RemoveAll(tempdir) + + logrus.SetLevel(logrus.InfoLevel) + + // Info + SIGUSR1 -> Debug + LogLevelSignalHandle(syscall.SIGUSR1) + require.Equal(t, logrus.GetLevel(), logrus.DebugLevel) + + // Debug + SIGUSR1 -> Debug + LogLevelSignalHandle(syscall.SIGUSR1) + require.Equal(t, logrus.GetLevel(), logrus.DebugLevel) + + // Debug + SIGUSR2-> Info + LogLevelSignalHandle(syscall.SIGUSR2) + require.Equal(t, logrus.GetLevel(), logrus.InfoLevel) +} diff --git a/utils/configuration_test.go b/utils/configuration_test.go index bf0c5f71a..7dbaf859d 100644 --- a/utils/configuration_test.go +++ b/utils/configuration_test.go @@ -6,8 +6,10 @@ import ( "fmt" "io/ioutil" "os" + "os/signal" "path/filepath" "reflect" + "syscall" "testing" "github.com/Sirupsen/logrus" @@ -560,3 +562,28 @@ func TestAdjustLogLevel(t *testing.T) { err = AdjustLogLevel(optDecrement) require.Error(t, err) } + +func TestSetSignalTrap(t *testing.T) { + var signalsPassedOn map[string]struct{} + + signalHandler := func(s os.Signal) { + signalsPassedOn := make(map[string]struct{}) + signalsPassedOn[s.String()] = struct{}{} + } + c := SetupSignalTrap(signalHandler) + + if len(notary.NotarySupportedSignals) == 0 { // currently, windows only + require.Nil(t, c) + } else { + require.NotNil(t, c) + defer signal.Stop(c) + } + + for _, s := range notary.NotarySupportedSignals { + syscallSignal, ok := s.(syscall.Signal) + require.True(t, ok) + require.NoError(t, syscall.Kill(syscall.Getpid(), syscallSignal)) + require.Len(t, signalsPassedOn, 0) + require.NotNil(t, signalsPassedOn[s.String()]) + } +} diff --git a/utils/configuration_windows.go b/utils/configuration_windows.go new file mode 100644 index 000000000..bb43c7e3b --- /dev/null +++ b/utils/configuration_windows.go @@ -0,0 +1,9 @@ +// +build windows + +package utils + +import "os" + +// LogLevelSignalHandle will do nothing, because we aren't currently supporting signal handling in windows +func LogLevelSignalHandle(sig os.Signal) { +}