693f244cce
This PR plumbs the plugins done ctx through the base and driver plugin clients (device already had it). Further, it adds generic handling of gRPC stream errors.
252 lines
6.2 KiB
Go
252 lines
6.2 KiB
Go
package drivers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/hashicorp/nomad/client/allocdir"
|
|
cstructs "github.com/hashicorp/nomad/client/structs"
|
|
"github.com/hashicorp/nomad/helper"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
"github.com/hashicorp/nomad/plugins/base"
|
|
"github.com/hashicorp/nomad/plugins/shared/hclspec"
|
|
"github.com/zclconf/go-cty/cty"
|
|
"github.com/zclconf/go-cty/cty/msgpack"
|
|
)
|
|
|
|
// DriverPlugin is the interface with drivers will implement. It is also
|
|
// implemented by a plugin client which proxies the calls to go-plugin. See
|
|
// the proto/driver.proto file for detailed information about each RPC and
|
|
// message structure.
|
|
type DriverPlugin interface {
|
|
base.BasePlugin
|
|
|
|
TaskConfigSchema() (*hclspec.Spec, error)
|
|
Capabilities() (*Capabilities, error)
|
|
Fingerprint(context.Context) (<-chan *Fingerprint, error)
|
|
|
|
RecoverTask(*TaskHandle) error
|
|
StartTask(*TaskConfig) (*TaskHandle, *cstructs.DriverNetwork, error)
|
|
WaitTask(ctx context.Context, taskID string) (<-chan *ExitResult, error)
|
|
StopTask(taskID string, timeout time.Duration, signal string) error
|
|
DestroyTask(taskID string, force bool) error
|
|
InspectTask(taskID string) (*TaskStatus, error)
|
|
TaskStats(taskID string) (*cstructs.TaskResourceUsage, error)
|
|
TaskEvents(context.Context) (<-chan *TaskEvent, error)
|
|
|
|
SignalTask(taskID string, signal string) error
|
|
ExecTask(taskID string, cmd []string, timeout time.Duration) (*ExecTaskResult, error)
|
|
}
|
|
|
|
// DriverSignalTaskNotSupported can be embedded by drivers which don't support
|
|
// the SignalTask RPC. This satisfies the SignalTask func requirement for the
|
|
// DriverPlugin interface.
|
|
type DriverSignalTaskNotSupported struct{}
|
|
|
|
func (DriverSignalTaskNotSupported) SignalTask(taskID, signal string) error {
|
|
return fmt.Errorf("SignalTask is not supported by this driver")
|
|
}
|
|
|
|
// DriverExecTaskNotSupported can be embedded by drivers which don't support
|
|
// the ExecTask RPC. This satisfies the ExecTask func requirement of the
|
|
// DriverPlugin interface.
|
|
type DriverExecTaskNotSupported struct{}
|
|
|
|
func (_ DriverExecTaskNotSupported) ExecTask(taskID, signal string) error {
|
|
return fmt.Errorf("ExecTask is not supported by this driver")
|
|
}
|
|
|
|
type HealthState string
|
|
|
|
var (
|
|
HealthStateUndetected = HealthState("undetected")
|
|
HealthStateUnhealthy = HealthState("unhealthy")
|
|
HealthStateHealthy = HealthState("healthy")
|
|
)
|
|
|
|
type Fingerprint struct {
|
|
Attributes map[string]string
|
|
Health HealthState
|
|
HealthDescription string
|
|
|
|
// Err is set by the plugin if an error occurred during fingerprinting
|
|
Err error
|
|
}
|
|
|
|
type FSIsolation string
|
|
|
|
var (
|
|
FSIsolationNone = FSIsolation("none")
|
|
FSIsolationChroot = FSIsolation("chroot")
|
|
FSIsolationImage = FSIsolation("image")
|
|
)
|
|
|
|
type Capabilities struct {
|
|
// SendSignals marks the driver as being able to send signals
|
|
SendSignals bool
|
|
|
|
// Exec marks the driver as being able to execute arbitrary commands
|
|
// such as health checks. Used by the ScriptExecutor interface.
|
|
Exec bool
|
|
|
|
//FSIsolation indicates what kind of filesystem isolation the driver supports.
|
|
FSIsolation cstructs.FSIsolation
|
|
}
|
|
|
|
type TaskConfig struct {
|
|
ID string
|
|
Name string
|
|
Env map[string]string
|
|
Resources *Resources
|
|
Devices []DeviceConfig
|
|
Mounts []MountConfig
|
|
User string
|
|
AllocDir string
|
|
rawDriverConfig []byte
|
|
StdoutPath string
|
|
StderrPath string
|
|
}
|
|
|
|
func (tc *TaskConfig) Copy() *TaskConfig {
|
|
if tc == nil {
|
|
return nil
|
|
}
|
|
c := new(TaskConfig)
|
|
*c = *tc
|
|
c.Env = helper.CopyMapStringString(c.Env)
|
|
c.Resources = tc.Resources.Copy()
|
|
return c
|
|
}
|
|
|
|
func (tc *TaskConfig) EnvList() []string {
|
|
l := make([]string, 0, len(tc.Env))
|
|
for k, v := range tc.Env {
|
|
l = append(l, k+"="+v)
|
|
}
|
|
|
|
sort.Strings(l)
|
|
return l
|
|
}
|
|
|
|
func (tc *TaskConfig) TaskDir() *allocdir.TaskDir {
|
|
taskDir := filepath.Join(tc.AllocDir, tc.Name)
|
|
return &allocdir.TaskDir{
|
|
Dir: taskDir,
|
|
SharedAllocDir: filepath.Join(tc.AllocDir, allocdir.SharedAllocName),
|
|
LogDir: filepath.Join(tc.AllocDir, allocdir.SharedAllocName, allocdir.LogDirName),
|
|
SharedTaskDir: filepath.Join(taskDir, allocdir.SharedAllocName),
|
|
LocalDir: filepath.Join(taskDir, allocdir.TaskLocal),
|
|
SecretsDir: filepath.Join(taskDir, allocdir.TaskSecrets),
|
|
}
|
|
}
|
|
|
|
func (tc *TaskConfig) DecodeDriverConfig(t interface{}) error {
|
|
return base.MsgPackDecode(tc.rawDriverConfig, t)
|
|
}
|
|
|
|
func (tc *TaskConfig) EncodeDriverConfig(val cty.Value) error {
|
|
data, err := msgpack.Marshal(val, val.Type())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tc.rawDriverConfig = data
|
|
return nil
|
|
}
|
|
|
|
type Resources struct {
|
|
NomadResources *structs.Resources
|
|
LinuxResources *LinuxResources
|
|
}
|
|
|
|
func (r *Resources) Copy() *Resources {
|
|
if r == nil {
|
|
return nil
|
|
}
|
|
res := new(Resources)
|
|
if r.NomadResources != nil {
|
|
res.NomadResources = r.NomadResources.Copy()
|
|
}
|
|
if r.LinuxResources != nil {
|
|
res.LinuxResources = r.LinuxResources.Copy()
|
|
}
|
|
return res
|
|
}
|
|
|
|
type LinuxResources struct {
|
|
CPUPeriod int64
|
|
CPUQuota int64
|
|
CPUShares int64
|
|
MemoryLimitBytes int64
|
|
OOMScoreAdj int64
|
|
CpusetCPUs string
|
|
CpusetMems string
|
|
}
|
|
|
|
func (r *LinuxResources) Copy() *LinuxResources {
|
|
res := new(LinuxResources)
|
|
*res = *r
|
|
return res
|
|
}
|
|
|
|
type DeviceConfig struct {
|
|
TaskPath string
|
|
HostPath string
|
|
Permissions string
|
|
}
|
|
|
|
type MountConfig struct {
|
|
TaskPath string
|
|
HostPath string
|
|
Readonly bool
|
|
}
|
|
|
|
const (
|
|
TaskStateUnknown TaskState = "unknown"
|
|
TaskStateRunning TaskState = "running"
|
|
TaskStateExited TaskState = "exited"
|
|
)
|
|
|
|
type TaskState string
|
|
|
|
type ExitResult struct {
|
|
ExitCode int
|
|
Signal int
|
|
OOMKilled bool
|
|
Err error
|
|
}
|
|
|
|
func (r *ExitResult) Successful() bool {
|
|
return r.ExitCode == 0 && r.Signal == 0 && r.Err == nil
|
|
}
|
|
|
|
type TaskStatus struct {
|
|
ID string
|
|
Name string
|
|
State TaskState
|
|
StartedAt time.Time
|
|
CompletedAt time.Time
|
|
ExitResult *ExitResult
|
|
DriverAttributes map[string]string
|
|
NetworkOverride *cstructs.DriverNetwork
|
|
}
|
|
|
|
type TaskEvent struct {
|
|
TaskID string
|
|
Timestamp time.Time
|
|
Message string
|
|
Annotations map[string]string
|
|
|
|
// Err is only used if an error occurred while consuming the RPC stream
|
|
Err error
|
|
}
|
|
|
|
type ExecTaskResult struct {
|
|
Stdout []byte
|
|
Stderr []byte
|
|
ExitResult *ExitResult
|
|
}
|