fb-vmware 1.7.1__tar.gz → 1.8.1__tar.gz
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-1.7.1 → fb_vmware-1.8.1}/PKG-INFO +2 -1
- fb_vmware-1.8.1/data/share/locale/de/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.8.1/data/share/locale/en/LC_MESSAGES/fb_vmware.mo +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/pyproject.toml +4 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/__init__.py +1 -1
- fb_vmware-1.8.1/src/fb_vmware/app/__init__.py +556 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_host_list.py +115 -100
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_network_list.py +176 -218
- fb_vmware-1.8.1/src/fb_vmware/app/get_rpool_list.py +386 -0
- fb_vmware-1.8.1/src/fb_vmware/app/get_storage_cluster_info.py +303 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_storage_cluster_list.py +100 -107
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_storage_list.py +145 -112
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_vm_info.py +79 -17
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/app/get_vm_list.py +169 -95
- fb_vmware-1.8.1/src/fb_vmware/app/search_storage.py +470 -0
- fb_vmware-1.8.1/src/fb_vmware/argparse_actions.py +78 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/base.py +28 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/cluster.py +99 -7
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/connect.py +450 -20
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/datastore.py +195 -6
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/dc.py +19 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/ds_cluster.py +215 -2
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/dvs.py +37 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/errors.py +31 -10
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/host.py +40 -2
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/host_port_group.py +1 -2
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/network.py +17 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/obj.py +30 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/vm.py +19 -1
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/xlate.py +8 -13
- fb_vmware-1.7.1/data/share/locale/de_DE/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.7.1/data/share/locale/en_US/LC_MESSAGES/fb_vmware.mo +0 -0
- fb_vmware-1.7.1/src/fb_vmware/app/__init__.py +0 -277
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/LICENSE +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/README.md +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/about.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/config/__init__.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/controller.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/disk.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/ether.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/iface.py +0 -0
- {fb_vmware-1.7.1 → fb_vmware-1.8.1}/src/fb_vmware/typed_dict.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fb_vmware
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.1
|
|
4
4
|
Summary: @summary: The module for a base vSphere handler object.
|
|
5
5
|
Author-email: Frank Brehm <frank@brehm-online.com>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -27,6 +27,7 @@ Requires-Dist: pytz
|
|
|
27
27
|
Requires-Dist: pyvmomi
|
|
28
28
|
Requires-Dist: PyYAML
|
|
29
29
|
Requires-Dist: requests
|
|
30
|
+
Requires-Dist: rich
|
|
30
31
|
Requires-Dist: semver
|
|
31
32
|
Requires-Dist: six
|
|
32
33
|
Requires-Dist: black ; extra == "development"
|
|
Binary file
|
|
Binary file
|
|
@@ -33,6 +33,7 @@ dependencies = [
|
|
|
33
33
|
"pyvmomi",
|
|
34
34
|
"PyYAML",
|
|
35
35
|
"requests",
|
|
36
|
+
"rich",
|
|
36
37
|
"semver",
|
|
37
38
|
"six",
|
|
38
39
|
]
|
|
@@ -47,12 +48,15 @@ name = "fb_vmware"
|
|
|
47
48
|
directory = "data"
|
|
48
49
|
|
|
49
50
|
[project.scripts]
|
|
51
|
+
get-vsphere-cluster-list = "fb_vmware.app.get_rpool_list:main"
|
|
50
52
|
get-vsphere-host-list = "fb_vmware.app.get_host_list:main"
|
|
51
53
|
get-vsphere-network-list = "fb_vmware.app.get_network_list:main"
|
|
54
|
+
get-vsphere-storage-cluster-info = "fb_vmware.app.get_storage_cluster_info:main"
|
|
52
55
|
get-vsphere-storage-cluster-list = "fb_vmware.app.get_storage_cluster_list:main"
|
|
53
56
|
get-vsphere-storage-list = "fb_vmware.app.get_storage_list:main"
|
|
54
57
|
get-vsphere-vm-info = "fb_vmware.app.get_vm_info:main"
|
|
55
58
|
get-vsphere-vm-list = "fb_vmware.app.get_vm_list:main"
|
|
59
|
+
search-vsphere-storage = "fb_vmware.app.search_storage:main"
|
|
56
60
|
|
|
57
61
|
[project.optional-dependencies]
|
|
58
62
|
development = [
|
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
@summary: A base module for all VMware/vSphere application classes.
|
|
5
|
+
|
|
6
|
+
@author: Frank Brehm
|
|
7
|
+
@contact: frank@brehm-online.com
|
|
8
|
+
@copyright: © 2025 by Frank Brehm, Berlin
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import absolute_import, print_function
|
|
11
|
+
|
|
12
|
+
# Standard modules
|
|
13
|
+
import copy
|
|
14
|
+
import logging
|
|
15
|
+
import os
|
|
16
|
+
import pathlib
|
|
17
|
+
import random
|
|
18
|
+
|
|
19
|
+
# Third party modules
|
|
20
|
+
import fb_tools.spinner
|
|
21
|
+
from fb_tools.cfg_app import FbConfigApplication
|
|
22
|
+
from fb_tools.common import pp
|
|
23
|
+
from fb_tools.errors import FbAppError
|
|
24
|
+
from fb_tools.multi_config import DEFAULT_ENCODING
|
|
25
|
+
|
|
26
|
+
import pytz
|
|
27
|
+
|
|
28
|
+
from rich.console import Console
|
|
29
|
+
from rich.prompt import InvalidResponse, Prompt, PromptBase, PromptType
|
|
30
|
+
|
|
31
|
+
# Own modules
|
|
32
|
+
from .. import __version__ as GLOBAL_VERSION
|
|
33
|
+
from ..config import VmwareConfiguration
|
|
34
|
+
from ..connect import VsphereConnection
|
|
35
|
+
from ..ds_cluster import VsphereDsCluster
|
|
36
|
+
from ..errors import VSphereExpectedError
|
|
37
|
+
from ..xlate import DOMAIN
|
|
38
|
+
from ..xlate import LOCALE_DIR
|
|
39
|
+
from ..xlate import XLATOR
|
|
40
|
+
from ..xlate import __base_dir__ as __xlate_base_dir__
|
|
41
|
+
from ..xlate import __lib_dir__ as __xlate_lib_dir__
|
|
42
|
+
from ..xlate import __mo_file__ as __xlate_mo_file__
|
|
43
|
+
from ..xlate import __module_dir__ as __xlate_module_dir__
|
|
44
|
+
|
|
45
|
+
__version__ = "1.7.2"
|
|
46
|
+
LOG = logging.getLogger(__name__)
|
|
47
|
+
TZ = pytz.timezone("Europe/Berlin")
|
|
48
|
+
|
|
49
|
+
_ = XLATOR.gettext
|
|
50
|
+
ngettext = XLATOR.ngettext
|
|
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
|
+
|
|
57
|
+
|
|
58
|
+
# =============================================================================
|
|
59
|
+
class VmwareAppError(FbAppError):
|
|
60
|
+
"""Base exception class for all exceptions in all VMware/vSphere application classes."""
|
|
61
|
+
|
|
62
|
+
pass
|
|
63
|
+
|
|
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
|
+
|
|
103
|
+
# =============================================================================
|
|
104
|
+
class BaseVmwareApplication(FbConfigApplication):
|
|
105
|
+
"""Base class for all VMware/vSphere application classes."""
|
|
106
|
+
|
|
107
|
+
term_colors = {
|
|
108
|
+
"kitty": "256",
|
|
109
|
+
"256color": "256",
|
|
110
|
+
"16color": "standard",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
default_all_vspheres = True
|
|
114
|
+
|
|
115
|
+
# -------------------------------------------------------------------------
|
|
116
|
+
def __init__(
|
|
117
|
+
self,
|
|
118
|
+
appname=None,
|
|
119
|
+
verbose=0,
|
|
120
|
+
version=GLOBAL_VERSION,
|
|
121
|
+
base_dir=None,
|
|
122
|
+
cfg_class=VmwareConfiguration,
|
|
123
|
+
initialized=False,
|
|
124
|
+
usage=None,
|
|
125
|
+
description=None,
|
|
126
|
+
argparse_epilog=None,
|
|
127
|
+
argparse_prefix_chars="-",
|
|
128
|
+
env_prefix=None,
|
|
129
|
+
append_appname_to_stems=True,
|
|
130
|
+
config_dir=None,
|
|
131
|
+
additional_stems=None,
|
|
132
|
+
additional_cfgdirs=None,
|
|
133
|
+
cfg_encoding=DEFAULT_ENCODING,
|
|
134
|
+
use_chardet=True,
|
|
135
|
+
):
|
|
136
|
+
"""Initialize a BaseVmwareApplication object."""
|
|
137
|
+
self.req_vspheres = None
|
|
138
|
+
self.do_vspheres = []
|
|
139
|
+
self.rich_console = None
|
|
140
|
+
|
|
141
|
+
if base_dir is None:
|
|
142
|
+
base_dir = pathlib.Path(os.getcwd()).resolve()
|
|
143
|
+
|
|
144
|
+
# Hash with all vSphere handler objects
|
|
145
|
+
self.vsphere = {}
|
|
146
|
+
|
|
147
|
+
super(BaseVmwareApplication, self).__init__(
|
|
148
|
+
appname=appname,
|
|
149
|
+
verbose=verbose,
|
|
150
|
+
version=version,
|
|
151
|
+
base_dir=base_dir,
|
|
152
|
+
description=description,
|
|
153
|
+
cfg_class=cfg_class,
|
|
154
|
+
append_appname_to_stems=append_appname_to_stems,
|
|
155
|
+
config_dir=config_dir,
|
|
156
|
+
additional_stems=additional_stems,
|
|
157
|
+
additional_cfgdirs=additional_cfgdirs,
|
|
158
|
+
cfg_encoding=cfg_encoding,
|
|
159
|
+
use_chardet=use_chardet,
|
|
160
|
+
initialized=False,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# -------------------------------------------------------------------------
|
|
164
|
+
def __del__(self):
|
|
165
|
+
"""Clean up in emergency case."""
|
|
166
|
+
if hasattr(self, "vsphere") and self.vsphere.keys():
|
|
167
|
+
self.cleaning_up()
|
|
168
|
+
|
|
169
|
+
# -------------------------------------------------------------------------
|
|
170
|
+
def as_dict(self, short=True):
|
|
171
|
+
"""
|
|
172
|
+
Transform the elements of the object into a dict.
|
|
173
|
+
|
|
174
|
+
@param short: don't include local properties in resulting dict.
|
|
175
|
+
@type short: bool
|
|
176
|
+
|
|
177
|
+
@return: structure as dict
|
|
178
|
+
@rtype: dict
|
|
179
|
+
"""
|
|
180
|
+
res = super(BaseVmwareApplication, self).as_dict(short=short)
|
|
181
|
+
|
|
182
|
+
res["xlate"]["fb_vmware"] = {
|
|
183
|
+
"__module_dir__": __xlate_module_dir__,
|
|
184
|
+
"__lib_dir__": __xlate_lib_dir__,
|
|
185
|
+
"__base_dir__": __xlate_base_dir__,
|
|
186
|
+
"LOCALE_DIR": LOCALE_DIR,
|
|
187
|
+
"DOMAIN": DOMAIN,
|
|
188
|
+
"__mo_file__": __xlate_mo_file__,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return res
|
|
192
|
+
|
|
193
|
+
# -------------------------------------------------------------------------
|
|
194
|
+
def post_init(self):
|
|
195
|
+
"""
|
|
196
|
+
Execute some things before calling run().
|
|
197
|
+
|
|
198
|
+
Here could be done some finishing actions after reading in commandline
|
|
199
|
+
parameters, configuration a.s.o.
|
|
200
|
+
|
|
201
|
+
This method could be overwritten by descendant classes, these
|
|
202
|
+
methhods should allways include a call to post_init() of the
|
|
203
|
+
parent class.
|
|
204
|
+
"""
|
|
205
|
+
self.initialized = False
|
|
206
|
+
|
|
207
|
+
super(BaseVmwareApplication, self).post_init()
|
|
208
|
+
|
|
209
|
+
if self.verbose > 2:
|
|
210
|
+
LOG.debug(_("{what} of {app} ...").format(what="post_init()", app=self.appname))
|
|
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
|
+
|
|
229
|
+
if not self.cfg.vsphere.keys():
|
|
230
|
+
msg = _("Did not found any configured vSphere environments.")
|
|
231
|
+
LOG.error(msg)
|
|
232
|
+
self.exit(3)
|
|
233
|
+
|
|
234
|
+
if self.args.req_vsphere:
|
|
235
|
+
self.req_vspheres = []
|
|
236
|
+
all_found = True
|
|
237
|
+
for vs_name in self.args.req_vsphere:
|
|
238
|
+
LOG.debug(_("Checking for configured vSphere instance {!r} ...").format(vs_name))
|
|
239
|
+
vs = vs_name.strip().lower()
|
|
240
|
+
if vs not in self.cfg.vsphere.keys():
|
|
241
|
+
all_found = False
|
|
242
|
+
msg = _(
|
|
243
|
+
"vSphere {!r} not found in list of configured vSphere instances."
|
|
244
|
+
).format(vs_name)
|
|
245
|
+
LOG.error(msg)
|
|
246
|
+
else:
|
|
247
|
+
if vs not in self.req_vspheres:
|
|
248
|
+
self.req_vspheres.append(vs)
|
|
249
|
+
if not all_found:
|
|
250
|
+
self.exit(1)
|
|
251
|
+
|
|
252
|
+
if self.req_vspheres:
|
|
253
|
+
self.do_vspheres = copy.copy(self.req_vspheres)
|
|
254
|
+
elif self.default_all_vspheres:
|
|
255
|
+
for vs_name in self.cfg.vsphere.keys():
|
|
256
|
+
self.do_vspheres.append(vs_name)
|
|
257
|
+
|
|
258
|
+
# -------------------------------------------------------------------------
|
|
259
|
+
def init_arg_parser(self):
|
|
260
|
+
"""Initiate the argument parser."""
|
|
261
|
+
self.add_vsphere_argument()
|
|
262
|
+
super(BaseVmwareApplication, self).init_arg_parser()
|
|
263
|
+
|
|
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(
|
|
270
|
+
"--vs",
|
|
271
|
+
"--vsphere",
|
|
272
|
+
dest="req_vsphere",
|
|
273
|
+
nargs="*",
|
|
274
|
+
help=_("The vSphere names from configuration, in which the VMs should be searched."),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# -------------------------------------------------------------------------
|
|
278
|
+
def perform_arg_parser(self):
|
|
279
|
+
"""Evaluate the command line parameters. Maybe overridden."""
|
|
280
|
+
if self.verbose > 2:
|
|
281
|
+
LOG.debug(_("Got command line arguments:") + "\n" + pp(self.args))
|
|
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
|
+
|
|
485
|
+
# -------------------------------------------------------------------------
|
|
486
|
+
def init_vsphere_handlers(self):
|
|
487
|
+
"""Initialize all vSphere handlers."""
|
|
488
|
+
if self.verbose > 1:
|
|
489
|
+
LOG.debug(_("Initializing vSphere handlers ..."))
|
|
490
|
+
|
|
491
|
+
try:
|
|
492
|
+
for vsphere_name in self.do_vspheres:
|
|
493
|
+
self.init_vsphere_handler(vsphere_name)
|
|
494
|
+
except VSphereExpectedError as e:
|
|
495
|
+
LOG.error(str(e))
|
|
496
|
+
self.exit(7)
|
|
497
|
+
|
|
498
|
+
# -------------------------------------------------------------------------
|
|
499
|
+
def init_vsphere_handler(self, vsphere_name):
|
|
500
|
+
"""Initialize the given vSphere handler."""
|
|
501
|
+
if self.verbose > 2:
|
|
502
|
+
LOG.debug(_("Initializing handler for vSphere {!r} ...").format(vsphere_name))
|
|
503
|
+
|
|
504
|
+
vsphere_data = self.cfg.vsphere[vsphere_name]
|
|
505
|
+
|
|
506
|
+
vsphere = VsphereConnection(
|
|
507
|
+
vsphere_data,
|
|
508
|
+
auto_close=True,
|
|
509
|
+
simulate=self.simulate,
|
|
510
|
+
force=self.force,
|
|
511
|
+
appname=self.appname,
|
|
512
|
+
verbose=self.verbose,
|
|
513
|
+
base_dir=self.base_dir,
|
|
514
|
+
terminal_has_colors=self.terminal_has_colors,
|
|
515
|
+
initialized=False,
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
if vsphere:
|
|
519
|
+
self.vsphere[vsphere_name] = vsphere
|
|
520
|
+
vsphere.initialized = True
|
|
521
|
+
else:
|
|
522
|
+
msg = _("Could not initialize {} object from:").format("VsphereConnection")
|
|
523
|
+
msg += "\n" + str(vsphere_data)
|
|
524
|
+
LOG.error(msg)
|
|
525
|
+
|
|
526
|
+
vsphere._check_credentials()
|
|
527
|
+
|
|
528
|
+
# -------------------------------------------------------------------------
|
|
529
|
+
def cleaning_up(self):
|
|
530
|
+
"""Close all vSphere connections and remove all vSphere handlers."""
|
|
531
|
+
if self.verbose > 1:
|
|
532
|
+
LOG.debug(_("Cleaning up ..."))
|
|
533
|
+
|
|
534
|
+
for vsphere_name in self.do_vspheres:
|
|
535
|
+
if vsphere_name in self.vsphere:
|
|
536
|
+
LOG.debug(_("Closing vSphere object {!r} ...").format(vsphere_name))
|
|
537
|
+
self.vsphere[vsphere_name].disconnect()
|
|
538
|
+
del self.vsphere[vsphere_name]
|
|
539
|
+
|
|
540
|
+
# -------------------------------------------------------------------------
|
|
541
|
+
@classmethod
|
|
542
|
+
def get_random_spinner_name(cls):
|
|
543
|
+
"""Return a randon spinner name from fb_tools.spinner.CycleList."""
|
|
544
|
+
randomizer = random.SystemRandom()
|
|
545
|
+
|
|
546
|
+
return randomizer.choice(list(fb_tools.spinner.CycleList.keys()))
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
# =============================================================================
|
|
550
|
+
if __name__ == "__main__":
|
|
551
|
+
|
|
552
|
+
pass
|
|
553
|
+
|
|
554
|
+
# =============================================================================
|
|
555
|
+
|
|
556
|
+
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list
|