snapctl 0.31.0__tar.gz → 0.32.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.32.0/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ Snapser Inc. Proprietary License
2
+
3
+ This CLI tool, its source code, and any accompanying documentation (collectively referred to as the "Software") are the property of Snapser Inc. ("Snapser"). The Software is provided under the following license terms and conditions:
4
+
5
+ 1. License Grant:
6
+ Snapser grants you a non-exclusive, non-transferable, revocable license to use the Software solely for your internal business purposes. You may not distribute, sublicense, rent, lease, sell, or otherwise transfer the Software or any portion thereof.
7
+
8
+ 2. Restrictions:
9
+ You may not modify, adapt, translate, reverse engineer, decompile, disassemble, or create derivative works based on the Software. You may not remove or alter any copyright, trademark, or other proprietary rights notices contained in the Software.
10
+
11
+ 3. Ownership:
12
+ The Software and all intellectual property rights therein are and shall remain the exclusive property of Snapser Inc. Nothing in this license agreement shall be construed to transfer ownership of the Software to you.
13
+
14
+ 4. Term and Termination:
15
+ This license is effective until terminated by either party. Snapser may terminate this license at any time if you breach any of its terms and conditions. Upon termination, you must immediately cease all use of the Software and destroy all copies thereof.
16
+
17
+ 5. Disclaimer of Warranty:
18
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, SNAPSER DISCLAIMS ALL WARRANTIES, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. SNAPSER DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE.
19
+
20
+ 6. Limitation of Liability:
21
+ IN NO EVENT SHALL SNAPSER BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF SNAPSER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
22
+
23
+ 7. Governing Law:
24
+ This license agreement shall be governed by and construed in accordance with the laws of the United States of America, excluding its conflicts of law principles. Any disputes arising out of or in connection with this agreement shall be subject to the exclusive jurisdiction of the courts located in the United States of America.
25
+
26
+ By using the Software, you agree to be bound by the terms and conditions of this license agreement. If you do not agree to these terms and conditions, do not use the Software.
27
+
28
+ Snapser Inc.
29
+ June 4, 2024
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: snapctl
3
- Version: 0.31.0
3
+ Version: 0.32.0
4
4
  Summary: Snapser CLI Tool
5
5
  Author: Ajinkya Apte
6
6
  Author-email: aj@snapser.com
@@ -101,7 +101,10 @@ be evaluated after verifying if there is any command line argument.
101
101
 
102
102
  Create a file named `~/.snapser/config`. Open it using the editor of your choice and replace with your
103
103
  personal Snapser Access key. Save the file. Advantage of using this method is you can use the `--profile`
104
- argument with your snapctl command to use different API keys.
104
+ argument with your snapctl command to use different API keys. NOTE: You may want to pass your own path
105
+ instead on relying on the default one the CLI looks for. You can do so by setting an environment
106
+ variable `SNAPSER_CONFIG_PATH='<your_custom_path>'`. Doing this will make sure that the CLI tool
107
+ will look for the config file at that path.
105
108
 
106
109
  ```
107
110
  [default]
@@ -241,16 +244,16 @@ snapctl byosnap push $byosnap_sid --tag $image_tag
241
244
  Upload swagger.json and README.md for you Snap
242
245
 
243
246
  ```
244
- # Help for the byogs command
247
+ # Help for the byosnap command
245
248
  snapctl byosnap upload-docs --help
246
249
 
247
250
  # Publish a new image
248
- # $byogs_sid = Game server ID for your snap
251
+ # $byosnap_sid = Snap ID for your snap
249
252
  # $image_tag = An image tag for your snap
250
253
  # $code_root_path = Local code path where your swagger.json and README.md files are present
251
254
  # Example:
252
255
  # snapctl byosnap upload-docs byosnap-jinks-flask --tag my-first-image --path /Users/DevName/Development/SnapserEngine/jinks_flask
253
- snapctl byosnap upload-docs $byogs_sid --tag $image_tag --path $code_root_path
256
+ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
254
257
  ```
255
258
 
256
259
  #### 6. byosnap publish-image
@@ -302,28 +305,7 @@ See all the supported commands
302
305
  snapctl byogs --help
303
306
  ```
304
307
 
305
- #### 2. [Deprecated soon] byogs create
306
-
307
- Create a custom game server. Note that you will have to build, push and publish your game server image, for it to be useable
308
- in a Snapend fleet.
309
-
310
- ```
311
- # Help for the byosnap command
312
- snapctl byogs create --help
313
-
314
- # Create a new snap
315
- # $byogs_sid = Game server ID for your snap. Should start with `byogs-`
316
- # $name = User friendly name for your BYOGs
317
- # $desc = User friendly description
318
- # $platform = Currently only supported platform is linux/amd64
319
- # $language = One of go, python, ruby, c#, c++, rust, java, node
320
-
321
- # Example:
322
- # snapctl byogs create byosnap-jinks-gs --name "Jinks Flask Microservice" --desc "Custom Microservice" --platform "linux/arm64" --language "go"
323
- snapctl byogs create $byogs_sid --name "$name" --desc "$desc" --platform "$platform" --language "$language"
324
- ```
325
-
326
- #### 3. byogs build
308
+ #### 2. byogs build
327
309
 
328
310
  Build your custom game server image.
329
311
 
@@ -332,15 +314,14 @@ Build your custom game server image.
332
314
  snapctl byogs build --help
333
315
 
334
316
  # Publish a new image
335
- # $byogs_sid = Game server ID for your snap
336
317
  # $image_tag = An image tag for your snap
337
318
  # $code_root_path = Local code path where your Dockerfile is present
338
319
  # Example:
339
320
  # snapctl byogs build byosnap-jinks-gs --tag my-first-image --path /Users/DevName/Development/SnapserEngine/game_server
340
- snapctl byogs build $byogs_sid --tag $image_tag --path $code_root_path
321
+ snapctl byogs build --tag $image_tag --path $code_root_path
341
322
  ```
342
323
 
343
- #### 4. byogs push
324
+ #### 3. byogs push
344
325
 
345
326
  Push your custom game server image.
346
327
 
@@ -349,51 +330,13 @@ Push your custom game server image.
349
330
  snapctl byogs push --help
350
331
 
351
332
  # Publish a new image
352
- # $byogs_sid = Game server ID for your snap
353
333
  # $image_tag = An image tag for your snap
354
334
  # Example:
355
335
  # snapctl byogs push byosnap-jinks-gs --tag my-first-image
356
- snapctl byogs push $byogs_sid --tag $image_tag
357
- ```
358
-
359
- #### 5. [Deprecated soon] byogs publish-image
360
-
361
- Publish your custom game server image. This command executes, `build` and `push` one after the other.
362
-
363
- ```
364
- # Help for the byogs command
365
- snapctl byogs publish-image --help
366
-
367
- # Publish a new image
368
- # $byogs_sid = Game server ID for your snap
369
- # $image_tag = An image tag for your snap
370
- # $code_root_path = Local code path where your Dockerfile is present
371
- # Example:
372
- # snapctl byogs publish-image byosnap-jinks-gs --tag my-first-image --path /Users/DevName/Development/SnapserEngine/game_server
373
- snapctl byogs publish-image $byogs_sid --tag $image_tag --path $code_root_path
374
- ```
375
-
376
- #### 6. [Deprecated soon] byogs publish-version
377
-
378
- Publish a new version for your game server. Only after your game server version is published, you will be able
379
- to use it in your Snapend fleet. This command should be run after you `push` or `publish-image` commands.
380
-
381
- ```
382
- # Help for the byogs command
383
- snapctl byogs publish-version --help
384
-
385
- # Publish a new image
386
- # $byogs_sid = Snap ID for your snap
387
- # $image_tag = Any image tag for your snap
388
- # $prefix = Prefix for your snap Eg: /v1
389
- # $version = Semantic version for your snap Eg: v0.0.1
390
- # $ingress_port = Ingress port for your snap Eg: 5003
391
- # Example:
392
- # snapctl byogs publish-image byosnap-jinks-gs --tag my-first-image --prefix /v1 --version v0.0.1 --http-port 5003
393
- snapctl byogs publish-version $byogs_sid --tag $image_tag --prefix $prefix --version $version --http-port $ingress_port
336
+ snapctl byogs push --tag $image_tag
394
337
  ```
395
338
 
396
- #### 7. [New] byogs publish
339
+ #### 4. byogs publish
397
340
 
398
341
  Publish your custom game server image. This commend replaces the old way of creating, publishing image and
399
342
  then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
@@ -523,9 +466,9 @@ snapctl snapend update --help
523
466
  # --blocking = (Optional) This makes sure the CLI waits till your Snapend is live.
524
467
  # Note at least one of the two needs to be present
525
468
  # Example:
526
- # snapctl snapend update gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs byogs-fleet-one:gs-1:v0.0.1,my-fleet-two:gs-2:v0.0.4
527
- # snapctl snapend update gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs fleet-one:v0.0.1,fleet-two:v0.0.4 --blocking
528
- snapctl snapend update $snapend_id --byosnaps $byosnaps --byogs $byogs --blocking
469
+ # snapctl snapend update --snapend-id gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs byogs-fleet-one:gs-1:v0.0.1,my-fleet-two:gs-2:v0.0.4
470
+ # snapctl snapend update --snapend-id gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs fleet-one:v0.0.1,fleet-two:v0.0.4 --blocking
471
+ snapctl snapend update --snapend-id $snapend_id --byosnaps $byosnaps --byogs $byogs --blocking
529
472
  ```
530
473
 
531
474
  #### 6. Get the Snapend state
@@ -84,7 +84,10 @@ be evaluated after verifying if there is any command line argument.
84
84
 
85
85
  Create a file named `~/.snapser/config`. Open it using the editor of your choice and replace with your
86
86
  personal Snapser Access key. Save the file. Advantage of using this method is you can use the `--profile`
87
- argument with your snapctl command to use different API keys.
87
+ argument with your snapctl command to use different API keys. NOTE: You may want to pass your own path
88
+ instead on relying on the default one the CLI looks for. You can do so by setting an environment
89
+ variable `SNAPSER_CONFIG_PATH='<your_custom_path>'`. Doing this will make sure that the CLI tool
90
+ will look for the config file at that path.
88
91
 
89
92
  ```
90
93
  [default]
@@ -224,16 +227,16 @@ snapctl byosnap push $byosnap_sid --tag $image_tag
224
227
  Upload swagger.json and README.md for you Snap
225
228
 
226
229
  ```
227
- # Help for the byogs command
230
+ # Help for the byosnap command
228
231
  snapctl byosnap upload-docs --help
229
232
 
230
233
  # Publish a new image
231
- # $byogs_sid = Game server ID for your snap
234
+ # $byosnap_sid = Snap ID for your snap
232
235
  # $image_tag = An image tag for your snap
233
236
  # $code_root_path = Local code path where your swagger.json and README.md files are present
234
237
  # Example:
235
238
  # snapctl byosnap upload-docs byosnap-jinks-flask --tag my-first-image --path /Users/DevName/Development/SnapserEngine/jinks_flask
236
- snapctl byosnap upload-docs $byogs_sid --tag $image_tag --path $code_root_path
239
+ snapctl byosnap upload-docs $byosnap_sid --tag $image_tag --path $code_root_path
237
240
  ```
238
241
 
239
242
  #### 6. byosnap publish-image
@@ -285,28 +288,7 @@ See all the supported commands
285
288
  snapctl byogs --help
286
289
  ```
287
290
 
288
- #### 2. [Deprecated soon] byogs create
289
-
290
- Create a custom game server. Note that you will have to build, push and publish your game server image, for it to be useable
291
- in a Snapend fleet.
292
-
293
- ```
294
- # Help for the byosnap command
295
- snapctl byogs create --help
296
-
297
- # Create a new snap
298
- # $byogs_sid = Game server ID for your snap. Should start with `byogs-`
299
- # $name = User friendly name for your BYOGs
300
- # $desc = User friendly description
301
- # $platform = Currently only supported platform is linux/amd64
302
- # $language = One of go, python, ruby, c#, c++, rust, java, node
303
-
304
- # Example:
305
- # snapctl byogs create byosnap-jinks-gs --name "Jinks Flask Microservice" --desc "Custom Microservice" --platform "linux/arm64" --language "go"
306
- snapctl byogs create $byogs_sid --name "$name" --desc "$desc" --platform "$platform" --language "$language"
307
- ```
308
-
309
- #### 3. byogs build
291
+ #### 2. byogs build
310
292
 
311
293
  Build your custom game server image.
312
294
 
@@ -315,15 +297,14 @@ Build your custom game server image.
315
297
  snapctl byogs build --help
316
298
 
317
299
  # Publish a new image
318
- # $byogs_sid = Game server ID for your snap
319
300
  # $image_tag = An image tag for your snap
320
301
  # $code_root_path = Local code path where your Dockerfile is present
321
302
  # Example:
322
303
  # snapctl byogs build byosnap-jinks-gs --tag my-first-image --path /Users/DevName/Development/SnapserEngine/game_server
323
- snapctl byogs build $byogs_sid --tag $image_tag --path $code_root_path
304
+ snapctl byogs build --tag $image_tag --path $code_root_path
324
305
  ```
325
306
 
326
- #### 4. byogs push
307
+ #### 3. byogs push
327
308
 
328
309
  Push your custom game server image.
329
310
 
@@ -332,51 +313,13 @@ Push your custom game server image.
332
313
  snapctl byogs push --help
333
314
 
334
315
  # Publish a new image
335
- # $byogs_sid = Game server ID for your snap
336
316
  # $image_tag = An image tag for your snap
337
317
  # Example:
338
318
  # snapctl byogs push byosnap-jinks-gs --tag my-first-image
339
- snapctl byogs push $byogs_sid --tag $image_tag
340
- ```
341
-
342
- #### 5. [Deprecated soon] byogs publish-image
343
-
344
- Publish your custom game server image. This command executes, `build` and `push` one after the other.
345
-
346
- ```
347
- # Help for the byogs command
348
- snapctl byogs publish-image --help
349
-
350
- # Publish a new image
351
- # $byogs_sid = Game server ID for your snap
352
- # $image_tag = An image tag for your snap
353
- # $code_root_path = Local code path where your Dockerfile is present
354
- # Example:
355
- # snapctl byogs publish-image byosnap-jinks-gs --tag my-first-image --path /Users/DevName/Development/SnapserEngine/game_server
356
- snapctl byogs publish-image $byogs_sid --tag $image_tag --path $code_root_path
357
- ```
358
-
359
- #### 6. [Deprecated soon] byogs publish-version
360
-
361
- Publish a new version for your game server. Only after your game server version is published, you will be able
362
- to use it in your Snapend fleet. This command should be run after you `push` or `publish-image` commands.
363
-
364
- ```
365
- # Help for the byogs command
366
- snapctl byogs publish-version --help
367
-
368
- # Publish a new image
369
- # $byogs_sid = Snap ID for your snap
370
- # $image_tag = Any image tag for your snap
371
- # $prefix = Prefix for your snap Eg: /v1
372
- # $version = Semantic version for your snap Eg: v0.0.1
373
- # $ingress_port = Ingress port for your snap Eg: 5003
374
- # Example:
375
- # snapctl byogs publish-image byosnap-jinks-gs --tag my-first-image --prefix /v1 --version v0.0.1 --http-port 5003
376
- snapctl byogs publish-version $byogs_sid --tag $image_tag --prefix $prefix --version $version --http-port $ingress_port
319
+ snapctl byogs push --tag $image_tag
377
320
  ```
378
321
 
379
- #### 7. [New] byogs publish
322
+ #### 4. byogs publish
380
323
 
381
324
  Publish your custom game server image. This commend replaces the old way of creating, publishing image and
382
325
  then publishing the byogs. Now all you have to do is publish your image and create a fleet using the web portal.
@@ -506,9 +449,9 @@ snapctl snapend update --help
506
449
  # --blocking = (Optional) This makes sure the CLI waits till your Snapend is live.
507
450
  # Note at least one of the two needs to be present
508
451
  # Example:
509
- # snapctl snapend update gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs byogs-fleet-one:gs-1:v0.0.1,my-fleet-two:gs-2:v0.0.4
510
- # snapctl snapend update gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs fleet-one:v0.0.1,fleet-two:v0.0.4 --blocking
511
- snapctl snapend update $snapend_id --byosnaps $byosnaps --byogs $byogs --blocking
452
+ # snapctl snapend update --snapend-id gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs byogs-fleet-one:gs-1:v0.0.1,my-fleet-two:gs-2:v0.0.4
453
+ # snapctl snapend update --snapend-id gx5x6bc0 --byosnaps byosnap-service-1:v1.0.0,byosnap-service--2:v1.0.0 --byogs fleet-one:v0.0.1,fleet-two:v0.0.4 --blocking
454
+ snapctl snapend update --snapend-id $snapend_id --byosnaps $byosnaps --byogs $byogs --blocking
512
455
  ```
513
456
 
514
457
  #### 6. Get the Snapend state
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "snapctl"
3
- version = "0.31.0"
3
+ version = "0.32.0"
4
4
  description = "Snapser CLI Tool"
5
5
  authors = ["Ajinkya Apte <aj@snapser.com>"]
6
6
  readme = "README.md"
@@ -3,18 +3,12 @@
3
3
  """
4
4
  import base64
5
5
  from binascii import Error as BinasciiError
6
- import json
7
6
  import os
8
- import re
9
7
  import subprocess
10
8
  from sys import platform
11
9
  from typing import Union
12
- import requests
13
- from requests.exceptions import RequestException
14
10
 
15
11
  from rich.progress import Progress, SpinnerColumn, TextColumn
16
- from snapctl.config.constants import SERVER_CALL_TIMEOUT
17
- from snapctl.config.constants import ERROR_SERVICE_VERSION_EXISTS, ERROR_TAG_NOT_AVAILABLE
18
12
  from snapctl.types.definitions import ResponseType
19
13
  from snapctl.utils.echo import error, success
20
14
  from snapctl.utils.helper import get_composite_token
@@ -25,11 +19,7 @@ class ByoGs:
25
19
  BYOGS CLI commands
26
20
  """
27
21
  SID = 'byogs'
28
- SUBCOMMANDS = [
29
- 'build', 'push',
30
- 'create', 'publish-image', 'publish-version',
31
- 'publish'
32
- ]
22
+ SUBCOMMANDS = ['build', 'push', 'publish']
33
23
  PLATFORMS = ['linux/amd64']
34
24
  LANGUAGES = ['go', 'python', 'ruby', 'c#', 'c++', 'rust', 'java', 'node']
35
25
  DEFAULT_BUILD_PLATFORM = 'linux/amd64'
@@ -37,34 +27,24 @@ class ByoGs:
37
27
  TAG_CHARACTER_LIMIT = 80
38
28
 
39
29
  def __init__(
40
- self, subcommand: str, base_url: str, api_key: str | None, sid: str, name: str, desc: str,
41
- platform_type: str, language: str, input_tag: Union[str, None], path: Union[str, None],
42
- dockerfile: str, version: Union[str, None], http_port: Union[int, None],
43
- debug_port: Union[int, None]
30
+ self, subcommand: str, base_url: str, api_key: str | None,
31
+ input_tag: Union[str, None], path: Union[str, None], dockerfile: str,
44
32
  ) -> None:
45
33
  self.subcommand: str = subcommand
46
34
  self.base_url: str = base_url
47
35
  self.api_key: str = api_key
48
- self.sid: str = sid
49
- if subcommand == 'publish':
50
- self.sid = ByoGs.SID
51
- self.name: str = name
52
- self.desc: str = desc
53
- self.platform_type: str = platform_type
54
- self.language: str = language
55
- self.token: Union[str, None] = None
56
- if subcommand != 'create':
57
- self.token: Union[str, None] = get_composite_token(
58
- base_url, api_key, 'byogs', {'service_id': self.sid}
59
- )
36
+ # self.sid: str = sid
37
+ # if subcommand == 'publish':
38
+ # self.sid = ByoGs.SID
39
+
40
+ self.token: Union[str, None] = get_composite_token(
41
+ base_url, api_key, 'byogs', {'service_id': ByoGs.SID}
42
+ )
60
43
  self.token_parts: Union[list, None] = ByoGs._get_token_values(
61
44
  self.token) if self.token is not None else None
62
45
  self.input_tag: Union[str, None] = input_tag
63
46
  self.path: Union[str, None] = path
64
47
  self.dockerfile: str = dockerfile
65
- self.version: Union[str, None] = version
66
- self.http_port: Union[int, None] = http_port
67
- self.debug_port: Union[int, None] = debug_port
68
48
 
69
49
  # Protected methods
70
50
 
@@ -151,7 +131,7 @@ class ByoGs:
151
131
 
152
132
  def _docker_build(self) -> bool:
153
133
  # Get the data
154
- image_tag = f'{self.sid}.{self.input_tag}'
134
+ image_tag = f'{ByoGs.SID}.{self.input_tag}'
155
135
  build_platform = ByoGs.DEFAULT_BUILD_PLATFORM
156
136
  if len(self.token_parts) == 4:
157
137
  build_platform = self.token_parts[3]
@@ -190,7 +170,7 @@ class ByoGs:
190
170
  def _docker_tag(self) -> bool:
191
171
  # Get the data
192
172
  ecr_repo_url = self.token_parts[0]
193
- image_tag = f'{self.sid}.{self.input_tag}'
173
+ image_tag = f'{ByoGs.SID}.{self.input_tag}'
194
174
  full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
195
175
  try:
196
176
  # Tag the repo
@@ -221,7 +201,7 @@ class ByoGs:
221
201
  def _docker_push(self) -> bool:
222
202
  try:
223
203
  ecr_repo_url = self.token_parts[0]
224
- image_tag = f'{self.sid}.{self.input_tag}'
204
+ image_tag = f'{ByoGs.SID}.{self.input_tag}'
225
205
  full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
226
206
 
227
207
  # Push the image
@@ -271,80 +251,33 @@ class ByoGs:
271
251
  if not self.subcommand in ByoGs.SUBCOMMANDS:
272
252
  response['msg'] = f"Invalid command. Valid commands are {', '.join(ByoGs.SUBCOMMANDS)}."
273
253
  return response
274
- # Validate the SID
275
- if not self.sid.startswith(ByoGs.SID):
276
- response['msg'] = (
277
- "Invalid Game Server ID. Valid Game Server IDs start "
278
- f"with {ByoGs.SID}."
279
- )
254
+ # Validation for subcommands
255
+ if self.token_parts is None:
256
+ response['msg'] = 'Invalid token. Please reach out to your support team'
280
257
  return response
281
- if len(self.sid) > ByoGs.SID_CHARACTER_LIMIT:
258
+ # Check tag
259
+ if self.input_tag is None or len(self.input_tag.split()) > 1 or \
260
+ len(self.input_tag) > ByoGs.TAG_CHARACTER_LIMIT:
282
261
  response['msg'] = (
283
- "Invalid Game Server ID. "
284
- f"Game Server ID should be less than {ByoGs.SID_CHARACTER_LIMIT} characters"
262
+ "Tag should be a single word with maximum of "
263
+ f"{ByoGs.TAG_CHARACTER_LIMIT} characters"
285
264
  )
286
265
  return response
287
- # Validation for subcommands
288
- if self.subcommand == 'create':
289
- if self.name == '':
290
- response['msg'] = "Missing name"
291
- return response
292
- if self.language not in ByoGs.LANGUAGES:
293
- response['msg'] = (
294
- "Invalid language. Valid languages "
295
- f"are {', '.join(ByoGs.LANGUAGES)}."
296
- )
266
+ if self.subcommand in ['build', 'publish']:
267
+ if not self.input_tag:
268
+ response['msg'] = "Missing required parameter: tag"
297
269
  return response
298
- if self.platform_type not in ByoGs.PLATFORMS:
299
- response['msg'] = (
300
- "Invalid platform. Valid platforms "
301
- f"are {', '.join(ByoGs.PLATFORMS)}."
302
- )
270
+ if not self.path:
271
+ response['msg'] = "Missing required parameter: path"
303
272
  return response
304
- else:
305
- if self.token_parts is None:
306
- response['msg'] = 'Invalid token. Please reach out to your support team'
273
+ # Check path
274
+ if not os.path.isfile(f"{self.path}/{self.dockerfile}"):
275
+ response['msg'] = f"Unable to find {self.dockerfile} at path {self.path}"
307
276
  return response
308
- # Check tag
309
- if self.input_tag is None or len(self.input_tag.split()) > 1 or \
310
- len(self.input_tag) > ByoGs.TAG_CHARACTER_LIMIT:
311
- response['msg'] = (
312
- "Tag should be a single word with maximum of "
313
- f"{ByoGs.TAG_CHARACTER_LIMIT} characters"
314
- )
277
+ elif self.subcommand == 'push':
278
+ if not self.input_tag:
279
+ response['msg'] = "Missing required parameter: tag"
315
280
  return response
316
- if self.subcommand in ['build', 'publish-image', 'publish']:
317
- if not self.input_tag:
318
- response['msg'] = "Missing required parameter: tag"
319
- return response
320
- if not self.path:
321
- response['msg'] = "Missing required parameter: path"
322
- return response
323
- # Check path
324
- if not os.path.isfile(f"{self.path}/{self.dockerfile}"):
325
- response['msg'] = f"Unable to find {self.dockerfile} at path {self.path}"
326
- return response
327
- elif self.subcommand == 'push':
328
- if not self.input_tag:
329
- response['msg'] = "Missing required parameter: tag"
330
- return response
331
- elif self.subcommand == 'publish-version':
332
- if not self.version:
333
- response['msg'] = "Missing required parameter: version"
334
- return response
335
- if not self.http_port:
336
- response['msg'] = "Missing required parameter: Ingress HTTP Port"
337
- return response
338
- pattern = r'^v\d+\.\d+\.\d+$'
339
- if not re.match(pattern, self.version):
340
- response['msg'] = "Version should be in the format vX.X.X"
341
- return response
342
- if not self.http_port.isdigit():
343
- response['msg'] = "Ingress HTTP Port should be a number"
344
- return response
345
- if self.debug_port and not self.debug_port.isdigit():
346
- response['msg'] = "Debug Port should be a number"
347
- return response
348
281
  # Send success
349
282
  response['error'] = False
350
283
  return response
@@ -376,63 +309,6 @@ class ByoGs:
376
309
  return True
377
310
 
378
311
  # Upper echelon commands
379
- def create(self) -> bool:
380
- """
381
- Create a new game server
382
- """
383
- with Progress(
384
- SpinnerColumn(),
385
- TextColumn("[progress.description]{task.description}"),
386
- transient=True,
387
- ) as progress:
388
- progress.add_task(
389
- description='Creating your game server...', total=None)
390
- try:
391
- payload = {
392
- "service_id": self.sid,
393
- "name": self.name,
394
- "description": self.desc,
395
- "platform": self.platform_type,
396
- "language": self.language,
397
- }
398
- res = requests.post(
399
- f"{self.base_url}/v1/snapser-api/byogs",
400
- json=payload, headers={'api-key': self.api_key},
401
- timeout=SERVER_CALL_TIMEOUT
402
- )
403
- if res.ok:
404
- return True
405
- response_json = res.json()
406
- if "api_error_code" in response_json:
407
- if response_json['api_error_code'] == ERROR_SERVICE_VERSION_EXISTS:
408
- error(
409
- 'Version already exists. Please update your version and try again'
410
- )
411
- if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
412
- error('Invalid tag. Please use the correct tag')
413
- else:
414
- error(
415
- f'Server error: {json.dumps(response_json, indent=2)}'
416
- )
417
- except RequestException as e:
418
- error(f"Exception: Unable to create your game server {e}")
419
- return False
420
-
421
- def publish_image(self) -> bool:
422
- """
423
- Publish the image
424
- 1. Check Dependencies
425
- 2. Login to Snapser Registry
426
- 3. Build your snap
427
- 4. Tag the repo
428
- 5. Push the image
429
- 6. Upload swagger.json
430
- """
431
- if not self._check_dependencies() or not self._docker_login() or \
432
- not self._docker_build() or not self._docker_tag() or not self._docker_push():
433
- return False
434
- return True
435
-
436
312
  def publish(self) -> bool:
437
313
  """
438
314
  Publish the image
@@ -447,47 +323,3 @@ class ByoGs:
447
323
  not self._docker_build() or not self._docker_tag() or not self._docker_push():
448
324
  return False
449
325
  return True
450
-
451
- def publish_version(self) -> bool:
452
- """
453
- Publish your game server version
454
- """
455
- with Progress(
456
- SpinnerColumn(),
457
- TextColumn("[progress.description]{task.description}"),
458
- transient=True,
459
- ) as progress:
460
- progress.add_task(
461
- description='Publishing your snap...', total=None)
462
- try:
463
- payload = {
464
- "version": self.version,
465
- "image_tag": self.input_tag,
466
- "http_port": self.http_port,
467
- }
468
- if self.debug_port:
469
- payload['debug_port'] = self.debug_port
470
- res = requests.post(
471
- f"{self.base_url}/v1/snapser-api/byogs/{self.sid}/versions",
472
- json=payload, headers={'api-key': self.api_key},
473
- timeout=SERVER_CALL_TIMEOUT
474
- )
475
- if res.ok:
476
- return True
477
- response_json = res.json()
478
- if "api_error_code" in response_json:
479
- if response_json['api_error_code'] == ERROR_SERVICE_VERSION_EXISTS:
480
- error(
481
- 'Version already exists. Please update your version and try again'
482
- )
483
- if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
484
- error('Invalid tag. Please use the correct tag')
485
- else:
486
- error(
487
- f'Server error: {json.dumps(response_json, indent=2)}'
488
- )
489
- except RequestException as e:
490
- error(
491
- f"Exception: Unable to publish a version for your snap {e}"
492
- )
493
- return False
@@ -35,12 +35,14 @@ class ByoSnap:
35
35
  DEFAULT_BUILD_PLATFORM = 'linux/arm64'
36
36
  SID_CHARACTER_LIMIT = 47
37
37
  TAG_CHARACTER_LIMIT = 80
38
+ VALID_CPU_MARKS = [100, 250, 500, 750, 1000, 1500, 2000, 3000]
39
+ VALID_MEMORY_MARKS = [0.125, 0.25, 0.5, 1, 2, 3, 4]
38
40
 
39
41
  def __init__(
40
42
  self, subcommand: str, base_url: str, api_key: str | None, sid: str, name: str,
41
43
  desc: str, platform_type: str, language: str, input_tag: Union[str, None],
42
44
  path: Union[str, None], dockerfile: str, prefix: str, version: Union[str, None],
43
- http_port: Union[int, None]
45
+ http_port: Union[int, None], byosnap_profile: Union[str, None]
44
46
  ) -> None:
45
47
  self.subcommand: str = subcommand
46
48
  self.base_url: str = base_url
@@ -65,6 +67,7 @@ class ByoSnap:
65
67
  self.prefix: str = prefix
66
68
  self.version: Union[str, None] = version
67
69
  self.http_port: Union[int, None] = http_port
70
+ self.byosnap_profile: Union[str, None] = byosnap_profile
68
71
 
69
72
  # Protected methods
70
73
  @staticmethod
@@ -254,6 +257,63 @@ class ByoSnap:
254
257
  success('Snap Upload Successful')
255
258
  return True
256
259
 
260
+ def _validate_byosnap_profile(self) -> bool:
261
+ """
262
+ Validate the BYOSnap profile
263
+ """
264
+ response = {
265
+ 'error': True,
266
+ 'message': ''
267
+ }
268
+ if not self.byosnap_profile:
269
+ response['message'] = "Missing BYOSnap profile path"
270
+ return response
271
+ if not os.path.isfile(self.byosnap_profile):
272
+ response['msg'] = (
273
+ "Unable to find BYOSnap profile "
274
+ F"JSON at path {self.byosnap_profile}"
275
+ )
276
+ return response
277
+ with open(self.byosnap_profile, 'rb') as file:
278
+ try:
279
+ profile_data = json.load(file)
280
+ except json.JSONDecodeError:
281
+ response['message'] = (
282
+ 'Invalid BYOSnap profile JSON. Please check the JSON structure'
283
+ )
284
+ return response
285
+ if 'dev_template' not in profile_data or \
286
+ 'stage_template' not in profile_data or \
287
+ 'prod_template' not in profile_data:
288
+ response['message'] = (
289
+ 'Invalid BYOSnap profile JSON. Please check the JSON structure'
290
+ )
291
+ return response
292
+ for profile in ['dev_template', 'stage_template', 'prod_template']:
293
+ if 'cpu' not in profile_data[profile] or \
294
+ 'memory' not in profile_data[profile] or \
295
+ 'cmd' not in profile_data[profile] or \
296
+ 'args' not in profile_data[profile] or \
297
+ 'env_params' not in profile_data[profile]:
298
+ response['message'] = (
299
+ 'Invalid BYOSnap profile JSON. Please check the JSON structure'
300
+ )
301
+ return response
302
+ if profile_data[profile]['cpu'] not in ByoSnap.VALID_CPU_MARKS:
303
+ response['message'] = (
304
+ 'Invalid CPU value in BYOSnap profile. '
305
+ f'Valid values are {", ".join(ByoSnap.VALID_CPU_MARKS)}'
306
+ )
307
+ return response
308
+ if profile_data[profile]['memory'] not in ByoSnap.VALID_MEMORY_MARKS:
309
+ response['message'] = (
310
+ 'Invalid Memory value in BYOSnap profile. '
311
+ f'Valid values are {", ".join(ByoSnap.VALID_MEMORY_MARKS)}'
312
+ )
313
+ return response
314
+ response['error'] = False
315
+ return response
316
+
257
317
  # Public methods
258
318
 
259
319
  # Validator
@@ -359,6 +419,12 @@ class ByoSnap:
359
419
  if not self.http_port.isdigit():
360
420
  response['msg'] = "Ingress HTTP Port should be a number"
361
421
  return response
422
+ # Check byosnap_profile path
423
+ validation_response = self._validate_byosnap_profile()
424
+ if validation_response['error']:
425
+ response['msg'] = validation_response['message']
426
+ return response
427
+
362
428
  # Send success
363
429
  response['error'] = False
364
430
  return response
@@ -539,11 +605,20 @@ class ByoSnap:
539
605
  progress.add_task(
540
606
  description='Publishing your snap...', total=None)
541
607
  try:
608
+ profile_data = {}
609
+ profile_data['dev_template'] = None
610
+ profile_data['stage_template'] = None
611
+ profile_data['prod_template'] = None
612
+ with open(self.byosnap_profile, 'rb') as file:
613
+ profile_data = json.load(file)
542
614
  payload = {
543
615
  "version": self.version,
544
616
  "image_tag": self.input_tag,
545
617
  "base_url": f"{self.prefix}/{self.sid}",
546
618
  "http_port": self.http_port,
619
+ "dev_template": profile_data['dev_template'],
620
+ "stage_template": profile_data['stage_template'],
621
+ "prod_template": profile_data['prod_template']
547
622
  }
548
623
  res = requests.post(
549
624
  f"{self.base_url}/v1/snapser-api/byosnaps/{self.sid}/versions",
@@ -0,0 +1,77 @@
1
+ """
2
+ Generate CLI commands
3
+ """
4
+ import json
5
+ from sys import platform
6
+ import os
7
+ from typing import Union
8
+
9
+ from snapctl.config.hashes import BYOSNAP_TEMPLATE
10
+ from snapctl.types.definitions import ResponseType
11
+ from snapctl.utils.echo import error, success
12
+
13
+
14
+ class Generate:
15
+ """
16
+ Generate CLI commands
17
+ """
18
+ SUBCOMMANDS = ['byosnap-profile']
19
+ BYOSNAP_PROFILE_FN = 'snapser-byosnap-profile.json'
20
+
21
+ def __init__(
22
+ self, subcommand: str, base_url: str, api_key: str | None,
23
+ out_path: Union[str, None]
24
+ ) -> None:
25
+ self.subcommand: str = subcommand
26
+ self.base_url: str = base_url
27
+ self.api_key: str = api_key
28
+ self.out_path: Union[str, None] = out_path
29
+
30
+ # Validator
31
+
32
+ def validate_input(self) -> ResponseType:
33
+ """
34
+ Validator
35
+ """
36
+ response: ResponseType = {
37
+ 'error': True,
38
+ 'msg': '',
39
+ 'data': []
40
+ }
41
+ if self.subcommand in ['byosnap-profile']:
42
+ # Check path
43
+ if self.out_path and not os.path.isdir(self.out_path):
44
+ response['msg'] = (
45
+ f"Invalid path {self.out_path}. Wont be able to "
46
+ "store the byosnap-profile.json file"
47
+ )
48
+ return response
49
+ # Send success
50
+ response['error'] = False
51
+ return response
52
+
53
+ def byosnap_profile(self) -> bool:
54
+ """
55
+ Generate snapser-byosnap-profile.json
56
+ """
57
+ file_path_symbol = '/'
58
+ if platform == 'win32':
59
+ file_path_symbol = '\\'
60
+ if self.out_path is not None:
61
+ file_save_path = f"{self.out_path}{file_path_symbol}{Generate.BYOSNAP_PROFILE_FN}"
62
+ else:
63
+ file_save_path = f"{os.getcwd()}{file_path_symbol}{Generate.BYOSNAP_PROFILE_FN}"
64
+ try:
65
+ with open(file_save_path, "w") as file:
66
+ json.dump(BYOSNAP_TEMPLATE, file, indent=4)
67
+ success(
68
+ f"{Generate.BYOSNAP_PROFILE_FN} saved at {file_save_path}"
69
+ )
70
+ return True
71
+ except (IOError, OSError) as file_error:
72
+ error(f"File error: {file_error}")
73
+ except json.JSONDecodeError as json_error:
74
+ error(f"JSON error: {json_error}")
75
+ except Exception as exception_error:
76
+ error(f"An unexpected error occurred: {exception_error}")
77
+ return False
@@ -2,13 +2,14 @@
2
2
  Constants used by snapctl
3
3
  """
4
4
  COMPANY_NAME = 'Snapser'
5
- VERSION = '0.31.0'
5
+ VERSION = '0.32.0'
6
6
  CONFIG_FILE_MAC = '~/.snapser/config'
7
7
  CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
8
8
 
9
9
  DEFAULT_PROFILE = 'default'
10
10
  API_KEY = 'SNAPSER_API_KEY'
11
11
  URL_KEY = 'SNAPSER_URL_KEY'
12
+ CONFIG_PATH_KEY = 'SNAPSER_CONFIG_PATH'
12
13
  SERVER_CALL_TIMEOUT = 30
13
14
 
14
15
  SNAPCTL_SUCCESS = 0
@@ -155,3 +155,17 @@ SERVICE_IDS = [
155
155
  'relay', 'remote-config', 'scheduler', 'sequencer', 'social-graph', 'statistics', 'storage',
156
156
  'trackables', 'xp'
157
157
  ]
158
+
159
+ DEFAULT_BYOSNAP_TEMPLATE = {
160
+ 'cpu': 100,
161
+ 'memory': 0.125,
162
+ 'cmd': '',
163
+ 'args': [],
164
+ 'env_params': []
165
+ }
166
+
167
+ BYOSNAP_TEMPLATE = {
168
+ 'dev_template': DEFAULT_BYOSNAP_TEMPLATE,
169
+ 'stage_template': DEFAULT_BYOSNAP_TEMPLATE,
170
+ 'prod_template': DEFAULT_BYOSNAP_TEMPLATE
171
+ }
@@ -11,9 +11,10 @@ import pyfiglet
11
11
  from snapctl.commands.byosnap import ByoSnap
12
12
  from snapctl.commands.byogs import ByoGs
13
13
  from snapctl.commands.game import Game
14
+ from snapctl.commands.generate import Generate
14
15
  from snapctl.commands.snapend import Snapend
15
16
  from snapctl.config.constants import COMPANY_NAME, API_KEY, URL_KEY, CONFIG_FILE_MAC, \
16
- CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS, SNAPCTL_ERROR
17
+ CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS, SNAPCTL_ERROR, CONFIG_PATH_KEY
17
18
  from snapctl.config.endpoints import END_POINTS
18
19
  from snapctl.config.hashes import CLIENT_SDK_TYPES, SERVER_SDK_TYPES, PROTOS_TYPES, SERVICE_IDS, \
19
20
  SNAPEND_MANIFEST_TYPES
@@ -50,22 +51,23 @@ def extract_config(extract_key: str, profile: str | None = None) -> object:
50
51
  'location': '',
51
52
  'value': None
52
53
  }
53
- # Option 1
54
+ # Option 1 - Get the API Key from the environment variable
54
55
  env_api_key = os.getenv(extract_key)
55
56
  if env_api_key is not None:
56
57
  result['location'] = 'environment-variable'
57
58
  result['value'] = env_api_key
58
59
  return result
59
- # Option 2
60
- config_file_path: str = ''
61
- encoding: str | None = None
62
- if platform == 'win32':
63
- config_file_path = os.path.expandvars(CONFIG_FILE_WIN)
64
- encoding = "utf-8-sig"
65
- else:
66
- config_file_path = os.path.expanduser(CONFIG_FILE_MAC)
60
+ encoding: str | None = "utf-8-sig" if platform == 'win32' else None
61
+ # Option 2 - Get the API Key from CONFIG PATH environment variable
62
+ config_file_path: str | None = os.getenv(CONFIG_PATH_KEY)
63
+ # Option 3 - Get the API Key from the hardcoded config file we look for
64
+ if config_file_path is None:
65
+ if platform == 'win32':
66
+ config_file_path = os.path.expandvars(CONFIG_FILE_WIN)
67
+ else:
68
+ config_file_path = os.path.expanduser(CONFIG_FILE_MAC)
69
+ result['location'] = f'config-file:{config_file_path}'
67
70
  if os.path.isfile(config_file_path):
68
- result['location'] = 'config-file'
69
71
  config = configparser.ConfigParser()
70
72
  config.read(config_file_path, encoding=encoding)
71
73
  config_profile: str = DEFAULT_PROFILE
@@ -282,6 +284,11 @@ def byosnap(
282
284
  http_port: Union[str, None] = typer.Option(
283
285
  None, "--http-port", help="(req: publish-version) Ingress HTTP port version"
284
286
  ),
287
+ byosnap_profile: Union[str, None] = typer.Option(
288
+ None, "--byosnap-profile", help=(
289
+ "(req: publish-version) Path to your byosnap-profile JSON file"
290
+ )
291
+ ),
285
292
  # overrides
286
293
  api_key: Union[str, None] = typer.Option(
287
294
  None, "--api-key", help="API Key override.", callback=api_key_context_callback
@@ -297,7 +304,7 @@ def byosnap(
297
304
  byosnap_obj: ByoSnap = ByoSnap(
298
305
  subcommand, ctx.obj['base_url'], ctx.obj['api_key'], sid,
299
306
  name, desc, platform_type, language, tag, path, docker_file,
300
- prefix, version, http_port
307
+ prefix, version, http_port, byosnap_profile
301
308
  )
302
309
  validate_input_response: ResponseType = byosnap_obj.validate_input()
303
310
  if validate_input_response['error']:
@@ -318,48 +325,21 @@ def byogs(
318
325
  subcommand: str = typer.Argument(
319
326
  ..., help="BYOGs Subcommands: " + ", ".join(ByoGs.SUBCOMMANDS) + "."
320
327
  ),
321
- sid: str = typer.Argument(
322
- ByoGs.SID, help="Game Server Id. Should start with byogs"
323
- ),
324
- # create
325
- name: str = typer.Option(
326
- None, "--name", help="(req: create) Name for your snap"
327
- ),
328
- desc: str = typer.Option(
329
- None, "--desc", help="(req: create) Description for your snap"
330
- ),
331
- platform_type: str = typer.Option(
332
- None, "--platform",
333
- help="(req: create) Platform for your snap - " + \
334
- ", ".join(ByoGs.PLATFORMS) + "."
335
- ),
336
- language: str = typer.Option(
337
- None, "--language",
338
- help="(req: create) Language of your snap - " + \
339
- ", ".join(ByoGs.LANGUAGES) + "."
340
- ),
328
+ # sid: str = typer.Argument(
329
+ # ByoGs.SID, help="Game Server Id. Should start with byogs"
330
+ # ),
341
331
  # publish, publish-image and publish-version
342
332
  tag: str = typer.Option(
343
333
  None, "--tag",
344
- help="(req: build, push, publish, publish-image and publish-version) Tag for your snap"
334
+ help="(req: build, push, publish) Tag for your snap"
345
335
  ),
346
336
  # publish and publish-image
347
337
  path: Union[str, None] = typer.Option(
348
- None, "--path", help="(req: build, publish, publish-image, upload-docs) Path to your snap code"
338
+ None, "--path", help="(req: build, publish) Path to your snap code"
349
339
  ),
350
340
  docker_file: str = typer.Option(
351
341
  "Dockerfile", help="Dockerfile name to use"
352
342
  ),
353
- # publish-version
354
- version: Union[str, None] = typer.Option(
355
- None, "--version", help="(req: publish-version) Snap version"
356
- ),
357
- http_port: Union[str, None] = typer.Option(
358
- None, "--http-port", help="(req: publish-version) Ingress HTTP port version"
359
- ),
360
- debug_port: Union[str, None] = typer.Option(
361
- None, "--debug-port", help="(optional: publish-version) Debug HTTP port version"
362
- ),
363
343
  # overrides
364
344
  api_key: Union[str, None] = typer.Option(
365
345
  None, "--api-key", help="API Key override.", callback=api_key_context_callback
@@ -373,9 +353,8 @@ def byogs(
373
353
  """
374
354
  validate_command_context(ctx)
375
355
  byogs_obj: ByoGs = ByoGs(
376
- subcommand, ctx.obj['base_url'], ctx.obj['api_key'], sid,
377
- name, desc, platform_type, language, tag, path, docker_file,
378
- version, http_port, debug_port
356
+ subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
357
+ tag, path, docker_file,
379
358
  )
380
359
  validate_input_response: ResponseType = byogs_obj.validate_input()
381
360
  if validate_input_response['error']:
@@ -561,3 +540,42 @@ def snapend(
561
540
  error(f"Snapend {subcommand} failed")
562
541
  raise typer.Exit(SNAPCTL_ERROR)
563
542
  success(f"Snapend {subcommand} complete")
543
+
544
+
545
+ @app.command()
546
+ def generate(
547
+ ctx: typer.Context,
548
+ # Required fields
549
+ subcommand: str = typer.Argument(
550
+ ..., help="Generate Subcommands: " + ", ".join(Generate.SUBCOMMANDS) + "."
551
+ ),
552
+ # byosnap-profile
553
+ out_path: Union[str, None] = typer.Option(
554
+ None, "--out-path", help="(req: byosnap-profile) Path to output the byosnap profile"
555
+ ),
556
+ # overrides
557
+ api_key: Union[str, None] = typer.Option(
558
+ None, "--api-key", help="API Key override.", callback=api_key_context_callback
559
+ ),
560
+ profile: Union[str, None] = typer.Option(
561
+ None, "--profile", help="Profile to use.", callback=profile_context_callback
562
+ ),
563
+ ) -> None:
564
+ """
565
+ Generate files to be used by other commands
566
+ """
567
+ validate_command_context(ctx)
568
+ generate_obj: Generate = Generate(
569
+ subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
570
+ out_path,
571
+ )
572
+ validate_input_response: ResponseType = generate_obj.validate_input()
573
+ if validate_input_response['error']:
574
+ error(validate_input_response['msg'])
575
+ raise typer.Exit(SNAPCTL_ERROR)
576
+ command_method = subcommand.replace('-', '_')
577
+ method: Callable[..., bool] = getattr(generate_obj, command_method)
578
+ if not method():
579
+ error(f"Generate {subcommand} failed")
580
+ raise typer.Exit(SNAPCTL_ERROR)
581
+ success(f"Generate {subcommand} complete")
File without changes
File without changes
File without changes