github.com/mattyr/nomad@v0.3.3-0.20160919021406-3485a065154a/client/driver/mock_driver.go (about)

     1  // +build nomad_test
     2  
     3  package driver
     4  
     5  import (
     6  	"errors"
     7  	"log"
     8  	"time"
     9  
    10  	"github.com/mitchellh/mapstructure"
    11  
    12  	"github.com/hashicorp/nomad/client/config"
    13  	dstructs "github.com/hashicorp/nomad/client/driver/structs"
    14  	"github.com/hashicorp/nomad/client/fingerprint"
    15  	cstructs "github.com/hashicorp/nomad/client/structs"
    16  	"github.com/hashicorp/nomad/nomad/structs"
    17  )
    18  
    19  // Add the mock driver to the list of builtin drivers
    20  func init() {
    21  	BuiltinDrivers["mock_driver"] = NewMockDriver
    22  }
    23  
    24  // MockDriverConfig is the driver configuration for the MockDriver
    25  type MockDriverConfig struct {
    26  
    27  	// KillAfter is the duration after which the mock driver indicates the task
    28  	// has exited after getting the initial SIGINT signal
    29  	KillAfter time.Duration `mapstructure:"kill_after"`
    30  
    31  	// RunFor is the duration for which the fake task runs for. After this
    32  	// period the MockDriver responds to the task running indicating that the
    33  	// task has terminated
    34  	RunFor time.Duration `mapstructure:"run_for"`
    35  
    36  	// ExitCode is the exit code with which the MockDriver indicates the task
    37  	// has exited
    38  	ExitCode int `mapstructure:"exit_code"`
    39  
    40  	// ExitSignal is the signal with which the MockDriver indicates the task has
    41  	// been killed
    42  	ExitSignal int `mapstructure:"exit_signal"`
    43  
    44  	// ExitErrMsg is the error message that the task returns while exiting
    45  	ExitErrMsg string `mapstructure:"exit_err_msg"`
    46  }
    47  
    48  // MockDriver is a driver which is used for testing purposes
    49  type MockDriver struct {
    50  	DriverContext
    51  	fingerprint.StaticFingerprinter
    52  }
    53  
    54  // NewMockDriver is a factory method which returns a new Mock Driver
    55  func NewMockDriver(ctx *DriverContext) Driver {
    56  	return &MockDriver{DriverContext: *ctx}
    57  }
    58  
    59  // Start starts the mock driver
    60  func (m *MockDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
    61  	var driverConfig MockDriverConfig
    62  	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
    63  		DecodeHook:       mapstructure.StringToTimeDurationHookFunc(),
    64  		WeaklyTypedInput: true,
    65  		Result:           &driverConfig,
    66  	})
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	if err := dec.Decode(task.Config); err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	h := mockDriverHandle{
    75  		taskName:    task.Name,
    76  		runFor:      driverConfig.RunFor,
    77  		killAfter:   driverConfig.KillAfter,
    78  		killTimeout: task.KillTimeout,
    79  		exitCode:    driverConfig.ExitCode,
    80  		exitSignal:  driverConfig.ExitSignal,
    81  		logger:      m.logger,
    82  		doneCh:      make(chan struct{}),
    83  		waitCh:      make(chan *dstructs.WaitResult, 1),
    84  	}
    85  	if driverConfig.ExitErrMsg != "" {
    86  		h.exitErr = errors.New(driverConfig.ExitErrMsg)
    87  	}
    88  	m.logger.Printf("[DEBUG] driver.mock: starting task %q", task.Name)
    89  	go h.run()
    90  	return &h, nil
    91  }
    92  
    93  // TODO implement Open when we need it.
    94  // Open re-connects the driver to the running task
    95  func (m *MockDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
    96  	return nil, nil
    97  }
    98  
    99  // TODO implement Open when we need it.
   100  // Validate validates the mock driver configuration
   101  func (m *MockDriver) Validate(map[string]interface{}) error {
   102  	return nil
   103  }
   104  
   105  // TODO implement Open when we need it.
   106  // Fingerprint fingerprints a node and returns if MockDriver is enabled
   107  func (m *MockDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
   108  	node.Attributes["driver.mock_driver"] = "1"
   109  	return true, nil
   110  }
   111  
   112  // MockDriverHandle is a driver handler which supervises a mock task
   113  type mockDriverHandle struct {
   114  	taskName    string
   115  	runFor      time.Duration
   116  	killAfter   time.Duration
   117  	killTimeout time.Duration
   118  	exitCode    int
   119  	exitSignal  int
   120  	exitErr     error
   121  	logger      *log.Logger
   122  	waitCh      chan *dstructs.WaitResult
   123  	doneCh      chan struct{}
   124  }
   125  
   126  // TODO Implement when we need it.
   127  func (h *mockDriverHandle) ID() string {
   128  	return ""
   129  }
   130  
   131  // TODO Implement when we need it.
   132  func (h *mockDriverHandle) WaitCh() chan *dstructs.WaitResult {
   133  	return h.waitCh
   134  }
   135  
   136  // TODO Implement when we need it.
   137  func (h *mockDriverHandle) Update(task *structs.Task) error {
   138  	return nil
   139  }
   140  
   141  // Kill kills a mock task
   142  func (h *mockDriverHandle) Kill() error {
   143  	h.logger.Printf("[DEBUG] driver.mock: killing task %q after kill timeout: %v", h.taskName, h.killTimeout)
   144  	select {
   145  	case <-h.doneCh:
   146  	case <-time.After(h.killAfter):
   147  		close(h.doneCh)
   148  	case <-time.After(h.killTimeout):
   149  		h.logger.Printf("[DEBUG] driver.mock: terminating task %q", h.taskName)
   150  		close(h.doneCh)
   151  	}
   152  	return nil
   153  }
   154  
   155  // TODO Implement when we need it.
   156  func (h *mockDriverHandle) Stats() (*cstructs.TaskResourceUsage, error) {
   157  	return nil, nil
   158  }
   159  
   160  // run waits for the configured amount of time and then indicates the task has
   161  // terminated
   162  func (h *mockDriverHandle) run() {
   163  	timer := time.NewTimer(h.runFor)
   164  	defer timer.Stop()
   165  	for {
   166  		select {
   167  		case <-timer.C:
   168  			close(h.doneCh)
   169  		case <-h.doneCh:
   170  			h.logger.Printf("[DEBUG] driver.mock: finished running task %q", h.taskName)
   171  			h.waitCh <- dstructs.NewWaitResult(h.exitCode, h.exitSignal, h.exitErr)
   172  			return
   173  		}
   174  	}
   175  }