snapctl 1.1.0__py3-none-any.whl → 1.1.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/snapend_manifest.py +376 -56
- snapctl/config/constants.py +3 -2
- snapctl/data/releases/1.1.1.mdx +8 -0
- snapctl/main.py +27 -3
- snapctl/utils/helper.py +8 -0
- {snapctl-1.1.0.dist-info → snapctl-1.1.1.dist-info}/METADATA +42 -8
- {snapctl-1.1.0.dist-info → snapctl-1.1.1.dist-info}/RECORD +10 -9
- {snapctl-1.1.0.dist-info → snapctl-1.1.1.dist-info}/LICENSE +0 -0
- {snapctl-1.1.0.dist-info → snapctl-1.1.1.dist-info}/WHEEL +0 -0
- {snapctl-1.1.0.dist-info → snapctl-1.1.1.dist-info}/entry_points.txt +0 -0
|
@@ -8,9 +8,9 @@ from requests.exceptions import RequestException
|
|
|
8
8
|
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
9
9
|
from snapctl.config.constants import SNAPCTL_SNAPEND_MANIFEST_UPGRADE_ERROR, SNAPCTL_INPUT_ERROR, \
|
|
10
10
|
SNAPCTL_SNAPEND_MANIFEST_CREATE_ERROR, SNAPCTL_SNAPEND_MANIFEST_UPDATE_ERROR, \
|
|
11
|
-
SNAPCTL_INTERNAL_SERVER_ERROR
|
|
11
|
+
SNAPCTL_INTERNAL_SERVER_ERROR, SNAPCTL_SNAPEND_MANIFEST_SYNC_ERROR
|
|
12
12
|
from snapctl.commands.snaps import Snaps
|
|
13
|
-
from snapctl.utils.helper import snapctl_error, snapctl_success
|
|
13
|
+
from snapctl.utils.helper import snapctl_error, snapctl_success, check_duplicates_in_list
|
|
14
14
|
from snapctl.utils.echo import info, warning, success
|
|
15
15
|
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ class SnapendManifest:
|
|
|
18
18
|
"""
|
|
19
19
|
CLI commands exposed for Snapend manifest
|
|
20
20
|
"""
|
|
21
|
-
SUBCOMMANDS = ['create', 'update', 'upgrade']
|
|
21
|
+
SUBCOMMANDS = ['create', 'sync', 'update', 'upgrade']
|
|
22
22
|
ENVIRONMENTS = ['DEVELOPMENT', 'STAGING', 'PRODUCTION']
|
|
23
23
|
FEATURES = ['WEB_SOCKETS']
|
|
24
24
|
AUTH_SNAP_ID = 'auth'
|
|
@@ -30,6 +30,10 @@ class SnapendManifest:
|
|
|
30
30
|
manifest_path_filename: Union[str, None] = None,
|
|
31
31
|
snaps: Union[str, None] = None,
|
|
32
32
|
features: Union[str, None] = None,
|
|
33
|
+
add_snaps: Union[str, None] = None,
|
|
34
|
+
remove_snaps: Union[str, None] = None,
|
|
35
|
+
add_features: Union[str, None] = None,
|
|
36
|
+
remove_features: Union[str, None] = None,
|
|
33
37
|
out_path_filename: Union[str, None] = None,
|
|
34
38
|
) -> None:
|
|
35
39
|
self.subcommand: str = subcommand
|
|
@@ -42,6 +46,10 @@ class SnapendManifest:
|
|
|
42
46
|
self.out_path_filename: Union[str, None] = out_path_filename
|
|
43
47
|
self.snaps = snaps
|
|
44
48
|
self.features = features
|
|
49
|
+
self.add_snaps = add_snaps
|
|
50
|
+
self.remove_snaps = remove_snaps
|
|
51
|
+
self.add_features = add_features
|
|
52
|
+
self.remove_features = remove_features
|
|
45
53
|
self.remote_snaps: list = self.load_snaps()
|
|
46
54
|
# Setup
|
|
47
55
|
self.setup_manifest()
|
|
@@ -137,6 +145,12 @@ class SnapendManifest:
|
|
|
137
145
|
message="Environment must be one of " +
|
|
138
146
|
f"{', '.join(SnapendManifest.ENVIRONMENTS)}.",
|
|
139
147
|
code=SNAPCTL_INPUT_ERROR)
|
|
148
|
+
if (not self.snaps or self.snaps == '') and \
|
|
149
|
+
(not self.features or self.features == ''):
|
|
150
|
+
snapctl_error(
|
|
151
|
+
message="At least one of snaps or features " +
|
|
152
|
+
"is required to sync a snapend manifest.",
|
|
153
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
140
154
|
if not self.out_path_filename:
|
|
141
155
|
snapctl_error(
|
|
142
156
|
message="Output path is required for create command.",
|
|
@@ -147,33 +161,80 @@ class SnapendManifest:
|
|
|
147
161
|
snapctl_error(
|
|
148
162
|
message="Output path must end with .json, .yaml or .yml",
|
|
149
163
|
code=SNAPCTL_INPUT_ERROR)
|
|
150
|
-
if
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
164
|
+
if self.snaps and self.snaps != '':
|
|
165
|
+
input_snaps_list = self.snaps.split(',')
|
|
166
|
+
repeat_snaps = check_duplicates_in_list(input_snaps_list)
|
|
167
|
+
if len(repeat_snaps) > 0:
|
|
168
|
+
snapctl_error(
|
|
169
|
+
message="Duplicate snaps found in input: " +
|
|
170
|
+
f"{', '.join(repeat_snaps)}. Please check and try again.",
|
|
171
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
172
|
+
remote_snaps_ids = [snap['id'] for snap in self.remote_snaps]
|
|
173
|
+
for input_snap in input_snaps_list:
|
|
174
|
+
if not input_snap in remote_snaps_ids:
|
|
175
|
+
snapctl_error(
|
|
176
|
+
message="Invalid Snap " + input_snap +
|
|
177
|
+
" provided with --snaps. Please check and try again.",
|
|
178
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
155
179
|
if self.features:
|
|
156
|
-
|
|
180
|
+
input_features_list = self.features.split(',')
|
|
181
|
+
repeat_features = check_duplicates_in_list(input_features_list)
|
|
182
|
+
if len(repeat_features) > 0:
|
|
183
|
+
snapctl_error(
|
|
184
|
+
message="Duplicate features found in input: " +
|
|
185
|
+
f"{', '.join(repeat_features)}. Please check and try again.",
|
|
186
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
187
|
+
for feature in input_features_list:
|
|
157
188
|
feature = feature.strip()
|
|
158
189
|
if feature.upper() not in SnapendManifest.FEATURES:
|
|
159
190
|
snapctl_error(
|
|
160
|
-
message="
|
|
191
|
+
message="--features must be one of " +
|
|
161
192
|
f"{', '.join(SnapendManifest.FEATURES)}.",
|
|
162
193
|
code=SNAPCTL_INPUT_ERROR)
|
|
163
|
-
elif self.subcommand == '
|
|
194
|
+
elif self.subcommand == 'sync':
|
|
164
195
|
if not self.manifest_path_filename:
|
|
165
196
|
snapctl_error(
|
|
166
|
-
message="Manifest path is required for
|
|
197
|
+
message="Manifest path is required for sync command.",
|
|
167
198
|
code=SNAPCTL_INPUT_ERROR)
|
|
168
199
|
if (not self.snaps or self.snaps == '') and \
|
|
169
200
|
(not self.features or self.features == ''):
|
|
170
201
|
snapctl_error(
|
|
171
202
|
message="At least one of snaps or features " +
|
|
172
|
-
"is required to
|
|
203
|
+
"is required to sync a snapend manifest.",
|
|
173
204
|
code=SNAPCTL_INPUT_ERROR)
|
|
205
|
+
if self.snaps and self.snaps != '':
|
|
206
|
+
input_snaps_list = self.snaps.split(',')
|
|
207
|
+
repeat_snaps = check_duplicates_in_list(input_snaps_list)
|
|
208
|
+
if len(repeat_snaps) > 0:
|
|
209
|
+
snapctl_error(
|
|
210
|
+
message="Duplicate snaps found in input: " +
|
|
211
|
+
f"{', '.join(repeat_snaps)}. Please check and try again.",
|
|
212
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
213
|
+
remote_snaps_ids = [snap['id'] for snap in self.remote_snaps]
|
|
214
|
+
for input_snap in input_snaps_list:
|
|
215
|
+
if not input_snap in remote_snaps_ids:
|
|
216
|
+
snapctl_error(
|
|
217
|
+
message="Invalid Snap " + input_snap +
|
|
218
|
+
" provided with --snaps. Please check and try again.",
|
|
219
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
220
|
+
if self.features:
|
|
221
|
+
input_features_list = self.features.split(',')
|
|
222
|
+
repeat_features = check_duplicates_in_list(input_features_list)
|
|
223
|
+
if len(repeat_features) > 0:
|
|
224
|
+
snapctl_error(
|
|
225
|
+
message="Duplicate features found in input: " +
|
|
226
|
+
f"{', '.join(repeat_features)}. Please check and try again.",
|
|
227
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
228
|
+
for feature in input_features_list:
|
|
229
|
+
feature = feature.strip()
|
|
230
|
+
if feature.upper() not in SnapendManifest.FEATURES:
|
|
231
|
+
snapctl_error(
|
|
232
|
+
message="--features must be one of " +
|
|
233
|
+
f"{', '.join(SnapendManifest.FEATURES)}.",
|
|
234
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
174
235
|
if not self.out_path_filename:
|
|
175
236
|
snapctl_error(
|
|
176
|
-
message="Output path is required for
|
|
237
|
+
message="Output path is required for sync command.",
|
|
177
238
|
code=SNAPCTL_INPUT_ERROR)
|
|
178
239
|
if self.out_path_filename and not (self.out_path_filename.endswith('.json') or
|
|
179
240
|
self.out_path_filename.endswith('.yaml') or
|
|
@@ -192,10 +253,132 @@ class SnapendManifest:
|
|
|
192
253
|
"Please check the file and try again.",
|
|
193
254
|
code=SNAPCTL_INPUT_ERROR)
|
|
194
255
|
elif self.subcommand == 'upgrade':
|
|
256
|
+
if not self.manifest_path_filename:
|
|
257
|
+
snapctl_error(
|
|
258
|
+
message="Manifest path is required for upgrade command.",
|
|
259
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
260
|
+
if self.snaps and self.snaps != '':
|
|
261
|
+
input_snaps_list = self.snaps.split(',')
|
|
262
|
+
repeat_snaps = check_duplicates_in_list(input_snaps_list)
|
|
263
|
+
if len(repeat_snaps) > 0:
|
|
264
|
+
snapctl_error(
|
|
265
|
+
message="Duplicate snaps found in input: " +
|
|
266
|
+
f"{', '.join(repeat_snaps)}. Please check and try again.",
|
|
267
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
268
|
+
if not self.out_path_filename:
|
|
269
|
+
snapctl_error(
|
|
270
|
+
message="Output path is required for upgrade command.",
|
|
271
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
272
|
+
if self.out_path_filename and not (self.out_path_filename.endswith('.json') or
|
|
273
|
+
self.out_path_filename.endswith('.yaml') or
|
|
274
|
+
self.out_path_filename.endswith('.yml')):
|
|
275
|
+
snapctl_error(
|
|
276
|
+
message="Output path must end with .json, .yaml or .yml",
|
|
277
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
278
|
+
if not self.manifest:
|
|
279
|
+
snapctl_error(
|
|
280
|
+
message="Unable to read the manifest file. " +
|
|
281
|
+
"Please check the file and try again.",
|
|
282
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
283
|
+
if 'service_definitions' not in self.manifest:
|
|
284
|
+
snapctl_error(
|
|
285
|
+
message="Invalid manifest file. Need service_definitions. " +
|
|
286
|
+
"Please check the file and try again.",
|
|
287
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
288
|
+
if self.snaps and self.snaps != '':
|
|
289
|
+
input_snaps_list = self.snaps.split(',')
|
|
290
|
+
remote_snaps_ids = [snap['id'] for snap in self.remote_snaps]
|
|
291
|
+
current_snap_ids = [snap['id']
|
|
292
|
+
for snap in self.manifest['service_definitions']]
|
|
293
|
+
for input_snap in input_snaps_list:
|
|
294
|
+
if not input_snap in remote_snaps_ids:
|
|
295
|
+
snapctl_error(
|
|
296
|
+
message="Invalid Snap " + input_snap +
|
|
297
|
+
" provided with --snaps. Please check and try again.",
|
|
298
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
299
|
+
if not input_snap in current_snap_ids:
|
|
300
|
+
snapctl_error(
|
|
301
|
+
message="Snap " + input_snap +
|
|
302
|
+
" provided with --snaps is not present in the manifest. " +
|
|
303
|
+
"Please check and try again.",
|
|
304
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
305
|
+
elif self.subcommand == 'update':
|
|
195
306
|
if not self.manifest_path_filename:
|
|
196
307
|
snapctl_error(
|
|
197
308
|
message="Manifest path is required for update command.",
|
|
198
309
|
code=SNAPCTL_INPUT_ERROR)
|
|
310
|
+
if (not self.add_snaps or self.add_snaps == '') and \
|
|
311
|
+
(not self.remove_snaps or self.remove_snaps == '') and \
|
|
312
|
+
(not self.add_features or self.add_features == '') and \
|
|
313
|
+
(not self.remove_features or self.remove_features == ''):
|
|
314
|
+
snapctl_error(
|
|
315
|
+
message="At least one of --add-snaps, --remove-snaps, add-features " +
|
|
316
|
+
"or --remove-features is required to update a snapend manifest.",
|
|
317
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
318
|
+
if self.add_snaps and self.add_snaps != '':
|
|
319
|
+
input_snaps_list = self.add_snaps.split(',')
|
|
320
|
+
repeat_snaps = check_duplicates_in_list(input_snaps_list)
|
|
321
|
+
if len(repeat_snaps) > 0:
|
|
322
|
+
snapctl_error(
|
|
323
|
+
message="Duplicate snaps found in input: " +
|
|
324
|
+
f"{', '.join(repeat_snaps)}. Please check and try again.",
|
|
325
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
326
|
+
remote_snaps_ids = [snap['id'] for snap in self.remote_snaps]
|
|
327
|
+
for input_snap in input_snaps_list:
|
|
328
|
+
if not input_snap in remote_snaps_ids:
|
|
329
|
+
snapctl_error(
|
|
330
|
+
message="Invalid Snap " + input_snap +
|
|
331
|
+
" provided with --add-snaps. Please check and try again.",
|
|
332
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
333
|
+
if self.remove_snaps and self.remove_snaps != '':
|
|
334
|
+
input_snaps_list = self.remove_snaps.split(',')
|
|
335
|
+
if SnapendManifest.AUTH_SNAP_ID in input_snaps_list:
|
|
336
|
+
snapctl_error(
|
|
337
|
+
message="Auth snap cannot be removed from the manifest.",
|
|
338
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
339
|
+
repeat_snaps = check_duplicates_in_list(input_snaps_list)
|
|
340
|
+
if len(repeat_snaps) > 0:
|
|
341
|
+
snapctl_error(
|
|
342
|
+
message="Duplicate snaps found in input: " +
|
|
343
|
+
f"{', '.join(repeat_snaps)}. Please check and try again.",
|
|
344
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
345
|
+
remote_snaps_ids = [snap['id'] for snap in self.remote_snaps]
|
|
346
|
+
for input_snap in input_snaps_list:
|
|
347
|
+
if not input_snap in remote_snaps_ids:
|
|
348
|
+
snapctl_error(
|
|
349
|
+
message="Invalid Snap " + input_snap +
|
|
350
|
+
" provided with --remove-snaps. Please check and try again.",
|
|
351
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
352
|
+
if self.add_features:
|
|
353
|
+
input_features_list = self.add_features.split(',')
|
|
354
|
+
repeat_features = check_duplicates_in_list(input_features_list)
|
|
355
|
+
if len(repeat_features) > 0:
|
|
356
|
+
snapctl_error(
|
|
357
|
+
message="Duplicate features found in input: " +
|
|
358
|
+
f"{', '.join(repeat_features)}. Please check and try again.",
|
|
359
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
360
|
+
for feature in input_features_list:
|
|
361
|
+
feature = feature.strip()
|
|
362
|
+
if feature.upper() not in SnapendManifest.FEATURES:
|
|
363
|
+
snapctl_error(
|
|
364
|
+
message="--add-features must be one of " +
|
|
365
|
+
f"{', '.join(SnapendManifest.FEATURES)}.",
|
|
366
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
367
|
+
if self.remove_features:
|
|
368
|
+
input_features_list = self.remove_features.split(',')
|
|
369
|
+
repeat_features = check_duplicates_in_list(input_features_list)
|
|
370
|
+
if len(repeat_features) > 0:
|
|
371
|
+
snapctl_error(
|
|
372
|
+
message="Duplicate features found in input: " +
|
|
373
|
+
f"{', '.join(repeat_features)}. Please check and try again.",
|
|
374
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
375
|
+
for feature in input_features_list:
|
|
376
|
+
feature = feature.strip()
|
|
377
|
+
if feature.upper() not in SnapendManifest.FEATURES:
|
|
378
|
+
snapctl_error(
|
|
379
|
+
message="--remove-features must be one of " +
|
|
380
|
+
f"{', '.join(SnapendManifest.FEATURES)}.",
|
|
381
|
+
code=SNAPCTL_INPUT_ERROR)
|
|
199
382
|
if not self.out_path_filename:
|
|
200
383
|
snapctl_error(
|
|
201
384
|
message="Output path is required for update command.",
|
|
@@ -250,7 +433,7 @@ class SnapendManifest:
|
|
|
250
433
|
"""
|
|
251
434
|
Create a snapend manifest
|
|
252
435
|
@test -
|
|
253
|
-
`python -m snapctl snapend-manifest create --name my-dev-snapend --env DEVELOPMENT --snaps auth,analytics --out-path-filename ./snapend-manifest.json`
|
|
436
|
+
`python -m snapctl snapend-manifest create --name my-dev-snapend --env DEVELOPMENT --snaps auth,analytics --out-path-filename ./snapend-create-manifest.json`
|
|
254
437
|
"""
|
|
255
438
|
progress = Progress(
|
|
256
439
|
SpinnerColumn(),
|
|
@@ -270,21 +453,14 @@ class SnapendManifest:
|
|
|
270
453
|
"external_endpoints": [],
|
|
271
454
|
"settings": []
|
|
272
455
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
snap_found = True
|
|
282
|
-
break
|
|
283
|
-
if not snap_found:
|
|
284
|
-
snapctl_error(
|
|
285
|
-
message=f"Snap ID {snap_id} not found in your snaps.",
|
|
286
|
-
code=SNAPCTL_INPUT_ERROR,
|
|
287
|
-
progress=progress)
|
|
456
|
+
if self.snaps and self.snaps != '':
|
|
457
|
+
snap_ids = [snap_id.strip()
|
|
458
|
+
for snap_id in self.snaps.split(',')]
|
|
459
|
+
for snap_id in snap_ids:
|
|
460
|
+
snap_sd = self._get_snap_sd(snap_id)
|
|
461
|
+
new_manifest['service_definitions'].append(snap_sd)
|
|
462
|
+
info(f"Added snap {snap_id} to the manifest.")
|
|
463
|
+
# If auth snap is not present, add it
|
|
288
464
|
found_auth = False
|
|
289
465
|
for final_snap in new_manifest['service_definitions']:
|
|
290
466
|
if final_snap['id'] == SnapendManifest.AUTH_SNAP_ID:
|
|
@@ -303,6 +479,7 @@ class SnapendManifest:
|
|
|
303
479
|
if feature.upper() not in new_manifest['feature_definitions']:
|
|
304
480
|
new_manifest['feature_definitions'].append(
|
|
305
481
|
feature.upper())
|
|
482
|
+
info(f"Added feature {feature} to the manifest.")
|
|
306
483
|
if self.out_path_filename:
|
|
307
484
|
# Based on the out-path extension, write JSON or YAML
|
|
308
485
|
if self.out_path_filename.endswith('.yaml') or self.out_path_filename.endswith('.yml'):
|
|
@@ -343,11 +520,11 @@ class SnapendManifest:
|
|
|
343
520
|
message='Failed to create snapend manifest.',
|
|
344
521
|
code=SNAPCTL_SNAPEND_MANIFEST_CREATE_ERROR, progress=progress)
|
|
345
522
|
|
|
346
|
-
def
|
|
523
|
+
def sync(self) -> bool:
|
|
347
524
|
"""
|
|
348
|
-
|
|
525
|
+
Sync with a snapend manifest
|
|
349
526
|
@test -
|
|
350
|
-
`python -m snapctl snapend-manifest
|
|
527
|
+
`python -m snapctl snapend-manifest sync --manifest-path-filename ./snapend-manifest.json --snaps analytics,auth --features WEB_SOCKETS --out-path-filename ./snapend-updated-manifest.json`
|
|
351
528
|
"""
|
|
352
529
|
progress = Progress(
|
|
353
530
|
SpinnerColumn(),
|
|
@@ -356,41 +533,33 @@ class SnapendManifest:
|
|
|
356
533
|
)
|
|
357
534
|
progress.start()
|
|
358
535
|
progress.add_task(
|
|
359
|
-
description='
|
|
536
|
+
description='Syncing snapend manifest...', total=None)
|
|
360
537
|
try:
|
|
361
538
|
if 'applied_configuration' in self.manifest:
|
|
362
539
|
info('Applied configuration found in the manifest. ')
|
|
363
540
|
warning(
|
|
364
541
|
'You need to ensure you have synced the manifest from remote. ' +
|
|
365
542
|
'Else if you try applying the newly generated manifest it may not work.')
|
|
366
|
-
|
|
367
543
|
current_snaps = self.manifest['service_definitions']
|
|
368
544
|
current_snap_ids = [snap['id'] for snap in current_snaps]
|
|
369
545
|
final_snaps = []
|
|
370
546
|
if self.snaps and self.snaps != '':
|
|
371
|
-
|
|
547
|
+
input_snap_list = self.snaps.split(',')
|
|
548
|
+
for snap_id in input_snap_list:
|
|
372
549
|
snap_id = snap_id.strip()
|
|
373
550
|
if snap_id == '':
|
|
374
551
|
continue
|
|
552
|
+
# Copy existing snap if already present
|
|
375
553
|
if snap_id in current_snap_ids:
|
|
376
554
|
warning(
|
|
377
555
|
f"Snap {snap_id} already exists in the manifest. Skipping...")
|
|
378
556
|
final_snaps.append(
|
|
379
557
|
current_snaps[current_snap_ids.index(snap_id)])
|
|
380
558
|
continue
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
snap_sd = self._get_snap_sd(snap_id)
|
|
386
|
-
final_snaps.append(snap_sd)
|
|
387
|
-
info(f"Added snap {snap_id} to the manifest.")
|
|
388
|
-
break
|
|
389
|
-
if not snap_found:
|
|
390
|
-
snapctl_error(
|
|
391
|
-
message=f"Snap ID {snap_id} not found in your snaps.",
|
|
392
|
-
code=SNAPCTL_INPUT_ERROR,
|
|
393
|
-
progress=progress)
|
|
559
|
+
# Else add new snap from remote snaps
|
|
560
|
+
snap_sd = self._get_snap_sd(snap_id)
|
|
561
|
+
final_snaps.append(snap_sd)
|
|
562
|
+
info(f"Added snap {snap_id} to the manifest.")
|
|
394
563
|
found_auth = False
|
|
395
564
|
for final_snap in final_snaps:
|
|
396
565
|
if final_snap['id'] == SnapendManifest.AUTH_SNAP_ID:
|
|
@@ -404,19 +573,23 @@ class SnapendManifest:
|
|
|
404
573
|
warning(
|
|
405
574
|
f'Old snaps list "{",".join(current_snap_ids)}" will be ' +
|
|
406
575
|
f'replaced with new snaps list "{",".join([snap['id'] for snap in final_snaps])}"')
|
|
576
|
+
final_snaps.sort(key=lambda x: x["id"])
|
|
407
577
|
self.manifest['service_definitions'] = final_snaps
|
|
408
578
|
|
|
409
579
|
final_features = []
|
|
410
580
|
if self.features and self.features != '':
|
|
411
581
|
current_features = self.manifest['feature_definitions']
|
|
412
|
-
|
|
582
|
+
input_feature_list = self.features.split(',')
|
|
583
|
+
for feature in input_feature_list:
|
|
413
584
|
feature = feature.strip()
|
|
414
585
|
if feature == '':
|
|
415
586
|
continue
|
|
587
|
+
final_features.append(feature.upper())
|
|
416
588
|
if feature.upper() in current_features:
|
|
417
589
|
warning(
|
|
418
590
|
f"Feature {feature} already exists in the manifest. Skipping...")
|
|
419
|
-
|
|
591
|
+
else:
|
|
592
|
+
info(f"Added feature {feature} to the manifest.")
|
|
420
593
|
warning(
|
|
421
594
|
f'Old features list: "{",".join(self.manifest["feature_definitions"])}" will ' +
|
|
422
595
|
f'be replaced with new features list: "{",".join([feature for feature in final_features])}"')
|
|
@@ -441,7 +614,7 @@ class SnapendManifest:
|
|
|
441
614
|
out_file.write(json.dumps(self.manifest, indent=4))
|
|
442
615
|
info(f"Output written to {self.out_path_filename}")
|
|
443
616
|
snapctl_success(
|
|
444
|
-
message="Snapend manifest
|
|
617
|
+
message="Snapend manifest synced successfully.",
|
|
445
618
|
progress=progress)
|
|
446
619
|
except ValueError as e:
|
|
447
620
|
snapctl_error(
|
|
@@ -449,13 +622,13 @@ class SnapendManifest:
|
|
|
449
622
|
code=SNAPCTL_INTERNAL_SERVER_ERROR, progress=progress)
|
|
450
623
|
except RequestException as e:
|
|
451
624
|
snapctl_error(
|
|
452
|
-
message=f"Exception: Unable to
|
|
453
|
-
code=
|
|
625
|
+
message=f"Exception: Unable to synced snapend manifest {e}",
|
|
626
|
+
code=SNAPCTL_SNAPEND_MANIFEST_SYNC_ERROR, progress=progress)
|
|
454
627
|
finally:
|
|
455
628
|
progress.stop()
|
|
456
629
|
snapctl_error(
|
|
457
|
-
message='Failed to
|
|
458
|
-
code=
|
|
630
|
+
message='Failed to synced the snapend manifest.',
|
|
631
|
+
code=SNAPCTL_SNAPEND_MANIFEST_SYNC_ERROR, progress=progress)
|
|
459
632
|
|
|
460
633
|
def upgrade(self) -> bool:
|
|
461
634
|
"""
|
|
@@ -504,6 +677,7 @@ class SnapendManifest:
|
|
|
504
677
|
f"Snap {snap['id']} is already at the latest " +
|
|
505
678
|
f"version {snap['version']}. Skipping...")
|
|
506
679
|
break
|
|
680
|
+
current_snaps.sort(key=lambda x: x["id"])
|
|
507
681
|
self.manifest['service_definitions'] = current_snaps
|
|
508
682
|
|
|
509
683
|
# Write output
|
|
@@ -539,3 +713,149 @@ class SnapendManifest:
|
|
|
539
713
|
snapctl_error(
|
|
540
714
|
message='Failed to upgrade the snapend manifest.',
|
|
541
715
|
code=SNAPCTL_SNAPEND_MANIFEST_UPGRADE_ERROR, progress=progress)
|
|
716
|
+
|
|
717
|
+
def update(self) -> bool:
|
|
718
|
+
"""
|
|
719
|
+
Update a snapend manifest
|
|
720
|
+
@test -
|
|
721
|
+
`python -m snapctl snapend-manifest update --manifest-path-filename ./snapend-manifest.json --add-snaps analytics,auth --add-features WEB_SOCKETS --out-path-filename ./snapend-updated-manifest.json`
|
|
722
|
+
"""
|
|
723
|
+
progress = Progress(
|
|
724
|
+
SpinnerColumn(),
|
|
725
|
+
TextColumn("[progress.description]{task.description}"),
|
|
726
|
+
transient=True,
|
|
727
|
+
)
|
|
728
|
+
progress.start()
|
|
729
|
+
progress.add_task(
|
|
730
|
+
description='Updating snapend manifest...', total=None)
|
|
731
|
+
try:
|
|
732
|
+
if 'applied_configuration' in self.manifest:
|
|
733
|
+
info('Applied configuration found in the manifest. ')
|
|
734
|
+
warning(
|
|
735
|
+
'You need to ensure you have synced the manifest from remote. ' +
|
|
736
|
+
'Else if you try applying the newly generated manifest it may not work.')
|
|
737
|
+
current_snaps = self.manifest['service_definitions']
|
|
738
|
+
current_snap_ids = [snap['id'] for snap in current_snaps]
|
|
739
|
+
final_added_snap_ids = []
|
|
740
|
+
final_removed_snap_ids = []
|
|
741
|
+
if self.add_snaps and self.add_snaps != '':
|
|
742
|
+
add_snap_list = self.add_snaps.split(',')
|
|
743
|
+
for snap_id in add_snap_list:
|
|
744
|
+
snap_id = snap_id.strip()
|
|
745
|
+
if snap_id == '':
|
|
746
|
+
continue
|
|
747
|
+
# Copy existing snap if already present
|
|
748
|
+
if snap_id in current_snap_ids:
|
|
749
|
+
warning(
|
|
750
|
+
f"Snap {snap_id} already exists in the manifest. Skipping...")
|
|
751
|
+
continue
|
|
752
|
+
# Else add new snap from remote snaps
|
|
753
|
+
snap_sd = self._get_snap_sd(snap_id)
|
|
754
|
+
current_snaps.append(snap_sd)
|
|
755
|
+
current_snap_ids.append(snap_id)
|
|
756
|
+
final_added_snap_ids.append(snap_id)
|
|
757
|
+
info(f"Added snap {snap_id} to the manifest.")
|
|
758
|
+
if self.remove_snaps and self.remove_snaps != '':
|
|
759
|
+
remove_snap_list = self.remove_snaps.split(',')
|
|
760
|
+
for snap_id in remove_snap_list:
|
|
761
|
+
snap_id = snap_id.strip()
|
|
762
|
+
if snap_id == '':
|
|
763
|
+
continue
|
|
764
|
+
if snap_id not in current_snap_ids:
|
|
765
|
+
warning(
|
|
766
|
+
f"Snap {snap_id} does not exist in the manifest. Skipping...")
|
|
767
|
+
continue
|
|
768
|
+
# Remove snap from current snaps
|
|
769
|
+
index = current_snap_ids.index(snap_id)
|
|
770
|
+
current_snaps.pop(index)
|
|
771
|
+
current_snap_ids.pop(index)
|
|
772
|
+
final_removed_snap_ids.append(snap_id)
|
|
773
|
+
info(f"Removed snap {snap_id} from the manifest.")
|
|
774
|
+
|
|
775
|
+
found_auth = False
|
|
776
|
+
for final_snap in current_snap_ids:
|
|
777
|
+
if final_snap == SnapendManifest.AUTH_SNAP_ID:
|
|
778
|
+
found_auth = True
|
|
779
|
+
break
|
|
780
|
+
if not found_auth:
|
|
781
|
+
auth_sd = self._get_snap_sd(SnapendManifest.AUTH_SNAP_ID)
|
|
782
|
+
current_snaps.append(auth_sd)
|
|
783
|
+
current_snap_ids.append(SnapendManifest.AUTH_SNAP_ID)
|
|
784
|
+
final_added_snap_ids.append(SnapendManifest.AUTH_SNAP_ID)
|
|
785
|
+
warning(
|
|
786
|
+
'Auth snap is required for snapend. Added auth snap to the manifest.')
|
|
787
|
+
warning(
|
|
788
|
+
f'New snaps "{",".join(final_added_snap_ids)}" were added. ' +
|
|
789
|
+
f'Snaps "{",".join(final_removed_snap_ids)}" were removed. ')
|
|
790
|
+
current_snaps.sort(key=lambda x: x["id"])
|
|
791
|
+
self.manifest['service_definitions'] = current_snaps
|
|
792
|
+
|
|
793
|
+
current_features = self.manifest['feature_definitions']
|
|
794
|
+
final_added_features = []
|
|
795
|
+
final_removed_features = []
|
|
796
|
+
if self.add_features and self.add_features != '':
|
|
797
|
+
add_feature_list = self.add_features.split(',')
|
|
798
|
+
for feature in add_feature_list:
|
|
799
|
+
feature = feature.strip()
|
|
800
|
+
if feature == '':
|
|
801
|
+
continue
|
|
802
|
+
if feature.upper() in current_features:
|
|
803
|
+
warning(
|
|
804
|
+
f"Feature {feature} already exists in the manifest. Skipping...")
|
|
805
|
+
continue
|
|
806
|
+
current_features.append(feature.upper())
|
|
807
|
+
final_added_features.append(feature.upper())
|
|
808
|
+
info(f"Added feature {feature} to the manifest.")
|
|
809
|
+
if self.remove_features and self.remove_features != '':
|
|
810
|
+
remove_feature_list = self.remove_features.split(',')
|
|
811
|
+
for feature in remove_feature_list:
|
|
812
|
+
feature = feature.strip()
|
|
813
|
+
if feature == '':
|
|
814
|
+
continue
|
|
815
|
+
if feature.upper() not in current_features:
|
|
816
|
+
warning(
|
|
817
|
+
f"Feature {feature} does not exist in the manifest. Skipping...")
|
|
818
|
+
continue
|
|
819
|
+
index = current_features.index(feature.upper())
|
|
820
|
+
current_features.pop(index)
|
|
821
|
+
final_removed_features.append(feature.upper())
|
|
822
|
+
info(f"Removed feature {feature} from the manifest.")
|
|
823
|
+
warning(
|
|
824
|
+
f'New features "{",".join(final_added_features)}" were added. ' +
|
|
825
|
+
f'Features "{",".join(final_removed_features)}" were removed. ')
|
|
826
|
+
current_features.sort()
|
|
827
|
+
self.manifest['feature_definitions'] = current_features
|
|
828
|
+
|
|
829
|
+
# Write output
|
|
830
|
+
# Based on the out-path extension, write JSON or YAML
|
|
831
|
+
if self.out_path_filename.endswith('.yaml') or self.out_path_filename.endswith('.yml'):
|
|
832
|
+
try:
|
|
833
|
+
import yaml # type: ignore
|
|
834
|
+
except ImportError as e:
|
|
835
|
+
snapctl_error(
|
|
836
|
+
message="YAML output requested but PyYAML is not installed. "
|
|
837
|
+
"Install with: pip install pyyaml",
|
|
838
|
+
code=SNAPCTL_INPUT_ERROR,
|
|
839
|
+
progress=progress)
|
|
840
|
+
with open(self.out_path_filename, 'w') as out_file:
|
|
841
|
+
yaml.dump(self.manifest, out_file, sort_keys=False)
|
|
842
|
+
else:
|
|
843
|
+
with open(self.out_path_filename, 'w') as out_file:
|
|
844
|
+
out_file.write(json.dumps(self.manifest, indent=4))
|
|
845
|
+
info(f"Output written to {self.out_path_filename}")
|
|
846
|
+
snapctl_success(
|
|
847
|
+
message="Snapend manifest updated successfully.",
|
|
848
|
+
progress=progress)
|
|
849
|
+
except ValueError as e:
|
|
850
|
+
snapctl_error(
|
|
851
|
+
message=f"Exception: {e}",
|
|
852
|
+
code=SNAPCTL_INTERNAL_SERVER_ERROR, progress=progress)
|
|
853
|
+
except RequestException as e:
|
|
854
|
+
snapctl_error(
|
|
855
|
+
message=f"Exception: Unable to update snapend manifest {e}",
|
|
856
|
+
code=SNAPCTL_SNAPEND_MANIFEST_UPDATE_ERROR, progress=progress)
|
|
857
|
+
finally:
|
|
858
|
+
progress.stop()
|
|
859
|
+
snapctl_error(
|
|
860
|
+
message='Failed to update the snapend manifest.',
|
|
861
|
+
code=SNAPCTL_SNAPEND_MANIFEST_UPDATE_ERROR, progress=progress)
|
snapctl/config/constants.py
CHANGED
|
@@ -3,7 +3,7 @@ Constants used by snapctl
|
|
|
3
3
|
"""
|
|
4
4
|
COMPANY_NAME = 'Snapser'
|
|
5
5
|
VERSION_PREFIX = ''
|
|
6
|
-
VERSION = '1.1.
|
|
6
|
+
VERSION = '1.1.1'
|
|
7
7
|
CONFIG_FILE_MAC = '~/.snapser/config'
|
|
8
8
|
CONFIG_FILE_WIN = '%homepath%\\.snapser\\config'
|
|
9
9
|
|
|
@@ -53,8 +53,9 @@ SNAPCTL_SNAPS_ENUMERATE_ERROR = 14
|
|
|
53
53
|
|
|
54
54
|
# Snapend Manifest Errors - 16 - 19
|
|
55
55
|
SNAPCTL_SNAPEND_MANIFEST_CREATE_ERROR = 16
|
|
56
|
-
|
|
56
|
+
SNAPCTL_SNAPEND_MANIFEST_SYNC_ERROR = 17
|
|
57
57
|
SNAPCTL_SNAPEND_MANIFEST_UPGRADE_ERROR = 18
|
|
58
|
+
SNAPCTL_SNAPEND_MANIFEST_UPDATE_ERROR = 19
|
|
58
59
|
|
|
59
60
|
# BYOGS Errors - 20 - 29
|
|
60
61
|
SNAPCTL_BYOGS_GENERIC_ERROR = 20
|
snapctl/main.py
CHANGED
|
@@ -861,20 +861,40 @@ def snapend_manifest(
|
|
|
861
861
|
),
|
|
862
862
|
manifest_path_filename: Union[str, None] = typer.Option(
|
|
863
863
|
None, "--manifest-path-filename", help=(
|
|
864
|
-
"(req:
|
|
864
|
+
"(req: sync, upgrade) Full Path to the manifest file including the filename."
|
|
865
865
|
)
|
|
866
866
|
),
|
|
867
867
|
snaps_list_str: str = typer.Option(
|
|
868
868
|
None, "--snaps", help=(
|
|
869
|
-
"(use: create,
|
|
869
|
+
"(use: create, sync, upgrade) Comma separated list of snap ids to add, sync or upgrade. "
|
|
870
870
|
)
|
|
871
871
|
),
|
|
872
872
|
features: str = typer.Option(
|
|
873
873
|
None, "--features", help=(
|
|
874
|
-
"(use: create,
|
|
874
|
+
"(use: create, sync) Comma separated list of feature flags to add, sync. "
|
|
875
875
|
"Features: " + ", ".join(SnapendManifest.FEATURES)
|
|
876
876
|
)
|
|
877
877
|
),
|
|
878
|
+
add_snaps: str = typer.Option(
|
|
879
|
+
None, "--add-snaps", help=(
|
|
880
|
+
"(use: update) Comma separated list of snap ids to add. "
|
|
881
|
+
)
|
|
882
|
+
),
|
|
883
|
+
remove_snaps: str = typer.Option(
|
|
884
|
+
None, "--remove-snaps", help=(
|
|
885
|
+
"(use: update) Comma separated list of snap ids to remove. "
|
|
886
|
+
)
|
|
887
|
+
),
|
|
888
|
+
add_features: str = typer.Option(
|
|
889
|
+
None, "--add-features", help=(
|
|
890
|
+
"(use: update) Comma separated list of features to add. "
|
|
891
|
+
)
|
|
892
|
+
),
|
|
893
|
+
remove_features: str = typer.Option(
|
|
894
|
+
None, "--remove-features", help=(
|
|
895
|
+
"(use: update) Comma separated list of features to remove. "
|
|
896
|
+
)
|
|
897
|
+
),
|
|
878
898
|
out_path_filename: Union[str, None] = typer.Option(
|
|
879
899
|
None, "--out-path-filename", help=(
|
|
880
900
|
"(optional: enumerate) Path and filename to output the manifest. The filename should end with .json or .yaml"
|
|
@@ -901,6 +921,10 @@ def snapend_manifest(
|
|
|
901
921
|
manifest_path_filename=manifest_path_filename,
|
|
902
922
|
snaps=snaps_list_str,
|
|
903
923
|
features=features,
|
|
924
|
+
add_snaps=add_snaps,
|
|
925
|
+
remove_snaps=remove_snaps,
|
|
926
|
+
add_features=add_features,
|
|
927
|
+
remove_features=remove_features,
|
|
904
928
|
out_path_filename=out_path_filename,
|
|
905
929
|
)
|
|
906
930
|
getattr(snapend_manifest_obj, subcommand.replace('-', '_'))()
|
snapctl/utils/helper.py
CHANGED
|
@@ -3,6 +3,7 @@ Helper functions for snapctl
|
|
|
3
3
|
"""
|
|
4
4
|
from typing import Union, Dict
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from collections import Counter
|
|
6
7
|
import re
|
|
7
8
|
import platform
|
|
8
9
|
import os
|
|
@@ -204,3 +205,10 @@ def get_config_value(environment: str, key: str) -> str:
|
|
|
204
205
|
if environment == '' or environment not in APP_CONFIG or key not in APP_CONFIG[environment]:
|
|
205
206
|
return ''
|
|
206
207
|
return APP_CONFIG[environment][key]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def check_duplicates_in_list(items: list[str]) -> list[str]:
|
|
211
|
+
'''
|
|
212
|
+
Check for duplicates in a list and return the duplicate items
|
|
213
|
+
'''
|
|
214
|
+
return [k for k, v in Counter(items).items() if v > 1]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: snapctl
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: Snapser CLI Tool
|
|
5
5
|
Author: Ajinkya Apte
|
|
6
6
|
Author-email: aj@snapser.com
|
|
@@ -641,7 +641,9 @@ snapctl snapend-manifest --help
|
|
|
641
641
|
|
|
642
642
|
#### 2. Snapend Manifest Create
|
|
643
643
|
|
|
644
|
-
Create a Snapend manifest.
|
|
644
|
+
Create a Snapend manifest. It should be noted that the latest versions of the snap at the time of running the command is what gets added to the manifest. For example, say the `analytics` snap has versions `v1.0.0`, `v1.1.0` available on the web portal. If you run the create command with `--snaps analytics` the `v1.1.0` which is the latest at that moment in time, gets added to your manifest.
|
|
645
|
+
|
|
646
|
+
The output manifest file can then be used with the `snapend create` or `snapend clone` commands.
|
|
645
647
|
|
|
646
648
|
```bash
|
|
647
649
|
# Create a Snapend manifest file
|
|
@@ -654,15 +656,21 @@ Create a Snapend manifest. The output manifest file can then be used with the `s
|
|
|
654
656
|
# Note: One of snaps or features is required
|
|
655
657
|
# Example:
|
|
656
658
|
# snapend-manifest create --name my-dev-snapend --env DEVELOPMENT --snaps auth,analytics --add-features WEB_SOCKETS --out-path ./snapend-manifest.json
|
|
657
|
-
|
|
659
|
+
|
|
660
|
+
snapctl snapend-manifest create --name $name --env $env --snaps $snaps --features $features --out-path-filename $output_path_filename
|
|
658
661
|
```
|
|
659
662
|
|
|
660
|
-
#### 3. Snapend Manifest
|
|
663
|
+
#### 3. Snapend Manifest Sync
|
|
664
|
+
|
|
665
|
+
Sync with an existing Snapend manifest. This command is idempotent and destructive.
|
|
661
666
|
|
|
662
|
-
|
|
667
|
+
- It ensures the input manifest gets replaced with the values you pass in `--snaps` and `--features`. For example: If your input manifest has a snap but you do not pass the snap in the `--snaps`, it will be removed from the output. Same goes for `--features`.
|
|
668
|
+
- Additionally, if a snap is present in the manifest and you pass it in as part of `--snaps` it will not be touched. But if a snap is not part of the manifest and you pass it in as part of `--snaps` it will be added with the latest version of the snap. For example, say the `analytics` snap has versions `v1.0.0`, `v1.1.0` available on the web portal. If you run the sync command with `--snaps analytics` and you had `v1.0.0` in the manifest then it wont be touched. However, if you did not have it in the manifest then the `v1.1.0` which is the latest at that moment in time, gets added to your manifest.
|
|
669
|
+
|
|
670
|
+
**IMPORTANT**: If you are looking for a command to purely add or remove snaps or features, consider using the `update` command instead.
|
|
663
671
|
|
|
664
672
|
```bash
|
|
665
|
-
#
|
|
673
|
+
# Sync a Snapend manifest file
|
|
666
674
|
# $input_manifest = Path and file name of the current manifest. The filename should end with .json or .yaml
|
|
667
675
|
# $output_path_filename = Path and file name to store the manifest. The filename should end with .json or .yaml
|
|
668
676
|
# $snaps = Comma separated list of snap ids you want to have at the end. You can get the snap ids from # the `snapctl snaps enumerate --out-path ./snaps.json` command.
|
|
@@ -671,14 +679,14 @@ Update an existing Snapend manifest.
|
|
|
671
679
|
# IMPORTANT: If your manifest has a feature but your --features does not. It will be removed.
|
|
672
680
|
# Note: One of snaps, and features is required
|
|
673
681
|
# Example:
|
|
674
|
-
# snapctl snapend-manifest
|
|
682
|
+
# snapctl snapend-manifest sync --manifest-path-filename ./snapser-jn86b0dv-manifest.yaml --add-snaps game-server-fleets --remove-snaps analytics --remove-features WEB_SOCKETS --out-path ./snapend-updated-manifest.yaml
|
|
675
683
|
|
|
676
684
|
snapctl snapend-manifest update --manifest-path-filename $input_manifest --snaps $snaps --features $features--out-path-filename $output_path_filename
|
|
677
685
|
```
|
|
678
686
|
|
|
679
687
|
#### 4. Snapend Manifest Upgrade
|
|
680
688
|
|
|
681
|
-
Upgrade all snaps or a list of snaps to the latest version
|
|
689
|
+
Upgrade all snaps or a list of snaps to the latest version of the snap available at that moment in time. If you do not pass in `--snaps` then all the snaps in the manifest will be upgraded. If you do pass a list of snaps then all snap Ids are expected to be valid.
|
|
682
690
|
|
|
683
691
|
```bash
|
|
684
692
|
# Update a Snapend manifest file
|
|
@@ -691,9 +699,35 @@ Upgrade all snaps or a list of snaps to the latest version
|
|
|
691
699
|
# snapctl snapend-manifest upgrade --manifest-path-filename ./snapser-jn86b0dv-manifest.yaml --snaps game-server-fleets --out-path ./snapend-updated-manifest.yaml
|
|
692
700
|
# snapctl snapend-manifest upgrade --manifest-path-filename ./snapser-jn86b0dv-manifest.yaml --out-path ./snapend-updated-manifest.yaml
|
|
693
701
|
|
|
702
|
+
snapctl snapend-manifest upgrade --manifest-path-filename $input_manifest --out-path-filename $output_path_filename
|
|
703
|
+
|
|
694
704
|
snapctl snapend-manifest upgrade --manifest-path-filename $input_manifest --snaps $snaps --out-path-filename $output_path_filename
|
|
695
705
|
```
|
|
696
706
|
|
|
707
|
+
#### 5. Snapend Manifest Update
|
|
708
|
+
|
|
709
|
+
Update your manifest. This command is additive and subtractive. It allows you to add or remove, snaps and features from an existing manifest. Unlike `sync`, this will only add or remove entities from your manifest, keeping the remaining part of the manifest intact. If your manifest has a snap and you pass it with `--add-snaps` then it will be ignored. However if you do not have a snap and you pass it with `--add-snaps` then the latest version of the snap will be added. If you pass a snap with `--remove-snaps` that is already not in the manifest, then it will be skipped. This ensures idempotency after the initial update is made to the snapend manifest.
|
|
710
|
+
|
|
711
|
+
**IMPORTANT**:
|
|
712
|
+
- All additions are performed before removals.
|
|
713
|
+
- If you are looking to have strict relation between your input (snaps + features) and your output manifest, consider using the `sync` command.
|
|
714
|
+
|
|
715
|
+
```bash
|
|
716
|
+
# Update a Snapend manifest file
|
|
717
|
+
# $input_manifest = Path and file name of the current manifest. The filename should end with .json or .yaml
|
|
718
|
+
# $output_path_filename = Path and file name to store the manifest. The filename should end with .json or .yaml
|
|
719
|
+
# $addSnaps = Comma separated list of snap ids you want to add to your manifest. You can get the snap ids from # the `snapctl snaps enumerate --out-path ./snaps.json` command.
|
|
720
|
+
# $removeSnaps = Comma separated list of snap ids you want to remove from your manifest. You can get the snap ids from # the `snapctl snaps enumerate --out-path ./snaps.json` command.
|
|
721
|
+
# $addFeatures = Pass `WEB_SOCKETS` if you want to enable web sockets for your backend.
|
|
722
|
+
# $removeFeatures = Pass `WEB_SOCKETS` if you want to disable web sockets for your backend.
|
|
723
|
+
# Note: One of add-snaps, remove-snaps, add-features or remove-features is required
|
|
724
|
+
# Example:
|
|
725
|
+
# snapctl snapend-manifest update --manifest-path-filename ./snapser-jn86b0dv-manifest.yaml --add-snaps game-server-fleets --remove-snaps analytics --remove-features WEB_SOCKETS --out-path ./snapend-updated-manifest.yaml
|
|
726
|
+
|
|
727
|
+
snapctl snapend-manifest update --manifest-path-filename $input_manifest --add-snaps $addSnaps --remove-snaps $removeSnaps --add-features $addFeatures --remove-features $removeFeatures --out-path-filename $output_path_filename
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
|
|
697
731
|
### 7. Snapend
|
|
698
732
|
Snapctl commands for your snapend
|
|
699
733
|
|
|
@@ -9,11 +9,11 @@ snapctl/commands/game.py,sha256=F6TL5T3i8yZAQxfsx0uma2tbLHCQ_gqA1wj6oxkAgGk,5236
|
|
|
9
9
|
snapctl/commands/generate.py,sha256=9-NlZVQllBT2LZT_t9S3ztwtHzTbM-C8_x0f6z70U3g,5606
|
|
10
10
|
snapctl/commands/release_notes.py,sha256=EMl-NK9-MSdRxiVyA0MLX4CBG0zijOctddEODQa5PZ4,2151
|
|
11
11
|
snapctl/commands/snapend.py,sha256=DuzqpVRiQzTI1LAJICDRAjoFNKhyhbMkfaBsmsjuxO4,50307
|
|
12
|
-
snapctl/commands/snapend_manifest.py,sha256=
|
|
12
|
+
snapctl/commands/snapend_manifest.py,sha256=F4Ql-jkfPvkTrrQ5RfTXp8Jk5s4EFSkWtoOvzxdcacQ,43255
|
|
13
13
|
snapctl/commands/snaps.py,sha256=VI7B1FtrYAyJTxtQcOU6BgImwRND0ZXJGTWSpCXKzW0,4103
|
|
14
14
|
snapctl/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
snapctl/config/app.py,sha256=U9Mm0BbGJoqcmBBam2tN7F-oTf_u9dK6EJsiB-yVvKg,888
|
|
16
|
-
snapctl/config/constants.py,sha256=
|
|
16
|
+
snapctl/config/constants.py,sha256=S0YABPFZfRF_NTrpZpfs6bnybhJrPPzLkXYkriJYJt8,4373
|
|
17
17
|
snapctl/config/endpoints.py,sha256=jD0n5ocJBbIkrb97F2_r9hqAHzUuddAqzqqBAPUKDTI,477
|
|
18
18
|
snapctl/config/hashes.py,sha256=3OKAyOxQPnn--_hvPIzFJnhC8NVfQK4WT-RH4PHEV1w,5242
|
|
19
19
|
snapctl/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -26,6 +26,7 @@ snapctl/data/releases/1.0.2.mdx,sha256=BptVj9boWRf_V22O0V4EzkGFPFWK6XzRQUQlmTFTZ
|
|
|
26
26
|
snapctl/data/releases/1.0.3.mdx,sha256=Ifm6kRQQghCWx_OJ3shNOxozUP3hH_yt8dMap7B-1tw,149
|
|
27
27
|
snapctl/data/releases/1.0.4.mdx,sha256=hKwi0tormf0gvKAY5W4G1BY7L6fgwOzlw3R-WGSH49g,243
|
|
28
28
|
snapctl/data/releases/1.1.0.mdx,sha256=w_X9SsMH-ghex8UYQn9b1AcQT9i3eeAlQWP2YCVU_kY,1303
|
|
29
|
+
snapctl/data/releases/1.1.1.mdx,sha256=J9PMNlO9EtbIH29Elfd8vsj9xwm-hYX8njFrlJy2Su0,244
|
|
29
30
|
snapctl/data/releases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
31
|
snapctl/data/releases/beta-0.46.0.mdx,sha256=_MJA7TnnJjAnNm_EOvoBiz7FjHwl4c49sYtZ9r4KZQE,2386
|
|
31
32
|
snapctl/data/releases/beta-0.46.4.mdx,sha256=3-ojdCyvax27sdd8nKmcP0zfCWEzi_edPbSlkFqla4o,173
|
|
@@ -40,16 +41,16 @@ snapctl/data/releases/beta-0.49.3.mdx,sha256=XmSfpiH-LqvKS2REJ5FGDcLgyEN-OcSzwrX
|
|
|
40
41
|
snapctl/data/releases/beta-0.50.0.mdx,sha256=_w9f1HjHqukQ8IaTfUdk2W3gBcSwjMyMA8-rjuUxYTo,399
|
|
41
42
|
snapctl/data/releases/beta-0.51.0.mdx,sha256=5_xY29NJtH3Qa92UycCudrwDkSlUHRVNnP4GE4hF7-Y,93
|
|
42
43
|
snapctl/data/releases/beta-0.53.1.mdx,sha256=b__2LPkDhU3cTw5UC19Hxv1rDz6BsSLeI6fhHjOCP08,149
|
|
43
|
-
snapctl/main.py,sha256=
|
|
44
|
+
snapctl/main.py,sha256=ZTHmYAW_np3ojTGO7l6eBu2Anbm84uWt9ry0HGQ8K4M,32478
|
|
44
45
|
snapctl/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
46
|
snapctl/types/definitions.py,sha256=EQzLeiXkJ8ISRlCqHMviNVsWWpmhWjpKaOBLdlvOTmY,644
|
|
46
47
|
snapctl/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
48
|
snapctl/utils/echo.py,sha256=9fxrPW9kNJwiJvJBFy9RlAP4qGRcPTOHfQb3pQh3CMg,1446
|
|
48
49
|
snapctl/utils/exceptions.py,sha256=deLs6sOKIUrhjKNgiMpNC1S6lkU0rpZ7Ml4Tx1CN_Ss,155
|
|
49
|
-
snapctl/utils/helper.py,sha256=
|
|
50
|
+
snapctl/utils/helper.py,sha256=8PwlN8xcx4ivHhEudt-PwAl1IL4h1vR0ah7qPEdzWhU,7424
|
|
50
51
|
snapctl/utils/telemetry.py,sha256=_VntKXUrKgJoLKCskH0Z5VhthiVo8CP572U0mcZIH4k,5028
|
|
51
|
-
snapctl-1.1.
|
|
52
|
-
snapctl-1.1.
|
|
53
|
-
snapctl-1.1.
|
|
54
|
-
snapctl-1.1.
|
|
55
|
-
snapctl-1.1.
|
|
52
|
+
snapctl-1.1.1.dist-info/LICENSE,sha256=6AcXm54KFSpmUI1ji9NIBd4Xl-DtjTqiyjBzfVb_CEk,2804
|
|
53
|
+
snapctl-1.1.1.dist-info/METADATA,sha256=9OSkp-ad-_KGShm8yjy71SoYy4h0WXScxiAocnvUGag,46268
|
|
54
|
+
snapctl-1.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
55
|
+
snapctl-1.1.1.dist-info/entry_points.txt,sha256=tkKW9MzmFdRs6Bgkv29G78i9WEBK4WIOWunPfe3t2Wg,44
|
|
56
|
+
snapctl-1.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|