Skip to content

Commit 2160cf8

Browse files
committed
validate exports/imports
1 parent 16213e9 commit 2160cf8

9 files changed

Lines changed: 115 additions & 56 deletions

File tree

genesis/manifests/examples/invalid_exports.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ resources:
1515
description: "Example node"
1616
cores: 1
1717
ram: 1024
18-
# project_id: "12345678-c625-4fee-81d5-f691897b8142"
18+
project_id: "12345678-c625-4fee-81d5-f691897b8142"
1919
disk_spec:
2020
kind: "root_disk"
2121
size: 10
2222
image: "{{ base_image_url | default('https://repository.genesis-core.tech/genesis-base/0.4.1/genesis-base.raw.gz') }}"
23+
24+
exports:
25+
example_node:
26+
# link: "$core.compute.nodes.example_node"
27+
no_link: "$core.compute.nodes.example_node"

genesis/manifests/examples/invalid_imports.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ resources:
2121
size: 10
2222
image: "{{ base_image_url | default('https://repository.genesis-core.tech/genesis-base/0.4.1/genesis-base.raw.gz') }}"
2323

24-
exports:
25-
example_node:
26-
no_link: "$core.compute.nodes.example_node"
24+
imports:
25+
pg18_valid:
26+
element: "$dbaas"
27+
kind: "resource"
28+
link: "$dbaas.types.postgres.versions.$pg18"
29+
var_default_cores_invalid:
30+
# element: "$core"
31+
kind: "resource"
32+
link: "$core.vs.variables.$default_cores"

genesis/manifests/specification/base_spec.yaml

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,47 @@ properties:
2626
- v1
2727
requirements:
2828
type: object
29+
additionalProperties:
30+
$ref: '#/components/schemas/requirements'
2931
resources:
3032
type: object
3133
properties: {}
3234
exports:
3335
type: object
36+
additionalProperties:
37+
$ref: '#/components/schemas/export'
3438
imports:
3539
type: object
40+
additionalProperties:
41+
$ref: '#/components/schemas/import'
3642
components:
37-
schemas: {}
43+
schemas:
44+
export:
45+
type: object
46+
properties:
47+
link:
48+
type: string
49+
required:
50+
- link
51+
requirements:
52+
type: object
53+
properties:
54+
from_version:
55+
type: string
56+
to_version:
57+
type: string
58+
import:
59+
type: object
60+
properties:
61+
element:
62+
type: string
63+
kind:
64+
type: string
65+
enum:
66+
- resource
67+
link:
68+
type: string
69+
required:
70+
- element
71+
- kind
72+
- link

genesis_core/common/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CommonValueErrorException(GCException):
3434
__template__ = "The provided value is invalid."
3535

3636

37-
class OpenApiValidateException(GCException):
37+
class OpenApiValidateException(CommonValueErrorException):
3838
__template__ = "OpenApiValidateException: {err}"
3939

4040
err: str

genesis_core/elements/dm/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from genesis_core.common import utils as cm_utils
4343
from genesis_core.elements.dm import utils
4444
from genesis_core.elements.dm.validate import (
45-
load_base_manifest_schema,
45+
load_full_manifest_schema,
4646
validate_manifest,
4747
)
4848
from genesis_core.elements import constants as cc
@@ -1072,7 +1072,7 @@ def __init__(self):
10721072

10731073
def load_schema(self):
10741074
if not self.schema:
1075-
self.schema = load_base_manifest_schema()
1075+
self.schema = load_full_manifest_schema()
10761076

10771077
def load_element_from_manifest(self, manifest):
10781078
schema_version = utils.get_required_field(manifest, "SchemaVersion")

genesis_core/elements/dm/validate.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,34 @@ def validate_manifest(data: dict, schema: tp.Optional[dict]) -> None:
7474
)
7575
except ValidationError as err:
7676
LOG.exception("Failed to validate data %s: %s", data, err)
77-
raise exceptions.OpenApiValidateException(err=str(err))
77+
raise exceptions.OpenApiValidateException(
78+
err=f"{err.message} in {err.json_path}"
79+
)
7880
return None
81+
82+
83+
def build_full_schema(base_manifest_schema: dict, user_api_spec: dict) -> dict:
84+
for path, path_obj in user_api_spec["paths"].items():
85+
path_parts = path.split("/")
86+
if len(path_parts) > 5:
87+
continue
88+
post_path = path_obj.get("post")
89+
if post_path:
90+
operation_id = post_path.get("operationId")
91+
if operation_id and operation_id.startswith("Create_v1"):
92+
schema_ref = post_path["requestBody"]["content"]["application/json"][
93+
"schema"
94+
]
95+
model_name = schema_ref["$ref"].split("/")[-1]
96+
api_part_1 = path_parts[2]
97+
api_part_2 = path_parts[3]
98+
model = user_api_spec["components"]["schemas"][model_name]
99+
resource = f"$core.{api_part_1}.{api_part_2}"
100+
base_manifest_schema["components"]["schemas"][model_name] = model
101+
base_manifest_schema["properties"]["resources"]["properties"][
102+
resource
103+
] = {
104+
"type": "object",
105+
"additionalProperties": schema_ref,
106+
}
107+
return base_manifest_schema

genesis_core/tests/functional/manifests/test_validate.py

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
# License for the specific language governing permissions and limitations
1515
# under the License.
1616

17+
import os
1718
import pytest
1819
import requests
1920
import yaml
2021

2122
from genesis_core.elements.dm.validate import (
2223
validate_manifest,
2324
dump_full_manifest_schema,
25+
build_full_schema,
2426
)
27+
from genesis_core.common import exceptions
28+
from genesis_core.common.utils import PROJECT_PATH
2529

2630
REPO_URL = "https://repository.genesis-core.tech/genesis-elements"
2731

@@ -49,41 +53,29 @@ def test_validate_manifests(
4953
validate_manifest(manifest, base_manifest_schema)
5054
validate_manifest(manifest, full_manifest_schema)
5155

56+
@pytest.mark.parametrize(
57+
"invalid_manifest",
58+
[
59+
"invalid_exports.yaml",
60+
"invalid_imports.yaml",
61+
"invalid_resource.yaml",
62+
],
63+
)
64+
def test_validate_error(
65+
self, invalid_manifest, base_manifest_schema, full_manifest_schema
66+
):
67+
with open(
68+
os.path.join(
69+
PROJECT_PATH, "genesis", "manifests", "examples", invalid_manifest
70+
),
71+
"r",
72+
) as f:
73+
manifest = yaml.safe_load(f)
74+
with pytest.raises(exceptions.OpenApiValidateException):
75+
validate_manifest(manifest, base_manifest_schema)
76+
validate_manifest(manifest, full_manifest_schema)
77+
5278
@pytest.mark.skip(reason="for manual running")
5379
def test_build_full_schema(self, base_manifest_schema, user_api_spec):
54-
path_schema = []
55-
for path, path_obj in user_api_spec["paths"].items():
56-
path_parts = path.split("/")
57-
if len(path_parts) > 5:
58-
continue
59-
post_path = path_obj.get("post")
60-
if post_path:
61-
operation_id = post_path.get("operationId")
62-
if operation_id and operation_id.startswith("Create_v1"):
63-
schema_ref = post_path["requestBody"]["content"][
64-
"application/json"
65-
]["schema"]
66-
model_name = schema_ref["$ref"].split("/")[-1]
67-
api_part_1 = path_parts[2]
68-
api_part_2 = path_parts[3]
69-
model = user_api_spec["components"]["schemas"][model_name]
70-
resource = f"$core.{api_part_1}.{api_part_2}"
71-
path_schema.append(
72-
{
73-
"path": path,
74-
"schema": schema_ref,
75-
"resource": resource,
76-
"model_name": model_name,
77-
"model": model,
78-
}
79-
)
80-
base_manifest_schema["components"]["schemas"][model_name] = model
81-
base_manifest_schema["properties"]["resources"]["properties"][
82-
resource
83-
] = {
84-
"type": "object",
85-
"additionalProperties": schema_ref,
86-
}
87-
88-
assert path_schema
89-
dump_full_manifest_schema(base_manifest_schema)
80+
full_schema = build_full_schema(base_manifest_schema, user_api_spec)
81+
dump_full_manifest_schema(full_schema)

genesis_core/tests/functional/service/test_elements.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@
1414
# License for the specific language governing permissions and limitations
1515
# under the License.
1616

17-
import typing as tp
18-
19-
from gcl_iam.tests.functional import clients as iam_clients
20-
2117
from genesis_core.elements.services import builders
2218

2319

@@ -31,8 +27,5 @@ def teardown_method(self) -> None:
3127

3228
def test_element_manager_builder(
3329
self,
34-
password_factory: tp.Callable,
35-
user_api_client: iam_clients.GenesisCoreTestRESTClient,
36-
auth_user_admin: iam_clients.GenesisCoreAuth,
3730
):
3831
self._service._iteration()

uv.lock

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)