Skip to content

Commit ac30eb3

Browse files
authored
Merge branch 'dev' into 100-feat-assets-api
2 parents d959943 + dd14499 commit ac30eb3

File tree

13 files changed

+1120
-2
lines changed

13 files changed

+1120
-2
lines changed

naas_python/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .domains.space.handlers.PythonHandler import primaryAdaptor as space
33
from .domains.secret.handlers.PythonHandler import primaryAdaptor as secret
44
from .domains.asset.handlers.PythonHandler import primaryAdaptor as asset
5+
from .domains.storage.handlers.PythonHandler import primaryAdaptor as storage
56
from .utils.log import initialize_logging
67

78
logger = initialize_logging()

naas_python/cli.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import typer
2+
import logging
3+
logging.basicConfig(level=logging.ERROR)
24

35
from naas_python.domains.registry.handlers.CLIRegistryHandler import (
46
primaryAdaptor as typerRegistryAdaptor,
@@ -18,6 +20,10 @@
1820
primaryAdaptor as typerAssetAdaptor,
1921
)
2022

23+
from naas_python.domains.storage.handlers.CLIStorageHandler import (
24+
primaryAdaptor as typerStorageAdaptor,
25+
)
26+
2127

2228
def _create_cli_app():
2329
app = typer.Typer(
@@ -32,6 +38,8 @@ def _create_cli_app():
3238
app.add_typer(typerRegistryAdaptor.app, name="registry")
3339
app.add_typer(typerSecretAdaptor.app, name="secret")
3440
app.add_typer(typerAssetAdaptor.app, name="asset")
41+
app.add_typer(typerStorageAdaptor.app, name="storage")
42+
3543

3644
return app
3745

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from .models.Storage import Storage
2+
3+
from typing import List
4+
5+
from naas_python.domains.storage.StorageSchema import (
6+
IStorageDomain,
7+
IStorageAdaptor,
8+
IStorageProviderAdaptor,
9+
Storage,
10+
Object,
11+
StorageProviderNotFound
12+
)
13+
class StorageDomain(IStorageDomain):
14+
def __init__(self, adaptor: IStorageAdaptor, storage_provider_adaptors : List[IStorageProviderAdaptor]):
15+
# List[IStorageProviderAdaptor])
16+
#Map[str : IStorageProviderAdaptor])
17+
self.adaptor = adaptor
18+
self.storage_provider_adaptors = storage_provider_adaptors
19+
20+
############### API ###############
21+
def create_workspace_storage(self,
22+
workspace_id: str,
23+
storage_name: Storage.__fields__['name'],
24+
) -> dict:
25+
response = self.adaptor.create_workspace_storage(
26+
workspace_id=workspace_id,
27+
storage_name=storage_name,
28+
)
29+
return response
30+
31+
def delete_workspace_storage(self,
32+
workspace_id: str,
33+
storage_name: Storage.__fields__['name']
34+
) -> dict:
35+
response = self.adaptor.delete_workspace_storage(
36+
workspace_id=workspace_id,
37+
storage_name=storage_name,
38+
)
39+
return response
40+
41+
def list_workspace_storage(self,
42+
workspace_id: str,
43+
) -> dict:
44+
response = self.adaptor.list_workspace_storage(
45+
workspace_id=workspace_id,
46+
)
47+
return response
48+
49+
def list_workspace_storage_object(self,
50+
workspace_id: str,
51+
storage_name: Storage.__fields__['name'],
52+
storage_prefix: Object.__fields__['prefix'],
53+
) -> dict:
54+
response = self.adaptor.list_workspace_storage_object(
55+
workspace_id=workspace_id,
56+
storage_name=storage_name,
57+
storage_prefix=storage_prefix,
58+
)
59+
return response
60+
61+
def delete_workspace_storage_object(self,
62+
workspace_id: str,
63+
storage_name: Storage.__fields__['name'],
64+
object_name: Object.__fields__['name'],
65+
) -> dict:
66+
response = self.adaptor.delete_workspace_storage_object(
67+
workspace_id=workspace_id,
68+
storage_name=storage_name,
69+
object_name=object_name,
70+
)
71+
return response
72+
73+
def create_workspace_storage_credentials(self,
74+
workspace_id: str,
75+
storage_name: Storage.__fields__['name'],
76+
) -> dict:
77+
credentials = self.adaptor.generate_credentials(workspace_id, storage_name)
78+
self.storage_provider.save_naas_credentials(workspace_id, storage_name, credentials)
79+
return dict
80+
81+
############### BOTO ###############
82+
def __get_storage_provider(self,
83+
workspace_id: str,
84+
storage_name: Storage.__fields__['name']
85+
) -> str:
86+
#TODO This function should check in ~.naas/credentials to grab the provider id (s3;azure;gcp;...)
87+
return 's3'
88+
89+
90+
def post_workspace_storage_object(self,
91+
workspace_id: str,
92+
storage_name: Storage.__fields__['name'],
93+
src_file: str,
94+
dst_file: str,
95+
) -> dict:
96+
97+
storage_provider_id = self.__get_storage_provider(workspace_id, storage_name)
98+
99+
if storage_provider_id not in self.storage_provider_adaptors:
100+
raise StorageProviderNotFound(f'Provider "{storage_provider_id}" is not implemented or not loaded.')
101+
102+
storage_provider : IStorageProviderAdaptor = self.storage_provider_adaptors[storage_provider_id]
103+
104+
if not storage_provider.valid_naas_credentials(workspace_id, storage_name):
105+
credentials = self.adaptor.generate_credentials(workspace_id, storage_name)
106+
storage_provider.save_naas_credentials(workspace_id, storage_name, credentials)
107+
108+
response = storage_provider.post_workspace_storage_object(workspace_id=workspace_id, storage_name=storage_name, src_file=src_file, dst_file=dst_file)
109+
return response
110+
111+
def get_workspace_storage_object(self,
112+
workspace_id: str,
113+
storage_name: Storage.__fields__['name'],
114+
src_file: str,
115+
dst_file: str,
116+
) -> bytes:
117+
118+
storage_provider_id = self.__get_storage_provider(workspace_id, storage_name)
119+
120+
if storage_provider_id not in self.storage_provider_adaptors:
121+
raise StorageProviderNotFound(f'Provider "{storage_provider_id}" is not implemented or not loaded.')
122+
123+
storage_provider : IStorageProviderAdaptor = self.storage_provider_adaptors[storage_provider_id]
124+
125+
if not storage_provider.valid_naas_credentials(workspace_id, storage_name):
126+
credentials = self.adaptor.generate_credentials(workspace_id, storage_name)
127+
storage_provider.save_naas_credentials(workspace_id, storage_name, credentials)
128+
129+
response = storage_provider.get_workspace_storage_object(workspace_id=workspace_id, storage_name=storage_name, src_file=src_file, dst_file=dst_file)
130+
return response
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
from abc import ABCMeta, abstractmethod
2+
from logging import getLogger
3+
from typing import List
4+
5+
from naas_models.pydantic.storage_p2p import *
6+
from .models.Storage import Storage, Object
7+
8+
9+
# Secondary Adaptor
10+
from naas_python.utils.exceptions import NaasException
11+
12+
logger = getLogger(__name__)
13+
14+
class IStorageAdaptor(metaclass=ABCMeta):
15+
@abstractmethod
16+
def create_workspace_storage(self,
17+
workspace_id: str,
18+
storage_name: Storage.__fields__['name'],
19+
) -> dict[str, str]:
20+
raise NotImplementedError
21+
22+
@abstractmethod
23+
def delete_workspace_storage(self,
24+
workspace_id: str,
25+
storage_name: Storage.__fields__['name'],
26+
) -> dict:
27+
raise NotImplementedError
28+
29+
@abstractmethod
30+
def list_workspace_storage(self,
31+
workspace_id: str,
32+
) -> dict:
33+
raise NotImplementedError
34+
35+
@abstractmethod
36+
def list_workspace_storage_object(self,
37+
workspace_id: str,
38+
storage_name: Storage.__fields__['name'],
39+
storage_prefix: Object.__fields__['prefix'],
40+
) -> dict:
41+
raise NotImplementedError
42+
43+
@abstractmethod
44+
def delete_workspace_storage_object(self,
45+
workspace_id: str,
46+
storage_name: Storage.__fields__['name'],
47+
object_name: Object.__fields__['name'],
48+
) -> dict:
49+
raise NotImplementedError
50+
51+
class IStorageProviderAdaptor(metaclass=ABCMeta):
52+
53+
provider_id : str
54+
55+
@abstractmethod
56+
def post_workspace_storage_object(self,
57+
workspace_id: str,
58+
storage_name: Storage.__fields__['name'],
59+
src_file: str,
60+
dst_file: str,
61+
) -> dict:
62+
raise NotImplementedError
63+
64+
@abstractmethod
65+
def get_workspace_storage_object(self,
66+
workspace_id: str,
67+
storage_name: Storage.__fields__['name'],
68+
src_file: str,
69+
dst_file: str,
70+
) -> bytes:
71+
raise NotImplementedError
72+
73+
# Domain
74+
class IStorageDomain(metaclass=ABCMeta):
75+
adaptor: IStorageAdaptor
76+
storage_provider_adaptors : List[IStorageProviderAdaptor]
77+
# storage_provider_adaptors : Map[str, IStorageProviderAdaptor]
78+
#TODO to be validated
79+
80+
@abstractmethod
81+
def create_workspace_storage(self,
82+
workspace_id: str,
83+
storage_name: Storage.__fields__['name'],
84+
) -> dict:
85+
raise NotImplementedError
86+
87+
@abstractmethod
88+
def delete_workspace_storage(self,
89+
workspace_id: str,
90+
storage_name: Storage.__fields__['name'],
91+
) -> dict:
92+
raise NotImplementedError
93+
94+
@abstractmethod
95+
def list_workspace_storage(self,
96+
workspace_id: str,
97+
) -> dict:
98+
raise NotImplementedError
99+
100+
@abstractmethod
101+
def list_workspace_storage_object(self,
102+
workspace_id: str,
103+
storage_name: Storage.__fields__['name'],
104+
storage_prefix: Object.__fields__['prefix'],
105+
) -> dict:
106+
raise NotImplementedError
107+
108+
@abstractmethod
109+
def delete_workspace_storage_object(self,
110+
workspace_id: str,
111+
storage_name: Storage.__fields__['name'],
112+
object_name: Object.__fields__['name'],
113+
) -> dict:
114+
raise NotImplementedError
115+
116+
@abstractmethod
117+
def post_workspace_storage_object(self,
118+
workspace_id: str,
119+
storage_name: Storage.__fields__['name'],
120+
src_file: str,
121+
dst_file: str,
122+
) -> dict:
123+
raise NotImplementedError
124+
125+
@abstractmethod
126+
def get_workspace_storage_object(self,
127+
workspace_id: str,
128+
storage_name: Storage.__fields__['name'],
129+
src_file: str,
130+
dst_file: str,
131+
) -> bytes:
132+
raise NotImplementedError
133+
134+
135+
@abstractmethod
136+
def create_workspace_storage_credentials(self,
137+
workspace_id: str,
138+
storage_name: Storage.__fields__['name'],
139+
) -> dict:
140+
raise NotImplementedError
141+
142+
# Primary Adaptor
143+
class IStorageInvoker(metaclass=ABCMeta):
144+
@abstractmethod
145+
def create_workspace_storage(self, **kwargs):
146+
raise NotImplementedError
147+
148+
@abstractmethod
149+
def delete_workspace_storage(self, **kwargs):
150+
raise NotImplementedError
151+
152+
@abstractmethod
153+
def list_workspace_storage(self, **kwargs):
154+
raise NotImplementedError
155+
156+
@abstractmethod
157+
def list_workspace_storage_object(self, **kwargs):
158+
raise NotImplementedError
159+
160+
@abstractmethod
161+
def delete_workspace_storage_object(self, **kwargs):
162+
raise NotImplementedError
163+
164+
@abstractmethod
165+
def post_workspace_storage_object(self, **kwargs):
166+
raise NotImplementedError
167+
168+
@abstractmethod
169+
def get_workspace_storage_object(self, **kwargs):
170+
raise NotImplementedError
171+
172+
@abstractmethod
173+
def create_workspace_storage_credentials(self, **kwargs):
174+
raise NotImplementedError
175+
176+
# Exceptions
177+
class BadCredentials(NaasException):
178+
pass
179+
class ClientError(NaasException):
180+
pass
181+
class ConnectionError(NaasException):
182+
pass
183+
class SSLError(NaasException):
184+
pass
185+
class BotoCoreError(NaasException):
186+
pass
187+
class StorageNotFoundError(NaasException):
188+
pass
189+
class NoSuchBucket(NaasException):
190+
pass
191+
class ExpiredToken(NaasException):
192+
pass
193+
class FileNotFoundError(NaasException):
194+
pass
195+
class BadRequest(NaasException):
196+
pass
197+
class ForbiddenError(NaasException):
198+
pass
199+
class APIError(NaasException):
200+
pass
201+
class StorageProviderNotFound(NaasException):
202+
pass
203+
class ServiceAuthenticationError(NaasException):
204+
pass
205+
class ServiceStatusError(NaasException):
206+
pass
207+
class ObjectAlreadyExists(NaasException):
208+
pass

0 commit comments

Comments
 (0)