snapctl 0.4.5__py3-none-any.whl → 0.22.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/__main__.py +3 -0
- snapctl/commands/byogs.py +443 -311
- snapctl/commands/byosnap.py +540 -335
- snapctl/commands/snapend.py +265 -182
- snapctl/config/constants.py +6 -1
- snapctl/config/endpoints.py +8 -5
- snapctl/config/hashes.py +13 -3
- snapctl/main.py +396 -183
- snapctl/types/definitions.py +11 -3
- snapctl/utils/echo.py +18 -3
- snapctl/utils/helper.py +33 -20
- {snapctl-0.4.5.dist-info → snapctl-0.22.1.dist-info}/METADATA +218 -67
- snapctl-0.22.1.dist-info/RECORD +20 -0
- {snapctl-0.4.5.dist-info → snapctl-0.22.1.dist-info}/WHEEL +1 -1
- snapctl-0.4.5.dist-info/RECORD +0 -20
- {snapctl-0.4.5.dist-info → snapctl-0.22.1.dist-info}/entry_points.txt +0 -0
snapctl/commands/byogs.py
CHANGED
|
@@ -1,341 +1,473 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BYOGS CLI commands
|
|
3
|
+
"""
|
|
1
4
|
import base64
|
|
5
|
+
from binascii import Error as BinasciiError
|
|
2
6
|
import json
|
|
3
7
|
import os
|
|
4
8
|
import re
|
|
5
|
-
import requests
|
|
6
9
|
import subprocess
|
|
7
|
-
|
|
8
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
9
10
|
from sys import platform
|
|
10
11
|
from typing import Union
|
|
12
|
+
import requests
|
|
13
|
+
from requests.exceptions import RequestException
|
|
14
|
+
|
|
15
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
16
|
+
from snapctl.config.constants import SERVER_CALL_TIMEOUT
|
|
11
17
|
from snapctl.config.constants import ERROR_SERVICE_VERSION_EXISTS, ERROR_TAG_NOT_AVAILABLE
|
|
12
18
|
from snapctl.types.definitions import ResponseType
|
|
13
19
|
from snapctl.utils.echo import error, success
|
|
14
20
|
from snapctl.utils.helper import get_composite_token
|
|
15
21
|
|
|
22
|
+
|
|
16
23
|
class ByoGs:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
"""
|
|
25
|
+
BYOGS CLI commands
|
|
26
|
+
"""
|
|
27
|
+
ID_PREFIX = 'byogs-'
|
|
28
|
+
SUBCOMMANDS = [
|
|
29
|
+
'build', 'push',
|
|
30
|
+
'create', 'publish-image', 'publish-version',
|
|
31
|
+
]
|
|
32
|
+
PLATFORMS = ['linux/amd64']
|
|
33
|
+
LANGUAGES = ['go', 'python', 'ruby', 'c#', 'c++', 'rust', 'java', 'node']
|
|
34
|
+
DEFAULT_BUILD_PLATFORM = 'linux/amd64'
|
|
35
|
+
SID_CHARACTER_LIMIT = 47
|
|
36
|
+
TAG_CHARACTER_LIMIT = 80
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
def __init__(
|
|
39
|
+
self, subcommand: str, base_url: str, api_key: str | None, sid: str, name: str, desc: str,
|
|
40
|
+
platform_type: str, language: str, input_tag: Union[str, None], path: Union[str, None],
|
|
41
|
+
dockerfile: str, version: Union[str, None], http_port: Union[int, None],
|
|
42
|
+
debug_port: Union[int, None]
|
|
43
|
+
) -> None:
|
|
44
|
+
self.subcommand: str = subcommand
|
|
45
|
+
self.base_url: str = base_url
|
|
46
|
+
self.api_key: str = api_key
|
|
47
|
+
self.sid: str = sid
|
|
48
|
+
self.name: str = name
|
|
49
|
+
self.desc: str = desc
|
|
50
|
+
self.platform_type: str = platform_type
|
|
51
|
+
self.language: str = language
|
|
52
|
+
if subcommand != 'create':
|
|
53
|
+
self.token: Union[str, None] = get_composite_token(
|
|
54
|
+
base_url, api_key, 'byogs', {'service_id': sid})
|
|
55
|
+
else:
|
|
56
|
+
self.token: Union[str, None] = None
|
|
57
|
+
self.token_parts: Union[list, None] = ByoGs._get_token_values(
|
|
58
|
+
self.token) if self.token is not None else None
|
|
59
|
+
self.input_tag: Union[str, None] = input_tag
|
|
60
|
+
self.path: Union[str, None] = path
|
|
61
|
+
self.dockerfile: str = dockerfile
|
|
62
|
+
self.version: Union[str, None] = version
|
|
63
|
+
self.http_port: Union[int, None] = http_port
|
|
64
|
+
self.debug_port: Union[int, None] = debug_port
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
def get_token_values(token: str) -> None | list:
|
|
42
|
-
try:
|
|
43
|
-
input_token = base64.b64decode(token).decode('ascii')
|
|
44
|
-
token_parts = input_token.split('|')
|
|
45
|
-
# url|web_app_token|service_id|ecr_repo_url|ecr_repo_username|ecr_repo_token
|
|
46
|
-
# url = self.token_parts[0]
|
|
47
|
-
# web_app_token = self.token_parts[1]
|
|
48
|
-
# service_id = self.token_parts[2]
|
|
49
|
-
# ecr_repo_url = self.token_parts[3]
|
|
50
|
-
# ecr_repo_username = self.token_parts[4]
|
|
51
|
-
# ecr_repo_token = self.token_parts[5]
|
|
52
|
-
# platform = self.token_parts[6]
|
|
53
|
-
if len(token_parts) >= 3:
|
|
54
|
-
return token_parts
|
|
55
|
-
except Exception:
|
|
56
|
-
pass
|
|
57
|
-
return None
|
|
66
|
+
# Protected methods
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return response
|
|
81
|
-
if self.platform not in ByoGs.PLATFORMS:
|
|
82
|
-
response['msg'] = f"Invalid platform. Valid platforms are {', '.join(ByoGs.PLATFORMS)}."
|
|
83
|
-
return response
|
|
84
|
-
else:
|
|
85
|
-
if self.token_parts is None:
|
|
86
|
-
response['msg'] = 'Invalid token. Please reach out to your support team'
|
|
87
|
-
return response
|
|
88
|
-
# Check tag
|
|
89
|
-
if self.tag is None or len(self.tag.split()) > 1 or len(self.tag) > 25:
|
|
90
|
-
response['msg'] = f"Tag should be a single word with maximum of 25 characters"
|
|
91
|
-
return response
|
|
92
|
-
if self.subcommand == 'publish-image':
|
|
93
|
-
if not self.path:
|
|
94
|
-
response['msg'] = f"Missing path"
|
|
95
|
-
return response
|
|
96
|
-
# Check path
|
|
97
|
-
if not os.path.isfile(f"{self.path}/{self.dockerfile}"):
|
|
98
|
-
response['msg'] = f"Unable to find {self.dockerfile} at path {self.path}"
|
|
99
|
-
return response
|
|
100
|
-
elif self.subcommand == 'publish-version':
|
|
101
|
-
if not self.version:
|
|
102
|
-
response['msg'] = f"Missing version"
|
|
103
|
-
return response
|
|
104
|
-
if not self.http_port:
|
|
105
|
-
response['msg'] = f"Missing Ingress HTTP Port"
|
|
106
|
-
return response
|
|
107
|
-
pattern = r'^v\d+\.\d+\.\d+$'
|
|
108
|
-
if not re.match(pattern, self.version):
|
|
109
|
-
response['msg'] = f"Version should be in the format vX.X.X"
|
|
110
|
-
return response
|
|
111
|
-
if not self.http_port.isdigit():
|
|
112
|
-
response['msg'] = f"Ingress HTTP Port should be a number"
|
|
113
|
-
return response
|
|
114
|
-
# Send success
|
|
115
|
-
response['error'] = False
|
|
116
|
-
return response
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _get_token_values(token: str) -> None | list:
|
|
70
|
+
"""
|
|
71
|
+
Get the token values
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
input_token = base64.b64decode(token).decode('ascii')
|
|
75
|
+
token_parts = input_token.split('|')
|
|
76
|
+
# url|web_app_token|service_id|ecr_repo_url|ecr_repo_username|ecr_repo_token
|
|
77
|
+
# url = self.token_parts[0]
|
|
78
|
+
# web_app_token = self.token_parts[1]
|
|
79
|
+
# service_id = self.token_parts[2]
|
|
80
|
+
# ecr_repo_url = self.token_parts[3]
|
|
81
|
+
# ecr_repo_username = self.token_parts[4]
|
|
82
|
+
# ecr_repo_token = self.token_parts[5]
|
|
83
|
+
# platform = self.token_parts[6]
|
|
84
|
+
if len(token_parts) >= 3:
|
|
85
|
+
return token_parts
|
|
86
|
+
except BinasciiError:
|
|
87
|
+
pass
|
|
88
|
+
return None
|
|
117
89
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
|
|
141
|
-
error('Invalid tag. Please use the correct tag')
|
|
142
|
-
else:
|
|
143
|
-
error(f'Server error: {json.dumps(response_json, indent=2)}')
|
|
144
|
-
except Exception as e:
|
|
145
|
-
error("Exception: Unable to create your game server")
|
|
146
|
-
return False
|
|
90
|
+
def _check_dependencies(self) -> bool:
|
|
91
|
+
try:
|
|
92
|
+
# Check dependencies
|
|
93
|
+
with Progress(
|
|
94
|
+
SpinnerColumn(),
|
|
95
|
+
TextColumn("[progress.description]{task.description}"),
|
|
96
|
+
transient=True,
|
|
97
|
+
) as progress:
|
|
98
|
+
progress.add_task(
|
|
99
|
+
description='Checking dependencies...', total=None)
|
|
100
|
+
try:
|
|
101
|
+
subprocess.run([
|
|
102
|
+
"docker", "--version"
|
|
103
|
+
], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=False)
|
|
104
|
+
except subprocess.CalledProcessError:
|
|
105
|
+
error('Docker not present')
|
|
106
|
+
return False
|
|
107
|
+
success('Dependencies Verified')
|
|
108
|
+
return True
|
|
109
|
+
except subprocess.CalledProcessError:
|
|
110
|
+
error('CLI Error')
|
|
111
|
+
return False
|
|
147
112
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
image_tag = f'{self.sid}.{self.tag}'
|
|
154
|
-
full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
|
|
155
|
-
build_platform = ByoGs.DEFAULT_BUILD_PLATFORM
|
|
156
|
-
if len(self.token_parts) == 4:
|
|
157
|
-
build_platform = self.token_parts[3]
|
|
158
|
-
try:
|
|
159
|
-
# Check dependencies
|
|
160
|
-
with Progress(
|
|
161
|
-
SpinnerColumn(),
|
|
162
|
-
TextColumn("[progress.description]{task.description}"),
|
|
163
|
-
transient=True,
|
|
164
|
-
) as progress:
|
|
165
|
-
progress.add_task(description=f'Checking dependencies...', total=None)
|
|
113
|
+
def _docker_login(self) -> bool:
|
|
114
|
+
# Get the data
|
|
115
|
+
ecr_repo_url = self.token_parts[0]
|
|
116
|
+
ecr_repo_username = self.token_parts[1]
|
|
117
|
+
ecr_repo_token = self.token_parts[2]
|
|
166
118
|
try:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
119
|
+
# Login to Snapser Registry
|
|
120
|
+
with Progress(
|
|
121
|
+
SpinnerColumn(),
|
|
122
|
+
TextColumn("[progress.description]{task.description}"),
|
|
123
|
+
transient=True,
|
|
124
|
+
) as progress:
|
|
125
|
+
progress.add_task(
|
|
126
|
+
description='Logging into Snapser Image Registry...', total=None)
|
|
127
|
+
if platform == 'win32':
|
|
128
|
+
response = subprocess.run([
|
|
129
|
+
'docker', 'login', '--username', ecr_repo_username,
|
|
130
|
+
'--password', ecr_repo_token, ecr_repo_url
|
|
131
|
+
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=False)
|
|
132
|
+
else:
|
|
133
|
+
response = subprocess.run([
|
|
134
|
+
f'echo "{ecr_repo_token}" | docker login '
|
|
135
|
+
f'--username {ecr_repo_username} --password-stdin {ecr_repo_url}'
|
|
136
|
+
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=False)
|
|
137
|
+
if response.returncode:
|
|
138
|
+
error(
|
|
139
|
+
'Unable to connect to the Snapser Container Repository. '
|
|
140
|
+
'Please confirm if docker is running or try restarting docker'
|
|
141
|
+
)
|
|
142
|
+
return False
|
|
143
|
+
success('Login Successful')
|
|
144
|
+
return True
|
|
145
|
+
except subprocess.CalledProcessError:
|
|
146
|
+
error('CLI Error')
|
|
147
|
+
return False
|
|
174
148
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
149
|
+
def _docker_build(self) -> bool:
|
|
150
|
+
# Get the data
|
|
151
|
+
image_tag = f'{self.sid}.{self.input_tag}'
|
|
152
|
+
build_platform = ByoGs.DEFAULT_BUILD_PLATFORM
|
|
153
|
+
if len(self.token_parts) == 4:
|
|
154
|
+
build_platform = self.token_parts[3]
|
|
155
|
+
try:
|
|
156
|
+
# Build your snap
|
|
157
|
+
with Progress(
|
|
158
|
+
SpinnerColumn(),
|
|
159
|
+
TextColumn("[progress.description]{task.description}"),
|
|
160
|
+
transient=True,
|
|
161
|
+
) as progress:
|
|
162
|
+
progress.add_task(
|
|
163
|
+
description='Building your snap...', total=None)
|
|
164
|
+
if platform == "win32":
|
|
165
|
+
response = subprocess.run([
|
|
166
|
+
# f"docker build --no-cache -t {tag} {path}"
|
|
167
|
+
'docker', 'build', '--platform', build_platform, '-t', image_tag, self.path
|
|
168
|
+
], shell=True, check=False)
|
|
169
|
+
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
170
|
+
else:
|
|
171
|
+
response = subprocess.run([
|
|
172
|
+
# f"docker build --no-cache -t {tag} {path}"
|
|
173
|
+
f"docker build --platform {build_platform} -t {image_tag} {self.path}"
|
|
174
|
+
], shell=True, check=False)
|
|
175
|
+
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
176
|
+
if response.returncode:
|
|
177
|
+
error('Unable to build docker')
|
|
178
|
+
return False
|
|
179
|
+
success('Build Successful')
|
|
180
|
+
return True
|
|
181
|
+
except subprocess.CalledProcessError:
|
|
182
|
+
error('CLI Error')
|
|
183
|
+
return False
|
|
194
184
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
185
|
+
def _docker_tag(self) -> bool:
|
|
186
|
+
# Get the data
|
|
187
|
+
ecr_repo_url = self.token_parts[0]
|
|
188
|
+
image_tag = f'{self.sid}.{self.input_tag}'
|
|
189
|
+
full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
|
|
190
|
+
try:
|
|
191
|
+
# Tag the repo
|
|
192
|
+
with Progress(
|
|
193
|
+
SpinnerColumn(),
|
|
194
|
+
TextColumn("[progress.description]{task.description}"),
|
|
195
|
+
transient=True,
|
|
196
|
+
) as progress:
|
|
197
|
+
progress.add_task(
|
|
198
|
+
description='Tagging your snap...', total=None)
|
|
199
|
+
if platform == "win32":
|
|
200
|
+
response = subprocess.run([
|
|
201
|
+
'docker', 'tag', image_tag, full_ecr_repo_url
|
|
202
|
+
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=False)
|
|
203
|
+
else:
|
|
204
|
+
response = subprocess.run([
|
|
205
|
+
f"docker tag {image_tag} {full_ecr_repo_url}"
|
|
206
|
+
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, check=False)
|
|
207
|
+
if response.returncode:
|
|
208
|
+
error('Unable to tag your snap')
|
|
209
|
+
return False
|
|
210
|
+
success('Tag Successful')
|
|
211
|
+
return True
|
|
212
|
+
except subprocess.CalledProcessError:
|
|
213
|
+
error('CLI Error')
|
|
214
|
+
return False
|
|
216
215
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
) as progress:
|
|
223
|
-
progress.add_task(description=f'Tagging your snap...', total=None)
|
|
224
|
-
if platform == "win32":
|
|
225
|
-
response = subprocess.run([
|
|
226
|
-
'docker', 'tag', image_tag, full_ecr_repo_url
|
|
227
|
-
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
228
|
-
else:
|
|
229
|
-
response = subprocess.run([
|
|
230
|
-
f"docker tag {image_tag} {full_ecr_repo_url}"
|
|
231
|
-
], shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
232
|
-
if response.returncode:
|
|
233
|
-
error('Unable to tag your snap')
|
|
234
|
-
return False
|
|
235
|
-
success('Tag Successful')
|
|
216
|
+
def _docker_push(self) -> bool:
|
|
217
|
+
try:
|
|
218
|
+
ecr_repo_url = self.token_parts[0]
|
|
219
|
+
image_tag = f'{self.sid}.{self.input_tag}'
|
|
220
|
+
full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
|
|
236
221
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
222
|
+
# Push the image
|
|
223
|
+
with Progress(
|
|
224
|
+
SpinnerColumn(),
|
|
225
|
+
TextColumn("[progress.description]{task.description}"),
|
|
226
|
+
transient=True,
|
|
227
|
+
) as progress:
|
|
228
|
+
progress.add_task(
|
|
229
|
+
description='Pushing your snap...', total=None)
|
|
230
|
+
if platform == "win32":
|
|
231
|
+
response = subprocess.run([
|
|
232
|
+
'docker', 'push', full_ecr_repo_url
|
|
233
|
+
], shell=True, check=False)
|
|
234
|
+
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
235
|
+
else:
|
|
236
|
+
response = subprocess.run([
|
|
237
|
+
f"docker push {full_ecr_repo_url}"
|
|
238
|
+
], shell=True, check=False)
|
|
239
|
+
# stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
|
240
|
+
if response.returncode:
|
|
241
|
+
error('Unable to push your snap')
|
|
242
|
+
return False
|
|
243
|
+
success('Snap Upload Successful')
|
|
244
|
+
return True
|
|
245
|
+
except subprocess.CalledProcessError:
|
|
246
|
+
error('CLI Error')
|
|
247
|
+
return False
|
|
241
248
|
|
|
242
|
-
|
|
243
|
-
ecr_repo_url = self.token_parts[0]
|
|
244
|
-
image_tag = f'{self.sid}.{self.tag}'
|
|
245
|
-
full_ecr_repo_url = f'{ecr_repo_url}:{image_tag}'
|
|
249
|
+
# Public methods
|
|
246
250
|
|
|
247
|
-
#
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
251
|
+
# Validator
|
|
252
|
+
def validate_input(self) -> ResponseType:
|
|
253
|
+
"""
|
|
254
|
+
Validator
|
|
255
|
+
"""
|
|
256
|
+
response: ResponseType = {
|
|
257
|
+
'error': True,
|
|
258
|
+
'msg': '',
|
|
259
|
+
'data': []
|
|
260
|
+
}
|
|
261
|
+
# Check API Key and Base URL
|
|
262
|
+
if not self.api_key or self.base_url == '':
|
|
263
|
+
response['msg'] = "Missing API Key."
|
|
264
|
+
return response
|
|
265
|
+
# Check subcommand
|
|
266
|
+
if not self.subcommand in ByoGs.SUBCOMMANDS:
|
|
267
|
+
response['msg'] = f"Invalid command. Valid commands are {', '.join(ByoGs.SUBCOMMANDS)}."
|
|
268
|
+
return response
|
|
269
|
+
# Validate the SID
|
|
270
|
+
if not self.sid.startswith(ByoGs.ID_PREFIX):
|
|
271
|
+
response['msg'] = (
|
|
272
|
+
"Invalid Game Server ID. Valid Game Server IDs start "
|
|
273
|
+
f"with {ByoGs.ID_PREFIX}."
|
|
274
|
+
)
|
|
275
|
+
return response
|
|
276
|
+
if len(self.sid) > ByoGs.SID_CHARACTER_LIMIT:
|
|
277
|
+
response['msg'] = (
|
|
278
|
+
"Invalid Game Server ID. "
|
|
279
|
+
f"Game Server ID should be less than {ByoGs.SID_CHARACTER_LIMIT} characters"
|
|
280
|
+
)
|
|
281
|
+
return response
|
|
282
|
+
# Validation for subcommands
|
|
283
|
+
if self.subcommand == 'create':
|
|
284
|
+
if self.name == '':
|
|
285
|
+
response['msg'] = "Missing name"
|
|
286
|
+
return response
|
|
287
|
+
if self.language not in ByoGs.LANGUAGES:
|
|
288
|
+
response['msg'] = (
|
|
289
|
+
"Invalid language. Valid languages "
|
|
290
|
+
f"are {', '.join(ByoGs.LANGUAGES)}."
|
|
291
|
+
)
|
|
292
|
+
return response
|
|
293
|
+
if self.platform_type not in ByoGs.PLATFORMS:
|
|
294
|
+
response['msg'] = (
|
|
295
|
+
"Invalid platform. Valid platforms "
|
|
296
|
+
f"are {', '.join(ByoGs.PLATFORMS)}."
|
|
297
|
+
)
|
|
298
|
+
return response
|
|
299
|
+
else:
|
|
300
|
+
if self.token_parts is None:
|
|
301
|
+
response['msg'] = 'Invalid token. Please reach out to your support team'
|
|
302
|
+
return response
|
|
303
|
+
# Check tag
|
|
304
|
+
if self.input_tag is None or len(self.input_tag.split()) > 1 or \
|
|
305
|
+
len(self.input_tag) > ByoGs.TAG_CHARACTER_LIMIT:
|
|
306
|
+
response['msg'] = (
|
|
307
|
+
"Tag should be a single word with maximum of "
|
|
308
|
+
f"{ByoGs.TAG_CHARACTER_LIMIT} characters"
|
|
309
|
+
)
|
|
310
|
+
return response
|
|
311
|
+
if self.subcommand == 'build' or self.subcommand == 'publish-image':
|
|
312
|
+
if not self.input_tag:
|
|
313
|
+
response['msg'] = "Missing required parameter: tag"
|
|
314
|
+
return response
|
|
315
|
+
if not self.path:
|
|
316
|
+
response['msg'] = "Missing required parameter: path"
|
|
317
|
+
return response
|
|
318
|
+
# Check path
|
|
319
|
+
if not os.path.isfile(f"{self.path}/{self.dockerfile}"):
|
|
320
|
+
response['msg'] = f"Unable to find {self.dockerfile} at path {self.path}"
|
|
321
|
+
return response
|
|
322
|
+
elif self.subcommand == 'push':
|
|
323
|
+
if not self.input_tag:
|
|
324
|
+
response['msg'] = "Missing required parameter: tag"
|
|
325
|
+
return response
|
|
326
|
+
elif self.subcommand == 'publish-version':
|
|
327
|
+
if not self.version:
|
|
328
|
+
response['msg'] = "Missing required parameter: version"
|
|
329
|
+
return response
|
|
330
|
+
if not self.http_port:
|
|
331
|
+
response['msg'] = "Missing required parameter: Ingress HTTP Port"
|
|
332
|
+
return response
|
|
333
|
+
pattern = r'^v\d+\.\d+\.\d+$'
|
|
334
|
+
if not re.match(pattern, self.version):
|
|
335
|
+
response['msg'] = "Version should be in the format vX.X.X"
|
|
336
|
+
return response
|
|
337
|
+
if not self.http_port.isdigit():
|
|
338
|
+
response['msg'] = "Ingress HTTP Port should be a number"
|
|
339
|
+
return response
|
|
340
|
+
if self.debug_port and not self.debug_port.isdigit():
|
|
341
|
+
response['msg'] = "Debug Port should be a number"
|
|
342
|
+
return response
|
|
343
|
+
# Send success
|
|
344
|
+
response['error'] = False
|
|
345
|
+
return response
|
|
267
346
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# dfile = open(f"{self.path}/swagger.json", "rb")
|
|
281
|
-
# test_res = requests.post(f"{self.base_url}/v1/snapser-api/byogs/{self.sid}/upload/{self.tag}/openapispec", files = {"attachment": dfile}, headers={'api-key': self.api_key})
|
|
282
|
-
# if test_res.ok:
|
|
283
|
-
# success('Uploaded Swagger.json')
|
|
284
|
-
# else:
|
|
285
|
-
# response_json = test_res.json()
|
|
286
|
-
# error(response_json['details'][0])
|
|
287
|
-
# except Exception as e:
|
|
288
|
-
# info('Unable to find swagger.json at ' + self.path + str(e))
|
|
347
|
+
# CRUD methods
|
|
348
|
+
def build(self) -> bool:
|
|
349
|
+
"""
|
|
350
|
+
Build the image
|
|
351
|
+
1. Check Dependencies
|
|
352
|
+
2. Login to Snapser Registry
|
|
353
|
+
3. Build your snap
|
|
354
|
+
"""
|
|
355
|
+
if not self._check_dependencies() or not self._docker_login() or \
|
|
356
|
+
not self._docker_build():
|
|
357
|
+
return False
|
|
358
|
+
return True
|
|
289
359
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
# else:
|
|
303
|
-
# error('Unable to upload your README.md')
|
|
304
|
-
# except Exception as e:
|
|
305
|
-
# info('Unable to find README.md at ' + self.path + str(e))
|
|
306
|
-
# return True
|
|
360
|
+
def push(self) -> bool:
|
|
361
|
+
"""
|
|
362
|
+
Tag the image
|
|
363
|
+
1. Check Dependencies
|
|
364
|
+
2. Login to Snapser Registry
|
|
365
|
+
3. Tag the snap
|
|
366
|
+
4. Push your snap
|
|
367
|
+
"""
|
|
368
|
+
if not self._check_dependencies() or not self._docker_login() or \
|
|
369
|
+
not self._docker_tag() or not self._docker_push():
|
|
370
|
+
return False
|
|
371
|
+
return True
|
|
307
372
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
373
|
+
# Upper echelon commands
|
|
374
|
+
def create(self) -> bool:
|
|
375
|
+
"""
|
|
376
|
+
Create a new game server
|
|
377
|
+
"""
|
|
378
|
+
with Progress(
|
|
379
|
+
SpinnerColumn(),
|
|
380
|
+
TextColumn("[progress.description]{task.description}"),
|
|
381
|
+
transient=True,
|
|
382
|
+
) as progress:
|
|
383
|
+
progress.add_task(
|
|
384
|
+
description='Creating your game server...', total=None)
|
|
385
|
+
try:
|
|
386
|
+
payload = {
|
|
387
|
+
"service_id": self.sid,
|
|
388
|
+
"name": self.name,
|
|
389
|
+
"description": self.desc,
|
|
390
|
+
"platform": self.platform_type,
|
|
391
|
+
"language": self.language,
|
|
392
|
+
}
|
|
393
|
+
res = requests.post(
|
|
394
|
+
f"{self.base_url}/v1/snapser-api/byogs",
|
|
395
|
+
json=payload, headers={'api-key': self.api_key},
|
|
396
|
+
timeout=SERVER_CALL_TIMEOUT
|
|
397
|
+
)
|
|
398
|
+
if res.ok:
|
|
399
|
+
return True
|
|
400
|
+
response_json = res.json()
|
|
401
|
+
if "api_error_code" in response_json:
|
|
402
|
+
if response_json['api_error_code'] == ERROR_SERVICE_VERSION_EXISTS:
|
|
403
|
+
error(
|
|
404
|
+
'Version already exists. Please update your version and try again'
|
|
405
|
+
)
|
|
406
|
+
if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
|
|
407
|
+
error('Invalid tag. Please use the correct tag')
|
|
408
|
+
else:
|
|
409
|
+
error(
|
|
410
|
+
f'Server error: {json.dumps(response_json, indent=2)}'
|
|
411
|
+
)
|
|
412
|
+
except RequestException as e:
|
|
413
|
+
error(f"Exception: Unable to create your game server {e}")
|
|
414
|
+
return False
|
|
313
415
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if res.ok:
|
|
329
|
-
return True
|
|
330
|
-
response_json = res.json()
|
|
331
|
-
if "api_error_code" in response_json:
|
|
332
|
-
if response_json['api_error_code'] == ERROR_SERVICE_VERSION_EXISTS:
|
|
333
|
-
error('Version already exists. Please update your version and try again')
|
|
334
|
-
if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
|
|
335
|
-
error('Invalid tag. Please use the correct tag')
|
|
336
|
-
else:
|
|
337
|
-
error(f'Server error: {json.dumps(response_json, indent=2)}')
|
|
338
|
-
except Exception as e:
|
|
339
|
-
error("Exception: Unable to publish a version for your snap")
|
|
340
|
-
return False
|
|
416
|
+
def publish_image(self) -> bool:
|
|
417
|
+
"""
|
|
418
|
+
Publish the image
|
|
419
|
+
1. Check Dependencies
|
|
420
|
+
2. Login to Snapser Registry
|
|
421
|
+
3. Build your snap
|
|
422
|
+
4. Tag the repo
|
|
423
|
+
5. Push the image
|
|
424
|
+
6. Upload swagger.json
|
|
425
|
+
"""
|
|
426
|
+
if not self._check_dependencies() or not self._docker_login() or \
|
|
427
|
+
not self._docker_build() or not self._docker_tag() or not self._docker_push():
|
|
428
|
+
return False
|
|
429
|
+
return True
|
|
341
430
|
|
|
431
|
+
def publish_version(self) -> bool:
|
|
432
|
+
"""
|
|
433
|
+
Publish your game server version
|
|
434
|
+
"""
|
|
435
|
+
with Progress(
|
|
436
|
+
SpinnerColumn(),
|
|
437
|
+
TextColumn("[progress.description]{task.description}"),
|
|
438
|
+
transient=True,
|
|
439
|
+
) as progress:
|
|
440
|
+
progress.add_task(
|
|
441
|
+
description='Publishing your snap...', total=None)
|
|
442
|
+
try:
|
|
443
|
+
payload = {
|
|
444
|
+
"version": self.version,
|
|
445
|
+
"image_tag": self.input_tag,
|
|
446
|
+
"http_port": self.http_port,
|
|
447
|
+
}
|
|
448
|
+
if self.debug_port:
|
|
449
|
+
payload['debug_port'] = self.debug_port
|
|
450
|
+
res = requests.post(
|
|
451
|
+
f"{self.base_url}/v1/snapser-api/byogs/{self.sid}/versions",
|
|
452
|
+
json=payload, headers={'api-key': self.api_key},
|
|
453
|
+
timeout=SERVER_CALL_TIMEOUT
|
|
454
|
+
)
|
|
455
|
+
if res.ok:
|
|
456
|
+
return True
|
|
457
|
+
response_json = res.json()
|
|
458
|
+
if "api_error_code" in response_json:
|
|
459
|
+
if response_json['api_error_code'] == ERROR_SERVICE_VERSION_EXISTS:
|
|
460
|
+
error(
|
|
461
|
+
'Version already exists. Please update your version and try again'
|
|
462
|
+
)
|
|
463
|
+
if response_json['api_error_code'] == ERROR_TAG_NOT_AVAILABLE:
|
|
464
|
+
error('Invalid tag. Please use the correct tag')
|
|
465
|
+
else:
|
|
466
|
+
error(
|
|
467
|
+
f'Server error: {json.dumps(response_json, indent=2)}'
|
|
468
|
+
)
|
|
469
|
+
except RequestException as e:
|
|
470
|
+
error(
|
|
471
|
+
f"Exception: Unable to publish a version for your snap {e}"
|
|
472
|
+
)
|
|
473
|
+
return False
|