From 992fc38604bfb2814ae4a85fdbd7e2fe7335b8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Fri, 22 Apr 2022 12:52:57 +0200 Subject: [PATCH] OAPI: add endpoint for fetching the tasks of a job Add `fetchJobTasks` operation to the Jobs API. This returns a summary of each of the job's tasks, suitable for display in a task list view. The actually used fields may need tweaking once we actually have a task list view, but at least the functionality is there. --- addon/flamenco/manager/__init__.py | 2 +- addon/flamenco/manager/api/jobs_api.py | 127 ++++++++ addon/flamenco/manager/api_client.py | 2 +- addon/flamenco/manager/configuration.py | 2 +- addon/flamenco/manager/docs/Job.md | 2 +- addon/flamenco/manager/docs/JobAllOf.md | 2 +- .../flamenco/manager/docs/JobTasksSummary.md | 13 + addon/flamenco/manager/docs/JobsApi.md | 68 ++++ addon/flamenco/manager/docs/TaskSummary.md | 18 ++ addon/flamenco/manager/model/job.py | 4 +- addon/flamenco/manager/model/job_all_of.py | 4 +- .../manager/model/job_tasks_summary.py | 261 +++++++++++++++ addon/flamenco/manager/model/task_summary.py | 297 ++++++++++++++++++ addon/flamenco/manager/models/__init__.py | 2 + addon/flamenco/manager_README.md | 6 +- internal/manager/api_impl/api_impl.go | 1 + internal/manager/api_impl/jobs_query.go | 39 +++ .../api_impl/mocks/api_impl_mock.gen.go | 15 + internal/manager/persistence/jobs_query.go | 16 + .../manager/persistence/jobs_query_test.go | 26 ++ internal/worker/mocks/client.gen.go | 20 ++ pkg/api/flamenco-manager.yaml | 46 ++- pkg/api/openapi_client.gen.go | 117 +++++++ pkg/api/openapi_server.gen.go | 20 ++ pkg/api/openapi_spec.gen.go | 209 ++++++------ pkg/api/openapi_types.gen.go | 17 +- web/app/src/manager-api/ApiClient.js | 2 +- web/app/src/manager-api/index.js | 14 + web/app/src/manager-api/manager/JobsApi.js | 47 +++ web/app/src/manager-api/model/Job.js | 6 +- web/app/src/manager-api/model/JobAllOf.js | 4 +- .../src/manager-api/model/JobTasksSummary.js | 73 +++++ web/app/src/manager-api/model/TaskSummary.js | 125 ++++++++ 33 files changed, 1486 insertions(+), 121 deletions(-) create mode 100644 addon/flamenco/manager/docs/JobTasksSummary.md create mode 100644 addon/flamenco/manager/docs/TaskSummary.md create mode 100644 addon/flamenco/manager/model/job_tasks_summary.py create mode 100644 addon/flamenco/manager/model/task_summary.py create mode 100644 web/app/src/manager-api/model/JobTasksSummary.js create mode 100644 web/app/src/manager-api/model/TaskSummary.js diff --git a/addon/flamenco/manager/__init__.py b/addon/flamenco/manager/__init__.py index c64e2a85..af47b382 100644 --- a/addon/flamenco/manager/__init__.py +++ b/addon/flamenco/manager/__init__.py @@ -10,7 +10,7 @@ """ -__version__ = "b699647e-dirty" +__version__ = "e399b14e-dirty" # import ApiClient from flamenco.manager.api_client import ApiClient diff --git a/addon/flamenco/manager/api/jobs_api.py b/addon/flamenco/manager/api/jobs_api.py index 2d54d4a4..34082009 100644 --- a/addon/flamenco/manager/api/jobs_api.py +++ b/addon/flamenco/manager/api/jobs_api.py @@ -26,6 +26,7 @@ from flamenco.manager.model.available_job_types import AvailableJobTypes from flamenco.manager.model.error import Error from flamenco.manager.model.job import Job from flamenco.manager.model.job_status_change import JobStatusChange +from flamenco.manager.model.job_tasks_summary import JobTasksSummary from flamenco.manager.model.jobs_query import JobsQuery from flamenco.manager.model.jobs_query_result import JobsQueryResult from flamenco.manager.model.submitted_job import SubmittedJob @@ -91,6 +92,55 @@ class JobsApi(object): }, api_client=api_client ) + self.fetch_job_tasks_endpoint = _Endpoint( + settings={ + 'response_type': (JobTasksSummary,), + 'auth': [], + 'endpoint_path': '/api/jobs/{job_id}/tasks', + 'operation_id': 'fetch_job_tasks', + 'http_method': 'GET', + 'servers': None, + }, + params_map={ + 'all': [ + 'job_id', + ], + 'required': [ + 'job_id', + ], + 'nullable': [ + ], + 'enum': [ + ], + 'validation': [ + ] + }, + root_map={ + 'validations': { + }, + 'allowed_values': { + }, + 'openapi_types': { + 'job_id': + (str,), + }, + 'attribute_map': { + 'job_id': 'job_id', + }, + 'location_map': { + 'job_id': 'path', + }, + 'collection_format_map': { + } + }, + headers_map={ + 'accept': [ + 'application/json' + ], + 'content_type': [], + }, + api_client=api_client + ) self.get_job_type_endpoint = _Endpoint( settings={ 'response_type': (AvailableJobType,), @@ -416,6 +466,83 @@ class JobsApi(object): job_id return self.fetch_job_endpoint.call_with_http_info(**kwargs) + def fetch_job_tasks( + self, + job_id, + **kwargs + ): + """Fetch a summary of all tasks of the given job. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.fetch_job_tasks(job_id, async_req=True) + >>> result = thread.get() + + Args: + job_id (str): + + Keyword Args: + _return_http_data_only (bool): response data without head status + code and headers. Default is True. + _preload_content (bool): if False, the urllib3.HTTPResponse object + will be returned without reading/decoding response data. + Default is True. + _request_timeout (int/float/tuple): timeout setting for this request. If + one number provided, it will be total request timeout. It can also + be a pair (tuple) of (connection, read) timeouts. + Default is None. + _check_input_type (bool): specifies if type checking + should be done one the data sent to the server. + Default is True. + _check_return_type (bool): specifies if type checking + should be done one the data received from the server. + Default is True. + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _content_type (str/None): force body content-type. + Default is None and content-type will be predicted by allowed + content-types and body. + _host_index (int/None): specifies the index of the server + that we want to use. + Default is read from the configuration. + async_req (bool): execute request asynchronously + + Returns: + JobTasksSummary + If the method is called asynchronously, returns the request + thread. + """ + kwargs['async_req'] = kwargs.get( + 'async_req', False + ) + kwargs['_return_http_data_only'] = kwargs.get( + '_return_http_data_only', True + ) + kwargs['_preload_content'] = kwargs.get( + '_preload_content', True + ) + kwargs['_request_timeout'] = kwargs.get( + '_request_timeout', None + ) + kwargs['_check_input_type'] = kwargs.get( + '_check_input_type', True + ) + kwargs['_check_return_type'] = kwargs.get( + '_check_return_type', True + ) + kwargs['_spec_property_naming'] = kwargs.get( + '_spec_property_naming', False + ) + kwargs['_content_type'] = kwargs.get( + '_content_type') + kwargs['_host_index'] = kwargs.get('_host_index') + kwargs['job_id'] = \ + job_id + return self.fetch_job_tasks_endpoint.call_with_http_info(**kwargs) + def get_job_type( self, type_name, diff --git a/addon/flamenco/manager/api_client.py b/addon/flamenco/manager/api_client.py index aa785e5b..44802d79 100644 --- a/addon/flamenco/manager/api_client.py +++ b/addon/flamenco/manager/api_client.py @@ -76,7 +76,7 @@ class ApiClient(object): self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = 'Flamenco/b699647e-dirty (Blender add-on)' + self.user_agent = 'Flamenco/e399b14e-dirty (Blender add-on)' def __enter__(self): return self diff --git a/addon/flamenco/manager/configuration.py b/addon/flamenco/manager/configuration.py index fc712b51..f47e21a0 100644 --- a/addon/flamenco/manager/configuration.py +++ b/addon/flamenco/manager/configuration.py @@ -404,7 +404,7 @@ conf = flamenco.manager.Configuration( "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 1.0.0\n"\ - "SDK Package Version: b699647e-dirty".\ + "SDK Package Version: e399b14e-dirty".\ format(env=sys.platform, pyversion=sys.version) def get_host_settings(self): diff --git a/addon/flamenco/manager/docs/Job.md b/addon/flamenco/manager/docs/Job.md index 7deac49e..92d47c60 100644 --- a/addon/flamenco/manager/docs/Job.md +++ b/addon/flamenco/manager/docs/Job.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes **type** | **str** | | **id** | **str** | UUID of the Job | **created** | **datetime** | Creation timestamp | -**updated** | **datetime** | Creation timestamp | +**updated** | **datetime** | Timestamp of last update. | **status** | [**JobStatus**](JobStatus.md) | | **activity** | **str** | Description of the last activity on this job. | **priority** | **int** | | defaults to 50 diff --git a/addon/flamenco/manager/docs/JobAllOf.md b/addon/flamenco/manager/docs/JobAllOf.md index 208d4cb3..2996067c 100644 --- a/addon/flamenco/manager/docs/JobAllOf.md +++ b/addon/flamenco/manager/docs/JobAllOf.md @@ -6,7 +6,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | UUID of the Job | **created** | **datetime** | Creation timestamp | -**updated** | **datetime** | Creation timestamp | +**updated** | **datetime** | Timestamp of last update. | **status** | [**JobStatus**](JobStatus.md) | | **activity** | **str** | Description of the last activity on this job. | **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] diff --git a/addon/flamenco/manager/docs/JobTasksSummary.md b/addon/flamenco/manager/docs/JobTasksSummary.md new file mode 100644 index 00000000..ade466c7 --- /dev/null +++ b/addon/flamenco/manager/docs/JobTasksSummary.md @@ -0,0 +1,13 @@ +# JobTasksSummary + +Simplified list of tasks of a job. Contains all tasks, but not all info of each task. + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**tasks** | [**[TaskSummary]**](TaskSummary.md) | | [optional] +**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/addon/flamenco/manager/docs/JobsApi.md b/addon/flamenco/manager/docs/JobsApi.md index c9606119..9889a680 100644 --- a/addon/flamenco/manager/docs/JobsApi.md +++ b/addon/flamenco/manager/docs/JobsApi.md @@ -5,6 +5,7 @@ All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- [**fetch_job**](JobsApi.md#fetch_job) | **GET** /api/jobs/{job_id} | Fetch info about the job. +[**fetch_job_tasks**](JobsApi.md#fetch_job_tasks) | **GET** /api/jobs/{job_id}/tasks | Fetch a summary of all tasks of the given job. [**get_job_type**](JobsApi.md#get_job_type) | **GET** /api/jobs/type/{typeName} | Get single job type and its parameters. [**get_job_types**](JobsApi.md#get_job_types) | **GET** /api/jobs/types | Get list of job types and their parameters. [**query_jobs**](JobsApi.md#query_jobs) | **POST** /api/jobs/query | Fetch list of jobs. @@ -77,6 +78,73 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **fetch_job_tasks** +> JobTasksSummary fetch_job_tasks(job_id) + +Fetch a summary of all tasks of the given job. + +### Example + + +```python +import time +import flamenco.manager +from flamenco.manager.api import jobs_api +from flamenco.manager.model.error import Error +from flamenco.manager.model.job_tasks_summary import JobTasksSummary +from pprint import pprint +# Defining the host is optional and defaults to http://localhost +# See configuration.py for a list of all supported configuration parameters. +configuration = flamenco.manager.Configuration( + host = "http://localhost" +) + + +# Enter a context with an instance of the API client +with flamenco.manager.ApiClient() as api_client: + # Create an instance of the API class + api_instance = jobs_api.JobsApi(api_client) + job_id = "job_id_example" # str | + + # example passing only required values which don't have defaults set + try: + # Fetch a summary of all tasks of the given job. + api_response = api_instance.fetch_job_tasks(job_id) + pprint(api_response) + except flamenco.manager.ApiException as e: + print("Exception when calling JobsApi->fetch_job_tasks: %s\n" % e) +``` + + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **job_id** | **str**| | + +### Return type + +[**JobTasksSummary**](JobTasksSummary.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Get summaries of the tasks of this job. | - | +**0** | Unexpected error. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **get_job_type** > AvailableJobType get_job_type(type_name) diff --git a/addon/flamenco/manager/docs/TaskSummary.md b/addon/flamenco/manager/docs/TaskSummary.md new file mode 100644 index 00000000..ffc6bd46 --- /dev/null +++ b/addon/flamenco/manager/docs/TaskSummary.md @@ -0,0 +1,18 @@ +# TaskSummary + +Just enough information about the task to show in the job's task list. + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**id** | **str** | | +**name** | **str** | | +**status** | [**TaskStatus**](TaskStatus.md) | | +**priority** | **int** | | +**task_type** | **str** | | +**updated** | **datetime** | | +**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/addon/flamenco/manager/model/job.py b/addon/flamenco/manager/model/job.py index 174a8377..ae848061 100644 --- a/addon/flamenco/manager/model/job.py +++ b/addon/flamenco/manager/model/job.py @@ -139,7 +139,7 @@ class Job(ModelComposed): priority (int): defaults to 50 # noqa: E501 id (str): UUID of the Job created (datetime): Creation timestamp - updated (datetime): Creation timestamp + updated (datetime): Timestamp of last update. status (JobStatus): activity (str): Description of the last activity on this job. _check_type (bool): if True, values for parameters in openapi_types @@ -249,7 +249,7 @@ class Job(ModelComposed): priority (int): defaults to 50 # noqa: E501 id (str): UUID of the Job created (datetime): Creation timestamp - updated (datetime): Creation timestamp + updated (datetime): Timestamp of last update. status (JobStatus): activity (str): Description of the last activity on this job. _check_type (bool): if True, values for parameters in openapi_types diff --git a/addon/flamenco/manager/model/job_all_of.py b/addon/flamenco/manager/model/job_all_of.py index 3ac458c0..6db70b3c 100644 --- a/addon/flamenco/manager/model/job_all_of.py +++ b/addon/flamenco/manager/model/job_all_of.py @@ -120,7 +120,7 @@ class JobAllOf(ModelNormal): Args: id (str): UUID of the Job created (datetime): Creation timestamp - updated (datetime): Creation timestamp + updated (datetime): Timestamp of last update. status (JobStatus): activity (str): Description of the last activity on this job. @@ -213,7 +213,7 @@ class JobAllOf(ModelNormal): Args: id (str): UUID of the Job created (datetime): Creation timestamp - updated (datetime): Creation timestamp + updated (datetime): Timestamp of last update. status (JobStatus): activity (str): Description of the last activity on this job. diff --git a/addon/flamenco/manager/model/job_tasks_summary.py b/addon/flamenco/manager/model/job_tasks_summary.py new file mode 100644 index 00000000..aeccb7e2 --- /dev/null +++ b/addon/flamenco/manager/model/job_tasks_summary.py @@ -0,0 +1,261 @@ +""" + Flamenco manager + + Render Farm manager API # noqa: E501 + + The version of the OpenAPI document: 1.0.0 + Generated by: https://openapi-generator.tech +""" + + +import re # noqa: F401 +import sys # noqa: F401 + +from flamenco.manager.model_utils import ( # noqa: F401 + ApiTypeError, + ModelComposed, + ModelNormal, + ModelSimple, + cached_property, + change_keys_js_to_python, + convert_js_args_to_python_args, + date, + datetime, + file_type, + none_type, + validate_get_composed_info, + OpenApiModel +) +from flamenco.manager.exceptions import ApiAttributeError + + +def lazy_import(): + from flamenco.manager.model.task_summary import TaskSummary + globals()['TaskSummary'] = TaskSummary + + +class JobTasksSummary(ModelNormal): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + + Attributes: + allowed_values (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + with a capitalized key describing the allowed value and an allowed + value. These dicts store the allowed enum values. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + discriminator_value_class_map (dict): A dict to go from the discriminator + variable value to the discriminator class name. + validations (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + that stores validations for max_length, min_length, max_items, + min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, + inclusive_minimum, and regex. + additional_properties_type (tuple): A tuple of classes accepted + as additional properties values. + """ + + allowed_values = { + } + + validations = { + } + + @cached_property + def additional_properties_type(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + """ + lazy_import() + return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 + + _nullable = False + + @cached_property + def openapi_types(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + + Returns + openapi_types (dict): The key is attribute name + and the value is attribute type. + """ + lazy_import() + return { + 'tasks': ([TaskSummary],), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + + attribute_map = { + 'tasks': 'tasks', # noqa: E501 + } + + read_only_vars = { + } + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 + """JobTasksSummary - a model defined in OpenAPI + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + tasks ([TaskSummary]): [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + self = super(OpenApiModel, cls).__new__(cls) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + return self + + required_properties = set([ + '_data_store', + '_check_type', + '_spec_property_naming', + '_path_to_item', + '_configuration', + '_visited_composed_classes', + ]) + + @convert_js_args_to_python_args + def __init__(self, *args, **kwargs): # noqa: E501 + """JobTasksSummary - a model defined in OpenAPI + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + tasks ([TaskSummary]): [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + if var_name in self.read_only_vars: + raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " + f"class with read only attributes.") diff --git a/addon/flamenco/manager/model/task_summary.py b/addon/flamenco/manager/model/task_summary.py new file mode 100644 index 00000000..81029867 --- /dev/null +++ b/addon/flamenco/manager/model/task_summary.py @@ -0,0 +1,297 @@ +""" + Flamenco manager + + Render Farm manager API # noqa: E501 + + The version of the OpenAPI document: 1.0.0 + Generated by: https://openapi-generator.tech +""" + + +import re # noqa: F401 +import sys # noqa: F401 + +from flamenco.manager.model_utils import ( # noqa: F401 + ApiTypeError, + ModelComposed, + ModelNormal, + ModelSimple, + cached_property, + change_keys_js_to_python, + convert_js_args_to_python_args, + date, + datetime, + file_type, + none_type, + validate_get_composed_info, + OpenApiModel +) +from flamenco.manager.exceptions import ApiAttributeError + + +def lazy_import(): + from flamenco.manager.model.task_status import TaskStatus + globals()['TaskStatus'] = TaskStatus + + +class TaskSummary(ModelNormal): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + + Attributes: + allowed_values (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + with a capitalized key describing the allowed value and an allowed + value. These dicts store the allowed enum values. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + discriminator_value_class_map (dict): A dict to go from the discriminator + variable value to the discriminator class name. + validations (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + that stores validations for max_length, min_length, max_items, + min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, + inclusive_minimum, and regex. + additional_properties_type (tuple): A tuple of classes accepted + as additional properties values. + """ + + allowed_values = { + } + + validations = { + } + + @cached_property + def additional_properties_type(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + """ + lazy_import() + return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 + + _nullable = False + + @cached_property + def openapi_types(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + + Returns + openapi_types (dict): The key is attribute name + and the value is attribute type. + """ + lazy_import() + return { + 'id': (str,), # noqa: E501 + 'name': (str,), # noqa: E501 + 'status': (TaskStatus,), # noqa: E501 + 'priority': (int,), # noqa: E501 + 'task_type': (str,), # noqa: E501 + 'updated': (datetime,), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + + attribute_map = { + 'id': 'id', # noqa: E501 + 'name': 'name', # noqa: E501 + 'status': 'status', # noqa: E501 + 'priority': 'priority', # noqa: E501 + 'task_type': 'task_type', # noqa: E501 + 'updated': 'updated', # noqa: E501 + } + + read_only_vars = { + } + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, id, name, status, priority, task_type, updated, *args, **kwargs): # noqa: E501 + """TaskSummary - a model defined in OpenAPI + + Args: + id (str): + name (str): + status (TaskStatus): + priority (int): + task_type (str): + updated (datetime): + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + self = super(OpenApiModel, cls).__new__(cls) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + self.id = id + self.name = name + self.status = status + self.priority = priority + self.task_type = task_type + self.updated = updated + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + return self + + required_properties = set([ + '_data_store', + '_check_type', + '_spec_property_naming', + '_path_to_item', + '_configuration', + '_visited_composed_classes', + ]) + + @convert_js_args_to_python_args + def __init__(self, id, name, status, priority, task_type, updated, *args, **kwargs): # noqa: E501 + """TaskSummary - a model defined in OpenAPI + + Args: + id (str): + name (str): + status (TaskStatus): + priority (int): + task_type (str): + updated (datetime): + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + self.id = id + self.name = name + self.status = status + self.priority = priority + self.task_type = task_type + self.updated = updated + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + if var_name in self.read_only_vars: + raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " + f"class with read only attributes.") diff --git a/addon/flamenco/manager/models/__init__.py b/addon/flamenco/manager/models/__init__.py index 2557c62d..35d58e6c 100644 --- a/addon/flamenco/manager/models/__init__.py +++ b/addon/flamenco/manager/models/__init__.py @@ -24,6 +24,7 @@ from flamenco.manager.model.job_metadata import JobMetadata from flamenco.manager.model.job_settings import JobSettings from flamenco.manager.model.job_status import JobStatus from flamenco.manager.model.job_status_change import JobStatusChange +from flamenco.manager.model.job_tasks_summary import JobTasksSummary from flamenco.manager.model.job_update import JobUpdate from flamenco.manager.model.jobs_query import JobsQuery from flamenco.manager.model.jobs_query_result import JobsQueryResult @@ -40,6 +41,7 @@ from flamenco.manager.model.shaman_requirements_response import ShamanRequiremen from flamenco.manager.model.shaman_single_file_status import ShamanSingleFileStatus from flamenco.manager.model.submitted_job import SubmittedJob from flamenco.manager.model.task_status import TaskStatus +from flamenco.manager.model.task_summary import TaskSummary from flamenco.manager.model.task_update import TaskUpdate from flamenco.manager.model.worker_registration import WorkerRegistration from flamenco.manager.model.worker_sign_on import WorkerSignOn diff --git a/addon/flamenco/manager_README.md b/addon/flamenco/manager_README.md index f8e66d5c..11138aed 100644 --- a/addon/flamenco/manager_README.md +++ b/addon/flamenco/manager_README.md @@ -4,7 +4,7 @@ Render Farm manager API The `flamenco.manager` package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: - API version: 1.0.0 -- Package version: b699647e-dirty +- Package version: e399b14e-dirty - Build package: org.openapitools.codegen.languages.PythonClientCodegen For more information, please visit [https://flamenco.io/](https://flamenco.io/) @@ -37,6 +37,7 @@ from flamenco.manager.model.available_job_types import AvailableJobTypes from flamenco.manager.model.error import Error from flamenco.manager.model.job import Job from flamenco.manager.model.job_status_change import JobStatusChange +from flamenco.manager.model.job_tasks_summary import JobTasksSummary from flamenco.manager.model.jobs_query import JobsQuery from flamenco.manager.model.jobs_query_result import JobsQueryResult from flamenco.manager.model.submitted_job import SubmittedJob @@ -69,6 +70,7 @@ All URIs are relative to *http://localhost* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- *JobsApi* | [**fetch_job**](flamenco/manager/docs/JobsApi.md#fetch_job) | **GET** /api/jobs/{job_id} | Fetch info about the job. +*JobsApi* | [**fetch_job_tasks**](flamenco/manager/docs/JobsApi.md#fetch_job_tasks) | **GET** /api/jobs/{job_id}/tasks | Fetch a summary of all tasks of the given job. *JobsApi* | [**get_job_type**](flamenco/manager/docs/JobsApi.md#get_job_type) | **GET** /api/jobs/type/{typeName} | Get single job type and its parameters. *JobsApi* | [**get_job_types**](flamenco/manager/docs/JobsApi.md#get_job_types) | **GET** /api/jobs/types | Get list of job types and their parameters. *JobsApi* | [**query_jobs**](flamenco/manager/docs/JobsApi.md#query_jobs) | **POST** /api/jobs/query | Fetch list of jobs. @@ -106,6 +108,7 @@ Class | Method | HTTP request | Description - [JobSettings](flamenco/manager/docs/JobSettings.md) - [JobStatus](flamenco/manager/docs/JobStatus.md) - [JobStatusChange](flamenco/manager/docs/JobStatusChange.md) + - [JobTasksSummary](flamenco/manager/docs/JobTasksSummary.md) - [JobUpdate](flamenco/manager/docs/JobUpdate.md) - [JobsQuery](flamenco/manager/docs/JobsQuery.md) - [JobsQueryResult](flamenco/manager/docs/JobsQueryResult.md) @@ -122,6 +125,7 @@ Class | Method | HTTP request | Description - [ShamanSingleFileStatus](flamenco/manager/docs/ShamanSingleFileStatus.md) - [SubmittedJob](flamenco/manager/docs/SubmittedJob.md) - [TaskStatus](flamenco/manager/docs/TaskStatus.md) + - [TaskSummary](flamenco/manager/docs/TaskSummary.md) - [TaskUpdate](flamenco/manager/docs/TaskUpdate.md) - [WorkerRegistration](flamenco/manager/docs/WorkerRegistration.md) - [WorkerSignOn](flamenco/manager/docs/WorkerSignOn.md) diff --git a/internal/manager/api_impl/api_impl.go b/internal/manager/api_impl/api_impl.go index 778c147a..9c4aa73a 100644 --- a/internal/manager/api_impl/api_impl.go +++ b/internal/manager/api_impl/api_impl.go @@ -56,6 +56,7 @@ type PersistenceService interface { // Database queries. QueryJobs(ctx context.Context, query api.JobsQuery) ([]*persistence.Job, error) + QueryJobTaskSummaries(ctx context.Context, jobUUID string) ([]*persistence.Task, error) } var _ PersistenceService = (*persistence.DB)(nil) diff --git a/internal/manager/api_impl/jobs_query.go b/internal/manager/api_impl/jobs_query.go index 00127cc3..b2b03097 100644 --- a/internal/manager/api_impl/jobs_query.go +++ b/internal/manager/api_impl/jobs_query.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "git.blender.org/flamenco/internal/manager/persistence" "git.blender.org/flamenco/pkg/api" "github.com/google/uuid" "github.com/labstack/echo/v4" @@ -58,3 +59,41 @@ func (f *Flamenco) QueryJobs(e echo.Context) error { } return e.JSON(http.StatusOK, result) } + +func (f *Flamenco) FetchJobTasks(e echo.Context, jobID string) error { + logger := requestLogger(e).With(). + Str("job", jobID). + Logger() + ctx := e.Request().Context() + + if _, err := uuid.Parse(jobID); err != nil { + logger.Debug().Msg("invalid job ID received") + return sendAPIError(e, http.StatusBadRequest, "job ID not valid") + } + + tasks, err := f.persist.QueryJobTaskSummaries(ctx, jobID) + if err != nil { + logger.Warn().Err(err).Msg("error querying for jobs") + return sendAPIError(e, http.StatusInternalServerError, "error querying for jobs") + } + + summaries := make([]api.TaskSummary, len(tasks)) + for i, task := range tasks { + summaries[i] = taskDBtoSummary(task) + } + result := api.JobTasksSummary{ + Tasks: &summaries, + } + return e.JSON(http.StatusOK, result) +} + +func taskDBtoSummary(task *persistence.Task) api.TaskSummary { + return api.TaskSummary{ + Id: task.UUID, + Name: task.Name, + Priority: task.Priority, + Status: task.Status, + TaskType: task.Type, + Updated: task.UpdatedAt, + } +} diff --git a/internal/manager/api_impl/mocks/api_impl_mock.gen.go b/internal/manager/api_impl/mocks/api_impl_mock.gen.go index 4a2930d4..b241cf37 100644 --- a/internal/manager/api_impl/mocks/api_impl_mock.gen.go +++ b/internal/manager/api_impl/mocks/api_impl_mock.gen.go @@ -114,6 +114,21 @@ func (mr *MockPersistenceServiceMockRecorder) FetchWorker(arg0, arg1 interface{} return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchWorker", reflect.TypeOf((*MockPersistenceService)(nil).FetchWorker), arg0, arg1) } +// QueryJobTaskSummaries mocks base method. +func (m *MockPersistenceService) QueryJobTaskSummaries(arg0 context.Context, arg1 string) ([]*persistence.Task, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryJobTaskSummaries", arg0, arg1) + ret0, _ := ret[0].([]*persistence.Task) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryJobTaskSummaries indicates an expected call of QueryJobTaskSummaries. +func (mr *MockPersistenceServiceMockRecorder) QueryJobTaskSummaries(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryJobTaskSummaries", reflect.TypeOf((*MockPersistenceService)(nil).QueryJobTaskSummaries), arg0, arg1) +} + // QueryJobs mocks base method. func (m *MockPersistenceService) QueryJobs(arg0 context.Context, arg1 api.JobsQuery) ([]*persistence.Job, error) { m.ctrl.T.Helper() diff --git a/internal/manager/persistence/jobs_query.go b/internal/manager/persistence/jobs_query.go index 062d79e2..314afbe1 100644 --- a/internal/manager/persistence/jobs_query.go +++ b/internal/manager/persistence/jobs_query.go @@ -68,3 +68,19 @@ func (db *DB) QueryJobs(ctx context.Context, apiQ api.JobsQuery) ([]*Job, error) tx := q.Scan(&result) return result, tx.Error } + +// QueryJobTaskSummaries retrieves all tasks of the job, but not all fields of those tasks. +// Fields are synchronised with api.TaskSummary. +func (db *DB) QueryJobTaskSummaries(ctx context.Context, jobUUID string) ([]*Task, error) { + logger := log.Ctx(ctx) + logger.Debug().Str("job", jobUUID).Msg("queryingtask summaries") + + var result []*Task + tx := db.gormDB.WithContext(ctx).Model(&Task{}). + Select("tasks.id", "tasks.uuid", "tasks.name", "tasks.priority", "tasks.status", "tasks.type", "tasks.updated_at"). + Joins("left join jobs on jobs.uuid = ?", jobUUID). + // Where("jobs.uuid=?", jobUUID). + Scan(&result) + + return result, tx.Error +} diff --git a/internal/manager/persistence/jobs_query_test.go b/internal/manager/persistence/jobs_query_test.go index 03b741b6..385b4d2c 100644 --- a/internal/manager/persistence/jobs_query_test.go +++ b/internal/manager/persistence/jobs_query_test.go @@ -104,3 +104,29 @@ func TestQueryMetadata(t *testing.T) { assert.Equal(t, otherJob.ID, result[0].ID, "status is %s", result[0].Status) assert.Equal(t, testJob.ID, result[1].ID, "status is %s", result[1].Status) } + +func TestFetchJobSummary(t *testing.T) { + ctx, close, db, job, authoredJob := jobTasksTestFixtures(t) + defer close() + + expectTaskUUIDs := map[string]bool{} + for _, task := range authoredJob.Tasks { + expectTaskUUIDs[task.UUID] = true + } + + // Create another test job, just to check we get the right tasks back. + otherAuthoredJob := createTestAuthoredJobWithTasks() + otherAuthoredJob.Status = api.JobStatusActive + otherAuthoredJob.Tasks = []job_compilers.AuthoredTask{} + otherAuthoredJob.JobID = "138678c8-efd0-452b-ac05-397ff4c02b26" + otherAuthoredJob.Metadata["project"] = "Other Project" + persistAuthoredJob(t, ctx, db, otherAuthoredJob) + + summaries, err := db.QueryJobTaskSummaries(ctx, job.UUID) + assert.NoError(t, err) + + assert.Len(t, summaries, len(expectTaskUUIDs)) + for _, summary := range summaries { + assert.True(t, expectTaskUUIDs[summary.UUID], "%q should be in %v", summary.UUID, expectTaskUUIDs) + } +} diff --git a/internal/worker/mocks/client.gen.go b/internal/worker/mocks/client.gen.go index c7386d3b..e93109f4 100644 --- a/internal/worker/mocks/client.gen.go +++ b/internal/worker/mocks/client.gen.go @@ -36,6 +36,26 @@ func (m *MockFlamencoClient) EXPECT() *MockFlamencoClientMockRecorder { return m.recorder } +// FetchJobTasksWithResponse mocks base method. +func (m *MockFlamencoClient) FetchJobTasksWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobTasksResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FetchJobTasksWithResponse", varargs...) + ret0, _ := ret[0].(*api.FetchJobTasksResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchJobTasksWithResponse indicates an expected call of FetchJobTasksWithResponse. +func (mr *MockFlamencoClientMockRecorder) FetchJobTasksWithResponse(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJobTasksWithResponse", reflect.TypeOf((*MockFlamencoClient)(nil).FetchJobTasksWithResponse), varargs...) +} + // FetchJobWithResponse mocks base method. func (m *MockFlamencoClient) FetchJobWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobResponse, error) { m.ctrl.T.Helper() diff --git a/pkg/api/flamenco-manager.yaml b/pkg/api/flamenco-manager.yaml index f8c60fae..770cd19c 100644 --- a/pkg/api/flamenco-manager.yaml +++ b/pkg/api/flamenco-manager.yaml @@ -351,6 +351,29 @@ paths: schema: $ref: "#/components/schemas/Error" + /api/jobs/{job_id}/tasks: + summary: Access tasks of this job. + get: + operationId: fetchJobTasks + summary: Fetch a summary of all tasks of the given job. + tags: [jobs] + parameters: + - name: job_id + in: path + required: true + schema: { type: string, format: uuid } + responses: + "200": + description: Get summaries of the tasks of this job. + content: + application/json: + schema: { $ref: "#/components/schemas/JobTasksSummary" } + default: + description: Unexpected error. + content: + application/json: + schema: + $ref: "#/components/schemas/Error" ## Shaman @@ -783,7 +806,7 @@ components: updated: type: string format: date-time - description: Creation timestamp + description: Timestamp of last update. status: { $ref: "#/components/schemas/JobStatus" } activity: { type: string, description: "Description of the last activity on this job." } required: [id, created, updated, status, activity] @@ -841,6 +864,27 @@ components: items: { $ref: "#/components/schemas/Job" } required: [jobs] + JobTasksSummary: + description: "Simplified list of tasks of a job. Contains all tasks, but not all info of each task." + type: object + properties: + tasks: + type: array + items: { $ref: "#/components/schemas/TaskSummary" } + required: [jobs] + + TaskSummary: + type: object + description: Just enough information about the task to show in the job's task list. + properties: + id: { type: string, format: uuid } + name: { type: string } + status: { $ref: "#/components/schemas/TaskStatus" } + priority: { type: integer } + task_type: { type: string } + updated: { type: string, format: date-time } + required: [id, name, status, priority, task_type, updated] + JobStatusChange: type: object properties: diff --git a/pkg/api/openapi_client.gen.go b/pkg/api/openapi_client.gen.go index 12ff9910..6ba7adb8 100644 --- a/pkg/api/openapi_client.gen.go +++ b/pkg/api/openapi_client.gen.go @@ -117,6 +117,9 @@ type ClientInterface interface { SetJobStatus(ctx context.Context, jobId string, body SetJobStatusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // FetchJobTasks request + FetchJobTasks(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) + // GetVersion request GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -286,6 +289,18 @@ func (c *Client) SetJobStatus(ctx context.Context, jobId string, body SetJobStat return c.Client.Do(req) } +func (c *Client) FetchJobTasks(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewFetchJobTasksRequest(c.Server, jobId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) GetVersion(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewGetVersionRequest(c.Server) if err != nil { @@ -751,6 +766,40 @@ func NewSetJobStatusRequestWithBody(server string, jobId string, contentType str return req, nil } +// NewFetchJobTasksRequest generates requests for FetchJobTasks +func NewFetchJobTasksRequest(server string, jobId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "job_id", runtime.ParamLocationPath, jobId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/api/jobs/%s/tasks", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewGetVersionRequest generates requests for GetVersion func NewGetVersionRequest(server string) (*http.Request, error) { var err error @@ -1282,6 +1331,9 @@ type ClientWithResponsesInterface interface { SetJobStatusWithResponse(ctx context.Context, jobId string, body SetJobStatusJSONRequestBody, reqEditors ...RequestEditorFn) (*SetJobStatusResponse, error) + // FetchJobTasks request + FetchJobTasksWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobTasksResponse, error) + // GetVersion request GetVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetVersionResponse, error) @@ -1487,6 +1539,29 @@ func (r SetJobStatusResponse) StatusCode() int { return 0 } +type FetchJobTasksResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *JobTasksSummary + JSONDefault *Error +} + +// Status returns HTTPResponse.Status +func (r FetchJobTasksResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r FetchJobTasksResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type GetVersionResponse struct { Body []byte HTTPResponse *http.Response @@ -1848,6 +1923,15 @@ func (c *ClientWithResponses) SetJobStatusWithResponse(ctx context.Context, jobI return ParseSetJobStatusResponse(rsp) } +// FetchJobTasksWithResponse request returning *FetchJobTasksResponse +func (c *ClientWithResponses) FetchJobTasksWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobTasksResponse, error) { + rsp, err := c.FetchJobTasks(ctx, jobId, reqEditors...) + if err != nil { + return nil, err + } + return ParseFetchJobTasksResponse(rsp) +} + // GetVersionWithResponse request returning *GetVersionResponse func (c *ClientWithResponses) GetVersionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetVersionResponse, error) { rsp, err := c.GetVersion(ctx, reqEditors...) @@ -2200,6 +2284,39 @@ func ParseSetJobStatusResponse(rsp *http.Response) (*SetJobStatusResponse, error return response, nil } +// ParseFetchJobTasksResponse parses an HTTP response from a FetchJobTasksWithResponse call +func ParseFetchJobTasksResponse(rsp *http.Response) (*FetchJobTasksResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &FetchJobTasksResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest JobTasksSummary + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && true: + var dest Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSONDefault = &dest + + } + + return response, nil +} + // ParseGetVersionResponse parses an HTTP response from a GetVersionWithResponse call func ParseGetVersionResponse(rsp *http.Response) (*GetVersionResponse, error) { bodyBytes, err := ioutil.ReadAll(rsp.Body) diff --git a/pkg/api/openapi_server.gen.go b/pkg/api/openapi_server.gen.go index ea914967..4c13d3fc 100644 --- a/pkg/api/openapi_server.gen.go +++ b/pkg/api/openapi_server.gen.go @@ -34,6 +34,9 @@ type ServerInterface interface { // (POST /api/jobs/{job_id}/setstatus) SetJobStatus(ctx echo.Context, jobId string) error + // Fetch a summary of all tasks of the given job. + // (GET /api/jobs/{job_id}/tasks) + FetchJobTasks(ctx echo.Context, jobId string) error // Get the Flamenco version of this Manager // (GET /api/version) GetVersion(ctx echo.Context) error @@ -162,6 +165,22 @@ func (w *ServerInterfaceWrapper) SetJobStatus(ctx echo.Context) error { return err } +// FetchJobTasks converts echo context to params. +func (w *ServerInterfaceWrapper) FetchJobTasks(ctx echo.Context) error { + var err error + // ------------- Path parameter "job_id" ------------- + var jobId string + + err = runtime.BindStyledParameterWithLocation("simple", false, "job_id", runtime.ParamLocationPath, ctx.Param("job_id"), &jobId) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter job_id: %s", err)) + } + + // Invoke the callback with all the unmarshalled arguments + err = w.Handler.FetchJobTasks(ctx, jobId) + return err +} + // GetVersion converts echo context to params. func (w *ServerInterfaceWrapper) GetVersion(ctx echo.Context) error { var err error @@ -389,6 +408,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/api/jobs/types", wrapper.GetJobTypes) router.GET(baseURL+"/api/jobs/:job_id", wrapper.FetchJob) router.POST(baseURL+"/api/jobs/:job_id/setstatus", wrapper.SetJobStatus) + router.GET(baseURL+"/api/jobs/:job_id/tasks", wrapper.FetchJobTasks) router.GET(baseURL+"/api/version", wrapper.GetVersion) router.POST(baseURL+"/api/worker/register-worker", wrapper.RegisterWorker) router.POST(baseURL+"/api/worker/sign-off", wrapper.SignOff) diff --git a/pkg/api/openapi_spec.gen.go b/pkg/api/openapi_spec.gen.go index a9ecf5bb..b5b6b01f 100644 --- a/pkg/api/openapi_spec.gen.go +++ b/pkg/api/openapi_spec.gen.go @@ -18,109 +18,112 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "vqPX9dn1/wQAAP//GzfZKqRpAAA=", + "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", + "1Gk663t6Xb69/J8AAAD//wGTUz2RbgAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/api/openapi_types.gen.go b/pkg/api/openapi_types.gen.go index 64ebb470..f0c4ba51 100644 --- a/pkg/api/openapi_types.gen.go +++ b/pkg/api/openapi_types.gen.go @@ -213,7 +213,7 @@ type Job struct { Id string `json:"id"` Status JobStatus `json:"status"` - // Creation timestamp + // Timestamp of last update. Updated time.Time `json:"updated"` } @@ -237,6 +237,11 @@ type JobStatusChange struct { Status JobStatus `json:"status"` } +// Simplified list of tasks of a job. Contains all tasks, but not all info of each task. +type JobTasksSummary struct { + Tasks *[]TaskSummary `json:"tasks,omitempty"` +} + // Subset of a Job, sent over SocketIO when a job changes. For new jobs, `previous_status` will be excluded. type JobUpdate struct { // UUID of the Job @@ -379,6 +384,16 @@ type SubmittedJob struct { // TaskStatus defines model for TaskStatus. type TaskStatus string +// Just enough information about the task to show in the job's task list. +type TaskSummary struct { + Id string `json:"id"` + Name string `json:"name"` + Priority int `json:"priority"` + Status TaskStatus `json:"status"` + TaskType string `json:"task_type"` + Updated time.Time `json:"updated"` +} + // TaskUpdate is sent by a Worker to update the status & logs of a task it's executing. type TaskUpdate struct { // One-liner to indicate what's currently happening with the task. Overwrites previously sent activity strings. diff --git a/web/app/src/manager-api/ApiClient.js b/web/app/src/manager-api/ApiClient.js index 327bcec9..bcf77e43 100644 --- a/web/app/src/manager-api/ApiClient.js +++ b/web/app/src/manager-api/ApiClient.js @@ -55,7 +55,7 @@ class ApiClient { * @default {} */ this.defaultHeaders = { - 'User-Agent': 'Flamenco/b699647e-dirty / webbrowser' + 'User-Agent': 'Flamenco/e399b14e-dirty / webbrowser' }; /** diff --git a/web/app/src/manager-api/index.js b/web/app/src/manager-api/index.js index 7549a99c..53f46278 100644 --- a/web/app/src/manager-api/index.js +++ b/web/app/src/manager-api/index.js @@ -26,6 +26,7 @@ import Job from './model/Job'; import JobAllOf from './model/JobAllOf'; import JobStatus from './model/JobStatus'; import JobStatusChange from './model/JobStatusChange'; +import JobTasksSummary from './model/JobTasksSummary'; import JobUpdate from './model/JobUpdate'; import JobsQuery from './model/JobsQuery'; import JobsQueryResult from './model/JobsQueryResult'; @@ -42,6 +43,7 @@ import ShamanRequirementsResponse from './model/ShamanRequirementsResponse'; import ShamanSingleFileStatus from './model/ShamanSingleFileStatus'; import SubmittedJob from './model/SubmittedJob'; import TaskStatus from './model/TaskStatus'; +import TaskSummary from './model/TaskSummary'; import TaskUpdate from './model/TaskUpdate'; import WorkerRegistration from './model/WorkerRegistration'; import WorkerSignOn from './model/WorkerSignOn'; @@ -170,6 +172,12 @@ export { */ JobStatusChange, + /** + * The JobTasksSummary model constructor. + * @property {module:model/JobTasksSummary} + */ + JobTasksSummary, + /** * The JobUpdate model constructor. * @property {module:model/JobUpdate} @@ -266,6 +274,12 @@ export { */ TaskStatus, + /** + * The TaskSummary model constructor. + * @property {module:model/TaskSummary} + */ + TaskSummary, + /** * The TaskUpdate model constructor. * @property {module:model/TaskUpdate} diff --git a/web/app/src/manager-api/manager/JobsApi.js b/web/app/src/manager-api/manager/JobsApi.js index bcbfb787..217f1baa 100644 --- a/web/app/src/manager-api/manager/JobsApi.js +++ b/web/app/src/manager-api/manager/JobsApi.js @@ -18,6 +18,7 @@ import AvailableJobTypes from '../model/AvailableJobTypes'; import Error from '../model/Error'; import Job from '../model/Job'; import JobStatusChange from '../model/JobStatusChange'; +import JobTasksSummary from '../model/JobTasksSummary'; import JobsQuery from '../model/JobsQuery'; import JobsQueryResult from '../model/JobsQueryResult'; import SubmittedJob from '../model/SubmittedJob'; @@ -88,6 +89,52 @@ export default class JobsApi { } + /** + * Fetch a summary of all tasks of the given job. + * @param {String} jobId + * @return {Promise} a {@link https://www.promisejs.org/|Promise}, with an object containing data of type {@link module:model/JobTasksSummary} and HTTP response + */ + fetchJobTasksWithHttpInfo(jobId) { + let postBody = null; + // verify the required parameter 'jobId' is set + if (jobId === undefined || jobId === null) { + throw new Error("Missing the required parameter 'jobId' when calling fetchJobTasks"); + } + + let pathParams = { + 'job_id': jobId + }; + let queryParams = { + }; + let headerParams = { + }; + let formParams = { + }; + + let authNames = []; + let contentTypes = []; + let accepts = ['application/json']; + let returnType = JobTasksSummary; + return this.apiClient.callApi( + '/api/jobs/{job_id}/tasks', 'GET', + pathParams, queryParams, headerParams, formParams, postBody, + authNames, contentTypes, accepts, returnType, null + ); + } + + /** + * Fetch a summary of all tasks of the given job. + * @param {String} jobId + * @return {Promise} a {@link https://www.promisejs.org/|Promise}, with data of type {@link module:model/JobTasksSummary} + */ + fetchJobTasks(jobId) { + return this.fetchJobTasksWithHttpInfo(jobId) + .then(function(response_and_data) { + return response_and_data.data; + }); + } + + /** * Get single job type and its parameters. * @param {String} typeName diff --git a/web/app/src/manager-api/model/Job.js b/web/app/src/manager-api/model/Job.js index 27d92293..c59940cb 100644 --- a/web/app/src/manager-api/model/Job.js +++ b/web/app/src/manager-api/model/Job.js @@ -32,7 +32,7 @@ class Job { * @param priority {Number} * @param id {String} UUID of the Job * @param created {Date} Creation timestamp - * @param updated {Date} Creation timestamp + * @param updated {Date} Timestamp of last update. * @param status {module:model/JobStatus} * @param activity {String} Description of the last activity on this job. */ @@ -147,7 +147,7 @@ Job.prototype['id'] = undefined; Job.prototype['created'] = undefined; /** - * Creation timestamp + * Timestamp of last update. * @member {Date} updated */ Job.prototype['updated'] = undefined; @@ -199,7 +199,7 @@ JobAllOf.prototype['id'] = undefined; */ JobAllOf.prototype['created'] = undefined; /** - * Creation timestamp + * Timestamp of last update. * @member {Date} updated */ JobAllOf.prototype['updated'] = undefined; diff --git a/web/app/src/manager-api/model/JobAllOf.js b/web/app/src/manager-api/model/JobAllOf.js index e8800ab7..2be915bb 100644 --- a/web/app/src/manager-api/model/JobAllOf.js +++ b/web/app/src/manager-api/model/JobAllOf.js @@ -25,7 +25,7 @@ class JobAllOf { * @alias module:model/JobAllOf * @param id {String} UUID of the Job * @param created {Date} Creation timestamp - * @param updated {Date} Creation timestamp + * @param updated {Date} Timestamp of last update. * @param status {module:model/JobStatus} * @param activity {String} Description of the last activity on this job. */ @@ -93,7 +93,7 @@ JobAllOf.prototype['id'] = undefined; JobAllOf.prototype['created'] = undefined; /** - * Creation timestamp + * Timestamp of last update. * @member {Date} updated */ JobAllOf.prototype['updated'] = undefined; diff --git a/web/app/src/manager-api/model/JobTasksSummary.js b/web/app/src/manager-api/model/JobTasksSummary.js new file mode 100644 index 00000000..4ae4da7c --- /dev/null +++ b/web/app/src/manager-api/model/JobTasksSummary.js @@ -0,0 +1,73 @@ +/** + * Flamenco manager + * Render Farm manager API + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + * + */ + +import ApiClient from '../ApiClient'; +import TaskSummary from './TaskSummary'; + +/** + * The JobTasksSummary model module. + * @module model/JobTasksSummary + * @version 0.0.0 + */ +class JobTasksSummary { + /** + * Constructs a new JobTasksSummary. + * Simplified list of tasks of a job. Contains all tasks, but not all info of each task. + * @alias module:model/JobTasksSummary + */ + constructor() { + + JobTasksSummary.initialize(this); + } + + /** + * Initializes the fields of this object. + * This method is used by the constructors of any subclasses, in order to implement multiple inheritance (mix-ins). + * Only for internal use. + */ + static initialize(obj) { + } + + /** + * Constructs a JobTasksSummary from a plain JavaScript object, optionally creating a new instance. + * Copies all relevant properties from data to obj if supplied or a new instance if not. + * @param {Object} data The plain JavaScript object bearing properties of interest. + * @param {module:model/JobTasksSummary} obj Optional instance to populate. + * @return {module:model/JobTasksSummary} The populated JobTasksSummary instance. + */ + static constructFromObject(data, obj) { + if (data) { + obj = obj || new JobTasksSummary(); + + if (data.hasOwnProperty('tasks')) { + obj['tasks'] = ApiClient.convertToType(data['tasks'], [TaskSummary]); + } + } + return obj; + } + + +} + +/** + * @member {Array.} tasks + */ +JobTasksSummary.prototype['tasks'] = undefined; + + + + + + +export default JobTasksSummary; + diff --git a/web/app/src/manager-api/model/TaskSummary.js b/web/app/src/manager-api/model/TaskSummary.js new file mode 100644 index 00000000..3f3c64a8 --- /dev/null +++ b/web/app/src/manager-api/model/TaskSummary.js @@ -0,0 +1,125 @@ +/** + * Flamenco manager + * Render Farm manager API + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + * + */ + +import ApiClient from '../ApiClient'; +import TaskStatus from './TaskStatus'; + +/** + * The TaskSummary model module. + * @module model/TaskSummary + * @version 0.0.0 + */ +class TaskSummary { + /** + * Constructs a new TaskSummary. + * Just enough information about the task to show in the job's task list. + * @alias module:model/TaskSummary + * @param id {String} + * @param name {String} + * @param status {module:model/TaskStatus} + * @param priority {Number} + * @param taskType {String} + * @param updated {Date} + */ + constructor(id, name, status, priority, taskType, updated) { + + TaskSummary.initialize(this, id, name, status, priority, taskType, updated); + } + + /** + * Initializes the fields of this object. + * This method is used by the constructors of any subclasses, in order to implement multiple inheritance (mix-ins). + * Only for internal use. + */ + static initialize(obj, id, name, status, priority, taskType, updated) { + obj['id'] = id; + obj['name'] = name; + obj['status'] = status; + obj['priority'] = priority; + obj['task_type'] = taskType; + obj['updated'] = updated; + } + + /** + * Constructs a TaskSummary from a plain JavaScript object, optionally creating a new instance. + * Copies all relevant properties from data to obj if supplied or a new instance if not. + * @param {Object} data The plain JavaScript object bearing properties of interest. + * @param {module:model/TaskSummary} obj Optional instance to populate. + * @return {module:model/TaskSummary} The populated TaskSummary instance. + */ + static constructFromObject(data, obj) { + if (data) { + obj = obj || new TaskSummary(); + + if (data.hasOwnProperty('id')) { + obj['id'] = ApiClient.convertToType(data['id'], 'String'); + } + if (data.hasOwnProperty('name')) { + obj['name'] = ApiClient.convertToType(data['name'], 'String'); + } + if (data.hasOwnProperty('status')) { + obj['status'] = TaskStatus.constructFromObject(data['status']); + } + if (data.hasOwnProperty('priority')) { + obj['priority'] = ApiClient.convertToType(data['priority'], 'Number'); + } + if (data.hasOwnProperty('task_type')) { + obj['task_type'] = ApiClient.convertToType(data['task_type'], 'String'); + } + if (data.hasOwnProperty('updated')) { + obj['updated'] = ApiClient.convertToType(data['updated'], 'Date'); + } + } + return obj; + } + + +} + +/** + * @member {String} id + */ +TaskSummary.prototype['id'] = undefined; + +/** + * @member {String} name + */ +TaskSummary.prototype['name'] = undefined; + +/** + * @member {module:model/TaskStatus} status + */ +TaskSummary.prototype['status'] = undefined; + +/** + * @member {Number} priority + */ +TaskSummary.prototype['priority'] = undefined; + +/** + * @member {String} task_type + */ +TaskSummary.prototype['task_type'] = undefined; + +/** + * @member {Date} updated + */ +TaskSummary.prototype['updated'] = undefined; + + + + + + +export default TaskSummary; +