From d60e4144eba1b4bfdcc30c8cac10960a112e887e Mon Sep 17 00:00:00 2001 From: Alessio Del Conte Date: Wed, 14 Feb 2024 14:48:03 +0100 Subject: [PATCH] Execution tokens are now cpu credit --- drmaatic/admin.py | 4 ++-- drmaatic/models.py | 26 +++++++++++++------------- drmaatic/static/swagger.yml | 24 ++++++++++++------------ drmaatic/throttles.py | 34 +++++++++++++++++----------------- drmaatic/urls.py | 4 ++-- drmaatic/views.py | 6 +++--- 6 files changed, 49 insertions(+), 49 deletions(-) diff --git a/drmaatic/admin.py b/drmaatic/admin.py index 488e2c0..c8b733a 100644 --- a/drmaatic/admin.py +++ b/drmaatic/admin.py @@ -86,8 +86,8 @@ def clean(self): class GroupAdmin(admin.ModelAdmin): # Define columns to show list_display = ('name', 'has_full_access', 'throttling_rate_burst', - 'token_renewal_time', 'execution_token_max_amount', 'execution_token_regen_amount', - '_execution_token_regen_time') + 'token_renewal_time', 'cpu_credit_max_amount', 'cpu_credit_regen_amount', + '_cpu_credit_regen_time') form = GroupForm diff --git a/drmaatic/models.py b/drmaatic/models.py index d7d142e..2c21abd 100644 --- a/drmaatic/models.py +++ b/drmaatic/models.py @@ -1,5 +1,5 @@ from django.contrib.auth.models import AbstractUser -from django.db import models +from django.db import models, OperationalError from django.utils.translation import gettext_lazy from pytimeparse.timeparse import timeparse @@ -44,33 +44,33 @@ class Group(models.Model): has_full_access = models.BooleanField(default=False, blank=False, null=False) throttling_rate_burst = models.CharField(max_length=30, default="10/s", null=False, blank=False) token_renewal_time = models.CharField(default="1 day", null=False, blank=False, max_length=40) - execution_token_max_amount = models.IntegerField(default=100, blank=False, null=False) - _execution_token_regen_time = models.CharField(default="30 seconds", null=False, blank=False, max_length=40) - execution_token_regen_amount = models.IntegerField(default=1, blank=False, null=False) + cpu_credit_max_amount = models.IntegerField(default=100, blank=False, null=False) + _cpu_credit_regen_time = models.CharField(default="30 seconds", null=False, blank=False, max_length=40) + cpu_credit_regen_amount = models.IntegerField(default=1, blank=False, null=False) @property - def execution_token_regen_time(self): - return timeparse(self._execution_token_regen_time) + def cpu_credit_regen_time(self): + return timeparse(self._cpu_credit_regen_time) @classproperty def anonymous(self): if table_exists('drmaatic_group', 'default'): return self.objects.get_or_create(name='anonymous', defaults={'throttling_rate_burst': '20/s', 'token_renewal_time': '3 days', - 'execution_token_max_amount': 100})[0] + 'cpu_credit_max_amount': 100})[0] else: return Group(name='anonymous', throttling_rate_burst='20/s', token_renewal_time='3 days', - execution_token_max_amount=100) + cpu_credit_max_amount=100) @classproperty def registered(self): - if table_exists('drmaatic_group', 'default'): + try: return self.objects.get_or_create(name='registered', defaults={'throttling_rate_burst': '30/s', 'token_renewal_time': '5 days', - 'execution_token_max_amount': 200})[0] - else: - return Group(name='anonymous', throttling_rate_burst='20/s', token_renewal_time='3 days', - execution_token_max_amount=100) + 'cpu_credit_max_amount': 200})[0] + except OperationalError: + return Group(name='registered', throttling_rate_burst='30/s', token_renewal_time='5 days', + cpu_credit_max_amount=200) def __str__(self): return self.name diff --git a/drmaatic/static/swagger.yml b/drmaatic/static/swagger.yml index 4aac215..90f1203 100644 --- a/drmaatic/static/swagger.yml +++ b/drmaatic/static/swagger.yml @@ -24,8 +24,8 @@ info: 2. **Job Management**: DRMAAtic enables users to create, manage, and monitor jobs seamlessly. Users can define jobs with varying parameters and types, submit them to the DRM (Digital Rights Management), and access job-related information. - 3. **Execution Tokens**: The system tracks and manages execution tokens, which are essential for job execution. - Users can check the number of available execution tokens, ensuring efficient resource utilization. + 3. **CPU credit**: The system tracks and manages CPU credit, which are essential for job execution. + Users can check the number of available CPU credit, ensuring efficient resource utilization. 4. **Task Catalog**: DRMAAtic offers a catalog of available tasks, providing users with detailed information about each task's parameters, requirements, and descriptions. @@ -38,7 +38,7 @@ info: - **Retrieve Internal JWT**: Allows users to obtain JWT tokens for authenticating with DRMAAtic, using access tokens from external providers. - - **Number of Execution Tokens**: Provides the count of available execution tokens for the user. + - **Amount of CPU credit**: Provides the count of available CPU credit for the user. - **Create a New Job**: Enables users to create new jobs, defining job parameters based on specific tasks. @@ -125,12 +125,12 @@ paths: example: 'Authentication header is not valid' tags: - 'Authentication' - /execution-tokens/: + /cpu-credit/: get: - operationId: get_execution_tokens_number - summary: 'Number of execution tokens' + operationId: get_cpu_credit_amount + summary: 'Amount of CPU credit' description: | - Get the number of execution tokens that the user has at the moment. + Get the amount of CPU credit that the user has at the moment. If the user is not logged, the user is identified with the IP address. Pass the JWT token in the Authorization header to identify the user. @@ -138,21 +138,21 @@ paths: - name: required in: query required: false - description: 'If the user needs a specific number of execution tokens, it returns the time in seconds that the user has to wait to get the required number of tokens' + description: 'If the user needs a specific amount of CPU credit, it returns the time in seconds that the user has to wait to get the required number of tokens' schema: type: integer minimum: 0 responses: '200': description: | - Number of execution tokens, and wait time if the user needs a specific number of tokens.
+ Amount of CPU credit, and wait time if the user needs a specific number of tokens.
**If the specified number of tokens exceeds the maximum number, "infinite" is returned as wait_time** content: application/json: schema: type: object properties: - available_execution_tokens: + available_cpu_credit: type: integer example: 10 wait_time: @@ -161,7 +161,7 @@ paths: - string example: 200 tags: - - 'Execution tokens' + - 'CPU credit' /job/: post: operationId: createJob @@ -806,7 +806,7 @@ components: type: string maxLength: 100 required_tokens: - description: 'Number of execution tokens that the job will need to be executed' + description: 'Amount of CPU credit that the job will need to be executed' type: integer maximum: 2147483647 minimum: 0 diff --git a/drmaatic/throttles.py b/drmaatic/throttles.py index f4e67e6..d9ea7d5 100644 --- a/drmaatic/throttles.py +++ b/drmaatic/throttles.py @@ -94,33 +94,33 @@ def user(self, user): self._user = user @property - def user_tokens_key(self): + def user_credit_key(self): return f"{self.TOKENS_CACHE_PREFIX}{self.user_id}" @property - def user_current_tokens(self): - return cache.get(self.user_tokens_key, self.max_tokens) + def user_current_credit(self): + return cache.get(self.user_credit_key, self.max_tokens) @property def max_tokens(self): if not self.anonymous_request: - return self.user.group.execution_token_max_amount + return self.user.group.cpu_credit_max_amount else: - return Group.anonymous.execution_token_max_amount + return Group.anonymous.cpu_credit_max_amount @property def token_regen_interval(self): if not self.anonymous_request: - return self.user.group.execution_token_regen_time + return self.user.group.cpu_credit_regen_time else: - return Group.anonymous.execution_token_regen_time + return Group.anonymous.cpu_credit_regen_time @property def token_regen_amount(self): if not self.anonymous_request: - return self.user.group.execution_token_regen_amount + return self.user.group.cpu_credit_regen_amount else: - return Group.anonymous.execution_token_regen_amount + return Group.anonymous.cpu_credit_regen_amount @property def last_regen_time_key(self): @@ -147,14 +147,14 @@ def regenerate_tokens(self): regenerated_tokens = int(time_since_last_regen / self.token_regen_interval) * self.token_regen_amount - new_tokens = min(max_tokens, self.user_current_tokens + regenerated_tokens) - cache.set(self.user_tokens_key, new_tokens, None) + new_tokens = min(max_tokens, self.user_current_credit + regenerated_tokens) + cache.set(self.user_credit_key, new_tokens, None) else: self.wait_time = timedelta(seconds=self.token_regen_interval - time_since_last_regen) def deduct_tokens(self, tokens): - new_tokens = max(0, self.user_current_tokens - tokens) - cache.set(self.user_tokens_key, new_tokens, None) + new_tokens = max(0, self.user_current_credit - tokens) + cache.set(self.user_credit_key, new_tokens, None) def extract_user_from_request(self, request): self.anonymous_request = False @@ -176,7 +176,7 @@ def calculate_time_to_wait(self, tokens_requested) -> float: if tokens_requested > self.max_tokens: return float('inf') - tokens_to_wait = tokens_requested - self.user_current_tokens + tokens_to_wait = tokens_requested - self.user_current_credit # If there are enough tokens, then no need to wait if tokens_to_wait <= 0: return 0 @@ -190,11 +190,11 @@ def allow_request(self, request, view): self.regenerate_tokens() - request.available_execution_tokens = self.user_current_tokens + request.available_cpu_credit = self.user_current_credit # If the request is for the view for retrieving the execution token, and the required parameter is present, then calculate the time to wait for # the tokens to be available, if ever - if self.view_name == 'retrieve_execution_token' and 'required' in request.query_params: + if self.view_name == 'retrieve_cpu_credit' and 'required' in request.query_params: try: token_requested = int(request.query_params['required']) except ValueError: @@ -212,7 +212,7 @@ def allow_request(self, request, view): except (Task.DoesNotExist, KeyError): return True - if self.user_current_tokens >= required_tokens: + if self.user_current_credit >= required_tokens: self.deduct_tokens(required_tokens) return self.throttle_success() diff --git a/drmaatic/urls.py b/drmaatic/urls.py index 08db6bf..30c109c 100644 --- a/drmaatic/urls.py +++ b/drmaatic/urls.py @@ -20,7 +20,7 @@ JobStatusView = drmaatic.job.views.JobViewSet.as_view({'get': 'status'}) JobAssignOwnershipView = drmaatic.job.views.JobViewSet.as_view({'put': 'assign_ownership'}) -ExecutionTokenView = drmaatic.views.retrieve_execution_token +CPUCreditView = drmaatic.views.retrieve_cpu_credit # Define URL patterns urlpatterns = [ @@ -32,7 +32,7 @@ re_path(r'^job/(?P[^/.]+)/status/$', JobStatusView), re_path(r'^job/(?P[^/.]+)/get_ownership/$', JobAssignOwnershipView), - re_path(r'^execution-tokens/$', ExecutionTokenView, name='execution tokens'), + re_path(r'^cpu-credit/$', CPUCreditView, name='CPU credit'), path(r'', TemplateView.as_view( template_name='swagger-ui.html', diff --git a/drmaatic/views.py b/drmaatic/views.py index fb5d235..ce037ad 100644 --- a/drmaatic/views.py +++ b/drmaatic/views.py @@ -23,14 +23,14 @@ def retrieve_internal_token(request, **kwargs): @authentication_classes([BearerAuthentication]) @throttle_classes([TokenBucketThrottle]) @renderer_classes([JSONRenderer]) -def retrieve_execution_token(request): +def retrieve_cpu_credit(request): # If in the request there is a required number of tokens, then calculate in how many seconds the tokens will be available, if ever if 'required' in request.query_params: wait_time = request.time_to_wait wait_time_value = 'infinite' if wait_time == float('inf') else int(wait_time) - return Response(data={'available_execution_tokens': request.available_execution_tokens, + return Response(data={'available_cpu_credit': request.available_cpu_credit, 'wait_time': wait_time_value}, status=status.HTTP_200_OK) # Based on the renderers, the response will be either JSON or plain text - return Response(data={'available_execution_tokens': request.available_execution_tokens}, status=status.HTTP_200_OK) + return Response(data={'available_cpu_credit': request.available_cpu_credit}, status=status.HTTP_200_OK)