feldera 0.147.0__tar.gz → 0.149.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.
Potentially problematic release.
This version of feldera might be problematic. Click here for more details.
- {feldera-0.147.0 → feldera-0.149.0}/PKG-INFO +1 -1
- {feldera-0.147.0 → feldera-0.149.0}/feldera/_callback_runner.py +4 -1
- {feldera-0.147.0 → feldera-0.149.0}/feldera/enums.py +99 -93
- {feldera-0.147.0 → feldera-0.149.0}/feldera/pipeline.py +92 -34
- {feldera-0.147.0 → feldera-0.149.0}/feldera/pipeline_builder.py +5 -2
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/_httprequests.py +5 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/feldera_client.py +139 -103
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/pipeline.py +13 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera.egg-info/PKG-INFO +1 -1
- {feldera-0.147.0 → feldera-0.149.0}/pyproject.toml +1 -1
- {feldera-0.147.0 → feldera-0.149.0}/README.md +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/__init__.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/_helpers.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/output_handler.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/__init__.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/_helpers.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/config.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/errors.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/feldera_config.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/sql_table.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/rest/sql_view.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/runtime_config.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/stats.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/tests/test_datafusionize.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera/testutils.py +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera.egg-info/SOURCES.txt +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera.egg-info/dependency_links.txt +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera.egg-info/requires.txt +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/feldera.egg-info/top_level.txt +0 -0
- {feldera-0.147.0 → feldera-0.149.0}/setup.cfg +0 -0
|
@@ -6,6 +6,7 @@ from queue import Queue, Empty
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
from feldera import FelderaClient
|
|
8
8
|
from feldera._helpers import dataframe_from_response
|
|
9
|
+
from feldera.enums import PipelineFieldSelector
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class _CallbackRunnerInstruction(Enum):
|
|
@@ -38,7 +39,9 @@ class CallbackRunner(Thread):
|
|
|
38
39
|
:meta private:
|
|
39
40
|
"""
|
|
40
41
|
|
|
41
|
-
pipeline = self.client.get_pipeline(
|
|
42
|
+
pipeline = self.client.get_pipeline(
|
|
43
|
+
self.pipeline_name, PipelineFieldSelector.ALL
|
|
44
|
+
)
|
|
42
45
|
|
|
43
46
|
schemas = pipeline.tables + pipeline.views
|
|
44
47
|
for schema in schemas:
|
|
@@ -34,131 +34,129 @@ class BuildMode(Enum):
|
|
|
34
34
|
GET_OR_CREATE = 3
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
class
|
|
37
|
+
class DeploymentDesiredStatus(Enum):
|
|
38
|
+
"""
|
|
39
|
+
Deployment desired status of the pipeline.
|
|
38
40
|
"""
|
|
39
|
-
Represents the state that this pipeline is currently in.
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
STOPPED = 0
|
|
43
|
+
UNAVAILABLE = 1
|
|
44
|
+
STANDBY = 2
|
|
45
|
+
PAUSED = 3
|
|
46
|
+
RUNNING = 4
|
|
47
|
+
SUSPENDED = 5
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
│ │
|
|
52
|
-
┌─────────┼────────────────────┴─────┐
|
|
53
|
-
│ ▼ │
|
|
54
|
-
│ Paused ◄──────► Unavailable │
|
|
55
|
-
│ │ ▲ ▲ │
|
|
56
|
-
│ /start │ │ /pause │ │
|
|
57
|
-
│ ▼ │ │ │
|
|
58
|
-
│ Running ◄─────────────┘ │
|
|
59
|
-
└────────────────────────────────────┘
|
|
49
|
+
@staticmethod
|
|
50
|
+
def from_str(value):
|
|
51
|
+
for member in DeploymentDesiredStatus:
|
|
52
|
+
if member.name.lower() == value.lower():
|
|
53
|
+
return member
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"Unknown value '{value}' for enum {DeploymentDesiredStatus.__name__}"
|
|
56
|
+
)
|
|
60
57
|
|
|
61
|
-
"""
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
class DeploymentResourcesDesiredStatus(Enum):
|
|
64
60
|
"""
|
|
65
|
-
The
|
|
61
|
+
The desired status of deployment resources of the pipeline.
|
|
66
62
|
"""
|
|
67
63
|
|
|
68
|
-
STOPPED =
|
|
69
|
-
|
|
70
|
-
The pipeline has not (yet) been started or has been stopped either
|
|
71
|
-
manually by the user or automatically by the system due to a
|
|
72
|
-
resource or runtime error.
|
|
64
|
+
STOPPED = 0
|
|
65
|
+
PROVISIONED = 1
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
@staticmethod
|
|
68
|
+
def from_str(value):
|
|
69
|
+
for member in DeploymentResourcesDesiredStatus:
|
|
70
|
+
if member.name.lower() == value.lower():
|
|
71
|
+
return member
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"Unknown value '{value}' for enum {DeploymentResourcesDesiredStatus.__name__}"
|
|
74
|
+
)
|
|
75
75
|
|
|
76
|
-
1. The user starts it via `/start` or `/pause`, transitioning to `PROVISIONING`.
|
|
77
|
-
2. Early start fails (e.g., compilation failure), transitioning to `STOPPING`.
|
|
78
|
-
"""
|
|
79
76
|
|
|
80
|
-
|
|
77
|
+
class DeploymentResourcesStatus(Enum):
|
|
81
78
|
"""
|
|
82
|
-
|
|
83
|
-
are being provisioned.
|
|
84
|
-
|
|
85
|
-
The pipeline remains in this state until:
|
|
86
|
-
|
|
87
|
-
1. Resources are provisioned successfully, transitioning to `INITIALIZING`.
|
|
88
|
-
2. Provisioning fails or times out, transitioning to `STOPPING`.
|
|
89
|
-
3. The user cancels the pipeline via `/stop`, transitioning to `STOPPING`.
|
|
79
|
+
The desired status of deployment resources of the pipeline.
|
|
90
80
|
"""
|
|
91
81
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
STOPPED = 0
|
|
83
|
+
PROVISIONING = 1
|
|
84
|
+
PROVISIONED = 2
|
|
85
|
+
STOPPING = 3
|
|
95
86
|
|
|
96
|
-
|
|
87
|
+
@staticmethod
|
|
88
|
+
def from_str(value):
|
|
89
|
+
for member in DeploymentResourcesStatus:
|
|
90
|
+
if member.name.lower() == value.lower():
|
|
91
|
+
return member
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"Unknown value '{value}' for enum {DeploymentResourcesStatus.__name__}"
|
|
94
|
+
)
|
|
97
95
|
|
|
98
|
-
1. Initialization succeeds, transitioning to `PAUSED`.
|
|
99
|
-
2. Initialization fails or times out, transitioning to `STOPPING`.
|
|
100
|
-
3. The user suspends the pipeline via `/suspend`, transitioning to `SUSPENDING`.
|
|
101
|
-
4. The user stops the pipeline via `/stop`, transitioning to `STOPPING`.
|
|
102
|
-
"""
|
|
103
96
|
|
|
104
|
-
|
|
97
|
+
class DeploymentRuntimeDesiredStatus(Enum):
|
|
105
98
|
"""
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
The pipeline remains in this state until:
|
|
109
|
-
|
|
110
|
-
1. The user starts it via `/start`, transitioning to `RUNNING`.
|
|
111
|
-
2. A runtime error occurs, transitioning to `STOPPING`.
|
|
112
|
-
3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
|
|
113
|
-
4. The user stops it via `/stop`, transitioning to `STOPPING`.
|
|
99
|
+
Deployment runtime desired status of the pipeline.
|
|
114
100
|
"""
|
|
115
101
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
102
|
+
UNAVAILABLE = 0
|
|
103
|
+
STANDBY = 1
|
|
104
|
+
PAUSED = 2
|
|
105
|
+
RUNNING = 3
|
|
106
|
+
SUSPENDED = 4
|
|
119
107
|
|
|
120
|
-
|
|
108
|
+
@staticmethod
|
|
109
|
+
def from_str(value):
|
|
110
|
+
for member in DeploymentRuntimeDesiredStatus:
|
|
111
|
+
if member.name.lower() == value.lower():
|
|
112
|
+
return member
|
|
113
|
+
raise ValueError(
|
|
114
|
+
f"Unknown value '{value}' for enum {DeploymentRuntimeDesiredStatus.__name__}"
|
|
115
|
+
)
|
|
121
116
|
|
|
122
|
-
1. The user pauses it via `/pause`, transitioning to `PAUSED`.
|
|
123
|
-
2. A runtime error occurs, transitioning to `STOPPING`.
|
|
124
|
-
3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
|
|
125
|
-
4. The user stops it via `/stop`, transitioning to `STOPPING`.
|
|
126
|
-
"""
|
|
127
117
|
|
|
128
|
-
|
|
118
|
+
class DeploymentRuntimeStatus(Enum):
|
|
129
119
|
"""
|
|
130
|
-
|
|
131
|
-
or not ready.
|
|
132
|
-
|
|
133
|
-
The pipeline remains in this state until:
|
|
134
|
-
|
|
135
|
-
1. A successful status check transitions it back to `PAUSED` or `RUNNING`.
|
|
136
|
-
2. A runtime error occurs, transitioning to `STOPPING`.
|
|
137
|
-
3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
|
|
138
|
-
4. The user stops it via `/stop`, transitioning to `STOPPING`.
|
|
139
|
-
|
|
140
|
-
Note: While in this state, `/start` or `/pause` express desired state but
|
|
141
|
-
are only applied once the pipeline becomes reachable.
|
|
120
|
+
Deployment runtime status of the pipeline.
|
|
142
121
|
"""
|
|
143
122
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
123
|
+
UNAVAILABLE = 0
|
|
124
|
+
STANDBY = 1
|
|
125
|
+
INITIALIZING = 2
|
|
126
|
+
BOOTSTRAPPING = 3
|
|
127
|
+
REPLAYING = 4
|
|
128
|
+
PAUSED = 5
|
|
129
|
+
RUNNING = 6
|
|
130
|
+
SUSPENDED = 7
|
|
147
131
|
|
|
148
|
-
|
|
132
|
+
@staticmethod
|
|
133
|
+
def from_str(value):
|
|
134
|
+
for member in DeploymentRuntimeStatus:
|
|
135
|
+
if member.name.lower() == value.lower():
|
|
136
|
+
return member
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"Unknown value '{value}' for enum {DeploymentRuntimeStatus.__name__}"
|
|
139
|
+
)
|
|
149
140
|
|
|
150
|
-
1. Suspension succeeds, transitioning to `STOPPING`.
|
|
151
|
-
2. A runtime error occurs, transitioning to `STOPPING`.
|
|
152
|
-
"""
|
|
153
141
|
|
|
154
|
-
|
|
142
|
+
class PipelineStatus(Enum):
|
|
155
143
|
"""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
The pipeline remains in this state until deallocation completes,
|
|
159
|
-
transitioning to `STOPPED`.
|
|
144
|
+
Represents the state that this pipeline is currently in.
|
|
160
145
|
"""
|
|
161
146
|
|
|
147
|
+
NOT_FOUND = 0
|
|
148
|
+
STOPPED = 1
|
|
149
|
+
PROVISIONING = 2
|
|
150
|
+
UNAVAILABLE = 3
|
|
151
|
+
STANDBY = 4
|
|
152
|
+
INITIALIZING = 5
|
|
153
|
+
BOOTSTRAPPING = 6
|
|
154
|
+
REPLAYING = 7
|
|
155
|
+
PAUSED = 8
|
|
156
|
+
RUNNING = 9
|
|
157
|
+
SUSPENDED = 10
|
|
158
|
+
STOPPING = 11
|
|
159
|
+
|
|
162
160
|
@staticmethod
|
|
163
161
|
def from_str(value):
|
|
164
162
|
for member in PipelineStatus:
|
|
@@ -338,3 +336,11 @@ class FaultToleranceModel(Enum):
|
|
|
338
336
|
raise ValueError(
|
|
339
337
|
f"Unknown value '{value}' for enum {FaultToleranceModel.__name__}"
|
|
340
338
|
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class PipelineFieldSelector(Enum):
|
|
342
|
+
ALL = "all"
|
|
343
|
+
"""Select all fields of a pipeline."""
|
|
344
|
+
|
|
345
|
+
STATUS = "status"
|
|
346
|
+
"""Select only the fields required to know the status of a pipeline."""
|
|
@@ -12,12 +12,18 @@ from queue import Queue
|
|
|
12
12
|
|
|
13
13
|
from feldera.rest.errors import FelderaAPIError
|
|
14
14
|
from feldera.enums import (
|
|
15
|
+
PipelineFieldSelector,
|
|
15
16
|
PipelineStatus,
|
|
16
17
|
ProgramStatus,
|
|
17
18
|
CheckpointStatus,
|
|
18
19
|
TransactionStatus,
|
|
20
|
+
StorageStatus,
|
|
21
|
+
DeploymentDesiredStatus,
|
|
22
|
+
DeploymentResourcesDesiredStatus,
|
|
23
|
+
DeploymentResourcesStatus,
|
|
24
|
+
DeploymentRuntimeDesiredStatus,
|
|
25
|
+
DeploymentRuntimeStatus,
|
|
19
26
|
)
|
|
20
|
-
from feldera.enums import StorageStatus
|
|
21
27
|
from feldera.rest.pipeline import Pipeline as InnerPipeline
|
|
22
28
|
from feldera.rest.feldera_client import FelderaClient
|
|
23
29
|
from feldera._callback_runner import _CallbackRunnerInstruction, CallbackRunner
|
|
@@ -55,14 +61,16 @@ class Pipeline:
|
|
|
55
61
|
# block until the callback runner is ready
|
|
56
62
|
queue.join()
|
|
57
63
|
|
|
58
|
-
def refresh(self):
|
|
64
|
+
def refresh(self, field_selector: PipelineFieldSelector):
|
|
59
65
|
"""
|
|
60
66
|
Calls the backend to get the updated, latest version of the pipeline.
|
|
61
67
|
|
|
68
|
+
:param field_selector: Choose what pipeline information to refresh; see PipelineFieldSelector enum definition.
|
|
69
|
+
|
|
62
70
|
:raises FelderaConnectionError: If there is an issue connecting to the backend.
|
|
63
71
|
"""
|
|
64
72
|
|
|
65
|
-
self._inner = self.client.get_pipeline(self.name)
|
|
73
|
+
self._inner = self.client.get_pipeline(self.name, field_selector)
|
|
66
74
|
|
|
67
75
|
def status(self) -> PipelineStatus:
|
|
68
76
|
"""
|
|
@@ -70,7 +78,7 @@ class Pipeline:
|
|
|
70
78
|
"""
|
|
71
79
|
|
|
72
80
|
try:
|
|
73
|
-
self.refresh()
|
|
81
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
74
82
|
return PipelineStatus.from_str(self._inner.deployment_status)
|
|
75
83
|
|
|
76
84
|
except FelderaAPIError as err:
|
|
@@ -119,7 +127,7 @@ class Pipeline:
|
|
|
119
127
|
|
|
120
128
|
ensure_dataframe_has_columns(df)
|
|
121
129
|
|
|
122
|
-
pipeline = self.client.get_pipeline(self.name)
|
|
130
|
+
pipeline = self.client.get_pipeline(self.name, PipelineFieldSelector.ALL)
|
|
123
131
|
if table_name.lower() != "now" and table_name.lower() not in [
|
|
124
132
|
tbl.name.lower() for tbl in pipeline.tables
|
|
125
133
|
]:
|
|
@@ -393,9 +401,7 @@ method or use `Pipeline.resume()` to resume a paused pipeline."""
|
|
|
393
401
|
|
|
394
402
|
return
|
|
395
403
|
|
|
396
|
-
self.client.
|
|
397
|
-
self.name, "Unable to START the pipeline.\n", wait=wait, timeout_s=timeout_s
|
|
398
|
-
)
|
|
404
|
+
self.client.start_pipeline_as_paused(self.name, wait=wait, timeout_s=timeout_s)
|
|
399
405
|
self.__setup_output_listeners()
|
|
400
406
|
self.resume(timeout_s=timeout_s)
|
|
401
407
|
|
|
@@ -505,6 +511,20 @@ metrics"""
|
|
|
505
511
|
|
|
506
512
|
self.client.activate_pipeline(self.name, wait=wait, timeout_s=timeout_s)
|
|
507
513
|
|
|
514
|
+
def start_paused(self, wait: bool = True, timeout_s: Optional[float] = None):
|
|
515
|
+
"""
|
|
516
|
+
Starts the pipeline in the paused state.
|
|
517
|
+
"""
|
|
518
|
+
|
|
519
|
+
self.client.start_pipeline_as_paused(self.name, wait=wait, timeout_s=timeout_s)
|
|
520
|
+
|
|
521
|
+
def start_standby(self, wait: bool = True, timeout_s: Optional[float] = None):
|
|
522
|
+
"""
|
|
523
|
+
Starts the pipeline in the standby state.
|
|
524
|
+
"""
|
|
525
|
+
|
|
526
|
+
self.client.start_pipeline_as_standby(self.name, wait=wait, timeout_s=timeout_s)
|
|
527
|
+
|
|
508
528
|
def pause(self, wait: bool = True, timeout_s: Optional[float] = None):
|
|
509
529
|
"""
|
|
510
530
|
Pause the pipeline.
|
|
@@ -562,7 +582,7 @@ metrics"""
|
|
|
562
582
|
pipeline to resume.
|
|
563
583
|
"""
|
|
564
584
|
|
|
565
|
-
self.client.
|
|
585
|
+
self.client.resume_pipeline(self.name, wait=wait, timeout_s=timeout_s)
|
|
566
586
|
|
|
567
587
|
def start_transaction(self) -> int:
|
|
568
588
|
"""
|
|
@@ -655,7 +675,7 @@ metrics"""
|
|
|
655
675
|
"""
|
|
656
676
|
|
|
657
677
|
try:
|
|
658
|
-
inner = client.get_pipeline(name)
|
|
678
|
+
inner = client.get_pipeline(name, PipelineFieldSelector.ALL)
|
|
659
679
|
return Pipeline._from_inner(inner, client)
|
|
660
680
|
except FelderaAPIError as err:
|
|
661
681
|
if err.status_code == 404:
|
|
@@ -931,7 +951,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
931
951
|
Return the program SQL code of the pipeline.
|
|
932
952
|
"""
|
|
933
953
|
|
|
934
|
-
self.refresh()
|
|
954
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
935
955
|
return self._inner.program_code
|
|
936
956
|
|
|
937
957
|
def modify(
|
|
@@ -971,7 +991,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
971
991
|
Return the storage status of the pipeline.
|
|
972
992
|
"""
|
|
973
993
|
|
|
974
|
-
self.refresh()
|
|
994
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
975
995
|
return StorageStatus.from_str(self._inner.storage_status)
|
|
976
996
|
|
|
977
997
|
def program_status(self) -> ProgramStatus:
|
|
@@ -983,7 +1003,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
983
1003
|
Rust code to a binary.
|
|
984
1004
|
"""
|
|
985
1005
|
|
|
986
|
-
self.refresh()
|
|
1006
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
987
1007
|
return ProgramStatus.from_value(self._inner.program_status)
|
|
988
1008
|
|
|
989
1009
|
def program_status_since(self) -> datetime:
|
|
@@ -991,7 +1011,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
991
1011
|
Return the timestamp when the current program status was set.
|
|
992
1012
|
"""
|
|
993
1013
|
|
|
994
|
-
self.refresh()
|
|
1014
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
995
1015
|
return datetime.fromisoformat(self._inner.program_status_since)
|
|
996
1016
|
|
|
997
1017
|
def udf_rust(self) -> str:
|
|
@@ -999,7 +1019,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
999
1019
|
Return the Rust code for UDFs.
|
|
1000
1020
|
"""
|
|
1001
1021
|
|
|
1002
|
-
self.refresh()
|
|
1022
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1003
1023
|
return self._inner.udf_rust
|
|
1004
1024
|
|
|
1005
1025
|
def udf_toml(self) -> str:
|
|
@@ -1007,7 +1027,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1007
1027
|
Return the Rust dependencies required by UDFs (in the TOML format).
|
|
1008
1028
|
"""
|
|
1009
1029
|
|
|
1010
|
-
self.refresh()
|
|
1030
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1011
1031
|
return self._inner.udf_toml
|
|
1012
1032
|
|
|
1013
1033
|
def program_config(self) -> Mapping[str, Any]:
|
|
@@ -1015,7 +1035,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1015
1035
|
Return the program config of the pipeline.
|
|
1016
1036
|
"""
|
|
1017
1037
|
|
|
1018
|
-
self.refresh()
|
|
1038
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1019
1039
|
return self._inner.program_config
|
|
1020
1040
|
|
|
1021
1041
|
def runtime_config(self) -> RuntimeConfig:
|
|
@@ -1023,7 +1043,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1023
1043
|
Return the runtime config of the pipeline.
|
|
1024
1044
|
"""
|
|
1025
1045
|
|
|
1026
|
-
self.refresh()
|
|
1046
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1027
1047
|
return RuntimeConfig.from_dict(self._inner.runtime_config)
|
|
1028
1048
|
|
|
1029
1049
|
def set_runtime_config(self, runtime_config: RuntimeConfig):
|
|
@@ -1048,7 +1068,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1048
1068
|
Return the ID of the pipeline.
|
|
1049
1069
|
"""
|
|
1050
1070
|
|
|
1051
|
-
self.refresh()
|
|
1071
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1052
1072
|
return self._inner.id
|
|
1053
1073
|
|
|
1054
1074
|
def description(self) -> str:
|
|
@@ -1056,7 +1076,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1056
1076
|
Return the description of the pipeline.
|
|
1057
1077
|
"""
|
|
1058
1078
|
|
|
1059
|
-
self.refresh()
|
|
1079
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1060
1080
|
return self._inner.description
|
|
1061
1081
|
|
|
1062
1082
|
def tables(self) -> List[SQLTable]:
|
|
@@ -1064,7 +1084,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1064
1084
|
Return the tables of the pipeline.
|
|
1065
1085
|
"""
|
|
1066
1086
|
|
|
1067
|
-
self.refresh()
|
|
1087
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1068
1088
|
return self._inner.tables
|
|
1069
1089
|
|
|
1070
1090
|
def views(self) -> List[SQLView]:
|
|
@@ -1072,7 +1092,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1072
1092
|
Return the views of the pipeline.
|
|
1073
1093
|
"""
|
|
1074
1094
|
|
|
1075
|
-
self.refresh()
|
|
1095
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1076
1096
|
return self._inner.views
|
|
1077
1097
|
|
|
1078
1098
|
def created_at(self) -> datetime:
|
|
@@ -1080,7 +1100,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1080
1100
|
Return the creation time of the pipeline.
|
|
1081
1101
|
"""
|
|
1082
1102
|
|
|
1083
|
-
self.refresh()
|
|
1103
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1084
1104
|
return datetime.fromisoformat(self._inner.created_at)
|
|
1085
1105
|
|
|
1086
1106
|
def version(self) -> int:
|
|
@@ -1088,7 +1108,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1088
1108
|
Return the version of the pipeline.
|
|
1089
1109
|
"""
|
|
1090
1110
|
|
|
1091
|
-
self.refresh()
|
|
1111
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1092
1112
|
return self._inner.version
|
|
1093
1113
|
|
|
1094
1114
|
def program_version(self) -> int:
|
|
@@ -1096,7 +1116,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1096
1116
|
Return the program version of the pipeline.
|
|
1097
1117
|
"""
|
|
1098
1118
|
|
|
1099
|
-
self.refresh()
|
|
1119
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1100
1120
|
return self._inner.program_version
|
|
1101
1121
|
|
|
1102
1122
|
def deployment_status_since(self) -> datetime:
|
|
@@ -1105,7 +1125,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1105
1125
|
was set.
|
|
1106
1126
|
"""
|
|
1107
1127
|
|
|
1108
|
-
self.refresh()
|
|
1128
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1109
1129
|
return datetime.fromisoformat(self._inner.deployment_status_since)
|
|
1110
1130
|
|
|
1111
1131
|
def deployment_config(self) -> Mapping[str, Any]:
|
|
@@ -1113,17 +1133,55 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1113
1133
|
Return the deployment config of the pipeline.
|
|
1114
1134
|
"""
|
|
1115
1135
|
|
|
1116
|
-
self.refresh()
|
|
1136
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1117
1137
|
return self._inner.deployment_config
|
|
1118
1138
|
|
|
1119
|
-
def deployment_desired_status(self) ->
|
|
1139
|
+
def deployment_desired_status(self) -> DeploymentDesiredStatus:
|
|
1120
1140
|
"""
|
|
1121
1141
|
Return the desired deployment status of the pipeline.
|
|
1122
1142
|
This is the next state that the pipeline should transition to.
|
|
1123
1143
|
"""
|
|
1124
1144
|
|
|
1125
|
-
self.refresh()
|
|
1126
|
-
return
|
|
1145
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1146
|
+
return DeploymentDesiredStatus.from_str(self._inner.deployment_desired_status)
|
|
1147
|
+
|
|
1148
|
+
def deployment_resources_desired_status(self) -> DeploymentResourcesDesiredStatus:
|
|
1149
|
+
"""
|
|
1150
|
+
Return the desired status of the the deployment resources.
|
|
1151
|
+
"""
|
|
1152
|
+
|
|
1153
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1154
|
+
return DeploymentResourcesDesiredStatus.from_str(
|
|
1155
|
+
self._inner.deployment_resources_desired_status
|
|
1156
|
+
)
|
|
1157
|
+
|
|
1158
|
+
def deployment_resources_status(self) -> DeploymentResourcesStatus:
|
|
1159
|
+
"""
|
|
1160
|
+
Return the status of the deployment resources.
|
|
1161
|
+
"""
|
|
1162
|
+
|
|
1163
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1164
|
+
return DeploymentResourcesStatus.from_str(
|
|
1165
|
+
self._inner.deployment_resources_status
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
def deployment_runtime_desired_status(self) -> DeploymentRuntimeDesiredStatus:
|
|
1169
|
+
"""
|
|
1170
|
+
Return the deployment runtime desired status.
|
|
1171
|
+
"""
|
|
1172
|
+
|
|
1173
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1174
|
+
return DeploymentRuntimeDesiredStatus.from_str(
|
|
1175
|
+
self._inner.deployment_runtime_desired_status
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
def deployment_runtime_status(self) -> DeploymentRuntimeStatus:
|
|
1179
|
+
"""
|
|
1180
|
+
Return the deployment runtime status.
|
|
1181
|
+
"""
|
|
1182
|
+
|
|
1183
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1184
|
+
return DeploymentRuntimeStatus.from_str(self._inner.deployment_runtime_status)
|
|
1127
1185
|
|
|
1128
1186
|
def deployment_error(self) -> Mapping[str, Any]:
|
|
1129
1187
|
"""
|
|
@@ -1131,7 +1189,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1131
1189
|
Returns an empty string if there is no error.
|
|
1132
1190
|
"""
|
|
1133
1191
|
|
|
1134
|
-
self.refresh()
|
|
1192
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1135
1193
|
return self._inner.deployment_error
|
|
1136
1194
|
|
|
1137
1195
|
def deployment_location(self) -> str:
|
|
@@ -1141,7 +1199,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1141
1199
|
at runtime (a TCP port number or a URI).
|
|
1142
1200
|
"""
|
|
1143
1201
|
|
|
1144
|
-
self.refresh()
|
|
1202
|
+
self.refresh(PipelineFieldSelector.STATUS)
|
|
1145
1203
|
return self._inner.deployment_location
|
|
1146
1204
|
|
|
1147
1205
|
def program_info(self) -> Mapping[str, Any]:
|
|
@@ -1152,7 +1210,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1152
1210
|
and the SQL program schema.
|
|
1153
1211
|
"""
|
|
1154
1212
|
|
|
1155
|
-
self.refresh()
|
|
1213
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1156
1214
|
return self._inner.program_info
|
|
1157
1215
|
|
|
1158
1216
|
def program_error(self) -> Mapping[str, Any]:
|
|
@@ -1162,7 +1220,7 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
|
|
|
1162
1220
|
`sql_compilation` and `rust_compilation` will be 0.
|
|
1163
1221
|
"""
|
|
1164
1222
|
|
|
1165
|
-
self.refresh()
|
|
1223
|
+
self.refresh(PipelineFieldSelector.ALL)
|
|
1166
1224
|
return self._inner.program_error
|
|
1167
1225
|
|
|
1168
1226
|
def errors(self) -> List[Mapping[str, Any]]:
|
|
@@ -4,7 +4,7 @@ from typing import Optional
|
|
|
4
4
|
from feldera.rest.feldera_client import FelderaClient
|
|
5
5
|
from feldera.rest.pipeline import Pipeline as InnerPipeline
|
|
6
6
|
from feldera.pipeline import Pipeline
|
|
7
|
-
from feldera.enums import CompilationProfile
|
|
7
|
+
from feldera.enums import CompilationProfile, PipelineFieldSelector
|
|
8
8
|
from feldera.runtime_config import RuntimeConfig
|
|
9
9
|
from feldera.rest.errors import FelderaAPIError
|
|
10
10
|
|
|
@@ -60,7 +60,10 @@ class PipelineBuilder:
|
|
|
60
60
|
raise ValueError("Name and SQL are required to create a pipeline")
|
|
61
61
|
|
|
62
62
|
try:
|
|
63
|
-
if
|
|
63
|
+
if (
|
|
64
|
+
self.client.get_pipeline(self.name, PipelineFieldSelector.STATUS)
|
|
65
|
+
is not None
|
|
66
|
+
):
|
|
64
67
|
raise RuntimeError(f"Pipeline with name {self.name} already exists")
|
|
65
68
|
except FelderaAPIError as err:
|
|
66
69
|
if err.error_code != "UnknownPipelineName":
|
|
@@ -206,6 +206,11 @@ class HttpRequests:
|
|
|
206
206
|
try:
|
|
207
207
|
request.raise_for_status()
|
|
208
208
|
|
|
209
|
+
if request is None:
|
|
210
|
+
# This shouldn't ever be the case, but we've seen it happen
|
|
211
|
+
return FelderaCommunicationError(
|
|
212
|
+
"Failed to Communicate with Feldera Received None as Response",
|
|
213
|
+
)
|
|
209
214
|
if stream:
|
|
210
215
|
return request
|
|
211
216
|
if request.headers.get("content-type") == "text/plain":
|
|
@@ -7,6 +7,7 @@ from decimal import Decimal
|
|
|
7
7
|
from typing import Generator, Mapping
|
|
8
8
|
from urllib.parse import quote
|
|
9
9
|
|
|
10
|
+
from feldera.enums import PipelineFieldSelector
|
|
10
11
|
from feldera.rest.config import Config
|
|
11
12
|
from feldera.rest.feldera_config import FelderaConfig
|
|
12
13
|
from feldera.rest.errors import FelderaTimeoutError, FelderaAPIError
|
|
@@ -93,14 +94,19 @@ class FelderaClient:
|
|
|
93
94
|
|
|
94
95
|
return FelderaClient(f"http://127.0.0.1:{port}")
|
|
95
96
|
|
|
96
|
-
def get_pipeline(
|
|
97
|
+
def get_pipeline(
|
|
98
|
+
self, pipeline_name: str, field_selector: PipelineFieldSelector
|
|
99
|
+
) -> Pipeline:
|
|
97
100
|
"""
|
|
98
101
|
Get a pipeline by name
|
|
99
102
|
|
|
100
103
|
:param pipeline_name: The name of the pipeline
|
|
104
|
+
:param field_selector: Choose what pipeline information to refresh; see PipelineFieldSelector enum definition.
|
|
101
105
|
"""
|
|
102
106
|
|
|
103
|
-
resp = self.http.get(
|
|
107
|
+
resp = self.http.get(
|
|
108
|
+
f"/pipelines/{pipeline_name}?selector={field_selector.value}"
|
|
109
|
+
)
|
|
104
110
|
|
|
105
111
|
return Pipeline.from_dict(resp)
|
|
106
112
|
|
|
@@ -130,12 +136,14 @@ class FelderaClient:
|
|
|
130
136
|
wait = ["Pending", "CompilingSql", "SqlCompiled", "CompilingRust"]
|
|
131
137
|
|
|
132
138
|
while True:
|
|
133
|
-
p = self.get_pipeline(name)
|
|
139
|
+
p = self.get_pipeline(name, PipelineFieldSelector.STATUS)
|
|
134
140
|
status = p.program_status
|
|
135
141
|
|
|
136
142
|
if status == "Success":
|
|
137
|
-
return
|
|
143
|
+
return self.get_pipeline(name, PipelineFieldSelector.ALL)
|
|
138
144
|
elif status not in wait:
|
|
145
|
+
p = self.get_pipeline(name, PipelineFieldSelector.ALL)
|
|
146
|
+
|
|
139
147
|
# error handling for SQL compilation errors
|
|
140
148
|
if status == "SqlError":
|
|
141
149
|
sql_errors = p.program_error["sql_compilation"]["messages"]
|
|
@@ -163,6 +171,46 @@ class FelderaClient:
|
|
|
163
171
|
logging.debug("still compiling %s, waiting for 100 more milliseconds", name)
|
|
164
172
|
time.sleep(0.1)
|
|
165
173
|
|
|
174
|
+
def __wait_for_pipeline_state(
|
|
175
|
+
self,
|
|
176
|
+
pipeline_name: str,
|
|
177
|
+
state: str,
|
|
178
|
+
timeout_s: float = 300.0,
|
|
179
|
+
start: bool = True,
|
|
180
|
+
):
|
|
181
|
+
start_time = time.monotonic()
|
|
182
|
+
|
|
183
|
+
while True:
|
|
184
|
+
if timeout_s is not None:
|
|
185
|
+
elapsed = time.monotonic() - start_time
|
|
186
|
+
if elapsed > timeout_s:
|
|
187
|
+
raise TimeoutError(
|
|
188
|
+
f"Timed out waiting for pipeline {pipeline_name} to"
|
|
189
|
+
f"transition to '{state}' state"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
resp = self.get_pipeline(pipeline_name, PipelineFieldSelector.STATUS)
|
|
193
|
+
status = resp.deployment_status
|
|
194
|
+
|
|
195
|
+
if status.lower() == state.lower():
|
|
196
|
+
break
|
|
197
|
+
elif (
|
|
198
|
+
status == "Stopped"
|
|
199
|
+
and len(resp.deployment_error or {}) > 0
|
|
200
|
+
and resp.deployment_desired_status == "Stopped"
|
|
201
|
+
):
|
|
202
|
+
err_msg = "Unable to START the pipeline:\n" if start else ""
|
|
203
|
+
raise RuntimeError(
|
|
204
|
+
f"""{err_msg}Unable to transition the pipeline to '{state}'.
|
|
205
|
+
Reason: The pipeline is in a STOPPED state due to the following error:
|
|
206
|
+
{resp.deployment_error.get("message", "")}"""
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
logging.debug(
|
|
210
|
+
"still starting %s, waiting for 100 more milliseconds", pipeline_name
|
|
211
|
+
)
|
|
212
|
+
time.sleep(0.1)
|
|
213
|
+
|
|
166
214
|
def create_pipeline(self, pipeline: Pipeline) -> Pipeline:
|
|
167
215
|
"""
|
|
168
216
|
Create a pipeline if it doesn't exist and wait for it to compile
|
|
@@ -284,9 +332,10 @@ class FelderaClient:
|
|
|
284
332
|
"""
|
|
285
333
|
|
|
286
334
|
:param pipeline_name: The name of the pipeline to activate
|
|
287
|
-
:param wait: Set True to wait for the pipeline to activate. True by
|
|
288
|
-
|
|
289
|
-
|
|
335
|
+
:param wait: Set True to wait for the pipeline to activate. True by
|
|
336
|
+
default
|
|
337
|
+
:param timeout_s: The amount of time in seconds to wait for the
|
|
338
|
+
pipeline to activate. 300 seconds by default.
|
|
290
339
|
"""
|
|
291
340
|
|
|
292
341
|
if timeout_s is None:
|
|
@@ -299,46 +348,23 @@ class FelderaClient:
|
|
|
299
348
|
if not wait:
|
|
300
349
|
return
|
|
301
350
|
|
|
302
|
-
|
|
351
|
+
self.__wait_for_pipeline_state(pipeline_name, "running", timeout_s)
|
|
303
352
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
resp = self.get_pipeline(pipeline_name)
|
|
313
|
-
status = resp.deployment_status
|
|
314
|
-
|
|
315
|
-
if status == "Running":
|
|
316
|
-
break
|
|
317
|
-
elif (
|
|
318
|
-
status == "Stopped"
|
|
319
|
-
and len(resp.deployment_error or {}) > 0
|
|
320
|
-
and resp.deployment_desired_status == "Stopped"
|
|
321
|
-
):
|
|
322
|
-
raise RuntimeError(
|
|
323
|
-
f"""Unable to ACTIVATE the pipeline.
|
|
324
|
-
Reason: The pipeline is in a STOPPED state due to the following error:
|
|
325
|
-
{resp.deployment_error.get("message", "")}"""
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
logging.debug(
|
|
329
|
-
"still starting %s, waiting for 100 more milliseconds", pipeline_name
|
|
330
|
-
)
|
|
331
|
-
time.sleep(0.1)
|
|
332
|
-
|
|
333
|
-
def start_pipeline(
|
|
334
|
-
self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
|
|
353
|
+
def _inner_start_pipeline(
|
|
354
|
+
self,
|
|
355
|
+
pipeline_name: str,
|
|
356
|
+
initial: str = "running",
|
|
357
|
+
wait: bool = True,
|
|
358
|
+
timeout_s: Optional[float] = 300,
|
|
335
359
|
):
|
|
336
360
|
"""
|
|
337
361
|
|
|
338
362
|
:param pipeline_name: The name of the pipeline to start
|
|
363
|
+
:param initial: The initial state to start the pipeline in. "running"
|
|
364
|
+
by default.
|
|
339
365
|
:param wait: Set True to wait for the pipeline to start. True by default
|
|
340
|
-
:param timeout_s: The amount of time in seconds to wait for the
|
|
341
|
-
to start. 300 seconds by default.
|
|
366
|
+
:param timeout_s: The amount of time in seconds to wait for the
|
|
367
|
+
pipeline to start. 300 seconds by default.
|
|
342
368
|
"""
|
|
343
369
|
|
|
344
370
|
if timeout_s is None:
|
|
@@ -346,55 +372,64 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
346
372
|
|
|
347
373
|
self.http.post(
|
|
348
374
|
path=f"/pipelines/{pipeline_name}/start",
|
|
375
|
+
params={"initial": initial},
|
|
349
376
|
)
|
|
350
377
|
|
|
351
378
|
if not wait:
|
|
352
379
|
return
|
|
353
380
|
|
|
354
|
-
|
|
381
|
+
self.__wait_for_pipeline_state(pipeline_name, initial, timeout_s)
|
|
355
382
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
raise TimeoutError(
|
|
361
|
-
f"Timed out waiting for pipeline {pipeline_name} to start"
|
|
362
|
-
)
|
|
383
|
+
def start_pipeline(
|
|
384
|
+
self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
|
|
385
|
+
):
|
|
386
|
+
"""
|
|
363
387
|
|
|
364
|
-
|
|
365
|
-
|
|
388
|
+
:param pipeline_name: The name of the pipeline to start
|
|
389
|
+
:param wait: Set True to wait for the pipeline to start.
|
|
390
|
+
True by default
|
|
391
|
+
:param timeout_s: The amount of time in seconds to wait for the
|
|
392
|
+
pipeline to start. 300 seconds by default.
|
|
393
|
+
"""
|
|
366
394
|
|
|
367
|
-
|
|
368
|
-
break
|
|
369
|
-
elif (
|
|
370
|
-
status == "Stopped"
|
|
371
|
-
and len(resp.deployment_error or {}) > 0
|
|
372
|
-
and resp.deployment_desired_status == "Stopped"
|
|
373
|
-
):
|
|
374
|
-
raise RuntimeError(
|
|
375
|
-
f"""Unable to START the pipeline.
|
|
376
|
-
Reason: The pipeline is in a STOPPED state due to the following error:
|
|
377
|
-
{resp.deployment_error.get("message", "")}"""
|
|
378
|
-
)
|
|
395
|
+
self._inner_start_pipeline(pipeline_name, "running", wait, timeout_s)
|
|
379
396
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
397
|
+
def start_pipeline_as_paused(
|
|
398
|
+
self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
|
|
399
|
+
):
|
|
400
|
+
"""
|
|
401
|
+
:param pipeline_name: The name of the pipeline to start as paused.
|
|
402
|
+
:param wait: Set True to wait for the pipeline to start as pause.
|
|
403
|
+
True by default
|
|
404
|
+
:param timeout_s: The amount of time in seconds to wait for the
|
|
405
|
+
pipeline to start. 300 seconds by default.
|
|
406
|
+
"""
|
|
384
407
|
|
|
385
|
-
|
|
408
|
+
self._inner_start_pipeline(pipeline_name, "paused", wait, timeout_s)
|
|
409
|
+
|
|
410
|
+
def start_pipeline_as_standby(
|
|
411
|
+
self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
|
|
412
|
+
):
|
|
413
|
+
"""
|
|
414
|
+
:param pipeline_name: The name of the pipeline to start as standby.
|
|
415
|
+
:param wait: Set True to wait for the pipeline to start as standby.
|
|
416
|
+
True by default
|
|
417
|
+
:param timeout_s: The amount of time in seconds to wait for the
|
|
418
|
+
pipeline to start. 300 seconds by default.
|
|
419
|
+
"""
|
|
420
|
+
|
|
421
|
+
self._inner_start_pipeline(pipeline_name, "paused", wait, timeout_s)
|
|
422
|
+
|
|
423
|
+
def resume_pipeline(
|
|
386
424
|
self,
|
|
387
425
|
pipeline_name: str,
|
|
388
|
-
error_message: str = None,
|
|
389
426
|
wait: bool = True,
|
|
390
427
|
timeout_s: Optional[float] = 300,
|
|
391
428
|
):
|
|
392
429
|
"""
|
|
393
|
-
|
|
430
|
+
Resume a pipeline
|
|
394
431
|
|
|
395
432
|
:param pipeline_name: The name of the pipeline to stop
|
|
396
|
-
:param error_message: The error message to show if the pipeline is in
|
|
397
|
-
STOPPED state due to a failure.
|
|
398
433
|
:param wait: Set True to wait for the pipeline to pause. True by default
|
|
399
434
|
:param timeout_s: The amount of time in seconds to wait for the pipeline
|
|
400
435
|
to pause. 300 seconds by default.
|
|
@@ -404,45 +439,42 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
404
439
|
timeout_s = 300
|
|
405
440
|
|
|
406
441
|
self.http.post(
|
|
407
|
-
path=f"/pipelines/{pipeline_name}/
|
|
442
|
+
path=f"/pipelines/{pipeline_name}/resume",
|
|
408
443
|
)
|
|
409
444
|
|
|
410
445
|
if not wait:
|
|
411
446
|
return
|
|
412
447
|
|
|
413
|
-
|
|
414
|
-
error_message = "Unable to PAUSE the pipeline.\n"
|
|
448
|
+
self.__wait_for_pipeline_state(pipeline_name, "running", timeout_s)
|
|
415
449
|
|
|
416
|
-
|
|
450
|
+
def pause_pipeline(
|
|
451
|
+
self,
|
|
452
|
+
pipeline_name: str,
|
|
453
|
+
wait: bool = True,
|
|
454
|
+
timeout_s: Optional[float] = 300,
|
|
455
|
+
):
|
|
456
|
+
"""
|
|
457
|
+
Pause a pipeline
|
|
417
458
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
459
|
+
:param pipeline_name: The name of the pipeline to stop
|
|
460
|
+
:param error_message: The error message to show if the pipeline is in
|
|
461
|
+
STOPPED state due to a failure.
|
|
462
|
+
:param wait: Set True to wait for the pipeline to pause. True by default
|
|
463
|
+
:param timeout_s: The amount of time in seconds to wait for the pipeline
|
|
464
|
+
to pause. 300 seconds by default.
|
|
465
|
+
"""
|
|
425
466
|
|
|
426
|
-
|
|
427
|
-
|
|
467
|
+
if timeout_s is None:
|
|
468
|
+
timeout_s = 300
|
|
428
469
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
status == "Stopped"
|
|
433
|
-
and len(resp.deployment_error or {}) > 0
|
|
434
|
-
and resp.deployment_desired_status == "Stopped"
|
|
435
|
-
):
|
|
436
|
-
raise RuntimeError(
|
|
437
|
-
error_message
|
|
438
|
-
+ f"""Reason: The pipeline is in a STOPPED state due to the following error:
|
|
439
|
-
{resp.deployment_error.get("message", "")}"""
|
|
440
|
-
)
|
|
470
|
+
self.http.post(
|
|
471
|
+
path=f"/pipelines/{pipeline_name}/pause",
|
|
472
|
+
)
|
|
441
473
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
474
|
+
if not wait:
|
|
475
|
+
return
|
|
476
|
+
|
|
477
|
+
self.__wait_for_pipeline_state(pipeline_name, "paused", timeout_s)
|
|
446
478
|
|
|
447
479
|
def stop_pipeline(
|
|
448
480
|
self,
|
|
@@ -478,7 +510,9 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
478
510
|
start = time.monotonic()
|
|
479
511
|
|
|
480
512
|
while time.monotonic() - start < timeout_s:
|
|
481
|
-
status = self.get_pipeline(
|
|
513
|
+
status = self.get_pipeline(
|
|
514
|
+
pipeline_name, PipelineFieldSelector.STATUS
|
|
515
|
+
).deployment_status
|
|
482
516
|
|
|
483
517
|
if status == "Stopped":
|
|
484
518
|
return
|
|
@@ -512,7 +546,9 @@ Reason: The pipeline is in a STOPPED state due to the following error:
|
|
|
512
546
|
start = time.monotonic()
|
|
513
547
|
|
|
514
548
|
while time.monotonic() - start < timeout_s:
|
|
515
|
-
status = self.get_pipeline(
|
|
549
|
+
status = self.get_pipeline(
|
|
550
|
+
pipeline_name, PipelineFieldSelector.STATUS
|
|
551
|
+
).storage_status
|
|
516
552
|
|
|
517
553
|
if status == "Cleared":
|
|
518
554
|
return
|
|
@@ -47,6 +47,9 @@ class Pipeline:
|
|
|
47
47
|
self.program_version: Optional[int] = None
|
|
48
48
|
self.deployment_config: Optional[dict] = None
|
|
49
49
|
self.deployment_desired_status: Optional[str] = None
|
|
50
|
+
self.deployment_desired_status_since: Optional[str] = None
|
|
51
|
+
self.deployment_id: Optional[str] = None
|
|
52
|
+
self.deployment_initial: Optional[str] = None
|
|
50
53
|
self.deployment_error: Optional[dict] = None
|
|
51
54
|
self.deployment_location: Optional[str] = None
|
|
52
55
|
self.program_info: Optional[dict] = (
|
|
@@ -57,6 +60,16 @@ class Pipeline:
|
|
|
57
60
|
self.program_error: Optional[dict] = None
|
|
58
61
|
self.storage_status: Optional[str] = None
|
|
59
62
|
|
|
63
|
+
self.deployment_resources_desired_status: Optional[str] = None
|
|
64
|
+
self.deployment_resources_desired_status_since: Optional[str] = None
|
|
65
|
+
self.deployment_resources_status: Optional[str] = None
|
|
66
|
+
self.deployment_resources_status_since: Optional[str] = None
|
|
67
|
+
|
|
68
|
+
self.deployment_runtime_desired_status: Optional[str] = None
|
|
69
|
+
self.deployment_runtime_desired_status_since: Optional[str] = None
|
|
70
|
+
self.deployment_runtime_status: Optional[str] = None
|
|
71
|
+
self.deployment_runtime_status_since: Optional[str] = None
|
|
72
|
+
|
|
60
73
|
@classmethod
|
|
61
74
|
def from_dict(cls, d: Mapping[str, Any]):
|
|
62
75
|
pipeline = cls("", "", "", "", {}, {})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|