Configuration - Control over command timeouts
This commit is contained in:
parent
dad5a17d36
commit
44eb5c5356
3 changed files with 61 additions and 14 deletions
30
config.go
30
config.go
|
@ -61,9 +61,12 @@ type (
|
||||||
|
|
||||||
// Handlers. Each handler has a name and contains a list of commands.
|
// Handlers. Each handler has a name and contains a list of commands.
|
||||||
tHandlers map[string][]string
|
tHandlers map[string][]string
|
||||||
|
// Handler timeouts.
|
||||||
|
tHandlerTimeouts map[string]int
|
||||||
|
|
||||||
// Certificate file updates configuration.
|
// Certificate file updates configuration.
|
||||||
tCertFileUpdateConfig struct {
|
tCertFileUpdateConfig struct {
|
||||||
|
CmdTimeout *int `yaml:"command_timeout"`
|
||||||
PreCommands []string `yaml:"pre_commands"`
|
PreCommands []string `yaml:"pre_commands"`
|
||||||
Handlers []string `yaml:"handlers"`
|
Handlers []string `yaml:"handlers"`
|
||||||
PostCommands []string `yaml:"post_commands"`
|
PostCommands []string `yaml:"post_commands"`
|
||||||
|
@ -86,10 +89,12 @@ type (
|
||||||
|
|
||||||
// Main configuration.
|
// Main configuration.
|
||||||
tConfiguration struct {
|
tConfiguration struct {
|
||||||
Socket *tSocketConfig `yaml:"socket"`
|
CmdTimeout int `yaml:"command_timeout"`
|
||||||
LdapConfig tLdapConfig `yaml:"ldap"`
|
Socket *tSocketConfig `yaml:"socket"`
|
||||||
Handlers tHandlers `yaml:"handlers"`
|
LdapConfig tLdapConfig `yaml:"ldap"`
|
||||||
Certificates []tCertificateFileConfig `yaml:"certificates"`
|
Handlers tHandlers `yaml:"handlers"`
|
||||||
|
HandlerTimeouts tHandlerTimeouts `yaml:"handler_timeouts"`
|
||||||
|
Certificates []tCertificateFileConfig `yaml:"certificates"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -235,7 +240,7 @@ func checkFileList(files []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the list of handles
|
// Validate the list of handlers and the timeout.
|
||||||
func (c *tCertFileUpdateConfig) Validate(handlers *tHandlers) error {
|
func (c *tCertFileUpdateConfig) Validate(handlers *tHandlers) error {
|
||||||
set := make(map[string]bool)
|
set := make(map[string]bool)
|
||||||
for _, handler := range c.Handlers {
|
for _, handler := range c.Handlers {
|
||||||
|
@ -247,6 +252,9 @@ func (c *tCertFileUpdateConfig) Validate(handlers *tHandlers) error {
|
||||||
}
|
}
|
||||||
set[handler] = true
|
set[handler] = true
|
||||||
}
|
}
|
||||||
|
if c.CmdTimeout != nil && *c.CmdTimeout <= 0 {
|
||||||
|
return fmt.Errorf("Command timeout must be >0.")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +297,9 @@ func (c *tCertificateFileConfig) Validate(handlers *tHandlers) error {
|
||||||
|
|
||||||
// Validate the configuration
|
// Validate the configuration
|
||||||
func (c *tConfiguration) Validate() error {
|
func (c *tConfiguration) Validate() error {
|
||||||
|
if c.CmdTimeout <= 0 {
|
||||||
|
return fmt.Errorf("Default command timeout must be >0.")
|
||||||
|
}
|
||||||
if c.Socket != nil {
|
if c.Socket != nil {
|
||||||
err := c.Socket.Validate()
|
err := c.Socket.Validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -299,6 +310,14 @@ func (c *tConfiguration) Validate() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for hdl, timeout := range c.HandlerTimeouts {
|
||||||
|
if _, exists := c.Handlers[hdl]; !exists {
|
||||||
|
return fmt.Errorf("Can't set timeout for unknown handler %s", hdl)
|
||||||
|
}
|
||||||
|
if timeout <= 0 {
|
||||||
|
return fmt.Errorf("Command timeout for handler %s must be >0.", hdl)
|
||||||
|
}
|
||||||
|
}
|
||||||
for idx, cfc := range c.Certificates {
|
for idx, cfc := range c.Certificates {
|
||||||
if cfc.Path == "" {
|
if cfc.Path == "" {
|
||||||
return fmt.Errorf("Certificate file entry #%d has no path.", idx+1)
|
return fmt.Errorf("Certificate file entry #%d has no path.", idx+1)
|
||||||
|
@ -314,6 +333,7 @@ func (c *tConfiguration) Validate() error {
|
||||||
// Create a configuration data structure containing default values.
|
// Create a configuration data structure containing default values.
|
||||||
func defaultConfiguration() tConfiguration {
|
func defaultConfiguration() tConfiguration {
|
||||||
cfg := tConfiguration{}
|
cfg := tConfiguration{}
|
||||||
|
cfg.CmdTimeout = 5
|
||||||
cfg.LdapConfig.Defaults.TLS = "no"
|
cfg.LdapConfig.Defaults.TLS = "no"
|
||||||
cfg.LdapConfig.Structure.CAChaining = "seeAlso"
|
cfg.LdapConfig.Structure.CAChaining = "seeAlso"
|
||||||
return cfg
|
return cfg
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# fetchcert configuration example / documentation
|
# fetchcert configuration example / documentation
|
||||||
# ===============================================
|
# ===============================================
|
||||||
|
|
||||||
|
# Default command execution timeout (seconds). 5 seconds is the default.
|
||||||
|
command_timeout: 5
|
||||||
|
|
||||||
# The UNIX socket the main program listens on. May be omitted if the program
|
# The UNIX socket the main program listens on. May be omitted if the program
|
||||||
# is intended to run in standalone mode only.
|
# is intended to run in standalone mode only.
|
||||||
socket:
|
socket:
|
||||||
|
@ -63,6 +66,11 @@ handlers:
|
||||||
- /usr/sbin/apache2ctl configtest
|
- /usr/sbin/apache2ctl configtest
|
||||||
- /usr/sbin/apache2ctl graceful
|
- /usr/sbin/apache2ctl graceful
|
||||||
|
|
||||||
|
# Handler command timeouts. If this section is missing, or if no entry is
|
||||||
|
# present for a handler, the default command timeout will be used.
|
||||||
|
handler_timeouts:
|
||||||
|
apache: 1
|
||||||
|
|
||||||
# Certificates that must be updated
|
# Certificates that must be updated
|
||||||
certificates:
|
certificates:
|
||||||
|
|
||||||
|
@ -101,6 +109,10 @@ certificates:
|
||||||
- /some/other/file.pem
|
- /some/other/file.pem
|
||||||
# Define what must be done after an update.
|
# Define what must be done after an update.
|
||||||
after_update:
|
after_update:
|
||||||
|
# Command execution timeout for pre- and post-commands. If this entry is
|
||||||
|
# missing, the default from command_timeout above will be used. This does
|
||||||
|
# not affect handlers.
|
||||||
|
command_timeout: 1
|
||||||
# Commands to execute before handlers are run. The order of the commands
|
# Commands to execute before handlers are run. The order of the commands
|
||||||
# is respected. If a command fails to run, execution stops.
|
# is respected. If a command fails to run, execution stops.
|
||||||
pre_commands: []
|
pre_commands: []
|
||||||
|
|
33
update.go
33
update.go
|
@ -122,7 +122,11 @@ func (u *tUpdate) runPreCommands() {
|
||||||
|
|
||||||
l := log.WithField("file", u.config.Certificates[i].Path)
|
l := log.WithField("file", u.config.Certificates[i].Path)
|
||||||
l.Info("Running pre-commands")
|
l.Info("Running pre-commands")
|
||||||
err := u.runCommands(commands, l)
|
timeout := u.config.CmdTimeout
|
||||||
|
if u.config.Certificates[i].AfterUpdate.CmdTimeout != nil {
|
||||||
|
timeout = *u.config.Certificates[i].AfterUpdate.CmdTimeout
|
||||||
|
}
|
||||||
|
err := u.runCommands(timeout, commands, l)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -159,7 +163,11 @@ func (u *tUpdate) runHandlers(handlers []string) map[string]bool {
|
||||||
for _, handler := range handlers {
|
for _, handler := range handlers {
|
||||||
l := log.WithField("handler", handler)
|
l := log.WithField("handler", handler)
|
||||||
l.Info("Running handler")
|
l.Info("Running handler")
|
||||||
err := u.runCommands(u.config.Handlers[handler], l)
|
timeout := u.config.CmdTimeout
|
||||||
|
if ht, exists := u.config.HandlerTimeouts[handler]; exists {
|
||||||
|
timeout = ht
|
||||||
|
}
|
||||||
|
err := u.runCommands(timeout, u.config.Handlers[handler], l)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -204,7 +212,11 @@ func (u *tUpdate) runPostCommands() {
|
||||||
|
|
||||||
l := log.WithField("file", u.config.Certificates[i].Path)
|
l := log.WithField("file", u.config.Certificates[i].Path)
|
||||||
l.Info("Running post-commands")
|
l.Info("Running post-commands")
|
||||||
err := u.runCommands(commands, l)
|
timeout := u.config.CmdTimeout
|
||||||
|
if u.config.Certificates[i].AfterUpdate.CmdTimeout != nil {
|
||||||
|
timeout = *u.config.Certificates[i].AfterUpdate.CmdTimeout
|
||||||
|
}
|
||||||
|
err := u.runCommands(timeout, commands, l)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -215,10 +227,10 @@ func (u *tUpdate) runPostCommands() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a list of commands
|
// Run a list of commands.
|
||||||
func (u *tUpdate) runCommands(commands []string, log *logrus.Entry) error {
|
func (u *tUpdate) runCommands(timeout int, commands []string, log *logrus.Entry) error {
|
||||||
for i := range commands {
|
for i := range commands {
|
||||||
err := u.runCommand(commands[i], log)
|
err := u.runCommand(timeout, commands[i], log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Failed while executing command '%s': %w",
|
"Failed while executing command '%s': %w",
|
||||||
|
@ -230,11 +242,14 @@ func (u *tUpdate) runCommands(commands []string, log *logrus.Entry) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a command through the `sh` shell.
|
// Run a command through the `sh` shell.
|
||||||
func (b *tUpdate) runCommand(command string, log *logrus.Entry) error {
|
func (b *tUpdate) runCommand(timeout int, command string, log *logrus.Entry) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
log = log.WithField("command", command)
|
log = log.WithFields(logrus.Fields{
|
||||||
|
"command": command,
|
||||||
|
"timeout": timeout,
|
||||||
|
})
|
||||||
log.Debug("Executing command")
|
log.Debug("Executing command")
|
||||||
cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
|
|
Loading…
Reference in a new issue