Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / testsupport / config_mock.py @ a5efec93

History | View | Annotate | Download (19 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
from ganeti.network import AddressPool
32

    
33
import mocks
34

    
35

    
36
def _StubGetEntResolver():
37
  return mocks.FakeGetentResolver()
38

    
39

    
40
# pylint: disable=R0904
41
class ConfigMock(config.ConfigWriter):
42
  """A mocked cluster configuration with added methods for easy customization.
43

44
  """
45

    
46
  def __init__(self):
47
    self._cur_group_id = 1
48
    self._cur_node_id = 1
49
    self._cur_inst_id = 1
50
    self._cur_disk_id = 1
51
    self._cur_os_id = 1
52
    self._cur_nic_id = 1
53
    self._cur_net_id = 1
54
    self._default_os = None
55

    
56
    super(ConfigMock, self).__init__(cfg_file="/dev/null",
57
                                     _getents=_StubGetEntResolver())
58

    
59
  def _GetUuid(self):
60
    return str(uuid_module.uuid4())
61

    
62
  def _GetObjUuid(self, obj):
63
    if obj is None:
64
      return None
65
    elif isinstance(obj, objects.ConfigObject):
66
      return obj.uuid
67
    else:
68
      return obj
69

    
70
  def AddNewNodeGroup(self,
71
                      uuid=None,
72
                      name=None,
73
                      ndparams=None,
74
                      diskparams=None,
75
                      ipolicy=None,
76
                      hv_state_static=None,
77
                      disk_state_static=None,
78
                      alloc_policy=None,
79
                      networks=None):
80
    """Add a new L{objects.NodeGroup} to the cluster configuration
81

82
    See L{objects.NodeGroup} for parameter documentation.
83

84
    @rtype: L{objects.NodeGroup}
85
    @return: the newly added node group
86

87
    """
88
    group_id = self._cur_group_id
89
    self._cur_group_id += 1
90

    
91
    if uuid is None:
92
      uuid = self._GetUuid()
93
    if name is None:
94
      name = "mock_group_%d" % group_id
95
    if networks is None:
96
      networks = {}
97

    
98
    group = objects.NodeGroup(uuid=uuid,
99
                              name=name,
100
                              ndparams=ndparams,
101
                              diskparams=diskparams,
102
                              ipolicy=ipolicy,
103
                              hv_state_static=hv_state_static,
104
                              disk_state_static=disk_state_static,
105
                              alloc_policy=alloc_policy,
106
                              networks=networks,
107
                              members=[])
108

    
109
    self.AddNodeGroup(group, None)
110
    return group
111

    
112
  # pylint: disable=R0913
113
  def AddNewNode(self,
114
                 uuid=None,
115
                 name=None,
116
                 primary_ip=None,
117
                 secondary_ip=None,
118
                 master_candidate=True,
119
                 offline=False,
120
                 drained=False,
121
                 group=None,
122
                 master_capable=True,
123
                 vm_capable=True,
124
                 ndparams=None,
125
                 powered=True,
126
                 hv_state=None,
127
                 hv_state_static=None,
128
                 disk_state=None,
129
                 disk_state_static=None):
130
    """Add a new L{objects.Node} to the cluster configuration
131

132
    See L{objects.Node} for parameter documentation.
133

134
    @rtype: L{objects.Node}
135
    @return: the newly added node
136

137
    """
138
    node_id = self._cur_node_id
139
    self._cur_node_id += 1
140

    
141
    if uuid is None:
142
      uuid = self._GetUuid()
143
    if name is None:
144
      name = "mock_node_%d.example.com" % node_id
145
    if primary_ip is None:
146
      primary_ip = "192.0.2.%d" % node_id
147
    if secondary_ip is None:
148
      secondary_ip = "203.0.113.%d" % node_id
149
    if group is None:
150
      group = self._default_group.uuid
151
    group = self._GetObjUuid(group)
152
    if ndparams is None:
153
      ndparams = {}
154

    
155
    node = objects.Node(uuid=uuid,
156
                        name=name,
157
                        primary_ip=primary_ip,
158
                        secondary_ip=secondary_ip,
159
                        master_candidate=master_candidate,
160
                        offline=offline,
161
                        drained=drained,
162
                        group=group,
163
                        master_capable=master_capable,
164
                        vm_capable=vm_capable,
165
                        ndparams=ndparams,
166
                        powered=powered,
167
                        hv_state=hv_state,
168
                        hv_state_static=hv_state_static,
169
                        disk_state=disk_state,
170
                        disk_state_static=disk_state_static)
171

    
172
    self.AddNode(node, None)
173
    return node
174

    
175
  def AddNewInstance(self,
176
                     uuid=None,
177
                     name=None,
178
                     primary_node=None,
179
                     os=None,
180
                     hypervisor=None,
181
                     hvparams=None,
182
                     beparams=None,
183
                     osparams=None,
184
                     osparams_private=None,
185
                     admin_state=None,
186
                     nics=None,
187
                     disks=None,
188
                     disk_template=None,
189
                     disks_active=None,
190
                     network_port=None,
191
                     secondary_node=None):
192
    """Add a new L{objects.Instance} to the cluster configuration
193

194
    See L{objects.Instance} for parameter documentation.
195

196
    @rtype: L{objects.Instance}
197
    @return: the newly added instance
198

199
    """
200
    inst_id = self._cur_inst_id
201
    self._cur_inst_id += 1
202

    
203
    if uuid is None:
204
      uuid = self._GetUuid()
205
    if name is None:
206
      name = "mock_inst_%d.example.com" % inst_id
207
    if primary_node is None:
208
      primary_node = self._master_node.uuid
209
    primary_node = self._GetObjUuid(primary_node)
210
    if os is None:
211
      os = self.GetDefaultOs().name + objects.OS.VARIANT_DELIM +\
212
           self.GetDefaultOs().supported_variants[0]
213
    if hypervisor is None:
214
      hypervisor = self.GetClusterInfo().enabled_hypervisors[0]
215
    if hvparams is None:
216
      hvparams = {}
217
    if beparams is None:
218
      beparams = {}
219
    if osparams is None:
220
      osparams = {}
221
    if osparams_private is None:
222
      osparams_private = {}
223
    if admin_state is None:
224
      admin_state = constants.ADMINST_DOWN
225
    if nics is None:
226
      nics = [self.CreateNic()]
227
    if disk_template is None:
228
      if disks is None:
229
        # user chose nothing, so create a plain disk for him
230
        disk_template = constants.DT_PLAIN
231
      elif len(disks) == 0:
232
        disk_template = constants.DT_DISKLESS
233
      else:
234
        disk_template = disks[0].dev_type
235
    if disks is None:
236
      if disk_template == constants.DT_DISKLESS:
237
        disks = []
238
      else:
239
        disks = [self.CreateDisk(dev_type=disk_template,
240
                                 primary_node=primary_node,
241
                                 secondary_node=secondary_node)]
242
    if disks_active is None:
243
      disks_active = admin_state == constants.ADMINST_UP
244

    
245
    inst = objects.Instance(uuid=uuid,
246
                            name=name,
247
                            primary_node=primary_node,
248
                            os=os,
249
                            hypervisor=hypervisor,
250
                            hvparams=hvparams,
251
                            beparams=beparams,
252
                            osparams=osparams,
253
                            osparams_private=osparams_private,
254
                            admin_state=admin_state,
255
                            nics=nics,
256
                            disks=disks,
257
                            disk_template=disk_template,
258
                            disks_active=disks_active,
259
                            network_port=network_port)
260
    self.AddInstance(inst, None)
261
    return inst
262

    
263
  def AddNewNetwork(self,
264
                    uuid=None,
265
                    name=None,
266
                    mac_prefix=None,
267
                    network=None,
268
                    network6=None,
269
                    gateway=None,
270
                    gateway6=None,
271
                    reservations=None,
272
                    ext_reservations=None):
273
    """Add a new L{objects.Network} to the cluster configuration
274

275
    See L{objects.Network} for parameter documentation.
276

277
    @rtype: L{objects.Network}
278
    @return: the newly added network
279

280
    """
281
    net_id = self._cur_net_id
282
    self._cur_net_id += 1
283

    
284
    if uuid is None:
285
      uuid = self._GetUuid()
286
    if name is None:
287
      name = "mock_net_%d" % net_id
288
    if network is None:
289
      network = "198.51.100.0/24"
290
    if gateway is None:
291
      if network[-3:] == "/24":
292
        gateway = network[:-4] + "1"
293
      else:
294
        gateway = "198.51.100.1"
295
    if network[-3:] == "/24" and gateway == network[:-4] + "1":
296
      if reservations is None:
297
        reservations = "0" * 256
298
      if ext_reservations:
299
        ext_reservations = "11" + ("0" * 253) + "1"
300
    elif reservations is None or ext_reservations is None:
301
      raise AssertionError("You have to specify 'reservations' and"
302
                           " 'ext_reservations'!")
303

    
304
    net = objects.Network(uuid=uuid,
305
                          name=name,
306
                          mac_prefix=mac_prefix,
307
                          network=network,
308
                          network6=network6,
309
                          gateway=gateway,
310
                          gateway6=gateway6,
311
                          reservations=reservations,
312
                          ext_reservations=ext_reservations)
313
    self.AddNetwork(net, None)
314
    return net
315

    
316
  def ConnectNetworkToGroup(self, net, group, netparams=None):
317
    """Connect the given network to the group.
318

319
    @type net: string or L{objects.Network}
320
    @param net: network object or UUID
321
    @type group: string of L{objects.NodeGroup}
322
    @param group: node group object of UUID
323
    @type netparams: dict
324
    @param netparams: network parameters for this connection
325

326
    """
327
    net_obj = None
328
    if isinstance(net, objects.Network):
329
      net_obj = net
330
    else:
331
      net_obj = self.GetNetwork(net)
332

    
333
    group_obj = None
334
    if isinstance(group, objects.NodeGroup):
335
      group_obj = group
336
    else:
337
      group_obj = self.GetNodeGroup(group)
338

    
339
    if net_obj is None or group_obj is None:
340
      raise AssertionError("Failed to get network or node group")
341

    
342
    if netparams is None:
343
      netparams = {
344
        constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
345
        constants.NIC_LINK: "br_mock"
346
      }
347

    
348
    group_obj.networks[net_obj.uuid] = netparams
349

    
350
  def CreateDisk(self,
351
                 uuid=None,
352
                 name=None,
353
                 dev_type=constants.DT_PLAIN,
354
                 logical_id=None,
355
                 children=None,
356
                 iv_name=None,
357
                 size=1024,
358
                 mode=constants.DISK_RDWR,
359
                 params=None,
360
                 spindles=None,
361
                 primary_node=None,
362
                 secondary_node=None,
363
                 create_nodes=False,
364
                 instance_disk_index=0):
365
    """Create a new L{objecs.Disk} object
366

367
    @rtype: L{objects.Disk}
368
    @return: the newly create disk object
369

370
    """
371
    disk_id = self._cur_disk_id
372
    self._cur_disk_id += 1
373

    
374
    if uuid is None:
375
      uuid = self._GetUuid()
376
    if name is None:
377
      name = "mock_disk_%d" % disk_id
378

    
379
    if dev_type == constants.DT_DRBD8:
380
      pnode_uuid = self._GetObjUuid(primary_node)
381
      snode_uuid = self._GetObjUuid(secondary_node)
382
      if logical_id is not None:
383
        pnode_uuid = logical_id[0]
384
        snode_uuid = logical_id[1]
385

    
386
      if pnode_uuid is None and create_nodes:
387
        pnode_uuid = self.AddNewNode().uuid
388
      if snode_uuid is None and create_nodes:
389
        snode_uuid = self.AddNewNode().uuid
390

    
391
      if pnode_uuid is None or snode_uuid is None:
392
        raise AssertionError("Trying to create DRBD disk without nodes!")
393

    
394
      if logical_id is None:
395
        logical_id = (pnode_uuid, snode_uuid,
396
                      constants.FIRST_DRBD_PORT + disk_id,
397
                      disk_id, disk_id, "mock_secret")
398
      if children is None:
399
        data_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
400
                                     size=size)
401
        meta_child = self.CreateDisk(dev_type=constants.DT_PLAIN,
402
                                     size=constants.DRBD_META_SIZE)
403
        children = [data_child, meta_child]
404
    elif dev_type == constants.DT_PLAIN:
405
      if logical_id is None:
406
        logical_id = ("mockvg", "mock_disk_%d" % disk_id)
407
    elif dev_type in constants.DTS_FILEBASED:
408
      if logical_id is None:
409
        logical_id = (constants.FD_LOOP, "/file/storage/disk%d" % disk_id)
410
    elif dev_type == constants.DT_BLOCK:
411
      if logical_id is None:
412
        logical_id = (constants.BLOCKDEV_DRIVER_MANUAL,
413
                      "/dev/disk/disk%d" % disk_id)
414
    elif logical_id is None:
415
      raise NotImplementedError
416
    if children is None:
417
      children = []
418
    if iv_name is None:
419
      iv_name = "disk/%d" % instance_disk_index
420
    if params is None:
421
      params = {}
422

    
423
    return objects.Disk(uuid=uuid,
424
                        name=name,
425
                        dev_type=dev_type,
426
                        logical_id=logical_id,
427
                        children=children,
428
                        iv_name=iv_name,
429
                        size=size,
430
                        mode=mode,
431
                        params=params,
432
                        spindles=spindles)
433

    
434
  def GetDefaultOs(self):
435
    if self._default_os is None:
436
      self._default_os = self.CreateOs(name="mocked_os")
437
    return self._default_os
438

    
439
  def CreateOs(self,
440
               name=None,
441
               path=None,
442
               api_versions=None,
443
               create_script=None,
444
               export_script=None,
445
               import_script=None,
446
               rename_script=None,
447
               verify_script=None,
448
               supported_variants=None,
449
               supported_parameters=None):
450
    """Create a new L{objects.OS} object
451

452
    @rtype: L{object.OS}
453
    @return: the newly create OS objects
454

455
    """
456
    os_id = self._cur_os_id
457
    self._cur_os_id += 1
458

    
459
    if name is None:
460
      name = "mock_os_%d" % os_id
461
    if path is None:
462
      path = "/mocked/path/%d" % os_id
463
    if api_versions is None:
464
      api_versions = [constants.OS_API_V20]
465
    if create_script is None:
466
      create_script = "mock_create.sh"
467
    if export_script is None:
468
      export_script = "mock_export.sh"
469
    if import_script is None:
470
      import_script = "mock_import.sh"
471
    if rename_script is None:
472
      rename_script = "mock_rename.sh"
473
    if verify_script is None:
474
      verify_script = "mock_verify.sh"
475
    if supported_variants is None:
476
      supported_variants = ["default"]
477
    if supported_parameters is None:
478
      supported_parameters = ["mock_param"]
479

    
480
    return objects.OS(name=name,
481
                      path=path,
482
                      api_versions=api_versions,
483
                      create_script=create_script,
484
                      export_script=export_script,
485
                      import_script=import_script,
486
                      rename_script=rename_script,
487
                      verify_script=verify_script,
488
                      supported_variants=supported_variants,
489
                      supported_parameters=supported_parameters)
490

    
491
  def CreateNic(self,
492
                uuid=None,
493
                name=None,
494
                mac=None,
495
                ip=None,
496
                network=None,
497
                nicparams=None,
498
                netinfo=None):
499
    """Create a new L{objecs.NIC} object
500

501
    @rtype: L{objects.NIC}
502
    @return: the newly create NIC object
503

504
    """
505
    nic_id = self._cur_nic_id
506
    self._cur_nic_id += 1
507

    
508
    if uuid is None:
509
      uuid = self._GetUuid()
510
    if name is None:
511
      name = "mock_nic_%d" % nic_id
512
    if mac is None:
513
      mac = "aa:00:00:aa:%02x:%02x" % (nic_id / 0xff, nic_id % 0xff)
514
    if isinstance(network, objects.Network):
515
      if ip:
516
        pool = AddressPool(network)
517
        pool.Reserve(ip)
518
      network = network.uuid
519
    if nicparams is None:
520
      nicparams = {}
521

    
522
    return objects.NIC(uuid=uuid,
523
                       name=name,
524
                       mac=mac,
525
                       ip=ip,
526
                       network=network,
527
                       nicparams=nicparams,
528
                       netinfo=netinfo)
529

    
530
  def SetEnabledDiskTemplates(self, enabled_disk_templates):
531
    """Set the enabled disk templates in the cluster.
532

533
    This also takes care of required IPolicy updates.
534

535
    @type enabled_disk_templates: list of string
536
    @param enabled_disk_templates: list of disk templates to enable
537

538
    """
539
    cluster = self.GetClusterInfo()
540
    cluster.enabled_disk_templates = list(enabled_disk_templates)
541
    cluster.ipolicy[constants.IPOLICY_DTS] = list(enabled_disk_templates)
542

    
543
  def _OpenConfig(self, accept_foreign):
544
    self._config_data = objects.ConfigData(
545
      version=constants.CONFIG_VERSION,
546
      cluster=None,
547
      nodegroups={},
548
      nodes={},
549
      instances={},
550
      networks={})
551

    
552
    master_node_uuid = self._GetUuid()
553

    
554
    self._cluster = objects.Cluster(
555
      serial_no=1,
556
      rsahostkeypub="",
557
      highest_used_port=(constants.FIRST_DRBD_PORT - 1),
558
      tcpudp_port_pool=set(),
559
      mac_prefix="aa:00:00",
560
      volume_group_name="xenvg",
561
      reserved_lvs=None,
562
      drbd_usermode_helper="/bin/true",
563
      master_node=master_node_uuid,
564
      master_ip="192.0.2.254",
565
      master_netdev=constants.DEFAULT_BRIDGE,
566
      master_netmask=None,
567
      use_external_mip_script=None,
568
      cluster_name="cluster.example.com",
569
      file_storage_dir="/tmp",
570
      shared_file_storage_dir=None,
571
      enabled_hypervisors=[constants.HT_XEN_HVM, constants.HT_XEN_PVM,
572
                           constants.HT_KVM],
573
      hvparams=constants.HVC_DEFAULTS.copy(),
574
      ipolicy=None,
575
      os_hvp={self.GetDefaultOs().name: constants.HVC_DEFAULTS.copy()},
576
      beparams=None,
577
      osparams=None,
578
      osparams_private_cluster=None,
579
      nicparams={constants.PP_DEFAULT: constants.NICC_DEFAULTS},
580
      ndparams=None,
581
      diskparams=None,
582
      candidate_pool_size=3,
583
      modify_etc_hosts=False,
584
      modify_ssh_setup=False,
585
      maintain_node_health=False,
586
      uid_pool=None,
587
      default_iallocator="mock_iallocator",
588
      hidden_os=None,
589
      blacklisted_os=None,
590
      primary_ip_family=None,
591
      prealloc_wipe_disks=None,
592
      enabled_disk_templates=list(constants.DISK_TEMPLATE_PREFERENCE),
593
      )
594
    self._cluster.ctime = self._cluster.mtime = time.time()
595
    self._cluster.UpgradeConfig()
596
    self._config_data.cluster = self._cluster
597

    
598
    self._default_group = self.AddNewNodeGroup(name="default")
599
    self._master_node = self.AddNewNode(uuid=master_node_uuid)
600

    
601
  def _WriteConfig(self, destination=None, feedback_fn=None):
602
    pass
603

    
604
  def _DistributeConfig(self, feedback_fn):
605
    pass
606

    
607
  def _GetRpc(self, address_list):
608
    raise AssertionError("This should not be used during tests!")