github.com/hernad/nomad@v1.6.112/drivers/shared/executor/utils.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package executor 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "os" 10 "os/exec" 11 12 "github.com/golang/protobuf/ptypes" 13 hclog "github.com/hashicorp/go-hclog" 14 plugin "github.com/hashicorp/go-plugin" 15 "github.com/hernad/nomad/drivers/shared/executor/proto" 16 "github.com/hernad/nomad/helper/stats" 17 "github.com/hernad/nomad/plugins/base" 18 ) 19 20 const ( 21 // ExecutorDefaultMaxPort is the default max port used by the executor for 22 // searching for an available port 23 ExecutorDefaultMaxPort = 14512 24 25 // ExecutorDefaultMinPort is the default min port used by the executor for 26 // searching for an available port 27 ExecutorDefaultMinPort = 14000 28 ) 29 30 // CreateExecutor launches an executor plugin and returns an instance of the 31 // Executor interface 32 func CreateExecutor(logger hclog.Logger, driverConfig *base.ClientDriverConfig, 33 executorConfig *ExecutorConfig) (Executor, *plugin.Client, error) { 34 35 executorConfig.CpuTotalTicks = stats.CpuTotalTicks() 36 c, err := json.Marshal(executorConfig) 37 if err != nil { 38 return nil, nil, fmt.Errorf("unable to create executor config: %v", err) 39 } 40 bin, err := os.Executable() 41 if err != nil { 42 return nil, nil, fmt.Errorf("unable to find the nomad binary: %v", err) 43 } 44 45 p := &ExecutorPlugin{ 46 logger: logger, 47 fsIsolation: executorConfig.FSIsolation, 48 cpuTotalTicks: executorConfig.CpuTotalTicks, 49 } 50 51 config := &plugin.ClientConfig{ 52 HandshakeConfig: base.Handshake, 53 Plugins: map[string]plugin.Plugin{"executor": p}, 54 Cmd: exec.Command(bin, "executor", string(c)), 55 AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, 56 Logger: logger.Named("executor"), 57 } 58 59 if driverConfig != nil { 60 config.MaxPort = driverConfig.ClientMaxPort 61 config.MinPort = driverConfig.ClientMinPort 62 } else { 63 config.MaxPort = ExecutorDefaultMaxPort 64 config.MinPort = ExecutorDefaultMinPort 65 } 66 67 // setting the setsid of the plugin process so that it doesn't get signals sent to 68 // the nomad client. 69 if config.Cmd != nil { 70 isolateCommand(config.Cmd) 71 } 72 73 return newExecutorClient(config, logger) 74 } 75 76 // ReattachToExecutor launches a plugin with a given plugin config 77 func ReattachToExecutor(reattachConfig *plugin.ReattachConfig, logger hclog.Logger) (Executor, *plugin.Client, error) { 78 config := &plugin.ClientConfig{ 79 HandshakeConfig: base.Handshake, 80 Reattach: reattachConfig, 81 Plugins: GetPluginMap(logger, false, stats.CpuTotalTicks()), 82 AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, 83 Logger: logger.Named("executor"), 84 } 85 86 return newExecutorClient(config, logger) 87 } 88 89 func newExecutorClient(config *plugin.ClientConfig, logger hclog.Logger) (Executor, *plugin.Client, error) { 90 executorClient := plugin.NewClient(config) 91 rpcClient, err := executorClient.Client() 92 if err != nil { 93 return nil, nil, fmt.Errorf("error creating rpc client for executor plugin: %v", err) 94 } 95 96 raw, err := rpcClient.Dispense("executor") 97 if err != nil { 98 return nil, nil, fmt.Errorf("unable to dispense the executor plugin: %v", err) 99 } 100 executorPlugin, ok := raw.(Executor) 101 if !ok { 102 return nil, nil, fmt.Errorf("unexpected executor rpc type: %T", raw) 103 } 104 return executorPlugin, executorClient, nil 105 } 106 107 func processStateToProto(ps *ProcessState) (*proto.ProcessState, error) { 108 timestamp, err := ptypes.TimestampProto(ps.Time) 109 if err != nil { 110 return nil, err 111 } 112 pb := &proto.ProcessState{ 113 Pid: int32(ps.Pid), 114 ExitCode: int32(ps.ExitCode), 115 Signal: int32(ps.Signal), 116 Time: timestamp, 117 } 118 119 return pb, nil 120 } 121 122 func processStateFromProto(pb *proto.ProcessState) (*ProcessState, error) { 123 timestamp, err := ptypes.Timestamp(pb.Time) 124 if err != nil { 125 return nil, err 126 } 127 128 return &ProcessState{ 129 Pid: int(pb.Pid), 130 ExitCode: int(pb.ExitCode), 131 Signal: int(pb.Signal), 132 Time: timestamp, 133 }, nil 134 } 135 136 // IsolationMode returns the namespace isolation mode as determined from agent 137 // plugin configuration and task driver configuration. The task configuration 138 // takes precedence, if it is configured. 139 func IsolationMode(plugin, task string) string { 140 if task != "" { 141 return task 142 } 143 return plugin 144 }