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
fb_vmware/__init__.py
CHANGED
fb_vmware/app/__init__.py
CHANGED
|
@@ -25,10 +25,14 @@ from fb_tools.multi_config import DEFAULT_ENCODING
|
|
|
25
25
|
|
|
26
26
|
import pytz
|
|
27
27
|
|
|
28
|
+
from rich.console import Console
|
|
29
|
+
from rich.prompt import InvalidResponse, Prompt, PromptBase, PromptType
|
|
30
|
+
|
|
28
31
|
# Own modules
|
|
29
32
|
from .. import __version__ as GLOBAL_VERSION
|
|
30
33
|
from ..config import VmwareConfiguration
|
|
31
34
|
from ..connect import VsphereConnection
|
|
35
|
+
from ..ds_cluster import VsphereDsCluster
|
|
32
36
|
from ..errors import VSphereExpectedError
|
|
33
37
|
from ..xlate import DOMAIN
|
|
34
38
|
from ..xlate import LOCALE_DIR
|
|
@@ -38,13 +42,18 @@ from ..xlate import __lib_dir__ as __xlate_lib_dir__
|
|
|
38
42
|
from ..xlate import __mo_file__ as __xlate_mo_file__
|
|
39
43
|
from ..xlate import __module_dir__ as __xlate_module_dir__
|
|
40
44
|
|
|
41
|
-
__version__ = "1.
|
|
45
|
+
__version__ = "1.7.2"
|
|
42
46
|
LOG = logging.getLogger(__name__)
|
|
43
47
|
TZ = pytz.timezone("Europe/Berlin")
|
|
44
48
|
|
|
45
49
|
_ = XLATOR.gettext
|
|
46
50
|
ngettext = XLATOR.ngettext
|
|
47
51
|
|
|
52
|
+
Prompt.validate_error_message = "[prompt.invalid]" + _("Please enter a valid value")
|
|
53
|
+
Prompt.illegal_choice_message = "[prompt.invalid.choice]" + _(
|
|
54
|
+
"Please select one of the available options"
|
|
55
|
+
)
|
|
56
|
+
|
|
48
57
|
|
|
49
58
|
# =============================================================================
|
|
50
59
|
class VmwareAppError(FbAppError):
|
|
@@ -53,10 +62,56 @@ class VmwareAppError(FbAppError):
|
|
|
53
62
|
pass
|
|
54
63
|
|
|
55
64
|
|
|
65
|
+
# =============================================================================
|
|
66
|
+
class PositiveIntPrompt(PromptBase[int]):
|
|
67
|
+
"""A prompt that returns an positive integer greater than zero.
|
|
68
|
+
|
|
69
|
+
Example:
|
|
70
|
+
>>> burrito_count = PositiveIntPrompt.ask("How many burritos do you want to order")
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
response_type = int
|
|
75
|
+
validate_error_message = "[prompt.invalid]" + _(
|
|
76
|
+
"Please enter a valid positive integer number greater than zero."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# -------------------------------------------------------------------------
|
|
80
|
+
def process_response(self, value: str) -> PromptType:
|
|
81
|
+
"""Process response from user, convert to prompt type.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
value (str): String typed by user.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
InvalidResponse: If ``value`` is invalid.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
PromptType: The value to be returned from ask method.
|
|
91
|
+
"""
|
|
92
|
+
value = value.strip()
|
|
93
|
+
try:
|
|
94
|
+
return_value: PromptType = self.response_type(value)
|
|
95
|
+
if return_value <= 0:
|
|
96
|
+
raise InvalidResponse(self.validate_error_message)
|
|
97
|
+
except ValueError:
|
|
98
|
+
raise InvalidResponse(self.validate_error_message)
|
|
99
|
+
|
|
100
|
+
return return_value
|
|
101
|
+
|
|
102
|
+
|
|
56
103
|
# =============================================================================
|
|
57
104
|
class BaseVmwareApplication(FbConfigApplication):
|
|
58
105
|
"""Base class for all VMware/vSphere application classes."""
|
|
59
106
|
|
|
107
|
+
term_colors = {
|
|
108
|
+
"kitty": "256",
|
|
109
|
+
"256color": "256",
|
|
110
|
+
"16color": "standard",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
default_all_vspheres = True
|
|
114
|
+
|
|
60
115
|
# -------------------------------------------------------------------------
|
|
61
116
|
def __init__(
|
|
62
117
|
self,
|
|
@@ -81,6 +136,7 @@ class BaseVmwareApplication(FbConfigApplication):
|
|
|
81
136
|
"""Initialize a BaseVmwareApplication object."""
|
|
82
137
|
self.req_vspheres = None
|
|
83
138
|
self.do_vspheres = []
|
|
139
|
+
self.rich_console = None
|
|
84
140
|
|
|
85
141
|
if base_dir is None:
|
|
86
142
|
base_dir = pathlib.Path(os.getcwd()).resolve()
|
|
@@ -153,6 +209,23 @@ class BaseVmwareApplication(FbConfigApplication):
|
|
|
153
209
|
if self.verbose > 2:
|
|
154
210
|
LOG.debug(_("{what} of {app} ...").format(what="post_init()", app=self.appname))
|
|
155
211
|
|
|
212
|
+
args_color = getattr(self.args, "color", "auto")
|
|
213
|
+
if args_color == "auto":
|
|
214
|
+
self.rich_console = Console()
|
|
215
|
+
else:
|
|
216
|
+
color_system = None
|
|
217
|
+
if args_color == "yes":
|
|
218
|
+
color_term = os.environ.get("COLORTERM", "").strip().lower()
|
|
219
|
+
if color_term in ("truecolor", "24bit"):
|
|
220
|
+
color_system = "truecolor"
|
|
221
|
+
else:
|
|
222
|
+
color_system = "standard"
|
|
223
|
+
term = os.environ.get("TERM", "").strip().lower()
|
|
224
|
+
_term_name, _hyphen, colors = term.rpartition("-")
|
|
225
|
+
color_system = self.term_colors.get(colors, "standard")
|
|
226
|
+
|
|
227
|
+
self.rich_console = Console(color_system=color_system)
|
|
228
|
+
|
|
156
229
|
if not self.cfg.vsphere.keys():
|
|
157
230
|
msg = _("Did not found any configured vSphere environments.")
|
|
158
231
|
LOG.error(msg)
|
|
@@ -178,18 +251,22 @@ class BaseVmwareApplication(FbConfigApplication):
|
|
|
178
251
|
|
|
179
252
|
if self.req_vspheres:
|
|
180
253
|
self.do_vspheres = copy.copy(self.req_vspheres)
|
|
181
|
-
|
|
254
|
+
elif self.default_all_vspheres:
|
|
182
255
|
for vs_name in self.cfg.vsphere.keys():
|
|
183
256
|
self.do_vspheres.append(vs_name)
|
|
184
257
|
|
|
185
|
-
self.init_vsphere_handlers()
|
|
186
|
-
|
|
187
258
|
# -------------------------------------------------------------------------
|
|
188
259
|
def init_arg_parser(self):
|
|
189
260
|
"""Initiate the argument parser."""
|
|
261
|
+
self.add_vsphere_argument()
|
|
190
262
|
super(BaseVmwareApplication, self).init_arg_parser()
|
|
191
263
|
|
|
192
|
-
|
|
264
|
+
# -------------------------------------------------------------------------
|
|
265
|
+
def add_vsphere_argument(self):
|
|
266
|
+
"""Add a commandline option for selecting the vSphere to use."""
|
|
267
|
+
vsphere_options = self.arg_parser.add_argument_group(_("vSphere options"))
|
|
268
|
+
|
|
269
|
+
vsphere_options.add_argument(
|
|
193
270
|
"--vs",
|
|
194
271
|
"--vsphere",
|
|
195
272
|
dest="req_vsphere",
|
|
@@ -203,6 +280,208 @@ class BaseVmwareApplication(FbConfigApplication):
|
|
|
203
280
|
if self.verbose > 2:
|
|
204
281
|
LOG.debug(_("Got command line arguments:") + "\n" + pp(self.args))
|
|
205
282
|
|
|
283
|
+
# -------------------------------------------------------------------------
|
|
284
|
+
def pre_run(self):
|
|
285
|
+
"""Execute some actions before the main routine."""
|
|
286
|
+
LOG.debug(_("Actions before running main routine."))
|
|
287
|
+
|
|
288
|
+
self.init_vsphere_handlers()
|
|
289
|
+
|
|
290
|
+
# -------------------------------------------------------------------------
|
|
291
|
+
def select_storage_type(self, storage_type=None):
|
|
292
|
+
"""Select a storage type for a virtual disk to create."""
|
|
293
|
+
types = {}
|
|
294
|
+
type_list = []
|
|
295
|
+
for st_type in VsphereDsCluster.valid_storage_types:
|
|
296
|
+
types[st_type.lower()] = st_type
|
|
297
|
+
type_list.append(st_type.lower())
|
|
298
|
+
types["any"] = "Any"
|
|
299
|
+
type_list.append("any")
|
|
300
|
+
|
|
301
|
+
if storage_type is not None:
|
|
302
|
+
if self.verbose > 2:
|
|
303
|
+
LOG.debug(f"Checking for storage type {storage_type!r} ...")
|
|
304
|
+
st_type = storage_type.lower()
|
|
305
|
+
if st_type in types:
|
|
306
|
+
return types[st_type]
|
|
307
|
+
msg = _("Invalid storage type {} given.").format(self.colored(st_type, "RED"))
|
|
308
|
+
raise VmwareAppError(msg)
|
|
309
|
+
|
|
310
|
+
if len(types) == 1:
|
|
311
|
+
idx = [types.keys()][0]
|
|
312
|
+
st_type = types[idx]
|
|
313
|
+
if self.verbose > 0:
|
|
314
|
+
LOG.debug(
|
|
315
|
+
f"Automatic select of storage type {st_type!r}, because it is the only one."
|
|
316
|
+
)
|
|
317
|
+
return st_type
|
|
318
|
+
|
|
319
|
+
st_type = Prompt.ask(
|
|
320
|
+
_("Select a storage type to search for the a storage location"),
|
|
321
|
+
choices=type_list,
|
|
322
|
+
show_choices=True,
|
|
323
|
+
case_sensitive=False,
|
|
324
|
+
console=self.rich_console,
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
return types[st_type.lower()]
|
|
328
|
+
|
|
329
|
+
# -------------------------------------------------------------------------
|
|
330
|
+
def select_vsphere(self):
|
|
331
|
+
"""Select exact one of the configured vSpheres."""
|
|
332
|
+
if self.do_vspheres and len(self.do_vspheres) == 1:
|
|
333
|
+
return self.do_vspheres[0]
|
|
334
|
+
|
|
335
|
+
if self.do_vspheres:
|
|
336
|
+
msg = _("There are multiple vSpheres selected on commandline.")
|
|
337
|
+
raise VmwareAppError(msg)
|
|
338
|
+
|
|
339
|
+
if not self.cfg.vsphere.keys():
|
|
340
|
+
msg = _("There are no configured vSpheres available.")
|
|
341
|
+
raise VmwareAppError(msg)
|
|
342
|
+
|
|
343
|
+
vspheres = []
|
|
344
|
+
for vs_name in self.cfg.vsphere.keys():
|
|
345
|
+
vspheres.append(vs_name)
|
|
346
|
+
|
|
347
|
+
vsphere = Prompt.ask(
|
|
348
|
+
_("Select the vSphere to search for the a storage location"),
|
|
349
|
+
choices=vspheres,
|
|
350
|
+
show_choices=True,
|
|
351
|
+
console=self.rich_console,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
return vsphere
|
|
355
|
+
|
|
356
|
+
# -------------------------------------------------------------------------
|
|
357
|
+
def select_datacenter(self, vs_name, dc_name=None):
|
|
358
|
+
"""Select a virtual datacenter from given vSphere."""
|
|
359
|
+
if not vs_name:
|
|
360
|
+
raise VmwareAppError(_("No vSphere name given."))
|
|
361
|
+
if vs_name not in self.vsphere:
|
|
362
|
+
raise VmwareAppError(
|
|
363
|
+
_("vSphere {} is not an active vSphere.").format(self.colored(vs_name, "RED"))
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
vsphere = self.vsphere[vs_name]
|
|
367
|
+
vsphere.get_datacenters()
|
|
368
|
+
dc_list = []
|
|
369
|
+
for _dc_name in vsphere.datacenters.keys():
|
|
370
|
+
dc_list.append(_dc_name)
|
|
371
|
+
|
|
372
|
+
if not len(dc_list):
|
|
373
|
+
msg = _("Did not found virtual datacenters in vSphere {}.").format(
|
|
374
|
+
self.colored(vs_name, "RED")
|
|
375
|
+
)
|
|
376
|
+
LOG.error(msg)
|
|
377
|
+
return None
|
|
378
|
+
|
|
379
|
+
if self.verbose > 2:
|
|
380
|
+
LOG.debug(f"Found datacenters in vSphere {vs_name}:\n" + pp(dc_list))
|
|
381
|
+
|
|
382
|
+
if dc_name:
|
|
383
|
+
if dc_name in dc_list:
|
|
384
|
+
return dc_name
|
|
385
|
+
msg = _("Datacenter {dc} does not exists in vSphere {vs}.").format(
|
|
386
|
+
dc=self.colored(dc_name, "RED"), vs=self.colored(vs_name, "CYAN")
|
|
387
|
+
)
|
|
388
|
+
LOG.error(msg)
|
|
389
|
+
return None
|
|
390
|
+
|
|
391
|
+
if len(dc_list) == 1:
|
|
392
|
+
if self.verbose > 0:
|
|
393
|
+
LOG.debug(
|
|
394
|
+
f"Automatic select of datacenter {dc_list[0]!r}, because it is the only one."
|
|
395
|
+
)
|
|
396
|
+
return dc_list[0]
|
|
397
|
+
|
|
398
|
+
dc_name = Prompt.ask(
|
|
399
|
+
_("Select a virtual datacenter to search for the storage location"),
|
|
400
|
+
choices=sorted(dc_list, key=str.lower),
|
|
401
|
+
show_choices=True,
|
|
402
|
+
console=self.rich_console,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
return dc_name
|
|
406
|
+
|
|
407
|
+
# -------------------------------------------------------------------------
|
|
408
|
+
def select_computing_cluster(self, vs_name, dc_name, cluster_name=None):
|
|
409
|
+
"""Select a cluster computing resource or computing resource in a datacenter."""
|
|
410
|
+
if not vs_name:
|
|
411
|
+
raise VmwareAppError(_("No vSphere name given."))
|
|
412
|
+
if vs_name not in self.vsphere:
|
|
413
|
+
raise VmwareAppError(
|
|
414
|
+
_("vSphere {} is not an active vSphere.").format(self.colored(vs_name, "RED"))
|
|
415
|
+
)
|
|
416
|
+
vsphere = self.vsphere[vs_name]
|
|
417
|
+
|
|
418
|
+
if not dc_name:
|
|
419
|
+
raise VmwareAppError(_("No virtual datacenter name given."))
|
|
420
|
+
vsphere.get_datacenters()
|
|
421
|
+
if dc_name not in vsphere.datacenters:
|
|
422
|
+
msg = _("Datacenter {dc} not found in vSphere {vs}.").format(
|
|
423
|
+
dc=self.colored(dc_name, "RED"), vs=self.colored(vs_name, "CYAN")
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
cluster_list = []
|
|
427
|
+
cluster_type = {}
|
|
428
|
+
vsphere.get_clusters(search_in_dc=dc_name)
|
|
429
|
+
for _cluster in vsphere.clusters:
|
|
430
|
+
cluster_list.append(_cluster.name)
|
|
431
|
+
cluster_type[_cluster.name] = _("cluster computing resource")
|
|
432
|
+
if _cluster.standalone:
|
|
433
|
+
cluster_type[_cluster.name] = _("host computing resource")
|
|
434
|
+
|
|
435
|
+
if not len(cluster_list):
|
|
436
|
+
msg = _("Did not found computing resources in dc {dc} in vSphere {vs}.").format(
|
|
437
|
+
dc=self.colored(dc_name, "RED"),
|
|
438
|
+
vs=self.colored(vs_name, "RED"),
|
|
439
|
+
)
|
|
440
|
+
LOG.error(msg)
|
|
441
|
+
return (None, None)
|
|
442
|
+
|
|
443
|
+
if self.verbose > 1:
|
|
444
|
+
msg = f"Found computing resources in datacenter {dc_name} in vSphere {vs_name}:\n"
|
|
445
|
+
msg += pp(cluster_type)
|
|
446
|
+
LOG.debug(msg)
|
|
447
|
+
|
|
448
|
+
if cluster_name:
|
|
449
|
+
if cluster_name in cluster_list:
|
|
450
|
+
return (cluster_name, cluster_type[cluster_name])
|
|
451
|
+
msg = _(
|
|
452
|
+
"Computing resource {cl} does not exists in datacenter {dc} in vSphere {vs}."
|
|
453
|
+
).format(
|
|
454
|
+
cl=self.colored(cluster_name, "RED"),
|
|
455
|
+
dc=self.colored(dc_name, "CYAN"),
|
|
456
|
+
vs=self.colored(vs_name, "CYAN"),
|
|
457
|
+
)
|
|
458
|
+
LOG.error(msg)
|
|
459
|
+
return (None, None)
|
|
460
|
+
|
|
461
|
+
if len(cluster_list) == 1:
|
|
462
|
+
if self.verbose > 0:
|
|
463
|
+
LOG.debug(
|
|
464
|
+
f"Automatic select of computing resource {cluster_list[0]!r}, "
|
|
465
|
+
"because it is the only one."
|
|
466
|
+
)
|
|
467
|
+
cluster_name = cluster_list[0]
|
|
468
|
+
return (cluster_name, cluster_type[cluster_name])
|
|
469
|
+
|
|
470
|
+
cluster_name = Prompt.ask(
|
|
471
|
+
_("Select a computing resource, which should be connected with the storage location"),
|
|
472
|
+
choices=sorted(cluster_list, key=str.lower),
|
|
473
|
+
show_choices=True,
|
|
474
|
+
console=self.rich_console,
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
return (cluster_name, cluster_type[cluster_name])
|
|
478
|
+
|
|
479
|
+
# -------------------------------------------------------------------------
|
|
480
|
+
def prompt_for_disk_size(self):
|
|
481
|
+
"""Ask for the size of a virtual disk in GiByte."""
|
|
482
|
+
disk_size_gb = PositiveIntPrompt.ask(_("Get the size of the virtual disk in GiByte"))
|
|
483
|
+
return disk_size_gb
|
|
484
|
+
|
|
206
485
|
# -------------------------------------------------------------------------
|
|
207
486
|
def init_vsphere_handlers(self):
|
|
208
487
|
"""Initialize all vSphere handlers."""
|
fb_vmware/app/get_host_list.py
CHANGED
|
@@ -18,18 +18,25 @@ import sys
|
|
|
18
18
|
from operator import itemgetter
|
|
19
19
|
|
|
20
20
|
# Third party modules
|
|
21
|
+
from babel.numbers import format_decimal
|
|
22
|
+
|
|
21
23
|
from fb_tools.argparse_actions import RegexOptionAction
|
|
22
24
|
from fb_tools.common import pp
|
|
23
25
|
from fb_tools.spinner import Spinner
|
|
24
26
|
from fb_tools.xlate import format_list
|
|
25
27
|
|
|
28
|
+
from rich import box
|
|
29
|
+
from rich.table import Table
|
|
30
|
+
from rich.text import Text
|
|
31
|
+
|
|
26
32
|
# Own modules
|
|
27
33
|
from . import BaseVmwareApplication, VmwareAppError
|
|
28
34
|
from .. import __version__ as GLOBAL_VERSION
|
|
29
35
|
from ..errors import VSphereExpectedError
|
|
36
|
+
from ..host import VsphereHost
|
|
30
37
|
from ..xlate import XLATOR
|
|
31
38
|
|
|
32
|
-
__version__ = "1.
|
|
39
|
+
__version__ = "1.5.3"
|
|
33
40
|
LOG = logging.getLogger(__name__)
|
|
34
41
|
|
|
35
42
|
_ = XLATOR.gettext
|
|
@@ -269,6 +276,7 @@ class GetHostsListApplication(BaseVmwareApplication):
|
|
|
269
276
|
summary["online"] = host.online
|
|
270
277
|
summary["no_portgroups"] = str(len(host.portgroups))
|
|
271
278
|
summary["power_state"] = host.power_state
|
|
279
|
+
summary["standby"] = host.standby
|
|
272
280
|
summary["os_name"] = host.product.name
|
|
273
281
|
summary["os_version"] = host.product.os_version
|
|
274
282
|
summary["quarantaine"] = host.quarantaine
|
|
@@ -278,108 +286,113 @@ class GetHostsListApplication(BaseVmwareApplication):
|
|
|
278
286
|
# -------------------------------------------------------------------------
|
|
279
287
|
def print_hosts(self, hosts):
|
|
280
288
|
"""Print on STDOUT all information about all hosts in a human readable format."""
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
"
|
|
307
|
-
|
|
308
|
-
"
|
|
309
|
-
"
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"online",
|
|
314
|
-
"maintenance",
|
|
289
|
+
hosts.sort(key=itemgetter(*self.sort_keys))
|
|
290
|
+
|
|
291
|
+
show_header = True
|
|
292
|
+
table_title = _("All physical hosts") + "\n"
|
|
293
|
+
box_style = box.ROUNDED
|
|
294
|
+
if self.quiet:
|
|
295
|
+
show_header = False
|
|
296
|
+
table_title = None
|
|
297
|
+
box_style = None
|
|
298
|
+
|
|
299
|
+
if self.quiet:
|
|
300
|
+
caption = None
|
|
301
|
+
else:
|
|
302
|
+
count = len(hosts)
|
|
303
|
+
if count:
|
|
304
|
+
caption = "\n" + ngettext(
|
|
305
|
+
"Found one VMware host.",
|
|
306
|
+
"Found {} VMware hosts.",
|
|
307
|
+
count,
|
|
308
|
+
).format(count)
|
|
309
|
+
else:
|
|
310
|
+
caption = "\n" + _("Found no VMware hosts.")
|
|
311
|
+
|
|
312
|
+
table = Table(
|
|
313
|
+
title=table_title,
|
|
314
|
+
title_style="bold cyan",
|
|
315
|
+
caption=caption,
|
|
316
|
+
caption_style="default on default",
|
|
317
|
+
caption_justify="left",
|
|
318
|
+
box=box_style,
|
|
319
|
+
show_header=show_header,
|
|
320
|
+
show_footer=False,
|
|
315
321
|
)
|
|
316
322
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
323
|
+
table.add_column(header=_("Host"))
|
|
324
|
+
table.add_column(header=_("vSphere"))
|
|
325
|
+
table.add_column(header=_("Data Center"))
|
|
326
|
+
table.add_column(header=_("Cluster"))
|
|
327
|
+
table.add_column(header=_("Vendor"))
|
|
328
|
+
table.add_column(header=_("Model"))
|
|
329
|
+
table.add_column(header=_("OS Name"))
|
|
330
|
+
table.add_column(header=_("OS Version"))
|
|
331
|
+
table.add_column(header=_("CPU cores/threads"), justify="right")
|
|
332
|
+
table.add_column(header=_("Memory in GiB"), justify="right")
|
|
333
|
+
table.add_column(header=_("Power State"))
|
|
334
|
+
table.add_column(header=_("Connect state"))
|
|
335
|
+
table.add_column(header=_("StandBy state"), justify="center")
|
|
336
|
+
table.add_column(header=_("Maintenance"), justify="center")
|
|
320
337
|
|
|
321
|
-
max_len = 0
|
|
322
|
-
count = 0
|
|
323
338
|
for host in hosts:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if self.verbose > 1:
|
|
348
|
-
LOG.debug("Label length:\n" + pp(str_lengths))
|
|
349
|
-
LOG.debug("Max line length: {} chars".format(max_len))
|
|
350
|
-
|
|
351
|
-
tpl = ""
|
|
352
|
-
for label in label_list:
|
|
353
|
-
if tpl != "":
|
|
354
|
-
tpl += " "
|
|
355
|
-
if label in ("memory_gb", "cpus", "no_portgroups"):
|
|
356
|
-
tpl += "{{{la}:>{le}}}".format(la=label, le=str_lengths[label])
|
|
339
|
+
row = []
|
|
340
|
+
|
|
341
|
+
row.append(host["name"])
|
|
342
|
+
row.append(host["vsphere"])
|
|
343
|
+
row.append(host["dc"])
|
|
344
|
+
row.append(host["cluster"])
|
|
345
|
+
row.append(host["vendor"])
|
|
346
|
+
row.append(host["model"])
|
|
347
|
+
row.append(host["os_name"])
|
|
348
|
+
row.append(host["os_version"])
|
|
349
|
+
row.append(host["cpus"])
|
|
350
|
+
row.append(format_decimal(host["memory_gb"], format="#,##0"))
|
|
351
|
+
|
|
352
|
+
power_state = host["power_state"]
|
|
353
|
+
if power_state in VsphereHost.power_state_label:
|
|
354
|
+
power_state = VsphereHost.power_state_label[power_state]
|
|
355
|
+
p_state = Text(power_state)
|
|
356
|
+
if host["power_state"].lower() == "poweredon":
|
|
357
|
+
p_state.stylize("bold green")
|
|
358
|
+
elif host["power_state"].lower() == "poweredoff":
|
|
359
|
+
p_state.stylize("bold red")
|
|
360
|
+
elif host["power_state"].lower() == "standby":
|
|
361
|
+
p_state.stylize("bold blue")
|
|
357
362
|
else:
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
363
|
+
p_state.stylize("bold magenta")
|
|
364
|
+
row.append(p_state)
|
|
365
|
+
|
|
366
|
+
connection_state = host["connection_state"]
|
|
367
|
+
if connection_state in VsphereHost.connect_state_label:
|
|
368
|
+
connection_state = VsphereHost.connect_state_label[connection_state]
|
|
369
|
+
c_state = Text(connection_state)
|
|
370
|
+
if host["connection_state"].lower() == "connected":
|
|
371
|
+
c_state.stylize("bold green")
|
|
372
|
+
elif host["connection_state"].lower() == "disconnected":
|
|
373
|
+
c_state.stylize("bold red")
|
|
374
|
+
else:
|
|
375
|
+
c_state.stylize("bold magenta")
|
|
376
|
+
row.append(c_state)
|
|
361
377
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
378
|
+
standby = host["standby"]
|
|
379
|
+
if standby == "none":
|
|
380
|
+
standby = "~"
|
|
381
|
+
if standby in VsphereHost.standby_mode_label:
|
|
382
|
+
standby = VsphereHost.standby_mode_label[standby]
|
|
383
|
+
row.append(standby)
|
|
366
384
|
|
|
367
|
-
|
|
385
|
+
m_state = Text(_("No"), style="bold green")
|
|
386
|
+
if host["maintenance"]:
|
|
387
|
+
m_state = Text(_("Yes"), style="bold yellow")
|
|
388
|
+
row.append(m_state)
|
|
368
389
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
390
|
+
table.add_row(*row)
|
|
391
|
+
|
|
392
|
+
self.rich_console.print(table)
|
|
372
393
|
|
|
373
394
|
if not self.quiet:
|
|
374
395
|
print()
|
|
375
|
-
if count == 0:
|
|
376
|
-
msg = _("Found no VMware hosts.")
|
|
377
|
-
else:
|
|
378
|
-
msg = ngettext("Found one VMware host.", "Found {} VMware hosts.", count).format(
|
|
379
|
-
count
|
|
380
|
-
)
|
|
381
|
-
print(msg)
|
|
382
|
-
print()
|
|
383
396
|
|
|
384
397
|
# -------------------------------------------------------------------------
|
|
385
398
|
def get_hosts(self, vsphere_name):
|
|
@@ -416,7 +429,11 @@ def main():
|
|
|
416
429
|
if app.verbose > 2:
|
|
417
430
|
print(_("{c}-Object:\n{a}").format(c=app.__class__.__name__, a=app), file=sys.stderr)
|
|
418
431
|
|
|
419
|
-
|
|
432
|
+
try:
|
|
433
|
+
app()
|
|
434
|
+
except KeyboardInterrupt:
|
|
435
|
+
print("\n" + app.colored(_("User interrupt."), "YELLOW"))
|
|
436
|
+
sys.exit(5)
|
|
420
437
|
|
|
421
438
|
sys.exit(0)
|
|
422
439
|
|