snapctl 0.43.1__py3-none-any.whl → 0.44.1__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.

Potentially problematic release.


This version of snapctl might be problematic. Click here for more details.

snapctl/commands/byogs.py CHANGED
@@ -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.http_port: Union[int, None] = None
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 'http_port' not in profile_data or \
194
- 'readiness_probe_config' not in profile_data or \
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 http_port, and readiness_probe_config fields. Please use ' +
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
- self.http_port = profile_data['http_port']
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.http_port:
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.http_port, int):
253
- snapctl_error("Ingress HTTP Port should be a number",
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
- "http_port": self.http_port,
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",
@@ -2,7 +2,7 @@
2
2
  Constants used by snapctl
3
3
  """
4
4
  COMPANY_NAME = 'Snapser'
5
- VERSION = '0.43.1'
5
+ VERSION = '0.44.1'
6
6
  CONFIG_FILE_MAC = '~/.snapser/config'
7
7
  CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
8
8
 
snapctl/config/hashes.py CHANGED
@@ -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
- "name": "TODO: Add your BYOSnap name here. Name has to start with byosnap-. This is to ensure we avoid any collisions.",
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 /. Eg: '/v1'",
196
- 'http_port': 'TODO: Add your HTTP Port. Eg: 8080',
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: Add your readiness delay in seconds here. Eg: 5 or use null",
199
- 'path': "TODO: Add your readiness path here. Eg: '/health' or use null",
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,
snapctl/main.py CHANGED
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: snapctl
3
- Version: 0.43.1
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
- # $path = 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
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 $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
@@ -1,23 +1,23 @@
1
1
  snapctl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  snapctl/__main__.py,sha256=43jKoTk8b85hk_MT6499N3ruHdEfM8WBImd_-3VzjI8,116
3
3
  snapctl/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- snapctl/commands/byogs.py,sha256=IE4E2Vpy6yJGtuS1M1mTdDF7wHw3pPPW6NkEeyPQt9w,18203
5
- snapctl/commands/byosnap.py,sha256=bYuebT8dFD6tmY1jWMMOs4rodOpcXQ1RYryCAeAwJG8,48689
4
+ snapctl/commands/byogs.py,sha256=jqX20rjgLg75E65Bx26TJpTDRQl2Eg6epFIZPXaJCbE,18989
5
+ snapctl/commands/byosnap.py,sha256=VgZ34gnwt8j1Li2uVXym3XNT1qI9YiS5xkVIBnx9KD4,53706
6
6
  snapctl/commands/game.py,sha256=nCXtEXAJkvOw26c_OBGr7Pz4hwu-5FXHyBR2kkXhLCM,5247
7
7
  snapctl/commands/generate.py,sha256=isiTl3SE1G7wqEWjdYPKDtlBR-HE2-iNdZK_pKgiKvY,8398
8
8
  snapctl/commands/snapend.py,sha256=Zq9lNp1NO5fHzlv2S4TrzBZUIxssOu4_ZEQFMO2Tfbc,34677
9
9
  snapctl/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- snapctl/config/constants.py,sha256=4FIn-Yd1HSuSQHbxjYsXEMnGqnWsY3C6HF-5s-msmuE,3309
10
+ snapctl/config/constants.py,sha256=4kChgdr97xeUtLE80GPM1cP8ClZxn_EKMsZRgNq3pXA,3309
11
11
  snapctl/config/endpoints.py,sha256=9kllA79xn9G_aBLp1rohURZi93pwYzTEWZ8ObtZ6crw,338
12
- snapctl/config/hashes.py,sha256=0Mtbv1J-RWxIkONguZbNOGuu431zElt0JHvxIes4eA4,5044
13
- snapctl/main.py,sha256=LgVXkCqDpmDZY9NJ0XoYq16-uV5-NKhu8x2wZ_Vqe_8,21450
12
+ snapctl/config/hashes.py,sha256=sLk221XI8-fAfiIZ_sKmddcebL9yTCDIlhxQZNj4NA8,5729
13
+ snapctl/main.py,sha256=DwndBr5-d18epV1PMzCINAargBMOblbXBTHsFsVZHXU,21463
14
14
  snapctl/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  snapctl/types/definitions.py,sha256=EQzLeiXkJ8ISRlCqHMviNVsWWpmhWjpKaOBLdlvOTmY,644
16
16
  snapctl/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  snapctl/utils/echo.py,sha256=V0qgjqqGXRiueMkq31enmNmdqciC8S90qGRcK8UupXA,1090
18
18
  snapctl/utils/helper.py,sha256=8HrLqX9RINJdadR7YI8epOXIfXOBDusXqvoR0kq6zok,5419
19
- snapctl-0.43.1.dist-info/LICENSE,sha256=6AcXm54KFSpmUI1ji9NIBd4Xl-DtjTqiyjBzfVb_CEk,2804
20
- snapctl-0.43.1.dist-info/METADATA,sha256=bWrjuKrzXIFomh8PVkEFg9bBaboQnCz3CBWlbY7dYpc,28838
21
- snapctl-0.43.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
22
- snapctl-0.43.1.dist-info/entry_points.txt,sha256=tkKW9MzmFdRs6Bgkv29G78i9WEBK4WIOWunPfe3t2Wg,44
23
- snapctl-0.43.1.dist-info/RECORD,,
19
+ snapctl-0.44.1.dist-info/LICENSE,sha256=6AcXm54KFSpmUI1ji9NIBd4Xl-DtjTqiyjBzfVb_CEk,2804
20
+ snapctl-0.44.1.dist-info/METADATA,sha256=QcNmOclG7_621_jHPOhaOZlx6H1d0JDzvy2ABEO1EW8,28866
21
+ snapctl-0.44.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
22
+ snapctl-0.44.1.dist-info/entry_points.txt,sha256=tkKW9MzmFdRs6Bgkv29G78i9WEBK4WIOWunPfe3t2Wg,44
23
+ snapctl-0.44.1.dist-info/RECORD,,