mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 02:45:42 +03:00
This commit prevents us from creating duplicate logmon hooks when restoring allocations by persisting the logmon reattach config using HookData.
142 lines
3.5 KiB
Go
142 lines
3.5 KiB
Go
package taskrunner
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
hclog "github.com/hashicorp/go-hclog"
|
|
plugin "github.com/hashicorp/go-plugin"
|
|
"github.com/hashicorp/nomad/client/allocrunner/interfaces"
|
|
"github.com/hashicorp/nomad/client/logmon"
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
"github.com/hashicorp/nomad/plugins/shared"
|
|
)
|
|
|
|
// logmonHook launches logmon and manages task logging
|
|
type logmonHook struct {
|
|
// logmon is the handle to the log monitor process for the task.
|
|
logmon logmon.LogMon
|
|
logmonPluginClient *plugin.Client
|
|
|
|
config *logmonHookConfig
|
|
|
|
logger hclog.Logger
|
|
}
|
|
|
|
type logmonHookConfig struct {
|
|
logDir string
|
|
stdoutFifo string
|
|
stderrFifo string
|
|
}
|
|
|
|
func newLogMonHook(cfg *logmonHookConfig, logger hclog.Logger) *logmonHook {
|
|
hook := &logmonHook{
|
|
config: cfg,
|
|
logger: logger,
|
|
}
|
|
|
|
return hook
|
|
}
|
|
|
|
func newLogMonHookConfig(taskName, logDir string) *logmonHookConfig {
|
|
cfg := &logmonHookConfig{
|
|
logDir: logDir,
|
|
}
|
|
if runtime.GOOS == "windows" {
|
|
id := uuid.Generate()[:8]
|
|
cfg.stdoutFifo = fmt.Sprintf("//./pipe/%s-%s.stdout", taskName, id)
|
|
cfg.stderrFifo = fmt.Sprintf("//./pipe/%s-%s.stderr", taskName, id)
|
|
} else {
|
|
cfg.stdoutFifo = filepath.Join(logDir, fmt.Sprintf(".%s.stdout.fifo", taskName))
|
|
cfg.stderrFifo = filepath.Join(logDir, fmt.Sprintf(".%s.stderr.fifo", taskName))
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
func (*logmonHook) Name() string {
|
|
return "logmon"
|
|
}
|
|
|
|
func (h *logmonHook) launchLogMon(reattachConfig *plugin.ReattachConfig) error {
|
|
l, c, err := logmon.LaunchLogMon(h.logger, reattachConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
h.logmon = l
|
|
h.logmonPluginClient = c
|
|
return nil
|
|
}
|
|
|
|
func reattachConfigFromHookData(data map[string]string) (*plugin.ReattachConfig, error) {
|
|
if data == nil || data["reattach_config"] == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
var cfg *shared.ReattachConfig
|
|
err := json.Unmarshal([]byte(data["reattach_config"]), cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return shared.ReattachConfigToGoPlugin(cfg)
|
|
}
|
|
|
|
func (h *logmonHook) Prestart(ctx context.Context,
|
|
req *interfaces.TaskPrestartRequest, resp *interfaces.TaskPrestartResponse) error {
|
|
|
|
reattachConfig, err := reattachConfigFromHookData(req.HookData)
|
|
if err != nil {
|
|
h.logger.Error("failed to load reattach config", "error", err)
|
|
return err
|
|
}
|
|
|
|
// Launch or reattach logmon instance for the task.
|
|
if err := h.launchLogMon(reattachConfig); err != nil {
|
|
h.logger.Error("failed to launch logmon process", "error", err)
|
|
return err
|
|
}
|
|
|
|
// Only tell logmon to start when we are not reattaching to a running instance
|
|
if reattachConfig == nil {
|
|
err := h.logmon.Start(&logmon.LogConfig{
|
|
LogDir: h.config.logDir,
|
|
StdoutLogFile: fmt.Sprintf("%s.stdout", req.Task.Name),
|
|
StderrLogFile: fmt.Sprintf("%s.stderr", req.Task.Name),
|
|
StdoutFifo: h.config.stdoutFifo,
|
|
StderrFifo: h.config.stderrFifo,
|
|
MaxFiles: req.Task.LogConfig.MaxFiles,
|
|
MaxFileSizeMB: req.Task.LogConfig.MaxFileSizeMB,
|
|
})
|
|
if err != nil {
|
|
h.logger.Error("failed to start logmon", "error", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
rCfg := shared.ReattachConfigFromGoPlugin(h.logmonPluginClient.ReattachConfig())
|
|
jsonCfg, err := json.Marshal(rCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.HookData = map[string]string{"reattach_config": string(jsonCfg)}
|
|
|
|
resp.Done = true
|
|
return nil
|
|
}
|
|
|
|
func (h *logmonHook) Stop(context.Context, *interfaces.TaskStopRequest, *interfaces.TaskStopResponse) error {
|
|
|
|
if h.logmon != nil {
|
|
h.logmon.Stop()
|
|
}
|
|
if h.logmonPluginClient != nil {
|
|
h.logmonPluginClient.Kill()
|
|
}
|
|
|
|
return nil
|
|
}
|