fb-vmware 1.7.1__py3-none-any.whl → 1.8.0__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.
- fb_vmware/__init__.py +1 -1
- fb_vmware/app/__init__.py +284 -5
- fb_vmware/app/get_host_list.py +110 -93
- fb_vmware/app/get_network_list.py +176 -218
- fb_vmware/app/get_storage_cluster_info.py +303 -0
- fb_vmware/app/get_storage_cluster_list.py +100 -107
- fb_vmware/app/get_storage_list.py +145 -112
- fb_vmware/app/get_vm_info.py +79 -17
- fb_vmware/app/get_vm_list.py +167 -93
- fb_vmware/app/search_storage.py +470 -0
- fb_vmware/argparse_actions.py +75 -0
- fb_vmware/base.py +28 -1
- fb_vmware/cluster.py +33 -4
- fb_vmware/connect.py +434 -17
- fb_vmware/datastore.py +195 -6
- fb_vmware/dc.py +19 -1
- fb_vmware/ds_cluster.py +215 -2
- fb_vmware/dvs.py +37 -1
- fb_vmware/errors.py +31 -10
- fb_vmware/host.py +39 -1
- fb_vmware/network.py +17 -1
- fb_vmware/obj.py +30 -1
- fb_vmware/vm.py +19 -1
- fb_vmware/xlate.py +8 -13
- fb_vmware-1.8.0.data/data/share/locale/de/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.8.0.data/data/share/locale/en/LC_MESSAGES/fb_vmware.mo +0 -0
- {fb_vmware-1.7.1.dist-info → fb_vmware-1.8.0.dist-info}/METADATA +2 -1
- fb_vmware-1.8.0.dist-info/RECORD +39 -0
- {fb_vmware-1.7.1.dist-info → fb_vmware-1.8.0.dist-info}/entry_points.txt +2 -0
- fb_vmware-1.7.1.data/data/share/locale/de_DE/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.7.1.data/data/share/locale/en_US/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.7.1.dist-info/RECORD +0 -36
- {fb_vmware-1.7.1.dist-info → fb_vmware-1.8.0.dist-info}/WHEEL +0 -0
- {fb_vmware-1.7.1.dist-info → fb_vmware-1.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -20,6 +20,10 @@ from operator import itemgetter
|
|
|
20
20
|
from fb_tools.common import pp
|
|
21
21
|
from fb_tools.spinner import Spinner
|
|
22
22
|
|
|
23
|
+
from rich import box
|
|
24
|
+
from rich.table import Table
|
|
25
|
+
from rich.text import Text
|
|
26
|
+
|
|
23
27
|
# Own modules
|
|
24
28
|
from . import BaseVmwareApplication, VmwareAppError
|
|
25
29
|
from .. import __version__ as GLOBAL_VERSION
|
|
@@ -28,7 +32,7 @@ from ..network import GeneralNetworksDict
|
|
|
28
32
|
from ..network import VsphereNetwork
|
|
29
33
|
from ..xlate import XLATOR
|
|
30
34
|
|
|
31
|
-
__version__ = "1.
|
|
35
|
+
__version__ = "1.8.3"
|
|
32
36
|
LOG = logging.getLogger(__name__)
|
|
33
37
|
|
|
34
38
|
_ = XLATOR.gettext
|
|
@@ -201,9 +205,14 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
201
205
|
all_dvs = []
|
|
202
206
|
|
|
203
207
|
print()
|
|
208
|
+
show_header = True
|
|
204
209
|
title = _("Distributed Virtual Switches")
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
title += "\n" + ("=" * len(title))
|
|
211
|
+
box_style = box.ROUNDED
|
|
212
|
+
if self.quiet:
|
|
213
|
+
show_header = False
|
|
214
|
+
title = None
|
|
215
|
+
box_style = None
|
|
207
216
|
|
|
208
217
|
# -----------------------------
|
|
209
218
|
def get_contact(dvs):
|
|
@@ -247,96 +256,123 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
247
256
|
}
|
|
248
257
|
all_dvs.append(dvs)
|
|
249
258
|
|
|
250
|
-
if len(all_dvs):
|
|
251
|
-
|
|
259
|
+
if not len(all_dvs):
|
|
260
|
+
c_title = Text(title, style="bold cyan")
|
|
261
|
+
self.rich_console.print(c_title)
|
|
262
|
+
print()
|
|
263
|
+
print(_("No Distributed Virtual Switches found."))
|
|
252
264
|
return
|
|
253
265
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
labels = {
|
|
261
|
-
"vsphere": "vSphere",
|
|
262
|
-
"dc": _("Data Center"),
|
|
263
|
-
"name": _("Name"),
|
|
264
|
-
"contact": _("Contact"),
|
|
265
|
-
"create_time": _("Creation time"),
|
|
266
|
-
"description": _("Description"),
|
|
267
|
-
"hosts": _("Hosts"),
|
|
268
|
-
"ports": _("Ports"),
|
|
269
|
-
"standalone_ports": _("Standalone Ports"),
|
|
270
|
-
"ratio_reservation": _("Ratio reservation"),
|
|
271
|
-
}
|
|
272
|
-
label_list = (
|
|
273
|
-
"name",
|
|
274
|
-
"vsphere",
|
|
275
|
-
"dc",
|
|
276
|
-
"create_time",
|
|
277
|
-
"hosts",
|
|
278
|
-
"ports",
|
|
279
|
-
"standalone_ports",
|
|
280
|
-
"ratio_reservation",
|
|
281
|
-
"contact",
|
|
282
|
-
"description",
|
|
266
|
+
table = Table(
|
|
267
|
+
title=title,
|
|
268
|
+
title_style="bold cyan",
|
|
269
|
+
box=box_style,
|
|
270
|
+
show_header=show_header,
|
|
271
|
+
show_footer=False,
|
|
283
272
|
)
|
|
284
273
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
274
|
+
table.add_column(header=_("Name"))
|
|
275
|
+
table.add_column(header=_("vSphere"))
|
|
276
|
+
table.add_column(header=_("Data Center"))
|
|
277
|
+
table.add_column(header=_("Creation time"))
|
|
278
|
+
table.add_column(header=_("Hosts"), justify="right")
|
|
279
|
+
table.add_column(header=_("Ports"), justify="right")
|
|
280
|
+
table.add_column(header=_("Standalone Ports"), justify="right")
|
|
281
|
+
table.add_column(header=_("Ratio reservation"), justify="right")
|
|
282
|
+
table.add_column(header=_("Contact"))
|
|
283
|
+
table.add_column(header=_("Description"))
|
|
284
|
+
|
|
285
|
+
sort_keys = ["vsphere", "name"]
|
|
286
|
+
all_dvs.sort(key=itemgetter(*sort_keys))
|
|
288
287
|
|
|
289
|
-
max_len = 0
|
|
290
|
-
count = 0
|
|
291
288
|
for dvs in all_dvs:
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if self.verbose > 1:
|
|
306
|
-
LOG.debug("Label length:\n" + pp(str_lengths))
|
|
307
|
-
LOG.debug("Max line length: {} chars".format(max_len))
|
|
308
|
-
|
|
309
|
-
tpl = ""
|
|
310
|
-
for label in label_list:
|
|
311
|
-
if tpl != "":
|
|
312
|
-
tpl += " "
|
|
313
|
-
if label in ("hosts", "ports", "standalone_ports", "ratio_reservation"):
|
|
314
|
-
tpl += "{{{la}:>{le}}}".format(la=label, le=str_lengths[label])
|
|
315
|
-
else:
|
|
316
|
-
tpl += "{{{la}:<{le}}}".format(la=label, le=str_lengths[label])
|
|
317
|
-
if self.verbose > 1:
|
|
318
|
-
LOG.debug(_("Line template: {}").format(tpl))
|
|
289
|
+
table.add_row(
|
|
290
|
+
dvs["name"],
|
|
291
|
+
dvs["vsphere"],
|
|
292
|
+
dvs["dc"],
|
|
293
|
+
dvs["create_time"],
|
|
294
|
+
dvs["hosts"],
|
|
295
|
+
dvs["ports"],
|
|
296
|
+
dvs["standalone_ports"],
|
|
297
|
+
dvs["ratio_reservation"],
|
|
298
|
+
dvs["description"],
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
self.rich_console.print(table)
|
|
319
302
|
|
|
320
303
|
if not self.quiet:
|
|
321
304
|
print()
|
|
322
|
-
print(tpl.format(**labels))
|
|
323
|
-
print("-" * max_len)
|
|
324
|
-
|
|
325
|
-
sort_keys = ["vsphere", "name"]
|
|
326
|
-
all_dvs.sort(key=itemgetter(*sort_keys))
|
|
327
|
-
for dvs in all_dvs:
|
|
328
|
-
count += 1
|
|
329
|
-
print(tpl.format(**dvs))
|
|
330
305
|
|
|
331
306
|
# -------------------------------------------------------------------------
|
|
332
307
|
def print_dv_portgroups(self):
|
|
333
308
|
"""Print on STDOUT all information about Distributed Virtual Port Groups."""
|
|
334
|
-
all_dvpgs = []
|
|
335
|
-
|
|
336
309
|
print()
|
|
310
|
+
|
|
311
|
+
show_header = True
|
|
337
312
|
title = _("Distributed Virtual Port Groups")
|
|
338
|
-
|
|
339
|
-
|
|
313
|
+
title += "\n" + ("=" * len(title))
|
|
314
|
+
box_style = box.ROUNDED
|
|
315
|
+
if self.quiet:
|
|
316
|
+
show_header = False
|
|
317
|
+
title = None
|
|
318
|
+
box_style = None
|
|
319
|
+
|
|
320
|
+
all_dvpgs = self._perform_dv_portgroups()
|
|
321
|
+
|
|
322
|
+
sort_keys = ["vsphere", "name"]
|
|
323
|
+
all_dvpgs.sort(key=itemgetter(*sort_keys))
|
|
324
|
+
|
|
325
|
+
if not len(all_dvpgs):
|
|
326
|
+
c_title = Text(title, style="bold cyan")
|
|
327
|
+
self.rich_console.print(c_title)
|
|
328
|
+
print()
|
|
329
|
+
print(_("No Distributed Virtual Port Groups found."))
|
|
330
|
+
return
|
|
331
|
+
|
|
332
|
+
table = Table(
|
|
333
|
+
title=title,
|
|
334
|
+
title_style="bold cyan",
|
|
335
|
+
box=box_style,
|
|
336
|
+
show_header=show_header,
|
|
337
|
+
show_footer=False,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
table.add_column(header=_("Name"))
|
|
341
|
+
table.add_column(header=_("vSphere"))
|
|
342
|
+
table.add_column(header=_("Data Center"))
|
|
343
|
+
table.add_column(header="DV Switch")
|
|
344
|
+
table.add_column(header="VLAN ID", justify="right")
|
|
345
|
+
table.add_column(header=_("Network"))
|
|
346
|
+
table.add_column(header=_("Accessible"), justify="center")
|
|
347
|
+
table.add_column(header=_("Type"))
|
|
348
|
+
table.add_column(header=_("Ports"), justify="right")
|
|
349
|
+
table.add_column(header=_("Uplink"), justify="center")
|
|
350
|
+
table.add_column(header=_("Description"))
|
|
351
|
+
|
|
352
|
+
for dvpg in all_dvpgs:
|
|
353
|
+
table.add_row(
|
|
354
|
+
dvpg["name"],
|
|
355
|
+
dvpg["vsphere"],
|
|
356
|
+
dvpg["dc"],
|
|
357
|
+
dvpg["dvs"],
|
|
358
|
+
dvpg["vlan_id"],
|
|
359
|
+
dvpg["network"],
|
|
360
|
+
dvpg["accessible"],
|
|
361
|
+
dvpg["type"],
|
|
362
|
+
dvpg["num_ports"],
|
|
363
|
+
dvpg["uplink"],
|
|
364
|
+
dvpg["description"],
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
self.rich_console.print(table)
|
|
368
|
+
|
|
369
|
+
if not self.quiet:
|
|
370
|
+
print()
|
|
371
|
+
|
|
372
|
+
# -------------------------------------------------------------------------
|
|
373
|
+
def _perform_dv_portgroups(self):
|
|
374
|
+
|
|
375
|
+
all_dvpgs = []
|
|
340
376
|
|
|
341
377
|
for vsphere_name in self.vsphere:
|
|
342
378
|
for name in self.vsphere[vsphere_name].dv_portgroups.keys():
|
|
@@ -351,9 +387,12 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
351
387
|
uplink = _("No")
|
|
352
388
|
if this_dvpg.uplink:
|
|
353
389
|
uplink = _("Yes")
|
|
390
|
+
|
|
354
391
|
accessible = "No"
|
|
355
392
|
if this_dvpg.accessible:
|
|
356
|
-
accessible = _("Yes")
|
|
393
|
+
accessible = Text(_("Yes"), style="bold green")
|
|
394
|
+
else:
|
|
395
|
+
accessible = Text(_("No"), style="bold red")
|
|
357
396
|
|
|
358
397
|
dc_name = "~"
|
|
359
398
|
if this_dvpg.dc_name:
|
|
@@ -378,96 +417,66 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
378
417
|
}
|
|
379
418
|
all_dvpgs.append(dvpg)
|
|
380
419
|
|
|
381
|
-
|
|
382
|
-
self._print_dv_portgroups(all_dvpgs)
|
|
383
|
-
return
|
|
420
|
+
return all_dvpgs
|
|
384
421
|
|
|
422
|
+
# -------------------------------------------------------------------------
|
|
423
|
+
def print_networks(self):
|
|
424
|
+
"""Print on STDOUT all information about Virtual Networks."""
|
|
385
425
|
print()
|
|
386
|
-
print(_("No Distributed Virtual Port Groups found."))
|
|
387
426
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
"
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
"description",
|
|
427
|
+
show_header = True
|
|
428
|
+
title = _("Virtual Networks")
|
|
429
|
+
title += "\n" + ("=" * len(title))
|
|
430
|
+
box_style = box.ROUNDED
|
|
431
|
+
if self.quiet:
|
|
432
|
+
show_header = False
|
|
433
|
+
title = None
|
|
434
|
+
box_style = None
|
|
435
|
+
|
|
436
|
+
all_networks = self._perform_networks()
|
|
437
|
+
|
|
438
|
+
if not len(all_networks):
|
|
439
|
+
c_title = Text(title, style="bold cyan")
|
|
440
|
+
self.rich_console.print(c_title)
|
|
441
|
+
print()
|
|
442
|
+
print(_("No Virtual Networks found."))
|
|
443
|
+
return
|
|
444
|
+
|
|
445
|
+
sort_keys = ["vsphere", "name"]
|
|
446
|
+
all_networks.sort(key=itemgetter(*sort_keys))
|
|
447
|
+
|
|
448
|
+
table = Table(
|
|
449
|
+
title=title,
|
|
450
|
+
title_style="bold cyan",
|
|
451
|
+
box=box_style,
|
|
452
|
+
show_header=show_header,
|
|
453
|
+
show_footer=False,
|
|
416
454
|
)
|
|
417
455
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
456
|
+
table.add_column(header=_("Name"))
|
|
457
|
+
table.add_column(header=_("vSphere"))
|
|
458
|
+
table.add_column(header=_("Data Center"))
|
|
459
|
+
table.add_column(header=_("Network"))
|
|
460
|
+
table.add_column(header=_("Accessible"), justify="center")
|
|
421
461
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
for label in labels.keys():
|
|
434
|
-
if max_len:
|
|
435
|
-
max_len += 2
|
|
436
|
-
max_len += str_lengths[label]
|
|
437
|
-
|
|
438
|
-
if self.verbose > 1:
|
|
439
|
-
LOG.debug("Label length:\n" + pp(str_lengths))
|
|
440
|
-
LOG.debug("Max line length: {} chars".format(max_len))
|
|
441
|
-
|
|
442
|
-
tpl = ""
|
|
443
|
-
for label in label_list:
|
|
444
|
-
if tpl != "":
|
|
445
|
-
tpl += " "
|
|
446
|
-
if label in ("num_ports", "vlan_id"):
|
|
447
|
-
tpl += "{{{la}:>{le}}}".format(la=label, le=str_lengths[label])
|
|
448
|
-
else:
|
|
449
|
-
tpl += "{{{la}:<{le}}}".format(la=label, le=str_lengths[label])
|
|
450
|
-
if self.verbose > 1:
|
|
451
|
-
LOG.debug(_("Line template: {}").format(tpl))
|
|
462
|
+
for network in all_networks:
|
|
463
|
+
table.add_row(
|
|
464
|
+
network["name"],
|
|
465
|
+
network["vsphere"],
|
|
466
|
+
network["dc"],
|
|
467
|
+
network["network"],
|
|
468
|
+
network["accessible"],
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
self.rich_console.print(table)
|
|
452
472
|
|
|
453
473
|
if not self.quiet:
|
|
454
474
|
print()
|
|
455
|
-
print(tpl.format(**labels))
|
|
456
|
-
print("-" * max_len)
|
|
457
|
-
|
|
458
|
-
for dvpg in all_dvpgs:
|
|
459
|
-
count += 1
|
|
460
|
-
print(tpl.format(**dvpg))
|
|
461
475
|
|
|
462
476
|
# -------------------------------------------------------------------------
|
|
463
|
-
def
|
|
464
|
-
"""Print on STDOUT all information about Virtual Networks."""
|
|
465
|
-
all_networks = []
|
|
477
|
+
def _perform_networks(self):
|
|
466
478
|
|
|
467
|
-
|
|
468
|
-
title = _("Virtual Networks")
|
|
469
|
-
print(self.colored(title, "cyan"))
|
|
470
|
-
print(self.colored("=" * len(title), "cyan"))
|
|
479
|
+
all_networks = []
|
|
471
480
|
|
|
472
481
|
for vsphere_name in self.vsphere:
|
|
473
482
|
for name in self.vsphere[vsphere_name].networks.keys():
|
|
@@ -475,9 +484,12 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
475
484
|
network = "~"
|
|
476
485
|
if this_network.network:
|
|
477
486
|
network = str(this_network.network)
|
|
487
|
+
|
|
478
488
|
accessible = "No"
|
|
479
489
|
if this_network.accessible:
|
|
480
|
-
accessible = _("Yes")
|
|
490
|
+
accessible = Text(_("Yes"), style="bold green")
|
|
491
|
+
else:
|
|
492
|
+
accessible = Text(_("No"), style="bold red")
|
|
481
493
|
|
|
482
494
|
dc_name = "~"
|
|
483
495
|
if this_network.dc_name:
|
|
@@ -492,65 +504,7 @@ class GetNetworkListApp(BaseVmwareApplication):
|
|
|
492
504
|
}
|
|
493
505
|
all_networks.append(net)
|
|
494
506
|
|
|
495
|
-
|
|
496
|
-
self._print_networks(all_networks)
|
|
497
|
-
return
|
|
498
|
-
|
|
499
|
-
print()
|
|
500
|
-
print(_("No Virtual Networks found."))
|
|
501
|
-
|
|
502
|
-
# -------------------------------------------------------------------------
|
|
503
|
-
def _print_networks(self, all_networks):
|
|
504
|
-
|
|
505
|
-
labels = {
|
|
506
|
-
"vsphere": "vSphere",
|
|
507
|
-
"dc": _("Data Center"),
|
|
508
|
-
"name": _("Name"),
|
|
509
|
-
"network": _("Network"),
|
|
510
|
-
"accessible": _("Accessible"),
|
|
511
|
-
}
|
|
512
|
-
label_list = ("name", "vsphere", "dc", "network", "accessible")
|
|
513
|
-
|
|
514
|
-
str_lengths = {}
|
|
515
|
-
for label in labels:
|
|
516
|
-
str_lengths[label] = len(labels[label])
|
|
517
|
-
|
|
518
|
-
max_len = 0
|
|
519
|
-
count = 0
|
|
520
|
-
for net in all_networks:
|
|
521
|
-
for label in labels.keys():
|
|
522
|
-
val = net[label]
|
|
523
|
-
if val is None:
|
|
524
|
-
val = "-"
|
|
525
|
-
net[label] = val
|
|
526
|
-
if len(val) > str_lengths[label]:
|
|
527
|
-
str_lengths[label] = len(val)
|
|
528
|
-
|
|
529
|
-
for label in labels.keys():
|
|
530
|
-
if max_len:
|
|
531
|
-
max_len += 2
|
|
532
|
-
max_len += str_lengths[label]
|
|
533
|
-
|
|
534
|
-
if self.verbose > 1:
|
|
535
|
-
LOG.debug("Label length:\n" + pp(str_lengths))
|
|
536
|
-
LOG.debug("Max line length: {} chars".format(max_len))
|
|
537
|
-
|
|
538
|
-
tpl = ""
|
|
539
|
-
for label in label_list:
|
|
540
|
-
if tpl != "":
|
|
541
|
-
tpl += " "
|
|
542
|
-
tpl += "{{{la}:<{le}}}".format(la=label, le=str_lengths[label])
|
|
543
|
-
if self.verbose > 1:
|
|
544
|
-
LOG.debug(_("Line template: {}").format(tpl))
|
|
545
|
-
|
|
546
|
-
if not self.quiet:
|
|
547
|
-
print()
|
|
548
|
-
print(tpl.format(**labels))
|
|
549
|
-
print("-" * max_len)
|
|
550
|
-
|
|
551
|
-
for net in all_networks:
|
|
552
|
-
count += 1
|
|
553
|
-
print(tpl.format(**net))
|
|
507
|
+
return all_networks
|
|
554
508
|
|
|
555
509
|
|
|
556
510
|
# =============================================================================
|
|
@@ -567,7 +521,11 @@ def main():
|
|
|
567
521
|
if app.verbose > 2:
|
|
568
522
|
print(_("{c}-Object:\n{a}").format(c=app.__class__.__name__, a=app), file=sys.stderr)
|
|
569
523
|
|
|
570
|
-
|
|
524
|
+
try:
|
|
525
|
+
app()
|
|
526
|
+
except KeyboardInterrupt:
|
|
527
|
+
print("\n" + app.colored(_("User interrupt."), "YELLOW"))
|
|
528
|
+
sys.exit(5)
|
|
571
529
|
|
|
572
530
|
sys.exit(0)
|
|
573
531
|
|