mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
Tools like `nomad-nodesim` are unable to implement a minimal implementation of an allocrunner so that we can test the client communication without having to lug around the entire allocrunner/taskrunner code base. The allocrunner was implemented with an interface specifically for this purpose, but there were circular imports that made it challenging to use in practice. Move the AllocRunner interface into an inner package and provide a factory function type. Provide a minimal test that exercises the new function so that consumers have some idea of what the minimum implementation required is.
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
|
|
}
|