166 lines
5.1 KiB
Go
166 lines
5.1 KiB
Go
|
// Copyright (c) HashiCorp, Inc.
|
||
|
// SPDX-License-Identifier: MPL-2.0
|
||
|
|
||
|
package client
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/hashicorp/nomad/ci"
|
||
|
"github.com/hashicorp/nomad/client/allocdir"
|
||
|
"github.com/hashicorp/nomad/client/allocrunner/interfaces"
|
||
|
"github.com/hashicorp/nomad/client/allocrunner/state"
|
||
|
"github.com/hashicorp/nomad/client/config"
|
||
|
cinterfaces "github.com/hashicorp/nomad/client/interfaces"
|
||
|
"github.com/hashicorp/nomad/client/pluginmanager/drivermanager"
|
||
|
cstructs "github.com/hashicorp/nomad/client/structs"
|
||
|
"github.com/hashicorp/nomad/nomad/mock"
|
||
|
"github.com/hashicorp/nomad/nomad/structs"
|
||
|
"github.com/hashicorp/nomad/plugins/device"
|
||
|
"github.com/hashicorp/nomad/plugins/drivers"
|
||
|
"github.com/hashicorp/nomad/testutil"
|
||
|
)
|
||
|
|
||
|
// TestEmptyAllocRunner demonstrates the minimum interface necessary to
|
||
|
// implement a mock AllocRunner that can report client status back to the server
|
||
|
func TestEmptyAllocRunner(t *testing.T) {
|
||
|
ci.Parallel(t)
|
||
|
|
||
|
s1, _, cleanupS1 := testServer(t, nil)
|
||
|
defer cleanupS1()
|
||
|
|
||
|
_, cleanup := TestClient(t, func(c *config.Config) {
|
||
|
c.RPCHandler = s1
|
||
|
c.AllocRunnerFactory = newEmptyAllocRunnerFunc
|
||
|
})
|
||
|
defer cleanup()
|
||
|
|
||
|
job := mock.Job()
|
||
|
job.Constraints = nil
|
||
|
job.TaskGroups[0].Constraints = nil
|
||
|
job.TaskGroups[0].Count = 1
|
||
|
task := job.TaskGroups[0].Tasks[0]
|
||
|
task.Driver = "mock_driver"
|
||
|
task.Config = map[string]interface{}{
|
||
|
"run_for": "10s",
|
||
|
}
|
||
|
task.Services = nil
|
||
|
|
||
|
// WaitForRunning polls the server until the ClientStatus is running
|
||
|
testutil.WaitForRunning(t, s1.RPC, job)
|
||
|
}
|
||
|
|
||
|
type emptyAllocRunner struct {
|
||
|
c cinterfaces.AllocStateHandler
|
||
|
alloc *structs.Allocation
|
||
|
allocState *state.State
|
||
|
allocLock sync.RWMutex
|
||
|
}
|
||
|
|
||
|
func newEmptyAllocRunnerFunc(conf *config.AllocRunnerConfig) (interfaces.AllocRunner, error) {
|
||
|
return &emptyAllocRunner{
|
||
|
c: conf.StateUpdater,
|
||
|
alloc: conf.Alloc,
|
||
|
allocState: &state.State{},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Alloc() *structs.Allocation {
|
||
|
ar.allocLock.RLock()
|
||
|
defer ar.allocLock.RUnlock()
|
||
|
return ar.alloc.Copy()
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Run() {
|
||
|
ar.allocLock.RLock()
|
||
|
defer ar.allocLock.RUnlock()
|
||
|
ar.alloc.ClientStatus = "running"
|
||
|
ar.c.AllocStateUpdated(ar.alloc)
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Restore() error { return nil }
|
||
|
func (ar *emptyAllocRunner) Update(update *structs.Allocation) {
|
||
|
ar.allocLock.Lock()
|
||
|
defer ar.allocLock.Unlock()
|
||
|
ar.alloc = update
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Reconnect(update *structs.Allocation) error {
|
||
|
ar.allocLock.Lock()
|
||
|
defer ar.allocLock.Unlock()
|
||
|
ar.alloc = update
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Shutdown() {}
|
||
|
func (ar *emptyAllocRunner) Destroy() {}
|
||
|
|
||
|
func (ar *emptyAllocRunner) IsDestroyed() bool { return false }
|
||
|
func (ar *emptyAllocRunner) IsMigrating() bool { return false }
|
||
|
func (ar *emptyAllocRunner) IsWaiting() bool { return false }
|
||
|
|
||
|
func (ar *emptyAllocRunner) WaitCh() <-chan struct{} { return make(chan struct{}) }
|
||
|
|
||
|
func (ar *emptyAllocRunner) DestroyCh() <-chan struct{} {
|
||
|
ch := make(chan struct{})
|
||
|
close(ch)
|
||
|
return ch
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) ShutdownCh() <-chan struct{} {
|
||
|
ch := make(chan struct{})
|
||
|
close(ch)
|
||
|
return ch
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) AllocState() *state.State {
|
||
|
ar.allocLock.RLock()
|
||
|
defer ar.allocLock.RUnlock()
|
||
|
return ar.allocState.Copy()
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) PersistState() error { return nil }
|
||
|
func (ar *emptyAllocRunner) AcknowledgeState(*state.State) {}
|
||
|
func (ar *emptyAllocRunner) LastAcknowledgedStateIsCurrent(*structs.Allocation) bool { return false }
|
||
|
|
||
|
func (ar *emptyAllocRunner) SetClientStatus(status string) {
|
||
|
ar.allocLock.Lock()
|
||
|
defer ar.allocLock.Unlock()
|
||
|
ar.alloc.ClientStatus = status
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) Signal(taskName, signal string) error { return nil }
|
||
|
func (ar *emptyAllocRunner) RestartTask(taskName string, taskEvent *structs.TaskEvent) error {
|
||
|
return nil
|
||
|
}
|
||
|
func (ar *emptyAllocRunner) RestartRunning(taskEvent *structs.TaskEvent) error { return nil }
|
||
|
func (ar *emptyAllocRunner) RestartAll(taskEvent *structs.TaskEvent) error { return nil }
|
||
|
|
||
|
func (ar *emptyAllocRunner) GetTaskEventHandler(taskName string) drivermanager.EventHandler {
|
||
|
return nil
|
||
|
}
|
||
|
func (ar *emptyAllocRunner) GetTaskExecHandler(taskName string) drivermanager.TaskExecHandler {
|
||
|
return nil
|
||
|
}
|
||
|
func (ar *emptyAllocRunner) GetTaskDriverCapabilities(taskName string) (*drivers.Capabilities, error) {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
func (ar *emptyAllocRunner) StatsReporter() interfaces.AllocStatsReporter { return ar }
|
||
|
func (ar *emptyAllocRunner) Listener() *cstructs.AllocListener { return nil }
|
||
|
func (ar *emptyAllocRunner) GetAllocDir() *allocdir.AllocDir { return nil }
|
||
|
|
||
|
// LatestAllocStats lets this empty runner implement AllocStatsReporter
|
||
|
func (ar *emptyAllocRunner) LatestAllocStats(taskFilter string) (*cstructs.AllocResourceUsage, error) {
|
||
|
return &cstructs.AllocResourceUsage{
|
||
|
ResourceUsage: &cstructs.ResourceUsage{
|
||
|
MemoryStats: &cstructs.MemoryStats{},
|
||
|
CpuStats: &cstructs.CpuStats{},
|
||
|
DeviceStats: []*device.DeviceGroupStats{},
|
||
|
},
|
||
|
Tasks: map[string]*cstructs.TaskResourceUsage{},
|
||
|
Timestamp: 0,
|
||
|
}, nil
|
||
|
}
|