Skip to content

Commit

Permalink
Version 0.7.0-dev.3 - WIP Commit
Browse files Browse the repository at this point in the history
- Moving computers again
  • Loading branch information
CCP-Zeulix committed Apr 11, 2024
1 parent 6a0c748 commit 975fe4d
Show file tree
Hide file tree
Showing 14 changed files with 220 additions and 29 deletions.
2 changes: 1 addition & 1 deletion fidelius/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.7.0-dev.2'
__version__ = '0.7.0-dev.3'

__author__ = 'Thordur Matthiasson <[email protected]>'
__license__ = 'MIT License'
Expand Down
5 changes: 2 additions & 3 deletions fidelius/fideliusapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from fidelius.structs.api import *
from fidelius.utils import *

from fidelius.gateway.paramstore import *
from fidelius.gateway.interface import *
from fidelius.gateway import FideliusFactory
20 changes: 20 additions & 0 deletions fidelius/gateway/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
__all__ = [
'FideliusFactory',
]

from fidelius.structs import *
from .interface import *
from ccptools.tpu import strimp

import logging
log = logging.getLogger(__name__)


class FideliusFactory:
@staticmethod
def get_class(impl: str = 'paramstore') -> Type[IFideliusRepo]:
return strimp.get_class(f'fidelius.gateway.{impl}._std.FideliusRepo', logger=log, reraise=True)

@staticmethod
def get_admin_class(impl: str = 'paramstore') -> Type[IFideliusAdminRepo]:
return strimp.get_class(f'fidelius.gateway.{impl}._std.FideliusAdmin', logger=log, reraise=True)
22 changes: 20 additions & 2 deletions fidelius/gateway/_abstract.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
__all__ = [
'_BaseFideliusRepo',
'_BaseFideliusAdminRepo',
]
from .interface import *

Expand All @@ -21,6 +22,7 @@ class _BaseFideliusRepo(IFideliusRepo, abc.ABC):
_EXPRESSION_PATTERN = re.compile(r'\${__FID__:(?:(?P<folder>\w+):)?(?P<name>[\w/-]+)}')

def __init__(self, app_props: FideliusAppProps, **kwargs):
log.debug('_BaseFideliusRepo.__init__')
self._app_props = app_props

# Any kwargs should have been handled by implementation specific stuff,
Expand All @@ -38,15 +40,15 @@ def app_props(self) -> FideliusAppProps:
def make_app_path(self, env: Optional[str] = None) -> str:
"""The full path to application specific parameters/secrets.
"""
return self._SHARED_PATH_FORMAT.format(group=self.app_props.group,
return self._APP_PATH_FORMAT.format(group=self.app_props.group,
env=env or self.app_props.env,
app=self.app_props.app,
name='{name}')

def make_shared_path(self, folder: str, env: Optional[str] = None) -> str:
"""The full path to group shared parameters/secrets.
"""
return self._APP_PATH_FORMAT.format(group=self.app_props.group,
return self._SHARED_PATH_FORMAT.format(group=self.app_props.group,
env=env or self.app_props.env,
folder=folder,
name='{name}')
Expand Down Expand Up @@ -155,3 +157,19 @@ def replace(self, string: str, no_default: bool = False) -> str:
if m:
return self.get(m.group('name'), m.group('folder'), no_default=no_default)
return string


class _BaseFideliusAdminRepo(_BaseFideliusRepo, IFideliusAdminRepo, abc.ABC):
"""Covers a lot of admin basic functionality common across most storage back-ends.
"""
def __init__(self, app_props: FideliusAppProps, tags: Optional[FideliusTags] = None, **kwargs):
log.debug('_BaseFideliusAdminRepo.__init__')
super().__init__(app_props, **kwargs)
self._tags = tags

@property
def tags(self) -> Optional[FideliusTags]:
return self._tags

def set_env(self, env: str):
self.app_props.env = env
6 changes: 3 additions & 3 deletions fidelius/gateway/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def __init__(self, app_props: FideliusAppProps, **kwargs):
"""
pass

@abc.abstractmethod
@property
@abc.abstractmethod
def app_props(self) -> FideliusAppProps:
"""The current application properties.
"""
Expand Down Expand Up @@ -151,9 +151,9 @@ def __init__(self, app_props: FideliusAppProps, tags: Optional[FideliusTags] = N
"""
pass

@abc.abstractmethod
@property
def tags(self) -> FideliusTags:
@abc.abstractmethod
def tags(self) -> Optional[FideliusTags]:
"""The tags to use when creating new parameters.
"""
pass
Expand Down
100 changes: 100 additions & 0 deletions fidelius/gateway/mock/_mockadmin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
__all__ = [
'MockFideliusAdmin',
]

from fidelius.gateway._abstract import *
from fidelius.structs import *

import logging
log = logging.getLogger(__name__)


class MockFideliusAdmin(_BaseFideliusAdminRepo):
def __init__(self, app_props: FideliusAppProps, tags: Optional[FideliusTags] = None, **kwargs):
"""This mock version of the Fidelius Admin stores created and updated
params in memory only.
Note that it does NOT extend the functionality of its non-Admin sibling,
the MockFideliusRepo and thus does not return a base64 encoded version
of every requested param/secret key name, but instead only uses its own
internal in-memory cache, and thus, `get` will not return anything that
hasn't been created first during that particular runtime.
This is mainly intended for unit testing other packages and apps that
use Fidelius.
"""
log.debug('MockFideliusAdmin.__init__')
super().__init__(app_props, tags, **kwargs)
self._cache = {}

def get_app_param(self, name: str, env: Optional[str] = None) -> Optional[str]:
return self._cache.get(self.get_full_path(name, env=env), None)

def get_shared_param(self, name: str, folder: str, env: Optional[str] = None) -> Optional[str]:
return self._cache.get(self.get_full_path(name, folder, env=env), None)

def _create(self, name: str, value: str, env: Optional[str] = None, folder: Optional[str] = None) -> (str, str):
key = self.get_full_path(name, folder=folder, env=env)
if key in self._cache:
raise FideliusParameterAlreadyExists(f'parameter already exists: {key}')
self._cache[key] = value
return key, self.get_expression_string(name, folder=folder)

def _update(self, name: str, value: str, env: Optional[str] = None, folder: Optional[str] = None) -> (str, str):
key = self.get_full_path(name, folder=folder, env=env)
if key not in self._cache:
raise FideliusParameterNotFound(f'parameter not found: {key}')
self._cache[key] = value
return key, self.get_expression_string(name, folder=folder)

def _delete(self, name: str, env: Optional[str] = None, folder: Optional[str] = None):
key = self.get_full_path(name, folder=folder, env=env)
if key not in self._cache:
raise FideliusParameterNotFound(f'parameter not found: {key}')
del self._cache[key]

def create_param(self, name: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._create(name, value=value, env=env)

def update_param(self, name: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._update(name, value=value, env=env)

def delete_param(self, name: str, env: Optional[str] = None):
self._delete(name, env=env)

def create_shared_param(self, name: str, folder: str, value: str,
description: Optional[str] = None,
env: Optional[str] = None) -> (str, str):
return self._create(name, value=value, env=env, folder=folder)

def update_shared_param(self, name: str, folder: str, value: str,
description: Optional[str] = None,
env: Optional[str] = None) -> (str, str):
return self._update(name, value=value, env=env, folder=folder)

def delete_shared_param(self, name: str, folder: str, env: Optional[str] = None):
self._delete(name, env=env, folder=folder)

def create_secret(self, name: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._create(name, value=value, env=env)

def update_secret(self, name: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._update(name, value=value, env=env)

def delete_secret(self, name: str, env: Optional[str] = None):
self._delete(name, env=env)

def create_shared_secret(self, name: str, folder: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._create(name, value=value, env=env, folder=folder)

def update_shared_secret(self, name: str, folder: str, value: str,
description: Optional[str] = None, env: Optional[str] = None) -> (str, str):
return self._update(name, value=value, env=env, folder=folder)

def delete_shared_secret(self, name: str, folder: str, env: Optional[str] = None):
self._delete(name, env=env, folder=folder)
34 changes: 15 additions & 19 deletions fidelius/gateway/mock/_mockrepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,27 @@
]

from fidelius.structs import *
from fidelius.gateway.interface import *
from fidelius.gateway._abstract import *

import json
import base64

import logging
log = logging.getLogger(__name__)


class MockFideliusRepo(IFideliusRepo):
_APP_FULL_NAME = '/fidelius/{group}/{env}/apps/{app}/{name}'
_SHARED_FULL_NAME = '/fidelius/{group}/{env}/shared/{folder}/{name}'
class MockFideliusRepo(_BaseFideliusRepo):
def __init__(self, app_props: FideliusAppProps, **kwargs):
"""This mock variation of the FideliusRepo simply returns a base64
encoded version of the full path of the requested parameter/secret.
def __init__(self, app: str, group: str, env: str, pre_seeded_cache: Optional[Union[dict, str]] = None, **kwargs):
super().__init__(app, group, env)
self._cache: Dict[str, str] = {}
self._loaded: bool = False
This is mainly intended for unit testing other packages and apps that
use Fidelius.
"""
log.debug('MockFideliusRepo.__init__')
super().__init__(app_props, **kwargs)

self._pre_seeded_cache = pre_seeded_cache
def get_app_param(self, name: str, env: Optional[str] = None) -> Optional[str]:
return base64.encodebytes(self.get_full_path(name, env=env).encode('utf-8')).decode('utf-8').strip()

def _load_all(self, folder: Optional[str] = None):
if isinstance(self._pre_seeded_cache, dict):
self._cache = self._pre_seeded_cache
elif isinstance(self._pre_seeded_cache, str) and self._pre_seeded_cache.lower().endswith('.json'):
with open(self._pre_seeded_cache, 'r') as fin:
self._cache = json.load(fin)

def get(self, name: str, folder: Optional[str] = None, no_default: bool = False) -> Optional[str]:
pass
def get_shared_param(self, name: str, folder: str, env: Optional[str] = None) -> Optional[str]:
return base64.encodebytes(self.get_full_path(name, folder=folder, env=env).encode('utf-8')).decode('utf-8').strip()
4 changes: 4 additions & 0 deletions fidelius/gateway/mock/_std.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""Here we import this modules implementation classes with generic names for the
Factory to use"""
from ._mockrepo import MockFideliusRepo as FideliusRepo
from ._mockadmin import MockFideliusAdmin as FideliusAdmin
1 change: 1 addition & 0 deletions fidelius/gateway/paramstore/_std.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._paramstorerepo import
2 changes: 1 addition & 1 deletion fidelius/structs/_appprops.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__all__ = [
'FideliusAppProps',
]
from ccptools.structs import *
import dataclasses


@dataclasses.dataclass
Expand Down
22 changes: 22 additions & 0 deletions fidelius/structs/_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
__all__ = [
'FideliusError',
'FideliusAdminError',
'FideliusParameterNotFound',
'FideliusParameterAlreadyExists',
]


class FideliusError(Exception):
pass


class FideliusAdminError(FideliusError):
pass


class FideliusParameterNotFound(FideliusAdminError, KeyError):
pass


class FideliusParameterAlreadyExists(FideliusAdminError, ValueError):
pass
4 changes: 4 additions & 0 deletions fidelius/structs/_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def __setattr__(self, name: str, value: Optional[str]):
def __delattr__(self, name: str):
self.__setattr__(name, None)

def __repr__(self) -> str:
tags = ', '.join([f"{k}='{v}'" for k, v in self.to_dict().items()])
return f'{self.__class__.__name__}({tags})'

def to_dict(self) -> Dict[str, str]:
d = {
'application': self.application,
Expand Down
1 change: 1 addition & 0 deletions fidelius/structs/api.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from ._tags import *
from ._appprops import *
from ._errors import *
26 changes: 26 additions & 0 deletions tests/test_mock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import unittest

from fidelius.fideliusapi import *

_app_props = FideliusAppProps(app='mock-app', group='somegroup', env='mock')


class TestMock(unittest.TestCase):
def test_mock(self):
fid = FideliusFactory.get_class('mock')(_app_props)
self.assertEqual('L2ZpZGVsaXVzL3NvbWVncm91cC9tb2NrL2FwcHMvbW9jay1hcHAvbW9jay12YWx1ZQ==', fid.get('mock-value'))
self.assertEqual('L2ZpZGVsaXVzL3NvbWVncm91cC9tb2NrL2FwcHMvbW9jay1hcHAvREJfUEFTU1dPUkQ=', fid.get('DB_PASSWORD'))
self.assertEqual('L2ZpZGVsaXVzL3NvbWVncm91cC9tb2NrL3NoYXJlZC9zaGFyZWRwb3N0Z3Jlcy9EQl9IT1NU', fid.get('DB_HOST', 'sharedpostgres'))

def test_mock_admin(self):
fia = FideliusFactory.get_admin_class('mock')(_app_props)
self.assertIsNone(fia.get('DB_PASSWORD'))

with self.assertRaises(FideliusParameterNotFound):
fia.delete_param('DB_PASSWORD')

with self.assertRaises(FideliusParameterNotFound):
fia.update_param('DB_PASSWORD', 'myBADpassword')

key, expression = fia.create_param('DB_PASSWORD', 'myBADpassword')

0 comments on commit 975fe4d

Please sign in to comment.