zenml-nightly 0.58.2.dev20240624__py3-none-any.whl → 0.58.2.dev20240625__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.
- zenml/VERSION +1 -1
- zenml/actions/base_action.py +177 -174
- zenml/actions/pipeline_run/pipeline_run_action.py +28 -23
- zenml/client.py +226 -55
- zenml/config/compiler.py +10 -9
- zenml/config/docker_settings.py +25 -9
- zenml/constants.py +1 -1
- zenml/event_hub/base_event_hub.py +5 -5
- zenml/event_hub/event_hub.py +15 -6
- zenml/event_sources/base_event.py +0 -11
- zenml/event_sources/base_event_source.py +7 -0
- zenml/event_sources/webhooks/base_webhook_event_source.py +1 -4
- zenml/exceptions.py +4 -0
- zenml/hooks/hook_validators.py +2 -3
- zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +3 -3
- zenml/integrations/mlflow/__init__.py +1 -1
- zenml/models/__init__.py +17 -0
- zenml/models/v2/core/action.py +276 -0
- zenml/models/v2/core/trigger.py +182 -141
- zenml/new/pipelines/pipeline.py +13 -3
- zenml/new/pipelines/pipeline_decorator.py +1 -2
- zenml/new/pipelines/run_utils.py +1 -12
- zenml/new/steps/step_decorator.py +2 -3
- zenml/pipelines/base_pipeline.py +0 -2
- zenml/pipelines/pipeline_decorator.py +1 -2
- zenml/steps/base_step.py +1 -2
- zenml/steps/step_decorator.py +1 -2
- zenml/types.py +10 -1
- zenml/utils/pipeline_docker_image_builder.py +20 -5
- zenml/zen_server/rbac/models.py +1 -0
- zenml/zen_server/rbac/utils.py +22 -1
- zenml/zen_server/routers/actions_endpoints.py +324 -0
- zenml/zen_server/routers/triggers_endpoints.py +30 -158
- zenml/zen_server/zen_server_api.py +2 -0
- zenml/zen_stores/migrations/versions/25155145c545_separate_actions_and_triggers.py +228 -0
- zenml/zen_stores/rest_zen_store.py +103 -4
- zenml/zen_stores/schemas/__init__.py +2 -0
- zenml/zen_stores/schemas/action_schemas.py +192 -0
- zenml/zen_stores/schemas/trigger_schemas.py +43 -50
- zenml/zen_stores/schemas/user_schemas.py +10 -2
- zenml/zen_stores/schemas/workspace_schemas.py +5 -0
- zenml/zen_stores/sql_zen_store.py +240 -30
- zenml/zen_stores/zen_store_interface.py +85 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/METADATA +1 -1
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/RECORD +48 -44
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/entry_points.txt +0 -0
zenml/steps/base_step.py
CHANGED
@@ -18,7 +18,6 @@ import hashlib
|
|
18
18
|
import inspect
|
19
19
|
from abc import abstractmethod
|
20
20
|
from collections import defaultdict
|
21
|
-
from types import FunctionType
|
22
21
|
from typing import (
|
23
22
|
TYPE_CHECKING,
|
24
23
|
Any,
|
@@ -76,10 +75,10 @@ if TYPE_CHECKING:
|
|
76
75
|
)
|
77
76
|
from zenml.model.lazy_load import ModelVersionDataLazyLoader
|
78
77
|
from zenml.model.model import Model
|
78
|
+
from zenml.types import HookSpecification
|
79
79
|
|
80
80
|
ParametersOrDict = Union["BaseParameters", Dict[str, Any]]
|
81
81
|
MaterializerClassOrSource = Union[str, Source, Type["BaseMaterializer"]]
|
82
|
-
HookSpecification = Union[str, Source, FunctionType]
|
83
82
|
OutputMaterializersSpecification = Union[
|
84
83
|
"MaterializerClassOrSource",
|
85
84
|
Sequence["MaterializerClassOrSource"],
|
zenml/steps/step_decorator.py
CHANGED
@@ -13,7 +13,6 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""Step decorator function."""
|
15
15
|
|
16
|
-
from types import FunctionType
|
17
16
|
from typing import (
|
18
17
|
TYPE_CHECKING,
|
19
18
|
Any,
|
@@ -37,9 +36,9 @@ if TYPE_CHECKING:
|
|
37
36
|
from zenml.config.source import Source
|
38
37
|
from zenml.materializers.base_materializer import BaseMaterializer
|
39
38
|
from zenml.model.model import Model
|
39
|
+
from zenml.types import HookSpecification
|
40
40
|
|
41
41
|
MaterializerClassOrSource = Union[str, "Source", Type["BaseMaterializer"]]
|
42
|
-
HookSpecification = Union[str, "Source", FunctionType]
|
43
42
|
OutputMaterializersSpecification = Union[
|
44
43
|
"MaterializerClassOrSource",
|
45
44
|
Sequence["MaterializerClassOrSource"],
|
zenml/types.py
CHANGED
@@ -11,7 +11,16 @@
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
12
|
# or implied. See the License for the specific language governing
|
13
13
|
# permissions and limitations under the License.
|
14
|
-
"""Custom types
|
14
|
+
"""Custom ZenML types."""
|
15
|
+
|
16
|
+
from typing import TYPE_CHECKING, Callable, Union
|
17
|
+
|
18
|
+
if TYPE_CHECKING:
|
19
|
+
from types import FunctionType
|
20
|
+
|
21
|
+
from zenml.config.source import Source
|
22
|
+
|
23
|
+
HookSpecification = Union[str, Source, FunctionType, Callable[..., None]]
|
15
24
|
|
16
25
|
|
17
26
|
class HTMLString(str):
|
@@ -32,6 +32,7 @@ from typing import (
|
|
32
32
|
import zenml
|
33
33
|
from zenml.config import DockerSettings
|
34
34
|
from zenml.config.docker_settings import (
|
35
|
+
DockerBuildConfig,
|
35
36
|
PythonEnvironmentExportMethod,
|
36
37
|
PythonPackageInstaller,
|
37
38
|
)
|
@@ -212,8 +213,13 @@ class PipelineDockerImageBuilder:
|
|
212
213
|
# used directly, so we tag it with the requested target name.
|
213
214
|
user_image_name = target_image_name
|
214
215
|
|
216
|
+
build_config = (
|
217
|
+
docker_settings.parent_image_build_config
|
218
|
+
or DockerBuildConfig()
|
219
|
+
)
|
215
220
|
build_context = build_context_class(
|
216
|
-
root=docker_settings.build_context_root
|
221
|
+
root=docker_settings.build_context_root,
|
222
|
+
dockerignore_file=build_config.dockerignore,
|
217
223
|
)
|
218
224
|
build_context.add_file(
|
219
225
|
source=docker_settings.dockerfile, destination="Dockerfile"
|
@@ -222,7 +228,8 @@ class PipelineDockerImageBuilder:
|
|
222
228
|
image_name_or_digest = image_builder.build(
|
223
229
|
image_name=user_image_name,
|
224
230
|
build_context=build_context,
|
225
|
-
docker_build_options=
|
231
|
+
docker_build_options=build_config.build_options
|
232
|
+
or docker_settings.build_options,
|
226
233
|
container_registry=container_registry if push else None,
|
227
234
|
)
|
228
235
|
|
@@ -247,13 +254,18 @@ class PipelineDockerImageBuilder:
|
|
247
254
|
|
248
255
|
if requires_zenml_build:
|
249
256
|
logger.info("Building Docker image `%s`.", target_image_name)
|
257
|
+
build_config = docker_settings.build_config or DockerBuildConfig()
|
258
|
+
|
250
259
|
# Leave the build context empty if we don't want to include any files
|
251
260
|
build_context_root = (
|
252
261
|
source_utils.get_source_root() if include_files else None
|
253
262
|
)
|
263
|
+
dockerignore = (
|
264
|
+
build_config.dockerignore or docker_settings.dockerignore
|
265
|
+
)
|
254
266
|
build_context = build_context_class(
|
255
267
|
root=build_context_root,
|
256
|
-
dockerignore_file=
|
268
|
+
dockerignore_file=dockerignore,
|
257
269
|
)
|
258
270
|
|
259
271
|
requirements_files = self.gather_requirements_files(
|
@@ -304,8 +316,11 @@ class PipelineDockerImageBuilder:
|
|
304
316
|
parent_image
|
305
317
|
)
|
306
318
|
|
307
|
-
build_options = {
|
308
|
-
|
319
|
+
build_options = {
|
320
|
+
"pull": pull_parent_image,
|
321
|
+
"rm": False,
|
322
|
+
**build_config.build_options,
|
323
|
+
}
|
309
324
|
dockerfile = self._generate_zenml_pipeline_dockerfile(
|
310
325
|
parent_image=parent_image,
|
311
326
|
docker_settings=docker_settings,
|
zenml/zen_server/rbac/models.py
CHANGED
zenml/zen_server/rbac/utils.py
CHANGED
@@ -189,7 +189,12 @@ def get_permission_denied_model(model: AnyResponse) -> AnyResponse:
|
|
189
189
|
The permission denied model.
|
190
190
|
"""
|
191
191
|
return model.model_copy(
|
192
|
-
update={
|
192
|
+
update={
|
193
|
+
"body": None,
|
194
|
+
"metadata": None,
|
195
|
+
"resources": None,
|
196
|
+
"permission_denied": True,
|
197
|
+
}
|
193
198
|
)
|
194
199
|
|
195
200
|
|
@@ -384,10 +389,12 @@ def get_resource_type_for_model(
|
|
384
389
|
is not associated with any resource type.
|
385
390
|
"""
|
386
391
|
from zenml.models import (
|
392
|
+
ActionResponse,
|
387
393
|
ArtifactResponse,
|
388
394
|
ArtifactVersionResponse,
|
389
395
|
CodeRepositoryResponse,
|
390
396
|
ComponentResponse,
|
397
|
+
EventSourceResponse,
|
391
398
|
FlavorResponse,
|
392
399
|
ModelResponse,
|
393
400
|
ModelVersionResponse,
|
@@ -402,6 +409,8 @@ def get_resource_type_for_model(
|
|
402
409
|
ServiceResponse,
|
403
410
|
StackResponse,
|
404
411
|
TagResponse,
|
412
|
+
TriggerExecutionResponse,
|
413
|
+
TriggerResponse,
|
405
414
|
UserResponse,
|
406
415
|
WorkspaceResponse,
|
407
416
|
)
|
@@ -410,6 +419,8 @@ def get_resource_type_for_model(
|
|
410
419
|
Any,
|
411
420
|
ResourceType,
|
412
421
|
] = {
|
422
|
+
ActionResponse: ResourceType.ACTION,
|
423
|
+
EventSourceResponse: ResourceType.EVENT_SOURCE,
|
413
424
|
FlavorResponse: ResourceType.FLAVOR,
|
414
425
|
ServiceConnectorResponse: ResourceType.SERVICE_CONNECTOR,
|
415
426
|
ComponentResponse: ResourceType.STACK_COMPONENT,
|
@@ -428,6 +439,8 @@ def get_resource_type_for_model(
|
|
428
439
|
PipelineBuildResponse: ResourceType.PIPELINE_BUILD,
|
429
440
|
PipelineRunResponse: ResourceType.PIPELINE_RUN,
|
430
441
|
TagResponse: ResourceType.TAG,
|
442
|
+
TriggerResponse: ResourceType.TRIGGER,
|
443
|
+
TriggerExecutionResponse: ResourceType.TRIGGER_EXECUTION,
|
431
444
|
ServiceAccountResponse: ResourceType.SERVICE_ACCOUNT,
|
432
445
|
ServiceResponse: ResourceType.SERVICE,
|
433
446
|
}
|
@@ -522,9 +535,11 @@ def get_schema_for_resource_type(
|
|
522
535
|
The database schema.
|
523
536
|
"""
|
524
537
|
from zenml.zen_stores.schemas import (
|
538
|
+
ActionSchema,
|
525
539
|
ArtifactSchema,
|
526
540
|
ArtifactVersionSchema,
|
527
541
|
CodeRepositorySchema,
|
542
|
+
EventSourceSchema,
|
528
543
|
FlavorSchema,
|
529
544
|
ModelSchema,
|
530
545
|
ModelVersionSchema,
|
@@ -539,6 +554,8 @@ def get_schema_for_resource_type(
|
|
539
554
|
StackComponentSchema,
|
540
555
|
StackSchema,
|
541
556
|
TagSchema,
|
557
|
+
TriggerExecutionSchema,
|
558
|
+
TriggerSchema,
|
542
559
|
UserSchema,
|
543
560
|
WorkspaceSchema,
|
544
561
|
)
|
@@ -564,6 +581,10 @@ def get_schema_for_resource_type(
|
|
564
581
|
ResourceType.PIPELINE_BUILD: PipelineBuildSchema,
|
565
582
|
ResourceType.RUN_METADATA: RunMetadataSchema,
|
566
583
|
ResourceType.USER: UserSchema,
|
584
|
+
ResourceType.ACTION: ActionSchema,
|
585
|
+
ResourceType.EVENT_SOURCE: EventSourceSchema,
|
586
|
+
ResourceType.TRIGGER: TriggerSchema,
|
587
|
+
ResourceType.TRIGGER_EXECUTION: TriggerExecutionSchema,
|
567
588
|
}
|
568
589
|
|
569
590
|
return mapping[resource_type]
|
@@ -0,0 +1,324 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2024. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at:
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
|
+
# or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
"""Endpoint definitions for actions."""
|
15
|
+
|
16
|
+
from uuid import UUID
|
17
|
+
|
18
|
+
from fastapi import APIRouter, Depends, Security
|
19
|
+
|
20
|
+
from zenml import ActionRequest
|
21
|
+
from zenml.actions.base_action import BaseActionHandler
|
22
|
+
from zenml.constants import (
|
23
|
+
ACTIONS,
|
24
|
+
API,
|
25
|
+
VERSION_1,
|
26
|
+
)
|
27
|
+
from zenml.enums import PluginType
|
28
|
+
from zenml.models import (
|
29
|
+
ActionFilter,
|
30
|
+
ActionResponse,
|
31
|
+
ActionUpdate,
|
32
|
+
Page,
|
33
|
+
)
|
34
|
+
from zenml.zen_server.auth import AuthContext, authorize
|
35
|
+
from zenml.zen_server.exceptions import error_response
|
36
|
+
from zenml.zen_server.rbac.endpoint_utils import (
|
37
|
+
verify_permissions_and_create_entity,
|
38
|
+
verify_permissions_and_list_entities,
|
39
|
+
)
|
40
|
+
from zenml.zen_server.rbac.models import Action, ResourceType
|
41
|
+
from zenml.zen_server.rbac.utils import (
|
42
|
+
dehydrate_response_model,
|
43
|
+
verify_permission_for_model,
|
44
|
+
)
|
45
|
+
from zenml.zen_server.utils import (
|
46
|
+
handle_exceptions,
|
47
|
+
make_dependable,
|
48
|
+
plugin_flavor_registry,
|
49
|
+
zen_store,
|
50
|
+
)
|
51
|
+
|
52
|
+
router = APIRouter(
|
53
|
+
prefix=API + VERSION_1 + ACTIONS,
|
54
|
+
tags=["actions"],
|
55
|
+
responses={401: error_response, 403: error_response},
|
56
|
+
)
|
57
|
+
|
58
|
+
|
59
|
+
@router.get(
|
60
|
+
"",
|
61
|
+
response_model=Page[ActionResponse],
|
62
|
+
responses={401: error_response, 404: error_response, 422: error_response},
|
63
|
+
)
|
64
|
+
@handle_exceptions
|
65
|
+
def list_actions(
|
66
|
+
action_filter_model: ActionFilter = Depends(make_dependable(ActionFilter)),
|
67
|
+
hydrate: bool = False,
|
68
|
+
_: AuthContext = Security(authorize),
|
69
|
+
) -> Page[ActionResponse]:
|
70
|
+
"""List actions.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
action_filter_model: Filter model used for pagination, sorting,
|
74
|
+
filtering.
|
75
|
+
hydrate: Flag deciding whether to hydrate the output model(s)
|
76
|
+
by including metadata fields in the response.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
Page of actions.
|
80
|
+
"""
|
81
|
+
|
82
|
+
def list_actions_fn(
|
83
|
+
filter_model: ActionFilter,
|
84
|
+
) -> Page[ActionResponse]:
|
85
|
+
"""List actions through their associated plugins.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
filter_model: Filter model used for pagination, sorting,
|
89
|
+
filtering.
|
90
|
+
|
91
|
+
Raises:
|
92
|
+
ValueError: If the action handler for flavor/type is not valid.
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
All actions.
|
96
|
+
"""
|
97
|
+
actions = zen_store().list_actions(
|
98
|
+
action_filter_model=filter_model, hydrate=hydrate
|
99
|
+
)
|
100
|
+
|
101
|
+
# Process the actions through their associated plugins
|
102
|
+
for idx, action in enumerate(actions.items):
|
103
|
+
action_handler = plugin_flavor_registry().get_plugin(
|
104
|
+
name=action.flavor,
|
105
|
+
_type=PluginType.ACTION,
|
106
|
+
subtype=action.plugin_subtype,
|
107
|
+
)
|
108
|
+
|
109
|
+
# Validate that the flavor and plugin_type correspond to an action
|
110
|
+
# handler implementation
|
111
|
+
if not isinstance(action_handler, BaseActionHandler):
|
112
|
+
raise ValueError(
|
113
|
+
f"Action handler plugin {action.plugin_subtype} "
|
114
|
+
f"for flavor {action.flavor} is not a valid action "
|
115
|
+
"handler plugin."
|
116
|
+
)
|
117
|
+
|
118
|
+
actions.items[idx] = action_handler.get_action(
|
119
|
+
action, hydrate=hydrate
|
120
|
+
)
|
121
|
+
|
122
|
+
return actions
|
123
|
+
|
124
|
+
return verify_permissions_and_list_entities(
|
125
|
+
filter_model=action_filter_model,
|
126
|
+
resource_type=ResourceType.ACTION,
|
127
|
+
list_method=list_actions_fn,
|
128
|
+
)
|
129
|
+
|
130
|
+
|
131
|
+
@router.get(
|
132
|
+
"/{action_id}",
|
133
|
+
response_model=ActionResponse,
|
134
|
+
responses={401: error_response, 404: error_response, 422: error_response},
|
135
|
+
)
|
136
|
+
@handle_exceptions
|
137
|
+
def get_action(
|
138
|
+
action_id: UUID,
|
139
|
+
hydrate: bool = True,
|
140
|
+
_: AuthContext = Security(authorize),
|
141
|
+
) -> ActionResponse:
|
142
|
+
"""Returns the requested action.
|
143
|
+
|
144
|
+
Args:
|
145
|
+
action_id: ID of the action.
|
146
|
+
hydrate: Flag deciding whether to hydrate the output model(s)
|
147
|
+
by including metadata fields in the response.
|
148
|
+
|
149
|
+
Raises:
|
150
|
+
ValueError: If the action handler for flavor/type is not valid.
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
The requested action.
|
154
|
+
"""
|
155
|
+
action = zen_store().get_action(action_id=action_id, hydrate=hydrate)
|
156
|
+
|
157
|
+
verify_permission_for_model(action, action=Action.READ)
|
158
|
+
|
159
|
+
action_handler = plugin_flavor_registry().get_plugin(
|
160
|
+
name=action.flavor,
|
161
|
+
_type=PluginType.ACTION,
|
162
|
+
subtype=action.plugin_subtype,
|
163
|
+
)
|
164
|
+
|
165
|
+
# Validate that the flavor and plugin_type correspond to an action
|
166
|
+
# handler implementation
|
167
|
+
if not isinstance(action_handler, BaseActionHandler):
|
168
|
+
raise ValueError(
|
169
|
+
f"Action handler plugin {action.plugin_subtype} "
|
170
|
+
f"for flavor {action.flavor} is not a valid action "
|
171
|
+
"handler plugin."
|
172
|
+
)
|
173
|
+
|
174
|
+
action = action_handler.get_action(action, hydrate=hydrate)
|
175
|
+
|
176
|
+
return dehydrate_response_model(action)
|
177
|
+
|
178
|
+
|
179
|
+
@router.post(
|
180
|
+
"",
|
181
|
+
response_model=ActionResponse,
|
182
|
+
responses={401: error_response, 409: error_response, 422: error_response},
|
183
|
+
)
|
184
|
+
@handle_exceptions
|
185
|
+
def create_action(
|
186
|
+
action: ActionRequest,
|
187
|
+
_: AuthContext = Security(authorize),
|
188
|
+
) -> ActionResponse:
|
189
|
+
"""Creates an action.
|
190
|
+
|
191
|
+
Args:
|
192
|
+
action: Action to create.
|
193
|
+
|
194
|
+
Raises:
|
195
|
+
ValueError: If the action handler for flavor/type is not valid.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
The created action.
|
199
|
+
"""
|
200
|
+
service_account = zen_store().get_service_account(
|
201
|
+
service_account_name_or_id=action.service_account_id
|
202
|
+
)
|
203
|
+
verify_permission_for_model(service_account, action=Action.READ)
|
204
|
+
|
205
|
+
action_handler = plugin_flavor_registry().get_plugin(
|
206
|
+
name=action.flavor,
|
207
|
+
_type=PluginType.ACTION,
|
208
|
+
subtype=action.plugin_subtype,
|
209
|
+
)
|
210
|
+
|
211
|
+
# Validate that the flavor and plugin_type correspond to an action
|
212
|
+
# handler implementation
|
213
|
+
if not isinstance(action_handler, BaseActionHandler):
|
214
|
+
raise ValueError(
|
215
|
+
f"Action handler plugin {action.plugin_subtype} "
|
216
|
+
f"for flavor {action.flavor} is not a valid action "
|
217
|
+
"handler plugin."
|
218
|
+
)
|
219
|
+
|
220
|
+
return verify_permissions_and_create_entity(
|
221
|
+
request_model=action,
|
222
|
+
resource_type=ResourceType.ACTION,
|
223
|
+
create_method=action_handler.create_action,
|
224
|
+
)
|
225
|
+
|
226
|
+
|
227
|
+
@router.put(
|
228
|
+
"/{action_id}",
|
229
|
+
response_model=ActionResponse,
|
230
|
+
responses={401: error_response, 404: error_response, 422: error_response},
|
231
|
+
)
|
232
|
+
@handle_exceptions
|
233
|
+
def update_action(
|
234
|
+
action_id: UUID,
|
235
|
+
action_update: ActionUpdate,
|
236
|
+
_: AuthContext = Security(authorize),
|
237
|
+
) -> ActionResponse:
|
238
|
+
"""Update an action.
|
239
|
+
|
240
|
+
Args:
|
241
|
+
action_id: ID of the action to update.
|
242
|
+
action_update: The action update.
|
243
|
+
|
244
|
+
Raises:
|
245
|
+
ValueError: If the action handler for flavor/type is not valid.
|
246
|
+
|
247
|
+
Returns:
|
248
|
+
The updated action.
|
249
|
+
"""
|
250
|
+
action = zen_store().get_action(action_id=action_id)
|
251
|
+
|
252
|
+
verify_permission_for_model(action, action=Action.UPDATE)
|
253
|
+
|
254
|
+
if action_update.service_account_id:
|
255
|
+
service_account = zen_store().get_service_account(
|
256
|
+
service_account_name_or_id=action_update.service_account_id
|
257
|
+
)
|
258
|
+
verify_permission_for_model(service_account, action=Action.READ)
|
259
|
+
|
260
|
+
action_handler = plugin_flavor_registry().get_plugin(
|
261
|
+
name=action.flavor,
|
262
|
+
_type=PluginType.ACTION,
|
263
|
+
subtype=action.plugin_subtype,
|
264
|
+
)
|
265
|
+
|
266
|
+
# Validate that the flavor and plugin_type correspond to an action
|
267
|
+
# handler implementation
|
268
|
+
if not isinstance(action_handler, BaseActionHandler):
|
269
|
+
raise ValueError(
|
270
|
+
f"Action handler plugin {action.plugin_subtype} "
|
271
|
+
f"for flavor {action.flavor} is not a valid action "
|
272
|
+
"handler plugin."
|
273
|
+
)
|
274
|
+
|
275
|
+
updated_action = action_handler.update_action(
|
276
|
+
action=action,
|
277
|
+
action_update=action_update,
|
278
|
+
)
|
279
|
+
|
280
|
+
return dehydrate_response_model(updated_action)
|
281
|
+
|
282
|
+
|
283
|
+
@router.delete(
|
284
|
+
"/{action_id}",
|
285
|
+
responses={401: error_response, 404: error_response, 422: error_response},
|
286
|
+
)
|
287
|
+
@handle_exceptions
|
288
|
+
def delete_action(
|
289
|
+
action_id: UUID,
|
290
|
+
force: bool = False,
|
291
|
+
_: AuthContext = Security(authorize),
|
292
|
+
) -> None:
|
293
|
+
"""Delete an action.
|
294
|
+
|
295
|
+
Args:
|
296
|
+
action_id: ID of the action.
|
297
|
+
force: Flag deciding whether to force delete the action.
|
298
|
+
|
299
|
+
Raises:
|
300
|
+
ValueError: If the action handler for flavor/type is not valid.
|
301
|
+
"""
|
302
|
+
action = zen_store().get_action(action_id=action_id)
|
303
|
+
|
304
|
+
verify_permission_for_model(action, action=Action.DELETE)
|
305
|
+
|
306
|
+
action_handler = plugin_flavor_registry().get_plugin(
|
307
|
+
name=action.flavor,
|
308
|
+
_type=PluginType.ACTION,
|
309
|
+
subtype=action.plugin_subtype,
|
310
|
+
)
|
311
|
+
|
312
|
+
# Validate that the flavor and plugin_type correspond to an action
|
313
|
+
# handler implementation
|
314
|
+
if not isinstance(action_handler, BaseActionHandler):
|
315
|
+
raise ValueError(
|
316
|
+
f"Action handler plugin {action.plugin_subtype} "
|
317
|
+
f"for flavor {action.flavor} is not a valid action "
|
318
|
+
"handler plugin."
|
319
|
+
)
|
320
|
+
|
321
|
+
action_handler.delete_action(
|
322
|
+
action=action,
|
323
|
+
force=force,
|
324
|
+
)
|