snapctl 0.43.1__tar.gz → 0.44.1__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.43.1 → snapctl-0.44.1}/PKG-INFO +3 -3
- {snapctl-0.43.1 → snapctl-0.44.1}/README.md +2 -2
- {snapctl-0.43.1 → snapctl-0.44.1}/pyproject.toml +1 -1
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/byogs.py +19 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/byosnap.py +105 -11
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/config/constants.py +1 -1
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/config/hashes.py +14 -5
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/main.py +1 -1
- {snapctl-0.43.1 → snapctl-0.44.1}/LICENSE +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/__init__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/__main__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/__init__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/game.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/generate.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/commands/snapend.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/config/__init__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/config/endpoints.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/types/__init__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/types/definitions.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/utils/__init__.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/utils/echo.py +0 -0
- {snapctl-0.43.1 → snapctl-0.44.1}/snapctl/utils/helper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: snapctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.44.1
|
|
4
4
|
Summary: Snapser CLI Tool
|
|
5
5
|
Author: Ajinkya Apte
|
|
6
6
|
Author-email: aj@snapser.com
|
|
@@ -365,10 +365,10 @@ snapctl byosnap publish-version --help
|
|
|
365
365
|
# $byosnap_sid = Snap ID for your snap
|
|
366
366
|
# $image_tag = An image tag for your snap
|
|
367
367
|
# $version = Semantic version for your snap Eg: v0.0.1
|
|
368
|
-
# $
|
|
368
|
+
# $byosnapProfilePath = Path to the snapser-byosnap-profile.json BYOSnap profile to configure dev, stage and prod settings for this snap. You can generate a base version of this file using the `snapctl generate profile --category byosnap --out-path <output_path>` command
|
|
369
369
|
# Example:
|
|
370
370
|
# snapctl byosnap publish-version byosnap-jinks-flask --tag my-first-image --version v0.0.1 --path /Users/DevName/Development/SnapserEngine/jinks_flask
|
|
371
|
-
snapctl byosnap publish-version $byosnap_sid --tag $image_tag --version $version --path $
|
|
371
|
+
snapctl byosnap publish-version $byosnap_sid --tag $image_tag --version $version --path $byosnapProfilePath
|
|
372
372
|
```
|
|
373
373
|
|
|
374
374
|
### BYO Game Server - Bring your own Game Server
|
|
@@ -346,10 +346,10 @@ snapctl byosnap publish-version --help
|
|
|
346
346
|
# $byosnap_sid = Snap ID for your snap
|
|
347
347
|
# $image_tag = An image tag for your snap
|
|
348
348
|
# $version = Semantic version for your snap Eg: v0.0.1
|
|
349
|
-
# $
|
|
349
|
+
# $byosnapProfilePath = Path to the snapser-byosnap-profile.json BYOSnap profile to configure dev, stage and prod settings for this snap. You can generate a base version of this file using the `snapctl generate profile --category byosnap --out-path <output_path>` command
|
|
350
350
|
# Example:
|
|
351
351
|
# snapctl byosnap publish-version byosnap-jinks-flask --tag my-first-image --version v0.0.1 --path /Users/DevName/Development/SnapserEngine/jinks_flask
|
|
352
|
-
snapctl byosnap publish-version $byosnap_sid --tag $image_tag --version $version --path $
|
|
352
|
+
snapctl byosnap publish-version $byosnap_sid --tag $image_tag --version $version --path $byosnapProfilePath
|
|
353
353
|
```
|
|
354
354
|
|
|
355
355
|
### BYO Game Server - Bring your own Game Server
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import base64
|
|
5
5
|
from binascii import Error as BinasciiError
|
|
6
6
|
import os
|
|
7
|
+
import json
|
|
7
8
|
import subprocess
|
|
8
9
|
import time
|
|
9
10
|
import platform as sys_platform
|
|
@@ -130,6 +131,24 @@ class ByoGs:
|
|
|
130
131
|
try:
|
|
131
132
|
# Login to Snapser Registry
|
|
132
133
|
if platform == 'win32':
|
|
134
|
+
# Start: Hack for Windows
|
|
135
|
+
data = {
|
|
136
|
+
"auths": {
|
|
137
|
+
"https://index.docker.io/v1/": {}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Path to the Docker config file, adjust the path as necessary
|
|
142
|
+
docker_config_path = os.path.expanduser('~\\.docker\\config.json')
|
|
143
|
+
|
|
144
|
+
# Ensure the directory exists
|
|
145
|
+
os.makedirs(os.path.dirname(docker_config_path), exist_ok=True)
|
|
146
|
+
|
|
147
|
+
# Write the data to the file
|
|
148
|
+
with open(docker_config_path, 'w', encoding='utf-8') as file:
|
|
149
|
+
json.dump(data, file)
|
|
150
|
+
info("Updated the docker config for docker login")
|
|
151
|
+
# End: Hack for Windows
|
|
133
152
|
response = subprocess.run([
|
|
134
153
|
'docker', 'login', '--username', ecr_repo_username,
|
|
135
154
|
'--password', ecr_repo_token, ecr_repo_url
|
|
@@ -91,7 +91,8 @@ class ByoSnap:
|
|
|
91
91
|
self.blocking: bool = blocking
|
|
92
92
|
# Override
|
|
93
93
|
self.prefix: Union[str, None] = None
|
|
94
|
-
self.
|
|
94
|
+
self.ingress_external_port: Union[dict, None] = None
|
|
95
|
+
self.ingress_internal_ports: Union[list, None] = None
|
|
95
96
|
self.readiness_path: Union[str, None] = None
|
|
96
97
|
self.readiness_delay: Union[str, None] = None
|
|
97
98
|
if self.subcommand in ['publish', 'publish-version']:
|
|
@@ -190,14 +191,15 @@ class ByoSnap:
|
|
|
190
191
|
)
|
|
191
192
|
if 'name' not in profile_data or 'description' not in profile_data or \
|
|
192
193
|
'platform' not in profile_data or 'language' not in profile_data or \
|
|
193
|
-
'prefix' not in profile_data or
|
|
194
|
-
'
|
|
194
|
+
'prefix' not in profile_data or \
|
|
195
|
+
('http_port' not in profile_data and 'ingress' not in profile_data) or \
|
|
196
|
+
'readiness_probe_config' not in profile_data or \
|
|
195
197
|
'initial_delay_seconds' not in profile_data['readiness_probe_config'] or \
|
|
196
198
|
'path' not in profile_data['readiness_probe_config']:
|
|
197
199
|
snapctl_error(
|
|
198
200
|
message='BYOSnap profile now requires name, description, platform, ' +
|
|
199
|
-
'language, prefix
|
|
200
|
-
'the following command: ' +
|
|
201
|
+
'language, prefix, ingress, and readiness_probe_config fields. ' +
|
|
202
|
+
'Please use the following command: ' +
|
|
201
203
|
'`snapctl generate profile --category byosnap --out-path $output_path` ' +
|
|
202
204
|
'to generate a new profile',
|
|
203
205
|
code=SNAPCTL_INPUT_ERROR
|
|
@@ -227,7 +229,26 @@ class ByoSnap:
|
|
|
227
229
|
self.platform_type = profile_data['platform']
|
|
228
230
|
self.language = profile_data['language']
|
|
229
231
|
self.prefix = profile_data['prefix']
|
|
230
|
-
|
|
232
|
+
# Setup the final ingress external port
|
|
233
|
+
final_ingress_external_port = {
|
|
234
|
+
'name': 'http',
|
|
235
|
+
'port': None
|
|
236
|
+
}
|
|
237
|
+
if 'http_port' in profile_data:
|
|
238
|
+
final_ingress_external_port = {
|
|
239
|
+
'name': 'http',
|
|
240
|
+
'port': profile_data['http_port']
|
|
241
|
+
}
|
|
242
|
+
warning('http_port is deprecated. Please use ingress.external_port. ' +
|
|
243
|
+
'You can generate a new BYOSnap profile via the `generate` command.')
|
|
244
|
+
elif 'ingress' in profile_data and 'external_port' in profile_data['ingress']:
|
|
245
|
+
final_ingress_external_port = profile_data['ingress']['external_port']
|
|
246
|
+
self.ingress_external_port = final_ingress_external_port
|
|
247
|
+
# Setup the final ingress internal ports
|
|
248
|
+
final_ingress_internal_ports = []
|
|
249
|
+
if 'ingress' in profile_data and 'internal_ports' in profile_data['ingress']:
|
|
250
|
+
final_ingress_internal_ports = profile_data['ingress']['internal_ports']
|
|
251
|
+
self.ingress_internal_ports = final_ingress_internal_ports
|
|
231
252
|
self.readiness_path = profile_data['readiness_probe_config']['path']
|
|
232
253
|
self.readiness_delay = \
|
|
233
254
|
profile_data['readiness_probe_config']['initial_delay_seconds']
|
|
@@ -240,18 +261,58 @@ class ByoSnap:
|
|
|
240
261
|
if self.prefix.endswith('/'):
|
|
241
262
|
snapctl_error("Prefix should not end with a forward slash (/)",
|
|
242
263
|
SNAPCTL_INPUT_ERROR)
|
|
264
|
+
# check that prefix does not contain multiple slashes
|
|
265
|
+
if self.prefix.count('/') > 1:
|
|
266
|
+
snapctl_error("Prefix should not contain multiple path segments",
|
|
267
|
+
SNAPCTL_INPUT_ERROR)
|
|
243
268
|
if not self.version:
|
|
244
269
|
snapctl_error("Missing version", SNAPCTL_INPUT_ERROR)
|
|
245
270
|
pattern = r'^v\d+\.\d+\.\d+$'
|
|
246
271
|
if not re.match(pattern, self.version):
|
|
247
272
|
snapctl_error("Version should be in the format vX.X.X",
|
|
248
273
|
SNAPCTL_INPUT_ERROR)
|
|
249
|
-
if not self.
|
|
274
|
+
if not self.ingress_external_port['port']:
|
|
250
275
|
snapctl_error("Missing Ingress HTTP Port",
|
|
251
276
|
SNAPCTL_INPUT_ERROR)
|
|
252
|
-
if not isinstance(self.
|
|
253
|
-
snapctl_error("Ingress
|
|
277
|
+
if not isinstance(self.ingress_external_port['port'], int):
|
|
278
|
+
snapctl_error("Ingress external port should be a number",
|
|
254
279
|
SNAPCTL_INPUT_ERROR)
|
|
280
|
+
# Check internal ports
|
|
281
|
+
duplicate_name = {}
|
|
282
|
+
duplicate_port = {}
|
|
283
|
+
index = 0
|
|
284
|
+
for internal_port in self.ingress_internal_ports:
|
|
285
|
+
if 'name' not in internal_port or 'port' not in internal_port:
|
|
286
|
+
snapctl_error("Internal ports need a name and a port. Check internal port " +
|
|
287
|
+
f"number {index}.",
|
|
288
|
+
SNAPCTL_INPUT_ERROR)
|
|
289
|
+
# Confirm the name does not collide with the external port
|
|
290
|
+
if internal_port['name'] == self.ingress_external_port['name']:
|
|
291
|
+
snapctl_error("Internal port name should not be the same as " +
|
|
292
|
+
"the external port name", SNAPCTL_INPUT_ERROR)
|
|
293
|
+
# Confirm the port does not collide with the external port
|
|
294
|
+
if internal_port['port'] == self.ingress_external_port['port']:
|
|
295
|
+
snapctl_error("Internal port number should not be the same as " +
|
|
296
|
+
"the external port number", SNAPCTL_INPUT_ERROR)
|
|
297
|
+
index += 1
|
|
298
|
+
if not internal_port['port']:
|
|
299
|
+
snapctl_error("Missing internal port. Check internal port " +
|
|
300
|
+
f"number {index}",
|
|
301
|
+
SNAPCTL_INPUT_ERROR)
|
|
302
|
+
if not isinstance(internal_port['port'], int):
|
|
303
|
+
snapctl_error("Internal port should be a number. Check internal port " +
|
|
304
|
+
f"number {index}",
|
|
305
|
+
SNAPCTL_INPUT_ERROR)
|
|
306
|
+
if internal_port['name'] in duplicate_name:
|
|
307
|
+
snapctl_error("Duplicate internal port name. Check internal port " +
|
|
308
|
+
f"number {index}",
|
|
309
|
+
SNAPCTL_INPUT_ERROR)
|
|
310
|
+
if internal_port['port'] in duplicate_port:
|
|
311
|
+
snapctl_error("Duplicate internal port number. Check internal port " +
|
|
312
|
+
f"number {index}",
|
|
313
|
+
SNAPCTL_INPUT_ERROR)
|
|
314
|
+
duplicate_name[internal_port['name']] = True
|
|
315
|
+
duplicate_port[internal_port['port']] = True
|
|
255
316
|
if self.readiness_path is not None:
|
|
256
317
|
if self.readiness_path.strip() == '':
|
|
257
318
|
snapctl_error("Readiness path cannot be empty",
|
|
@@ -315,6 +376,25 @@ class ByoSnap:
|
|
|
315
376
|
try:
|
|
316
377
|
# Login to Snapser Registry
|
|
317
378
|
if platform == 'win32':
|
|
379
|
+
# Start: Hack for Windows
|
|
380
|
+
data = {
|
|
381
|
+
"auths": {
|
|
382
|
+
"https://index.docker.io/v1/": {}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# Path to the Docker config file, adjust the path as necessary
|
|
387
|
+
docker_config_path = os.path.expanduser(
|
|
388
|
+
'~\\.docker\\config.json')
|
|
389
|
+
|
|
390
|
+
# Ensure the directory exists
|
|
391
|
+
os.makedirs(os.path.dirname(docker_config_path), exist_ok=True)
|
|
392
|
+
|
|
393
|
+
# Write the data to the file
|
|
394
|
+
with open(docker_config_path, 'w', encoding='utf-8') as file:
|
|
395
|
+
json.dump(data, file)
|
|
396
|
+
info("Updated the docker config for docker login")
|
|
397
|
+
# End: Hack for Windows
|
|
318
398
|
response = subprocess.run([
|
|
319
399
|
'docker', 'login', '--username', ecr_repo_username,
|
|
320
400
|
'--password', ecr_repo_token, ecr_repo_url
|
|
@@ -583,6 +663,15 @@ class ByoSnap:
|
|
|
583
663
|
if self.path is None and self.resources_path is None:
|
|
584
664
|
snapctl_error(
|
|
585
665
|
"Missing one of: path or resources-path parameter", SNAPCTL_INPUT_ERROR)
|
|
666
|
+
if not self.tag:
|
|
667
|
+
snapctl_error("Missing tag", SNAPCTL_INPUT_ERROR)
|
|
668
|
+
if len(self.tag.split()) > 1 or \
|
|
669
|
+
len(self.tag) > ByoSnap.TAG_CHARACTER_LIMIT:
|
|
670
|
+
snapctl_error(
|
|
671
|
+
"Tag should be a single word with maximum of " +
|
|
672
|
+
f"{ByoSnap.TAG_CHARACTER_LIMIT} characters",
|
|
673
|
+
SNAPCTL_INPUT_ERROR
|
|
674
|
+
)
|
|
586
675
|
elif self.subcommand == 'publish-version':
|
|
587
676
|
if self.token_parts is None:
|
|
588
677
|
snapctl_error('Invalid token. Please reach out to your support team.',
|
|
@@ -918,14 +1007,19 @@ class ByoSnap:
|
|
|
918
1007
|
"version": self.version,
|
|
919
1008
|
"image_tag": self.tag,
|
|
920
1009
|
"base_url": f"{self.prefix}/{self.sid}",
|
|
921
|
-
"
|
|
1010
|
+
"ingress": {
|
|
1011
|
+
"external_port": self.ingress_external_port,
|
|
1012
|
+
"internal_ports": self.ingress_internal_ports
|
|
1013
|
+
},
|
|
922
1014
|
"readiness_probe_config": {
|
|
923
1015
|
"path": self.readiness_path,
|
|
924
1016
|
"initial_delay_seconds": self.readiness_delay
|
|
925
1017
|
},
|
|
926
1018
|
"dev_template": profile_data['dev_template'],
|
|
927
1019
|
"stage_template": profile_data['stage_template'],
|
|
928
|
-
"prod_template": profile_data['prod_template']
|
|
1020
|
+
"prod_template": profile_data['prod_template'],
|
|
1021
|
+
# Currently not supported so we are just hardcoding an empty list
|
|
1022
|
+
"egress": {"ports": []},
|
|
929
1023
|
}
|
|
930
1024
|
res = requests.post(
|
|
931
1025
|
f"{self.base_url}/v1/snapser-api/byosnaps/{self.sid}/versions",
|
|
@@ -188,15 +188,24 @@ DEFAULT_BYOSNAP_PROD_TEMPLATE: Dict[str, object] = {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
BYOSNAP_TEMPLATE: Dict[str, Dict[str, object]] = {
|
|
191
|
-
|
|
191
|
+
'name': "TODO: Add your BYOSnap name here. Name has to start with byosnap-. This is to ensure we avoid any collisions.",
|
|
192
192
|
'description': "TODO: Add your BYOSnap description here",
|
|
193
193
|
'platform': "TODO: Add your platform here. Options are 'linux/arm64' or 'linux/amd64'",
|
|
194
194
|
'language': "TODO: Add your language here. Options are 'go', 'node', 'python', 'java', 'csharp', 'cpp', 'rust', 'ruby', 'php', 'perl', 'clojure', 'lua', 'ts', 'js', 'kotlin', 'c'",
|
|
195
|
-
'prefix': "TODO: Add your prefix here. Prefix should start with
|
|
196
|
-
'
|
|
195
|
+
'prefix': "TODO: Add your prefix here. Prefix should start with / and only contain one path segment. Eg: '/v1'",
|
|
196
|
+
'ingress': {
|
|
197
|
+
'external_port': {
|
|
198
|
+
'name': 'http',
|
|
199
|
+
'port': "TODO: Enter your external port here. Eg: 5003. Make sure it is a number and not a string."
|
|
200
|
+
},
|
|
201
|
+
'internal_ports': [{
|
|
202
|
+
'name': 'TODO: Optionally add your internal port name here. Eg: grpc. Names should be unique across the `ingress` dict. IMPORTANT: If you are not adding any internal ports, just keep `internal_ports: []`",',
|
|
203
|
+
'port': "TODO: Optionally add your internal port here. Eg: 5004. Make sure it is a number and not a string. Port numbers should be unique across the `ingress` dict."
|
|
204
|
+
}]
|
|
205
|
+
},
|
|
197
206
|
'readiness_probe_config': {
|
|
198
|
-
'initial_delay_seconds': "TODO:
|
|
199
|
-
'path': "TODO:
|
|
207
|
+
'initial_delay_seconds': "TODO: Optionally add your readiness delay in seconds here. Eg: 5 or use null. Make sure it is a number and not a string.",
|
|
208
|
+
'path': "TODO: Optionally add your readiness path here. Eg: '/health' or use null",
|
|
200
209
|
},
|
|
201
210
|
'dev_template': DEFAULT_BYOSNAP_DEV_TEMPLATE,
|
|
202
211
|
'stage_template': DEFAULT_BYOSNAP_STAGE_TEMPLATE,
|
|
@@ -361,7 +361,7 @@ def byosnap(
|
|
|
361
361
|
# publish-image and publish-version
|
|
362
362
|
tag: str = typer.Option(
|
|
363
363
|
None, "--tag", help=(
|
|
364
|
-
"(req: publish-image, publish-version) Tag for your snap"
|
|
364
|
+
"(req: publish-image, publish-version, upload-docs) Tag for your snap"
|
|
365
365
|
)
|
|
366
366
|
),
|
|
367
367
|
# overrides
|
|
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
|