open-nomad/plugins/drivers/driver.go
Alex Dadgar 693f244cce Plugin client's handle plugin dying
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.
2018-11-12 17:09:27 -08:00

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
}