orchestrator-core 2.10.0rc1__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orchestrator/__init__.py +1 -1
- orchestrator/api/api_v1/api.py +24 -3
- orchestrator/api/api_v1/endpoints/processes.py +1 -1
- orchestrator/api/api_v1/endpoints/product_blocks.py +56 -0
- orchestrator/api/api_v1/endpoints/products.py +28 -1
- orchestrator/api/api_v1/endpoints/resource_types.py +56 -0
- orchestrator/api/api_v1/endpoints/settings.py +2 -1
- orchestrator/api/api_v1/endpoints/workflows.py +54 -0
- orchestrator/app.py +3 -2
- orchestrator/cli/generator/generator/product_block.py +1 -9
- orchestrator/cli/generator/templates/create_product.j2 +2 -1
- orchestrator/cli/generator/templates/modify_product.j2 +2 -1
- orchestrator/cli/generator/templates/shared_workflows.j2 +2 -1
- orchestrator/cli/generator/templates/terminate_product.j2 +1 -1
- orchestrator/cli/generator/templates/test_create_workflow.j2 +0 -1
- orchestrator/cli/generator/templates/test_modify_workflow.j2 +1 -2
- orchestrator/cli/generator/templates/test_terminate_workflow.j2 +1 -1
- orchestrator/cli/generator/templates/validate_product.j2 +3 -1
- orchestrator/cli/helpers/print_helpers.py +1 -1
- orchestrator/config/assignee.py +1 -1
- orchestrator/db/models.py +17 -0
- orchestrator/devtools/populator.py +1 -1
- orchestrator/devtools/scripts/migrate_20.py +11 -106
- orchestrator/devtools/scripts/migrate_30.py +61 -0
- orchestrator/devtools/scripts/shared.py +108 -0
- orchestrator/distlock/managers/redis_distlock_manager.py +3 -2
- orchestrator/domain/base.py +1 -2
- orchestrator/domain/lifecycle.py +2 -1
- orchestrator/graphql/resolvers/settings.py +2 -1
- orchestrator/graphql/schemas/product.py +19 -2
- orchestrator/migrations/helpers.py +1 -1
- orchestrator/migrations/versions/schema/2025-02-12_bac6be6f2b4f_added_input_state_table.py +56 -0
- orchestrator/schemas/engine_settings.py +1 -1
- orchestrator/schemas/product.py +4 -0
- orchestrator/schemas/product_block.py +4 -0
- orchestrator/schemas/resource_type.py +4 -0
- orchestrator/schemas/subscription.py +2 -1
- orchestrator/schemas/workflow.py +4 -0
- orchestrator/services/celery.py +7 -4
- orchestrator/services/input_state.py +76 -0
- orchestrator/services/processes.py +8 -6
- orchestrator/services/products.py +1 -1
- orchestrator/services/subscriptions.py +2 -1
- orchestrator/services/tasks.py +13 -7
- orchestrator/services/workflows.py +13 -0
- orchestrator/settings.py +5 -2
- orchestrator/targets.py +1 -1
- orchestrator/types.py +8 -43
- orchestrator/utils/errors.py +2 -1
- orchestrator/utils/redis.py +6 -11
- orchestrator/utils/redis_client.py +35 -0
- orchestrator/utils/state.py +2 -1
- orchestrator/workflow.py +3 -1
- orchestrator/workflows/modify_note.py +1 -2
- orchestrator/workflows/steps.py +2 -1
- orchestrator/workflows/tasks/cleanup_tasks_log.py +1 -1
- orchestrator/workflows/tasks/resume_workflows.py +1 -1
- orchestrator/workflows/tasks/validate_product_type.py +1 -1
- orchestrator/workflows/tasks/validate_products.py +1 -1
- orchestrator/workflows/utils.py +2 -2
- {orchestrator_core-2.10.0rc1.dist-info → orchestrator_core-3.0.0.dist-info}/METADATA +10 -8
- {orchestrator_core-2.10.0rc1.dist-info → orchestrator_core-3.0.0.dist-info}/RECORD +64 -56
- {orchestrator_core-2.10.0rc1.dist-info → orchestrator_core-3.0.0.dist-info}/WHEEL +1 -1
- {orchestrator_core-2.10.0rc1.dist-info → orchestrator_core-3.0.0.dist-info/licenses}/LICENSE +0 -0
orchestrator/__init__.py
CHANGED
orchestrator/api/api_v1/api.py
CHANGED
|
@@ -19,12 +19,15 @@ from fastapi.routing import APIRouter
|
|
|
19
19
|
from orchestrator.api.api_v1.endpoints import (
|
|
20
20
|
health,
|
|
21
21
|
processes,
|
|
22
|
+
product_blocks,
|
|
22
23
|
products,
|
|
24
|
+
resource_types,
|
|
23
25
|
settings,
|
|
24
26
|
subscription_customer_descriptions,
|
|
25
27
|
subscriptions,
|
|
26
28
|
translations,
|
|
27
29
|
user,
|
|
30
|
+
workflows,
|
|
28
31
|
ws,
|
|
29
32
|
)
|
|
30
33
|
from orchestrator.security import authorize
|
|
@@ -34,14 +37,32 @@ api_router = APIRouter()
|
|
|
34
37
|
api_router.include_router(
|
|
35
38
|
processes.router, prefix="/processes", tags=["Core", "Processes"], dependencies=[Depends(authorize)]
|
|
36
39
|
)
|
|
40
|
+
api_router.include_router(
|
|
41
|
+
subscriptions.router,
|
|
42
|
+
prefix="/subscriptions",
|
|
43
|
+
tags=["Core", "Subscriptions"],
|
|
44
|
+
dependencies=[Depends(authorize)],
|
|
45
|
+
)
|
|
37
46
|
api_router.include_router(processes.ws_router, prefix="/processes", tags=["Core", "Processes"])
|
|
38
47
|
api_router.include_router(
|
|
39
48
|
products.router, prefix="/products", tags=["Core", "Product"], dependencies=[Depends(authorize)]
|
|
40
49
|
)
|
|
41
50
|
api_router.include_router(
|
|
42
|
-
|
|
43
|
-
prefix="/
|
|
44
|
-
tags=["Core", "
|
|
51
|
+
product_blocks.router,
|
|
52
|
+
prefix="/product_blocks",
|
|
53
|
+
tags=["Core", "Product Blocks"],
|
|
54
|
+
dependencies=[Depends(authorize)],
|
|
55
|
+
)
|
|
56
|
+
api_router.include_router(
|
|
57
|
+
resource_types.router,
|
|
58
|
+
prefix="/resource_types",
|
|
59
|
+
tags=["Core", "Resource Types"],
|
|
60
|
+
dependencies=[Depends(authorize)],
|
|
61
|
+
)
|
|
62
|
+
api_router.include_router(
|
|
63
|
+
workflows.router,
|
|
64
|
+
prefix="/workflows",
|
|
65
|
+
tags=["Core", "Workflows"],
|
|
45
66
|
dependencies=[Depends(authorize)],
|
|
46
67
|
)
|
|
47
68
|
api_router.include_router(
|
|
@@ -61,7 +61,6 @@ from orchestrator.services.processes import (
|
|
|
61
61
|
)
|
|
62
62
|
from orchestrator.services.settings import get_engine_settings
|
|
63
63
|
from orchestrator.settings import app_settings
|
|
64
|
-
from orchestrator.types import JSON, State
|
|
65
64
|
from orchestrator.utils.enrich_process import enrich_process
|
|
66
65
|
from orchestrator.websocket import (
|
|
67
66
|
WS_CHANNELS,
|
|
@@ -70,6 +69,7 @@ from orchestrator.websocket import (
|
|
|
70
69
|
websocket_manager,
|
|
71
70
|
)
|
|
72
71
|
from orchestrator.workflow import ProcessStatus
|
|
72
|
+
from pydantic_forms.types import JSON, State
|
|
73
73
|
|
|
74
74
|
router = APIRouter()
|
|
75
75
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright 2019-2020 SURF.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
|
|
14
|
+
from http import HTTPStatus
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
from fastapi.param_functions import Body
|
|
18
|
+
from fastapi.routing import APIRouter
|
|
19
|
+
|
|
20
|
+
from orchestrator.api.error_handling import raise_status
|
|
21
|
+
from orchestrator.db import db
|
|
22
|
+
from orchestrator.db.models import ProductBlockTable
|
|
23
|
+
from orchestrator.schemas.product_block import ProductBlockPatchSchema, ProductBlockSchema
|
|
24
|
+
|
|
25
|
+
router = APIRouter()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@router.get("/{product_block_id}", response_model=ProductBlockSchema)
|
|
29
|
+
def get_product_block_description(product_block_id: UUID) -> str:
|
|
30
|
+
product_block = db.session.get(ProductBlockTable, product_block_id)
|
|
31
|
+
if product_block is None:
|
|
32
|
+
raise_status(HTTPStatus.NOT_FOUND)
|
|
33
|
+
return product_block
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@router.patch("/{product_block_id}", status_code=HTTPStatus.CREATED, response_model=ProductBlockSchema)
|
|
37
|
+
async def patch_product_block_by_id(
|
|
38
|
+
product_block_id: UUID, data: ProductBlockPatchSchema = Body(...)
|
|
39
|
+
) -> ProductBlockTable:
|
|
40
|
+
product_block = db.session.get(ProductBlockTable, product_block_id)
|
|
41
|
+
if not product_block:
|
|
42
|
+
raise_status(HTTPStatus.NOT_FOUND, f"Product_block id {product_block_id} not found")
|
|
43
|
+
|
|
44
|
+
return await _patch_product_block_description(data, product_block)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def _patch_product_block_description(
|
|
48
|
+
data: ProductBlockPatchSchema,
|
|
49
|
+
product_block: ProductBlockTable,
|
|
50
|
+
) -> ProductBlockTable:
|
|
51
|
+
|
|
52
|
+
updated_properties = data.model_dump(exclude_unset=True)
|
|
53
|
+
description = updated_properties.get("description", product_block.description)
|
|
54
|
+
product_block.description = description
|
|
55
|
+
db.session.commit()
|
|
56
|
+
return product_block
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
from http import HTTPStatus
|
|
15
15
|
from uuid import UUID
|
|
16
16
|
|
|
17
|
+
from fastapi.param_functions import Body
|
|
17
18
|
from fastapi.routing import APIRouter
|
|
18
19
|
from sqlalchemy import select
|
|
19
20
|
from sqlalchemy.orm import joinedload, selectinload
|
|
@@ -21,6 +22,7 @@ from sqlalchemy.orm import joinedload, selectinload
|
|
|
21
22
|
from orchestrator.api.error_handling import raise_status
|
|
22
23
|
from orchestrator.db import ProductBlockTable, ProductTable, db
|
|
23
24
|
from orchestrator.schemas import ProductSchema
|
|
25
|
+
from orchestrator.schemas.product import ProductPatchSchema
|
|
24
26
|
|
|
25
27
|
router = APIRouter()
|
|
26
28
|
|
|
@@ -48,6 +50,13 @@ def fetch(tag: str | None = None, product_type: str | None = None) -> list[Produ
|
|
|
48
50
|
response_model=ProductSchema,
|
|
49
51
|
)
|
|
50
52
|
def product_by_id(product_id: UUID) -> ProductTable:
|
|
53
|
+
product = _product_by_id(product_id)
|
|
54
|
+
if not product:
|
|
55
|
+
raise_status(HTTPStatus.NOT_FOUND, f"Product id {product_id} not found")
|
|
56
|
+
return product
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _product_by_id(product_id: UUID) -> ProductTable | None:
|
|
51
60
|
stmt = (
|
|
52
61
|
select(ProductTable)
|
|
53
62
|
.options(
|
|
@@ -57,7 +66,25 @@ def product_by_id(product_id: UUID) -> ProductTable:
|
|
|
57
66
|
)
|
|
58
67
|
.filter(ProductTable.product_id == product_id)
|
|
59
68
|
)
|
|
60
|
-
|
|
69
|
+
return db.session.scalars(stmt).unique().one_or_none()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@router.patch("/{product_id}", status_code=HTTPStatus.CREATED, response_model=ProductSchema)
|
|
73
|
+
async def patch_product_by_id(product_id: UUID, data: ProductPatchSchema = Body(...)) -> ProductTable:
|
|
74
|
+
product = _product_by_id(product_id)
|
|
61
75
|
if not product:
|
|
62
76
|
raise_status(HTTPStatus.NOT_FOUND, f"Product id {product_id} not found")
|
|
77
|
+
|
|
78
|
+
return await _patch_product_description(data, product)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def _patch_product_description(
|
|
82
|
+
data: ProductPatchSchema,
|
|
83
|
+
product: ProductTable,
|
|
84
|
+
) -> ProductTable:
|
|
85
|
+
|
|
86
|
+
updated_properties = data.model_dump(exclude_unset=True)
|
|
87
|
+
description = updated_properties.get("description", product.description)
|
|
88
|
+
product.description = description
|
|
89
|
+
db.session.commit()
|
|
63
90
|
return product
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright 2019-2020 SURF.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
|
|
14
|
+
from http import HTTPStatus
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
from fastapi.param_functions import Body
|
|
18
|
+
from fastapi.routing import APIRouter
|
|
19
|
+
|
|
20
|
+
from orchestrator.api.error_handling import raise_status
|
|
21
|
+
from orchestrator.db import db
|
|
22
|
+
from orchestrator.db.models import ResourceTypeTable
|
|
23
|
+
from orchestrator.schemas.resource_type import ResourceTypePatchSchema, ResourceTypeSchema
|
|
24
|
+
|
|
25
|
+
router = APIRouter()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@router.get("/{resource_type_id}", response_model=ResourceTypeSchema)
|
|
29
|
+
def get_resource_type_description(resource_type_id: UUID) -> str:
|
|
30
|
+
resource_type = db.session.get(ResourceTypeTable, resource_type_id)
|
|
31
|
+
if resource_type is None:
|
|
32
|
+
raise_status(HTTPStatus.NOT_FOUND)
|
|
33
|
+
return resource_type
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@router.patch("/{resource_type_id}", status_code=HTTPStatus.CREATED, response_model=ResourceTypeSchema)
|
|
37
|
+
async def patch_resource_type_by_id(
|
|
38
|
+
resource_type_id: UUID, data: ResourceTypePatchSchema = Body(...)
|
|
39
|
+
) -> ResourceTypeTable:
|
|
40
|
+
resource_type = db.session.get(ResourceTypeTable, resource_type_id)
|
|
41
|
+
if not resource_type:
|
|
42
|
+
raise_status(HTTPStatus.NOT_FOUND, f"ResourceType id {resource_type_id} not found")
|
|
43
|
+
|
|
44
|
+
return await _patch_resource_type_description(data, resource_type)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def _patch_resource_type_description(
|
|
48
|
+
data: ResourceTypePatchSchema,
|
|
49
|
+
resource_type: ResourceTypeTable,
|
|
50
|
+
) -> ResourceTypeTable:
|
|
51
|
+
|
|
52
|
+
updated_properties = data.model_dump(exclude_unset=True)
|
|
53
|
+
description = updated_properties.get("description", resource_type.description)
|
|
54
|
+
resource_type.description = description
|
|
55
|
+
db.session.commit()
|
|
56
|
+
return resource_type
|
|
@@ -28,6 +28,7 @@ from orchestrator.services import processes, settings
|
|
|
28
28
|
from orchestrator.settings import ExecutorType, app_settings
|
|
29
29
|
from orchestrator.utils.json import json_dumps
|
|
30
30
|
from orchestrator.utils.redis import delete_keys_matching_pattern
|
|
31
|
+
from orchestrator.utils.redis_client import create_redis_asyncio_client
|
|
31
32
|
from orchestrator.websocket import WS_CHANNELS, broadcast_invalidate_cache, websocket_manager
|
|
32
33
|
|
|
33
34
|
router = APIRouter()
|
|
@@ -41,7 +42,7 @@ CACHE_FLUSH_OPTIONS: dict[str, str] = {
|
|
|
41
42
|
|
|
42
43
|
@router.delete("/cache/{name}")
|
|
43
44
|
async def clear_cache(name: str) -> int | None:
|
|
44
|
-
cache: AIORedis =
|
|
45
|
+
cache: AIORedis = create_redis_asyncio_client(app_settings.CACHE_URI)
|
|
45
46
|
if name not in CACHE_FLUSH_OPTIONS:
|
|
46
47
|
raise_status(HTTPStatus.BAD_REQUEST, "Invalid cache name")
|
|
47
48
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright 2019-2020 SURF.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
|
|
14
|
+
from http import HTTPStatus
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
from fastapi.param_functions import Body
|
|
18
|
+
from fastapi.routing import APIRouter
|
|
19
|
+
|
|
20
|
+
from orchestrator.api.error_handling import raise_status
|
|
21
|
+
from orchestrator.db import db
|
|
22
|
+
from orchestrator.db.models import WorkflowTable
|
|
23
|
+
from orchestrator.schemas.workflow import WorkflowPatchSchema, WorkflowSchema
|
|
24
|
+
|
|
25
|
+
router = APIRouter()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@router.get("/{workflow_id}", response_model=WorkflowSchema)
|
|
29
|
+
def get_workflow_description(workflow_id: UUID) -> str:
|
|
30
|
+
workflow = db.session.get(WorkflowTable, workflow_id)
|
|
31
|
+
if workflow is None:
|
|
32
|
+
raise_status(HTTPStatus.NOT_FOUND)
|
|
33
|
+
return workflow
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@router.patch("/{workflow_id}", status_code=HTTPStatus.CREATED, response_model=WorkflowSchema)
|
|
37
|
+
async def patch_workflow_by_id(workflow_id: UUID, data: WorkflowPatchSchema = Body(...)) -> WorkflowTable:
|
|
38
|
+
workflow = db.session.get(WorkflowTable, workflow_id)
|
|
39
|
+
if not workflow:
|
|
40
|
+
raise_status(HTTPStatus.NOT_FOUND, f"Workflow id {workflow_id} not found")
|
|
41
|
+
|
|
42
|
+
return await _patch_workflow_description(data, workflow)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def _patch_workflow_description(
|
|
46
|
+
data: WorkflowPatchSchema,
|
|
47
|
+
workflow: WorkflowTable,
|
|
48
|
+
) -> WorkflowTable:
|
|
49
|
+
|
|
50
|
+
updated_properties = data.model_dump(exclude_unset=True)
|
|
51
|
+
description = updated_properties.get("description", workflow.description)
|
|
52
|
+
workflow.description = description
|
|
53
|
+
db.session.commit()
|
|
54
|
+
return workflow
|
orchestrator/app.py
CHANGED
|
@@ -199,8 +199,9 @@ class OrchestratorCore(FastAPI):
|
|
|
199
199
|
|
|
200
200
|
def register_graphql(
|
|
201
201
|
self: "OrchestratorCore",
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
# mypy 1.9 cannot properly inspect these, fixed in 1.15
|
|
203
|
+
query: Any = Query, # type: ignore
|
|
204
|
+
mutation: Any = Mutation, # type: ignore
|
|
204
205
|
register_models: bool = True,
|
|
205
206
|
subscription_interface: Any = SubscriptionInterface,
|
|
206
207
|
graphql_models: StrawberryModelType | None = None,
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
# See the License for the specific language governing permissions and
|
|
12
12
|
# limitations under the License.
|
|
13
13
|
|
|
14
|
-
import re
|
|
15
14
|
from collections import ChainMap
|
|
16
15
|
from collections.abc import Mapping
|
|
17
16
|
from pathlib import Path
|
|
@@ -56,15 +55,8 @@ def get_product_block_path(product_block: dict) -> Path:
|
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
def enrich_product_block(product_block: dict) -> dict:
|
|
59
|
-
def to_block_name() -> str:
|
|
60
|
-
"""Separate block name into words."""
|
|
61
|
-
type = product_block["type"]
|
|
62
|
-
name = re.sub("(.)([A-Z][a-z]+)", r"\1 \2", type)
|
|
63
|
-
return re.sub("([a-z0-9])([A-Z])", r"\1 \2", name)
|
|
64
|
-
|
|
65
58
|
fields = get_all_fields(product_block)
|
|
66
|
-
block_name = product_block.get("block_name",
|
|
67
|
-
|
|
59
|
+
block_name = product_block.get("block_name", product_block.get("type"))
|
|
68
60
|
return product_block | {
|
|
69
61
|
"fields": fields,
|
|
70
62
|
"block_name": block_name,
|
|
@@ -7,11 +7,12 @@ from typing import Annotated
|
|
|
7
7
|
|
|
8
8
|
import structlog
|
|
9
9
|
from pydantic import AfterValidator, ConfigDict, model_validator
|
|
10
|
+
from pydantic_forms.types import FormGenerator, State, UUIDstr
|
|
10
11
|
|
|
11
12
|
from orchestrator.forms import FormPage
|
|
12
13
|
from orchestrator.forms.validators import Divider, Label, CustomerId, MigrationSummary
|
|
13
14
|
from orchestrator.targets import Target
|
|
14
|
-
from orchestrator.types import
|
|
15
|
+
from orchestrator.types import SubscriptionLifecycle
|
|
15
16
|
from orchestrator.workflow import StepList, begin, step
|
|
16
17
|
from orchestrator.workflows.steps import store_process_subscription
|
|
17
18
|
from orchestrator.workflows.utils import create_workflow
|
|
@@ -6,11 +6,12 @@ from typing import Annotated
|
|
|
6
6
|
|
|
7
7
|
import structlog
|
|
8
8
|
from pydantic import AfterValidator, ConfigDict, model_validator
|
|
9
|
+
from pydantic_forms.types import FormGenerator, State, UUIDstr
|
|
9
10
|
from pydantic_forms.validators import ReadOnlyField
|
|
10
11
|
|
|
11
12
|
from orchestrator.forms import FormPage
|
|
12
13
|
from orchestrator.forms.validators import CustomerId, Divider
|
|
13
|
-
from orchestrator.types import
|
|
14
|
+
from orchestrator.types import SubscriptionLifecycle
|
|
14
15
|
from orchestrator.workflow import StepList, begin, step
|
|
15
16
|
from orchestrator.workflows.steps import set_status
|
|
16
17
|
from orchestrator.workflows.utils import modify_workflow
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import structlog
|
|
4
4
|
from pydantic import AfterValidator, ConfigDict, model_validator
|
|
5
|
+
from pydantic_forms.types import InputForm, State, UUIDstr
|
|
5
6
|
|
|
6
7
|
from orchestrator.forms import FormPage
|
|
7
8
|
from orchestrator.forms.validators import DisplaySubscription
|
|
8
|
-
from orchestrator.types import InputForm, State, UUIDstr
|
|
9
9
|
from orchestrator.workflow import StepList, begin, step
|
|
10
10
|
from orchestrator.workflows.utils import terminate_workflow
|
|
11
11
|
|
|
@@ -4,7 +4,6 @@ from orchestrator.db import ProductTable
|
|
|
4
4
|
from orchestrator.forms import FormValidationError
|
|
5
5
|
|
|
6
6
|
from test.unit_tests.workflows import assert_complete, extract_state, run_workflow
|
|
7
|
-
|
|
8
7
|
from {{ product_types_module }}.{{ product.variable }} import {{ product.type }}
|
|
9
8
|
|
|
10
9
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from orchestrator.forms import FormValidationError
|
|
3
|
-
|
|
4
3
|
from orchestrator.types import SubscriptionLifecycle
|
|
5
|
-
from test.unit_tests.workflows import assert_complete, extract_state, run_workflow
|
|
6
4
|
|
|
5
|
+
from test.unit_tests.workflows import assert_complete, extract_state, run_workflow
|
|
7
6
|
from {{ product_types_module }}.{{ product.variable }} import {{ product.type }}
|
|
8
7
|
|
|
9
8
|
|
|
@@ -4,8 +4,8 @@ import pytest
|
|
|
4
4
|
from orchestrator.forms import FormValidationError
|
|
5
5
|
{% endif %}
|
|
6
6
|
from orchestrator.types import SubscriptionLifecycle
|
|
7
|
-
from test.unit_tests.workflows import assert_complete, extract_state, run_workflow
|
|
8
7
|
|
|
8
|
+
from test.unit_tests.workflows import assert_complete, extract_state, run_workflow
|
|
9
9
|
from {{ product_types_module }}.{{ product.variable }} import {{ product.type }}
|
|
10
10
|
|
|
11
11
|
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
import structlog
|
|
4
4
|
{% if product.nso_service_id_path %}
|
|
5
5
|
from deepdiff import DeepDiff
|
|
6
|
+
{% endif %}
|
|
7
|
+
from pydantic_forms.types import State
|
|
8
|
+
{% if product.nso_service_id_path %}
|
|
6
9
|
from surf.products.services.nso.nso import build_payload
|
|
7
10
|
{% endif %}
|
|
8
|
-
from orchestrator.types import State
|
|
9
11
|
from orchestrator.workflow import StepList, begin, step
|
|
10
12
|
from orchestrator.workflows.utils import validate_workflow
|
|
11
13
|
|
orchestrator/config/assignee.py
CHANGED
orchestrator/db/models.py
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
import enum
|
|
16
17
|
from datetime import datetime, timezone
|
|
17
18
|
|
|
18
19
|
import sqlalchemy
|
|
@@ -23,6 +24,7 @@ from sqlalchemy import (
|
|
|
23
24
|
Boolean,
|
|
24
25
|
CheckConstraint,
|
|
25
26
|
Column,
|
|
27
|
+
Enum,
|
|
26
28
|
ForeignKey,
|
|
27
29
|
Index,
|
|
28
30
|
Integer,
|
|
@@ -81,6 +83,20 @@ class UtcTimestamp(TypeDecorator):
|
|
|
81
83
|
return value.astimezone(timezone.utc) if value else value
|
|
82
84
|
|
|
83
85
|
|
|
86
|
+
class InputStateTable(BaseModel):
|
|
87
|
+
__tablename__ = "input_states"
|
|
88
|
+
|
|
89
|
+
class InputType(enum.Enum):
|
|
90
|
+
user_input = "user_input"
|
|
91
|
+
initial_state = "initial_state"
|
|
92
|
+
|
|
93
|
+
input_state_id = mapped_column(UUIDType, primary_key=True, server_default=text("uuid_generate_v4()"), index=True)
|
|
94
|
+
process_id = mapped_column("pid", UUIDType, ForeignKey("processes.pid"), nullable=False)
|
|
95
|
+
input_state = mapped_column(pg.JSONB(), nullable=False) # type: ignore
|
|
96
|
+
input_time = mapped_column(UtcTimestamp, server_default=text("current_timestamp()"), nullable=False)
|
|
97
|
+
input_type = mapped_column(Enum(InputType), nullable=False)
|
|
98
|
+
|
|
99
|
+
|
|
84
100
|
class ProcessTable(BaseModel):
|
|
85
101
|
__tablename__ = "processes"
|
|
86
102
|
|
|
@@ -101,6 +117,7 @@ class ProcessTable(BaseModel):
|
|
|
101
117
|
steps = relationship(
|
|
102
118
|
"ProcessStepTable", cascade="delete", passive_deletes=True, order_by="asc(ProcessStepTable.executed_at)"
|
|
103
119
|
)
|
|
120
|
+
input_states = relationship("InputStateTable", cascade="delete", order_by="desc(InputStateTable.input_time)")
|
|
104
121
|
process_subscriptions = relationship("ProcessSubscriptionTable", back_populates="process", passive_deletes=True)
|
|
105
122
|
workflow = relationship("WorkflowTable", back_populates="processes")
|
|
106
123
|
|
|
@@ -26,8 +26,8 @@ import structlog
|
|
|
26
26
|
from more_itertools import first, first_true
|
|
27
27
|
|
|
28
28
|
from nwastdlib.url import URL
|
|
29
|
-
from orchestrator.types import State
|
|
30
29
|
from pydantic_forms.types import InputForm as LegacyInputForm
|
|
30
|
+
from pydantic_forms.types import State
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class JSONSubSchema(TypedDict, total=False):
|