From 17cb1a3fd93fe9146663b592ebba3d92a2e32ebe Mon Sep 17 00:00:00 2001 From: slashburygin Date: Wed, 29 Apr 2026 11:23:37 +0300 Subject: [PATCH] add v1/imports and v1/exports --- docs/openapi/openapi_boot.yaml | 2 +- docs/openapi/openapi_orch.yaml | 2 +- docs/openapi/openapi_status.yaml | 2 +- docs/openapi/openapi_user.yaml | 244 +++++++++++++++++- genesis_core/elements/dm/models.py | 8 +- .../tests/functional/restapi/em/test_em.py | 9 + .../tests/manual/openapi/test_openapi.py | 4 + genesis_core/user_api/em/api/controllers.py | 24 +- genesis_core/user_api/em/api/routes.py | 22 ++ 9 files changed, 306 insertions(+), 11 deletions(-) diff --git a/docs/openapi/openapi_boot.yaml b/docs/openapi/openapi_boot.yaml index 6e284bfa..76eb52fe 100644 --- a/docs/openapi/openapi_boot.yaml +++ b/docs/openapi/openapi_boot.yaml @@ -1346,7 +1346,7 @@ paths: $ref: '#/components/responses/Error' operationId: Refresh_secret_v1_nodes_NodeEncryptionKeyUuid_actions_refresh_secret_invoke servers: - - url: http://127.0.0.1:40937 + - url: http://127.0.0.1:11013 description: '' variables: version: diff --git a/docs/openapi/openapi_orch.yaml b/docs/openapi/openapi_orch.yaml index a7e719d2..d1ad7297 100644 --- a/docs/openapi/openapi_orch.yaml +++ b/docs/openapi/openapi_orch.yaml @@ -345,7 +345,7 @@ paths: $ref: '#/components/responses/Error' operationId: Get_payload_v1_agents_UniversalAgentUuid_actions_get_payload servers: - - url: http://127.0.0.1:47869 + - url: http://127.0.0.1:11011 description: '' variables: version: diff --git a/docs/openapi/openapi_status.yaml b/docs/openapi/openapi_status.yaml index cf01b0f1..4c71f4fb 100644 --- a/docs/openapi/openapi_status.yaml +++ b/docs/openapi/openapi_status.yaml @@ -979,7 +979,7 @@ paths: $ref: '#/components/responses/Error' operationId: Delete_v1_kind_KindModelKind_resources_ResourceRes_uuid servers: - - url: http://127.0.0.1:41393 + - url: http://127.0.0.1:11012 description: '' variables: version: diff --git a/docs/openapi/openapi_user.yaml b/docs/openapi/openapi_user.yaml index b0433e49..8f842305 100644 --- a/docs/openapi/openapi_user.yaml +++ b/docs/openapi/openapi_user.yaml @@ -3226,6 +3226,9 @@ components: minLength: 0 maxLength: 9223372036854775807 example: any_string + sync_to_ecosystem: + type: boolean + example: true id: type: integer minimum: -9223372036854775807 @@ -3262,6 +3265,9 @@ components: minLength: 0 maxLength: 9223372036854775807 example: any_string + sync_to_ecosystem: + type: boolean + example: true id: type: integer minimum: -9223372036854775807 @@ -3298,6 +3304,9 @@ components: minLength: 0 maxLength: 9223372036854775807 example: any_string + sync_to_ecosystem: + type: boolean + example: true id: type: integer minimum: -9223372036854775807 @@ -3334,6 +3343,9 @@ components: minLength: 0 maxLength: 9223372036854775807 example: any_string + sync_to_ecosystem: + type: boolean + example: true id: type: integer minimum: -9223372036854775807 @@ -13672,6 +13684,12 @@ components: - MANUAL example: AUTO_HEX default: AUTO_HEX + default_length: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 value: type: string minLength: 1 @@ -13748,6 +13766,12 @@ components: - MANUAL example: AUTO_HEX default: AUTO_HEX + default_length: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 value: type: string minLength: 1 @@ -13824,6 +13848,12 @@ components: - MANUAL example: AUTO_HEX default: AUTO_HEX + default_length: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 value: type: string minLength: 1 @@ -13900,6 +13930,12 @@ components: - MANUAL example: AUTO_HEX default: AUTO_HEX + default_length: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 value: type: string minLength: 1 @@ -17004,6 +17040,12 @@ components: example: 00000000-0000-0000-0000-000000000000 format: uuid required: true + sync_to_ecosystem: + name: sync_to_ecosystem + in: query + schema: + type: boolean + example: true id: name: id in: query @@ -18479,6 +18521,15 @@ components: example: 00000000-0000-0000-0000-000000000000 format: uuid required: true + default_length: + name: default_length + in: query + schema: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 RSAKeyUuid: name: RSAKeyUuid in: path @@ -20065,6 +20116,11 @@ paths: maxLength: 255 example: any_string default: '' + - name: sync_to_ecosystem + in: query + schema: + type: boolean + example: true - name: id in: query schema: @@ -21022,6 +21078,180 @@ paths: default: $ref: '#/components/responses/Error' operationId: Set_profile_v1_em_elements_ElementUuid_actions_set_profile_invoke + /v1/em/exports/: + get: + summary: Get Exports + tags: + - Export + parameters: + - name: created_at + in: query + schema: + type: string + x-ogen-time-format: '2006-01-02T15:04:05.000576Z' + example: '2006-01-02T15:04:05.000576Z' + format: date-time + default: '2006-01-02T15:04:05.000576Z' + - name: updated_at + in: query + schema: + type: string + x-ogen-time-format: '2006-01-02T15:04:05.000576Z' + example: '2006-01-02T15:04:05.000576Z' + format: date-time + default: '2006-01-02T15:04:05.000576Z' + - name: element + in: query + schema: + type: string + - name: name + in: query + schema: + type: string + minLength: 0 + maxLength: 255 + example: any_string + default: '' + - name: kind + in: query + schema: + type: string + minLength: 2 + maxLength: 256 + example: any_string + - name: link + in: query + schema: + type: string + minLength: 2 + maxLength: 256 + example: any_string + responses: + '200': + description: Export_Filter + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Export_Filter' + default: + $ref: '#/components/responses/Error' + operationId: Filter_v1_em_exports + /v1/em/exports/{ExportUuid}: + get: + summary: Get Export + tags: + - Export + parameters: + - name: ExportUuid + in: path + schema: + type: string + example: 00000000-0000-0000-0000-000000000000 + format: uuid + required: true + responses: + '200': + description: Export_Get + content: + application/json: + schema: + $ref: '#/components/schemas/Export_Get' + default: + $ref: '#/components/responses/Error' + operationId: Get_v1_em_exports_ExportUuid + /v1/em/imports/: + get: + summary: Get Imports + tags: + - Import + parameters: + - name: created_at + in: query + schema: + type: string + x-ogen-time-format: '2006-01-02T15:04:05.000576Z' + example: '2006-01-02T15:04:05.000576Z' + format: date-time + default: '2006-01-02T15:04:05.000576Z' + - name: updated_at + in: query + schema: + type: string + x-ogen-time-format: '2006-01-02T15:04:05.000576Z' + example: '2006-01-02T15:04:05.000576Z' + format: date-time + default: '2006-01-02T15:04:05.000576Z' + - name: element + in: query + schema: + type: string + - name: from_element + in: query + schema: + type: string + - name: from_resource + in: query + schema: + type: string + - name: name + in: query + schema: + type: string + minLength: 0 + maxLength: 255 + example: any_string + default: '' + - name: kind + in: query + schema: + type: string + minLength: 2 + maxLength: 256 + example: any_string + - name: link + in: query + schema: + type: string + minLength: 2 + maxLength: 256 + example: any_string + responses: + '200': + description: Import_Filter + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Import_Filter' + default: + $ref: '#/components/responses/Error' + operationId: Filter_v1_em_imports + /v1/em/imports/{ImportUuid}: + get: + summary: Get Import + tags: + - Import + parameters: + - name: ImportUuid + in: path + schema: + type: string + example: 00000000-0000-0000-0000-000000000000 + format: uuid + required: true + responses: + '200': + description: Import_Get + content: + application/json: + schema: + $ref: '#/components/schemas/Import_Get' + default: + $ref: '#/components/responses/Error' + operationId: Get_v1_em_imports_ImportUuid /v1/em/manifests/: get: summary: Get Manifests @@ -25081,6 +25311,14 @@ paths: - MANUAL example: AUTO_HEX default: AUTO_HEX + - name: default_length + in: query + schema: + type: integer + minimum: 1 + maximum: 512 + example: 256 + default: 32 - name: value in: query schema: @@ -26379,7 +26617,7 @@ paths: $ref: '#/components/responses/Error' operationId: Select_value_v1_vs_variables_VariableUuid_actions_select_value_invoke servers: - - url: http://127.0.0.1:42579 + - url: http://127.0.0.1:11010 description: '' variables: version: @@ -26401,12 +26639,12 @@ tags: description: '' - name: Domain description: '' + - name: Element + description: '' - name: Export description: '' - name: Import description: '' - - name: Element - description: '' - name: Manifest description: '' - name: Resource diff --git a/genesis_core/elements/dm/models.py b/genesis_core/elements/dm/models.py index 4819e1d0..c71a7bff 100644 --- a/genesis_core/elements/dm/models.py +++ b/genesis_core/elements/dm/models.py @@ -992,20 +992,20 @@ def __init__(self, element): def element(self): return self._element - def add_resource(self, resource): + def add_resource(self, resource: "Resource") -> None: if resource.link in self._namespace_resources: raise ValueError( - f"Resource with link string '{resource.link}' already exists." + f"Resource with link string '{resource.link}' in element '{resource.element.name}' already exists." ) self._namespace_resources[resource.link] = resource def get_resources(self): return list(self._namespace_resources.values()) - def delete_resource(self, resource): + def delete_resource(self, resource: "Resource") -> None: if resource.link not in self._namespace_resources: raise ValueError( - f"Resource with link string '{resource.link}' does not exist." + f"Resource with link string '{resource.link}' in element '{resource.element.name}' does not exist." ) del self._namespace_resources[resource.link] diff --git a/genesis_core/tests/functional/restapi/em/test_em.py b/genesis_core/tests/functional/restapi/em/test_em.py index 12d15d34..58989b81 100644 --- a/genesis_core/tests/functional/restapi/em/test_em.py +++ b/genesis_core/tests/functional/restapi/em/test_em.py @@ -111,9 +111,18 @@ def test_manifests( resources_data = response.json() assert isinstance(resources_data, list) + url = client.build_collection_uri(["em", "imports"]) + response = client.get(url) + assert response.status_code == 200 imports_data = response.json() assert isinstance(imports_data, list) + url = client.build_collection_uri(["em", "exports"]) + response = client.get(url) + assert response.status_code == 200 + exports_data = response.json() + assert isinstance(exports_data, list) + # uninstall url = client.build_resource_uri( ["em", "manifests", manifest_uuid, "actions", "uninstall", "invoke"] diff --git a/genesis_core/tests/manual/openapi/test_openapi.py b/genesis_core/tests/manual/openapi/test_openapi.py index 6c9092f3..91063d6c 100644 --- a/genesis_core/tests/manual/openapi/test_openapi.py +++ b/genesis_core/tests/manual/openapi/test_openapi.py @@ -49,6 +49,7 @@ def test_user_openapi( path = os.path.join(PROJECT_PATH, "docs", "openapi", "openapi_user.yaml") spec = response.json() + spec["servers"][0]["url"] = "http://127.0.0.1:11010" spec["info"]["version"] = "latest" with open(path, "w") as f: yaml.dump(spec, f) @@ -61,6 +62,7 @@ def test_user_openapi( assert response.status_code == 200 path = os.path.join(PROJECT_PATH, "docs", "openapi", "openapi_boot.yaml") spec = response.json() + spec["servers"][0]["url"] = "http://127.0.0.1:11013" spec["info"]["version"] = "latest" with open(path, "w") as f: yaml.dump(spec, f) @@ -78,6 +80,7 @@ def test_user_openapi( path = os.path.join(PROJECT_PATH, "docs", "openapi", "openapi_orch.yaml") spec = response.json() + spec["servers"][0]["url"] = "http://127.0.0.1:11011" spec["info"]["version"] = "latest" with open(path, "w") as f: yaml.dump(spec, f) @@ -95,6 +98,7 @@ def test_user_openapi( path = os.path.join(PROJECT_PATH, "docs", "openapi", "openapi_status.yaml") spec = response.json() + spec["servers"][0]["url"] = "http://127.0.0.1:11012" spec["info"]["version"] = "latest" with open(path, "w") as f: yaml.dump(spec, f) diff --git a/genesis_core/user_api/em/api/controllers.py b/genesis_core/user_api/em/api/controllers.py index 78fa4972..e5a15f44 100644 --- a/genesis_core/user_api/em/api/controllers.py +++ b/genesis_core/user_api/em/api/controllers.py @@ -152,7 +152,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) -class ResourceAllController(controllers.BaseResourceController): +class ResourceAllController(iam_controllers.PolicyBasedController): """Controller for /v1/resources/ endpoint""" # NOTE(slashburygin): we need it here because in restalchemy we can add model to resources only once @@ -178,6 +178,17 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) +class ExportAllController(iam_controllers.PolicyBasedController): + """Controller for /v1/exports/ endpoint""" + + # NOTE(slashburygin): we need it here because in restalchemy we can add model to resources only once + __resource__ = resources.ResourceMap.model_type_to_resource[models.Export] + + def __init__(self, *args, **kwargs): + models.element_engine.load_from_database() + super().__init__(*args, **kwargs) + + class ElementImportController( controllers.BaseNestedResourceControllerPaginated, ): @@ -193,6 +204,17 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) +class ImportAllController(iam_controllers.PolicyBasedController): + """Controller for /v1/imports/ endpoint""" + + # NOTE(slashburygin): we need it here because in restalchemy we can add model to resources only once + __resource__ = resources.ResourceMap.model_type_to_resource[models.Import] + + def __init__(self, *args, **kwargs): + models.element_engine.load_from_database() + super().__init__(*args, **kwargs) + + class ServicesController(iam_controllers.PolicyBasedController): """Controller for /v1/em/services/ endpoint""" diff --git a/genesis_core/user_api/em/api/routes.py b/genesis_core/user_api/em/api/routes.py index 90b09f36..842f89db 100644 --- a/genesis_core/user_api/em/api/routes.py +++ b/genesis_core/user_api/em/api/routes.py @@ -76,12 +76,32 @@ class ElementExportRoute(routes.Route): __controller__ = controllers.ElementExportController +class ExportAllRoute(routes.Route): + """Handler for /v1/exports/[] endpoint""" + + __controller__ = controllers.ExportAllController + __allow_methods__ = [ + routes.FILTER, + routes.GET, + ] + + class ElementImportRoute(routes.Route): """Handler for /v1/em/elements//imports/ endpoint""" __controller__ = controllers.ElementImportController +class ImportAllRoute(routes.Route): + """Handler for /v1/imports/[] endpoint""" + + __controller__ = controllers.ImportAllController + __allow_methods__ = [ + routes.FILTER, + routes.GET, + ] + + class ElementSetProfileActionRoute(routes.Action): """Handler for /v1/em/elements//actions/set_profile/invoke endpoint""" @@ -121,4 +141,6 @@ class ElementManagerRoute(routes.Route): manifests = routes.route(ManifestRoute) elements = routes.route(ElementRoute) resources = routes.route(ResourceAllRoute) + exports = routes.route(ExportAllRoute) + imports = routes.route(ImportAllRoute) services = routes.route(ServicesRoute)