diff options
Diffstat (limited to 'executor/utils.go')
-rw-r--r-- | executor/utils.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/executor/utils.go b/executor/utils.go new file mode 100644 index 0000000..237152a --- /dev/null +++ b/executor/utils.go @@ -0,0 +1,138 @@ +package executor + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + + "github.com/golang/protobuf/ptypes" + hclog "github.com/hashicorp/go-hclog" + plugin "github.com/hashicorp/go-plugin" + "github.com/hashicorp/nomad/drivers/shared/executor/proto" + "github.com/hashicorp/nomad/plugins/base" +) + +const ( + // ExecutorDefaultMaxPort is the default max port used by the executor for + // searching for an available port + ExecutorDefaultMaxPort = 14512 + + // ExecutorDefaultMinPort is the default min port used by the executor for + // searching for an available port + ExecutorDefaultMinPort = 14000 +) + +// CreateExecutor launches an executor plugin and returns an instance of the +// Executor interface +func CreateExecutor(logger hclog.Logger, driverConfig *base.ClientDriverConfig, + executorConfig *ExecutorConfig) (Executor, *plugin.Client, error) { + + c, err := json.Marshal(executorConfig) + if err != nil { + return nil, nil, fmt.Errorf("unable to create executor config: %v", err) + } + bin, err := os.Executable() + if err != nil { + return nil, nil, fmt.Errorf("unable to find the nomad binary: %v", err) + } + + p := &ExecutorPlugin{ + logger: logger, + fsIsolation: executorConfig.FSIsolation, + } + + config := &plugin.ClientConfig{ + HandshakeConfig: base.Handshake, + Plugins: map[string]plugin.Plugin{"executor": p}, + Cmd: exec.Command(bin, "executor", string(c)), + AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, + Logger: logger.Named("executor"), + } + + if driverConfig != nil { + config.MaxPort = driverConfig.ClientMaxPort + config.MinPort = driverConfig.ClientMinPort + } else { + config.MaxPort = ExecutorDefaultMaxPort + config.MinPort = ExecutorDefaultMinPort + } + + // setting the setsid of the plugin process so that it doesn't get signals sent to + // the nomad client. + if config.Cmd != nil { + isolateCommand(config.Cmd) + } + + return newExecutorClient(config, logger) +} + +// ReattachToExecutor launches a plugin with a given plugin config +func ReattachToExecutor(reattachConfig *plugin.ReattachConfig, logger hclog.Logger) (Executor, *plugin.Client, error) { + config := &plugin.ClientConfig{ + HandshakeConfig: base.Handshake, + Reattach: reattachConfig, + Plugins: GetPluginMap(logger, false), + AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, + Logger: logger.Named("executor"), + } + + return newExecutorClient(config, logger) +} + +func newExecutorClient(config *plugin.ClientConfig, logger hclog.Logger) (Executor, *plugin.Client, error) { + executorClient := plugin.NewClient(config) + rpcClient, err := executorClient.Client() + if err != nil { + return nil, nil, fmt.Errorf("error creating rpc client for executor plugin: %v", err) + } + + raw, err := rpcClient.Dispense("executor") + if err != nil { + return nil, nil, fmt.Errorf("unable to dispense the executor plugin: %v", err) + } + executorPlugin, ok := raw.(Executor) + if !ok { + return nil, nil, fmt.Errorf("unexpected executor rpc type: %T", raw) + } + return executorPlugin, executorClient, nil +} + +func processStateToProto(ps *ProcessState) (*proto.ProcessState, error) { + timestamp, err := ptypes.TimestampProto(ps.Time) + if err != nil { + return nil, err + } + pb := &proto.ProcessState{ + Pid: int32(ps.Pid), + ExitCode: int32(ps.ExitCode), + Signal: int32(ps.Signal), + Time: timestamp, + } + + return pb, nil +} + +func processStateFromProto(pb *proto.ProcessState) (*ProcessState, error) { + timestamp, err := ptypes.Timestamp(pb.Time) + if err != nil { + return nil, err + } + + return &ProcessState{ + Pid: int(pb.Pid), + ExitCode: int(pb.ExitCode), + Signal: int(pb.Signal), + Time: timestamp, + }, nil +} + +// IsolationMode returns the namespace isolation mode as determined from agent +// plugin configuration and task driver configuration. The task configuration +// takes precedence, if it is configured. +func IsolationMode(plugin, task string) string { + if task != "" { + return task + } + return plugin +} |