peak-sdk 1.3.0__py3-none-any.whl → 1.4.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.
- peak/__init__.py +1 -1
- peak/_metadata.py +43 -0
- peak/_version.py +1 -1
- peak/cli/cli.py +2 -1
- peak/cli/helpers.py +26 -0
- peak/cli/press/blocks/specs.py +0 -2
- peak/cli/resources/services.py +632 -0
- peak/cli/resources/webapps.py +75 -14
- peak/cli/resources/workflows.py +0 -4
- peak/output.py +9 -0
- peak/press/blocks.py +10 -15
- peak/resources/__init__.py +2 -2
- peak/resources/services.py +413 -0
- peak/resources/webapps.py +13 -7
- peak/resources/workflows.py +0 -4
- peak/sample_yaml/resources/services/create_or_update_service.yaml +24 -0
- peak/sample_yaml/resources/services/create_service.yaml +24 -0
- peak/sample_yaml/resources/services/test_service.yaml +8 -0
- peak/sample_yaml/resources/services/update_service.yaml +22 -0
- peak/sample_yaml/resources/workflows/create_or_update_workflow.yaml +0 -1
- peak/sample_yaml/resources/workflows/update_workflow.yaml +0 -1
- peak/template.py +2 -2
- {peak_sdk-1.3.0.dist-info → peak_sdk-1.4.0.dist-info}/LICENSE +1 -1
- {peak_sdk-1.3.0.dist-info → peak_sdk-1.4.0.dist-info}/METADATA +1 -1
- {peak_sdk-1.3.0.dist-info → peak_sdk-1.4.0.dist-info}/RECORD +27 -21
- {peak_sdk-1.3.0.dist-info → peak_sdk-1.4.0.dist-info}/WHEEL +0 -0
- {peak_sdk-1.3.0.dist-info → peak_sdk-1.4.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,632 @@
|
|
1
|
+
#
|
2
|
+
# # Copyright © 2024 Peak AI Limited. or its affiliates. All Rights Reserved.
|
3
|
+
# #
|
4
|
+
# # Licensed under the Apache License, Version 2.0 (the "License"). You
|
5
|
+
# # may not use this file except in compliance with the License. A copy of
|
6
|
+
# # the License is located at:
|
7
|
+
# #
|
8
|
+
# # https://github.com/PeakBI/peak-sdk/blob/main/LICENSE
|
9
|
+
# #
|
10
|
+
# # or in the "license" file accompanying this file. This file is
|
11
|
+
# # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
12
|
+
# # ANY KIND, either express or implied. See the License for the specific
|
13
|
+
# # language governing permissions and limitations under the License.
|
14
|
+
# #
|
15
|
+
# # This file is part of the peak-sdk.
|
16
|
+
# # see (https://github.com/PeakBI/peak-sdk)
|
17
|
+
# #
|
18
|
+
# # You should have received a copy of the APACHE LICENSE, VERSION 2.0
|
19
|
+
# # along with this program. If not, see <https://apache.org/licenses/LICENSE-2.0>
|
20
|
+
#
|
21
|
+
|
22
|
+
#
|
23
|
+
"""Peak Services service commands."""
|
24
|
+
|
25
|
+
import json
|
26
|
+
from typing import Any, Dict, List, Optional
|
27
|
+
|
28
|
+
import typer
|
29
|
+
from peak.cli import args, helpers
|
30
|
+
from peak.cli.args import DRY_RUN, GENERATE_YAML, OUTPUT_TYPES, PAGING
|
31
|
+
from peak.constants import OutputTypes, OutputTypesNoTable
|
32
|
+
from peak.helpers import combine_dictionaries, map_user_options, parse_list_of_strings, variables_to_dict
|
33
|
+
from peak.output import Writer
|
34
|
+
from peak.resources.services import Service
|
35
|
+
from typing_extensions import Annotated
|
36
|
+
|
37
|
+
app = typer.Typer(
|
38
|
+
help="Develop web services to deliver insights, suggestions and recommendations.",
|
39
|
+
short_help="Create and Manage Services.",
|
40
|
+
)
|
41
|
+
|
42
|
+
_SERVICE_ID = typer.Argument(..., help="ID of the service to be used in this operation.")
|
43
|
+
|
44
|
+
_SERVICE_NAME = typer.Argument(..., help="Name of the service to be used in this operation.")
|
45
|
+
|
46
|
+
_LIST_STATUS = typer.Option(
|
47
|
+
None,
|
48
|
+
help="A list of service status to filter the list by. Valid values are `CREATING`, `DEPLOYING`, `AVAILABLE`, `DELETING`, `CREATE_FAILED`, `DELETE_FAILED`.",
|
49
|
+
)
|
50
|
+
|
51
|
+
_SERVICE_TYPE = typer.Option(
|
52
|
+
None,
|
53
|
+
help="A list of service types to filter the list by. Valid values are `api`, `web-app` and `shiny`.",
|
54
|
+
)
|
55
|
+
|
56
|
+
_LIST_NAME = typer.Option(None, help="Service name to search for.")
|
57
|
+
|
58
|
+
FILE_HELP_STRING = (
|
59
|
+
"Path to the file that defines the body for this operation, supports both `yaml` file or a `jinja` template."
|
60
|
+
)
|
61
|
+
|
62
|
+
NAME = typer.Option(None, help="Name of the service")
|
63
|
+
|
64
|
+
DESCRIPTION = typer.Option(None, help="Description of the service")
|
65
|
+
|
66
|
+
TITLE = typer.Option(None, help="Title of the service")
|
67
|
+
|
68
|
+
IMAGE_ID = typer.Option(None, help="ID of the image to be used in this operation.")
|
69
|
+
|
70
|
+
VERSION_ID = typer.Option(
|
71
|
+
None,
|
72
|
+
help="ID of the version to be used in this operation. If version-id is not passed, service will be created using latest ready version of the image.",
|
73
|
+
)
|
74
|
+
|
75
|
+
INSTANCE_TYPE_ID = typer.Option(None, help="The ID of the instance type to be used in this operation.")
|
76
|
+
|
77
|
+
SESSION_STICKINESS = typer.Option(
|
78
|
+
None,
|
79
|
+
help="Enable session stickiness for the service. Not required for API type services.",
|
80
|
+
)
|
81
|
+
|
82
|
+
_ENVS = typer.Option(None, help="List of plain text environment variables in the format arg1=value1.")
|
83
|
+
|
84
|
+
_SECRETS = typer.Option(None, help="List of secret names to be passed as environment variables.")
|
85
|
+
|
86
|
+
_ENTRYPOINT = typer.Option(None, help="Entrypoint for the service.")
|
87
|
+
|
88
|
+
_HEALTH_CHECK_URL = typer.Option(None, help="Endpoint to monitor service's operational status.")
|
89
|
+
|
90
|
+
_HTTP_METHOD = typer.Option(None, help="HTTP method to be used to test the service.")
|
91
|
+
|
92
|
+
_PATH = typer.Option(None, help="Path to be used to test the service.")
|
93
|
+
|
94
|
+
_PAYLOAD = typer.Option(None, help="Payload to be used to test the service. To be passed in stringified json format.")
|
95
|
+
|
96
|
+
MAPPING = {
|
97
|
+
"imageId": "imageDetails",
|
98
|
+
"versionId": "imageDetails",
|
99
|
+
"instanceTypeId": "resources",
|
100
|
+
"env": "parameters",
|
101
|
+
"secrets": "parameters", # pragma: allowlist secret
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
@app.command("list", short_help="List services.", options_metavar="list_services")
|
106
|
+
def list_services(
|
107
|
+
ctx: typer.Context,
|
108
|
+
page_size: Optional[int] = args.PAGE_SIZE,
|
109
|
+
page_number: Optional[int] = args.PAGE_NUMBER,
|
110
|
+
status: Optional[List[str]] = _LIST_STATUS,
|
111
|
+
name: Optional[str] = _LIST_NAME,
|
112
|
+
service_type: Optional[List[str]] = _SERVICE_TYPE,
|
113
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
114
|
+
output_type: Optional[OutputTypes] = OUTPUT_TYPES, # noqa: ARG001
|
115
|
+
) -> None:
|
116
|
+
"""***List*** all services that exist for the tenant.
|
117
|
+
|
118
|
+
\b
|
119
|
+
📝 ***Example usage:***<br/>
|
120
|
+
```bash
|
121
|
+
peak services list --page-size 10 --page-number 1 --status CREATING --name test --service-type web-app
|
122
|
+
```
|
123
|
+
|
124
|
+
\b
|
125
|
+
🆗 ***Response:***
|
126
|
+
```
|
127
|
+
{
|
128
|
+
"servicesCount": 1,
|
129
|
+
"services": [...],
|
130
|
+
"pageCount": 1,
|
131
|
+
"pageNumber": 1,
|
132
|
+
"pageSize": 25
|
133
|
+
}
|
134
|
+
```
|
135
|
+
|
136
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/list-service)
|
137
|
+
"""
|
138
|
+
service_client: Service = ctx.obj["client"]
|
139
|
+
writer: Writer = ctx.obj["writer"]
|
140
|
+
|
141
|
+
with writer.pager():
|
142
|
+
response = service_client.list_services(
|
143
|
+
page_size=page_size,
|
144
|
+
page_number=page_number,
|
145
|
+
return_iterator=False,
|
146
|
+
status=parse_list_of_strings(status),
|
147
|
+
name=name,
|
148
|
+
service_type=service_type,
|
149
|
+
)
|
150
|
+
writer.write(response)
|
151
|
+
|
152
|
+
|
153
|
+
@app.command(short_help="Create a new service.", options_metavar="create_service")
|
154
|
+
def create(
|
155
|
+
ctx: typer.Context,
|
156
|
+
file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
|
157
|
+
params_file: str = args.TEMPLATE_PARAMS_FILE,
|
158
|
+
params: List[str] = args.TEMPLATE_PARAMS,
|
159
|
+
name: str = NAME,
|
160
|
+
title: str = TITLE,
|
161
|
+
description: str = DESCRIPTION,
|
162
|
+
image_id: int = IMAGE_ID,
|
163
|
+
version_id: int = VERSION_ID,
|
164
|
+
instance_type_id: int = INSTANCE_TYPE_ID,
|
165
|
+
session_stickiness: bool = SESSION_STICKINESS,
|
166
|
+
service_type: Optional[str] = _SERVICE_TYPE,
|
167
|
+
env: Optional[List[str]] = _ENVS,
|
168
|
+
secrets: Optional[List[str]] = _SECRETS,
|
169
|
+
entrypoint: Optional[str] = _ENTRYPOINT,
|
170
|
+
health_check_url: Optional[str] = _HEALTH_CHECK_URL,
|
171
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
172
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
173
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
174
|
+
generate: Optional[bool] = GENERATE_YAML, # noqa: ARG001
|
175
|
+
) -> None:
|
176
|
+
"""***Create*** a new service and start its deployment.
|
177
|
+
|
178
|
+
\b
|
179
|
+
🧩 ***Input file schema(yaml):***<br/>
|
180
|
+
```yaml
|
181
|
+
body (map):
|
182
|
+
name (string): Name of the service.
|
183
|
+
title (string | required: false): Title of the service.
|
184
|
+
description (string | required: false): Description of the service.
|
185
|
+
serviceType (string | required: false): Type of the service. Valid values are `api`, `web-app` and `shiny`. Default value is `web-app`.
|
186
|
+
imageDetails (map):
|
187
|
+
imageId (number): ID of the image.
|
188
|
+
versionId (number | required: false): ID of the image version. If versionId is not passed, service will be created using latest ready version of the image.
|
189
|
+
resources (map | required: false):
|
190
|
+
instanceTypeId (number): ID of the instance type.
|
191
|
+
parameters (map | required: false):
|
192
|
+
env (map | required: false): Key-Value pair where key is the name of the env.
|
193
|
+
secrets (list(str) | required: false): List of secret names to be passed.
|
194
|
+
sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
|
195
|
+
entrypoint (string | required: false): Entrypoint for the service.
|
196
|
+
healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
|
197
|
+
```
|
198
|
+
|
199
|
+
\b
|
200
|
+
📝 ***Example usage:***
|
201
|
+
```bash
|
202
|
+
peak services create '/path/to/file.yml' -v '/path/to/params.yml'
|
203
|
+
```
|
204
|
+
|
205
|
+
\b
|
206
|
+
📝 ***Example usage without yaml:***
|
207
|
+
```bash
|
208
|
+
peak services create --name <name> --title <title> --description <description> --service-type web-app --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
|
209
|
+
```
|
210
|
+
|
211
|
+
\b
|
212
|
+
🆗 ***Response:***
|
213
|
+
```json
|
214
|
+
{
|
215
|
+
"id": "db88c21d-1add-45dd-a72e-8c6b83b68dee"
|
216
|
+
}
|
217
|
+
```
|
218
|
+
|
219
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service)
|
220
|
+
"""
|
221
|
+
service_client: Service = ctx.obj["client"]
|
222
|
+
writer: Writer = ctx.obj["writer"]
|
223
|
+
|
224
|
+
user_options: Dict[str, Any] = variables_to_dict(
|
225
|
+
name,
|
226
|
+
description,
|
227
|
+
title,
|
228
|
+
image_id,
|
229
|
+
version_id,
|
230
|
+
instance_type_id,
|
231
|
+
session_stickiness,
|
232
|
+
service_type,
|
233
|
+
env,
|
234
|
+
secrets,
|
235
|
+
entrypoint,
|
236
|
+
)
|
237
|
+
user_options = map_user_options(user_options, MAPPING)
|
238
|
+
|
239
|
+
body: Dict[str, Any] = {}
|
240
|
+
if file:
|
241
|
+
body = helpers.template_handler(file=file, params_file=params_file, params=params)
|
242
|
+
body = helpers.remove_unknown_args(body, service_client.create_service)
|
243
|
+
|
244
|
+
updated_body = combine_dictionaries(body.get("body") or {}, user_options)
|
245
|
+
|
246
|
+
if env:
|
247
|
+
updated_body["parameters"]["env"] = helpers.parse_envs(env)
|
248
|
+
|
249
|
+
if secrets:
|
250
|
+
updated_body["parameters"]["secrets"] = parse_list_of_strings(secrets)
|
251
|
+
|
252
|
+
if health_check_url:
|
253
|
+
updated_body["healthCheckURL"] = health_check_url
|
254
|
+
|
255
|
+
with writer.pager():
|
256
|
+
response = service_client.create_service(body=updated_body)
|
257
|
+
writer.write(response)
|
258
|
+
|
259
|
+
|
260
|
+
@app.command(short_help="Update an existing service.", options_metavar="update_service")
|
261
|
+
def update(
|
262
|
+
ctx: typer.Context,
|
263
|
+
service_id: str = _SERVICE_ID,
|
264
|
+
file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
|
265
|
+
params_file: str = args.TEMPLATE_PARAMS_FILE,
|
266
|
+
params: List[str] = args.TEMPLATE_PARAMS,
|
267
|
+
title: str = TITLE,
|
268
|
+
description: str = DESCRIPTION,
|
269
|
+
image_id: int = IMAGE_ID,
|
270
|
+
version_id: int = VERSION_ID,
|
271
|
+
instance_type_id: int = INSTANCE_TYPE_ID,
|
272
|
+
session_stickiness: bool = SESSION_STICKINESS,
|
273
|
+
env: Optional[List[str]] = _ENVS,
|
274
|
+
secrets: Optional[List[str]] = _SECRETS,
|
275
|
+
entrypoint: Optional[str] = _ENTRYPOINT,
|
276
|
+
health_check_url: Optional[str] = _HEALTH_CHECK_URL,
|
277
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
278
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
279
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
280
|
+
generate: Optional[bool] = GENERATE_YAML, # noqa: ARG001
|
281
|
+
) -> None:
|
282
|
+
"""***Update*** an existing service.
|
283
|
+
|
284
|
+
\b
|
285
|
+
When updating the service, it will trigger a redeployment only under specific conditions.
|
286
|
+
Redeployment is triggered if you make changes to any of the following parameters: imageId, versionId, instanceTypeId, env, secrets or sessionStickiness.
|
287
|
+
However, only modifying the title or description will not trigger a redeployment.
|
288
|
+
|
289
|
+
With the help of this operation, we can just update the required fields (except name and serviceType) and keep the rest of the fields as it is.
|
290
|
+
|
291
|
+
\b
|
292
|
+
🧩 ***Input file schema(yaml):***<br/>
|
293
|
+
```yaml
|
294
|
+
body (map):
|
295
|
+
title (string | required: false): Title of the service.
|
296
|
+
description (string | required: false): Description of the service.
|
297
|
+
imageDetails (map | required: false):
|
298
|
+
imageId (number): ID of the image.
|
299
|
+
versionId (number | required: false): ID of the image version. If versionId is not passed, service will be created using latest ready version of the image.
|
300
|
+
resources (map | required: false):
|
301
|
+
instanceTypeId (number): ID of the instance type.
|
302
|
+
parameters (map | required: false):
|
303
|
+
env (map | required: false): Key-Value pair where key is the name of the env.
|
304
|
+
secrets (list(str) | required: false): List of secret names to be passed.
|
305
|
+
sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
|
306
|
+
entrypoint (string | required: false): Entrypoint for the service.
|
307
|
+
healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
|
308
|
+
```
|
309
|
+
|
310
|
+
\b
|
311
|
+
📝 ***Example usage:***
|
312
|
+
```bash
|
313
|
+
peak services update <service-id> '/path/to/file.yml' -v '/path/to/params.yml'
|
314
|
+
```
|
315
|
+
|
316
|
+
\b
|
317
|
+
📝 ***Example usage without yaml:***
|
318
|
+
```bash
|
319
|
+
peak services update <service-id> --title <title> --description <description> --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
|
320
|
+
```
|
321
|
+
|
322
|
+
\b
|
323
|
+
🆗 ***Response:***
|
324
|
+
```json
|
325
|
+
{
|
326
|
+
"id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
|
327
|
+
}
|
328
|
+
```
|
329
|
+
|
330
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/update-service)
|
331
|
+
"""
|
332
|
+
service_client: Service = ctx.obj["client"]
|
333
|
+
writer: Writer = ctx.obj["writer"]
|
334
|
+
|
335
|
+
user_options: Dict[str, Any] = variables_to_dict(
|
336
|
+
description,
|
337
|
+
title,
|
338
|
+
image_id,
|
339
|
+
version_id,
|
340
|
+
instance_type_id,
|
341
|
+
session_stickiness,
|
342
|
+
env,
|
343
|
+
secrets,
|
344
|
+
entrypoint,
|
345
|
+
)
|
346
|
+
user_options = map_user_options(user_options, MAPPING)
|
347
|
+
|
348
|
+
body: Dict[str, Any] = {}
|
349
|
+
if file:
|
350
|
+
body = helpers.template_handler(file=file, params_file=params_file, params=params)
|
351
|
+
body = helpers.remove_unknown_args(body, service_client.update_service)
|
352
|
+
|
353
|
+
updated_body = combine_dictionaries(body.get("body") or {}, user_options)
|
354
|
+
|
355
|
+
if env:
|
356
|
+
updated_body["parameters"]["env"] = helpers.parse_envs(env)
|
357
|
+
|
358
|
+
if secrets:
|
359
|
+
updated_body["parameters"]["secrets"] = parse_list_of_strings(secrets)
|
360
|
+
|
361
|
+
if health_check_url:
|
362
|
+
updated_body["healthCheckURL"] = health_check_url
|
363
|
+
|
364
|
+
with writer.pager():
|
365
|
+
response = service_client.update_service(service_id=service_id, body=updated_body)
|
366
|
+
writer.write(response)
|
367
|
+
|
368
|
+
|
369
|
+
@app.command(
|
370
|
+
short_help="Create a new service or Update an existing service.",
|
371
|
+
options_metavar="create_or_update_service",
|
372
|
+
)
|
373
|
+
def create_or_update(
|
374
|
+
ctx: typer.Context,
|
375
|
+
file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
|
376
|
+
params_file: str = args.TEMPLATE_PARAMS_FILE,
|
377
|
+
params: List[str] = args.TEMPLATE_PARAMS,
|
378
|
+
name: str = NAME,
|
379
|
+
title: str = TITLE,
|
380
|
+
description: str = DESCRIPTION,
|
381
|
+
image_id: int = IMAGE_ID,
|
382
|
+
version_id: int = VERSION_ID,
|
383
|
+
instance_type_id: int = INSTANCE_TYPE_ID,
|
384
|
+
session_stickiness: bool = SESSION_STICKINESS,
|
385
|
+
service_type: Optional[str] = _SERVICE_TYPE,
|
386
|
+
env: Optional[List[str]] = _ENVS,
|
387
|
+
secrets: Optional[List[str]] = _SECRETS,
|
388
|
+
entrypoint: Optional[str] = _ENTRYPOINT,
|
389
|
+
health_check_url: Optional[str] = _HEALTH_CHECK_URL,
|
390
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
391
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
392
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
393
|
+
generate: Optional[bool] = GENERATE_YAML, # noqa: ARG001
|
394
|
+
) -> None:
|
395
|
+
"""***Create*** a new service or ***Update*** an existing service based on service name and start its deployment.
|
396
|
+
|
397
|
+
\b
|
398
|
+
When updating the service, it will trigger a redeployment only under specific conditions.
|
399
|
+
Redeployment is triggered if you make changes to any of the following parameters: imageId, versionId, instanceTypeId, env, secrets or sessionStickiness.
|
400
|
+
However, only modifying the title or description will not trigger a redeployment.
|
401
|
+
|
402
|
+
\b
|
403
|
+
🧩 ***Input file schema(yaml):***<br/>
|
404
|
+
```yaml
|
405
|
+
body (map):
|
406
|
+
name (string): Name of the service.
|
407
|
+
title (string | required: false): Title of the service.
|
408
|
+
description (string | required: false): Description of the service.
|
409
|
+
serviceType (string | required: false): Type of the service. Valid values are `api`, `web-app` and `shiny`. Default value is `web-app`.
|
410
|
+
imageDetails (map):
|
411
|
+
imageId (number): ID of the image.
|
412
|
+
versionId (number | required: false): ID of the image version. If versionId is not passed, service will be created using latest ready version of the image.
|
413
|
+
resources (map | required: false):
|
414
|
+
instanceTypeId (number): ID of the instance type.
|
415
|
+
parameters (map | required: false):
|
416
|
+
env (map | required: false): Key-Value pair where key is the name of the env.
|
417
|
+
secrets (list(str) | required: false): List of secret names to be passed.
|
418
|
+
sessionStickiness (boolean | required: false): Enable session stickiness for the service. Default value is false. Enabling session stickiness will tie each user to a specific server for all their requests. Not required for API type services.
|
419
|
+
entrypoint (string | required: false): Entrypoint for the service.
|
420
|
+
healthCheckURL (string | required: false): Endpoint to monitor service's operational status.
|
421
|
+
```
|
422
|
+
|
423
|
+
\b
|
424
|
+
📝 ***Example usage:***
|
425
|
+
```bash
|
426
|
+
peak services create-or-update '/path/to/file.yml' -v '/path/to/params.yml'
|
427
|
+
```
|
428
|
+
|
429
|
+
\b
|
430
|
+
📝 ***Example usage without yaml:***
|
431
|
+
```bash
|
432
|
+
peak services create-or-update --name <name> --title <title> --description <description> --image-id <image-id> --version-id <version-id> --instance-type-id <instance-type-id> --session-stickiness
|
433
|
+
```
|
434
|
+
|
435
|
+
\b
|
436
|
+
🆗 ***Response:***
|
437
|
+
```json
|
438
|
+
{
|
439
|
+
"id": "db88c21d-1add-45dd-a72e-8c6b83b68dee"
|
440
|
+
}
|
441
|
+
```
|
442
|
+
|
443
|
+
🔗 [**API Documentation for creating a new service**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/create-service)
|
444
|
+
|
445
|
+
🔗 [**API Documentation for updating an existing service**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/update-service)
|
446
|
+
"""
|
447
|
+
service_client: Service = ctx.obj["client"]
|
448
|
+
writer: Writer = ctx.obj["writer"]
|
449
|
+
|
450
|
+
user_options: Dict[str, Any] = variables_to_dict(
|
451
|
+
name,
|
452
|
+
description,
|
453
|
+
title,
|
454
|
+
image_id,
|
455
|
+
version_id,
|
456
|
+
instance_type_id,
|
457
|
+
session_stickiness,
|
458
|
+
service_type,
|
459
|
+
env,
|
460
|
+
secrets,
|
461
|
+
entrypoint,
|
462
|
+
)
|
463
|
+
user_options = map_user_options(user_options, MAPPING)
|
464
|
+
|
465
|
+
body: Dict[str, Any] = {}
|
466
|
+
if file:
|
467
|
+
body = helpers.template_handler(file=file, params_file=params_file, params=params)
|
468
|
+
body = helpers.remove_unknown_args(body, service_client.create_or_update_service)
|
469
|
+
|
470
|
+
updated_body = combine_dictionaries(body.get("body") or {}, user_options)
|
471
|
+
|
472
|
+
if env:
|
473
|
+
updated_body["parameters"]["env"] = helpers.parse_envs(env)
|
474
|
+
|
475
|
+
if secrets:
|
476
|
+
updated_body["parameters"]["secrets"] = parse_list_of_strings(secrets)
|
477
|
+
|
478
|
+
if health_check_url:
|
479
|
+
updated_body["healthCheckURL"] = health_check_url
|
480
|
+
|
481
|
+
response = service_client.create_or_update_service(body=updated_body)
|
482
|
+
writer.write(response)
|
483
|
+
|
484
|
+
|
485
|
+
@app.command(short_help="Delete an existing service.", options_metavar="delete_service")
|
486
|
+
def delete(
|
487
|
+
ctx: typer.Context,
|
488
|
+
service_id: str = _SERVICE_ID,
|
489
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
490
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
491
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
492
|
+
) -> None:
|
493
|
+
"""***Delete*** an existing service.
|
494
|
+
|
495
|
+
\b
|
496
|
+
📝 ***Example usage:***<br/>
|
497
|
+
```bash
|
498
|
+
peak services delete <service-id>
|
499
|
+
```
|
500
|
+
|
501
|
+
\b
|
502
|
+
🆗 ***Response:***
|
503
|
+
```json
|
504
|
+
{
|
505
|
+
"id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee"
|
506
|
+
}
|
507
|
+
```
|
508
|
+
|
509
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/delete-service)
|
510
|
+
"""
|
511
|
+
service_client: Service = ctx.obj["client"]
|
512
|
+
writer: Writer = ctx.obj["writer"]
|
513
|
+
|
514
|
+
with writer.pager():
|
515
|
+
response = service_client.delete_service(service_id=service_id)
|
516
|
+
writer.write(response)
|
517
|
+
|
518
|
+
|
519
|
+
@app.command(short_help="Describe details of a service.", options_metavar="describe_service")
|
520
|
+
def describe(
|
521
|
+
ctx: typer.Context,
|
522
|
+
service_id: str = _SERVICE_ID,
|
523
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
524
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
525
|
+
) -> None:
|
526
|
+
"""***Describe*** details for the specific service.
|
527
|
+
|
528
|
+
\b
|
529
|
+
📝 ***Example usage:***<br/>
|
530
|
+
```bash
|
531
|
+
peak services describe <service-id>
|
532
|
+
```
|
533
|
+
|
534
|
+
\b
|
535
|
+
🆗 ***Response:***
|
536
|
+
```
|
537
|
+
{
|
538
|
+
"id": "ab11c21d-1add-45dd-a72e-8c6b83b68dee",
|
539
|
+
"name": "awesome-service",
|
540
|
+
"status": "AVAILABLE",
|
541
|
+
"serviceType": "web-app",
|
542
|
+
"imageDetails": {
|
543
|
+
"imageId": 1,
|
544
|
+
"versionId": 1
|
545
|
+
},
|
546
|
+
"resources": {
|
547
|
+
"instanceTypeId": 1
|
548
|
+
},
|
549
|
+
"sessionStickiness": false,
|
550
|
+
"createdAt": "2020-01-01T18:00:00.000Z",
|
551
|
+
"createdBy": "someone@peak.ai",
|
552
|
+
"updatedAt": "2020-01-01T18:00:00.000Z",
|
553
|
+
"updatedBy": "someone@peak.ai",
|
554
|
+
"tags": [...]
|
555
|
+
}
|
556
|
+
```
|
557
|
+
|
558
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/get-service)
|
559
|
+
"""
|
560
|
+
service_client: Service = ctx.obj["client"]
|
561
|
+
writer: Writer = ctx.obj["writer"]
|
562
|
+
|
563
|
+
with writer.pager():
|
564
|
+
response = service_client.describe_service(service_id=service_id)
|
565
|
+
writer.write(response)
|
566
|
+
|
567
|
+
|
568
|
+
@app.command(short_help="Test API type service", options_metavar="test_service")
|
569
|
+
def test(
|
570
|
+
ctx: typer.Context,
|
571
|
+
service_name: str = _SERVICE_NAME,
|
572
|
+
file: Annotated[Optional[str], typer.Argument(..., help=FILE_HELP_STRING)] = None,
|
573
|
+
params_file: str = args.TEMPLATE_PARAMS_FILE,
|
574
|
+
params: List[str] = args.TEMPLATE_PARAMS,
|
575
|
+
http_method: str = _HTTP_METHOD,
|
576
|
+
path: Optional[str] = _PATH,
|
577
|
+
payload: Optional[str] = _PAYLOAD,
|
578
|
+
dry_run: Optional[bool] = DRY_RUN, # noqa: ARG001
|
579
|
+
paging: Optional[bool] = PAGING, # noqa: ARG001
|
580
|
+
output_type: Optional[OutputTypesNoTable] = OUTPUT_TYPES, # noqa: ARG001
|
581
|
+
generate: Optional[bool] = GENERATE_YAML, # noqa: ARG001
|
582
|
+
) -> None:
|
583
|
+
"""***Test*** an API type service.
|
584
|
+
|
585
|
+
\b
|
586
|
+
🧩 ***Input file schema(yaml):***<br/>
|
587
|
+
```yaml
|
588
|
+
payload (map): payload to be used to test the service.
|
589
|
+
```
|
590
|
+
|
591
|
+
\b
|
592
|
+
📝 ***Example usage:***
|
593
|
+
```bash
|
594
|
+
peak services test <service-name> '/path/to/file.yml' -v '/path/to/params.yml'
|
595
|
+
```
|
596
|
+
|
597
|
+
\b
|
598
|
+
📝 ***Example usage without yaml:***<br/>
|
599
|
+
```bash
|
600
|
+
peak services test <service-name> --http-method 'get' --path '/'
|
601
|
+
```
|
602
|
+
|
603
|
+
\b
|
604
|
+
🆗 ***Response:***
|
605
|
+
```
|
606
|
+
{
|
607
|
+
"responseBody": "{"status": "OK"}",
|
608
|
+
"responseStatus": 200,
|
609
|
+
"reqStartTime": "2024-01-01T10:00:01.064Z",
|
610
|
+
"reqEndTime": "2024-01-01T10:00:05.064Z",
|
611
|
+
"responseSize": "1KB"
|
612
|
+
}
|
613
|
+
```
|
614
|
+
|
615
|
+
🔗 [**API Documentation**](https://service.peak.ai/webapps/api-docs/index.htm#/Services/test-api-service)
|
616
|
+
"""
|
617
|
+
service_client: Service = ctx.obj["client"]
|
618
|
+
writer: Writer = ctx.obj["writer"]
|
619
|
+
|
620
|
+
body: Dict[str, Any] = {}
|
621
|
+
if file:
|
622
|
+
body = helpers.template_handler(file=file, params_file=params_file, params=params)
|
623
|
+
body = helpers.remove_unknown_args(body, service_client.test_service)
|
624
|
+
|
625
|
+
with writer.pager():
|
626
|
+
response = service_client.test_service(
|
627
|
+
service_name=service_name,
|
628
|
+
http_method=http_method,
|
629
|
+
path=path,
|
630
|
+
payload=json.loads(payload) if payload else body.get("payload"),
|
631
|
+
)
|
632
|
+
writer.write(response)
|