diff --git a/addon/flamenco/comms.py b/addon/flamenco/comms.py index d69e5b9e..78bdc7f3 100644 --- a/addon/flamenco/comms.py +++ b/addon/flamenco/comms.py @@ -4,6 +4,7 @@ import logging import dataclasses +import platform from typing import TYPE_CHECKING, Optional from urllib3.exceptions import HTTPError, MaxRetryError @@ -16,20 +17,20 @@ if TYPE_CHECKING: from flamenco.manager import ApiClient as _ApiClient from flamenco.manager.models import ( FlamencoVersion as _FlamencoVersion, - ManagerConfiguration as _ManagerConfiguration, + SharedStorageLocation as _SharedStorageLocation, ) from .preferences import FlamencoPreferences as _FlamencoPreferences else: _ApiClient = object _FlamencoPreferences = object _FlamencoVersion = object - _ManagerConfiguration = object + _SharedStorageLocation = object @dataclasses.dataclass(frozen=True) class ManagerInfo: version: Optional[_FlamencoVersion] = None - config: Optional[_ManagerConfiguration] = None + storage: Optional[_SharedStorageLocation] = None error: str = "" @classmethod @@ -38,9 +39,9 @@ class ManagerInfo: @classmethod def with_info( - cls, version: _FlamencoVersion, config: _ManagerConfiguration + cls, version: _FlamencoVersion, storage: _SharedStorageLocation ) -> "ManagerInfo": - return cls(version=version, config=config) + return cls(version=version, storage=storage) def flamenco_api_client(manager_url: str) -> _ApiClient: @@ -120,13 +121,14 @@ def ping_manager( # Do a late import, so that the API is only imported when actually used. from flamenco.manager import ApiException from flamenco.manager.apis import MetaApi - from flamenco.manager.models import FlamencoVersion, ManagerConfiguration + from flamenco.manager.models import FlamencoVersion, SharedStorageLocation meta_api = MetaApi(api_client) error = "" try: version: FlamencoVersion = meta_api.get_version() - config: ManagerConfiguration = meta_api.get_configuration() + storage: SharedStorageLocation = meta_api.get_shared_storage( + "users", platform.system().lower()) except ApiException as ex: error = "Manager cannot be reached: %s" % ex except MaxRetryError as ex: @@ -142,10 +144,10 @@ def ping_manager( return ManagerInfo.with_error(error) # Store whether this Manager supports the Shaman API. - prefs.is_shaman_enabled = config.shaman_enabled - prefs.job_storage = config.storage_location + prefs.is_shaman_enabled = storage.shaman_enabled + prefs.job_storage = storage.location report = "%s version %s found" % (version.name, version.version) window_manager.flamenco_status_ping = report - return ManagerInfo.with_info(version, config) + return ManagerInfo.with_info(version, storage) diff --git a/internal/manager/api_impl/meta.go b/internal/manager/api_impl/meta.go index a174e443..6cf08b20 100644 --- a/internal/manager/api_impl/meta.go +++ b/internal/manager/api_impl/meta.go @@ -68,6 +68,24 @@ func (f *Flamenco) GetVariables(e echo.Context, audience api.ManagerVariableAudi return e.JSON(http.StatusOK, apiVars) } +func (f *Flamenco) GetSharedStorage(e echo.Context, audience api.ManagerVariableAudience, platform string) error { + location := f.config.EffectiveStoragePath() + + feeder := make(chan string, 1) + receiver := make(chan string, 1) + + feeder <- location + close(feeder) + f.config.ExpandVariables(feeder, receiver, config.VariableAudience(audience), config.VariablePlatform(platform)) + + return e.JSON(http.StatusOK, api.SharedStorageLocation{ + Audience: audience, + Platform: platform, + Location: <-receiver, + ShamanEnabled: f.isShamanEnabled(), + }) +} + func (f *Flamenco) CheckSharedStoragePath(e echo.Context) error { logger := requestLogger(e) diff --git a/internal/manager/api_impl/meta_test.go b/internal/manager/api_impl/meta_test.go index f6e5e195..18783cef 100644 --- a/internal/manager/api_impl/meta_test.go +++ b/internal/manager/api_impl/meta_test.go @@ -15,6 +15,7 @@ import ( "github.com/golang/mock/gomock" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGetVariables(t *testing.T) { @@ -64,6 +65,89 @@ func TestGetVariables(t *testing.T) { } } +func TestGetSharedStorage(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mf := newMockedFlamenco(mockCtrl) + + conf := config.GetTestConfig(func(c *config.Conf) { + // Test with a Manager on Windows. + c.MockCurrentGOOSForTests("windows") + + // Set up a two-way variable to do the mapping. + c.Variables["shared_storage_mapping"] = config.Variable{ + IsTwoWay: true, + Values: []config.VariableValue{ + {Value: "/user/shared/storage", Platform: config.VariablePlatformLinux, Audience: config.VariableAudienceUsers}, + {Value: "/worker/shared/storage", Platform: config.VariablePlatformLinux, Audience: config.VariableAudienceWorkers}, + {Value: `S:\storage`, Platform: config.VariablePlatformWindows, Audience: config.VariableAudienceAll}, + }, + } + }) + mf.config.EXPECT().Get().Return(&conf).AnyTimes() + mf.config.EXPECT().EffectiveStoragePath().Return(`S:\storage\flamenco`).AnyTimes() + + { // Test user client on Linux. + mf.config.EXPECT(). + ExpandVariables(gomock.Any(), gomock.Any(), config.VariableAudienceUsers, config.VariablePlatformLinux). + Do(func(inputChannel <-chan string, outputChannel chan<- string, audience config.VariableAudience, platform config.VariablePlatform) { + // Defer to the actual ExpandVariables() implementation of the above config. + conf.ExpandVariables(inputChannel, outputChannel, audience, platform) + }) + mf.shaman.EXPECT().IsEnabled().Return(false) + + echoCtx := mf.prepareMockedRequest(nil) + err := mf.flamenco.GetSharedStorage(echoCtx, api.ManagerVariableAudienceUsers, "linux") + require.NoError(t, err) + assertResponseJSON(t, echoCtx, http.StatusOK, api.SharedStorageLocation{ + Location: "/user/shared/storage/flamenco", + Audience: api.ManagerVariableAudienceUsers, + Platform: "linux", + }) + } + + { // Test worker client on Linux with Shaman enabled. + mf.config.EXPECT(). + ExpandVariables(gomock.Any(), gomock.Any(), config.VariableAudienceWorkers, config.VariablePlatformLinux). + Do(func(inputChannel <-chan string, outputChannel chan<- string, audience config.VariableAudience, platform config.VariablePlatform) { + // Defer to the actual ExpandVariables() implementation of the above config. + conf.ExpandVariables(inputChannel, outputChannel, audience, platform) + }) + mf.shaman.EXPECT().IsEnabled().Return(true) + + echoCtx := mf.prepareMockedRequest(nil) + err := mf.flamenco.GetSharedStorage(echoCtx, api.ManagerVariableAudienceWorkers, "linux") + require.NoError(t, err) + assertResponseJSON(t, echoCtx, http.StatusOK, api.SharedStorageLocation{ + Location: "/worker/shared/storage/flamenco", + Audience: api.ManagerVariableAudienceWorkers, + Platform: "linux", + ShamanEnabled: true, + }) + } + + { // Test user client on Windows. + mf.config.EXPECT(). + ExpandVariables(gomock.Any(), gomock.Any(), config.VariableAudienceUsers, config.VariablePlatformWindows). + Do(func(inputChannel <-chan string, outputChannel chan<- string, audience config.VariableAudience, platform config.VariablePlatform) { + // Defer to the actual ExpandVariables() implementation of the above config. + conf.ExpandVariables(inputChannel, outputChannel, audience, platform) + }) + mf.shaman.EXPECT().IsEnabled().Return(false) + + echoCtx := mf.prepareMockedRequest(nil) + err := mf.flamenco.GetSharedStorage(echoCtx, api.ManagerVariableAudienceUsers, "windows") + require.NoError(t, err) + assertResponseJSON(t, echoCtx, http.StatusOK, api.SharedStorageLocation{ + Location: `S:\storage\flamenco`, + Audience: api.ManagerVariableAudienceUsers, + Platform: "windows", + }) + } + +} + func TestCheckSharedStoragePath(t *testing.T) { mf, finish := metaTestFixtures(t) defer finish() diff --git a/internal/manager/api_impl/support_test.go b/internal/manager/api_impl/support_test.go index 23a5d27c..97e660ee 100644 --- a/internal/manager/api_impl/support_test.go +++ b/internal/manager/api_impl/support_test.go @@ -70,6 +70,7 @@ func newMockedFlamenco(mockCtrl *gomock.Controller) mockedFlamenco { logStorage: logStore, config: cs, stateMachine: sm, + shaman: sha, clock: clock, lastRender: lr, localStorage: localStore,