peak-sdk 1.4.0__py3-none-any.whl → 1.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.
Files changed (50) hide show
  1. peak/_metadata.py +58 -3
  2. peak/_version.py +1 -1
  3. peak/cli/cli.py +4 -2
  4. peak/cli/helpers.py +2 -0
  5. peak/cli/press/blocks/specs.py +2 -2
  6. peak/cli/press/specs.py +4 -2
  7. peak/cli/resources/alerts/__init__.py +35 -0
  8. peak/cli/resources/alerts/emails.py +360 -0
  9. peak/cli/resources/images.py +1 -1
  10. peak/cli/resources/services.py +23 -0
  11. peak/cli/resources/users.py +71 -0
  12. peak/cli/resources/workflows.py +77 -15
  13. peak/cli/ruff.toml +5 -3
  14. peak/compression.py +2 -2
  15. peak/exceptions.py +4 -6
  16. peak/handler.py +3 -5
  17. peak/helpers.py +35 -9
  18. peak/output.py +2 -2
  19. peak/press/apps.py +8 -16
  20. peak/press/blocks.py +8 -16
  21. peak/press/deployments.py +2 -4
  22. peak/press/specs.py +12 -14
  23. peak/resources/__init__.py +3 -2
  24. peak/resources/alerts.py +309 -0
  25. peak/resources/artifacts.py +2 -4
  26. peak/resources/images.py +8 -14
  27. peak/resources/services.py +7 -6
  28. peak/resources/users.py +93 -0
  29. peak/resources/webapps.py +3 -5
  30. peak/resources/workflows.py +106 -16
  31. peak/sample_yaml/resources/emails/send_email.yaml +15 -0
  32. peak/sample_yaml/resources/services/create_or_update_service.yaml +1 -0
  33. peak/sample_yaml/resources/services/create_service.yaml +1 -0
  34. peak/sample_yaml/resources/services/update_service.yaml +1 -0
  35. peak/sample_yaml/resources/workflows/create_or_update_workflow.yaml +28 -0
  36. peak/sample_yaml/resources/workflows/create_workflow.yaml +10 -0
  37. peak/sample_yaml/resources/workflows/patch_workflow.yaml +28 -0
  38. peak/sample_yaml/resources/workflows/update_workflow.yaml +28 -0
  39. peak/session.py +7 -4
  40. peak/telemetry.py +1 -1
  41. peak/template.py +6 -4
  42. peak/tools/logging/__init__.py +26 -268
  43. peak/tools/logging/log_level.py +35 -3
  44. peak/tools/logging/logger.py +389 -0
  45. peak/validators.py +34 -2
  46. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/METADATA +11 -12
  47. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/RECORD +50 -43
  48. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/WHEEL +1 -1
  49. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/LICENSE +0 -0
  50. {peak_sdk-1.4.0.dist-info → peak_sdk-1.6.0.dist-info}/entry_points.txt +0 -0
@@ -19,6 +19,7 @@
19
19
  # # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
20
20
  #
21
21
  """Workflow client module."""
22
+
22
23
  from __future__ import annotations
23
24
 
24
25
  from typing import Any, Dict, Iterator, List, Literal, Optional, overload
@@ -51,8 +52,7 @@ class Workflow(BaseClient):
51
52
  name: Optional[str] = None,
52
53
  *,
53
54
  return_iterator: Literal[False],
54
- ) -> Dict[str, Any]:
55
- ...
55
+ ) -> Dict[str, Any]: ...
56
56
 
57
57
  @overload
58
58
  def list_workflows(
@@ -65,8 +65,7 @@ class Workflow(BaseClient):
65
65
  name: Optional[str] = None,
66
66
  *,
67
67
  return_iterator: Literal[True] = True,
68
- ) -> Iterator[Dict[str, Any]]:
69
- ...
68
+ ) -> Iterator[Dict[str, Any]]: ...
70
69
 
71
70
  def list_workflows(
72
71
  self: Workflow,
@@ -166,10 +165,30 @@ class Workflow(BaseClient):
166
165
  "runtimeExceeded": "number"
167
166
  },
168
167
  "user": "string",
168
+ },
169
+ {
170
+ "events": {
171
+ "success": "boolean",
172
+ "fail": "boolean",
173
+ "runtimeExceeded": "number"
174
+ },
169
175
  "webhook": {
170
176
  "name": "string(required)",
171
177
  "url": "string(required)",
172
- "payload": "string(required)",
178
+ "payload": "string(required)"
179
+ }
180
+ },
181
+ {
182
+ "events": {
183
+ "success": "boolean",
184
+ "fail": "boolean",
185
+ "runtimeExceeded": "number"
186
+ },
187
+ "email": {
188
+ "name": "string",
189
+ "recipients": {
190
+ "to": ["string"]
191
+ }
173
192
  }
174
193
  }
175
194
  ],
@@ -295,10 +314,30 @@ class Workflow(BaseClient):
295
314
  "runtimeExceeded": "number"
296
315
  },
297
316
  "user": "string",
317
+ },
318
+ {
319
+ "events": {
320
+ "success": "boolean",
321
+ "fail": "boolean",
322
+ "runtimeExceeded": "number"
323
+ },
298
324
  "webhook": {
299
325
  "name": "string(required)",
300
326
  "url": "string(required)",
301
- "payload": "string(required)",
327
+ "payload": "string(required)"
328
+ }
329
+ },
330
+ {
331
+ "events": {
332
+ "success": "boolean",
333
+ "fail": "boolean",
334
+ "runtimeExceeded": "number"
335
+ },
336
+ "email": {
337
+ "name": "string",
338
+ "recipients": {
339
+ "to": ["string"]
340
+ }
302
341
  }
303
342
  }
304
343
  ],
@@ -382,7 +421,7 @@ class Workflow(BaseClient):
382
421
  ForbiddenException: The user does not have permission to perform the operation.
383
422
  InternalServerErrorException: The server failed to process the request.
384
423
  """
385
- workflow_name = body["name"] if "name" in body else ""
424
+ workflow_name = body.get("name", "")
386
425
  response = (
387
426
  {}
388
427
  if not len(workflow_name)
@@ -463,10 +502,30 @@ class Workflow(BaseClient):
463
502
  "runtimeExceeded": "number"
464
503
  },
465
504
  "user": "string",
505
+ },
506
+ {
507
+ "events": {
508
+ "success": "boolean",
509
+ "fail": "boolean",
510
+ "runtimeExceeded": "number"
511
+ },
466
512
  "webhook": {
467
513
  "name": "string(required)",
468
514
  "url": "string(required)",
469
- "payload": "string(required)",
515
+ "payload": "string(required)"
516
+ }
517
+ },
518
+ {
519
+ "events": {
520
+ "success": "boolean",
521
+ "fail": "boolean",
522
+ "runtimeExceeded": "number"
523
+ },
524
+ "email": {
525
+ "name": "string",
526
+ "recipients": {
527
+ "to": ["string"]
528
+ }
470
529
  }
471
530
  }
472
531
  ],
@@ -624,10 +683,30 @@ class Workflow(BaseClient):
624
683
  "runtimeExceeded": "number"
625
684
  },
626
685
  "user": "string",
686
+ },
687
+ {
688
+ "events": {
689
+ "success": "boolean",
690
+ "fail": "boolean",
691
+ "runtimeExceeded": "number"
692
+ },
627
693
  "webhook": {
628
694
  "name": "string(required)",
629
695
  "url": "string(required)",
630
- "payload": "string(required)",
696
+ "payload": "string(required)"
697
+ }
698
+ },
699
+ {
700
+ "events": {
701
+ "success": "boolean",
702
+ "fail": "boolean",
703
+ "runtimeExceeded": "number"
704
+ },
705
+ "email": {
706
+ "name": "string",
707
+ "recipients": {
708
+ "to": ["string"]
709
+ }
631
710
  }
632
711
  }
633
712
  ],
@@ -961,12 +1040,13 @@ class Workflow(BaseClient):
961
1040
  workflow_id: int,
962
1041
  date_from: Optional[str] = None,
963
1042
  date_to: Optional[str] = None,
1043
+ status: Optional[List[str]] = None,
1044
+ count: Optional[int] = None,
964
1045
  page_size: Optional[int] = None,
965
1046
  page_number: Optional[int] = None,
966
1047
  *,
967
1048
  return_iterator: Literal[False],
968
- ) -> Dict[str, Any]:
969
- ...
1049
+ ) -> Dict[str, Any]: ...
970
1050
 
971
1051
  @overload
972
1052
  def list_executions(
@@ -974,18 +1054,21 @@ class Workflow(BaseClient):
974
1054
  workflow_id: int,
975
1055
  date_from: Optional[str] = None,
976
1056
  date_to: Optional[str] = None,
1057
+ status: Optional[List[str]] = None,
1058
+ count: Optional[int] = None,
977
1059
  page_size: Optional[int] = None,
978
1060
  page_number: Optional[int] = None,
979
1061
  *,
980
1062
  return_iterator: Literal[True] = True,
981
- ) -> Iterator[Dict[str, Any]]:
982
- ...
1063
+ ) -> Iterator[Dict[str, Any]]: ...
983
1064
 
984
1065
  def list_executions(
985
1066
  self: Workflow,
986
1067
  workflow_id: int,
987
1068
  date_from: Optional[str] = None,
988
1069
  date_to: Optional[str] = None,
1070
+ status: Optional[List[str]] = None,
1071
+ count: Optional[int] = None,
989
1072
  page_size: Optional[int] = None,
990
1073
  page_number: Optional[int] = None,
991
1074
  *,
@@ -1000,6 +1083,11 @@ class Workflow(BaseClient):
1000
1083
  workflow_id (int): ID of the workflow to fetch executions.
1001
1084
  date_from (str | None): The date after which the executions should be included (in ISO format). Defaults to None
1002
1085
  date_to (str | None): The date till which the executions should be included (in ISO format). Defaults to None
1086
+ status (List[str] | None): The status of the executions to filter by.
1087
+ Valid values are `Success`, `Running`, `Stopped`, `Stopping` and `Failed`.
1088
+ count (int | None): Number of executions required in the provided time range or 90 days (Ordered by latest to earliest).
1089
+ For example, if 5 is provided, it will return last 5 workflow executions.
1090
+ By default, it will return all the executions.
1003
1091
  page_size (int | None): Number of executions per page.
1004
1092
  page_number (int | None): Page number to fetch. Only used when return_iterator is False.
1005
1093
  return_iterator (bool): Whether to return an iterator object or list of executions for a specified page number, defaults to True.
@@ -1011,7 +1099,7 @@ class Workflow(BaseClient):
1011
1099
  Set `return_iterator` to True if you want automatic client-side pagination, or False if you want server-side pagination.
1012
1100
 
1013
1101
  Raises:
1014
- BadRequestException: BadRequestException: The given request parameters are invalid.
1102
+ BadRequestException: The given request parameters are invalid.
1015
1103
  UnauthorizedException: The credentials are invalid.
1016
1104
  ForbiddenException: The user does not have permission to perform the operation.
1017
1105
  NotFoundException: The given workflow does not exist.
@@ -1021,6 +1109,8 @@ class Workflow(BaseClient):
1021
1109
  method, endpoint = HttpMethods.GET, f"{self.BASE_ENDPOINT}/workflows/executions/{workflow_id}"
1022
1110
 
1023
1111
  params: Dict[str, Any] = {
1112
+ "count": count,
1113
+ "statuses": status,
1024
1114
  "dateTo": date_to,
1025
1115
  "dateFrom": date_from,
1026
1116
  "pageSize": page_size,
@@ -1068,7 +1158,7 @@ class Workflow(BaseClient):
1068
1158
  Dict[str, Any]: A dictionary containing the logs for the given execution.
1069
1159
 
1070
1160
  Raises:
1071
- BadRequestException: BadRequestException: The given request parameters are invalid.
1161
+ BadRequestException: The given request parameters are invalid.
1072
1162
  UnauthorizedException: The credentials are invalid.
1073
1163
  ForbiddenException: The user does not have permission to perform the operation.
1074
1164
  NotFoundException: The given workflow does not exist.
@@ -1123,7 +1213,7 @@ class Workflow(BaseClient):
1123
1213
  Dict[str, Any]: A dictionary containing the logs for the given execution.
1124
1214
 
1125
1215
  Raises:
1126
- BadRequestException: BadRequestException: The given request parameters are invalid.
1216
+ BadRequestException: The given request parameters are invalid.
1127
1217
  UnauthorizedException: The credentials are invalid.
1128
1218
  ForbiddenException: The user does not have permission to perform the operation.
1129
1219
  NotFoundException: The given workflow does not exist.
@@ -0,0 +1,15 @@
1
+ # send_email.yaml
2
+
3
+ body:
4
+ recipients:
5
+ - person1@peak.ai
6
+ - person2@peak.ai
7
+ cc:
8
+ - person3@peak.ai
9
+ bcc:
10
+ - person4@peak.ai
11
+ subject: Hello from Peak
12
+ templateName: my-email-template
13
+ templateParameters:
14
+ name: John
15
+ company: Peak
@@ -22,3 +22,4 @@ body:
22
22
  python
23
23
  app.py
24
24
  healthCheckURL: /health
25
+ minInstances: 1
@@ -22,3 +22,4 @@ body:
22
22
  python
23
23
  app.py
24
24
  healthCheckURL: /health
25
+ minInstances: 1
@@ -20,3 +20,4 @@ body:
20
20
  python
21
21
  app.py
22
22
  healthCheckURL: /health
23
+ minInstances: 1
@@ -4,6 +4,34 @@ body:
4
4
  name: my-new-workflow
5
5
  triggers:
6
6
  - webhook: true
7
+ watchers:
8
+ - user: abc@peak.ai
9
+ events:
10
+ success: false
11
+ fail: true
12
+ - webhook:
13
+ name: info
14
+ url: "https://abc.com/post"
15
+ payload: '{ "pingback-url": "https:/workflow/123" }'
16
+ events:
17
+ success: false
18
+ fail: true
19
+ runtimeExceeded: 10
20
+ - email:
21
+ name: "email-watcher-1"
22
+ recipients:
23
+ to:
24
+ - user1@peak.ai
25
+ - user2@peak.ai
26
+ events:
27
+ success: false
28
+ fail: true
29
+ runtimeExceeded: 10
30
+ retryOptions:
31
+ duration: 5
32
+ exitCodes: [1, 2]
33
+ exponentialBackoff: true
34
+ numberOfRetries: 3
7
35
  tags:
8
36
  - name: CLI
9
37
  steps:
@@ -17,6 +17,16 @@ body:
17
17
  success: false
18
18
  fail: true
19
19
  runtimeExceeded: 10
20
+ - email:
21
+ name: "email-watcher-1"
22
+ recipients:
23
+ to:
24
+ - user1@peak.ai
25
+ - user2@peak.ai
26
+ events:
27
+ success: false
28
+ fail: true
29
+ runtimeExceeded: 10
20
30
  retryOptions:
21
31
  duration: 5
22
32
  exitCodes: [1, 2]
@@ -4,6 +4,34 @@ body:
4
4
  name: "updated-workflow"
5
5
  triggers:
6
6
  - {}
7
+ watchers:
8
+ - user: abc@peak.ai
9
+ events:
10
+ success: false
11
+ fail: true
12
+ - webhook:
13
+ name: info
14
+ url: "https://abc.com/post"
15
+ payload: '{ "pingback-url": "https:/workflow/123" }'
16
+ events:
17
+ success: false
18
+ fail: true
19
+ runtimeExceeded: 10
20
+ - email:
21
+ name: "email-watcher-1"
22
+ recipients:
23
+ to:
24
+ - user1@peak.ai
25
+ - user2@peak.ai
26
+ events:
27
+ success: false
28
+ fail: true
29
+ runtimeExceeded: 10
30
+ retryOptions:
31
+ duration: 5
32
+ exitCodes: [1, 2]
33
+ exponentialBackoff: true
34
+ numberOfRetries: 3
7
35
  steps:
8
36
  step1:
9
37
  imageId: 100
@@ -4,6 +4,34 @@ body:
4
4
  name: updated-workflow
5
5
  triggers:
6
6
  - webhook: true
7
+ watchers:
8
+ - user: abc@peak.ai
9
+ events:
10
+ success: false
11
+ fail: true
12
+ - webhook:
13
+ name: info
14
+ url: "https://abc.com/post"
15
+ payload: '{ "pingback-url": "https:/workflow/123" }'
16
+ events:
17
+ success: false
18
+ fail: true
19
+ runtimeExceeded: 10
20
+ - email:
21
+ name: "email-watcher-1"
22
+ recipients:
23
+ to:
24
+ - user1@peak.ai
25
+ - user2@peak.ai
26
+ events:
27
+ success: false
28
+ fail: true
29
+ runtimeExceeded: 10
30
+ retryOptions:
31
+ duration: 5
32
+ exitCodes: [1, 2]
33
+ exponentialBackoff: true
34
+ numberOfRetries: 3
7
35
  tags:
8
36
  - name: CLI
9
37
  steps:
peak/session.py CHANGED
@@ -70,7 +70,7 @@ class Session:
70
70
 
71
71
  Args:
72
72
  auth_token (str | None): Authentication token. Both API Key and Bearer tokens are supported.
73
- Picks up from `API_KEY` environment variable if not provided.
73
+ Picks up from `PEAK_AUTH_TOKEN` or `API_KEY` environment variable if not provided.
74
74
  stage (str | None): Name of the stage where tenant is created. Default is `prod`.
75
75
  """
76
76
  self.base_domain: str = ""
@@ -238,9 +238,12 @@ class Session:
238
238
  self.auth_token = auth_token
239
239
  return
240
240
 
241
- logger.info("auth_token not given, searching for API_KEY in env variables")
242
- if not os.environ.get("API_KEY"):
243
- raise exceptions.MissingEnvironmentVariableException(env_var="API_KEY")
241
+ logger.info("auth_token not given, searching for 'PEAK_AUTH_TOKEN' or 'API_KEY' in env variables")
242
+ if not os.environ.get("API_KEY") and not os.environ.get("PEAK_AUTH_TOKEN"):
243
+ raise exceptions.MissingEnvironmentVariableException(env_var="PEAK_AUTH_TOKEN or API_KEY")
244
+ if os.environ.get("PEAK_AUTH_TOKEN"):
245
+ self.auth_token = os.environ["PEAK_AUTH_TOKEN"]
246
+ return
244
247
  self.auth_token = os.environ["API_KEY"]
245
248
 
246
249
  def _set_stage(self, stage: Optional[str]) -> None:
peak/telemetry.py CHANGED
@@ -80,7 +80,7 @@ def telemetry(make_request: F) -> F:
80
80
  """
81
81
  stage = Stage.PROD
82
82
  if session_meta:
83
- stage = session_meta["stage"] if "stage" in session_meta else Stage.PROD
83
+ stage = session_meta.get("stage", Stage.PROD)
84
84
  base_domain = get_base_domain(stage.value, "service")
85
85
  return f"{base_domain}/resource-usage/api/v1/telemetry"
86
86
 
peak/template.py CHANGED
@@ -38,10 +38,12 @@ from peak.helpers import remove_none_values
38
38
  def _parse_jinja_template(template_path: Path, params: Dict[str, Any]) -> str:
39
39
  """Read, parse and render the Jinja template text."""
40
40
  jinja_loader = _CustomJinjaLoader()
41
- jinja_env = jinja2.Environment( # TODO: show warning if variable not found in params # noqa: TD002, TD003, RUF100
42
- loader=jinja_loader,
43
- autoescape=False, # noqa: S701
44
- extensions=[_IncludeWithIndentation],
41
+ jinja_env = (
42
+ jinja2.Environment( # TODO: show warning if variable not found in params # noqa: TD002, TD003, RUF100, FIX002
43
+ loader=jinja_loader,
44
+ autoescape=False, # noqa: S701
45
+ extensions=[_IncludeWithIndentation],
46
+ )
45
47
  )
46
48
  jinja_template: jinja2.Template = jinja_env.get_template(str(template_path))
47
49
  return jinja_template.render(params, os_env=os.environ)