pipekit-sdk 2.0.0__tar.gz → 2.1.0__tar.gz
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.
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/PKG-INFO +3 -1
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/pyproject.toml +2 -1
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/__init__.py +3 -3
- pipekit_sdk-2.1.0/src/pipekit_sdk/models/_config.py +9 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/model.py +7 -8
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/v1.py +4 -5
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/v1alpha1.py +21 -21
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/service.py +121 -13
- pipekit_sdk-2.0.0/src/pipekit_sdk/models/_config.py +0 -15
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/LICENSE +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/README.md +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/__init__.py +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/_helpers.py +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/big.py +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/inf.py +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/intstr.py +0 -0
- {pipekit_sdk-2.0.0 → pipekit_sdk-2.1.0}/src/pipekit_sdk/models/resource.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pipekit-sdk
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Pipekit Python SDK
|
|
5
5
|
Home-page: https://pipekit.io
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -16,8 +16,10 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
20
|
Requires-Dist: hera (>=5.5.2)
|
|
20
21
|
Requires-Dist: pydantic (<3)
|
|
22
|
+
Requires-Dist: pyjwt (>=2.9.0,<3.0.0)
|
|
21
23
|
Requires-Dist: responses (>=0.25.3,<0.26.0)
|
|
22
24
|
Project-URL: Documentation, https://docs.pipekit.io/
|
|
23
25
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pipekit-sdk"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.1.0"
|
|
4
4
|
description = "Pipekit Python SDK"
|
|
5
5
|
authors = ["Pipekit <ci@pipekit.io>"]
|
|
6
6
|
license = "BSD-3-Clause"
|
|
@@ -27,6 +27,7 @@ python = ">=3.8,<4"
|
|
|
27
27
|
hera = ">=5.5.2"
|
|
28
28
|
pydantic = "<3"
|
|
29
29
|
responses = "^0.25.3"
|
|
30
|
+
pyjwt = "^2.9.0"
|
|
30
31
|
|
|
31
32
|
[tool.poetry.group.dev.dependencies]
|
|
32
33
|
ruff = "*"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from pydantic import BaseModel as PydanticBaseModel
|
|
2
|
+
from pydantic import ConfigDict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseModel(PydanticBaseModel):
|
|
6
|
+
model_config = ConfigDict(
|
|
7
|
+
populate_by_name=True, # support populating object by Field alias
|
|
8
|
+
use_enum_values=True, # supports using enums, which are then unpacked to obtain the actual `.value`
|
|
9
|
+
)
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from datetime import datetime
|
|
6
5
|
from typing import Dict, List, Optional
|
|
7
6
|
|
|
8
|
-
from pydantic import Field
|
|
7
|
+
from pydantic import AwareDatetime, Field
|
|
9
8
|
from typing_extensions import Annotated
|
|
10
9
|
|
|
11
10
|
from pipekit_sdk.models._config import BaseModel
|
|
@@ -13,7 +12,7 @@ from pipekit_sdk.models._config import BaseModel
|
|
|
13
12
|
|
|
14
13
|
class Cluster(BaseModel):
|
|
15
14
|
api_key: Annotated[Optional[str], Field(alias="apiKey")] = None
|
|
16
|
-
created_at: Annotated[
|
|
15
|
+
created_at: Annotated[AwareDatetime, Field(alias="createdAt")]
|
|
17
16
|
description: str
|
|
18
17
|
identity_uuid: Annotated[str, Field(alias="identityUUID")]
|
|
19
18
|
is_active: Annotated[bool, Field(alias="isActive")]
|
|
@@ -23,7 +22,7 @@ class Cluster(BaseModel):
|
|
|
23
22
|
pipekit_agent_version: Annotated[str, Field(alias="pipekitAgentVersion")]
|
|
24
23
|
port: Optional[int] = None
|
|
25
24
|
type: List[str]
|
|
26
|
-
updated_at: Annotated[
|
|
25
|
+
updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")]
|
|
27
26
|
uuid: str
|
|
28
27
|
workflow_group_priorities: Annotated[Optional[Dict[str, int]], Field(alias="workflowGroupPriorities")] = None
|
|
29
28
|
|
|
@@ -43,7 +42,7 @@ class GitInfo(BaseModel):
|
|
|
43
42
|
|
|
44
43
|
class Logs(BaseModel):
|
|
45
44
|
container_name: Annotated[str, Field(alias="containerName")]
|
|
46
|
-
created_at: Annotated[
|
|
45
|
+
created_at: Annotated[AwareDatetime, Field(alias="createdAt")]
|
|
47
46
|
identity_uuid: Annotated[str, Field(alias="identityUUID")]
|
|
48
47
|
log_type: Annotated[str, Field(alias="logType")]
|
|
49
48
|
node_id: Annotated[Optional[str], Field(alias="nodeId")] = None
|
|
@@ -52,7 +51,7 @@ class Logs(BaseModel):
|
|
|
52
51
|
pod_name: Annotated[str, Field(alias="podName")]
|
|
53
52
|
run_uuid: Annotated[str, Field(alias="runUUID")]
|
|
54
53
|
stream_cursor: Annotated[str, Field(alias="streamCursor")]
|
|
55
|
-
updated_at: Annotated[
|
|
54
|
+
updated_at: Annotated[AwareDatetime, Field(alias="updatedAt")]
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
class Pipe(BaseModel):
|
|
@@ -77,7 +76,7 @@ class PipeRun(BaseModel):
|
|
|
77
76
|
check_id: Annotated[Optional[int], Field(alias="checkId")] = None
|
|
78
77
|
cluster_name: Annotated[Optional[str], Field(alias="clusterName")] = None
|
|
79
78
|
cluster_uuid: Annotated[Optional[str], Field(alias="clusterUUID")] = None
|
|
80
|
-
created_at: Annotated[Optional[
|
|
79
|
+
created_at: Annotated[Optional[AwareDatetime], Field(alias="createdAt")] = None
|
|
81
80
|
git_info: Annotated[Optional[GitInfo], Field(alias="gitInfo")] = None
|
|
82
81
|
identity_uuid: Annotated[Optional[str], Field(alias="identityUUID")] = None
|
|
83
82
|
message: Optional[str] = None
|
|
@@ -92,6 +91,6 @@ class PipeRun(BaseModel):
|
|
|
92
91
|
source_name: Annotated[Optional[str], Field(alias="sourceName")] = None
|
|
93
92
|
source_type: Annotated[Optional[str], Field(alias="sourceType")] = None
|
|
94
93
|
status: Optional[str] = None
|
|
95
|
-
updated_at: Annotated[Optional[
|
|
94
|
+
updated_at: Annotated[Optional[AwareDatetime], Field(alias="updatedAt")] = None
|
|
96
95
|
user_name: Annotated[Optional[str], Field(alias="userName")] = None
|
|
97
96
|
uuid: Optional[str] = None
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from datetime import datetime
|
|
6
5
|
from typing import Any, Dict, List, Optional
|
|
7
6
|
|
|
8
|
-
from pydantic import Field
|
|
7
|
+
from pydantic import AwareDatetime, Field, RootModel
|
|
9
8
|
from typing_extensions import Annotated
|
|
10
9
|
|
|
11
10
|
from pipekit_sdk.models._config import BaseModel
|
|
@@ -276,8 +275,8 @@ class FCVolumeSource(BaseModel):
|
|
|
276
275
|
] = None
|
|
277
276
|
|
|
278
277
|
|
|
279
|
-
class FieldsV1(
|
|
280
|
-
|
|
278
|
+
class FieldsV1(RootModel[Any]):
|
|
279
|
+
root: Annotated[
|
|
281
280
|
Any,
|
|
282
281
|
Field(
|
|
283
282
|
description=(
|
|
@@ -1317,7 +1316,7 @@ class TCPSocketAction(BaseModel):
|
|
|
1317
1316
|
|
|
1318
1317
|
|
|
1319
1318
|
class Time(BaseModel):
|
|
1320
|
-
time: Annotated[
|
|
1319
|
+
time: Annotated[AwareDatetime, Field(alias="Time")]
|
|
1321
1320
|
|
|
1322
1321
|
|
|
1323
1322
|
class Toleration(BaseModel):
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
|
-
from pydantic import Field
|
|
7
|
+
from pydantic import Field, RootModel
|
|
8
8
|
from typing_extensions import Annotated
|
|
9
9
|
|
|
10
10
|
from pipekit_sdk.models._config import BaseModel
|
|
@@ -12,8 +12,8 @@ from pipekit_sdk.models._config import BaseModel
|
|
|
12
12
|
from . import intstr, v1
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class Amount(
|
|
16
|
-
|
|
15
|
+
class Amount(RootModel[Any]):
|
|
16
|
+
root: Any
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class ArtGCStatus(BaseModel):
|
|
@@ -190,8 +190,8 @@ class Histogram(BaseModel):
|
|
|
190
190
|
value: str
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
class Item(
|
|
194
|
-
|
|
193
|
+
class Item(RootModel[Any]):
|
|
194
|
+
root: Any
|
|
195
195
|
|
|
196
196
|
|
|
197
197
|
class LabelValueFrom(BaseModel):
|
|
@@ -244,8 +244,8 @@ class NodeSynchronizationStatus(BaseModel):
|
|
|
244
244
|
waiting: Optional[str] = None
|
|
245
245
|
|
|
246
246
|
|
|
247
|
-
class NoneStrategy(
|
|
248
|
-
|
|
247
|
+
class NoneStrategy(RootModel[Any]):
|
|
248
|
+
root: Any
|
|
249
249
|
|
|
250
250
|
|
|
251
251
|
class OAuth2EndpointParam(BaseModel):
|
|
@@ -258,12 +258,12 @@ class OSSLifecycleRule(BaseModel):
|
|
|
258
258
|
mark_infrequent_access_after_days: Annotated[Optional[int], Field(alias="markInfrequentAccessAfterDays")] = None
|
|
259
259
|
|
|
260
260
|
|
|
261
|
-
class ParallelSteps(
|
|
262
|
-
|
|
261
|
+
class ParallelSteps(RootModel[Any]):
|
|
262
|
+
root: Any
|
|
263
263
|
|
|
264
264
|
|
|
265
|
-
class Plugin(
|
|
266
|
-
|
|
265
|
+
class Plugin(RootModel[Any]):
|
|
266
|
+
root: Any
|
|
267
267
|
|
|
268
268
|
|
|
269
269
|
class Prometheus(BaseModel):
|
|
@@ -280,8 +280,8 @@ class RawArtifact(BaseModel):
|
|
|
280
280
|
data: str
|
|
281
281
|
|
|
282
282
|
|
|
283
|
-
class RetryNodeAntiAffinity(
|
|
284
|
-
|
|
283
|
+
class RetryNodeAntiAffinity(RootModel[Any]):
|
|
284
|
+
root: Any
|
|
285
285
|
|
|
286
286
|
|
|
287
287
|
class S3EncryptionOptions(BaseModel):
|
|
@@ -315,8 +315,8 @@ class Sequence(BaseModel):
|
|
|
315
315
|
start: Optional[intstr.IntOrString] = None
|
|
316
316
|
|
|
317
317
|
|
|
318
|
-
class SuppliedValueFrom(
|
|
319
|
-
|
|
318
|
+
class SuppliedValueFrom(RootModel[Any]):
|
|
319
|
+
root: Any
|
|
320
320
|
|
|
321
321
|
|
|
322
322
|
class SuspendTemplate(BaseModel):
|
|
@@ -388,8 +388,8 @@ class WorkflowTemplateRef(BaseModel):
|
|
|
388
388
|
name: Optional[str] = None
|
|
389
389
|
|
|
390
390
|
|
|
391
|
-
class ZipStrategy(
|
|
392
|
-
|
|
391
|
+
class ZipStrategy(RootModel[Any]):
|
|
392
|
+
root: Any
|
|
393
393
|
|
|
394
394
|
|
|
395
395
|
class ArchiveStrategy(BaseModel):
|
|
@@ -1689,7 +1689,7 @@ class WorkflowStatus(BaseModel):
|
|
|
1689
1689
|
] = None
|
|
1690
1690
|
|
|
1691
1691
|
|
|
1692
|
-
CronWorkflow.
|
|
1693
|
-
CronWorkflowSpec.
|
|
1694
|
-
DAGTask.
|
|
1695
|
-
Workflow.
|
|
1692
|
+
CronWorkflow.model_rebuild()
|
|
1693
|
+
CronWorkflowSpec.model_rebuild()
|
|
1694
|
+
DAGTask.model_rebuild()
|
|
1695
|
+
Workflow.model_rebuild()
|
|
@@ -2,19 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
-
from
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Generator, List, Optional, cast
|
|
6
9
|
|
|
10
|
+
import jwt
|
|
7
11
|
import requests
|
|
8
12
|
from hera.workflows import CronWorkflow, Workflow
|
|
9
13
|
from hera.workflows.models import WorkflowCreateRequest
|
|
14
|
+
from pydantic import BaseModel, ValidationError
|
|
10
15
|
|
|
11
16
|
from pipekit_sdk._helpers import is_valid_uuid
|
|
12
17
|
from pipekit_sdk.models.model import Cluster, Logs, Pipe, PipeRun
|
|
13
18
|
|
|
14
19
|
|
|
20
|
+
class _LoginResponse(BaseModel):
|
|
21
|
+
"""LoginResponse is a model for Login responses."""
|
|
22
|
+
|
|
23
|
+
token_type: str
|
|
24
|
+
access_token: str
|
|
25
|
+
expires_in: int
|
|
26
|
+
refresh_token: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class _AccessToken(BaseModel):
|
|
30
|
+
"""AccessToken is a model for decoded access tokens."""
|
|
31
|
+
|
|
32
|
+
identityUUID: str
|
|
33
|
+
ClusterUUID: str
|
|
34
|
+
OrgUUID: str
|
|
35
|
+
isActive: bool
|
|
36
|
+
products: List[str]
|
|
37
|
+
iss: str
|
|
38
|
+
sub: str
|
|
39
|
+
exp: int
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _ValidationResult(Enum):
|
|
43
|
+
OK = 0
|
|
44
|
+
INVALID_TOKEN = 1
|
|
45
|
+
EXPIRED_TOKEN = 2
|
|
46
|
+
|
|
47
|
+
|
|
15
48
|
class PipekitService:
|
|
16
49
|
"""PipekitService is a wrapper around the Pipekit API. It provides a simple interface to interact with Pipekit."""
|
|
17
50
|
|
|
51
|
+
@staticmethod
|
|
52
|
+
def __from_home_dir() -> Optional[_LoginResponse]:
|
|
53
|
+
home = Path.home()
|
|
54
|
+
pipekit_token_file_path = os.path.join(home, ".pipekit", "token")
|
|
55
|
+
try:
|
|
56
|
+
with open(pipekit_token_file_path, "r") as f:
|
|
57
|
+
raw_data = f.read()
|
|
58
|
+
return _LoginResponse.model_validate_json(raw_data)
|
|
59
|
+
except ValidationError:
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def __write_home_dir(login_resp: _LoginResponse):
|
|
64
|
+
home = Path.home()
|
|
65
|
+
pipekit_token_file_path = os.path.join(home, ".pipekit", "token")
|
|
66
|
+
with open(pipekit_token_file_path, "w") as f:
|
|
67
|
+
payload = login_resp.model_dump_json(indent=2)
|
|
68
|
+
f.write(payload)
|
|
69
|
+
|
|
18
70
|
def __init__(
|
|
19
71
|
self,
|
|
20
72
|
username: str = "",
|
|
@@ -38,8 +90,60 @@ class PipekitService:
|
|
|
38
90
|
self.access_token = token
|
|
39
91
|
return
|
|
40
92
|
|
|
93
|
+
maybe_resp = self.__from_home_dir()
|
|
94
|
+
self.token_data = maybe_resp
|
|
95
|
+
|
|
96
|
+
if self.token_data is not None:
|
|
97
|
+
self.__token_login_flow()
|
|
98
|
+
return
|
|
99
|
+
|
|
41
100
|
self.__login()
|
|
42
101
|
|
|
102
|
+
def __update_token(self) -> None:
|
|
103
|
+
login_url = f"{self.id_url}/api/id/v1/oauth/token"
|
|
104
|
+
assert self.token_data is not None, "Token data was None, this implies a bug"
|
|
105
|
+
login_request = {"grant_type": "refresh_token", "refresh_token": self.token_data.refresh_token}
|
|
106
|
+
login_response = requests.post(
|
|
107
|
+
login_url,
|
|
108
|
+
data=json.dumps(login_request),
|
|
109
|
+
headers={"Content-Type": "application/json"},
|
|
110
|
+
timeout=10,
|
|
111
|
+
)
|
|
112
|
+
if login_response.status_code // 100 != 2:
|
|
113
|
+
raise Exception(
|
|
114
|
+
"Couldn't refresh access token, obtained non 2xx status code, try logging in again via the cli"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
login_response_model = _LoginResponse.model_validate(login_response.json())
|
|
118
|
+
self.__write_home_dir(login_response_model)
|
|
119
|
+
self.access_token = login_response_model.access_token
|
|
120
|
+
|
|
121
|
+
def __validate_token(self) -> _ValidationResult:
|
|
122
|
+
assert self.token_data is not None
|
|
123
|
+
try:
|
|
124
|
+
decoded_payload = jwt.decode(self.token_data.access_token, options={"verify_signature": False})
|
|
125
|
+
acc_tk = _AccessToken.model_validate(decoded_payload)
|
|
126
|
+
exp_time = datetime.fromtimestamp(acc_tk.exp)
|
|
127
|
+
now_time = datetime.now()
|
|
128
|
+
|
|
129
|
+
if exp_time <= now_time:
|
|
130
|
+
return _ValidationResult.EXPIRED_TOKEN
|
|
131
|
+
except jwt.PyJWTError:
|
|
132
|
+
return _ValidationResult.INVALID_TOKEN
|
|
133
|
+
return _ValidationResult.OK
|
|
134
|
+
|
|
135
|
+
def __token_login_flow(self) -> None:
|
|
136
|
+
assert self.token_data is not None, "token was None when it was expected to be valid"
|
|
137
|
+
res = self.__validate_token()
|
|
138
|
+
if res == _ValidationResult.EXPIRED_TOKEN:
|
|
139
|
+
self.__update_token()
|
|
140
|
+
elif res == _ValidationResult.INVALID_TOKEN:
|
|
141
|
+
raise RuntimeError(
|
|
142
|
+
"Token was invalid, if the `.pipekit/token` file is corrupted, please delete the file and login again"
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
self.access_token = self.token_data.access_token
|
|
146
|
+
|
|
43
147
|
def __login(self) -> None:
|
|
44
148
|
login_request = {
|
|
45
149
|
"username": self.username,
|
|
@@ -80,7 +184,7 @@ class PipekitService:
|
|
|
80
184
|
if clusters_response.status_code // 100 != 2:
|
|
81
185
|
raise Exception(f"List clusters failed: {clusters_response.text}")
|
|
82
186
|
|
|
83
|
-
clusters = [Cluster.
|
|
187
|
+
clusters = [Cluster.model_validate(cluster) for cluster in clusters_response.json()]
|
|
84
188
|
return clusters
|
|
85
189
|
|
|
86
190
|
def list_pipes(
|
|
@@ -107,7 +211,7 @@ class PipekitService:
|
|
|
107
211
|
if pipes_response.status_code // 100 != 2:
|
|
108
212
|
raise Exception(f"List pipes failed: {pipes_response.text}")
|
|
109
213
|
|
|
110
|
-
pipes_page = [Pipe.
|
|
214
|
+
pipes_page = [Pipe.model_validate(item) for item in pipes_response.json()["items"]]
|
|
111
215
|
if len(pipes_page) == 0:
|
|
112
216
|
break
|
|
113
217
|
|
|
@@ -135,7 +239,7 @@ class PipekitService:
|
|
|
135
239
|
if pipe_response.status_code // 100 != 2:
|
|
136
240
|
raise Exception(f"Get pipe failed: {pipe_response.text}")
|
|
137
241
|
|
|
138
|
-
return Pipe.
|
|
242
|
+
return Pipe.model_validate(pipe_response.json())
|
|
139
243
|
|
|
140
244
|
def list_runs_by_cluster(
|
|
141
245
|
self,
|
|
@@ -160,7 +264,7 @@ class PipekitService:
|
|
|
160
264
|
if runs_response.status_code // 100 != 2:
|
|
161
265
|
raise Exception(f"List runs failed: {runs_response.text}")
|
|
162
266
|
|
|
163
|
-
runs_page = [PipeRun.
|
|
267
|
+
runs_page = [PipeRun.model_validate(item) for item in runs_response.json()["items"]]
|
|
164
268
|
if len(runs_page) == 0:
|
|
165
269
|
break
|
|
166
270
|
|
|
@@ -196,7 +300,7 @@ class PipekitService:
|
|
|
196
300
|
if runs_response.status_code // 100 != 2:
|
|
197
301
|
raise Exception(f"List runs failed: {runs_response.text}")
|
|
198
302
|
|
|
199
|
-
runs_page = [PipeRun.
|
|
303
|
+
runs_page = [PipeRun.model_validate(item) for item in runs_response.json()["items"]]
|
|
200
304
|
if len(runs_page) == 0:
|
|
201
305
|
break
|
|
202
306
|
|
|
@@ -224,7 +328,7 @@ class PipekitService:
|
|
|
224
328
|
if run_response.status_code // 100 != 2:
|
|
225
329
|
raise Exception(f"Get run failed: {run_response.text}")
|
|
226
330
|
|
|
227
|
-
return PipeRun.
|
|
331
|
+
return PipeRun.model_validate(run_response.json())
|
|
228
332
|
|
|
229
333
|
def get_cluster(
|
|
230
334
|
self,
|
|
@@ -241,7 +345,7 @@ class PipekitService:
|
|
|
241
345
|
if cluster_response.status_code // 100 != 2:
|
|
242
346
|
raise Exception(f"Get cluster failed: {cluster_response.text}")
|
|
243
347
|
|
|
244
|
-
return Cluster.
|
|
348
|
+
return Cluster.model_validate(cluster_response.json())
|
|
245
349
|
|
|
246
350
|
def get_cluster_by_name(
|
|
247
351
|
self,
|
|
@@ -293,7 +397,7 @@ class PipekitService:
|
|
|
293
397
|
if submit_response.status_code // 100 != 2:
|
|
294
398
|
raise Exception(f"Submit failed: {submit_response.text}")
|
|
295
399
|
|
|
296
|
-
return PipeRun.
|
|
400
|
+
return PipeRun.model_validate(submit_response.json())
|
|
297
401
|
|
|
298
402
|
def create(self, cron_workflow: CronWorkflow, cluster: str, pipe_name: str = "") -> PipeRun:
|
|
299
403
|
"""Create a CronWorkflow on the cluster, under an existing or new pipe with the given name."""
|
|
@@ -328,7 +432,7 @@ class PipekitService:
|
|
|
328
432
|
if create_response.status_code // 100 != 2:
|
|
329
433
|
raise Exception(f"Create failed: {create_response.text}")
|
|
330
434
|
|
|
331
|
-
return PipeRun.
|
|
435
|
+
return PipeRun.model_validate(create_response.json())
|
|
332
436
|
|
|
333
437
|
def __apply_run_action(
|
|
334
438
|
self,
|
|
@@ -348,7 +452,7 @@ class PipekitService:
|
|
|
348
452
|
if action_response.status_code // 100 != 2:
|
|
349
453
|
raise Exception(f"Action failed: {action_response.text}")
|
|
350
454
|
|
|
351
|
-
return PipeRun.
|
|
455
|
+
return PipeRun.model_validate(action_response.json())
|
|
352
456
|
|
|
353
457
|
def restart(
|
|
354
458
|
self,
|
|
@@ -388,7 +492,7 @@ class PipekitService:
|
|
|
388
492
|
if logs_response.status_code // 100 != 2:
|
|
389
493
|
raise Exception(f"Get logs failed: {logs_response.text}")
|
|
390
494
|
|
|
391
|
-
return [Logs.
|
|
495
|
+
return [Logs.model_validate(log) for log in list(logs_response.json())]
|
|
392
496
|
|
|
393
497
|
def __get_logs_stream(
|
|
394
498
|
self,
|
|
@@ -464,7 +568,7 @@ class PipekitService:
|
|
|
464
568
|
# bye
|
|
465
569
|
return
|
|
466
570
|
else:
|
|
467
|
-
yield Logs.
|
|
571
|
+
yield Logs.model_validate(json.loads(line))
|
|
468
572
|
|
|
469
573
|
except requests.exceptions.Timeout:
|
|
470
574
|
pass # we'll ignore timeout errors and reconnect
|
|
@@ -486,3 +590,7 @@ class PipekitService:
|
|
|
486
590
|
|
|
487
591
|
for log in self.get_logs(run_uuid, pod_name=pod_name, container_name=container_name):
|
|
488
592
|
self.__print_log_message(log)
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
if __name__ == "__main__":
|
|
596
|
+
p = PipekitService()
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from pydantic.v1 import BaseModel as PydanticBaseModel
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class BaseModel(PydanticBaseModel):
|
|
5
|
-
class Config:
|
|
6
|
-
"""General config for generated models."""
|
|
7
|
-
|
|
8
|
-
allow_population_by_field_name = True
|
|
9
|
-
"""support populating object by Field alias"""
|
|
10
|
-
|
|
11
|
-
allow_mutation = True
|
|
12
|
-
"""allow mutation of objects post instantiation"""
|
|
13
|
-
|
|
14
|
-
use_enum_values = True
|
|
15
|
-
"""supports using enums, which are then unpacked to obtain the actual `.value`"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|