This repository has been archived by the owner on Nov 19, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea95a86
commit 596ac5e
Showing
14 changed files
with
991 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package main | ||
|
||
import ( | ||
log "github.com/hashicorp/go-hclog" | ||
|
||
"github.com/hashicorp/nomad/plugins" | ||
"github.com/jet/damon/plugin" | ||
) | ||
|
||
func main() { | ||
// Serve the plugin | ||
plugins.Serve(factory) | ||
} | ||
|
||
// factory returns a new instance of the LXC driver plugin | ||
func factory(log log.Logger) interface{} { | ||
return plugin.NewDriverPlugin(log) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package container | ||
|
||
import ( | ||
"context" | ||
"io" | ||
|
||
"github.com/jet/damon/win32" | ||
) | ||
|
||
type TaskConfig struct { | ||
Command []string | ||
Dir string | ||
EnvList []string | ||
Stdout io.Writer | ||
Stderr io.Writer | ||
} | ||
|
||
type Task struct { | ||
osProcess *win32.Process | ||
} | ||
|
||
func (t *Task) Wait(ctx context.Context) (int, error) { | ||
exitCh := make(chan int, 1) | ||
errCh := make(chan error, 1) | ||
go func() { | ||
defer close(exitCh) | ||
defer close(errCh) | ||
res, err := t.osProcess.Wait() | ||
if err != nil { | ||
errCh <- err | ||
return | ||
} | ||
if res.Err != nil { | ||
errCh <- res.Err | ||
return | ||
} | ||
exitCh <- res.ExitStatus | ||
}() | ||
select { | ||
case err := <-errCh: | ||
t.osProcess.Kill() | ||
return -1, err | ||
case res := <-exitCh: | ||
return res, nil | ||
case <-ctx.Done(): | ||
t.osProcess.Kill() | ||
return -1, ctx.Err() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package plugin | ||
|
||
import ( | ||
// "fmt" | ||
|
||
"fmt" | ||
"io" | ||
"os/exec" | ||
"strings" | ||
|
||
log "github.com/hashicorp/go-hclog" | ||
"github.com/hashicorp/nomad/client/lib/fifo" | ||
"github.com/jet/damon/container" | ||
|
||
"github.com/hashicorp/nomad/plugins/drivers" | ||
) | ||
|
||
type damonExec struct { | ||
cmd *exec.Cmd | ||
ccfg *container.Config | ||
taskConfig TaskConfig | ||
cfg *drivers.TaskConfig | ||
stdout io.WriteCloser | ||
stderr io.WriteCloser | ||
logger log.Logger | ||
} | ||
|
||
type hcLogWrapper struct { | ||
Logger log.Logger | ||
} | ||
|
||
func (l hcLogWrapper) Logln(v ...interface{}) { | ||
if l.Logger == nil { | ||
return | ||
} | ||
l.Logger.Debug(fmt.Sprint(v...)) | ||
} | ||
func (l hcLogWrapper) Error(err error, msg string) { | ||
if l.Logger == nil { | ||
return | ||
} | ||
l.Logger.Error(msg, "error", err) | ||
} | ||
|
||
func getCPUMHz(cfg *drivers.TaskConfig, taskConfig TaskConfig, logger log.Logger) int { | ||
if taskConfig.CPULimit > 0 { | ||
return taskConfig.CPULimit | ||
} | ||
return int(cfg.Resources.NomadResources.Cpu.CpuShares) | ||
} | ||
|
||
func getMemoryMB(cfg *drivers.TaskConfig, taskConfig TaskConfig, logger log.Logger) int { | ||
if taskConfig.MemoryLimit > 0 { | ||
return taskConfig.MemoryLimit | ||
} | ||
return int(cfg.Resources.NomadResources.Memory.MemoryMB) | ||
} | ||
|
||
func newDamonExec(cfg *drivers.TaskConfig, taskConfig TaskConfig, logger log.Logger) (*damonExec, error) { | ||
var d damonExec | ||
d.ccfg = &container.Config{ | ||
Name: cfg.ID, | ||
EnforceCPU: taskConfig.EnforceCPULimit, | ||
CPUMHzLimit: getCPUMHz(cfg, taskConfig, logger), | ||
EnforceMemory: taskConfig.EnforceMemoryLimit, | ||
MemoryMBLimit: getMemoryMB(cfg, taskConfig, logger), | ||
RestrictedToken: taskConfig.RestrictedToken, | ||
CPUHardCap: true, | ||
Logger: hcLogWrapper{Logger: logger}, | ||
} | ||
d.cfg = cfg | ||
d.taskConfig = taskConfig | ||
d.cmd = exec.Command(taskConfig.Command, taskConfig.Args...) | ||
d.cmd.Dir = cfg.TaskDir().Dir | ||
d.cmd.Env = cfg.EnvList() | ||
d.logger = logger | ||
return &d, nil | ||
} | ||
|
||
func (d *damonExec) startContainer(commandCfg *drivers.TaskConfig) (*taskHandle, error) { | ||
d.logger.Debug("running executable", "task_id", commandCfg.ID, "command", d.cmd.Path, "args", strings.Join(d.cmd.Args, " ")) | ||
stdout, err := d.Stdout() | ||
if err != nil { | ||
return nil, err | ||
} | ||
stderr, err := d.Stderr() | ||
if err != nil { | ||
return nil, err | ||
} | ||
cmd := d.cmd | ||
cmd.Stdout = stdout | ||
cmd.Stderr = stderr | ||
c, err := container.RunContained(d.cmd, d.ccfg) | ||
if err != nil { | ||
defer d.Close() | ||
return nil, err | ||
} | ||
return &taskHandle{ | ||
container: c, | ||
pid: c.PID, | ||
logger: d.logger, | ||
taskConfig: commandCfg, | ||
startedAt: c.StartTime, | ||
procState: drivers.TaskStateRunning, | ||
}, nil | ||
} | ||
|
||
func (d *damonExec) Stdout() (io.Writer, error) { | ||
if d.stdout == nil { | ||
if d.cfg.StdoutPath == "" { | ||
return DevNull, nil | ||
} | ||
stdout, err := fifo.OpenWriter(d.cfg.StdoutPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to open stdout fifo '%s': %v", d.cfg.StdoutPath, err) | ||
} | ||
d.logger.Trace("stdout fifo opened", "path", "task_id", d.cfg.ID, d.cfg.StderrPath) | ||
d.stdout = stdout | ||
} | ||
return d.stdout, nil | ||
} | ||
|
||
func (d *damonExec) Stderr() (io.Writer, error) { | ||
if d.stderr == nil { | ||
if d.cfg.StderrPath == "" { | ||
return DevNull, nil | ||
} | ||
stderr, err := fifo.OpenWriter(d.cfg.StderrPath) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to open stderr fifo '%s': %v", d.cfg.StderrPath, err) | ||
} | ||
d.logger.Trace("stderr fifo opened", "path", "task_id", d.cfg.ID, d.cfg.StderrPath) | ||
d.stderr = stderr | ||
} | ||
return d.stderr, nil | ||
} | ||
|
||
func (d *damonExec) Close() { | ||
d.logger.Trace("damon closed", "task_id", d.cfg.ID) | ||
if d.stdout != nil { | ||
d.logger.Trace("stdout fifo closed", "task_id", d.cfg.ID) | ||
d.stdout.Close() | ||
} | ||
if d.stderr != nil { | ||
d.logger.Trace("stderr fifo closed", "task_id", d.cfg.ID) | ||
d.stderr.Close() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package plugin | ||
|
||
type devNull int | ||
|
||
// DevNull is a no-op io device | ||
// It implements: | ||
// - io.Reader | ||
// - io.Writer | ||
// - io.Closer (implicitly: io.ReadCloser & io.WriteCloser) | ||
// - io.Seeker (implicitly: io.ReadSeeker & io.WriteSeeker) | ||
// - io.ReaderAt | ||
// - io.WriterAt | ||
// - io.StringWriter | ||
const DevNull = devNull(0) | ||
|
||
// Read implements a no-op io.Reader | ||
func (n devNull) Read(p []byte) (int, error) { | ||
return 0, nil | ||
} | ||
|
||
// ReadAt implements a no-op io.ReaderAt | ||
func (n devNull) ReadAt(p []byte, off int64) (int, error) { | ||
return 0, nil | ||
} | ||
|
||
//Write implements a discarding io.Writer | ||
func (n devNull) Write(p []byte) (int, error) { | ||
return len(p), nil | ||
} | ||
|
||
//WriteAt implements a discarding io.WriterAt | ||
func (n devNull) WriteAt(p []byte, off int64) (int, error) { | ||
return len(p), nil | ||
} | ||
|
||
// WriteString implements a discarding io.StringWriter | ||
func (n devNull) WriteString(s string) (int, error) { | ||
return len(s), nil | ||
} | ||
|
||
// Close implements a no-op io.Closer | ||
func (n devNull) Close() error { | ||
return nil | ||
} | ||
|
||
// Seek implements a no-op io.Seeker | ||
func (n devNull) Seek(offset, whence int) (int64, error) { | ||
return 0, nil | ||
} |
Oops, something went wrong.