polyaxon 2.4.0rc1__py3-none-any.whl → 2.6.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.
- polyaxon/_auxiliaries/default_scheduling.py +17 -7
- polyaxon/_auxiliaries/init.py +14 -6
- polyaxon/_auxiliaries/sidecar.py +10 -8
- polyaxon/_cli/dashboard.py +2 -5
- polyaxon/_cli/run.py +14 -0
- polyaxon/_cli/version.py +4 -1
- polyaxon/_compiler/contexts/contexts.py +4 -0
- polyaxon/_compiler/resolver/agent.py +10 -9
- polyaxon/_compiler/resolver/runtime.py +4 -0
- polyaxon/_constants/metadata.py +1 -0
- polyaxon/_contexts/keys.py +1 -0
- polyaxon/_deploy/schemas/auth.py +3 -3
- polyaxon/_deploy/schemas/celery.py +10 -8
- polyaxon/_deploy/schemas/deployment.py +148 -116
- polyaxon/_deploy/schemas/email.py +8 -8
- polyaxon/_deploy/schemas/ingress.py +7 -7
- polyaxon/_deploy/schemas/intervals.py +3 -1
- polyaxon/_deploy/schemas/operators.py +8 -8
- polyaxon/_deploy/schemas/proxy.py +9 -9
- polyaxon/_deploy/schemas/rbac.py +1 -1
- polyaxon/_deploy/schemas/root_user.py +5 -5
- polyaxon/_deploy/schemas/security_context.py +25 -15
- polyaxon/_deploy/schemas/service.py +73 -69
- polyaxon/_deploy/schemas/ssl.py +3 -3
- polyaxon/_deploy/schemas/ui.py +10 -6
- polyaxon/_docker/builder/builder.py +4 -1
- polyaxon/_docker/converter/base/containers.py +4 -7
- polyaxon/_docker/converter/base/env_vars.py +5 -5
- polyaxon/_docker/converter/base/mounts.py +2 -2
- polyaxon/_docker/docker_types.py +57 -30
- polyaxon/_env_vars/keys.py +2 -0
- polyaxon/_flow/__init__.py +3 -2
- polyaxon/_flow/builds/__init__.py +8 -8
- polyaxon/_flow/cache/__init__.py +4 -4
- polyaxon/_flow/component/base.py +25 -18
- polyaxon/_flow/component/component.py +4 -3
- polyaxon/_flow/early_stopping/__init__.py +1 -1
- polyaxon/_flow/early_stopping/policies.py +12 -10
- polyaxon/_flow/environment/__init__.py +42 -24
- polyaxon/_flow/events/__init__.py +1 -1
- polyaxon/_flow/hooks/__init__.py +11 -11
- polyaxon/_flow/init/__init__.py +41 -25
- polyaxon/_flow/io/io.py +57 -47
- polyaxon/_flow/joins/__init__.py +5 -5
- polyaxon/_flow/matrix/bayes.py +23 -17
- polyaxon/_flow/matrix/grid_search.py +16 -7
- polyaxon/_flow/matrix/hyperband.py +10 -10
- polyaxon/_flow/matrix/hyperopt.py +14 -9
- polyaxon/_flow/matrix/iterative.py +14 -8
- polyaxon/_flow/matrix/mapping.py +4 -4
- polyaxon/_flow/matrix/params.py +138 -77
- polyaxon/_flow/matrix/random_search.py +10 -5
- polyaxon/_flow/matrix/tuner.py +4 -4
- polyaxon/_flow/mounts/artifacts_mounts.py +1 -1
- polyaxon/_flow/notifications/__init__.py +1 -1
- polyaxon/_flow/operations/base.py +10 -8
- polyaxon/_flow/operations/compiled_operation.py +5 -4
- polyaxon/_flow/operations/operation.py +30 -22
- polyaxon/_flow/optimization/__init__.py +2 -2
- polyaxon/_flow/params/params.py +10 -9
- polyaxon/_flow/plugins/__init__.py +19 -13
- polyaxon/_flow/run/dag.py +12 -9
- polyaxon/_flow/run/dask/dask.py +4 -4
- polyaxon/_flow/run/dask/replica.py +17 -11
- polyaxon/_flow/run/job.py +17 -11
- polyaxon/_flow/run/kubeflow/mpi_job.py +10 -5
- polyaxon/_flow/run/kubeflow/mx_job.py +25 -9
- polyaxon/_flow/run/kubeflow/paddle_job.py +16 -9
- polyaxon/_flow/run/kubeflow/pytorch_job.py +24 -17
- polyaxon/_flow/run/kubeflow/replica.py +17 -11
- polyaxon/_flow/run/kubeflow/scheduling_policy.py +7 -5
- polyaxon/_flow/run/kubeflow/tf_job.py +15 -8
- polyaxon/_flow/run/kubeflow/xgboost_job.py +9 -4
- polyaxon/_flow/run/ray/ray.py +9 -6
- polyaxon/_flow/run/ray/replica.py +25 -16
- polyaxon/_flow/run/resources.py +14 -13
- polyaxon/_flow/run/service.py +4 -4
- polyaxon/_flow/schedules/cron.py +4 -4
- polyaxon/_flow/schedules/interval.py +4 -4
- polyaxon/_flow/templates/__init__.py +3 -3
- polyaxon/_flow/termination/__init__.py +3 -3
- polyaxon/_fs/async_manager.py +1 -1
- polyaxon/_fs/watcher.py +26 -27
- polyaxon/_k8s/k8s_validation.py +1 -1
- polyaxon/_k8s/logging/async_monitor.py +18 -3
- polyaxon/_local_process/converter/base/containers.py +4 -7
- polyaxon/_local_process/converter/base/env_vars.py +5 -5
- polyaxon/_local_process/process_types.py +15 -12
- polyaxon/_polyaxonfile/specs/compiled_operation.py +1 -1
- polyaxon/_polyaxonfile/specs/libs/parser.py +1 -1
- polyaxon/_polyaxonfile/specs/libs/validator.py +1 -1
- polyaxon/_polyaxonfile/specs/operation.py +1 -1
- polyaxon/_polyaxonfile/specs/sections.py +8 -0
- polyaxon/_runner/agent/async_agent.py +9 -6
- polyaxon/_runner/agent/base_agent.py +8 -5
- polyaxon/_runner/agent/sync_agent.py +8 -5
- polyaxon/_runner/converter/converter.py +12 -4
- polyaxon/_schemas/agent.py +69 -37
- polyaxon/_schemas/authentication.py +4 -4
- polyaxon/_schemas/base.py +26 -2
- polyaxon/_schemas/checks.py +3 -3
- polyaxon/_schemas/cli.py +4 -6
- polyaxon/_schemas/client.py +20 -18
- polyaxon/_schemas/compatibility.py +4 -4
- polyaxon/_schemas/container_resources.py +1 -1
- polyaxon/_schemas/home.py +3 -3
- polyaxon/_schemas/installation.py +13 -9
- polyaxon/_schemas/lifecycle.py +23 -23
- polyaxon/_schemas/log_handler.py +2 -2
- polyaxon/_schemas/services.py +26 -14
- polyaxon/_schemas/types/artifacts.py +3 -3
- polyaxon/_schemas/types/dockerfile.py +14 -12
- polyaxon/_schemas/types/event.py +2 -2
- polyaxon/_schemas/types/file.py +3 -3
- polyaxon/_schemas/types/git.py +12 -4
- polyaxon/_schemas/types/tensorboard.py +14 -8
- polyaxon/_schemas/user.py +3 -3
- polyaxon/_schemas/version.py +2 -2
- polyaxon/_sdk/api/agents_v1_api.py +45 -45
- polyaxon/_sdk/api/artifacts_stores_v1_api.py +3 -3
- polyaxon/_sdk/api/auth_v1_api.py +13 -13
- polyaxon/_sdk/api/connections_v1_api.py +15 -15
- polyaxon/_sdk/api/dashboards_v1_api.py +15 -15
- polyaxon/_sdk/api/organizations_v1_api.py +77 -77
- polyaxon/_sdk/api/presets_v1_api.py +15 -15
- polyaxon/_sdk/api/project_dashboards_v1_api.py +17 -17
- polyaxon/_sdk/api/project_searches_v1_api.py +17 -17
- polyaxon/_sdk/api/projects_v1_api.py +65 -65
- polyaxon/_sdk/api/queues_v1_api.py +19 -19
- polyaxon/_sdk/api/runs_v1_api.py +127 -127
- polyaxon/_sdk/api/searches_v1_api.py +15 -15
- polyaxon/_sdk/api/service_accounts_v1_api.py +27 -27
- polyaxon/_sdk/api/tags_v1_api.py +17 -17
- polyaxon/_sdk/api/teams_v1_api.py +51 -51
- polyaxon/_sdk/api/users_v1_api.py +25 -25
- polyaxon/_sdk/api/versions_v1_api.py +7 -7
- polyaxon/_sdk/schemas/v1_activity.py +8 -8
- polyaxon/_sdk/schemas/v1_agent.py +17 -16
- polyaxon/_sdk/schemas/v1_agent_state_response.py +4 -4
- polyaxon/_sdk/schemas/v1_agent_state_response_agent_state.py +10 -10
- polyaxon/_sdk/schemas/v1_agent_status_body_request.py +3 -3
- polyaxon/_sdk/schemas/v1_analytics_spec.py +4 -4
- polyaxon/_sdk/schemas/v1_artifact_tree.py +3 -3
- polyaxon/_sdk/schemas/v1_auth.py +1 -1
- polyaxon/_sdk/schemas/v1_cloning.py +3 -3
- polyaxon/_sdk/schemas/v1_connection_response.py +9 -9
- polyaxon/_sdk/schemas/v1_dashboard.py +9 -9
- polyaxon/_sdk/schemas/v1_dashboard_spec.py +5 -5
- polyaxon/_sdk/schemas/v1_entities_tags.py +2 -2
- polyaxon/_sdk/schemas/v1_entities_transfer.py +2 -2
- polyaxon/_sdk/schemas/v1_entity_notification_body.py +7 -7
- polyaxon/_sdk/schemas/v1_entity_stage_body_request.py +5 -5
- polyaxon/_sdk/schemas/v1_entity_status_body_request.py +5 -5
- polyaxon/_sdk/schemas/v1_events_response.py +2 -2
- polyaxon/_sdk/schemas/v1_list_activities_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_agents_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_bookmarks_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_connections_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_dashboards_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_organization_members_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_organizations_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_presets_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_project_versions_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_projects_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_queues_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_run_artifacts_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_run_connections_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_run_edges_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_runs_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_searches_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_service_accounts_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_tags_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_team_members_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_teams_response.py +4 -4
- polyaxon/_sdk/schemas/v1_list_token_response.py +4 -4
- polyaxon/_sdk/schemas/v1_operation_body.py +8 -8
- polyaxon/_sdk/schemas/v1_organization.py +16 -16
- polyaxon/_sdk/schemas/v1_organization_member.py +6 -6
- polyaxon/_sdk/schemas/v1_password_change.py +3 -3
- polyaxon/_sdk/schemas/v1_pipeline.py +3 -3
- polyaxon/_sdk/schemas/v1_preset.py +11 -12
- polyaxon/_sdk/schemas/v1_project.py +17 -17
- polyaxon/_sdk/schemas/v1_project_settings.py +11 -11
- polyaxon/_sdk/schemas/v1_project_version.py +20 -20
- polyaxon/_sdk/schemas/v1_queue.py +12 -12
- polyaxon/_sdk/schemas/v1_run.py +38 -38
- polyaxon/_sdk/schemas/v1_run_connection.py +3 -3
- polyaxon/_sdk/schemas/v1_run_edge.py +5 -5
- polyaxon/_sdk/schemas/v1_run_edge_lineage.py +3 -3
- polyaxon/_sdk/schemas/v1_run_edges_graph.py +1 -1
- polyaxon/_sdk/schemas/v1_run_reference_catalog.py +4 -4
- polyaxon/_sdk/schemas/v1_run_settings.py +9 -9
- polyaxon/_sdk/schemas/v1_search.py +10 -10
- polyaxon/_sdk/schemas/v1_search_spec.py +14 -14
- polyaxon/_sdk/schemas/v1_section_spec.py +12 -12
- polyaxon/_sdk/schemas/v1_service_account.py +9 -9
- polyaxon/_sdk/schemas/v1_settings_catalog.py +4 -4
- polyaxon/_sdk/schemas/v1_tag.py +6 -6
- polyaxon/_sdk/schemas/v1_team.py +11 -11
- polyaxon/_sdk/schemas/v1_team_member.py +6 -6
- polyaxon/_sdk/schemas/v1_team_settings.py +2 -2
- polyaxon/_sdk/schemas/v1_token.py +10 -10
- polyaxon/_sdk/schemas/v1_trial_start.py +6 -6
- polyaxon/_sdk/schemas/v1_user.py +6 -6
- polyaxon/_sdk/schemas/v1_user_access.py +7 -7
- polyaxon/_sdk/schemas/v1_user_email.py +1 -1
- polyaxon/_sdk/schemas/v1_user_singup.py +5 -5
- polyaxon/_sdk/schemas/v1_uuids.py +1 -1
- polyaxon/_sidecar/container/__init__.py +13 -8
- polyaxon/_utils/cli_constants.py +2 -0
- polyaxon/_utils/test_utils.py +2 -1
- polyaxon/pkg.py +1 -1
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/METADATA +13 -13
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/RECORD +218 -218
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/WHEEL +1 -1
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/LICENSE +0 -0
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/entry_points.txt +0 -0
- {polyaxon-2.4.0rc1.dist-info → polyaxon-2.6.0.dist-info}/top_level.txt +0 -0
@@ -117,12 +117,17 @@ class V1XGBoostJob(BaseRun, DestinationImageMixin):
|
|
117
117
|
"""
|
118
118
|
|
119
119
|
_IDENTIFIER = V1RunKind.XGBJOB
|
120
|
+
_CUSTOM_DUMP_FIELDS = {"master", "worker"}
|
120
121
|
|
121
122
|
kind: Literal[_IDENTIFIER] = _IDENTIFIER
|
122
|
-
clean_pod_policy: Optional[V1CleanPodPolicy] = Field(
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
clean_pod_policy: Optional[V1CleanPodPolicy] = Field(
|
124
|
+
alias="cleanPodPolicy", default=None
|
125
|
+
)
|
126
|
+
scheduling_policy: Optional[V1SchedulingPolicy] = Field(
|
127
|
+
alias="schedulingPolicy", default=None
|
128
|
+
)
|
129
|
+
master: Optional[Union[V1KFReplica, RefField]] = None
|
130
|
+
worker: Optional[Union[V1KFReplica, RefField]] = None
|
126
131
|
|
127
132
|
def apply_image_destination(self, image: str):
|
128
133
|
if self.chief:
|
polyaxon/_flow/run/ray/ray.py
CHANGED
@@ -135,14 +135,17 @@ class V1RayJob(BaseRun, DestinationImageMixin):
|
|
135
135
|
"""
|
136
136
|
|
137
137
|
_IDENTIFIER = V1RunKind.RAYJOB
|
138
|
+
_CUSTOM_DUMP_FIELDS = {"head", "workers"}
|
138
139
|
|
139
140
|
kind: Literal[_IDENTIFIER] = _IDENTIFIER
|
140
|
-
entrypoint: Optional[str]
|
141
|
-
runtime_env: Optional[Union[Dict[str, Any], RefField]] = Field(
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
141
|
+
entrypoint: Optional[str] = None
|
142
|
+
runtime_env: Optional[Union[Dict[str, Any], RefField]] = Field(
|
143
|
+
alias="runtimeEnv", default=None
|
144
|
+
)
|
145
|
+
metadata: Optional[Union[Dict[str, str], RefField]] = Field(default=None)
|
146
|
+
ray_version: Optional[str] = Field(alias="rayVersion", default=None)
|
147
|
+
head: Optional[Union[V1RayReplica, RefField]] = None
|
148
|
+
workers: Optional[Dict[str, Union[V1RayReplica, RefField]]] = Field(default=None)
|
146
149
|
|
147
150
|
def apply_image_destination(self, image: str):
|
148
151
|
if self.head:
|
@@ -1,6 +1,12 @@
|
|
1
1
|
from typing import Dict, List, Optional, Union
|
2
2
|
|
3
|
-
from clipped.compact.pydantic import
|
3
|
+
from clipped.compact.pydantic import (
|
4
|
+
Field,
|
5
|
+
StrictStr,
|
6
|
+
field_validator,
|
7
|
+
validation_always,
|
8
|
+
validation_before,
|
9
|
+
)
|
4
10
|
from clipped.types.ref_or_obj import IntOrRef, RefField
|
5
11
|
|
6
12
|
from polyaxon._flow.environment import V1Environment
|
@@ -210,31 +216,34 @@ class V1RayReplica(BaseSchemaModel):
|
|
210
216
|
|
211
217
|
_IDENTIFIER = "replica"
|
212
218
|
_SWAGGER_FIELDS = ["volumes", "sidecars", "container"]
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
219
|
+
_CUSTOM_DUMP_FIELDS = {"environment"}
|
220
|
+
|
221
|
+
replicas: Optional[IntOrRef] = None
|
222
|
+
min_replicas: Optional[IntOrRef] = Field(alias="minReplicas", default=None)
|
223
|
+
max_replicas: Optional[IntOrRef] = Field(alias="maxReplicas", default=None)
|
224
|
+
ray_start_params: Optional[Dict[str, str]] = Field(
|
225
|
+
alias="rayStartParams", default=None
|
226
|
+
)
|
227
|
+
environment: Optional[Union[V1Environment, RefField]] = None
|
228
|
+
connections: Optional[Union[List[StrictStr], RefField]] = None
|
229
|
+
volumes: Optional[Union[List[k8s_schemas.V1Volume], RefField]] = None
|
230
|
+
init: Optional[Union[List[V1Init], RefField]] = None
|
231
|
+
sidecars: Optional[Union[List[k8s_schemas.V1Container], RefField]] = None
|
232
|
+
container: Optional[Union[k8s_schemas.V1Container, RefField]] = None
|
233
|
+
|
234
|
+
@field_validator("volumes", **validation_always, **validation_before)
|
226
235
|
def validate_volumes(cls, v):
|
227
236
|
if not v:
|
228
237
|
return v
|
229
238
|
return [k8s_validation.validate_k8s_volume(vi) for vi in v]
|
230
239
|
|
231
|
-
@
|
240
|
+
@field_validator("sidecars", **validation_always, **validation_before)
|
232
241
|
def validate_helper_containers(cls, v):
|
233
242
|
if not v:
|
234
243
|
return v
|
235
244
|
return [k8s_validation.validate_k8s_container(vi) for vi in v]
|
236
245
|
|
237
|
-
@
|
246
|
+
@field_validator("container", **validation_always, **validation_before)
|
238
247
|
def validate_container(cls, v):
|
239
248
|
return k8s_validation.validate_k8s_container(v)
|
240
249
|
|
polyaxon/_flow/run/resources.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional, Union
|
1
|
+
from typing import ClassVar, Optional, Set, Union
|
2
2
|
|
3
3
|
from clipped.compact.pydantic import StrictStr
|
4
4
|
from clipped.types.numbers import StrictIntOrFloat
|
@@ -9,18 +9,19 @@ from polyaxon._schemas.base import BaseSchemaModel
|
|
9
9
|
|
10
10
|
|
11
11
|
class V1RunResources(BaseSchemaModel):
|
12
|
-
cpu: Optional[Union[StrictIntOrFloat, StrictStr]]
|
13
|
-
memory: Optional[Union[StrictIntOrFloat, StrictStr]]
|
14
|
-
gpu: Optional[Union[StrictIntOrFloat, StrictStr]]
|
15
|
-
custom: Optional[Union[StrictIntOrFloat, StrictStr]]
|
16
|
-
cost: Optional[Union[StrictIntOrFloat, StrictStr]]
|
17
|
-
|
18
|
-
_MEMORY = "memory"
|
19
|
-
_CPU = "cpu"
|
20
|
-
_GPU = "gpu"
|
21
|
-
_CUSTOM_RESOURCE = "custom"
|
22
|
-
_COST = "cost"
|
23
|
-
|
12
|
+
cpu: Optional[Union[StrictIntOrFloat, StrictStr]] = None
|
13
|
+
memory: Optional[Union[StrictIntOrFloat, StrictStr]] = None
|
14
|
+
gpu: Optional[Union[StrictIntOrFloat, StrictStr]] = None
|
15
|
+
custom: Optional[Union[StrictIntOrFloat, StrictStr]] = None
|
16
|
+
cost: Optional[Union[StrictIntOrFloat, StrictStr]] = None
|
17
|
+
|
18
|
+
_MEMORY: ClassVar[str] = "memory"
|
19
|
+
_CPU: ClassVar[str] = "cpu"
|
20
|
+
_GPU: ClassVar[str] = "gpu"
|
21
|
+
_CUSTOM_RESOURCE: ClassVar[str] = "custom"
|
22
|
+
_COST: ClassVar[str] = "cost"
|
23
|
+
|
24
|
+
_VALUES: ClassVar[Set[str]] = {_MEMORY, _CPU, _GPU, _CUSTOM_RESOURCE, _COST}
|
24
25
|
|
25
26
|
@classmethod
|
26
27
|
def validate_memory(cls, value):
|
polyaxon/_flow/run/service.py
CHANGED
@@ -272,7 +272,7 @@ class V1Service(V1Job):
|
|
272
272
|
_IDENTIFIER = V1RunKind.SERVICE
|
273
273
|
|
274
274
|
kind: Literal[_IDENTIFIER] = _IDENTIFIER
|
275
|
-
ports: Optional[Union[List[StrictInt], RefField]]
|
276
|
-
rewrite_path: Optional[BoolOrRef] = Field(alias="rewritePath")
|
277
|
-
is_external: Optional[BoolOrRef] = Field(alias="isExternal")
|
278
|
-
replicas: Optional[IntOrRef]
|
275
|
+
ports: Optional[Union[List[StrictInt], RefField]] = None
|
276
|
+
rewrite_path: Optional[BoolOrRef] = Field(alias="rewritePath", default=None)
|
277
|
+
is_external: Optional[BoolOrRef] = Field(alias="isExternal", default=None)
|
278
|
+
replicas: Optional[IntOrRef] = None
|
polyaxon/_flow/schedules/cron.py
CHANGED
@@ -114,7 +114,7 @@ class V1CronSchedule(BaseSchemaModel):
|
|
114
114
|
|
115
115
|
kind: Literal[_IDENTIFIER] = _IDENTIFIER
|
116
116
|
cron: StrictStr
|
117
|
-
start_at: Optional[DatetimeOrRef] = Field(alias="startAt")
|
118
|
-
end_at: Optional[DatetimeOrRef] = Field(alias="endAt")
|
119
|
-
max_runs: Optional[IntOrRef] = Field(alias="maxRuns")
|
120
|
-
depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast")
|
117
|
+
start_at: Optional[DatetimeOrRef] = Field(alias="startAt", default=None)
|
118
|
+
end_at: Optional[DatetimeOrRef] = Field(alias="endAt", default=None)
|
119
|
+
max_runs: Optional[IntOrRef] = Field(alias="maxRuns", default=None)
|
120
|
+
depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast", default=None)
|
@@ -117,8 +117,8 @@ class V1IntervalSchedule(BaseSchemaModel):
|
|
117
117
|
_USE_DISCRIMINATOR = True
|
118
118
|
|
119
119
|
kind: Literal[_IDENTIFIER] = _IDENTIFIER
|
120
|
-
start_at: Optional[DatetimeOrRef] = Field(alias="startAt")
|
121
|
-
end_at: Optional[DatetimeOrRef] = Field(alias="endAt")
|
122
|
-
max_runs: Optional[IntOrRef] = Field(alias="maxRuns")
|
120
|
+
start_at: Optional[DatetimeOrRef] = Field(alias="startAt", default=None)
|
121
|
+
end_at: Optional[DatetimeOrRef] = Field(alias="endAt", default=None)
|
122
|
+
max_runs: Optional[IntOrRef] = Field(alias="maxRuns", default=None)
|
123
123
|
frequency: TimeDeltaOrRef
|
124
|
-
depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast")
|
124
|
+
depends_on_past: Optional[BoolOrRef] = Field(alias="dependsOnPast", default=None)
|
@@ -80,9 +80,9 @@ class V1Template(BaseSchemaModel):
|
|
80
80
|
|
81
81
|
_IDENTIFIER = "template"
|
82
82
|
|
83
|
-
enabled: Optional[BoolOrRef]
|
84
|
-
description: Optional[StrictStr]
|
85
|
-
fields: Optional[Union[List[StrictStr], RefField]]
|
83
|
+
enabled: Optional[BoolOrRef] = None
|
84
|
+
description: Optional[StrictStr] = None
|
85
|
+
fields: Optional[Union[List[StrictStr], RefField]] = None
|
86
86
|
|
87
87
|
|
88
88
|
class TemplateMixinConfig:
|
@@ -99,6 +99,6 @@ class V1Termination(BaseSchemaModel):
|
|
99
99
|
|
100
100
|
_IDENTIFIER = "termination"
|
101
101
|
|
102
|
-
max_retries: Optional[IntOrRef] = Field(alias="maxRetries")
|
103
|
-
ttl: Optional[IntOrRef]
|
104
|
-
timeout: Optional[IntOrRef]
|
102
|
+
max_retries: Optional[IntOrRef] = Field(alias="maxRetries", default=None)
|
103
|
+
ttl: Optional[IntOrRef] = None
|
104
|
+
timeout: Optional[IntOrRef] = None
|
polyaxon/_fs/async_manager.py
CHANGED
@@ -314,7 +314,7 @@ async def list_files(
|
|
314
314
|
|
315
315
|
|
316
316
|
async def delete_file_or_dir(
|
317
|
-
fs: FSSystem, store_path: str, subpath:
|
317
|
+
fs: FSSystem, store_path: str, subpath: Optional[str], is_file: bool
|
318
318
|
) -> bool:
|
319
319
|
try:
|
320
320
|
await ensure_async_execution(
|
polyaxon/_fs/watcher.py
CHANGED
@@ -3,36 +3,43 @@ import os
|
|
3
3
|
from datetime import datetime
|
4
4
|
from typing import Dict, List, Optional, Set, Tuple
|
5
5
|
|
6
|
+
from clipped.compact.pydantic import PYDANTIC_VERSION
|
6
7
|
from clipped.utils.dates import path_last_modified
|
7
8
|
from clipped.utils.paths import get_files_and_dirs_in_path
|
8
9
|
|
9
10
|
from polyaxon._contexts import paths as ctx_paths
|
10
|
-
from polyaxon._schemas.base import BaseSchemaModel
|
11
|
+
from polyaxon._schemas.base import BaseSchemaModel, RootModel
|
11
12
|
|
12
13
|
|
13
|
-
class PathData(
|
14
|
-
|
14
|
+
class PathData(RootModel):
|
15
|
+
if PYDANTIC_VERSION.startswith("2."):
|
16
|
+
root: Tuple[str, datetime, str]
|
17
|
+
else:
|
18
|
+
__root__: Tuple[str, datetime, str]
|
15
19
|
|
16
|
-
class Config
|
20
|
+
class Config:
|
17
21
|
validate_assignment = False
|
18
22
|
|
19
23
|
@property
|
20
24
|
def base(self) -> str:
|
21
|
-
return self.
|
25
|
+
return self.get_root()[0]
|
22
26
|
|
23
27
|
@property
|
24
28
|
def ts(self) -> datetime:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
root = self.get_root()
|
30
|
+
if isinstance(root[1], str):
|
31
|
+
self.set_root(
|
32
|
+
(
|
33
|
+
root[0],
|
34
|
+
datetime.fromisoformat(root[1]),
|
35
|
+
root[1],
|
36
|
+
)
|
30
37
|
)
|
31
|
-
return
|
38
|
+
return root[1]
|
32
39
|
|
33
40
|
@property
|
34
41
|
def op(self) -> str:
|
35
|
-
return self.
|
42
|
+
return self.get_root()[2]
|
36
43
|
|
37
44
|
|
38
45
|
class FSWatcher(BaseSchemaModel):
|
@@ -42,8 +49,8 @@ class FSWatcher(BaseSchemaModel):
|
|
42
49
|
_RM = "rm"
|
43
50
|
_NOOP = ""
|
44
51
|
|
45
|
-
dir_mapping: Optional[Dict[str, PathData]]
|
46
|
-
file_mapping: Optional[Dict[str, PathData]]
|
52
|
+
dir_mapping: Optional[Dict[str, PathData]] = None
|
53
|
+
file_mapping: Optional[Dict[str, PathData]] = None
|
47
54
|
|
48
55
|
@property
|
49
56
|
def dirs_mp(self) -> Dict[str, PathData]:
|
@@ -71,17 +78,11 @@ class FSWatcher(BaseSchemaModel):
|
|
71
78
|
data = mapping.get(rel_path)
|
72
79
|
if data:
|
73
80
|
if current_ts > data.ts:
|
74
|
-
mapping[rel_path] = PathData.
|
75
|
-
__root__=(base_path, current_ts, self._PUT)
|
76
|
-
)
|
81
|
+
mapping[rel_path] = PathData.make((base_path, current_ts, self._PUT))
|
77
82
|
else:
|
78
|
-
mapping[rel_path] = PathData.
|
79
|
-
__root__=(base_path, data.ts, self._NOOP)
|
80
|
-
)
|
83
|
+
mapping[rel_path] = PathData.make((base_path, data.ts, self._NOOP))
|
81
84
|
else:
|
82
|
-
mapping[rel_path] = PathData.
|
83
|
-
__root__=(base_path, current_ts, self._PUT)
|
84
|
-
)
|
85
|
+
mapping[rel_path] = PathData.make((base_path, current_ts, self._PUT))
|
85
86
|
return mapping
|
86
87
|
|
87
88
|
def sync_file(self, path: str, base_path: str):
|
@@ -92,12 +93,10 @@ class FSWatcher(BaseSchemaModel):
|
|
92
93
|
|
93
94
|
def init(self):
|
94
95
|
self.dir_mapping = {
|
95
|
-
p: PathData.
|
96
|
-
for p, d in self.dirs_mp.items()
|
96
|
+
p: PathData.make((d.base, d.ts, self._RM)) for p, d in self.dirs_mp.items()
|
97
97
|
}
|
98
98
|
self.file_mapping = {
|
99
|
-
p: PathData.
|
100
|
-
for p, d in self.files_mp.items()
|
99
|
+
p: PathData.make((d.base, d.ts, self._RM)) for p, d in self.files_mp.items()
|
101
100
|
}
|
102
101
|
|
103
102
|
def sync(self, path: str, exclude: Optional[List[str]] = None):
|
polyaxon/_k8s/k8s_validation.py
CHANGED
@@ -14,7 +14,7 @@ def _validate_schema(value: Optional[Union[Swagger, Dict]], cls: Type[Swagger]):
|
|
14
14
|
return cls(**{to_snake_case(k): value[k] for k in value})
|
15
15
|
if isinstance(value, cls):
|
16
16
|
return value
|
17
|
-
raise
|
17
|
+
raise ValueError(
|
18
18
|
"This field expects a dict or an instance of {}.".format(cls.__name__)
|
19
19
|
)
|
20
20
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import datetime
|
2
|
+
import logging
|
2
3
|
|
3
4
|
from typing import List, Optional, Tuple
|
4
5
|
|
@@ -10,6 +11,8 @@ from polyaxon._flow import V1RunKind
|
|
10
11
|
from polyaxon._k8s.manager.async_manager import AsyncK8sManager
|
11
12
|
from traceml.logging import V1Log, V1Logs
|
12
13
|
|
14
|
+
_logger = logging.getLogger("haupt.k8s.logs")
|
15
|
+
|
13
16
|
|
14
17
|
async def handle_container_logs(
|
15
18
|
k8s_manager: AsyncK8sManager, pod: V1Pod, container_name: str, **params
|
@@ -23,8 +26,20 @@ async def handle_container_logs(
|
|
23
26
|
timestamps=True,
|
24
27
|
**params,
|
25
28
|
)
|
26
|
-
except ApiException:
|
27
|
-
|
29
|
+
except ApiException as e:
|
30
|
+
_logger.warning(
|
31
|
+
"Error collecting logs for %s - container %s: %s",
|
32
|
+
pod.metadata.name,
|
33
|
+
container_name,
|
34
|
+
e,
|
35
|
+
)
|
36
|
+
except Exception as e:
|
37
|
+
_logger.warning(
|
38
|
+
"Unexpected error collecting logs for %s - container %s: %s",
|
39
|
+
pod.metadata.name,
|
40
|
+
container_name,
|
41
|
+
e,
|
42
|
+
)
|
28
43
|
if not resp:
|
29
44
|
return []
|
30
45
|
|
@@ -108,7 +123,7 @@ async def collect_agent_service_logs(
|
|
108
123
|
async def query_k8s_pod_logs(
|
109
124
|
k8s_manager: AsyncK8sManager,
|
110
125
|
pod: V1Pod,
|
111
|
-
last_time: Optional[datetime.datetime],
|
126
|
+
last_time: Optional[datetime.datetime] = None,
|
112
127
|
stream: bool = False,
|
113
128
|
) -> Tuple[List[V1Log], Optional[datetime.datetime]]:
|
114
129
|
new_time = now()
|
@@ -36,11 +36,8 @@ class ContainerMixin(BaseConverter):
|
|
36
36
|
env: List[process_types.V1EnvVar],
|
37
37
|
) -> List[process_types.V1EnvVar]:
|
38
38
|
def sanitize_env_dict(d: Dict):
|
39
|
-
return process_types.V1EnvVar(
|
40
|
-
|
41
|
-
d_k: sanitize_value(d_v, handle_dict=False)
|
42
|
-
for d_k, d_v in d.items()
|
43
|
-
}
|
39
|
+
return process_types.V1EnvVar.make(
|
40
|
+
{d_k: sanitize_value(d_v, handle_dict=False) for d_k, d_v in d.items()}
|
44
41
|
)
|
45
42
|
|
46
43
|
results = []
|
@@ -50,8 +47,8 @@ class ContainerMixin(BaseConverter):
|
|
50
47
|
results.append(e)
|
51
48
|
elif isinstance(e, tuple):
|
52
49
|
if e[1] is not None:
|
53
|
-
e = process_types.V1EnvVar(
|
54
|
-
|
50
|
+
e = process_types.V1EnvVar.make(
|
51
|
+
(e[0], sanitize_value(e[1], handle_dict=False))
|
55
52
|
)
|
56
53
|
results.append(e)
|
57
54
|
elif isinstance(e, process_types.V1EnvVar):
|
@@ -42,7 +42,7 @@ class EnvMixin(BaseConverter):
|
|
42
42
|
except (ValueError, TypeError) as e:
|
43
43
|
raise PolyaxonConverterError(e)
|
44
44
|
|
45
|
-
return process_types.V1EnvVar(
|
45
|
+
return process_types.V1EnvVar.make((name, value))
|
46
46
|
|
47
47
|
@staticmethod
|
48
48
|
def _get_from_json_resource(
|
@@ -59,7 +59,7 @@ class EnvMixin(BaseConverter):
|
|
59
59
|
except Exception as e:
|
60
60
|
raise PolyaxonConverterError from e
|
61
61
|
|
62
|
-
return [process_types.V1EnvVar(
|
62
|
+
return [process_types.V1EnvVar.make(k) for k in (secret_value.items())]
|
63
63
|
|
64
64
|
@classmethod
|
65
65
|
def _get_env_from_json_resources(
|
@@ -82,10 +82,10 @@ class EnvMixin(BaseConverter):
|
|
82
82
|
try:
|
83
83
|
secret_value = orjson_loads(secret)
|
84
84
|
except orjson.JSONDecodeError:
|
85
|
-
return process_types.V1EnvVar(
|
85
|
+
return process_types.V1EnvVar.make((key, secret))
|
86
86
|
|
87
87
|
value = secret_value.get(key)
|
88
|
-
return process_types.V1EnvVar(
|
88
|
+
return process_types.V1EnvVar.make((key, value))
|
89
89
|
|
90
90
|
@classmethod
|
91
91
|
def _get_items_from_json_resource(
|
@@ -104,7 +104,7 @@ class EnvMixin(BaseConverter):
|
|
104
104
|
for item in resource.items:
|
105
105
|
value = secret_value.get(item)
|
106
106
|
if value:
|
107
|
-
items_from.append(process_types.V1EnvVar(
|
107
|
+
items_from.append(process_types.V1EnvVar.make((item, value)))
|
108
108
|
return items_from
|
109
109
|
|
110
110
|
@classmethod
|
@@ -1,27 +1,30 @@
|
|
1
1
|
from typing import Dict, List, Optional, Tuple, Union
|
2
2
|
|
3
|
-
from clipped.compact.pydantic import Field
|
3
|
+
from clipped.compact.pydantic import PYDANTIC_VERSION, Field
|
4
4
|
|
5
|
-
from polyaxon._schemas.base import BaseSchemaModel
|
5
|
+
from polyaxon._schemas.base import BaseSchemaModel, RootModel
|
6
6
|
|
7
7
|
|
8
|
-
class V1EnvVar(
|
9
|
-
|
8
|
+
class V1EnvVar(RootModel):
|
9
|
+
if PYDANTIC_VERSION.startswith("2."):
|
10
|
+
root: Union[Tuple[str, str], Dict[str, str]]
|
11
|
+
else:
|
12
|
+
__root__: Union[Tuple[str, str], Dict[str, str]]
|
10
13
|
|
11
14
|
def to_cmd(self):
|
12
|
-
if isinstance(self.
|
13
|
-
value = self.
|
15
|
+
if isinstance(self._root, tuple):
|
16
|
+
value = self._root
|
14
17
|
else:
|
15
|
-
value = self.
|
18
|
+
value = self._root.items()
|
16
19
|
return [f"{value[0]}={value[1]}"]
|
17
20
|
|
18
21
|
|
19
22
|
class V1Container(BaseSchemaModel):
|
20
|
-
name: Optional[str]
|
21
|
-
command: Optional[List[str]]
|
22
|
-
args: Optional[List[str]]
|
23
|
-
env: Optional[List[V1EnvVar]]
|
24
|
-
working_dir: Optional[str] = Field(alias="workingDir")
|
23
|
+
name: Optional[str] = None
|
24
|
+
command: Optional[List[str]] = None
|
25
|
+
args: Optional[List[str]] = None
|
26
|
+
env: Optional[List[V1EnvVar]] = None
|
27
|
+
working_dir: Optional[str] = Field(alias="workingDir", default=None)
|
25
28
|
|
26
29
|
def get_cmd_args(self):
|
27
30
|
cmd_args = ["run", "--rm"]
|
@@ -348,7 +348,7 @@ class CompiledOperationSpecification(BaseSpecification):
|
|
348
348
|
"conditions",
|
349
349
|
"skip_on_upstream_skip",
|
350
350
|
}
|
351
|
-
patch_keys = patch_keys.intersection(preset.
|
351
|
+
patch_keys = patch_keys.intersection(preset.model_fields_set)
|
352
352
|
patch_data = {k: getattr(preset, k) for k in patch_keys}
|
353
353
|
patch_compiled = V1CompiledOperation.construct(**patch_data)
|
354
354
|
return config.patch(patch_compiled, strategy=preset.patch_strategy)
|
@@ -93,7 +93,7 @@ class PolyaxonfileParser:
|
|
93
93
|
# Check workflow
|
94
94
|
for section in Sections.PARSING_SECTIONS:
|
95
95
|
config_section = cls._get_section(config, section)
|
96
|
-
if config_section:
|
96
|
+
if config_section is not None:
|
97
97
|
parsed_data[section] = cls.parse_expression(
|
98
98
|
config_section, parsed_params
|
99
99
|
)
|
@@ -11,7 +11,7 @@ def validate(spec, data):
|
|
11
11
|
|
12
12
|
def validate_keys(section, config, section_data):
|
13
13
|
extra_args = [
|
14
|
-
key for key in section_data.keys() if key not in config.
|
14
|
+
key for key in section_data.keys() if key not in config.model_fields.keys()
|
15
15
|
]
|
16
16
|
if extra_args:
|
17
17
|
raise PolyaxonfileError(
|
@@ -107,7 +107,7 @@ class OperationSpecification(BaseSpecification):
|
|
107
107
|
"conditions",
|
108
108
|
"skip_on_upstream_skip",
|
109
109
|
}
|
110
|
-
patch_keys = patch_keys.intersection(config.
|
110
|
+
patch_keys = patch_keys.intersection(config.model_fields_set)
|
111
111
|
patch_data = {k: getattr(config, k) for k in patch_keys}
|
112
112
|
patch_compiled = V1CompiledOperation.construct(contexts=contexts, **patch_data)
|
113
113
|
|
@@ -99,6 +99,14 @@ class Sections:
|
|
99
99
|
CONDITIONS,
|
100
100
|
SKIP_ON_UPSTREAM_SKIP,
|
101
101
|
PATCH_STRATEGY,
|
102
|
+
"is_approved",
|
103
|
+
"patch_strategy",
|
104
|
+
"is_preset",
|
105
|
+
"hub_ref",
|
106
|
+
"dag_ref",
|
107
|
+
"path_ref",
|
108
|
+
"url_ref",
|
109
|
+
"skip_on_upstream_skip",
|
102
110
|
)
|
103
111
|
|
104
112
|
REQUIRED_SECTIONS = (VERSION, KIND)
|
@@ -24,10 +24,10 @@ class BaseAsyncAgent(BaseAgent):
|
|
24
24
|
IS_ASYNC = True
|
25
25
|
|
26
26
|
async def _enter(self):
|
27
|
-
if not self.client._is_managed:
|
28
|
-
return self
|
29
27
|
logger.warning("Agent is starting.")
|
30
28
|
await self.executor.refresh()
|
29
|
+
if not self.client._is_managed:
|
30
|
+
return self
|
31
31
|
try:
|
32
32
|
agent = await self.client.get_info()
|
33
33
|
self._check_status(agent)
|
@@ -81,13 +81,16 @@ class BaseAsyncAgent(BaseAgent):
|
|
81
81
|
|
82
82
|
async def reconcile(self):
|
83
83
|
if (
|
84
|
-
now() - self.
|
84
|
+
now() - self._last_data_collected_at
|
85
85
|
).total_seconds() > self.SLEEP_AGENT_DATA_COLLECT_TIME:
|
86
|
+
await self.collect_agent_data()
|
87
|
+
if (
|
88
|
+
now() - self._last_reconciled_at
|
89
|
+
).total_seconds() < self.SLEEP_AGENT_DATA_RECONCILE_TIME:
|
86
90
|
return
|
87
91
|
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
logger.info("Checking cluster state.")
|
93
|
+
self._last_reconciled_at = now()
|
91
94
|
# Update reconcile
|
92
95
|
namespaces = [settings.AGENT_CONFIG.namespace]
|
93
96
|
namespaces += settings.AGENT_CONFIG.additional_namespaces or []
|
@@ -4,7 +4,7 @@ import traceback
|
|
4
4
|
from concurrent.futures import ThreadPoolExecutor
|
5
5
|
from typing import Any, Dict, Optional, Tuple, Type
|
6
6
|
|
7
|
-
from clipped.utils.tz import now
|
7
|
+
from clipped.utils.tz import get_datetime_from_now, now
|
8
8
|
|
9
9
|
from polyaxon import settings
|
10
10
|
from polyaxon._auxiliaries import V1PolyaxonInitContainer, V1PolyaxonSidecarContainer
|
@@ -24,7 +24,8 @@ class BaseAgent:
|
|
24
24
|
HEALTH_FILE = "/tmp/.healthz"
|
25
25
|
SLEEP_STOP_TIME = 60 * 5
|
26
26
|
SLEEP_ARCHIVED_TIME = 60 * 60
|
27
|
-
SLEEP_AGENT_DATA_COLLECT_TIME = 60 *
|
27
|
+
SLEEP_AGENT_DATA_COLLECT_TIME = 60 * 15
|
28
|
+
SLEEP_AGENT_DATA_RECONCILE_TIME = 60 * 5
|
28
29
|
IS_ASYNC = False
|
29
30
|
|
30
31
|
def __init__(
|
@@ -38,11 +39,13 @@ class BaseAgent:
|
|
38
39
|
self.max_interval = max(max_interval, 3)
|
39
40
|
if not agent_uuid and not owner:
|
40
41
|
owner = DEFAULT
|
42
|
+
last_hour = get_datetime_from_now(days=0, hours=1)
|
41
43
|
self.executor = None
|
42
44
|
self._default_auth = bool(agent_uuid)
|
43
|
-
self._executor_refreshed_at =
|
45
|
+
self._executor_refreshed_at = last_hour
|
44
46
|
self._graceful_shutdown = False
|
45
|
-
self.
|
47
|
+
self._last_data_collected_at = last_hour
|
48
|
+
self._last_reconciled_at = last_hour
|
46
49
|
self.client = AgentClient(
|
47
50
|
owner=owner, agent_uuid=agent_uuid, is_async=self.IS_ASYNC
|
48
51
|
)
|
@@ -60,7 +63,7 @@ class BaseAgent:
|
|
60
63
|
|
61
64
|
def collect_agent_data(self):
|
62
65
|
logger.info("Collecting agent data.")
|
63
|
-
self.
|
66
|
+
self._last_data_collected_at = now()
|
64
67
|
try:
|
65
68
|
return self.client.collect_agent_data(
|
66
69
|
namespace=settings.CLIENT_CONFIG.namespace
|