Skip to content

Commit

Permalink
[CI] use Python 3.9 as that is what we have in Alma9
Browse files Browse the repository at this point in the history
  • Loading branch information
Rasmus Oscar Welander committed Sep 6, 2024
1 parent 49337c6 commit 52fdebc
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 46 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python 3.12
- name: Set up Python 3.9
uses: actions/setup-python@v3
with:
python-version: "3.12"
python-version: "3.9"

- name: Install dependencies
run: |
Expand Down
7 changes: 4 additions & 3 deletions cs3client/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import jwt
import datetime
import logging
from typing import Union
from cs3.gateway.v1beta1.gateway_api_pb2 import AuthenticateRequest
from cs3.auth.registry.v1beta1.registry_api_pb2 import ListAuthProvidersRequest
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
Expand Down Expand Up @@ -38,9 +39,9 @@ def __init__(self, cs3_client: CS3Client) -> None:
self._log: logging.Logger = cs3_client._log
self._config: Config = cs3_client._config
# The user should be able to change the client secret (e.g. token) and client id at runtime
self._client_secret: str | None = self._config.auth_client_secret
self._client_id: str | None = self._config.auth_client_id
self._token: str | None = None
self._client_secret: Union[str, None] = self._config.auth_client_secret
self._client_id: Union[str, None] = self._config.auth_client_id
self._token: Union[str, None] = None

def set_client_secret(self, token: str) -> None:
"""
Expand Down
27 changes: 14 additions & 13 deletions cs3client/cs3resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

import cs3.storage.provider.v1beta1.resources_pb2 as cs3spr
from typing import Union


class Resource:
Expand All @@ -26,12 +27,12 @@ class Resource:

def __init__(
self,
abs_path: str | None = None,
rel_path: str | None = None,
opaque_id: str | None = None,
parent_id: str | None = None,
storage_id: str | None = None,
space_id: str | None = None,
abs_path: Union[str, None] = None,
rel_path: Union[str, None] = None,
opaque_id: Union[str, None] = None,
parent_id: Union[str, None] = None,
storage_id: Union[str, None] = None,
space_id: Union[str, None] = None,
) -> None:
"""
initializes the Resource class, either abs_path, rel_path or opaque_id is required
Expand All @@ -45,15 +46,15 @@ def __init__(
:param storage_id: storage id (optional)
:param space_id: space id (optional)
"""
self._abs_path: str | None = abs_path
self._rel_path: str | None = rel_path
self._parent_id: str | None = parent_id
self._opaque_id: str | None = opaque_id
self._space_id: str | None = space_id
self._storage_id: str | None = storage_id
self._abs_path: Union[str, None] = abs_path
self._rel_path: Union[str, None] = rel_path
self._parent_id: Union[str, None] = parent_id
self._opaque_id: Union[str, None] = opaque_id
self._space_id: Union[str, None] = space_id
self._storage_id: Union[str, None] = storage_id

@classmethod
def from_file_ref_and_endpoint(cls, file: str, endpoint: str | None = None) -> "Resource":
def from_file_ref_and_endpoint(cls, file: str, endpoint: Union[str, None] = None) -> "Resource":
"""
Extracts the attributes from the file and endpoint and returns a resource.
Expand Down
27 changes: 17 additions & 10 deletions cs3client/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import logging
import http
import requests
from typing import Union
from typing import Generator
import cs3.storage.provider.v1beta1.resources_pb2 as cs3spr
import cs3.storage.provider.v1beta1.provider_api_pb2 as cs3sp
Expand Down Expand Up @@ -169,7 +170,8 @@ def touch_file(self, auth_token: tuple, resource: Resource) -> None:
self._log.debug(f'msg="Invoked TouchFile" trace="{res.status.trace}"')

def write_file(
self, auth_token: tuple, resource: Resource, content: str | bytes, size: int, lock_md: tuple = ('', '')
self, auth_token: tuple, resource: Resource, content: Union[str, bytes], size: int,
lock_md: tuple = ('', '')
) -> None:
"""
Write a file using the given userid as access token. The entire content is written
Expand Down Expand Up @@ -307,9 +309,11 @@ def read_file(self, auth_token: tuple, resource: Resource, lock_id: str = None)
raise IOError(e)
data = fileget.iter_content(self._config.chunk_size)
if fileget.status_code != http.client.OK:
# status.message.replace('"', "'") is not allowed inside f strings python<3.12
status_msg = fileget.reason.replace('"', "'")
self._log.error(
f'msg="Error downloading file from Reva" code="{fileget.status_code}" '
f'reason="{fileget.reason.replace('"', "'")}"'
f'reason="{status_msg}"'
)
raise IOError(fileget.reason)
else:
Expand Down Expand Up @@ -355,7 +359,7 @@ def list_dir(
for info in res.infos:
yield info

def _set_lock_using_xattr(self, auth_token, resource: Resource, app_name: str, lock_id: int | str) -> None:
def _set_lock_using_xattr(self, auth_token, resource: Resource, app_name: str, lock_id: Union[int, str]) -> None:
""""
Set a lock to a resource with the given value metadata and appname as holder
Expand All @@ -376,7 +380,7 @@ def _set_lock_using_xattr(self, auth_token, resource: Resource, app_name: str, l
self.set_xattr(auth_token, resource, LOCK_ATTR_KEY, f"{app_name}!{lock_id}!{expiration}", None)
return

def set_lock(self, auth_token: tuple, resource: Resource, app_name: str, lock_id: int | str) -> None:
def set_lock(self, auth_token: tuple, resource: Resource, app_name: str, lock_id: Union[int, str]) -> None:
"""
Set a lock to a resource with the given value and appname as holder
Expand Down Expand Up @@ -439,7 +443,7 @@ def _get_lock_using_xattr(self, auth_token: tuple, resource: Resource) -> dict:
except KeyError:
return None

def get_lock(self, auth_token: tuple, resource: Resource) -> cs3spr.Lock | dict | None:
def get_lock(self, auth_token: tuple, resource: Resource) -> Union[cs3spr.Lock, dict, None]:
"""
Get the lock for the given filepath
Expand Down Expand Up @@ -480,7 +484,8 @@ def get_lock(self, auth_token: tuple, resource: Resource) -> cs3spr.Lock | dict
}

def _refresh_lock_using_xattr(
self, auth_token: tuple, resource: Resource, app_name: str, lock_id: str | int, existing_lock_id: str | int = None
self, auth_token: tuple, resource: Resource, app_name: str, lock_id: Union[str, int],
existing_lock_id: Union[str, int] = None
) -> None:
"""
Refresh the lock metadata for the given filepath
Expand Down Expand Up @@ -513,8 +518,8 @@ def _refresh_lock_using_xattr(
return

def refresh_lock(
self, auth_token: tuple, resource: Resource, app_name: str, lock_id: str | int,
existing_lock_id: str | int = None
self, auth_token: tuple, resource: Resource, app_name: str, lock_id: Union[str, int],
existing_lock_id: Union[str, int] = None
):
"""
Refresh the lock for the given filepath
Expand Down Expand Up @@ -553,7 +558,9 @@ def refresh_lock(
self._log.debug(f'msg="Invoked RefreshLock" {resource.get_file_ref_str()} result="{res.status.trace}" '
f'value="{lock_id}" old_value="{existing_lock_id}"')

def _unlock_using_xattr(self, auth_token: tuple, resource: Resource, app_name: str, lock_id: str | int) -> None:
def _unlock_using_xattr(
self, auth_token: tuple, resource: Resource, app_name: str, lock_id: Union[str, int]
) -> None:
"""
Remove the lock for the given filepath
Expand Down Expand Up @@ -581,7 +588,7 @@ def _unlock_using_xattr(self, auth_token: tuple, resource: Resource, app_name: s
self.remove_xattr(resource, LOCK_ATTR_KEY, None)
return

def unlock(self, auth_token: tuple, resource: Resource, app_name, lock_id: str | int):
def unlock(self, auth_token: tuple, resource: Resource, app_name, lock_id: Union[str, int]):
"""
Remove the lock for the given filepath
Expand Down
44 changes: 26 additions & 18 deletions cs3client/statuscodehandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,78 +20,86 @@ def __init__(self, log: logging.Logger, config: Config) -> None:
self._log = log
self._config = config

def _log_not_found_info(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_not_found_info(self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None) -> None:
self._log.info(
f'msg="Not found on {operation}" {msg + " " if msg else ""} '
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def _log_authentication_error(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_authentication_error(
self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None
) -> None:
self._log.error(
f'msg="Authentication failed on {operation}" {msg + " " if msg else ""}'
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def _log_unknown_error(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_unknown_error(self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None) -> None:
self._log.error(
f'msg="Failed to {operation}, unknown error" {msg + " " if msg else ""}'
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def _log_precondition_info(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_precondition_info(
self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None
) -> None:
self._log.info(
f'msg="Failed precondition on {operation}" {msg + " " if msg else ""}'
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def _log_already_exists(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_already_exists(self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None) -> None:
self._log.info(
f'msg="Already exists on {operation}" {msg + " " if msg else ""}'
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def _log_unimplemented(self, status: cs3status.Status, operation: str, msg: str = None) -> None:
def _log_unimplemented(self, status: cs3status.Status, operation: str, status_msg: str, msg: str = None) -> None:
self._log.info(
f'msg="Invoked {operation} on unimplemented feature" {msg + " " if msg else ""}'
f'userid="{self._config.auth_client_id if self._config.auth_client_id else "no_id_set"}" '
f'trace="{status.trace}" reason="{status.message.replace('"', "'")}"'
f'trace="{status.trace}" reason="{status_msg}"'
)

def handle_errors(self, status: cs3status.Status, operation: str, msg: str = None) -> None:

if status.code == cs3code.CODE_OK:
return
# status.message.replace('"', "'") is not allowed inside f strings python<3.12
status_message = status.message.replace('"', "'")

if status.code == cs3code.CODE_FAILED_PRECONDITION or status.code == cs3code.CODE_ABORTED:
self._log_precondition_info(status, operation, msg)
self._log_precondition_info(status, operation, status_message, msg)
raise FileLockedException(f'Failed precondition: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"')
if status.code == cs3code.CODE_ALREADY_EXISTS:
self._log_already_exists(status, operation, msg)
self._log_already_exists(status, operation, status_message, msg)
raise AlreadyExistsException(f'Resource already exists: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"')
if status.code == cs3code.CODE_UNIMPLEMENTED:
self._log.info(f'msg="Invoked {operation} on unimplemented feature" ')
raise UnimplementedException(f'Unimplemented feature: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"')
if status.code == cs3code.CODE_NOT_FOUND:
self._log_not_found_info(status, operation, msg)
self._log_not_found_info(status, operation, status_message, msg)
raise NotFoundException(f'Not found: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"')
if status.code == cs3code.CODE_UNAUTHENTICATED:
self._log_authentication_error(status, operation, msg)
self._log_authentication_error(status, operation, status_message, msg)
raise AuthenticationException(f'Operation not permitted: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"')
if status.code != cs3code.CODE_OK:
if "path not found" in str(status.message).lower():
self._log.info(f'msg="Invoked {operation} on missing file" ')
raise NotFoundException(
message=f'No such file or directory: operation="{operation}" '
f'status_code="{status.code}" message="{status.message}"'
f'status_code="{status.code}" message="{status.message}"'
)
self._log_unknown_error(status, operation, msg)
self._log_unknown_error(status, operation, status_message, msg)
raise UnknownException(f'Unknown Error: operation="{operation}" status_code="{status.code}" '
f'message="{status.message}"')

0 comments on commit 52fdebc

Please sign in to comment.