Skip to content

Commit d799c09

Browse files
committed
feat: update file management to support project_id and user_file model
Signed-off-by: kang2453 <[email protected]>
1 parent 14602eb commit d799c09

22 files changed

+1027
-343
lines changed

src/spaceone/file_manager/conf/router_conf.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
ROUTER = [
22
{
3-
"router_path": "spaceone.file_manager.interface.rest.files:router",
3+
"router_path": "spaceone.file_manager.interface.rest.file:router",
4+
"router_options": {
5+
"prefix": "/files",
6+
},
7+
},
8+
{
9+
"router_path": "spaceone.file_manager.interface.rest.user_file:router",
410
"router_options": {
511
"prefix": "/files",
612
},

src/spaceone/file_manager/connector/aws_s3_connector.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,16 @@ def get_download_url(self, file_id, file_name):
5858

5959
return response
6060

61-
def check_file(self, file_id, file_name):
62-
object_name = self._generate_object_name(file_id, file_name)
61+
def check_file(self, remote_file_path):
6362
try:
64-
self.client.get_object(Bucket=self.bucket_name, Key=object_name)
63+
self.client.head_object(Bucket=self.bucket_name, Key=remote_file_path)
6564
return True
6665
except Exception as e:
6766
_LOGGER.debug(f"[check_file] get_object error: {e}")
6867
return False
6968

70-
def delete_file(self, file_id, file_name):
71-
object_name = self._generate_object_name(file_id, file_name)
72-
self.client.delete_object(Bucket=self.bucket_name, Key=object_name)
69+
def delete_file(self, remote_file_path):
70+
self.client.delete_object(Bucket=self.bucket_name, Key=remote_file_path)
7371

7472
@staticmethod
7573
def _generate_object_name(file_id, file_name):

src/spaceone/file_manager/connector/file_base_connector.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ def get_download_url(self, file_id: str, file_name: str) -> str:
1313
pass
1414

1515
@abc.abstractmethod
16-
def check_file(self, file_id: str, file_name: str) -> bool:
16+
def check_file(self, remote_file_path:str) -> bool:
1717
pass
1818

1919
@abc.abstractmethod
20-
def delete_file(self, file_id: str, file_name: str) -> None:
20+
def delete_file(self, remote_file_path:str ) -> None:
2121
pass
2222

2323
@abc.abstractmethod
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import logging
2+
import boto3
3+
from io import BytesIO
4+
import botocore
5+
from botocore.client import Config as BotocoreConfig
6+
7+
from spaceone.core.error import *
8+
from spaceone.file_manager.connector.file_base_connector import FileBaseConnector
9+
10+
__all__ = ["MinIOS3Connector"]
11+
_LOGGER = logging.getLogger(__name__)
12+
13+
class MinIOS3Connector(FileBaseConnector):
14+
def __init__(self, *args, **kwargs):
15+
super().__init__(*args, **kwargs)
16+
17+
self.client = None
18+
self.bucket_name = None
19+
self._create_session()
20+
self._set_bucket()
21+
22+
def _create_session(self):
23+
endpoint = self.config.get("minio_endpoint")
24+
access_key_id = self.config.get("minio_access_key_id")
25+
secret_access_key = self.config.get("minio_secret_access_key")
26+
region_name = self.config.get("region_name")
27+
28+
if endpoint is None:
29+
raise ERROR_CONNECTOR_CONFIGURATION(backend="MinIOS3Connector")
30+
31+
if region_name is None:
32+
raise ERROR_CONNECTOR_CONFIGURATION(backend="MinIOS3Connector")
33+
34+
35+
if access_key_id and secret_access_key:
36+
self.client = boto3.client(
37+
"s3",
38+
endpoint_url=endpoint,
39+
aws_access_key_id=access_key_id,
40+
aws_secret_access_key=secret_access_key,
41+
region_name=region_name,
42+
config=BotocoreConfig(signature_version='s3v4'),
43+
)
44+
else:
45+
self.client = boto3.client("s3", region_name=region_name)
46+
47+
def _set_bucket(self):
48+
bucket_name = self.config.get("bucket_name")
49+
50+
if bucket_name is None:
51+
raise ERROR_CONNECTOR_CONFIGURATION(backend="MinIOS3Connector")
52+
53+
self.bucket_name = bucket_name
54+
55+
def get_upload_url(self, file_id, file_name):
56+
object_name = self._generate_object_name(file_id, file_name)
57+
response = self.client.generate_presigned_post(self.bucket_name, object_name)
58+
return response["url"], response["fields"]
59+
60+
def get_download_url(self, file_id: str, file_name: str) -> str:
61+
object_name = self._generate_object_name(file_id, file_name)
62+
response = self.client.generate_presigned_url(
63+
"get_object", Params={"Bucket": self.bucket_name, "Key": object_name}, ExpiresIn=86400
64+
)
65+
return response
66+
67+
def check_file(self, file_id, file_name):
68+
object_name = self._generate_object_name(file_id, file_name)
69+
try:
70+
self.client.get_object(Bucket=self.bucket_name, Key=object_name)
71+
return True
72+
except botocore.exceptions.ClientError as e:
73+
_LOGGER.debug(f"[check_file] get_object error: {e}")
74+
return False
75+
76+
def delete_file(self, file_id, file_name):
77+
object_name = self._generate_object_name(file_id, file_name)
78+
self.client.delete_object(Bucket=self.bucket_name, Key=object_name)
79+
80+
@staticmethod
81+
def _generate_object_name(file_id, file_name):
82+
return f"{file_id}/{file_name}"
83+
84+
def upload_file(self, remote_file_path:str, data: bytes) -> None:
85+
file_obj = BytesIO(data)
86+
if self.client is None:
87+
raise ERROR_CONNECTOR_CONFIGURATION(backend="MinIOS3Connector")
88+
self.client.upload_fileobj(file_obj, self.bucket_name, remote_file_path)
89+
90+
def download_file(self, remote_file_path:str) :
91+
92+
if self.client is None:
93+
raise ERROR_CONNECTOR_CONFIGURATION(backend="MinIOS3Connector")
94+
95+
obj = self.client.get_object(Bucket=self.bucket_name, Key=remote_file_path)
96+
return obj["Body"]
+15-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
from spaceone.core.error import *
22

33

4+
class ERROR_NOT_AUTHORIZATION_USER(ERROR_BASE):
5+
_message = "Not authorization user. (user_id = {user_id}, domain_id = {domain_id})"
6+
47
class ERROR_NOT_SUPPORTED_RESOURCE_GROUP(ERROR_BASE):
58
_message = "Not supported resource group. (resource_group = {resource_group})"
69

710
class ERROR_NOT_DEFINED_FILE_BACKEND(ERROR_BASE):
811
_message = "File backend not defined. (backend = {backend})"
912

1013
class ERROR_FILE_DOWNLOAD_URL_EXIST(ERROR_BASE):
11-
_message = "File download url is not exist. (file_id = {file_id})"
14+
_message = "File download url is not exist. (file_id = {file_id}, name = {name})"
1215

1316

1417
class ERROR_FILE_DOWNLOAD_FAILED(ERROR_BASE):
15-
_message = "File download failed. (file_id = {file_id})"
18+
_message = "File download failed. (name = {name})"
19+
20+
class ERROR_NOT_MATCH_USER_ID(ERROR_BASE):
21+
_message = "Not match user_id. (user_id = {user_id}, domain_id = {domain_id})"
22+
23+
class ERROR_FILE_UPLOAD_FAILED(ERROR_BASE):
24+
_message = "File upload failed. (name = {name})"
25+
26+
27+
class ERROR_FILE_DELETE_FAILED(ERROR_BASE):
28+
_message = "File delete failed. (name = {name})"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from spaceone.api.file_manager.v1 import userfile_pb2, userfile_pb2_grpc
2+
from spaceone.core.pygrpc import BaseAPI
3+
from spaceone.file_manager.service.user_file_service import UserFileService
4+
5+
6+
class UserFile(BaseAPI, userfile_pb2_grpc.UserFileServicer):
7+
pb2 = userfile_pb2
8+
pb2_grpc = userfile_pb2_grpc
9+
10+
def update(self, request, context):
11+
params, metadata = self.parse_request(request, context)
12+
file_svc = UserFileService(metadata)
13+
response: dict = file_svc.update(params)
14+
return self.dict_to_message(response)
15+
16+
def delete(self, request, context):
17+
params, metadata = self.parse_request(request, context)
18+
file_svc = UserFileService(metadata)
19+
file_svc.delete(params)
20+
return self.empty()
21+
22+
def get(self, request, context):
23+
params, metadata = self.parse_request(request, context)
24+
file_svc = UserFileService(metadata)
25+
response: dict = file_svc.get(params)
26+
return self.dict_to_message(response)
27+
28+
def list(self, request, context):
29+
params, metadata = self.parse_request(request, context)
30+
file_svc = UserFileService(metadata)
31+
response: dict = file_svc.list(params)
32+
return self.dict_to_message(response)
33+
34+
def stat(self, request, context):
35+
params, metadata = self.parse_request(request, context)
36+
file_svc = UserFileService(metadata)
37+
response: dict = file_svc.stat(params)
38+
return self.dict_to_message(response)

0 commit comments

Comments
 (0)