Add architecture for multiple managers
using the chain of responsibility pattern.
This commit is contained in:
40
internal/environment/abstract_manager.go
Normal file
40
internal/environment/abstract_manager.go
Normal file
@ -0,0 +1,40 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
"github.com/openHPI/poseidon/internal/runner"
|
||||
"github.com/openHPI/poseidon/pkg/dto"
|
||||
)
|
||||
|
||||
// AbstractManager is used to have a fallback environment manager in the chain of responsibility
|
||||
// following the null object pattern.
|
||||
type AbstractManager struct {
|
||||
nextHandler ManagerHandler
|
||||
}
|
||||
|
||||
func (n *AbstractManager) SetNextHandler(next ManagerHandler) {
|
||||
n.nextHandler = next
|
||||
}
|
||||
|
||||
func (n *AbstractManager) NextHandler() ManagerHandler {
|
||||
return n.nextHandler
|
||||
}
|
||||
|
||||
func (n *AbstractManager) List(_ bool) ([]runner.ExecutionEnvironment, error) {
|
||||
return []runner.ExecutionEnvironment{}, nil
|
||||
}
|
||||
|
||||
func (n *AbstractManager) Get(_ dto.EnvironmentID, _ bool) (runner.ExecutionEnvironment, error) {
|
||||
return nil, runner.ErrNullObject
|
||||
}
|
||||
|
||||
func (n *AbstractManager) CreateOrUpdate(_ dto.EnvironmentID, _ dto.ExecutionEnvironmentRequest) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (n *AbstractManager) Delete(_ dto.EnvironmentID) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (n *AbstractManager) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
return map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData{}
|
||||
}
|
57
internal/environment/aws_manager.go
Normal file
57
internal/environment/aws_manager.go
Normal file
@ -0,0 +1,57 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/openHPI/poseidon/internal/runner"
|
||||
"github.com/openHPI/poseidon/pkg/dto"
|
||||
)
|
||||
|
||||
// AWSEnvironmentManager contains no functionality at the moment.
|
||||
// IMPROVE: Create Lambda functions dynamically.
|
||||
type AWSEnvironmentManager struct {
|
||||
*AbstractManager
|
||||
runnerManager runner.Accessor
|
||||
}
|
||||
|
||||
func NewAWSEnvironmentManager(runnerManager runner.Accessor) *AWSEnvironmentManager {
|
||||
m := &AWSEnvironmentManager{&AbstractManager{nil}, runnerManager}
|
||||
runnerManager.Load()
|
||||
return m
|
||||
}
|
||||
|
||||
func (a *AWSEnvironmentManager) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
list, err := a.NextHandler().List(fetch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aws wraped: %w", err)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (a *AWSEnvironmentManager) Get(id dto.EnvironmentID, fetch bool) (runner.ExecutionEnvironment, error) {
|
||||
e, err := a.NextHandler().Get(id, fetch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aws wraped: %w", err)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (a *AWSEnvironmentManager) CreateOrUpdate(
|
||||
id dto.EnvironmentID, request dto.ExecutionEnvironmentRequest) (bool, error) {
|
||||
isCreated, err := a.NextHandler().CreateOrUpdate(id, request)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("aws wraped: %w", err)
|
||||
}
|
||||
return isCreated, nil
|
||||
}
|
||||
|
||||
func (a *AWSEnvironmentManager) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
isFound, err := a.NextHandler().Delete(id)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("aws wraped: %w", err)
|
||||
}
|
||||
return isFound, nil
|
||||
}
|
||||
|
||||
func (a *AWSEnvironmentManager) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
return a.NextHandler().Statistics()
|
||||
}
|
@ -1,30 +1,20 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/openHPI/poseidon/internal/nomad"
|
||||
"github.com/openHPI/poseidon/internal/runner"
|
||||
"github.com/openHPI/poseidon/pkg/dto"
|
||||
"github.com/openHPI/poseidon/pkg/logging"
|
||||
"os"
|
||||
)
|
||||
|
||||
// templateEnvironmentJobHCL holds our default job in HCL format.
|
||||
// The default job is used when creating new job and provides
|
||||
// common settings that all the jobs share.
|
||||
//go:embed template-environment-job.hcl
|
||||
var templateEnvironmentJobHCL string
|
||||
|
||||
var log = logging.GetLogger("environment")
|
||||
// ManagerHandler is one handler in the chain of responsibility of environment managers.
|
||||
// Each manager can handle different requests.
|
||||
type ManagerHandler interface {
|
||||
Manager
|
||||
SetNextHandler(next ManagerHandler)
|
||||
NextHandler() ManagerHandler
|
||||
}
|
||||
|
||||
// Manager encapsulates API calls to the executor API for creation and deletion of execution environments.
|
||||
type Manager interface {
|
||||
// Load fetches all already created execution environments from the executor and registers them at the runner manager.
|
||||
// It should be called during the startup process (e.g. on creation of the Manager).
|
||||
Load() error
|
||||
|
||||
// List returns all environments known by Poseidon.
|
||||
// When `fetch` is set the environments are fetched from the executor before returning.
|
||||
List(fetch bool) ([]runner.ExecutionEnvironment, error)
|
||||
@ -48,185 +38,3 @@ type Manager interface {
|
||||
// Statistics returns statistical data for each execution environment.
|
||||
Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData
|
||||
}
|
||||
|
||||
type NomadEnvironmentManager struct {
|
||||
runnerManager runner.Manager
|
||||
api nomad.ExecutorAPI
|
||||
templateEnvironmentHCL string
|
||||
}
|
||||
|
||||
func NewNomadEnvironmentManager(
|
||||
runnerManager runner.Manager,
|
||||
apiClient nomad.ExecutorAPI,
|
||||
templateJobFile string,
|
||||
) (*NomadEnvironmentManager, error) {
|
||||
if err := loadTemplateEnvironmentJobHCL(templateJobFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := &NomadEnvironmentManager{runnerManager, apiClient, templateEnvironmentJobHCL}
|
||||
if err := m.Load(); err != nil {
|
||||
log.WithError(err).Error("Error recovering the execution environments")
|
||||
}
|
||||
runnerManager.Load()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Get(id dto.EnvironmentID, fetch bool) (
|
||||
executionEnvironment runner.ExecutionEnvironment, err error) {
|
||||
executionEnvironment, ok := m.runnerManager.GetEnvironment(id)
|
||||
|
||||
if fetch {
|
||||
fetchedEnvironment, err := fetchEnvironment(id, m.api)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case fetchedEnvironment == nil:
|
||||
_, err = m.Delete(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok = false
|
||||
case !ok:
|
||||
m.runnerManager.StoreEnvironment(fetchedEnvironment)
|
||||
executionEnvironment = fetchedEnvironment
|
||||
ok = true
|
||||
default:
|
||||
executionEnvironment.SetConfigFrom(fetchedEnvironment)
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
err = runner.ErrUnknownExecutionEnvironment
|
||||
}
|
||||
return executionEnvironment, err
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
if fetch {
|
||||
err := m.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return m.runnerManager.ListEnvironments(), nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) CreateOrUpdate(id dto.EnvironmentID, request dto.ExecutionEnvironmentRequest) (
|
||||
created bool, err error) {
|
||||
// Check if execution environment is already existing (in the local memory).
|
||||
environment, isExistingEnvironment := m.runnerManager.GetEnvironment(id)
|
||||
if isExistingEnvironment {
|
||||
// Remove existing environment to force downloading the newest Docker image.
|
||||
// See https://github.com/openHPI/poseidon/issues/69
|
||||
err = environment.Delete(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to remove the environment: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new environment with the given request options.
|
||||
environment, err = NewNomadEnvironmentFromRequest(m.templateEnvironmentHCL, id, request)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error creating Nomad environment: %w", err)
|
||||
}
|
||||
|
||||
// Keep a copy of environment specification in memory.
|
||||
m.runnerManager.StoreEnvironment(environment)
|
||||
|
||||
// Register template Job with Nomad.
|
||||
err = environment.Register(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error registering template job in API: %w", err)
|
||||
}
|
||||
|
||||
// Launch idle runners based on the template job.
|
||||
err = environment.ApplyPrewarmingPoolSize(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error scaling template job in API: %w", err)
|
||||
}
|
||||
|
||||
return !isExistingEnvironment, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
executionEnvironment, ok := m.runnerManager.GetEnvironment(id)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
m.runnerManager.DeleteEnvironment(id)
|
||||
err := executionEnvironment.Delete(m.api)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("could not delete environment: %w", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
return m.runnerManager.EnvironmentStatistics()
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Load() error {
|
||||
templateJobs, err := m.api.LoadEnvironmentJobs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load template jobs: %w", err)
|
||||
}
|
||||
|
||||
for _, job := range templateJobs {
|
||||
jobLogger := log.WithField("jobID", *job.ID)
|
||||
if *job.Status != structs.JobStatusRunning {
|
||||
jobLogger.Info("Job not running, skipping ...")
|
||||
continue
|
||||
}
|
||||
configTaskGroup := nomad.FindAndValidateConfigTaskGroup(job)
|
||||
if configTaskGroup == nil {
|
||||
jobLogger.Info("Couldn't find config task group in job, skipping ...")
|
||||
continue
|
||||
}
|
||||
environment := &NomadEnvironment{
|
||||
jobHCL: templateEnvironmentJobHCL,
|
||||
job: job,
|
||||
idleRunners: runner.NewLocalRunnerStorage(),
|
||||
}
|
||||
m.runnerManager.StoreEnvironment(environment)
|
||||
jobLogger.Info("Successfully recovered environment")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadTemplateEnvironmentJobHCL loads the template environment job HCL from the given path.
|
||||
// If the path is empty, the embedded default file is used.
|
||||
func loadTemplateEnvironmentJobHCL(path string) error {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading template environment job: %w", err)
|
||||
}
|
||||
templateEnvironmentJobHCL = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchEnvironment(id dto.EnvironmentID, apiClient nomad.ExecutorAPI) (runner.ExecutionEnvironment, error) {
|
||||
environments, err := apiClient.LoadEnvironmentJobs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching the environment jobs: %w", err)
|
||||
}
|
||||
var fetchedEnvironment runner.ExecutionEnvironment
|
||||
for _, job := range environments {
|
||||
environmentID, err := nomad.EnvironmentIDFromTemplateJobID(*job.ID)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Cannot parse environment id of loaded environment")
|
||||
continue
|
||||
}
|
||||
if id == environmentID {
|
||||
fetchedEnvironment = &NomadEnvironment{
|
||||
jobHCL: templateEnvironmentJobHCL,
|
||||
job: job,
|
||||
idleRunners: runner.NewLocalRunnerStorage(),
|
||||
}
|
||||
}
|
||||
}
|
||||
return fetchedEnvironment, nil
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ import (
|
||||
runner "github.com/openHPI/poseidon/internal/runner"
|
||||
)
|
||||
|
||||
// ManagerMock is an autogenerated mock type for the Manager type
|
||||
type ManagerMock struct {
|
||||
// ManagerHandlerMock is an autogenerated mock type for the ManagerHandler type
|
||||
type ManagerHandlerMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateOrUpdate provides a mock function with given fields: id, request
|
||||
func (_m *ManagerMock) CreateOrUpdate(id dto.EnvironmentID, request dto.ExecutionEnvironmentRequest) (bool, error) {
|
||||
func (_m *ManagerHandlerMock) CreateOrUpdate(id dto.EnvironmentID, request dto.ExecutionEnvironmentRequest) (bool, error) {
|
||||
ret := _m.Called(id, request)
|
||||
|
||||
var r0 bool
|
||||
@ -36,7 +36,7 @@ func (_m *ManagerMock) CreateOrUpdate(id dto.EnvironmentID, request dto.Executio
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: id
|
||||
func (_m *ManagerMock) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
func (_m *ManagerHandlerMock) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
ret := _m.Called(id)
|
||||
|
||||
var r0 bool
|
||||
@ -57,7 +57,7 @@ func (_m *ManagerMock) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: id, fetch
|
||||
func (_m *ManagerMock) Get(id dto.EnvironmentID, fetch bool) (runner.ExecutionEnvironment, error) {
|
||||
func (_m *ManagerHandlerMock) Get(id dto.EnvironmentID, fetch bool) (runner.ExecutionEnvironment, error) {
|
||||
ret := _m.Called(id, fetch)
|
||||
|
||||
var r0 runner.ExecutionEnvironment
|
||||
@ -80,7 +80,7 @@ func (_m *ManagerMock) Get(id dto.EnvironmentID, fetch bool) (runner.ExecutionEn
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: fetch
|
||||
func (_m *ManagerMock) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
func (_m *ManagerHandlerMock) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
ret := _m.Called(fetch)
|
||||
|
||||
var r0 []runner.ExecutionEnvironment
|
||||
@ -102,22 +102,29 @@ func (_m *ManagerMock) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Load provides a mock function with given fields:
|
||||
func (_m *ManagerMock) Load() error {
|
||||
// NextHandler provides a mock function with given fields:
|
||||
func (_m *ManagerHandlerMock) NextHandler() ManagerHandler {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func() error); ok {
|
||||
var r0 ManagerHandler
|
||||
if rf, ok := ret.Get(0).(func() ManagerHandler); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(ManagerHandler)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetNextHandler provides a mock function with given fields: m
|
||||
func (_m *ManagerHandlerMock) SetNextHandler(m ManagerHandler) {
|
||||
_m.Called(m)
|
||||
}
|
||||
|
||||
// Statistics provides a mock function with given fields:
|
||||
func (_m *ManagerMock) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
func (_m *ManagerHandlerMock) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData
|
204
internal/environment/nomad_manager.go
Normal file
204
internal/environment/nomad_manager.go
Normal file
@ -0,0 +1,204 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/openHPI/poseidon/internal/nomad"
|
||||
"github.com/openHPI/poseidon/internal/runner"
|
||||
"github.com/openHPI/poseidon/pkg/dto"
|
||||
"github.com/openHPI/poseidon/pkg/logging"
|
||||
"os"
|
||||
)
|
||||
|
||||
// templateEnvironmentJobHCL holds our default job in HCL format.
|
||||
// The default job is used when creating new job and provides
|
||||
// common settings that all the jobs share.
|
||||
//go:embed template-environment-job.hcl
|
||||
var templateEnvironmentJobHCL string
|
||||
|
||||
var log = logging.GetLogger("environment")
|
||||
|
||||
type NomadEnvironmentManager struct {
|
||||
*AbstractManager
|
||||
runnerManager runner.Manager
|
||||
api nomad.ExecutorAPI
|
||||
templateEnvironmentHCL string
|
||||
}
|
||||
|
||||
func NewNomadEnvironmentManager(
|
||||
runnerManager runner.Manager,
|
||||
apiClient nomad.ExecutorAPI,
|
||||
templateJobFile string,
|
||||
) (*NomadEnvironmentManager, error) {
|
||||
if err := loadTemplateEnvironmentJobHCL(templateJobFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := &NomadEnvironmentManager{&AbstractManager{nil}, runnerManager,
|
||||
apiClient, templateEnvironmentJobHCL}
|
||||
if err := m.Load(); err != nil {
|
||||
log.WithError(err).Error("Error recovering the execution environments")
|
||||
}
|
||||
runnerManager.Load()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Get(id dto.EnvironmentID, fetch bool) (
|
||||
executionEnvironment runner.ExecutionEnvironment, err error) {
|
||||
executionEnvironment, ok := m.runnerManager.GetEnvironment(id)
|
||||
|
||||
if fetch {
|
||||
fetchedEnvironment, err := fetchEnvironment(id, m.api)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case fetchedEnvironment == nil:
|
||||
_, err = m.Delete(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok = false
|
||||
case !ok:
|
||||
m.runnerManager.StoreEnvironment(fetchedEnvironment)
|
||||
executionEnvironment = fetchedEnvironment
|
||||
ok = true
|
||||
default:
|
||||
executionEnvironment.SetConfigFrom(fetchedEnvironment)
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
err = runner.ErrUnknownExecutionEnvironment
|
||||
}
|
||||
return executionEnvironment, err
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) List(fetch bool) ([]runner.ExecutionEnvironment, error) {
|
||||
if fetch {
|
||||
err := m.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return m.runnerManager.ListEnvironments(), nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) CreateOrUpdate(id dto.EnvironmentID, request dto.ExecutionEnvironmentRequest) (
|
||||
created bool, err error) {
|
||||
// Check if execution environment is already existing (in the local memory).
|
||||
environment, isExistingEnvironment := m.runnerManager.GetEnvironment(id)
|
||||
if isExistingEnvironment {
|
||||
// Remove existing environment to force downloading the newest Docker image.
|
||||
// See https://github.com/openHPI/poseidon/issues/69
|
||||
err = environment.Delete(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to remove the environment: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new environment with the given request options.
|
||||
environment, err = NewNomadEnvironmentFromRequest(m.templateEnvironmentHCL, id, request)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error creating Nomad environment: %w", err)
|
||||
}
|
||||
|
||||
// Keep a copy of environment specification in memory.
|
||||
m.runnerManager.StoreEnvironment(environment)
|
||||
|
||||
// Register template Job with Nomad.
|
||||
err = environment.Register(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error registering template job in API: %w", err)
|
||||
}
|
||||
|
||||
// Launch idle runners based on the template job.
|
||||
err = environment.ApplyPrewarmingPoolSize(m.api)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error scaling template job in API: %w", err)
|
||||
}
|
||||
|
||||
return !isExistingEnvironment, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Delete(id dto.EnvironmentID) (bool, error) {
|
||||
executionEnvironment, ok := m.runnerManager.GetEnvironment(id)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
m.runnerManager.DeleteEnvironment(id)
|
||||
err := executionEnvironment.Delete(m.api)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("could not delete environment: %w", err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Statistics() map[dto.EnvironmentID]*dto.StatisticalExecutionEnvironmentData {
|
||||
return m.runnerManager.EnvironmentStatistics()
|
||||
}
|
||||
|
||||
func (m *NomadEnvironmentManager) Load() error {
|
||||
templateJobs, err := m.api.LoadEnvironmentJobs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load template jobs: %w", err)
|
||||
}
|
||||
|
||||
for _, job := range templateJobs {
|
||||
jobLogger := log.WithField("jobID", *job.ID)
|
||||
if *job.Status != structs.JobStatusRunning {
|
||||
jobLogger.Info("Job not running, skipping ...")
|
||||
continue
|
||||
}
|
||||
configTaskGroup := nomad.FindAndValidateConfigTaskGroup(job)
|
||||
if configTaskGroup == nil {
|
||||
jobLogger.Info("Couldn't find config task group in job, skipping ...")
|
||||
continue
|
||||
}
|
||||
environment := &NomadEnvironment{
|
||||
jobHCL: templateEnvironmentJobHCL,
|
||||
job: job,
|
||||
idleRunners: runner.NewLocalRunnerStorage(),
|
||||
}
|
||||
m.runnerManager.StoreEnvironment(environment)
|
||||
jobLogger.Info("Successfully recovered environment")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadTemplateEnvironmentJobHCL loads the template environment job HCL from the given path.
|
||||
// If the path is empty, the embedded default file is used.
|
||||
func loadTemplateEnvironmentJobHCL(path string) error {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading template environment job: %w", err)
|
||||
}
|
||||
templateEnvironmentJobHCL = string(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchEnvironment(id dto.EnvironmentID, apiClient nomad.ExecutorAPI) (runner.ExecutionEnvironment, error) {
|
||||
environments, err := apiClient.LoadEnvironmentJobs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching the environment jobs: %w", err)
|
||||
}
|
||||
var fetchedEnvironment runner.ExecutionEnvironment
|
||||
for _, job := range environments {
|
||||
environmentID, err := nomad.EnvironmentIDFromTemplateJobID(*job.ID)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Cannot parse environment id of loaded environment")
|
||||
continue
|
||||
}
|
||||
if id == environmentID {
|
||||
fetchedEnvironment = &NomadEnvironment{
|
||||
jobHCL: templateEnvironmentJobHCL,
|
||||
job: job,
|
||||
idleRunners: runner.NewLocalRunnerStorage(),
|
||||
}
|
||||
}
|
||||
}
|
||||
return fetchedEnvironment, nil
|
||||
}
|
Reference in New Issue
Block a user