Statistics
| Branch: | Tag: | Revision:

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!")