diff --git a/internal/daemon/common/worker_list.go b/internal/daemon/common/worker_list.go index ba9ee995a..bf57b1492 100644 --- a/internal/daemon/common/worker_list.go +++ b/internal/daemon/common/worker_list.go @@ -102,3 +102,33 @@ func SeparateManagedWorkers(workers WorkerList) (managedWorkers, nonManagedWorke func IsManagedWorker(worker *server.Worker) bool { return len(worker.CanonicalTags()[ManagedWorkerTag]) != 0 } + +// FilterWorkersByLocalStorageState filters the workers by their local storage state. +// Workers that support local storage state feature will be considered healthy if their +// local storage state is Available. +// If the worker does not have any workers in the Available local storage state, it +// will return workers with Unknown local storage state. +// Workers that do not support local storage state will be considered healthy. +func FilterWorkersByLocalStorageState(workers WorkerList) (healthyWorkers WorkerList) { + availableWorkers := make([]*server.Worker, 0, len(workers)) + unknownWorkers := make([]*server.Worker, 0, len(workers)) + + for _, worker := range workers { + sv := version.FromVersionString(worker.GetReleaseVersion()).Semver() + if version.SupportsFeature(sv, version.LocalStorageState) { + ls := worker.GetLocalStorageState() + if ls == server.AvailableLocalStorageState.String() { + availableWorkers = append(availableWorkers, worker) + } else if ls == server.UnknownLocalStorageState.String() { + unknownWorkers = append(unknownWorkers, worker) + } + } else { + availableWorkers = append(availableWorkers, worker) + } + } + + if len(availableWorkers) > 0 { + return availableWorkers + } + return unknownWorkers +} diff --git a/internal/daemon/controller/handlers/workers/worker_service_test.go b/internal/daemon/controller/handlers/workers/worker_service_test.go index 8ff9e092d..7bb3daaa9 100644 --- a/internal/daemon/controller/handlers/workers/worker_service_test.go +++ b/internal/daemon/controller/handlers/workers/worker_service_test.go @@ -354,6 +354,7 @@ func TestList(t *testing.T) { LastStatusTime: w.GetLastStatusTime().GetTimestamp(), ReleaseVersion: w.ReleaseVersion, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }) } @@ -375,6 +376,7 @@ func TestList(t *testing.T) { LastStatusTime: w.GetLastStatusTime().GetTimestamp(), ReleaseVersion: w.ReleaseVersion, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }) } @@ -650,6 +652,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } }, @@ -679,6 +682,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } }, @@ -750,6 +754,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } }, @@ -776,6 +781,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } // In the previous test, the name will now be blank if it's the @@ -810,6 +816,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } // The name will not be updated if it's the pki-kms worker @@ -844,6 +851,7 @@ func TestUpdate(t *testing.T) { AuthorizedActions: testAuthorizedActions, Type: PkiWorkerType, DirectlyConnectedDownstreamWorkers: connectedDownstreams, + LocalStorageState: server.UnknownLocalStorageState.String(), }, } // The name will not have been updated previously if it's the pki-kms worker @@ -1584,6 +1592,7 @@ func TestCreateWorkerLed(t *testing.T) { tc.res.Item.UpdatedTime = got.GetItem().GetUpdatedTime() tc.res.Item.Scope = got.GetItem().Scope tc.res.Item.AuthorizedActions = got.GetItem().GetAuthorizedActions() + tc.res.Item.LocalStorageState = got.GetItem().GetLocalStorageState() } } assert.Equal(tc.res, got) @@ -1931,6 +1940,7 @@ func TestCreateControllerLed(t *testing.T) { tc.res.Item.Scope = got.GetItem().Scope tc.res.Item.AuthorizedActions = got.GetItem().GetAuthorizedActions() tc.res.Item.ControllerGeneratedActivationToken = got.GetItem().GetControllerGeneratedActivationToken() + tc.res.Item.LocalStorageState = got.GetItem().GetLocalStorageState() } } assert.Equal(tc.res, got) diff --git a/internal/server/worker.go b/internal/server/worker.go index aa3b20442..6b57c4b1a 100644 --- a/internal/server/worker.go +++ b/internal/server/worker.go @@ -85,7 +85,8 @@ func ValidLocalStorageState(s string) bool { func (t LocalStorageState) String() string { switch t { case AvailableLocalStorageState, LowStorageLocalStorageState, - OutOfStorageLocalStorageState, NotConfiguredLocalStorageState: + OutOfStorageLocalStorageState, NotConfiguredLocalStorageState, + CriticallyLowStorageLocalStorageState: return string(t) } return string(UnknownLocalStorageState) diff --git a/version/feature_manager.go b/version/feature_manager.go index 3c33448de..6efd06747 100644 --- a/version/feature_manager.go +++ b/version/feature_manager.go @@ -23,6 +23,7 @@ const ( SshSessionRecording SupportIdInGrants PluginDelete + LocalStorageState ) var featureMap map[Feature]MetadataConstraint @@ -85,6 +86,11 @@ func init() { featureMap[PluginDelete] = MetadataConstraint{ Constraints: mustNewConstraints(">= 0.15.0"), } + + // Worker supports reporting local storage state + featureMap[LocalStorageState] = MetadataConstraint{ + Constraints: mustNewConstraints(">= 0.16.0"), + } } func mustNewConstraints(v string) gvers.Constraints {