snapctl 0.32.0__py3-none-any.whl → 0.32.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 +175 -181
- snapctl/commands/byosnap.py +378 -371
- snapctl/commands/game.py +63 -57
- snapctl/commands/generate.py +48 -32
- snapctl/commands/snapend.py +361 -281
- snapctl/config/constants.py +72 -8
- snapctl/main.py +100 -135
- snapctl/types/definitions.py +20 -4
- snapctl/utils/echo.py +10 -2
- snapctl/utils/helper.py +60 -3
- {snapctl-0.32.0.dist-info → snapctl-0.32.1.dist-info}/METADATA +92 -2
- snapctl-0.32.1.dist-info/RECORD +23 -0
- snapctl-0.32.0.dist-info/RECORD +0 -23
- {snapctl-0.32.0.dist-info → snapctl-0.32.1.dist-info}/LICENSE +0 -0
- {snapctl-0.32.0.dist-info → snapctl-0.32.1.dist-info}/WHEEL +0 -0
- {snapctl-0.32.0.dist-info → snapctl-0.32.1.dist-info}/entry_points.txt +0 -0
snapctl/config/constants.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Constants used by snapctl
|
|
3
3
|
"""
|
|
4
4
|
COMPANY_NAME = 'Snapser'
|
|
5
|
-
VERSION = '0.32.
|
|
5
|
+
VERSION = '0.32.1'
|
|
6
6
|
CONFIG_FILE_MAC = '~/.snapser/config'
|
|
7
7
|
CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
|
|
8
8
|
|
|
@@ -12,16 +12,80 @@ URL_KEY = 'SNAPSER_URL_KEY'
|
|
|
12
12
|
CONFIG_PATH_KEY = 'SNAPSER_CONFIG_PATH'
|
|
13
13
|
SERVER_CALL_TIMEOUT = 30
|
|
14
14
|
|
|
15
|
-
SNAPCTL_SUCCESS = 0
|
|
16
|
-
SNAPCTL_ERROR = 1
|
|
17
|
-
|
|
18
15
|
# HTTP codes
|
|
19
16
|
HTTP_UNAUTHORIZED = 401
|
|
20
17
|
HTTP_FORBIDDEN = 403
|
|
21
18
|
HTTP_NOT_FOUND = 404
|
|
22
19
|
HTTP_CONFLICT = 409
|
|
23
20
|
|
|
24
|
-
# Error codes
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
# HTTP Error codes
|
|
22
|
+
HTTP_ERROR_SERVICE_VERSION_EXISTS = 542
|
|
23
|
+
HTTP_ERROR_TAG_NOT_AVAILABLE = 544
|
|
24
|
+
HTTP_ERROR_ADD_ON_NOT_ENABLED = 547
|
|
25
|
+
HTTP_ERROR_DUPLICATE_GAME_NAME = 2
|
|
26
|
+
|
|
27
|
+
# CLI Return Codes
|
|
28
|
+
SNAPCTL_SUCCESS = 0
|
|
29
|
+
SNAPCTL_ERROR = 1
|
|
30
|
+
SNAPCTL_INPUT_ERROR = 2
|
|
31
|
+
|
|
32
|
+
# Configuration Errors
|
|
33
|
+
SNAPCTL_CONFIGURATION_INCORRECT = 10
|
|
34
|
+
SNAPCTL_CONFIGURATION_ERROR = 11
|
|
35
|
+
SNAPCTL_DEPENDENCY_MISSING = 12
|
|
36
|
+
|
|
37
|
+
# BYOGS Errors
|
|
38
|
+
SNAPCTL_BYOGS_GENERIC_ERROR = 20
|
|
39
|
+
SNAPCTL_BYOGS_DEPENDENCY_MISSING = 21
|
|
40
|
+
SNAPCTL_BYOGS_ECR_LOGIN_ERROR = 22
|
|
41
|
+
SNAPCTL_BYOGS_BUILD_ERROR = 23
|
|
42
|
+
SNAPCTL_BYOGS_TAG_ERROR = 24
|
|
43
|
+
SNAPCTL_BYOGS_PUBLISH_ERROR = 25
|
|
44
|
+
SNAPCTL_BYOGS_PUBLISH_PERMISSION_ERROR = 26
|
|
45
|
+
SNAPCTL_BYOGS_PUBLISH_DUPLICATE_TAG_ERROR = 27
|
|
46
|
+
|
|
47
|
+
# BYOSNAP Errors
|
|
48
|
+
SNAPCTL_BYOSNAP_GENERIC_ERROR = 30
|
|
49
|
+
SNAPCTL_BYOSNAP_DEPENDENCY_MISSING = 31
|
|
50
|
+
SNAPCTL_BYOSNAP_ECR_LOGIN_ERROR = 32
|
|
51
|
+
SNAPCTL_BYOSNAP_BUILD_ERROR = 33
|
|
52
|
+
SNAPCTL_BYOSNAP_TAG_ERROR = 34
|
|
53
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_ERROR = 35
|
|
54
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_PERMISSION_ERROR = 36
|
|
55
|
+
SNAPCTL_BYOSNAP_PUBLISH_IMAGE_DUPLICATE_TAG_ERROR = 37
|
|
56
|
+
SNAPCTL_BYOSNAP_CREATE_ERROR = 38
|
|
57
|
+
SNAPCTL_BYOSNAP_CREATE_PERMISSION_ERROR = 39
|
|
58
|
+
SNAPCTL_BYOSNAP_CREATE_DUPLICATE_NAME_ERROR = 40
|
|
59
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_ERROR = 41
|
|
60
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_PERMISSION_ERROR = 42
|
|
61
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_VERSION_ERROR = 43
|
|
62
|
+
SNAPCTL_BYOSNAP_PUBLISH_VERSION_DUPLICATE_TAG_ERROR = 44
|
|
63
|
+
|
|
64
|
+
# Game Errors
|
|
65
|
+
SNAPCTL_GAME_GENERIC_ERROR = 50
|
|
66
|
+
SNAPCTL_GAME_CREATE_ERROR = 51
|
|
67
|
+
SNAPCTL_GAME_CREATE_PERMISSION_ERROR = 52
|
|
68
|
+
SNAPCTL_GAME_CREATE_DUPLICATE_NAME_ERROR = 53
|
|
69
|
+
SNAPCTL_GAME_ENUMERATE_ERROR = 54
|
|
70
|
+
|
|
71
|
+
# Snapend Errors
|
|
72
|
+
SNAPCTL_SNAPEND_GENERIC_ERROR = 60
|
|
73
|
+
SNAPCTL_SNAPEND_ENUMERATE_ERROR = 61
|
|
74
|
+
SNAPCTL_SNAPEND_CLONE_ERROR = 62
|
|
75
|
+
SNAPCTL_SNAPEND_CLONE_SERVER_ERROR = 63
|
|
76
|
+
SNAPCTL_SNAPEND_CLONE_TIMEOUT_ERROR = 64
|
|
77
|
+
SNAPCTL_SNAPEND_APPLY_ERROR = 65
|
|
78
|
+
SNAPCTL_SNAPEND_APPLY_SERVER_ERROR = 66
|
|
79
|
+
SNAPCTL_SNAPEND_APPLY_TIMEOUT_ERROR = 67
|
|
80
|
+
SNAPCTL_SNAPEND_PROMOTE_ERROR = 68
|
|
81
|
+
SNAPCTL_SNAPEND_PROMOTE_SERVER_ERROR = 69
|
|
82
|
+
SNAPCTL_SNAPEND_PROMOTE_TIMEOUT_ERROR = 70
|
|
83
|
+
SNAPCTL_SNAPEND_DOWNLOAD_ERROR = 71
|
|
84
|
+
SNAPCTL_SNAPEND_UPDATE_ERROR = 72
|
|
85
|
+
SNAPCTL_SNAPEND_UPDATE_SERVER_ERROR = 73
|
|
86
|
+
SNAPCTL_SNAPEND_UPDATE_TIMEOUT_ERROR = 74
|
|
87
|
+
SNAPCTL_SNAPEND_STATE_ERROR = 75
|
|
88
|
+
|
|
89
|
+
# Generate Errors
|
|
90
|
+
SNAPCTL_GENERATE_GENERIC_ERROR = 80
|
|
91
|
+
SNAPCTL_GENERATE_BYOSNAP_PROFILE_ERROR = 81
|
snapctl/main.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import configparser
|
|
5
5
|
import os
|
|
6
6
|
from sys import platform
|
|
7
|
-
from typing import Union
|
|
7
|
+
from typing import Union
|
|
8
8
|
import typer
|
|
9
9
|
import pyfiglet
|
|
10
10
|
|
|
@@ -14,12 +14,13 @@ from snapctl.commands.game import Game
|
|
|
14
14
|
from snapctl.commands.generate import Generate
|
|
15
15
|
from snapctl.commands.snapend import Snapend
|
|
16
16
|
from snapctl.config.constants import COMPANY_NAME, API_KEY, URL_KEY, CONFIG_FILE_MAC, \
|
|
17
|
-
CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS,
|
|
17
|
+
CONFIG_FILE_WIN, DEFAULT_PROFILE, VERSION, SNAPCTL_SUCCESS, CONFIG_PATH_KEY, \
|
|
18
|
+
SNAPCTL_CONFIGURATION_INCORRECT
|
|
18
19
|
from snapctl.config.endpoints import END_POINTS
|
|
19
20
|
from snapctl.config.hashes import CLIENT_SDK_TYPES, SERVER_SDK_TYPES, PROTOS_TYPES, SERVICE_IDS, \
|
|
20
21
|
SNAPEND_MANIFEST_TYPES
|
|
21
|
-
from snapctl.types.definitions import ResponseType
|
|
22
22
|
from snapctl.utils.echo import error, success, info
|
|
23
|
+
from snapctl.utils.helper import validate_api_key
|
|
23
24
|
|
|
24
25
|
######### Globals #########
|
|
25
26
|
|
|
@@ -66,20 +67,22 @@ def extract_config(extract_key: str, profile: str | None = None) -> object:
|
|
|
66
67
|
config_file_path = os.path.expandvars(CONFIG_FILE_WIN)
|
|
67
68
|
else:
|
|
68
69
|
config_file_path = os.path.expanduser(CONFIG_FILE_MAC)
|
|
69
|
-
result['location'] = f'
|
|
70
|
+
result['location'] = f'{config_file_path}'
|
|
70
71
|
if os.path.isfile(config_file_path):
|
|
71
72
|
config = configparser.ConfigParser()
|
|
72
73
|
config.read(config_file_path, encoding=encoding)
|
|
73
74
|
config_profile: str = DEFAULT_PROFILE
|
|
74
75
|
if profile is not None and profile != '' and profile != DEFAULT_PROFILE:
|
|
75
|
-
result['location'] = f'{config_file_path}:profile {profile}'
|
|
76
|
+
result['location'] = f'"{config_file_path}:profile {profile}"'
|
|
76
77
|
config_profile = f'profile {profile}'
|
|
77
|
-
info(
|
|
78
|
+
info(
|
|
79
|
+
f'Trying to extract API KEY from "{config_file_path}:profile {profile}"'
|
|
80
|
+
)
|
|
78
81
|
result['value'] = config.get(
|
|
79
82
|
config_profile, extract_key, fallback=None, raw=True
|
|
80
83
|
)
|
|
81
84
|
else:
|
|
82
|
-
|
|
85
|
+
info(
|
|
83
86
|
f'Config file on platform {platform} not found at {config_file_path}')
|
|
84
87
|
return result
|
|
85
88
|
|
|
@@ -111,14 +114,9 @@ def validate_command_context(
|
|
|
111
114
|
Validator to confirm if the context has been set properly
|
|
112
115
|
"""
|
|
113
116
|
if ctx.obj['api_key'] is None or ctx.obj['base_url'] == '':
|
|
114
|
-
error(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
f"API Key Category:{ctx.obj['api_key_location']} "
|
|
118
|
-
f"Base URL:{ctx.obj['base_url']}"
|
|
119
|
-
)
|
|
120
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
121
|
-
info(f"Using API Key from {ctx.obj['api_key_location']}")
|
|
117
|
+
error("Snapctl Configuration Incorrect. Unable to extract API Key",
|
|
118
|
+
SNAPCTL_CONFIGURATION_INCORRECT)
|
|
119
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_INCORRECT)
|
|
122
120
|
|
|
123
121
|
######### CALLBACKS #########
|
|
124
122
|
|
|
@@ -174,16 +172,16 @@ def profile_context_callback(
|
|
|
174
172
|
# Ensure ctx object is instantiated
|
|
175
173
|
ctx.ensure_object(dict)
|
|
176
174
|
api_key_obj = extract_config(API_KEY, profile)
|
|
177
|
-
if api_key_obj['value'] is None and profile is not None and profile != '':
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
175
|
+
# if api_key_obj['value'] is None and profile is not None and profile != '':
|
|
176
|
+
# conf_file = ''
|
|
177
|
+
# if platform == 'win32':
|
|
178
|
+
# conf_file = os.path.expandvars(CONFIG_FILE_WIN)
|
|
179
|
+
# else:
|
|
180
|
+
# conf_file = os.path.expanduser(CONFIG_FILE_MAC)
|
|
181
|
+
# error(
|
|
182
|
+
# f'Invalid profile input {profile}. '
|
|
183
|
+
# f'Please check your snap config file at {conf_file}'
|
|
184
|
+
# )
|
|
187
185
|
ctx.obj['version'] = VERSION
|
|
188
186
|
ctx.obj['api_key'] = api_key_obj['value']
|
|
189
187
|
ctx.obj['api_key_location'] = api_key_obj['location']
|
|
@@ -198,7 +196,7 @@ def version_callback(value: bool = True):
|
|
|
198
196
|
"""
|
|
199
197
|
if value:
|
|
200
198
|
success(f"Snapctl version: {VERSION}")
|
|
201
|
-
raise typer.Exit(SNAPCTL_SUCCESS)
|
|
199
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
202
200
|
|
|
203
201
|
|
|
204
202
|
@app.callback()
|
|
@@ -227,12 +225,57 @@ def validate(
|
|
|
227
225
|
profile: Union[str, None] = typer.Option(
|
|
228
226
|
None, "--profile", help="Profile to use.", callback=profile_context_callback
|
|
229
227
|
),
|
|
230
|
-
):
|
|
228
|
+
) -> None:
|
|
231
229
|
"""
|
|
232
230
|
Validate your Snapctl setup
|
|
233
231
|
"""
|
|
234
232
|
validate_command_context(ctx)
|
|
233
|
+
validate_api_key(ctx.obj['base_url'], ctx.obj['api_key'])
|
|
235
234
|
success("Setup is valid")
|
|
235
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@app.command()
|
|
239
|
+
def byogs(
|
|
240
|
+
ctx: typer.Context,
|
|
241
|
+
# Required fields
|
|
242
|
+
subcommand: str = typer.Argument(
|
|
243
|
+
..., help="BYOGs Subcommands: " + ", ".join(ByoGs.SUBCOMMANDS) + "."
|
|
244
|
+
),
|
|
245
|
+
# sid: str = typer.Argument(
|
|
246
|
+
# ByoGs.SID, help="Game Server Id. Should start with byogs"
|
|
247
|
+
# ),
|
|
248
|
+
# publish, publish-image and publish-version
|
|
249
|
+
tag: str = typer.Option(
|
|
250
|
+
None, "--tag",
|
|
251
|
+
help="(req: build, push, publish) Tag for your snap"
|
|
252
|
+
),
|
|
253
|
+
# publish and publish-image
|
|
254
|
+
path: Union[str, None] = typer.Option(
|
|
255
|
+
None, "--path", help="(req: build, publish) Path to your snap code"
|
|
256
|
+
),
|
|
257
|
+
docker_file: str = typer.Option(
|
|
258
|
+
"Dockerfile", help="Dockerfile name to use"
|
|
259
|
+
),
|
|
260
|
+
# overrides
|
|
261
|
+
api_key: Union[str, None] = typer.Option(
|
|
262
|
+
None, "--api-key", help="API Key override.", callback=api_key_context_callback
|
|
263
|
+
),
|
|
264
|
+
profile: Union[str, None] = typer.Option(
|
|
265
|
+
None, "--profile", help="Profile to use.", callback=profile_context_callback
|
|
266
|
+
),
|
|
267
|
+
) -> None:
|
|
268
|
+
"""
|
|
269
|
+
Bring your own game server commands
|
|
270
|
+
"""
|
|
271
|
+
validate_command_context(ctx)
|
|
272
|
+
byogs_obj: ByoGs = ByoGs(
|
|
273
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
274
|
+
tag, path, docker_file,
|
|
275
|
+
)
|
|
276
|
+
getattr(byogs_obj, subcommand.replace('-', '_'))()
|
|
277
|
+
success(f"BYOGs {subcommand} complete")
|
|
278
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
236
279
|
|
|
237
280
|
|
|
238
281
|
@app.command()
|
|
@@ -306,39 +349,22 @@ def byosnap(
|
|
|
306
349
|
name, desc, platform_type, language, tag, path, docker_file,
|
|
307
350
|
prefix, version, http_port, byosnap_profile
|
|
308
351
|
)
|
|
309
|
-
|
|
310
|
-
if validate_input_response['error']:
|
|
311
|
-
error(validate_input_response['msg'])
|
|
312
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
313
|
-
command_method = subcommand.replace('-', '_')
|
|
314
|
-
method: Callable[..., bool] = getattr(byosnap_obj, command_method)
|
|
315
|
-
if not method():
|
|
316
|
-
error(f"BYOSnap {subcommand} failed")
|
|
317
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
352
|
+
getattr(byosnap_obj, subcommand.replace('-', '_'))()
|
|
318
353
|
success(f"BYOSnap {subcommand} complete")
|
|
354
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
319
355
|
|
|
320
356
|
|
|
321
357
|
@app.command()
|
|
322
|
-
def
|
|
358
|
+
def game(
|
|
323
359
|
ctx: typer.Context,
|
|
324
360
|
# Required fields
|
|
325
361
|
subcommand: str = typer.Argument(
|
|
326
|
-
..., help="
|
|
327
|
-
),
|
|
328
|
-
# sid: str = typer.Argument(
|
|
329
|
-
# ByoGs.SID, help="Game Server Id. Should start with byogs"
|
|
330
|
-
# ),
|
|
331
|
-
# publish, publish-image and publish-version
|
|
332
|
-
tag: str = typer.Option(
|
|
333
|
-
None, "--tag",
|
|
334
|
-
help="(req: build, push, publish) Tag for your snap"
|
|
335
|
-
),
|
|
336
|
-
# publish and publish-image
|
|
337
|
-
path: Union[str, None] = typer.Option(
|
|
338
|
-
None, "--path", help="(req: build, publish) Path to your snap code"
|
|
362
|
+
..., help="Game Subcommands: " + ", ".join(Game.SUBCOMMANDS) + "."
|
|
339
363
|
),
|
|
340
|
-
|
|
341
|
-
|
|
364
|
+
# name
|
|
365
|
+
name: str = typer.Option(
|
|
366
|
+
None, "--name",
|
|
367
|
+
help=("(req: create) Name of your game: ")
|
|
342
368
|
),
|
|
343
369
|
# overrides
|
|
344
370
|
api_key: Union[str, None] = typer.Option(
|
|
@@ -349,36 +375,26 @@ def byogs(
|
|
|
349
375
|
),
|
|
350
376
|
) -> None:
|
|
351
377
|
"""
|
|
352
|
-
|
|
378
|
+
Game commands
|
|
353
379
|
"""
|
|
354
380
|
validate_command_context(ctx)
|
|
355
|
-
|
|
356
|
-
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
357
|
-
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
if validate_input_response['error']:
|
|
361
|
-
error(validate_input_response['msg'])
|
|
362
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
363
|
-
command_method = subcommand.replace('-', '_')
|
|
364
|
-
method: Callable[..., bool] = getattr(byogs_obj, command_method)
|
|
365
|
-
if not method():
|
|
366
|
-
error(f"BYOGs {subcommand} failed")
|
|
367
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
368
|
-
success(f"BYOGs {subcommand} complete")
|
|
381
|
+
game_obj: Game = Game(
|
|
382
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'], name)
|
|
383
|
+
getattr(game_obj, subcommand.replace('-', '_'))()
|
|
384
|
+
success(f"Game {subcommand} complete")
|
|
385
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
369
386
|
|
|
370
387
|
|
|
371
388
|
@app.command()
|
|
372
|
-
def
|
|
389
|
+
def generate(
|
|
373
390
|
ctx: typer.Context,
|
|
374
391
|
# Required fields
|
|
375
392
|
subcommand: str = typer.Argument(
|
|
376
|
-
..., help="
|
|
393
|
+
..., help="Generate Subcommands: " + ", ".join(Generate.SUBCOMMANDS) + "."
|
|
377
394
|
),
|
|
378
|
-
#
|
|
379
|
-
|
|
380
|
-
None, "--
|
|
381
|
-
help=("(req: create) Name of your game: ")
|
|
395
|
+
# byosnap-profile
|
|
396
|
+
out_path: Union[str, None] = typer.Option(
|
|
397
|
+
None, "--out-path", help="(req: byosnap-profile) Path to output the byosnap profile"
|
|
382
398
|
),
|
|
383
399
|
# overrides
|
|
384
400
|
api_key: Union[str, None] = typer.Option(
|
|
@@ -389,21 +405,16 @@ def game(
|
|
|
389
405
|
),
|
|
390
406
|
) -> None:
|
|
391
407
|
"""
|
|
392
|
-
|
|
408
|
+
Generate files to be used by other commands
|
|
393
409
|
"""
|
|
394
410
|
validate_command_context(ctx)
|
|
395
|
-
|
|
396
|
-
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
method: Callable[..., bool] = getattr(game_obj, command_method)
|
|
403
|
-
if not method():
|
|
404
|
-
error(f"Game {subcommand} failed")
|
|
405
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
406
|
-
success(f"Game {subcommand} complete")
|
|
411
|
+
generate_obj: Generate = Generate(
|
|
412
|
+
subcommand, ctx.obj['base_url'], ctx.obj['api_key'],
|
|
413
|
+
out_path,
|
|
414
|
+
)
|
|
415
|
+
getattr(generate_obj, subcommand.replace('-', '_'))()
|
|
416
|
+
success(f"Generate {subcommand} complete")
|
|
417
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
407
418
|
|
|
408
419
|
|
|
409
420
|
@app.command()
|
|
@@ -416,7 +427,7 @@ def snapend(
|
|
|
416
427
|
# snapend_id: str = typer.Argument(..., help="Snapend Id"),
|
|
417
428
|
snapend_id: str = typer.Option(
|
|
418
429
|
None, "--snapend-id",
|
|
419
|
-
help=("(req: update, download) Snapend Id")
|
|
430
|
+
help=("(req: state, update, download) Snapend Id")
|
|
420
431
|
),
|
|
421
432
|
# enumerate
|
|
422
433
|
game_id: str = typer.Option(
|
|
@@ -530,52 +541,6 @@ def snapend(
|
|
|
530
541
|
# Update
|
|
531
542
|
byosnaps, byogs, blocking
|
|
532
543
|
)
|
|
533
|
-
|
|
534
|
-
if validate_input_response['error']:
|
|
535
|
-
error(validate_input_response['msg'])
|
|
536
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
537
|
-
command_method = subcommand.replace('-', '_')
|
|
538
|
-
method: Callable[..., bool] = getattr(snapend_obj, command_method)
|
|
539
|
-
if not method():
|
|
540
|
-
error(f"Snapend {subcommand} failed")
|
|
541
|
-
raise typer.Exit(SNAPCTL_ERROR)
|
|
544
|
+
getattr(snapend_obj, subcommand.replace('-', '_'))()
|
|
542
545
|
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")
|
|
546
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
snapctl/types/definitions.py
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This file contains the definitions of the types used in the snapctl package.
|
|
3
3
|
"""
|
|
4
|
+
from typing import List, Union
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
class
|
|
7
|
+
class ErrorResponse:
|
|
7
8
|
"""
|
|
8
9
|
This class represents the response type of the Snapser API.
|
|
9
10
|
"""
|
|
10
|
-
|
|
11
|
-
msg: str
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
def __init__(self, error: bool, code: int, msg: str, data: Union[List, str]):
|
|
13
|
+
self.error = error
|
|
14
|
+
self.code = code
|
|
15
|
+
self.msg = msg
|
|
16
|
+
self.data = data
|
|
17
|
+
|
|
18
|
+
def to_dict(self):
|
|
19
|
+
'''
|
|
20
|
+
Convert the object to a dictionary
|
|
21
|
+
|
|
22
|
+
'''
|
|
23
|
+
return {
|
|
24
|
+
'error': self.error,
|
|
25
|
+
'code': self.code,
|
|
26
|
+
'msg': self.msg,
|
|
27
|
+
'data': self.data
|
|
28
|
+
}
|
snapctl/utils/echo.py
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module contains functions to print messages to the console.
|
|
3
3
|
"""
|
|
4
|
+
import json
|
|
5
|
+
import typer
|
|
4
6
|
from rich import print
|
|
7
|
+
from snapctl.config.constants import SNAPCTL_ERROR
|
|
8
|
+
from snapctl.types.definitions import ErrorResponse
|
|
5
9
|
# Run `python -m rich.emoji` to get a list of all emojis that are supported
|
|
6
10
|
|
|
7
11
|
|
|
8
|
-
def error(msg: str) -> None:
|
|
12
|
+
def error(msg: str, code: int = SNAPCTL_ERROR, data: object = None) -> None:
|
|
9
13
|
"""
|
|
10
14
|
Prints an error message to the console.
|
|
11
15
|
"""
|
|
16
|
+
error_response = ErrorResponse(
|
|
17
|
+
error=True, code=code, msg=msg, data=data if data else ''
|
|
18
|
+
)
|
|
12
19
|
print(f"[bold red]Error[/bold red] {msg}")
|
|
20
|
+
typer.echo(json.dumps(error_response.to_dict()), err=True)
|
|
13
21
|
|
|
14
22
|
|
|
15
23
|
def info(msg: str) -> None:
|
|
@@ -23,4 +31,4 @@ def success(msg: str) -> None:
|
|
|
23
31
|
"""
|
|
24
32
|
Prints a success message to the console.
|
|
25
33
|
"""
|
|
26
|
-
print(f"[green]Success[/green] {msg}")
|
|
34
|
+
print(f"[bold green]Success[/bold green] {msg}")
|
snapctl/utils/helper.py
CHANGED
|
@@ -3,11 +3,46 @@ Helper functions for snapctl
|
|
|
3
3
|
"""
|
|
4
4
|
import requests
|
|
5
5
|
import typer
|
|
6
|
+
from requests.exceptions import RequestException
|
|
7
|
+
from rich.progress import Progress
|
|
6
8
|
from snapctl.config.constants import HTTP_NOT_FOUND, HTTP_FORBIDDEN, HTTP_UNAUTHORIZED, \
|
|
7
|
-
SERVER_CALL_TIMEOUT
|
|
9
|
+
SERVER_CALL_TIMEOUT, SNAPCTL_CONFIGURATION_ERROR, SNAPCTL_SUCCESS
|
|
8
10
|
from snapctl.utils.echo import error, success
|
|
9
11
|
|
|
10
12
|
|
|
13
|
+
def validate_api_key(base_url: str, api_key: str | None):
|
|
14
|
+
"""
|
|
15
|
+
This function validates the API Key
|
|
16
|
+
"""
|
|
17
|
+
try:
|
|
18
|
+
url = f"{base_url}/v1/snapser-api/games"
|
|
19
|
+
res = requests.get(
|
|
20
|
+
url, headers={'api-key': api_key},
|
|
21
|
+
timeout=SERVER_CALL_TIMEOUT
|
|
22
|
+
)
|
|
23
|
+
if res.ok:
|
|
24
|
+
success('API Key validated')
|
|
25
|
+
return True
|
|
26
|
+
if res.status_code == HTTP_NOT_FOUND:
|
|
27
|
+
error('Service ID is invalid.', SNAPCTL_CONFIGURATION_ERROR)
|
|
28
|
+
elif res.status_code == HTTP_UNAUTHORIZED:
|
|
29
|
+
error(
|
|
30
|
+
'API Key verification failed. Your API Key is either invalid or may have expired. ',
|
|
31
|
+
SNAPCTL_CONFIGURATION_ERROR
|
|
32
|
+
)
|
|
33
|
+
elif res.status_code == HTTP_FORBIDDEN:
|
|
34
|
+
error(
|
|
35
|
+
'Permission denied. Your role has been revoked. Please contact your administrator.',
|
|
36
|
+
SNAPCTL_CONFIGURATION_ERROR
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
error('Failed to validate API Key. Error:',
|
|
40
|
+
SNAPCTL_CONFIGURATION_ERROR)
|
|
41
|
+
except RequestException as e:
|
|
42
|
+
error(f"Exception: Unable to update your snapend {e}")
|
|
43
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_ERROR)
|
|
44
|
+
|
|
45
|
+
|
|
11
46
|
def get_composite_token(base_url: str, api_key: str | None, action: str, params: object) -> str:
|
|
12
47
|
"""
|
|
13
48
|
This function exchanges the api_key for a composite token.
|
|
@@ -30,9 +65,31 @@ def get_composite_token(base_url: str, api_key: str | None, action: str, params:
|
|
|
30
65
|
)
|
|
31
66
|
elif res.status_code == HTTP_FORBIDDEN:
|
|
32
67
|
error(
|
|
33
|
-
'Permission denied. Your role has been revoked. Please contact your administrator.'
|
|
68
|
+
'Permission denied. Your role has been revoked. Please contact your administrator.'
|
|
69
|
+
)
|
|
34
70
|
else:
|
|
35
71
|
error(f'Failed to validate API Key. Error: {res.text}')
|
|
36
|
-
raise typer.Exit()
|
|
72
|
+
raise typer.Exit(code=SNAPCTL_CONFIGURATION_ERROR)
|
|
37
73
|
success('API Key validated')
|
|
38
74
|
return res.json()['token']
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def snapctl_success(message: str, progress: Progress | None = None, no_exit: bool = False):
|
|
78
|
+
"""
|
|
79
|
+
This function exits the snapctl
|
|
80
|
+
"""
|
|
81
|
+
if progress:
|
|
82
|
+
progress.stop()
|
|
83
|
+
success(message)
|
|
84
|
+
if not no_exit:
|
|
85
|
+
raise typer.Exit(code=SNAPCTL_SUCCESS)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def snapctl_error(message: str, code: int, progress: Progress | None = None):
|
|
89
|
+
"""
|
|
90
|
+
This function exits the snapctl
|
|
91
|
+
"""
|
|
92
|
+
if progress:
|
|
93
|
+
progress.stop()
|
|
94
|
+
error(message, code)
|
|
95
|
+
raise typer.Exit(code=code)
|