diff --git a/addon/flamenco/manager/__init__.py b/addon/flamenco/manager/__init__.py index 5d1bc200..26ebb906 100644 --- a/addon/flamenco/manager/__init__.py +++ b/addon/flamenco/manager/__init__.py @@ -10,7 +10,7 @@ """ -__version__ = "81563c07" +__version__ = "5d304593" # 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 beac7b35..dc4125ef 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_blocklist import JobBlocklist +from flamenco.manager.model.job_last_rendered_image_info import JobLastRenderedImageInfo 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 @@ -144,6 +145,55 @@ class JobsApi(object): }, api_client=api_client ) + self.fetch_job_last_rendered_info_endpoint = _Endpoint( + settings={ + 'response_type': (JobLastRenderedImageInfo,), + 'auth': [], + 'endpoint_path': '/api/jobs/{job_id}/last-rendered', + 'operation_id': 'fetch_job_last_rendered_info', + '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.fetch_job_tasks_endpoint = _Endpoint( settings={ 'response_type': (JobTasksSummary,), @@ -805,6 +855,83 @@ class JobsApi(object): job_id return self.fetch_job_blocklist_endpoint.call_with_http_info(**kwargs) + def fetch_job_last_rendered_info( + self, + job_id, + **kwargs + ): + """Get the URL that serves the last-rendered images of this 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_last_rendered_info(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: + JobLastRenderedImageInfo + 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_last_rendered_info_endpoint.call_with_http_info(**kwargs) + def fetch_job_tasks( self, job_id, diff --git a/addon/flamenco/manager/api_client.py b/addon/flamenco/manager/api_client.py index b54e3470..1cc6170a 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/81563c07 (Blender add-on)' + self.user_agent = 'Flamenco/5d304593 (Blender add-on)' def __enter__(self): return self diff --git a/addon/flamenco/manager/configuration.py b/addon/flamenco/manager/configuration.py index ebe47a52..22fe8a78 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: 81563c07".\ + "SDK Package Version: 5d304593".\ format(env=sys.platform, pyversion=sys.version) def get_host_settings(self): diff --git a/addon/flamenco/manager/docs/JobLastRenderedImageInfo.md b/addon/flamenco/manager/docs/JobLastRenderedImageInfo.md new file mode 100644 index 00000000..94410c45 --- /dev/null +++ b/addon/flamenco/manager/docs/JobLastRenderedImageInfo.md @@ -0,0 +1,14 @@ +# JobLastRenderedImageInfo + +Enough information for a client to piece together different strings to form a host-relative URL to the last-rendered image. To construct the URL, concatenate \"{base}/{one of the suffixes}\". + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**base** | **str** | | +**suffixes** | **[str]** | | +**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 d4e0c936..a21edaf9 100644 --- a/addon/flamenco/manager/docs/JobsApi.md +++ b/addon/flamenco/manager/docs/JobsApi.md @@ -6,6 +6,7 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**fetch_job**](JobsApi.md#fetch_job) | **GET** /api/jobs/{job_id} | Fetch info about the job. [**fetch_job_blocklist**](JobsApi.md#fetch_job_blocklist) | **GET** /api/jobs/{job_id}/blocklist | Fetch the list of workers that are blocked from doing certain task types on this job. +[**fetch_job_last_rendered_info**](JobsApi.md#fetch_job_last_rendered_info) | **GET** /api/jobs/{job_id}/last-rendered | Get the URL that serves the last-rendered images of this 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. [**fetch_task**](JobsApi.md#fetch_task) | **GET** /api/tasks/{task_id} | Fetch a single task. [**fetch_task_log_tail**](JobsApi.md#fetch_task_log_tail) | **GET** /api/tasks/{task_id}/logtail | Fetch the last few lines of the task's log. @@ -150,6 +151,71 @@ 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_last_rendered_info** +> JobLastRenderedImageInfo fetch_job_last_rendered_info(job_id) + +Get the URL that serves the last-rendered images of this job. + +### Example + + +```python +import time +import flamenco.manager +from flamenco.manager.api import jobs_api +from flamenco.manager.model.job_last_rendered_image_info import JobLastRenderedImageInfo +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: + # Get the URL that serves the last-rendered images of this job. + api_response = api_instance.fetch_job_last_rendered_info(job_id) + pprint(api_response) + except flamenco.manager.ApiException as e: + print("Exception when calling JobsApi->fetch_job_last_rendered_info: %s\n" % e) +``` + + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **job_id** | **str**| | + +### Return type + +[**JobLastRenderedImageInfo**](JobLastRenderedImageInfo.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Normal response. | - | + +[[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) diff --git a/addon/flamenco/manager/model/job_last_rendered_image_info.py b/addon/flamenco/manager/model/job_last_rendered_image_info.py new file mode 100644 index 00000000..f2c71918 --- /dev/null +++ b/addon/flamenco/manager/model/job_last_rendered_image_info.py @@ -0,0 +1,267 @@ +""" + 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 + + + +class JobLastRenderedImageInfo(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 + """ + 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. + """ + return { + 'base': (str,), # noqa: E501 + 'suffixes': ([str],), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + + attribute_map = { + 'base': 'base', # noqa: E501 + 'suffixes': 'suffixes', # noqa: E501 + } + + read_only_vars = { + } + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, base, suffixes, *args, **kwargs): # noqa: E501 + """JobLastRenderedImageInfo - a model defined in OpenAPI + + Args: + base (str): + suffixes ([str]): + + 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.base = base + self.suffixes = suffixes + 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, base, suffixes, *args, **kwargs): # noqa: E501 + """JobLastRenderedImageInfo - a model defined in OpenAPI + + Args: + base (str): + suffixes ([str]): + + 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.base = base + self.suffixes = suffixes + 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 0be44680..129a5a38 100644 --- a/addon/flamenco/manager/models/__init__.py +++ b/addon/flamenco/manager/models/__init__.py @@ -23,6 +23,7 @@ from flamenco.manager.model.job import Job from flamenco.manager.model.job_all_of import JobAllOf from flamenco.manager.model.job_blocklist import JobBlocklist from flamenco.manager.model.job_blocklist_entry import JobBlocklistEntry +from flamenco.manager.model.job_last_rendered_image_info import JobLastRenderedImageInfo from flamenco.manager.model.job_metadata import JobMetadata from flamenco.manager.model.job_settings import JobSettings from flamenco.manager.model.job_status import JobStatus diff --git a/addon/flamenco/manager_README.md b/addon/flamenco/manager_README.md index 23f1cabd..c984012d 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: 81563c07 +- Package version: 5d304593 - 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_blocklist import JobBlocklist +from flamenco.manager.model.job_last_rendered_image_info import JobLastRenderedImageInfo 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 @@ -74,6 +75,7 @@ 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_blocklist**](flamenco/manager/docs/JobsApi.md#fetch_job_blocklist) | **GET** /api/jobs/{job_id}/blocklist | Fetch the list of workers that are blocked from doing certain task types on this job. +*JobsApi* | [**fetch_job_last_rendered_info**](flamenco/manager/docs/JobsApi.md#fetch_job_last_rendered_info) | **GET** /api/jobs/{job_id}/last-rendered | Get the URL that serves the last-rendered images of this 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* | [**fetch_task**](flamenco/manager/docs/JobsApi.md#fetch_task) | **GET** /api/tasks/{task_id} | Fetch a single task. *JobsApi* | [**fetch_task_log_tail**](flamenco/manager/docs/JobsApi.md#fetch_task_log_tail) | **GET** /api/tasks/{task_id}/logtail | Fetch the last few lines of the task's log. @@ -120,6 +122,7 @@ Class | Method | HTTP request | Description - [JobAllOf](flamenco/manager/docs/JobAllOf.md) - [JobBlocklist](flamenco/manager/docs/JobBlocklist.md) - [JobBlocklistEntry](flamenco/manager/docs/JobBlocklistEntry.md) + - [JobLastRenderedImageInfo](flamenco/manager/docs/JobLastRenderedImageInfo.md) - [JobMetadata](flamenco/manager/docs/JobMetadata.md) - [JobSettings](flamenco/manager/docs/JobSettings.md) - [JobStatus](flamenco/manager/docs/JobStatus.md) diff --git a/internal/worker/mocks/client.gen.go b/internal/worker/mocks/client.gen.go index 8231e163..45fa7f04 100644 --- a/internal/worker/mocks/client.gen.go +++ b/internal/worker/mocks/client.gen.go @@ -56,6 +56,26 @@ func (mr *MockFlamencoClientMockRecorder) FetchJobBlocklistWithResponse(arg0, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJobBlocklistWithResponse", reflect.TypeOf((*MockFlamencoClient)(nil).FetchJobBlocklistWithResponse), varargs...) } +// FetchJobLastRenderedInfoWithResponse mocks base method. +func (m *MockFlamencoClient) FetchJobLastRenderedInfoWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobLastRenderedInfoResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "FetchJobLastRenderedInfoWithResponse", varargs...) + ret0, _ := ret[0].(*api.FetchJobLastRenderedInfoResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchJobLastRenderedInfoWithResponse indicates an expected call of FetchJobLastRenderedInfoWithResponse. +func (mr *MockFlamencoClientMockRecorder) FetchJobLastRenderedInfoWithResponse(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, "FetchJobLastRenderedInfoWithResponse", reflect.TypeOf((*MockFlamencoClient)(nil).FetchJobLastRenderedInfoWithResponse), varargs...) +} + // FetchJobTasksWithResponse mocks base method. func (m *MockFlamencoClient) FetchJobTasksWithResponse(arg0 context.Context, arg1 string, arg2 ...api.RequestEditorFn) (*api.FetchJobTasksResponse, error) { m.ctrl.T.Helper() diff --git a/pkg/api/openapi_client.gen.go b/pkg/api/openapi_client.gen.go index 058daf73..3f12852c 100644 --- a/pkg/api/openapi_client.gen.go +++ b/pkg/api/openapi_client.gen.go @@ -120,6 +120,9 @@ type ClientInterface interface { // FetchJobBlocklist request FetchJobBlocklist(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) + // FetchJobLastRenderedInfo request + FetchJobLastRenderedInfo(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) + // SetJobStatus request with any body SetJobStatusWithBody(ctx context.Context, jobId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -337,6 +340,18 @@ func (c *Client) FetchJobBlocklist(ctx context.Context, jobId string, reqEditors return c.Client.Do(req) } +func (c *Client) FetchJobLastRenderedInfo(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewFetchJobLastRenderedInfoRequest(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) SetJobStatusWithBody(ctx context.Context, jobId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewSetJobStatusRequestWithBody(c.Server, jobId, contentType, body) if err != nil { @@ -992,6 +1007,40 @@ func NewFetchJobBlocklistRequest(server string, jobId string) (*http.Request, er return req, nil } +// NewFetchJobLastRenderedInfoRequest generates requests for FetchJobLastRenderedInfo +func NewFetchJobLastRenderedInfoRequest(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/last-rendered", 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 +} + // NewSetJobStatusRequest calls the generic SetJobStatus builder with application/json body func NewSetJobStatusRequest(server string, jobId string, body SetJobStatusJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -1900,6 +1949,9 @@ type ClientWithResponsesInterface interface { // FetchJobBlocklist request FetchJobBlocklistWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobBlocklistResponse, error) + // FetchJobLastRenderedInfo request + FetchJobLastRenderedInfoWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobLastRenderedInfoResponse, error) + // SetJobStatus request with any body SetJobStatusWithBodyWithResponse(ctx context.Context, jobId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetJobStatusResponse, error) @@ -2164,6 +2216,28 @@ func (r FetchJobBlocklistResponse) StatusCode() int { return 0 } +type FetchJobLastRenderedInfoResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *JobLastRenderedImageInfo +} + +// Status returns HTTPResponse.Status +func (r FetchJobLastRenderedInfoResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r FetchJobLastRenderedInfoResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type SetJobStatusResponse struct { Body []byte HTTPResponse *http.Response @@ -2761,6 +2835,15 @@ func (c *ClientWithResponses) FetchJobBlocklistWithResponse(ctx context.Context, return ParseFetchJobBlocklistResponse(rsp) } +// FetchJobLastRenderedInfoWithResponse request returning *FetchJobLastRenderedInfoResponse +func (c *ClientWithResponses) FetchJobLastRenderedInfoWithResponse(ctx context.Context, jobId string, reqEditors ...RequestEditorFn) (*FetchJobLastRenderedInfoResponse, error) { + rsp, err := c.FetchJobLastRenderedInfo(ctx, jobId, reqEditors...) + if err != nil { + return nil, err + } + return ParseFetchJobLastRenderedInfoResponse(rsp) +} + // SetJobStatusWithBodyWithResponse request with arbitrary body returning *SetJobStatusResponse func (c *ClientWithResponses) SetJobStatusWithBodyWithResponse(ctx context.Context, jobId string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetJobStatusResponse, error) { rsp, err := c.SetJobStatusWithBody(ctx, jobId, contentType, body, reqEditors...) @@ -3260,6 +3343,32 @@ func ParseFetchJobBlocklistResponse(rsp *http.Response) (*FetchJobBlocklistRespo return response, nil } +// ParseFetchJobLastRenderedInfoResponse parses an HTTP response from a FetchJobLastRenderedInfoWithResponse call +func ParseFetchJobLastRenderedInfoResponse(rsp *http.Response) (*FetchJobLastRenderedInfoResponse, error) { + bodyBytes, err := ioutil.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &FetchJobLastRenderedInfoResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest JobLastRenderedImageInfo + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + } + + return response, nil +} + // ParseSetJobStatusResponse parses an HTTP response from a SetJobStatusWithResponse call func ParseSetJobStatusResponse(rsp *http.Response) (*SetJobStatusResponse, error) { bodyBytes, err := ioutil.ReadAll(rsp.Body) diff --git a/pkg/api/openapi_server.gen.go b/pkg/api/openapi_server.gen.go index 4869bc4d..c3819537 100644 --- a/pkg/api/openapi_server.gen.go +++ b/pkg/api/openapi_server.gen.go @@ -37,6 +37,9 @@ type ServerInterface interface { // Fetch the list of workers that are blocked from doing certain task types on this job. // (GET /api/jobs/{job_id}/blocklist) FetchJobBlocklist(ctx echo.Context, jobId string) error + // Get the URL that serves the last-rendered images of this job. + // (GET /api/jobs/{job_id}/last-rendered) + FetchJobLastRenderedInfo(ctx echo.Context, jobId string) error // (POST /api/jobs/{job_id}/setstatus) SetJobStatus(ctx echo.Context, jobId string) error @@ -211,6 +214,22 @@ func (w *ServerInterfaceWrapper) FetchJobBlocklist(ctx echo.Context) error { return err } +// FetchJobLastRenderedInfo converts echo context to params. +func (w *ServerInterfaceWrapper) FetchJobLastRenderedInfo(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.FetchJobLastRenderedInfo(ctx, jobId) + return err +} + // SetJobStatus converts echo context to params. func (w *ServerInterfaceWrapper) SetJobStatus(ctx echo.Context) error { var err error @@ -596,6 +615,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/api/jobs/:job_id", wrapper.FetchJob) router.DELETE(baseURL+"/api/jobs/:job_id/blocklist", wrapper.RemoveJobBlocklist) router.GET(baseURL+"/api/jobs/:job_id/blocklist", wrapper.FetchJobBlocklist) + router.GET(baseURL+"/api/jobs/:job_id/last-rendered", wrapper.FetchJobLastRenderedInfo) router.POST(baseURL+"/api/jobs/:job_id/setstatus", wrapper.SetJobStatus) router.GET(baseURL+"/api/jobs/:job_id/tasks", wrapper.FetchJobTasks) router.GET(baseURL+"/api/tasks/:task_id", wrapper.FetchTask) diff --git a/pkg/api/openapi_spec.gen.go b/pkg/api/openapi_spec.gen.go index 89228336..1bc36bf5 100644 --- a/pkg/api/openapi_spec.gen.go +++ b/pkg/api/openapi_spec.gen.go @@ -18,148 +18,151 @@ import ( // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "///7VfgJs6QAAA==", + "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", + "eXvz/wMAAP//xXvKGjWoAAA=", } // 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 227e32ea..fdf94f02 100644 --- a/pkg/api/openapi_types.gen.go +++ b/pkg/api/openapi_types.gen.go @@ -250,6 +250,12 @@ type JobBlocklistEntry struct { WorkerId string `json:"worker_id"` } +// Enough information for a client to piece together different strings to form a host-relative URL to the last-rendered image. To construct the URL, concatenate "{base}/{one of the suffixes}". +type JobLastRenderedImageInfo struct { + Base string `json:"base"` + Suffixes []string `json:"suffixes"` +} + // Arbitrary metadata strings. More complex structures can be modeled by using `a.b.c` notation for the key. type JobMetadata struct { AdditionalProperties map[string]string `json:"-"` diff --git a/web/app/src/manager-api/ApiClient.js b/web/app/src/manager-api/ApiClient.js index aad56431..7a51a421 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/81563c07 / webbrowser' + 'User-Agent': 'Flamenco/5d304593 / webbrowser' }; /** diff --git a/web/app/src/manager-api/index.js b/web/app/src/manager-api/index.js index 1612f064..b5e9119d 100644 --- a/web/app/src/manager-api/index.js +++ b/web/app/src/manager-api/index.js @@ -26,6 +26,7 @@ import FlamencoVersion from './model/FlamencoVersion'; import Job from './model/Job'; import JobAllOf from './model/JobAllOf'; import JobBlocklistEntry from './model/JobBlocklistEntry'; +import JobLastRenderedImageInfo from './model/JobLastRenderedImageInfo'; import JobStatus from './model/JobStatus'; import JobStatusChange from './model/JobStatusChange'; import JobTasksSummary from './model/JobTasksSummary'; @@ -190,6 +191,12 @@ export { */ JobBlocklistEntry, + /** + * The JobLastRenderedImageInfo model constructor. + * @property {module:model/JobLastRenderedImageInfo} + */ + JobLastRenderedImageInfo, + /** * The JobStatus model constructor. * @property {module:model/JobStatus} diff --git a/web/app/src/manager-api/manager/JobsApi.js b/web/app/src/manager-api/manager/JobsApi.js index e84bb7f8..2a9e500d 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 JobBlocklistEntry from '../model/JobBlocklistEntry'; +import JobLastRenderedImageInfo from '../model/JobLastRenderedImageInfo'; import JobStatusChange from '../model/JobStatusChange'; import JobTasksSummary from '../model/JobTasksSummary'; import JobsQuery from '../model/JobsQuery'; @@ -138,6 +139,52 @@ export default class JobsApi { } + /** + * Get the URL that serves the last-rendered images of this job. + * @param {String} jobId + * @return {Promise} a {@link https://www.promisejs.org/|Promise}, with an object containing data of type {@link module:model/JobLastRenderedImageInfo} and HTTP response + */ + fetchJobLastRenderedInfoWithHttpInfo(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 fetchJobLastRenderedInfo"); + } + + let pathParams = { + 'job_id': jobId + }; + let queryParams = { + }; + let headerParams = { + }; + let formParams = { + }; + + let authNames = []; + let contentTypes = []; + let accepts = ['application/json']; + let returnType = JobLastRenderedImageInfo; + return this.apiClient.callApi( + '/api/jobs/{job_id}/last-rendered', 'GET', + pathParams, queryParams, headerParams, formParams, postBody, + authNames, contentTypes, accepts, returnType, null + ); + } + + /** + * Get the URL that serves the last-rendered images of this job. + * @param {String} jobId + * @return {Promise} a {@link https://www.promisejs.org/|Promise}, with data of type {@link module:model/JobLastRenderedImageInfo} + */ + fetchJobLastRenderedInfo(jobId) { + return this.fetchJobLastRenderedInfoWithHttpInfo(jobId) + .then(function(response_and_data) { + return response_and_data.data; + }); + } + + /** * Fetch a summary of all tasks of the given job. * @param {String} jobId diff --git a/web/app/src/manager-api/model/JobLastRenderedImageInfo.js b/web/app/src/manager-api/model/JobLastRenderedImageInfo.js new file mode 100644 index 00000000..f23e46e3 --- /dev/null +++ b/web/app/src/manager-api/model/JobLastRenderedImageInfo.js @@ -0,0 +1,84 @@ +/** + * 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'; + +/** + * The JobLastRenderedImageInfo model module. + * @module model/JobLastRenderedImageInfo + * @version 0.0.0 + */ +class JobLastRenderedImageInfo { + /** + * Constructs a new JobLastRenderedImageInfo. + * Enough information for a client to piece together different strings to form a host-relative URL to the last-rendered image. To construct the URL, concatenate \"{base}/{one of the suffixes}\". + * @alias module:model/JobLastRenderedImageInfo + * @param base {String} + * @param suffixes {Array.} + */ + constructor(base, suffixes) { + + JobLastRenderedImageInfo.initialize(this, base, suffixes); + } + + /** + * 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, base, suffixes) { + obj['base'] = base; + obj['suffixes'] = suffixes; + } + + /** + * Constructs a JobLastRenderedImageInfo 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/JobLastRenderedImageInfo} obj Optional instance to populate. + * @return {module:model/JobLastRenderedImageInfo} The populated JobLastRenderedImageInfo instance. + */ + static constructFromObject(data, obj) { + if (data) { + obj = obj || new JobLastRenderedImageInfo(); + + if (data.hasOwnProperty('base')) { + obj['base'] = ApiClient.convertToType(data['base'], 'String'); + } + if (data.hasOwnProperty('suffixes')) { + obj['suffixes'] = ApiClient.convertToType(data['suffixes'], ['String']); + } + } + return obj; + } + + +} + +/** + * @member {String} base + */ +JobLastRenderedImageInfo.prototype['base'] = undefined; + +/** + * @member {Array.} suffixes + */ +JobLastRenderedImageInfo.prototype['suffixes'] = undefined; + + + + + + +export default JobLastRenderedImageInfo; +