cs3client 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cs3client/__init__.py +0 -0
- cs3client/app.py +84 -0
- cs3client/auth.py +141 -0
- cs3client/checkpoint.py +86 -0
- cs3client/config.py +198 -0
- cs3client/cs3client.py +73 -0
- cs3client/cs3resource.py +207 -0
- cs3client/exceptions/__init__.py +0 -0
- cs3client/exceptions/exceptions.py +73 -0
- cs3client/file.py +628 -0
- cs3client/share.py +734 -0
- cs3client/statuscodehandler.py +105 -0
- cs3client/user.py +108 -0
- cs3client-0.0.1.dist-info/LICENSE +175 -0
- cs3client-0.0.1.dist-info/METADATA +368 -0
- cs3client-0.0.1.dist-info/RECORD +18 -0
- cs3client-0.0.1.dist-info/WHEEL +5 -0
- cs3client-0.0.1.dist-info/top_level.txt +1 -0
cs3client/__init__.py
ADDED
|
File without changes
|
cs3client/app.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
app.py
|
|
3
|
+
|
|
4
|
+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
|
|
5
|
+
Emails: rasmus.oscar.welander@cern.ch, diogo.castro@cern.ch, giuseppe.lopresti@cern.ch
|
|
6
|
+
Last updated: 30/08/2024
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import cs3.app.registry.v1beta1.registry_api_pb2 as cs3arreg
|
|
11
|
+
import cs3.app.registry.v1beta1.resources_pb2 as cs3arres
|
|
12
|
+
import cs3.gateway.v1beta1.gateway_api_pb2 as cs3gw
|
|
13
|
+
import cs3.app.provider.v1beta1.resources_pb2 as cs3apr
|
|
14
|
+
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
|
|
15
|
+
|
|
16
|
+
from .cs3resource import Resource
|
|
17
|
+
from .statuscodehandler import StatusCodeHandler
|
|
18
|
+
from .config import Config
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class App:
|
|
22
|
+
"""
|
|
23
|
+
App class to handle app related API calls with CS3 Gateway API.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
config: Config,
|
|
29
|
+
log: logging.Logger,
|
|
30
|
+
gateway: GatewayAPIStub,
|
|
31
|
+
status_code_handler: StatusCodeHandler,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Initializes the App class with configuration, logger, auth, and gateway stub,
|
|
35
|
+
|
|
36
|
+
:param config: Config object containing the configuration parameters.
|
|
37
|
+
:param log: Logger instance for logging.
|
|
38
|
+
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
|
|
39
|
+
:param status_code_handler: An instance of the StatusCodeHandler class.
|
|
40
|
+
"""
|
|
41
|
+
self._status_code_handler: StatusCodeHandler = status_code_handler
|
|
42
|
+
self._gateway: GatewayAPIStub = gateway
|
|
43
|
+
self._log: logging.Logger = log
|
|
44
|
+
self._config: Config = config
|
|
45
|
+
|
|
46
|
+
def open_in_app(
|
|
47
|
+
self, auth_token: tuple, resource: Resource, view_mode: str = None, app: str = None
|
|
48
|
+
) -> cs3apr.OpenInAppURL:
|
|
49
|
+
"""
|
|
50
|
+
Open a file in an app, given the resource, view mode (VIEW_MODE_VIEW_ONLY, VIEW_MODE_READ_ONLY,
|
|
51
|
+
VIEW_MODE_READ_WRITE, VIEW_MODE_PREVIEW), and app name.
|
|
52
|
+
|
|
53
|
+
:param auth_token: tuple in the form ('x-access-token', <token>) (see auth.get_token/auth.check_token)
|
|
54
|
+
:param resource: Resource object containing the resource information.
|
|
55
|
+
:param view_mode: View mode of the app.
|
|
56
|
+
:param app: App name.
|
|
57
|
+
:return: URL to open the file in the app.
|
|
58
|
+
:raises: AuthenticationException (Operation not permitted)
|
|
59
|
+
:raises: NotFoundException (Resource not found)
|
|
60
|
+
:raises: UnknownException (Unknown error)
|
|
61
|
+
"""
|
|
62
|
+
view_mode_type = None
|
|
63
|
+
if view_mode:
|
|
64
|
+
view_mode_type = cs3gw.OpenInAppRequest.ViewMode.Value(view_mode)
|
|
65
|
+
req = cs3gw.OpenInAppRequest(ref=resource.ref, view_mode=view_mode_type, app=app)
|
|
66
|
+
res = self._gateway.OpenInApp(request=req, metadata=[auth_token])
|
|
67
|
+
self._status_code_handler.handle_errors(res.status, "open in app", f"{resource.get_file_ref_str()}")
|
|
68
|
+
self._log.debug(f'msg="Invoked OpenInApp" {resource.get_file_ref_str()} trace="{res.status.trace}"')
|
|
69
|
+
return res.OpenInAppURL
|
|
70
|
+
|
|
71
|
+
def list_app_providers(self, auth_token: dict) -> list[cs3arres.ProviderInfo]:
|
|
72
|
+
"""
|
|
73
|
+
list_app_providers lists all the app providers.
|
|
74
|
+
|
|
75
|
+
:param auth_token: tuple in the form ('x-access-token', <token>) (see auth.get_token/auth.check_token)
|
|
76
|
+
:return: List of app providers.
|
|
77
|
+
:raises: AuthenticationException (Operation not permitted)
|
|
78
|
+
:raises: UnknownException (Unknown error)
|
|
79
|
+
"""
|
|
80
|
+
req = cs3arreg.ListAppProvidersRequest()
|
|
81
|
+
res = self._gateway.ListAppProviders(request=req, metadata=[auth_token])
|
|
82
|
+
self._status_code_handler.handle_errors(res.status, "list app providers")
|
|
83
|
+
self._log.debug(f'msg="Invoked ListAppProviders" res_count="{len(res.providers)}" trace="{res.status.trace}"')
|
|
84
|
+
return res.providers
|
cs3client/auth.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""
|
|
2
|
+
auth.py
|
|
3
|
+
|
|
4
|
+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
|
|
5
|
+
Emails: rasmus.oscar.welander@cern.ch, diogo.castro@cern.ch, giuseppe.lopresti@cern.ch
|
|
6
|
+
Last updated: 30/08/2024
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import grpc
|
|
10
|
+
import jwt
|
|
11
|
+
import datetime
|
|
12
|
+
import logging
|
|
13
|
+
from typing import Union
|
|
14
|
+
from cs3.gateway.v1beta1.gateway_api_pb2 import AuthenticateRequest
|
|
15
|
+
from cs3.auth.registry.v1beta1.registry_api_pb2 import ListAuthProvidersRequest
|
|
16
|
+
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
|
|
17
|
+
from cs3.rpc.v1beta1.code_pb2 import CODE_OK
|
|
18
|
+
|
|
19
|
+
from .cs3client import CS3Client
|
|
20
|
+
from .exceptions.exceptions import AuthenticationException, SecretNotSetException
|
|
21
|
+
from .config import Config
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Auth:
|
|
25
|
+
"""
|
|
26
|
+
Auth class to handle authentication and token validation with CS3 Gateway API.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, cs3_client: CS3Client) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Initializes the Auth class with configuration, logger, and gateway stub,
|
|
32
|
+
NOTE that token OR the client secret has to be set when instantiating the auth object.
|
|
33
|
+
|
|
34
|
+
:param config: Config object containing the configuration parameters.
|
|
35
|
+
:param log: Logger instance for logging.
|
|
36
|
+
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
|
|
37
|
+
"""
|
|
38
|
+
self._gateway: GatewayAPIStub = cs3_client._gateway
|
|
39
|
+
self._log: logging.Logger = cs3_client._log
|
|
40
|
+
self._config: Config = cs3_client._config
|
|
41
|
+
# The user should be able to change the client secret (e.g. token) and client id at runtime
|
|
42
|
+
self._client_secret: Union[str, None] = self._config.auth_client_secret
|
|
43
|
+
self._client_id: Union[str, None] = self._config.auth_client_id
|
|
44
|
+
self._token: Union[str, None] = None
|
|
45
|
+
|
|
46
|
+
def set_client_secret(self, token: str) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Sets the client secret, exists so that the user can change the client secret (e.g. token, password) at runtime,
|
|
49
|
+
without having to create a new Auth object. Note client secret has to be set when
|
|
50
|
+
instantiating the client object or through the configuration.
|
|
51
|
+
|
|
52
|
+
:param token: Auth token/password.
|
|
53
|
+
"""
|
|
54
|
+
self._client_secret = token
|
|
55
|
+
|
|
56
|
+
def set_client_id(self, id: str) -> None:
|
|
57
|
+
"""
|
|
58
|
+
Sets the client id, exists so that the user can change the client id at runtime, without having to create
|
|
59
|
+
a new Auth object. Settings this (either through config or here) is optional unless you are using
|
|
60
|
+
basic authentication.
|
|
61
|
+
|
|
62
|
+
:param token: id.
|
|
63
|
+
"""
|
|
64
|
+
self._client_id = id
|
|
65
|
+
|
|
66
|
+
def get_token(self) -> tuple[str, str]:
|
|
67
|
+
"""
|
|
68
|
+
Attempts to get a valid authentication token. If the token is not valid, a new token is requested
|
|
69
|
+
if the client secret is set, if only the token is set then an exception will be thrown stating that
|
|
70
|
+
the credentials have expired.
|
|
71
|
+
|
|
72
|
+
:return tuple: A tuple containing the header key and the token.
|
|
73
|
+
:raises: AuthenticationException (token expired, or failed to authenticate)
|
|
74
|
+
:raises: SecretNotSetException (neither token or client secret was set)
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
if not self._client_secret:
|
|
78
|
+
self._log.error("Attempted to authenticate, client secret was not set")
|
|
79
|
+
raise SecretNotSetException("The client secret (e.g. token, passowrd) is not set")
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
self.check_token(self._token)
|
|
83
|
+
except AuthenticationException:
|
|
84
|
+
# Token has expired or has not been set, obtain another one.
|
|
85
|
+
req = AuthenticateRequest(
|
|
86
|
+
type=self._config.auth_login_type,
|
|
87
|
+
client_id=self._client_id,
|
|
88
|
+
client_secret=self._client_secret,
|
|
89
|
+
)
|
|
90
|
+
# Send the authentication request to the CS3 Gateway
|
|
91
|
+
res = self._gateway.Authenticate(req)
|
|
92
|
+
|
|
93
|
+
if res.status.code != CODE_OK:
|
|
94
|
+
self._log.error(f'msg="Failed to authenticate" '
|
|
95
|
+
f'user="{self._client_id if self._client_id else "no_id_set"}" '
|
|
96
|
+
f'error_code="{res.status}"')
|
|
97
|
+
raise AuthenticationException(
|
|
98
|
+
f'Failed to authenticate: user="{self._client_id if self._client_id else "no_id_set"}" '
|
|
99
|
+
f'error_code="{res.status}"'
|
|
100
|
+
)
|
|
101
|
+
self._token = res.token
|
|
102
|
+
self._log.debug(f'msg="Authenticated user" user="{self._client_id if self._client_id else "no_id_set"}"')
|
|
103
|
+
return ("x-access-token", self._token)
|
|
104
|
+
|
|
105
|
+
def list_auth_providers(self) -> list[str]:
|
|
106
|
+
"""
|
|
107
|
+
list authentication providers
|
|
108
|
+
|
|
109
|
+
:return: a list of the supported authentication types
|
|
110
|
+
:raises: ConnectionError (Could not connect to host)
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
res = self._gateway.ListAuthProviders(request=ListAuthProvidersRequest())
|
|
114
|
+
if res.status.code != CODE_OK:
|
|
115
|
+
self._log.error(f'msg="List auth providers request failed" error_code="{res.status}"')
|
|
116
|
+
raise Exception(res.status.message)
|
|
117
|
+
except grpc.RpcError as e:
|
|
118
|
+
self._log.error("List auth providers request failed")
|
|
119
|
+
raise ConnectionError(e)
|
|
120
|
+
return res.types
|
|
121
|
+
|
|
122
|
+
@classmethod
|
|
123
|
+
def check_token(cls, token: str) -> tuple:
|
|
124
|
+
"""
|
|
125
|
+
Checks if the given token is set and valid.
|
|
126
|
+
|
|
127
|
+
:param token: JWT token as a string.
|
|
128
|
+
:return tuple: A tuple containing the header key and the token.
|
|
129
|
+
:raises: ValueError (Token missing)
|
|
130
|
+
:raises: AuthenticationException (Token is expired)
|
|
131
|
+
"""
|
|
132
|
+
if not token:
|
|
133
|
+
raise AuthenticationException("Token not set")
|
|
134
|
+
# Decode the token without verifying the signature
|
|
135
|
+
decoded_token = jwt.decode(jwt=token, algorithms=["HS256"], options={"verify_signature": False})
|
|
136
|
+
now = datetime.datetime.now().timestamp()
|
|
137
|
+
token_expiration = decoded_token.get("exp")
|
|
138
|
+
if token_expiration and now > token_expiration:
|
|
139
|
+
raise AuthenticationException("Token has expired")
|
|
140
|
+
|
|
141
|
+
return ("x-access-token", token)
|
cs3client/checkpoint.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
checkpoint.py
|
|
3
|
+
|
|
4
|
+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
|
|
5
|
+
Emails: rasmus.oscar.welander@cern.ch, diogo.castro@cern.ch, giuseppe.lopresti@cern.ch
|
|
6
|
+
Last updated: 30/08/2024
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Generator
|
|
10
|
+
import logging
|
|
11
|
+
import cs3.storage.provider.v1beta1.resources_pb2 as cs3spr
|
|
12
|
+
import cs3.storage.provider.v1beta1.provider_api_pb2 as cs3spp
|
|
13
|
+
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
|
|
14
|
+
|
|
15
|
+
from .config import Config
|
|
16
|
+
from .statuscodehandler import StatusCodeHandler
|
|
17
|
+
from .cs3resource import Resource
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Checkpoint:
|
|
21
|
+
"""
|
|
22
|
+
Checkpoint class to handle checkpoint related API calls with CS3 Gateway API.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config: Config,
|
|
28
|
+
log: logging.Logger,
|
|
29
|
+
gateway: GatewayAPIStub,
|
|
30
|
+
status_code_handler: StatusCodeHandler,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Initializes the checkpoint class with configuration, logger, auth, and gateway stub,
|
|
34
|
+
|
|
35
|
+
:param config: Config object containing the configuration parameters.
|
|
36
|
+
:param log: Logger instance for logging.
|
|
37
|
+
:param gateway: GatewayAPIStub instance for interacting with CS3 Gateway.
|
|
38
|
+
:param status_code_handler: An instance of the StatusCodeHandler class.
|
|
39
|
+
"""
|
|
40
|
+
self._gateway: GatewayAPIStub = gateway
|
|
41
|
+
self._log: logging.Logger = log
|
|
42
|
+
self._config: Config = config
|
|
43
|
+
self._status_code_handler: StatusCodeHandler = status_code_handler
|
|
44
|
+
|
|
45
|
+
def list_file_versions(
|
|
46
|
+
self, auth_token: tuple, resource: Resource, page_token: str = "", page_size: int = 0
|
|
47
|
+
) -> Generator[cs3spr.FileVersion, any, any]:
|
|
48
|
+
"""
|
|
49
|
+
List all versions of a file.
|
|
50
|
+
|
|
51
|
+
:param auth_token: tuple in the form ('x-access-token', <token>) (see auth.get_token/auth.check_token)
|
|
52
|
+
:param resource: Resource object containing the resource information.
|
|
53
|
+
:param page_token: Token for pagination.
|
|
54
|
+
:param page_size: Number of file versions to return.
|
|
55
|
+
(default is zero, where the server decides the number of versions to return)
|
|
56
|
+
:return: List of file versions (None if no versions are found).
|
|
57
|
+
:raises: AuthenticationException (Operation not permitted)
|
|
58
|
+
:raises: NotFoundException (File not found)
|
|
59
|
+
:raises: UnknownException (Unknown error)
|
|
60
|
+
"""
|
|
61
|
+
req = cs3spp.ListFileVersionsRequest(ref=resource.ref, page_token=page_token, page_size=page_size)
|
|
62
|
+
res = self._gateway.ListFileVersions(request=req, metadata=[auth_token])
|
|
63
|
+
self._status_code_handler.handle_errors(res.status, "list file versions", f"{resource.get_file_ref_str()}")
|
|
64
|
+
self._log.debug(f'msg="list file versions" {resource.get_file_ref_str()} trace="{res.status.trace}"')
|
|
65
|
+
return res.versions
|
|
66
|
+
|
|
67
|
+
def restore_file_version(
|
|
68
|
+
self, auth_token: tuple, resource: Resource, version_key: str, lock_id: str = None
|
|
69
|
+
) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Restore a file to a previous version.
|
|
72
|
+
|
|
73
|
+
:param auth_token: tuple in the form ('x-access-token', <token>) (see auth.get_token/auth.check_token)
|
|
74
|
+
:param resource: Resource object containing the resource information.
|
|
75
|
+
:param version_key: Key of the version to restore.
|
|
76
|
+
:param lock_id: Lock ID of the file (OPTIONAL).
|
|
77
|
+
:return: None (Success)
|
|
78
|
+
:raises: AuthenticationException (Operation not permitted)
|
|
79
|
+
:raises: NotFoundException (File not found)
|
|
80
|
+
:raises: UnknownException (Unknown error)
|
|
81
|
+
"""
|
|
82
|
+
req = cs3spp.RestoreFileVersionRequest(ref=resource.ref, key=version_key, lock_id=lock_id)
|
|
83
|
+
res = self._gateway.RestoreFileVersion(request=req, metadata=[auth_token])
|
|
84
|
+
self._status_code_handler.handle_errors(res.status, "restore file version", f"{resource.get_file_ref_str()}")
|
|
85
|
+
self._log.debug(f'msg="restore file version" {resource.get_file_ref_str()} trace="{res.status.trace}"')
|
|
86
|
+
return
|
cs3client/config.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
config.py
|
|
3
|
+
|
|
4
|
+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
|
|
5
|
+
Emails: rasmus.oscar.welander@cern.ch, diogo.castro@cern.ch, giuseppe.lopresti@cern.ch
|
|
6
|
+
Last updated: 29/07/2024
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from configparser import ConfigParser
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Config:
|
|
13
|
+
"""
|
|
14
|
+
A class to read and store the configuration parameters provided to the CS3 client.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: ConfigParser, config_category: str) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Initializes the Config class with the configuration parameters.
|
|
20
|
+
|
|
21
|
+
:param config: Dictionary containing configuration parameters.
|
|
22
|
+
:param config_category: The category of the configuration parameters.
|
|
23
|
+
"""
|
|
24
|
+
self._config_category: str = config_category
|
|
25
|
+
self._config: ConfigParser = config
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def host(self) -> str:
|
|
29
|
+
"""
|
|
30
|
+
The host property returns the host address and port from the configuration.
|
|
31
|
+
|
|
32
|
+
:return: host address:port
|
|
33
|
+
"""
|
|
34
|
+
return self._config.get(self._config_category, "host")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def chunk_size(self) -> int:
|
|
38
|
+
"""
|
|
39
|
+
The chunk_size property returns the chunk_size value from the configuration,
|
|
40
|
+
fallback to 4194304 if not present.
|
|
41
|
+
|
|
42
|
+
:return: The chunk size value.
|
|
43
|
+
"""
|
|
44
|
+
return self._config.getint(self._config_category, "chunk_size", fallback=4194304)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def grpc_timeout(self) -> int:
|
|
48
|
+
"""
|
|
49
|
+
The grpc_timeout property returns the grpc_timeout value from the configuration,
|
|
50
|
+
fallback to 10 if not present.
|
|
51
|
+
|
|
52
|
+
:return: The grpc timeout value.
|
|
53
|
+
"""
|
|
54
|
+
return self._config.getint(self._config_category, "grpc_timeout", fallback=10)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def http_timeout(self) -> int:
|
|
58
|
+
"""
|
|
59
|
+
The http_timeout property returns the http_timeout value from the configuration,
|
|
60
|
+
fallback to 10 if not present.
|
|
61
|
+
|
|
62
|
+
:return: The http timeout value.
|
|
63
|
+
"""
|
|
64
|
+
return self._config.getint(self._config_category, "http_timeout", fallback=10)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def ssl_enabled(self) -> bool:
|
|
68
|
+
"""
|
|
69
|
+
The ssl_enabled property returns the ssl_enabled value from the configuration,
|
|
70
|
+
fallback to True if not present.
|
|
71
|
+
|
|
72
|
+
:return: ssl_enabled value.
|
|
73
|
+
"""
|
|
74
|
+
return self._config.getboolean(self._config_category, "ssl_enabled", fallback=False)
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def ssl_verify(self) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
The ssl_verify property returns the ssl_verify value from the configuration,
|
|
80
|
+
|
|
81
|
+
:return: ssl_verify
|
|
82
|
+
"""
|
|
83
|
+
return self._config.getboolean(self._config_category, "ssl_verify", fallback=False)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def ssl_client_cert(self) -> str:
|
|
87
|
+
"""
|
|
88
|
+
The ssl_client_cert property returns the ssl_client_cert value from the configuration,
|
|
89
|
+
if not present, fallback to an empty string since it is not required if ssl is not enabled.
|
|
90
|
+
|
|
91
|
+
:return: ssl_client_cert
|
|
92
|
+
"""
|
|
93
|
+
return self._config.get(self._config_category, "ssl_client_cert", fallback=None)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def ssl_client_key(self) -> str:
|
|
97
|
+
"""
|
|
98
|
+
The ssl_client_key property returns the ssl_client_key value from the configuration,
|
|
99
|
+
if not present, fallback to an empty string since it is not required if ssl is not enabled.
|
|
100
|
+
|
|
101
|
+
:return: ssl_client_key
|
|
102
|
+
"""
|
|
103
|
+
return self._config.get(self._config_category, "ssl_client_key", fallback=None)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def ssl_ca_cert(self) -> str:
|
|
107
|
+
"""
|
|
108
|
+
The ssl_ca_cert property returns the ssl_ca_cert value from the configuration,
|
|
109
|
+
if not present, fallback to an empty string since it is not required if ssl is not enabled.
|
|
110
|
+
|
|
111
|
+
:return: ssl_ca_cert
|
|
112
|
+
"""
|
|
113
|
+
return self._config.get(self._config_category, "ssl_ca_cert", fallback=None)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def auth_login_type(self) -> str:
|
|
117
|
+
"""
|
|
118
|
+
The auth_login_type property returns the auth_login_type value from the configuration.
|
|
119
|
+
e.g. basic, bearer, oauth, machine.
|
|
120
|
+
|
|
121
|
+
:return: auth_login_type
|
|
122
|
+
"""
|
|
123
|
+
return self._config.get(self._config_category, "auth_login_type", fallback="basic")
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def auth_client_id(self) -> str:
|
|
127
|
+
"""
|
|
128
|
+
The auth_client_id property returns the auth_client_id value from the configuration,
|
|
129
|
+
|
|
130
|
+
:return: auth_client_id
|
|
131
|
+
"""
|
|
132
|
+
return self._config.get(self._config_category, "auth_client_id", fallback=None)
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def auth_client_secret(self) -> str:
|
|
136
|
+
"""
|
|
137
|
+
The auth_client_secret property returns the auth_client_secret value from the configuration,
|
|
138
|
+
|
|
139
|
+
:return: auth_client_secret
|
|
140
|
+
"""
|
|
141
|
+
return self._config.get(self._config_category, "auth_client_secret", fallback=None)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def tus_enabled(self) -> bool:
|
|
145
|
+
"""
|
|
146
|
+
The tus_enabled property returns the tus_enabled value from the configuration,
|
|
147
|
+
|
|
148
|
+
:return: tus_enabled
|
|
149
|
+
"""
|
|
150
|
+
return self._config.getboolean(self._config_category, "tus_enabled", fallback=False)
|
|
151
|
+
|
|
152
|
+
# For the lock implementation
|
|
153
|
+
@property
|
|
154
|
+
def lock_by_setting_attr(self) -> bool:
|
|
155
|
+
"""
|
|
156
|
+
The lock_by_setting_attr property returns the lock_by_setting_attr value from the configuration,
|
|
157
|
+
fallback to False if not present.
|
|
158
|
+
|
|
159
|
+
The lock by setting attribute setting should be set if the storage provider does not
|
|
160
|
+
implement locking functionality. In which case the client will use the fallback mechanism
|
|
161
|
+
by locking resources by setting metadata attributes. If lock_not_impl is set to false and
|
|
162
|
+
lock_by_setting_attr is set to true, the client will attempt to lock normally first,
|
|
163
|
+
and if that fails, it will attempt to lock by setting metadata attributes.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
:return: lock_by_setting_attr
|
|
167
|
+
"""
|
|
168
|
+
return self._config.getboolean(self._config_category, "lock_by_setting_attr", fallback=False)
|
|
169
|
+
|
|
170
|
+
# For the lock implementation
|
|
171
|
+
@property
|
|
172
|
+
def lock_not_impl(self) -> bool:
|
|
173
|
+
"""
|
|
174
|
+
The lock_not_impl property returns the lock_not_impl value from the configuration,
|
|
175
|
+
fallback to False if not present.
|
|
176
|
+
|
|
177
|
+
The lock not implemented setting should be set if the storage provider
|
|
178
|
+
does not implement locking functionality. In which case the client will use the
|
|
179
|
+
fallback mechanism by locking resources by setting metadata attributes if the
|
|
180
|
+
lock_by_setting_attr is set to True.
|
|
181
|
+
|
|
182
|
+
:return: lock_not_impl
|
|
183
|
+
"""
|
|
184
|
+
return self._config.getboolean(self._config_category, "lock_not_impl", fallback=False)
|
|
185
|
+
|
|
186
|
+
# For the lock implementation
|
|
187
|
+
@property
|
|
188
|
+
def lock_expiration(self) -> int:
|
|
189
|
+
"""
|
|
190
|
+
The lock_expiration property returns the lock_expiration value from the configuration,
|
|
191
|
+
fallback to 1800 if not present.
|
|
192
|
+
|
|
193
|
+
The lock expiration setting is used to determine the time
|
|
194
|
+
in seconds before a lock is considered expired.
|
|
195
|
+
|
|
196
|
+
:return: lock_expiration
|
|
197
|
+
"""
|
|
198
|
+
return self._config.getint(self._config_category, "lock_expiration", fallback=1800)
|
cs3client/cs3client.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
cs3client.py
|
|
3
|
+
|
|
4
|
+
Authors: Rasmus Welander, Diogo Castro, Giuseppe Lo Presti.
|
|
5
|
+
Emails: rasmus.oscar.welander@cern.ch, diogo.castro@cern.ch, giuseppe.lopresti@cern.ch
|
|
6
|
+
Last updated: 30/08/2024
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import grpc
|
|
10
|
+
import logging
|
|
11
|
+
import cs3.gateway.v1beta1.gateway_api_pb2_grpc as cs3gw_grpc
|
|
12
|
+
from configparser import ConfigParser
|
|
13
|
+
|
|
14
|
+
from .file import File
|
|
15
|
+
from .user import User
|
|
16
|
+
from .share import Share
|
|
17
|
+
from .statuscodehandler import StatusCodeHandler
|
|
18
|
+
from .app import App
|
|
19
|
+
from .checkpoint import Checkpoint
|
|
20
|
+
from .config import Config
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CS3Client:
|
|
24
|
+
"""
|
|
25
|
+
Client class to interact with the CS3 API.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, config: ConfigParser, config_category: str, log: logging.Logger) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Initializes the CS3Client class with configuration and logger.
|
|
31
|
+
:param config: Dictionary containing configuration parameters.
|
|
32
|
+
:param config_category: Category of the configuration parameters.
|
|
33
|
+
:param log: Logger instance for logging.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
self._config: Config = Config(config, config_category)
|
|
37
|
+
self._log: logging.Logger = log
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
self.channel: grpc.Channel = self._create_channel()
|
|
41
|
+
grpc.channel_ready_future(self.channel).result(timeout=self._config.grpc_timeout)
|
|
42
|
+
except grpc.FutureTimeoutError as e:
|
|
43
|
+
log.error(f'msg="Failed to connect to Reva via GRPC" error="{e}"')
|
|
44
|
+
raise TimeoutError("Failed to connect to Reva via GRPC")
|
|
45
|
+
|
|
46
|
+
self._gateway: cs3gw_grpc.GatewayAPIStub = cs3gw_grpc.GatewayAPIStub(self.channel)
|
|
47
|
+
self._status_code_handler: StatusCodeHandler = StatusCodeHandler(self._log, self._config)
|
|
48
|
+
self.file: File = File(self._config, self._log, self._gateway, self._status_code_handler)
|
|
49
|
+
self.user: User = User(self._config, self._log, self._gateway, self._status_code_handler)
|
|
50
|
+
self.app: App = App(self._config, self._log, self._gateway, self._status_code_handler)
|
|
51
|
+
self.checkpoint: Checkpoint = Checkpoint(
|
|
52
|
+
self._config, self._log, self._gateway, self._status_code_handler
|
|
53
|
+
)
|
|
54
|
+
self.share = Share(self._config, self._log, self._gateway, self._status_code_handler)
|
|
55
|
+
|
|
56
|
+
def _create_channel(self) -> grpc.Channel:
|
|
57
|
+
"""
|
|
58
|
+
create_channel creates a gRPC channel to the specified host.
|
|
59
|
+
|
|
60
|
+
:return: gRPC channel to the specified host.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
if self._config.ssl_enabled:
|
|
64
|
+
|
|
65
|
+
credentials = grpc.ssl_channel_credentials(
|
|
66
|
+
root_certificates=self._config.ssl_ca_cert,
|
|
67
|
+
private_key=self._config.ssl_client_key,
|
|
68
|
+
certificate_chain=self._config.ssl_client_cert,
|
|
69
|
+
)
|
|
70
|
+
channel = grpc.secure_channel(self._config.host, credentials)
|
|
71
|
+
else:
|
|
72
|
+
channel = grpc.insecure_channel(self._config.host)
|
|
73
|
+
return channel
|