root / test / py / cmdlib / testsupport / config_mock.py @ 27619aac
History | View | Annotate | Download (18.8 kB)
1 |
#
|
---|---|
2 |
#
|
3 |
|
4 |
# Copyright (C) 2013 Google Inc.
|
5 |
#
|
6 |
# This program is free software; you can redistribute it and/or modify
|
7 |
# it under the terms of the GNU General Public License as published by
|
8 |
# the Free Software Foundation; either version 2 of the License, or
|
9 |
# (at your option) any later version.
|
10 |
#
|
11 |
# This program is distributed in the hope that it will be useful, but
|
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
# General Public License for more details.
|
15 |
#
|
16 |
# You should have received a copy of the GNU General Public License
|
17 |
# along with this program; if not, write to the Free Software
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 |
# 02110-1301, USA.
|
20 |
|
21 |
|
22 |
"""Support for mocking the cluster configuration"""
|
23 |
|
24 |
|
25 |
import time |
26 |
import uuid as uuid_module |
27 |
|
28 |
from ganeti import config |
29 |
from ganeti import constants |
30 |
from ganeti import objects |
31 |
|
32 |
import mocks |
33 |
|
34 |
|
35 |
def _StubGetEntResolver(): |
36 |
return mocks.FakeGetentResolver()
|
37 |
|
38 |
|
39 |
# pylint: disable=R0904
|
40 |
class ConfigMock(config.ConfigWriter): |
41 |
"""A mocked cluster configuration with added methods for easy customization.
|
42 |
|
43 |
"""
|
44 |
|
45 |
def __init__(self): |
46 |
self._cur_group_id = 1 |
47 |
self._cur_node_id = 1 |
48 |
self._cur_inst_id = 1 |
49 |
self._cur_disk_id = 1 |
50 |
self._cur_os_id = 1 |
51 |
self._cur_nic_id = 1 |
52 |
self._cur_net_id = 1 |
53 |
self._default_os = None |
54 |
|
55 |
super(ConfigMock, self).__init__(cfg_file="/dev/null", |
56 |
_getents=_StubGetEntResolver()) |
57 |
|
58 |
def _GetUuid(self): |
59 |
return str(uuid_module.uuid4()) |
60 |
|
61 |
def _GetObjUuid(self, obj): |
62 |
if obj is None: |
63 |
return None |
64 |
elif isinstance(obj, objects.ConfigObject): |
65 |
return obj.uuid
|
66 |
else:
|
67 |
return obj
|
68 |
|
69 |
def AddNewNodeGroup(self, |
70 |
uuid=None,
|
71 |
name=None,
|
72 |
ndparams=None,
|
73 |
diskparams=None,
|
74 |
ipolicy=None,
|
75 |
hv_state_static=None,
|
76 |
disk_state_static=None,
|
77 |
alloc_policy=None,
|
78 |
networks=None):
|
79 |
"""Add a new L{objects.NodeGroup} to the cluster configuration
|
80 |
|
81 |
See L{objects.NodeGroup} for parameter documentation.
|
82 |
|
83 |
@rtype: L{objects.NodeGroup}
|
84 |
@return: the newly added node group
|
85 |
|
86 |
"""
|
87 |
group_id = self._cur_group_id
|
88 |
self._cur_group_id += 1 |
89 |
|
90 |
if uuid is None: |
91 |
uuid = self._GetUuid()
|
92 |
if name is None: |
93 |
name = "mock_group_%d" % group_id
|
94 |
if networks is None: |
95 |
networks = {} |
96 |
|
97 |
group = objects.NodeGroup(uuid=uuid, |
98 |
name=name, |
99 |
ndparams=ndparams, |
100 |
diskparams=diskparams, |
101 |
ipolicy=ipolicy, |
102 |
hv_state_static=hv_state_static, |
103 |
disk_state_static=disk_state_static, |
104 |
alloc_policy=alloc_policy, |
105 |
networks=networks, |
106 |
members=[]) |
107 |
|
108 |
self.AddNodeGroup(group, None) |
109 |
return group
|
110 |
|
111 |
# pylint: disable=R0913
|
112 |
def AddNewNode(self, |
113 |
uuid=None,
|
114 |
name=None,
|
115 |
primary_ip=None,
|
116 |
secondary_ip=None,
|
117 |
master_candidate=True,
|
118 |
offline=False,
|
119 |
drained=False,
|
120 |
group=None,
|
121 |
master_capable=True,
|
122 |
vm_capable=True,
|
123 |
ndparams=None,
|
124 |
powered=True,
|
125 |
hv_state=None,
|
126 |
hv_state_static=None,
|
127 |
disk_state=None,
|
128 |
disk_state_static=None):
|
129 |
"""Add a new L{objects.Node} to the cluster configuration
|
130 |
|
131 |
See L{objects.Node} for parameter documentation.
|
132 |
|
133 |
@rtype: L{objects.Node}
|
134 |
@return: the newly added node
|
135 |
|
136 |
"""
|
137 |
node_id = self._cur_node_id
|
138 |
self._cur_node_id += 1 |
139 |
|
140 |
if uuid is None: |
141 |
uuid = self._GetUuid()
|
142 |
if name is None: |
143 |
name = "mock_node_%d.example.com" % node_id
|
144 |
if primary_ip is None: |
145 |
primary_ip = "192.168.0.%d" % node_id
|
146 |
if secondary_ip is None: |
147 |
secondary_ip = "192.168.1.%d" % node_id
|
148 |
if group is None: |
149 |
group = self._default_group.uuid
|
150 |
group = self._GetObjUuid(group)
|
151 |
if ndparams is None: |
152 |
ndparams = {} |
153 |
|
154 |
node = objects.Node(uuid=uuid, |
155 |
name=name, |
156 |
primary_ip=primary_ip, |
157 |
secondary_ip=secondary_ip, |
158 |
master_candidate=master_candidate, |
159 |
offline=offline, |
160 |
drained=drained, |
161 |
group=group, |
162 |
master_capable=master_capable, |
163 |
vm_capable=vm_capable, |
164 |
ndparams=ndparams, |
165 |
powered=powered, |
166 |
hv_state=hv_state, |
167 |
hv_state_static=hv_state_static, |
168 |
disk_state=disk_state, |
169 |
disk_state_static=disk_state_static) |
170 |
|
171 |
self.AddNode(node, None) |
172 |
return node
|
173 |
|
174 |
def AddNewInstance(self, |
175 |
uuid=None,
|
176 |
name=None,
|
177 |
primary_node=None,
|
178 |
os=None,
|
179 |
hypervisor=None,
|
180 |
hvparams=None,
|
181 |
beparams=None,
|
182 |
osparams=None,
|
183 |
admin_state=None,
|
184 |
nics=None,
|
185 |
disks=None,
|
186 |
disk_template=None,
|
187 |
disks_active=None,
|
188 |
network_port=None,
|
189 |
secondary_node=None):
|
190 |
"""Add a new L{objects.Instance} to the cluster configuration
|
191 |
|
192 |
See L{objects.Instance} for parameter documentation.
|
193 |
|
194 |
@rtype: L{objects.Instance}
|
195 |
@return: the newly added instance
|
196 |
|
197 |
"""
|
198 |
inst_id = self._cur_inst_id
|
199 |
self._cur_inst_id += 1 |
200 |
|
201 |
if uuid is None: |
202 |
uuid = self._GetUuid()
|
203 |
if name is None: |
204 |
name = "mock_inst_%d.example.com" % inst_id
|
205 |
if primary_node is None: |
206 |
primary_node = self._master_node.uuid
|
207 |
primary_node = self._GetObjUuid(primary_node)
|
208 |
if os is None: |
209 |
os = self.GetDefaultOs().name + objects.OS.VARIANT_DELIM +\
|
210 |
self.GetDefaultOs().supported_variants[0] |
211 |
if hypervisor is None: |
212 |
hypervisor = self.GetClusterInfo().enabled_hypervisors[0] |
213 |
if hvparams is None: |
214 |
hvparams = {} |
215 |
if beparams is None: |
216 |
beparams = {} |
217 |
if osparams is None: |
218 |
osparams = {} |
219 |
if admin_state is None: |
220 |
admin_state = constants.ADMINST_DOWN |
221 |
if nics is None: |
222 |
nics = [self.CreateNic()]
|
223 |
if disk_template is None: |
224 |
if disks is None: |
225 |
# user chose nothing, so create a plain disk for him
|
226 |
disk_template = constants.DT_PLAIN |
227 |
elif len(disks) == 0: |
228 |
disk_template = constants.DT_DISKLESS |
229 |
else:
|
230 |
disk_template = disks[0].dev_type
|
231 |
if disks is None: |
232 |
if disk_template == constants.DT_DISKLESS:
|
233 |
disks = [] |
234 |
else:
|
235 |
disks = [self.CreateDisk(dev_type=disk_template,
|
236 |
primary_node=primary_node, |
237 |
secondary_node=secondary_node)] |
238 |
if disks_active is None: |
239 |
disks_active = admin_state == constants.ADMINST_UP |
240 |
|
241 |
inst = objects.Instance(uuid=uuid, |
242 |
name=name, |
243 |
primary_node=primary_node, |
244 |
os=os, |
245 |
hypervisor=hypervisor, |
246 |
hvparams=hvparams, |
247 |
beparams=beparams, |
248 |
osparams=osparams, |
249 |
admin_state=admin_state, |
250 |
nics=nics, |
251 |
disks=disks, |
252 |
disk_template=disk_template, |
253 |
disks_active=disks_active, |
254 |
network_port=network_port) |
255 |
self.AddInstance(inst, None) |
256 |
return inst
|
257 |
|
258 |
def AddNewNetwork(self, |
259 |
uuid=None,
|
260 |
name=None,
|
261 |
mac_prefix=None,
|
262 |
network=None,
|
263 |
network6=None,
|
264 |
gateway=None,
|
265 |
gateway6=None,
|
266 |
reservations=None,
|
267 |
ext_reservations=None):
|
268 |
"""Add a new L{objects.Network} to the cluster configuration
|
269 |
|
270 |
See L{objects.Network} for parameter documentation.
|
271 |
|
272 |
@rtype: L{objects.Network}
|
273 |
@return: the newly added network
|
274 |
|
275 |
"""
|
276 |
net_id = self._cur_net_id
|
277 |
self._cur_net_id += 1 |
278 |
|
279 |
if uuid is None: |
280 |
uuid = self._GetUuid()
|
281 |
if name is None: |
282 |
name = "mock_net_%d" % net_id
|
283 |
if network is None: |
284 |
network = "192.168.123.0/24"
|
285 |
if gateway is None: |
286 |
if network[-3:] == "/24": |
287 |
gateway = network[:-4] + "1" |
288 |
else:
|
289 |
gateway = "192.168.123.1"
|
290 |
if network[-3:] == "/24" and gateway == network[:-4] + "1": |
291 |
if reservations is None: |
292 |
reservations = "0" * 256 |
293 |
if ext_reservations:
|
294 |
ext_reservations = "11" + ("0" * 253) + "1" |
295 |
elif reservations is None or ext_reservations is None: |
296 |
raise AssertionError("You have to specify 'reservations' and" |
297 |
" 'ext_reservations'!")
|
298 |
|
299 |
net = objects.Network(uuid=uuid, |
300 |
name=name, |
301 |
mac_prefix=mac_prefix, |
302 |
network=network, |
303 |
network6=network6, |
304 |
gateway=gateway, |
305 |
gateway6=gateway6, |
306 |
reservations=reservations, |
307 |
ext_reservations=ext_reservations) |
308 |
self.AddNetwork(net, None) |
309 |
return net
|
310 |
|
311 |
def ConnectNetworkToGroup(self, net, group, netparams=None): |
312 |
"""Connect the given network to the group.
|
313 |
|
314 |
@type net: string or L{objects.Network}
|
315 |
@param net: network object or UUID
|
316 |
@type group: string of L{objects.NodeGroup}
|
317 |
@param group: node group object of UUID
|
318 |
@type netparams: dict
|
319 |
@param netparams: network parameters for this connection
|
320 |
|
321 |
"""
|
322 |
net_obj = None
|
323 |
if isinstance(net, objects.Network): |
324 |
net_obj = net |
325 |
else:
|
326 |
net_obj = self.GetNetwork(net)
|
327 |
|
328 |
group_obj = None
|
329 |
if isinstance(group, objects.NodeGroup): |
330 |
group_obj = group |
331 |
else:
|
332 |
group_obj = self.GetNodeGroup(group)
|
333 |
|
334 |
if net_obj is None or group_obj is None: |
335 |
raise AssertionError("Failed to get network or node group") |
336 |
|
337 |
if netparams is None: |
338 |
netparams = { |
339 |
constants.NIC_MODE: constants.NIC_MODE_BRIDGED, |
340 |
constants.NIC_LINK: "br_mock"
|
341 |
} |
342 |
|
343 |
group_obj.networks[net_obj.uuid] = netparams |
344 |
|
345 |
def CreateDisk(self, |
346 |
uuid=None,
|
347 |
name=None,
|
348 |
dev_type=constants.DT_PLAIN, |
349 |
logical_id=None,
|
350 |
physical_id=None,
|
351 |
children=None,
|
352 |
iv_name=None,
|
353 |
size=1024,
|
354 |
mode=constants.DISK_RDWR, |
355 |
params=None,
|
356 |
spindles=None,
|
357 |
primary_node=None,
|
358 |
secondary_node=None,
|
359 |
create_nodes=False,
|
360 |
instance_disk_index=0):
|
361 |
"""Create a new L{objecs.Disk} object
|
362 |
|
363 |
@rtype: L{objects.Disk}
|
364 |
@return: the newly create disk object
|
365 |
|
366 |
"""
|
367 |
disk_id = self._cur_disk_id
|
368 |
self._cur_disk_id += 1 |
369 |
|
370 |
if uuid is None: |
371 |
uuid = self._GetUuid()
|
372 |
if name is None: |
373 |
name = "mock_disk_%d" % disk_id
|
374 |
|
375 |
if dev_type == constants.DT_DRBD8:
|
376 |
pnode_uuid = self._GetObjUuid(primary_node)
|
377 |
snode_uuid = self._GetObjUuid(secondary_node)
|
378 |
if logical_id is not None: |
379 |
pnode_uuid = logical_id[0]
|
380 |
snode_uuid = logical_id[1]
|
381 |
|
382 |
if pnode_uuid is None and create_nodes: |
383 |
pnode_uuid = self.AddNewNode().uuid
|
384 |
if snode_uuid is None and create_nodes: |
385 |
snode_uuid = self.AddNewNode().uuid
|
386 |
|
387 |
if pnode_uuid is None or snode_uuid is None: |
388 |
raise AssertionError("Trying to create DRBD disk without nodes!") |
389 |
|
390 |
if logical_id is None: |
391 |
logical_id = (pnode_uuid, snode_uuid, |
392 |
constants.FIRST_DRBD_PORT + disk_id, |
393 |
disk_id, disk_id, "mock_secret")
|
394 |
if children is None: |
395 |
data_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
|
396 |
size=size) |
397 |
meta_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
|
398 |
size=constants.DRBD_META_SIZE) |
399 |
children = [data_child, meta_child] |
400 |
elif dev_type == constants.DT_PLAIN:
|
401 |
if logical_id is None: |
402 |
logical_id = ("mockvg", "mock_disk_%d" % disk_id) |
403 |
elif dev_type in (constants.DT_FILE, constants.DT_SHARED_FILE): |
404 |
if logical_id is None: |
405 |
logical_id = (constants.FD_LOOP, "/file/storage/disk%d" % disk_id)
|
406 |
elif dev_type == constants.DT_BLOCK:
|
407 |
if logical_id is None: |
408 |
logical_id = (constants.BLOCKDEV_DRIVER_MANUAL, |
409 |
"/dev/disk/disk%d" % disk_id)
|
410 |
elif logical_id is None: |
411 |
raise NotImplementedError |
412 |
if children is None: |
413 |
children = [] |
414 |
if iv_name is None: |
415 |
iv_name = "disk/%d" % instance_disk_index
|
416 |
if params is None: |
417 |
params = {} |
418 |
|
419 |
return objects.Disk(uuid=uuid,
|
420 |
name=name, |
421 |
dev_type=dev_type, |
422 |
logical_id=logical_id, |
423 |
physical_id=physical_id, |
424 |
children=children, |
425 |
iv_name=iv_name, |
426 |
size=size, |
427 |
mode=mode, |
428 |
params=params, |
429 |
spindles=spindles) |
430 |
|
431 |
def GetDefaultOs(self): |
432 |
if self._default_os is None: |
433 |
self._default_os = self.CreateOs(name="mocked_os") |
434 |
return self._default_os |
435 |
|
436 |
def CreateOs(self, |
437 |
name=None,
|
438 |
path=None,
|
439 |
api_versions=None,
|
440 |
create_script=None,
|
441 |
export_script=None,
|
442 |
import_script=None,
|
443 |
rename_script=None,
|
444 |
verify_script=None,
|
445 |
supported_variants=None,
|
446 |
supported_parameters=None):
|
447 |
"""Create a new L{objects.OS} object
|
448 |
|
449 |
@rtype: L{object.OS}
|
450 |
@return: the newly create OS objects
|
451 |
|
452 |
"""
|
453 |
os_id = self._cur_os_id
|
454 |
self._cur_os_id += 1 |
455 |
|
456 |
if name is None: |
457 |
name = "mock_os_%d" % os_id
|
458 |
if path is None: |
459 |
path = "/mocked/path/%d" % os_id
|
460 |
if api_versions is None: |
461 |
api_versions = [constants.OS_API_V20] |
462 |
if create_script is None: |
463 |
create_script = "mock_create.sh"
|
464 |
if export_script is None: |
465 |
export_script = "mock_export.sh"
|
466 |
if import_script is None: |
467 |
import_script = "mock_import.sh"
|
468 |
if rename_script is None: |
469 |
rename_script = "mock_rename.sh"
|
470 |
if verify_script is None: |
471 |
verify_script = "mock_verify.sh"
|
472 |
if supported_variants is None: |
473 |
supported_variants = ["default"]
|
474 |
if supported_parameters is None: |
475 |
supported_parameters = ["mock_param"]
|
476 |
|
477 |
return objects.OS(name=name,
|
478 |
path=path, |
479 |
api_versions=api_versions, |
480 |
create_script=create_script, |
481 |
export_script=export_script, |
482 |
import_script=import_script, |
483 |
rename_script=rename_script, |
484 |
verify_script=verify_script, |
485 |
supported_variants=supported_variants, |
486 |
supported_parameters=supported_parameters) |
487 |
|
488 |
def CreateNic(self, |
489 |
uuid=None,
|
490 |
name=None,
|
491 |
mac=None,
|
492 |
ip=None,
|
493 |
network=None,
|
494 |
nicparams=None,
|
495 |
netinfo=None):
|
496 |
"""Create a new L{objecs.NIC} object
|
497 |
|
498 |
@rtype: L{objects.NIC}
|
499 |
@return: the newly create NIC object
|
500 |
|
501 |
"""
|
502 |
nic_id = self._cur_nic_id
|
503 |
self._cur_nic_id += 1 |
504 |
|
505 |
if uuid is None: |
506 |
uuid = self._GetUuid()
|
507 |
if name is None: |
508 |
name = "mock_nic_%d" % nic_id
|
509 |
if mac is None: |
510 |
mac = "aa:00:00:aa:%02x:%02x" % (nic_id / 0xff, nic_id % 0xff) |
511 |
if isinstance(network, objects.Network): |
512 |
network = network.uuid |
513 |
if nicparams is None: |
514 |
nicparams = {} |
515 |
|
516 |
return objects.NIC(uuid=uuid,
|
517 |
name=name, |
518 |
mac=mac, |
519 |
ip=ip, |
520 |
network=network, |
521 |
nicparams=nicparams, |
522 |
netinfo=netinfo) |
523 |
|
524 |
def SetEnabledDiskTemplates(self, enabled_disk_templates): |
525 |
"""Set the enabled disk templates in the cluster.
|
526 |
|
527 |
This also takes care of required IPolicy updates.
|
528 |
|
529 |
@type enabled_disk_templates: list of string
|
530 |
@param enabled_disk_templates: list of disk templates to enable
|
531 |
|
532 |
"""
|
533 |
cluster = self.GetClusterInfo()
|
534 |
cluster.enabled_disk_templates = list(enabled_disk_templates)
|
535 |
cluster.ipolicy[constants.IPOLICY_DTS] = list(enabled_disk_templates)
|
536 |
|
537 |
def _OpenConfig(self, accept_foreign): |
538 |
self._config_data = objects.ConfigData(
|
539 |
version=constants.CONFIG_VERSION, |
540 |
cluster=None,
|
541 |
nodegroups={}, |
542 |
nodes={}, |
543 |
instances={}, |
544 |
networks={}) |
545 |
|
546 |
master_node_uuid = self._GetUuid()
|
547 |
|
548 |
self._cluster = objects.Cluster(
|
549 |
serial_no=1,
|
550 |
rsahostkeypub="",
|
551 |
highest_used_port=(constants.FIRST_DRBD_PORT - 1),
|
552 |
tcpudp_port_pool=set(),
|
553 |
mac_prefix="aa:00:00",
|
554 |
volume_group_name="xenvg",
|
555 |
reserved_lvs=None,
|
556 |
drbd_usermode_helper="/bin/true",
|
557 |
master_node=master_node_uuid, |
558 |
master_ip="192.168.0.254",
|
559 |
master_netdev=constants.DEFAULT_BRIDGE, |
560 |
master_netmask=None,
|
561 |
use_external_mip_script=None,
|
562 |
cluster_name="cluster.example.com",
|
563 |
file_storage_dir="/tmp",
|
564 |
shared_file_storage_dir=None,
|
565 |
enabled_hypervisors=[constants.HT_XEN_HVM, constants.HT_XEN_PVM, |
566 |
constants.HT_KVM], |
567 |
hvparams=constants.HVC_DEFAULTS.copy(), |
568 |
ipolicy=None,
|
569 |
os_hvp={self.GetDefaultOs().name: constants.HVC_DEFAULTS.copy()},
|
570 |
beparams=None,
|
571 |
osparams=None,
|
572 |
nicparams={constants.PP_DEFAULT: constants.NICC_DEFAULTS}, |
573 |
ndparams=None,
|
574 |
diskparams=None,
|
575 |
candidate_pool_size=3,
|
576 |
modify_etc_hosts=False,
|
577 |
modify_ssh_setup=False,
|
578 |
maintain_node_health=False,
|
579 |
uid_pool=None,
|
580 |
default_iallocator="mock_iallocator",
|
581 |
hidden_os=None,
|
582 |
blacklisted_os=None,
|
583 |
primary_ip_family=None,
|
584 |
prealloc_wipe_disks=None,
|
585 |
enabled_disk_templates=list(constants.DISK_TEMPLATE_PREFERENCE),
|
586 |
) |
587 |
self._cluster.ctime = self._cluster.mtime = time.time() |
588 |
self._cluster.UpgradeConfig()
|
589 |
self._config_data.cluster = self._cluster |
590 |
|
591 |
self._default_group = self.AddNewNodeGroup(name="default") |
592 |
self._master_node = self.AddNewNode(uuid=master_node_uuid) |
593 |
|
594 |
def _WriteConfig(self, destination=None, feedback_fn=None): |
595 |
pass
|
596 |
|
597 |
def _DistributeConfig(self, feedback_fn): |
598 |
pass
|
599 |
|
600 |
def _GetRpc(self, address_list): |
601 |
raise AssertionError("This should not be used during tests!") |