snapctl 0.35.0__tar.gz → 0.38.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 snapctl might be problematic. Click here for more details.
- {snapctl-0.35.0 → snapctl-0.38.0}/PKG-INFO +9 -1
- {snapctl-0.35.0 → snapctl-0.38.0}/README.md +8 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/pyproject.toml +1 -1
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/byogs.py +15 -4
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/byosnap.py +62 -12
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/config/constants.py +1 -1
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/config/hashes.py +11 -1
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/main.py +10 -3
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/utils/echo.py +7 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/utils/helper.py +60 -1
- {snapctl-0.35.0 → snapctl-0.38.0}/LICENSE +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/__init__.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/__main__.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/__init__.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/game.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/generate.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/commands/snapend.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/config/__init__.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/config/endpoints.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/types/__init__.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/types/definitions.py +0 -0
- {snapctl-0.35.0 → snapctl-0.38.0}/snapctl/utils/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: snapctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.38.0
|
|
4
4
|
Summary: Snapser CLI Tool
|
|
5
5
|
Author: Ajinkya Apte
|
|
6
6
|
Author-email: aj@snapser.com
|
|
@@ -264,6 +264,10 @@ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
|
|
|
264
264
|
Publish a custom snap code image. This command executes, `build`, `push` and `upload-docs` one
|
|
265
265
|
after the other.
|
|
266
266
|
|
|
267
|
+
**IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
|
|
268
|
+
Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
|
|
269
|
+
a mismatch.
|
|
270
|
+
|
|
267
271
|
```
|
|
268
272
|
# Help for the byosnap command
|
|
269
273
|
snapctl byosnap publish-image --help
|
|
@@ -348,6 +352,10 @@ snapctl byogs push --tag $image_tag
|
|
|
348
352
|
Publish your custom game server image. This commend replaces the old way of creating, publishing image and
|
|
349
353
|
then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
|
|
350
354
|
|
|
355
|
+
**IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
|
|
356
|
+
Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
|
|
357
|
+
a mismatch.
|
|
358
|
+
|
|
351
359
|
```
|
|
352
360
|
# Help for the byogs command
|
|
353
361
|
snapctl byogs publish --help
|
|
@@ -245,6 +245,10 @@ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
|
|
|
245
245
|
Publish a custom snap code image. This command executes, `build`, `push` and `upload-docs` one
|
|
246
246
|
after the other.
|
|
247
247
|
|
|
248
|
+
**IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
|
|
249
|
+
Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
|
|
250
|
+
a mismatch.
|
|
251
|
+
|
|
248
252
|
```
|
|
249
253
|
# Help for the byosnap command
|
|
250
254
|
snapctl byosnap publish-image --help
|
|
@@ -329,6 +333,10 @@ snapctl byogs push --tag $image_tag
|
|
|
329
333
|
Publish your custom game server image. This commend replaces the old way of creating, publishing image and
|
|
330
334
|
then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
|
|
331
335
|
|
|
336
|
+
**IMPORTANT**: Take note of the hardware architecture of machine and your Dockerfile commands.
|
|
337
|
+
Commands in docker file may be hardware architecture specific. Snapser throws a warning if it detects
|
|
338
|
+
a mismatch.
|
|
339
|
+
|
|
332
340
|
```
|
|
333
341
|
# Help for the byogs command
|
|
334
342
|
snapctl byogs publish --help
|
|
@@ -5,6 +5,7 @@ import base64
|
|
|
5
5
|
from binascii import Error as BinasciiError
|
|
6
6
|
import os
|
|
7
7
|
import subprocess
|
|
8
|
+
import platform as sys_platform
|
|
8
9
|
from sys import platform
|
|
9
10
|
from typing import Union
|
|
10
11
|
|
|
@@ -13,8 +14,9 @@ from snapctl.config.constants import SNAPCTL_BYOGS_DEPENDENCY_MISSING, \
|
|
|
13
14
|
SNAPCTL_BYOGS_ECR_LOGIN_ERROR, SNAPCTL_BYOGS_BUILD_ERROR, \
|
|
14
15
|
SNAPCTL_BYOGS_TAG_ERROR, SNAPCTL_BYOGS_PUBLISH_ERROR, \
|
|
15
16
|
SNAPCTL_BYOGS_PUBLISH_DUPLICATE_TAG_ERROR, SNAPCTL_INPUT_ERROR
|
|
16
|
-
from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success
|
|
17
|
-
|
|
17
|
+
from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success, \
|
|
18
|
+
check_dockerfile_architecture
|
|
19
|
+
from snapctl.utils.echo import info, warning
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class ByoGs:
|
|
@@ -150,6 +152,13 @@ class ByoGs:
|
|
|
150
152
|
build_platform = self.token_parts[3]
|
|
151
153
|
# Build your snap
|
|
152
154
|
docker_file_path = os.path.join(self.path, self.dockerfile)
|
|
155
|
+
# Warning check for architecture specific commands
|
|
156
|
+
info(f'Building on system architecture {sys_platform.machine()}')
|
|
157
|
+
check_response = check_dockerfile_architecture(
|
|
158
|
+
docker_file_path, sys_platform.machine())
|
|
159
|
+
if check_response['error']:
|
|
160
|
+
warning(check_response['message'])
|
|
161
|
+
# Build the image
|
|
153
162
|
if platform == "win32":
|
|
154
163
|
response = subprocess.run([
|
|
155
164
|
# f"docker build --no-cache -t {tag} {path}"
|
|
@@ -160,7 +169,8 @@ class ByoGs:
|
|
|
160
169
|
else:
|
|
161
170
|
response = subprocess.run([
|
|
162
171
|
# f"docker build --no-cache -t {tag} {path}"
|
|
163
|
-
f"docker build --platform {
|
|
172
|
+
f"docker build --platform {
|
|
173
|
+
build_platform} -t {self.input_tag} "
|
|
164
174
|
f"-f {docker_file_path} {self.path}"
|
|
165
175
|
], shell=True, check=False)
|
|
166
176
|
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
@@ -247,7 +257,8 @@ class ByoGs:
|
|
|
247
257
|
# Check subcommand
|
|
248
258
|
if not self.subcommand in ByoGs.SUBCOMMANDS:
|
|
249
259
|
snapctl_error(
|
|
250
|
-
f"Invalid command. Valid commands are {
|
|
260
|
+
f"Invalid command. Valid commands are {
|
|
261
|
+
', '.join(ByoGs.SUBCOMMANDS)}.",
|
|
251
262
|
SNAPCTL_INPUT_ERROR)
|
|
252
263
|
# Validation for subcommands
|
|
253
264
|
if self.token_parts is None:
|
|
@@ -7,6 +7,7 @@ import json
|
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
9
|
import subprocess
|
|
10
|
+
import platform as sys_platform
|
|
10
11
|
from sys import platform
|
|
11
12
|
from typing import Union
|
|
12
13
|
import requests
|
|
@@ -22,8 +23,9 @@ from snapctl.config.constants import HTTP_ERROR_SERVICE_VERSION_EXISTS, \
|
|
|
22
23
|
SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR, SNAPCTL_BYOSNAP_CREATE_PERMISSION_ERROR, \
|
|
23
24
|
SNAPCTL_BYOSNAP_CREATE_ERROR, SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_TAG_ERROR, \
|
|
24
25
|
SNAPCTL_BYOSNAP_PUBLISH_VERSION_ERROR
|
|
25
|
-
from snapctl.utils.echo import success, info
|
|
26
|
-
from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success
|
|
26
|
+
from snapctl.utils.echo import success, info, warning
|
|
27
|
+
from snapctl.utils.helper import get_composite_token, snapctl_error, snapctl_success, \
|
|
28
|
+
check_dockerfile_architecture
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
class ByoSnap:
|
|
@@ -41,13 +43,16 @@ class ByoSnap:
|
|
|
41
43
|
TAG_CHARACTER_LIMIT = 80
|
|
42
44
|
VALID_CPU_MARKS = [100, 250, 500, 750, 1000, 1500, 2000, 3000]
|
|
43
45
|
VALID_MEMORY_MARKS = [0.125, 0.25, 0.5, 1, 2, 3, 4]
|
|
46
|
+
MAX_READINESS_TIMEOUT = 30
|
|
47
|
+
MAX_MIN_REPLICAS = 4
|
|
44
48
|
|
|
45
49
|
def __init__(
|
|
46
50
|
self, subcommand: str, base_url: str, api_key: str | None, sid: str, name: str,
|
|
47
51
|
desc: str, platform_type: str, language: str, input_tag: Union[str, None],
|
|
48
52
|
path: Union[str, None], dockerfile: str, prefix: str, version: Union[str, None],
|
|
49
53
|
http_port: Union[int, None], byosnap_profile: Union[str, None],
|
|
50
|
-
skip_build: bool = False
|
|
54
|
+
skip_build: bool = False, readiness_path: Union[str, None] = None,
|
|
55
|
+
readiness_delay: Union[int, None] = None
|
|
51
56
|
) -> None:
|
|
52
57
|
self.subcommand: str = subcommand
|
|
53
58
|
self.base_url: str = base_url
|
|
@@ -74,6 +79,8 @@ class ByoSnap:
|
|
|
74
79
|
self.http_port: Union[int, None] = http_port
|
|
75
80
|
self.byosnap_profile: Union[str, None] = byosnap_profile
|
|
76
81
|
self.skip_build: bool = skip_build
|
|
82
|
+
self.readiness_path: Union[str, None] = readiness_path
|
|
83
|
+
self.readiness_delay: Union[int, None] = readiness_delay
|
|
77
84
|
# Validate the input
|
|
78
85
|
self.validate_input()
|
|
79
86
|
|
|
@@ -179,6 +186,13 @@ class ByoSnap:
|
|
|
179
186
|
try:
|
|
180
187
|
# Build your snap
|
|
181
188
|
docker_file_path = os.path.join(self.path, self.dockerfile)
|
|
189
|
+
# Warning check for architecture specific commands
|
|
190
|
+
info(f'Building on system architecture {sys_platform.machine()}')
|
|
191
|
+
check_response = check_dockerfile_architecture(
|
|
192
|
+
docker_file_path, sys_platform.machine())
|
|
193
|
+
if check_response['error']:
|
|
194
|
+
warning(check_response['message'])
|
|
195
|
+
# Build the image
|
|
182
196
|
if platform == "win32":
|
|
183
197
|
response = subprocess.run([
|
|
184
198
|
# f"docker build --no-cache -t {tag} {path}"
|
|
@@ -189,7 +203,8 @@ class ByoSnap:
|
|
|
189
203
|
else:
|
|
190
204
|
response = subprocess.run([
|
|
191
205
|
# f"docker build --no-cache -t {tag} {path}"
|
|
192
|
-
f"docker build --platform {
|
|
206
|
+
f"docker build --platform {
|
|
207
|
+
build_platform} -t {self.input_tag} "
|
|
193
208
|
f"-f {docker_file_path} {self.path}"
|
|
194
209
|
], shell=True, check=False)
|
|
195
210
|
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
@@ -300,6 +315,7 @@ class ByoSnap:
|
|
|
300
315
|
SNAPCTL_INPUT_ERROR
|
|
301
316
|
)
|
|
302
317
|
for profile in ['dev_template', 'stage_template', 'prod_template']:
|
|
318
|
+
# Currently, not checking for 'min_replicas' not in profile_data[profile]
|
|
303
319
|
if 'cpu' not in profile_data[profile] or \
|
|
304
320
|
'memory' not in profile_data[profile] or \
|
|
305
321
|
'cmd' not in profile_data[profile] or \
|
|
@@ -312,13 +328,25 @@ class ByoSnap:
|
|
|
312
328
|
if profile_data[profile]['cpu'] not in ByoSnap.VALID_CPU_MARKS:
|
|
313
329
|
snapctl_error(
|
|
314
330
|
'Invalid CPU value in BYOSnap profile. '
|
|
315
|
-
f'Valid values are {
|
|
331
|
+
f'Valid values are {
|
|
332
|
+
", ".join(map(str, ByoSnap.VALID_CPU_MARKS))}',
|
|
316
333
|
SNAPCTL_INPUT_ERROR
|
|
317
334
|
)
|
|
318
335
|
if profile_data[profile]['memory'] not in ByoSnap.VALID_MEMORY_MARKS:
|
|
319
336
|
snapctl_error(
|
|
320
337
|
'Invalid Memory value in BYOSnap profile. '
|
|
321
|
-
f'Valid values are {
|
|
338
|
+
f'Valid values are {
|
|
339
|
+
", ".join(map(str, ByoSnap.VALID_MEMORY_MARKS))}',
|
|
340
|
+
SNAPCTL_INPUT_ERROR
|
|
341
|
+
)
|
|
342
|
+
if 'min_replicas' in profile_data[profile] and \
|
|
343
|
+
(not isinstance(profile_data[profile]['min_replicas'], int) or
|
|
344
|
+
int(profile_data[profile]['min_replicas']) < 0 or
|
|
345
|
+
int(profile_data[profile]['min_replicas']) > ByoSnap.MAX_MIN_REPLICAS):
|
|
346
|
+
snapctl_error(
|
|
347
|
+
'Invalid Min Replicas value in BYOSnap profile. '
|
|
348
|
+
f'Minimum replicas should be between 0 and {
|
|
349
|
+
ByoSnap.MAX_MIN_REPLICAS}',
|
|
322
350
|
SNAPCTL_INPUT_ERROR
|
|
323
351
|
)
|
|
324
352
|
|
|
@@ -342,13 +370,15 @@ class ByoSnap:
|
|
|
342
370
|
# Validate the SID
|
|
343
371
|
if not self.sid.startswith(ByoSnap.ID_PREFIX):
|
|
344
372
|
snapctl_error(
|
|
345
|
-
f"Invalid Snap ID. Valid Snap IDs start with {
|
|
373
|
+
f"Invalid Snap ID. Valid Snap IDs start with {
|
|
374
|
+
ByoSnap.ID_PREFIX}.",
|
|
346
375
|
SNAPCTL_INPUT_ERROR
|
|
347
376
|
)
|
|
348
377
|
if len(self.sid) > ByoSnap.SID_CHARACTER_LIMIT:
|
|
349
378
|
snapctl_error(
|
|
350
379
|
"Invalid Snap ID. "
|
|
351
|
-
f"Snap ID should be less than {
|
|
380
|
+
f"Snap ID should be less than {
|
|
381
|
+
ByoSnap.SID_CHARACTER_LIMIT} characters",
|
|
352
382
|
SNAPCTL_INPUT_ERROR
|
|
353
383
|
)
|
|
354
384
|
# Validation for subcommands
|
|
@@ -391,7 +421,8 @@ class ByoSnap:
|
|
|
391
421
|
# Check path
|
|
392
422
|
if not self.skip_build and not os.path.isfile(f"{self.path}/{self.dockerfile}"):
|
|
393
423
|
snapctl_error(
|
|
394
|
-
f"Unable to find {
|
|
424
|
+
f"Unable to find {
|
|
425
|
+
self.dockerfile} at path {self.path}",
|
|
395
426
|
SNAPCTL_INPUT_ERROR)
|
|
396
427
|
# elif self.subcommand == 'push':
|
|
397
428
|
# if not self.input_tag:
|
|
@@ -405,7 +436,8 @@ class ByoSnap:
|
|
|
405
436
|
if not self.input_tag:
|
|
406
437
|
snapctl_error(
|
|
407
438
|
"Missing required parameter: tag", SNAPCTL_INPUT_ERROR)
|
|
408
|
-
if len(self.input_tag.split()) > 1 or
|
|
439
|
+
if len(self.input_tag.split()) > 1 or \
|
|
440
|
+
len(self.input_tag) > ByoSnap.TAG_CHARACTER_LIMIT:
|
|
409
441
|
snapctl_error(
|
|
410
442
|
"Tag should be a single word with maximum of "
|
|
411
443
|
f"{ByoSnap.TAG_CHARACTER_LIMIT} characters",
|
|
@@ -431,6 +463,18 @@ class ByoSnap:
|
|
|
431
463
|
if not self.http_port.isdigit():
|
|
432
464
|
snapctl_error("Ingress HTTP Port should be a number",
|
|
433
465
|
SNAPCTL_INPUT_ERROR)
|
|
466
|
+
if self.readiness_path is not None:
|
|
467
|
+
if self.readiness_path.strip() == '':
|
|
468
|
+
snapctl_error("Readiness path cannot be empty",
|
|
469
|
+
SNAPCTL_INPUT_ERROR)
|
|
470
|
+
if not self.readiness_path.strip().startswith('/'):
|
|
471
|
+
snapctl_error("Readiness path has to start with /",
|
|
472
|
+
SNAPCTL_INPUT_ERROR)
|
|
473
|
+
if self.readiness_delay is not None:
|
|
474
|
+
if self.readiness_delay < 0 or \
|
|
475
|
+
self.readiness_delay > ByoSnap.MAX_READINESS_TIMEOUT:
|
|
476
|
+
snapctl_error("Readiness delay should be between 0 "
|
|
477
|
+
f"and {ByoSnap.MAX_READINESS_TIMEOUT}", SNAPCTL_INPUT_ERROR)
|
|
434
478
|
# Check byosnap_profile path
|
|
435
479
|
self._validate_byosnap_profile()
|
|
436
480
|
|
|
@@ -495,7 +539,8 @@ class ByoSnap:
|
|
|
495
539
|
info('Unable to upload your swagger.json')
|
|
496
540
|
except RequestException as e:
|
|
497
541
|
info(
|
|
498
|
-
f'Exception: Unable to find swagger.json at {
|
|
542
|
+
f'Exception: Unable to find swagger.json at {
|
|
543
|
+
self.path} {e}'
|
|
499
544
|
)
|
|
500
545
|
else:
|
|
501
546
|
info(f'No swagger.json found at {self.path}'
|
|
@@ -561,7 +606,8 @@ class ByoSnap:
|
|
|
561
606
|
if "api_error_code" in response_json and "message" in response_json:
|
|
562
607
|
if response_json['api_error_code'] == HTTP_ERROR_SERVICE_VERSION_EXISTS:
|
|
563
608
|
snapctl_error(
|
|
564
|
-
f'BYOSnap {
|
|
609
|
+
f'BYOSnap {
|
|
610
|
+
self.name} already exists. Please use a different name',
|
|
565
611
|
SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR,
|
|
566
612
|
progress
|
|
567
613
|
)
|
|
@@ -628,6 +674,10 @@ class ByoSnap:
|
|
|
628
674
|
"image_tag": self.input_tag,
|
|
629
675
|
"base_url": f"{self.prefix}/{self.sid}",
|
|
630
676
|
"http_port": self.http_port,
|
|
677
|
+
"readiness_probe_config": {
|
|
678
|
+
"path": self.readiness_path,
|
|
679
|
+
"initial_delay_seconds": self.readiness_delay
|
|
680
|
+
},
|
|
631
681
|
"dev_template": profile_data['dev_template'],
|
|
632
682
|
"stage_template": profile_data['stage_template'],
|
|
633
683
|
"prod_template": profile_data['prod_template']
|
|
@@ -149,7 +149,7 @@ SNAPEND_MANIFEST_TYPES: dict[str, dict[str, str]] = {
|
|
|
149
149
|
},
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
SERVICE_IDS = [
|
|
152
|
+
SERVICE_IDS: list[str] = [
|
|
153
153
|
'analytics', 'auth', 'client-logs', 'events', 'experiments', 'gdpr', 'guilds', 'hades', 'iap',
|
|
154
154
|
'inventory', 'leaderboards', 'matchmaking', 'notifications', 'parties', 'profiles', 'quests',
|
|
155
155
|
'relay', 'remote-config', 'scheduler', 'sequencer', 'social-graph', 'statistics', 'storage',
|
|
@@ -159,6 +159,7 @@ SERVICE_IDS = [
|
|
|
159
159
|
DEFAULT_BYOSNAP_DEV_TEMPLATE = {
|
|
160
160
|
'cpu': 100,
|
|
161
161
|
'memory': 0.125,
|
|
162
|
+
'min_replicas': 1,
|
|
162
163
|
'cmd': '',
|
|
163
164
|
'args': [],
|
|
164
165
|
'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "DEVELOPMENT"}]
|
|
@@ -167,6 +168,7 @@ DEFAULT_BYOSNAP_DEV_TEMPLATE = {
|
|
|
167
168
|
DEFAULT_BYOSNAP_STAGE_TEMPLATE = {
|
|
168
169
|
'cpu': 100,
|
|
169
170
|
'memory': 0.125,
|
|
171
|
+
'min_replicas': 1,
|
|
170
172
|
'cmd': '',
|
|
171
173
|
'args': [],
|
|
172
174
|
'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "STAGING"}]
|
|
@@ -175,6 +177,7 @@ DEFAULT_BYOSNAP_STAGE_TEMPLATE = {
|
|
|
175
177
|
DEFAULT_BYOSNAP_PROD_TEMPLATE = {
|
|
176
178
|
'cpu': 100,
|
|
177
179
|
'memory': 0.125,
|
|
180
|
+
'min_replicas': 2,
|
|
178
181
|
'cmd': '',
|
|
179
182
|
'args': [],
|
|
180
183
|
'env_params': [{'key': "SNAPSER_ENVIRONMENT", 'value': "PRODUCTION"}]
|
|
@@ -185,3 +188,10 @@ BYOSNAP_TEMPLATE = {
|
|
|
185
188
|
'stage_template': DEFAULT_BYOSNAP_STAGE_TEMPLATE,
|
|
186
189
|
'prod_template': DEFAULT_BYOSNAP_PROD_TEMPLATE
|
|
187
190
|
}
|
|
191
|
+
|
|
192
|
+
ARCHITECTURE_MAPPING: dict[str, str] = {
|
|
193
|
+
'x86_64': 'amd64',
|
|
194
|
+
'arm64': 'arm64',
|
|
195
|
+
'aarch64': 'arm64',
|
|
196
|
+
'amd64': 'amd64'
|
|
197
|
+
}
|
|
@@ -76,7 +76,8 @@ def extract_config(extract_key: str, profile: str | None = None) -> object:
|
|
|
76
76
|
result['location'] = f'"{config_file_path}:profile {profile}"'
|
|
77
77
|
config_profile = f'profile {profile}'
|
|
78
78
|
info(
|
|
79
|
-
f'Trying to extract API KEY from "{
|
|
79
|
+
f'Trying to extract API KEY from "{
|
|
80
|
+
config_file_path}:profile {profile}"'
|
|
80
81
|
)
|
|
81
82
|
result['value'] = config.get(
|
|
82
83
|
config_profile, extract_key, fallback=None, raw=True
|
|
@@ -338,7 +339,12 @@ def byosnap(
|
|
|
338
339
|
skip_build: bool = typer.Option(
|
|
339
340
|
False, "--skip-build", help="(optional: publish-image) Skip the build step. You have to pass the image tag you used during the build step."
|
|
340
341
|
),
|
|
341
|
-
|
|
342
|
+
readiness_path: str = typer.Option(
|
|
343
|
+
None, "--readiness-path", help="(req: publish-version) Readiness path for your snap"
|
|
344
|
+
),
|
|
345
|
+
readiness_delay: int = typer.Option(
|
|
346
|
+
None, "--readiness-delay", help="(req: publish-version) Delay before readiness check"
|
|
347
|
+
),
|
|
342
348
|
# overrides
|
|
343
349
|
api_key: Union[str, None] = typer.Option(
|
|
344
350
|
None, "--api-key", help="API Key override.", callback=api_key_context_callback
|
|
@@ -354,7 +360,8 @@ def byosnap(
|
|
|
354
360
|
byosnap_obj: ByoSnap = ByoSnap(
|
|
355
361
|
subcommand, ctx.obj['base_url'], ctx.obj['api_key'], sid,
|
|
356
362
|
name, desc, platform_type, language, tag, path, docker_file,
|
|
357
|
-
prefix, version, http_port, byosnap_profile, skip_build
|
|
363
|
+
prefix, version, http_port, byosnap_profile, skip_build,
|
|
364
|
+
readiness_path, readiness_delay
|
|
358
365
|
)
|
|
359
366
|
getattr(byosnap_obj, subcommand.replace('-', '_'))()
|
|
360
367
|
success(f"BYOSnap {subcommand} complete")
|
|
@@ -20,6 +20,13 @@ def error(msg: str, code: int = SNAPCTL_ERROR, data: object = None) -> None:
|
|
|
20
20
|
typer.echo(json.dumps(error_response.to_dict()), err=True)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
def warning(msg: str) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Prints a warning message to the console.
|
|
26
|
+
"""
|
|
27
|
+
print(f"[bold yellow]Warning[/bold yellow] {msg}")
|
|
28
|
+
|
|
29
|
+
|
|
23
30
|
def info(msg: str) -> None:
|
|
24
31
|
"""
|
|
25
32
|
Prints an info message to the console.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Helper functions for snapctl
|
|
3
3
|
"""
|
|
4
|
+
import re
|
|
4
5
|
import requests
|
|
5
6
|
import typer
|
|
6
7
|
from requests.exceptions import RequestException
|
|
7
8
|
from rich.progress import Progress
|
|
8
9
|
from snapctl.config.constants import HTTP_NOT_FOUND, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, \
|
|
9
10
|
SERVER_CALL_TIMEOUT, SNAPCTL_CONFIGURATION_ERROR, SNAPCTL_SUCCESS
|
|
11
|
+
from snapctl.config.hashes import ARCHITECTURE_MAPPING
|
|
10
12
|
from snapctl.utils.echo import error, success
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
def validate_api_key(base_url: str, api_key: str | None):
|
|
15
|
+
def validate_api_key(base_url: str, api_key: str | None) -> bool:
|
|
14
16
|
"""
|
|
15
17
|
This function validates the API Key
|
|
16
18
|
"""
|
|
@@ -74,6 +76,63 @@ def get_composite_token(base_url: str, api_key: str | None, action: str, params:
|
|
|
74
76
|
return res.json()['token']
|
|
75
77
|
|
|
76
78
|
|
|
79
|
+
def check_dockerfile_architecture(dockerfile_path: str, system_arch: str) -> dict[str, object]:
|
|
80
|
+
"""
|
|
81
|
+
Check the Dockerfile for architecture specific commands
|
|
82
|
+
"""
|
|
83
|
+
response = {
|
|
84
|
+
'error': False,
|
|
85
|
+
'message': ''
|
|
86
|
+
}
|
|
87
|
+
# Normalize system architecture
|
|
88
|
+
system_arch = ARCHITECTURE_MAPPING.get(system_arch, system_arch)
|
|
89
|
+
try:
|
|
90
|
+
lines = []
|
|
91
|
+
with open(dockerfile_path, 'r') as file:
|
|
92
|
+
lines = file.readlines()
|
|
93
|
+
for line_number, line in enumerate(lines, 1):
|
|
94
|
+
if line.startswith('#'):
|
|
95
|
+
continue
|
|
96
|
+
# Checking various build and run commands for architecture specifics
|
|
97
|
+
patterns = [
|
|
98
|
+
# FROM with platform
|
|
99
|
+
r'FROM --platform=linux/(\w+)',
|
|
100
|
+
# dotnet runtime
|
|
101
|
+
r'-r linux-(\w+)',
|
|
102
|
+
# Build args specifying arch
|
|
103
|
+
r'--build-arg ARCH=(\w+)',
|
|
104
|
+
# Environment variables setting arch
|
|
105
|
+
r'ENV ARCH=(\w+)',
|
|
106
|
+
# cmake specifying arch
|
|
107
|
+
r'cmake.*?-DARCH=(\w+)',
|
|
108
|
+
# make specifying arch
|
|
109
|
+
r'make.*?ARCH=(\w+)'
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
for pattern in patterns:
|
|
113
|
+
match = re.search(pattern, line)
|
|
114
|
+
if match and ARCHITECTURE_MAPPING.get(match.group(1)) != system_arch:
|
|
115
|
+
response['error'] = True
|
|
116
|
+
response['message'] = (
|
|
117
|
+
f'[Architecture Mismatch] Line {line_number}: "{
|
|
118
|
+
line.strip()}" '
|
|
119
|
+
f' of Dockerfile {dockerfile_path}'
|
|
120
|
+
f' specifies architecture {
|
|
121
|
+
match.group(1)}, which does not match the '
|
|
122
|
+
f' systems ({system_arch}).'
|
|
123
|
+
)
|
|
124
|
+
return response
|
|
125
|
+
except FileNotFoundError:
|
|
126
|
+
response['error'] = True
|
|
127
|
+
response['message'] = f'Dockerfile not found at {dockerfile_path}'
|
|
128
|
+
return response
|
|
129
|
+
except Exception as e:
|
|
130
|
+
response['error'] = True
|
|
131
|
+
response['message'] = f'Exception {e}'
|
|
132
|
+
return response
|
|
133
|
+
return response
|
|
134
|
+
|
|
135
|
+
|
|
77
136
|
def snapctl_success(message: str, progress: Progress | None = None, no_exit: bool = False):
|
|
78
137
|
"""
|
|
79
138
|
This function exits the snapctl
|
|
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
|