Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cmdlib_unittest.py @ 0c77c331

History | View | Annotate | Download (42.6 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2008, 2011, 2012 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
"""Script for unittesting the cmdlib module"""
23

    
24

    
25
import os
26
import unittest
27
import time
28
import tempfile
29
import shutil
30
import operator
31
import itertools
32
import copy
33

    
34
from ganeti import constants
35
from ganeti import mcpu
36
from ganeti import cmdlib
37
from ganeti import opcodes
38
from ganeti import errors
39
from ganeti import utils
40
from ganeti import luxi
41
from ganeti import ht
42
from ganeti import objects
43
from ganeti import compat
44
from ganeti import rpc
45
from ganeti.hypervisor import hv_xen
46

    
47
import testutils
48
import mocks
49

    
50

    
51
class TestCertVerification(testutils.GanetiTestCase):
52
  def setUp(self):
53
    testutils.GanetiTestCase.setUp(self)
54

    
55
    self.tmpdir = tempfile.mkdtemp()
56

    
57
  def tearDown(self):
58
    shutil.rmtree(self.tmpdir)
59

    
60
  def testVerifyCertificate(self):
61
    cmdlib._VerifyCertificate(self._TestDataFilename("cert1.pem"))
62

    
63
    nonexist_filename = os.path.join(self.tmpdir, "does-not-exist")
64

    
65
    (errcode, msg) = cmdlib._VerifyCertificate(nonexist_filename)
66
    self.assertEqual(errcode, cmdlib.LUClusterVerifyConfig.ETYPE_ERROR)
67

    
68
    # Try to load non-certificate file
69
    invalid_cert = self._TestDataFilename("bdev-net.txt")
70
    (errcode, msg) = cmdlib._VerifyCertificate(invalid_cert)
71
    self.assertEqual(errcode, cmdlib.LUClusterVerifyConfig.ETYPE_ERROR)
72

    
73

    
74
class TestOpcodeParams(testutils.GanetiTestCase):
75
  def testParamsStructures(self):
76
    for op in sorted(mcpu.Processor.DISPATCH_TABLE):
77
      lu = mcpu.Processor.DISPATCH_TABLE[op]
78
      lu_name = lu.__name__
79
      self.failIf(hasattr(lu, "_OP_REQP"),
80
                  msg=("LU '%s' has old-style _OP_REQP" % lu_name))
81
      self.failIf(hasattr(lu, "_OP_DEFS"),
82
                  msg=("LU '%s' has old-style _OP_DEFS" % lu_name))
83
      self.failIf(hasattr(lu, "_OP_PARAMS"),
84
                  msg=("LU '%s' has old-style _OP_PARAMS" % lu_name))
85

    
86

    
87
class TestIAllocatorChecks(testutils.GanetiTestCase):
88
  def testFunction(self):
89
    class TestLU(object):
90
      def __init__(self, opcode):
91
        self.cfg = mocks.FakeConfig()
92
        self.op = opcode
93

    
94
    class OpTest(opcodes.OpCode):
95
       OP_PARAMS = [
96
        ("iallocator", None, ht.NoType, None),
97
        ("node", None, ht.NoType, None),
98
        ]
99

    
100
    default_iallocator = mocks.FakeConfig().GetDefaultIAllocator()
101
    other_iallocator = default_iallocator + "_not"
102

    
103
    op = OpTest()
104
    lu = TestLU(op)
105

    
106
    c_i = lambda: cmdlib._CheckIAllocatorOrNode(lu, "iallocator", "node")
107

    
108
    # Neither node nor iallocator given
109
    op.iallocator = None
110
    op.node = None
111
    c_i()
112
    self.assertEqual(lu.op.iallocator, default_iallocator)
113
    self.assertEqual(lu.op.node, None)
114

    
115
    # Both, iallocator and node given
116
    op.iallocator = "test"
117
    op.node = "test"
118
    self.assertRaises(errors.OpPrereqError, c_i)
119

    
120
    # Only iallocator given
121
    op.iallocator = other_iallocator
122
    op.node = None
123
    c_i()
124
    self.assertEqual(lu.op.iallocator, other_iallocator)
125
    self.assertEqual(lu.op.node, None)
126

    
127
    # Only node given
128
    op.iallocator = None
129
    op.node = "node"
130
    c_i()
131
    self.assertEqual(lu.op.iallocator, None)
132
    self.assertEqual(lu.op.node, "node")
133

    
134
    # No node, iallocator or default iallocator
135
    op.iallocator = None
136
    op.node = None
137
    lu.cfg.GetDefaultIAllocator = lambda: None
138
    self.assertRaises(errors.OpPrereqError, c_i)
139

    
140

    
141
class TestLUTestJqueue(unittest.TestCase):
142
  def test(self):
143
    self.assert_(cmdlib.LUTestJqueue._CLIENT_CONNECT_TIMEOUT <
144
                 (luxi.WFJC_TIMEOUT * 0.75),
145
                 msg=("Client timeout too high, might not notice bugs"
146
                      " in WaitForJobChange"))
147

    
148

    
149
class TestLUQuery(unittest.TestCase):
150
  def test(self):
151
    self.assertEqual(sorted(cmdlib._QUERY_IMPL.keys()),
152
                     sorted(constants.QR_VIA_OP))
153

    
154
    assert constants.QR_NODE in constants.QR_VIA_OP
155
    assert constants.QR_INSTANCE in constants.QR_VIA_OP
156

    
157
    for i in constants.QR_VIA_OP:
158
      self.assert_(cmdlib._GetQueryImplementation(i))
159

    
160
    self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation, "")
161
    self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation,
162
                      "xyz")
163

    
164

    
165
class TestLUGroupAssignNodes(unittest.TestCase):
166

    
167
  def testCheckAssignmentForSplitInstances(self):
168
    node_data = dict((name, objects.Node(name=name, group=group))
169
                     for (name, group) in [("n1a", "g1"), ("n1b", "g1"),
170
                                           ("n2a", "g2"), ("n2b", "g2"),
171
                                           ("n3a", "g3"), ("n3b", "g3"),
172
                                           ("n3c", "g3"),
173
                                           ])
174

    
175
    def Instance(name, pnode, snode):
176
      if snode is None:
177
        disks = []
178
        disk_template = constants.DT_DISKLESS
179
      else:
180
        disks = [objects.Disk(dev_type=constants.LD_DRBD8,
181
                              logical_id=[pnode, snode, 1, 17, 17])]
182
        disk_template = constants.DT_DRBD8
183

    
184
      return objects.Instance(name=name, primary_node=pnode, disks=disks,
185
                              disk_template=disk_template)
186

    
187
    instance_data = dict((name, Instance(name, pnode, snode))
188
                         for name, pnode, snode in [("inst1a", "n1a", "n1b"),
189
                                                    ("inst1b", "n1b", "n1a"),
190
                                                    ("inst2a", "n2a", "n2b"),
191
                                                    ("inst3a", "n3a", None),
192
                                                    ("inst3b", "n3b", "n1b"),
193
                                                    ("inst3c", "n3b", "n2b"),
194
                                                    ])
195

    
196
    # Test first with the existing state.
197
    (new, prev) = \
198
      cmdlib.LUGroupAssignNodes.CheckAssignmentForSplitInstances([],
199
                                                                 node_data,
200
                                                                 instance_data)
201

    
202
    self.assertEqual([], new)
203
    self.assertEqual(set(["inst3b", "inst3c"]), set(prev))
204

    
205
    # And now some changes.
206
    (new, prev) = \
207
      cmdlib.LUGroupAssignNodes.CheckAssignmentForSplitInstances([("n1b",
208
                                                                   "g3")],
209
                                                                 node_data,
210
                                                                 instance_data)
211

    
212
    self.assertEqual(set(["inst1a", "inst1b"]), set(new))
213
    self.assertEqual(set(["inst3c"]), set(prev))
214

    
215

    
216
class TestClusterVerifySsh(unittest.TestCase):
217
  def testMultipleGroups(self):
218
    fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes
219
    mygroupnodes = [
220
      objects.Node(name="node20", group="my", offline=False),
221
      objects.Node(name="node21", group="my", offline=False),
222
      objects.Node(name="node22", group="my", offline=False),
223
      objects.Node(name="node23", group="my", offline=False),
224
      objects.Node(name="node24", group="my", offline=False),
225
      objects.Node(name="node25", group="my", offline=False),
226
      objects.Node(name="node26", group="my", offline=True),
227
      ]
228
    nodes = [
229
      objects.Node(name="node1", group="g1", offline=True),
230
      objects.Node(name="node2", group="g1", offline=False),
231
      objects.Node(name="node3", group="g1", offline=False),
232
      objects.Node(name="node4", group="g1", offline=True),
233
      objects.Node(name="node5", group="g1", offline=False),
234
      objects.Node(name="node10", group="xyz", offline=False),
235
      objects.Node(name="node11", group="xyz", offline=False),
236
      objects.Node(name="node40", group="alloff", offline=True),
237
      objects.Node(name="node41", group="alloff", offline=True),
238
      objects.Node(name="node50", group="aaa", offline=False),
239
      ] + mygroupnodes
240
    assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
241

    
242
    (online, perhost) = fn(mygroupnodes, "my", nodes)
243
    self.assertEqual(online, ["node%s" % i for i in range(20, 26)])
244
    self.assertEqual(set(perhost.keys()), set(online))
245

    
246
    self.assertEqual(perhost, {
247
      "node20": ["node10", "node2", "node50"],
248
      "node21": ["node11", "node3", "node50"],
249
      "node22": ["node10", "node5", "node50"],
250
      "node23": ["node11", "node2", "node50"],
251
      "node24": ["node10", "node3", "node50"],
252
      "node25": ["node11", "node5", "node50"],
253
      })
254

    
255
  def testSingleGroup(self):
256
    fn = cmdlib.LUClusterVerifyGroup._SelectSshCheckNodes
257
    nodes = [
258
      objects.Node(name="node1", group="default", offline=True),
259
      objects.Node(name="node2", group="default", offline=False),
260
      objects.Node(name="node3", group="default", offline=False),
261
      objects.Node(name="node4", group="default", offline=True),
262
      ]
263
    assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
264

    
265
    (online, perhost) = fn(nodes, "default", nodes)
266
    self.assertEqual(online, ["node2", "node3"])
267
    self.assertEqual(set(perhost.keys()), set(online))
268

    
269
    self.assertEqual(perhost, {
270
      "node2": [],
271
      "node3": [],
272
      })
273

    
274

    
275
class TestClusterVerifyFiles(unittest.TestCase):
276
  @staticmethod
277
  def _FakeErrorIf(errors, cond, ecode, item, msg, *args, **kwargs):
278
    assert ((ecode == constants.CV_ENODEFILECHECK and
279
             ht.TNonEmptyString(item)) or
280
            (ecode == constants.CV_ECLUSTERFILECHECK and
281
             item is None))
282

    
283
    if args:
284
      msg = msg % args
285

    
286
    if cond:
287
      errors.append((item, msg))
288

    
289
  _VerifyFiles = cmdlib.LUClusterVerifyGroup._VerifyFiles
290

    
291
  def test(self):
292
    errors = []
293
    master_name = "master.example.com"
294
    nodeinfo = [
295
      objects.Node(name=master_name, offline=False, vm_capable=True),
296
      objects.Node(name="node2.example.com", offline=False, vm_capable=True),
297
      objects.Node(name="node3.example.com", master_candidate=True,
298
                   vm_capable=False),
299
      objects.Node(name="node4.example.com", offline=False, vm_capable=True),
300
      objects.Node(name="nodata.example.com", offline=False, vm_capable=True),
301
      objects.Node(name="offline.example.com", offline=True),
302
      ]
303
    cluster = objects.Cluster(modify_etc_hosts=True,
304
                              enabled_hypervisors=[constants.HT_XEN_HVM])
305
    files_all = set([
306
      constants.CLUSTER_DOMAIN_SECRET_FILE,
307
      constants.RAPI_CERT_FILE,
308
      constants.RAPI_USERS_FILE,
309
      ])
310
    files_opt = set([
311
      constants.RAPI_USERS_FILE,
312
      hv_xen.XL_CONFIG_FILE,
313
      constants.VNC_PASSWORD_FILE,
314
      ])
315
    files_mc = set([
316
      constants.CLUSTER_CONF_FILE,
317
      ])
318
    files_vm = set([
319
      hv_xen.XEND_CONFIG_FILE,
320
      hv_xen.XL_CONFIG_FILE,
321
      constants.VNC_PASSWORD_FILE,
322
      ])
323
    nvinfo = {
324
      master_name: rpc.RpcResult(data=(True, {
325
        constants.NV_FILELIST: {
326
          constants.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
327
          constants.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
328
          constants.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
329
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
330
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
331
        }})),
332
      "node2.example.com": rpc.RpcResult(data=(True, {
333
        constants.NV_FILELIST: {
334
          constants.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
335
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
336
          }
337
        })),
338
      "node3.example.com": rpc.RpcResult(data=(True, {
339
        constants.NV_FILELIST: {
340
          constants.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
341
          constants.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
342
          }
343
        })),
344
      "node4.example.com": rpc.RpcResult(data=(True, {
345
        constants.NV_FILELIST: {
346
          constants.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
347
          constants.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
348
          constants.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
349
          constants.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
350
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
351
          }
352
        })),
353
      "nodata.example.com": rpc.RpcResult(data=(True, {})),
354
      "offline.example.com": rpc.RpcResult(offline=True),
355
      }
356
    assert set(nvinfo.keys()) == set(map(operator.attrgetter("name"), nodeinfo))
357

    
358
    self._VerifyFiles(compat.partial(self._FakeErrorIf, errors), nodeinfo,
359
                      master_name, nvinfo,
360
                      (files_all, files_opt, files_mc, files_vm))
361
    self.assertEqual(sorted(errors), sorted([
362
      (None, ("File %s found with 2 different checksums (variant 1 on"
363
              " node2.example.com, node3.example.com, node4.example.com;"
364
              " variant 2 on master.example.com)" % constants.RAPI_CERT_FILE)),
365
      (None, ("File %s is missing from node(s) node2.example.com" %
366
              constants.CLUSTER_DOMAIN_SECRET_FILE)),
367
      (None, ("File %s should not exist on node(s) node4.example.com" %
368
              constants.CLUSTER_CONF_FILE)),
369
      (None, ("File %s is missing from node(s) node4.example.com" %
370
              hv_xen.XEND_CONFIG_FILE)),
371
      (None, ("File %s is missing from node(s) node3.example.com" %
372
              constants.CLUSTER_CONF_FILE)),
373
      (None, ("File %s found with 2 different checksums (variant 1 on"
374
              " master.example.com; variant 2 on node4.example.com)" %
375
              constants.CLUSTER_CONF_FILE)),
376
      (None, ("File %s is optional, but it must exist on all or no nodes (not"
377
              " found on master.example.com, node2.example.com,"
378
              " node3.example.com)" % constants.RAPI_USERS_FILE)),
379
      (None, ("File %s is optional, but it must exist on all or no nodes (not"
380
              " found on node2.example.com)" % hv_xen.XL_CONFIG_FILE)),
381
      ("nodata.example.com", "Node did not return file checksum data"),
382
      ]))
383

    
384

    
385
class _FakeLU:
386
  def __init__(self, cfg=NotImplemented, proc=NotImplemented):
387
    self.warning_log = []
388
    self.info_log = []
389
    self.cfg = cfg
390
    self.proc = proc
391

    
392
  def LogWarning(self, text, *args):
393
    self.warning_log.append((text, args))
394

    
395
  def LogInfo(self, text, *args):
396
    self.info_log.append((text, args))
397

    
398

    
399
class TestLoadNodeEvacResult(unittest.TestCase):
400
  def testSuccess(self):
401
    for moved in [[], [
402
      ("inst20153.example.com", "grp2", ["nodeA4509", "nodeB2912"]),
403
      ]]:
404
      for early_release in [False, True]:
405
        for use_nodes in [False, True]:
406
          jobs = [
407
            [opcodes.OpInstanceReplaceDisks().__getstate__()],
408
            [opcodes.OpInstanceMigrate().__getstate__()],
409
            ]
410

    
411
          alloc_result = (moved, [], jobs)
412
          assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
413

    
414
          lu = _FakeLU()
415
          result = cmdlib._LoadNodeEvacResult(lu, alloc_result,
416
                                              early_release, use_nodes)
417

    
418
          if moved:
419
            (_, (info_args, )) = lu.info_log.pop(0)
420
            for (instname, instgroup, instnodes) in moved:
421
              self.assertTrue(instname in info_args)
422
              if use_nodes:
423
                for i in instnodes:
424
                  self.assertTrue(i in info_args)
425
              else:
426
                self.assertTrue(instgroup in info_args)
427

    
428
          self.assertFalse(lu.info_log)
429
          self.assertFalse(lu.warning_log)
430

    
431
          for op in itertools.chain(*result):
432
            if hasattr(op.__class__, "early_release"):
433
              self.assertEqual(op.early_release, early_release)
434
            else:
435
              self.assertFalse(hasattr(op, "early_release"))
436

    
437
  def testFailed(self):
438
    alloc_result = ([], [
439
      ("inst5191.example.com", "errormsg21178"),
440
      ], [])
441
    assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
442

    
443
    lu = _FakeLU()
444
    self.assertRaises(errors.OpExecError, cmdlib._LoadNodeEvacResult,
445
                      lu, alloc_result, False, False)
446
    self.assertFalse(lu.info_log)
447
    (_, (args, )) = lu.warning_log.pop(0)
448
    self.assertTrue("inst5191.example.com" in args)
449
    self.assertTrue("errormsg21178" in args)
450
    self.assertFalse(lu.warning_log)
451

    
452

    
453
class TestUpdateAndVerifySubDict(unittest.TestCase):
454
  def setUp(self):
455
    self.type_check = {
456
        "a": constants.VTYPE_INT,
457
        "b": constants.VTYPE_STRING,
458
        "c": constants.VTYPE_BOOL,
459
        "d": constants.VTYPE_STRING,
460
        }
461

    
462
  def test(self):
463
    old_test = {
464
      "foo": {
465
        "d": "blubb",
466
        "a": 321,
467
        },
468
      "baz": {
469
        "a": 678,
470
        "b": "678",
471
        "c": True,
472
        },
473
      }
474
    test = {
475
      "foo": {
476
        "a": 123,
477
        "b": "123",
478
        "c": True,
479
        },
480
      "bar": {
481
        "a": 321,
482
        "b": "321",
483
        "c": False,
484
        },
485
      }
486

    
487
    mv = {
488
      "foo": {
489
        "a": 123,
490
        "b": "123",
491
        "c": True,
492
        "d": "blubb"
493
        },
494
      "bar": {
495
        "a": 321,
496
        "b": "321",
497
        "c": False,
498
        },
499
      "baz": {
500
        "a": 678,
501
        "b": "678",
502
        "c": True,
503
        },
504
      }
505

    
506
    verified = cmdlib._UpdateAndVerifySubDict(old_test, test, self.type_check)
507
    self.assertEqual(verified, mv)
508

    
509
  def testWrong(self):
510
    test = {
511
      "foo": {
512
        "a": "blubb",
513
        "b": "123",
514
        "c": True,
515
        },
516
      "bar": {
517
        "a": 321,
518
        "b": "321",
519
        "c": False,
520
        },
521
      }
522

    
523
    self.assertRaises(errors.TypeEnforcementError,
524
                      cmdlib._UpdateAndVerifySubDict, {}, test, self.type_check)
525

    
526

    
527
class TestHvStateHelper(unittest.TestCase):
528
  def testWithoutOpData(self):
529
    self.assertEqual(cmdlib._MergeAndVerifyHvState(None, NotImplemented), None)
530

    
531
  def testWithoutOldData(self):
532
    new = {
533
      constants.HT_XEN_PVM: {
534
        constants.HVST_MEMORY_TOTAL: 4096,
535
        },
536
      }
537
    self.assertEqual(cmdlib._MergeAndVerifyHvState(new, None), new)
538

    
539
  def testWithWrongHv(self):
540
    new = {
541
      "i-dont-exist": {
542
        constants.HVST_MEMORY_TOTAL: 4096,
543
        },
544
      }
545
    self.assertRaises(errors.OpPrereqError, cmdlib._MergeAndVerifyHvState, new,
546
                      None)
547

    
548
class TestDiskStateHelper(unittest.TestCase):
549
  def testWithoutOpData(self):
550
    self.assertEqual(cmdlib._MergeAndVerifyDiskState(None, NotImplemented),
551
                     None)
552

    
553
  def testWithoutOldData(self):
554
    new = {
555
      constants.LD_LV: {
556
        "xenvg": {
557
          constants.DS_DISK_RESERVED: 1024,
558
          },
559
        },
560
      }
561
    self.assertEqual(cmdlib._MergeAndVerifyDiskState(new, None), new)
562

    
563
  def testWithWrongStorageType(self):
564
    new = {
565
      "i-dont-exist": {
566
        "xenvg": {
567
          constants.DS_DISK_RESERVED: 1024,
568
          },
569
        },
570
      }
571
    self.assertRaises(errors.OpPrereqError, cmdlib._MergeAndVerifyDiskState,
572
                      new, None)
573

    
574

    
575
class TestComputeMinMaxSpec(unittest.TestCase):
576
  def setUp(self):
577
    self.ipolicy = {
578
      constants.ISPECS_MAX: {
579
        constants.ISPEC_MEM_SIZE: 512,
580
        constants.ISPEC_DISK_SIZE: 1024,
581
        },
582
      constants.ISPECS_MIN: {
583
        constants.ISPEC_MEM_SIZE: 128,
584
        constants.ISPEC_DISK_COUNT: 1,
585
        },
586
      }
587

    
588
  def testNoneValue(self):
589
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
590
                                              self.ipolicy, None) is None)
591

    
592
  def testAutoValue(self):
593
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_MEM_SIZE, None,
594
                                              self.ipolicy,
595
                                              constants.VALUE_AUTO) is None)
596

    
597
  def testNotDefined(self):
598
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_NIC_COUNT, None,
599
                                              self.ipolicy, 3) is None)
600

    
601
  def testNoMinDefined(self):
602
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_SIZE, None,
603
                                              self.ipolicy, 128) is None)
604

    
605
  def testNoMaxDefined(self):
606
    self.assertTrue(cmdlib._ComputeMinMaxSpec(constants.ISPEC_DISK_COUNT, None,
607
                                                self.ipolicy, 16) is None)
608

    
609
  def testOutOfRange(self):
610
    for (name, val) in ((constants.ISPEC_MEM_SIZE, 64),
611
                        (constants.ISPEC_MEM_SIZE, 768),
612
                        (constants.ISPEC_DISK_SIZE, 4096),
613
                        (constants.ISPEC_DISK_COUNT, 0)):
614
      min_v = self.ipolicy[constants.ISPECS_MIN].get(name, val)
615
      max_v = self.ipolicy[constants.ISPECS_MAX].get(name, val)
616
      self.assertEqual(cmdlib._ComputeMinMaxSpec(name, None,
617
                                                 self.ipolicy, val),
618
                       "%s value %s is not in range [%s, %s]" %
619
                       (name, val,min_v, max_v))
620
      self.assertEqual(cmdlib._ComputeMinMaxSpec(name, "1",
621
                                                 self.ipolicy, val),
622
                       "%s/1 value %s is not in range [%s, %s]" %
623
                       (name, val,min_v, max_v))
624

    
625
  def test(self):
626
    for (name, val) in ((constants.ISPEC_MEM_SIZE, 256),
627
                        (constants.ISPEC_MEM_SIZE, 128),
628
                        (constants.ISPEC_MEM_SIZE, 512),
629
                        (constants.ISPEC_DISK_SIZE, 1024),
630
                        (constants.ISPEC_DISK_SIZE, 0),
631
                        (constants.ISPEC_DISK_COUNT, 1),
632
                        (constants.ISPEC_DISK_COUNT, 5)):
633
      self.assertTrue(cmdlib._ComputeMinMaxSpec(name, None, self.ipolicy, val)
634
                      is None)
635

    
636

    
637
def _ValidateComputeMinMaxSpec(name, *_):
638
  assert name in constants.ISPECS_PARAMETERS
639
  return None
640

    
641

    
642
class _SpecWrapper:
643
  def __init__(self, spec):
644
    self.spec = spec
645

    
646
  def ComputeMinMaxSpec(self, *args):
647
    return self.spec.pop(0)
648

    
649

    
650
class TestComputeIPolicySpecViolation(unittest.TestCase):
651
  def test(self):
652
    compute_fn = _ValidateComputeMinMaxSpec
653
    ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
654
                                              [1024], 1, _compute_fn=compute_fn)
655
    self.assertEqual(ret, [])
656

    
657
  def testInvalidArguments(self):
658
    self.assertRaises(AssertionError, cmdlib._ComputeIPolicySpecViolation,
659
                      NotImplemented, 1024, 1, 1, 1, [], 1)
660

    
661
  def testInvalidSpec(self):
662
    spec = _SpecWrapper([None, False, "foo", None, "bar", None])
663
    compute_fn = spec.ComputeMinMaxSpec
664
    ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
665
                                              [1024], 1, _compute_fn=compute_fn)
666
    self.assertEqual(ret, ["foo", "bar"])
667
    self.assertFalse(spec.spec)
668

    
669

    
670
class _StubComputeIPolicySpecViolation:
671
  def __init__(self, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
672
               spindle_use):
673
    self.mem_size = mem_size
674
    self.cpu_count = cpu_count
675
    self.disk_count = disk_count
676
    self.nic_count = nic_count
677
    self.disk_sizes = disk_sizes
678
    self.spindle_use = spindle_use
679

    
680
  def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
681
               spindle_use):
682
    assert self.mem_size == mem_size
683
    assert self.cpu_count == cpu_count
684
    assert self.disk_count == disk_count
685
    assert self.nic_count == nic_count
686
    assert self.disk_sizes == disk_sizes
687
    assert self.spindle_use == spindle_use
688

    
689
    return []
690

    
691

    
692
class TestComputeIPolicyInstanceViolation(unittest.TestCase):
693
  def test(self):
694
    beparams = {
695
      constants.BE_MAXMEM: 2048,
696
      constants.BE_VCPUS: 2,
697
      constants.BE_SPINDLE_USE: 4,
698
      }
699
    disks = [objects.Disk(size=512)]
700
    instance = objects.Instance(beparams=beparams, disks=disks, nics=[])
701
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 4)
702
    ret = cmdlib._ComputeIPolicyInstanceViolation(NotImplemented, instance,
703
                                                  _compute_fn=stub)
704
    self.assertEqual(ret, [])
705

    
706

    
707
class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
708
  def test(self):
709
    ispec = {
710
      constants.ISPEC_MEM_SIZE: 2048,
711
      constants.ISPEC_CPU_COUNT: 2,
712
      constants.ISPEC_DISK_COUNT: 1,
713
      constants.ISPEC_DISK_SIZE: [512],
714
      constants.ISPEC_NIC_COUNT: 0,
715
      constants.ISPEC_SPINDLE_USE: 1,
716
      }
717
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 1)
718
    ret = cmdlib._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
719
                                                      _compute_fn=stub)
720
    self.assertEqual(ret, [])
721

    
722

    
723
class _CallRecorder:
724
  def __init__(self, return_value=None):
725
    self.called = False
726
    self.return_value = return_value
727

    
728
  def __call__(self, *args):
729
    self.called = True
730
    return self.return_value
731

    
732

    
733
class TestComputeIPolicyNodeViolation(unittest.TestCase):
734
  def setUp(self):
735
    self.recorder = _CallRecorder(return_value=[])
736

    
737
  def testSameGroup(self):
738
    ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
739
                                              "foo", "foo",
740
                                              _compute_fn=self.recorder)
741
    self.assertFalse(self.recorder.called)
742
    self.assertEqual(ret, [])
743

    
744
  def testDifferentGroup(self):
745
    ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
746
                                              "foo", "bar",
747
                                              _compute_fn=self.recorder)
748
    self.assertTrue(self.recorder.called)
749
    self.assertEqual(ret, [])
750

    
751

    
752
class _FakeConfigForTargetNodeIPolicy:
753
  def __init__(self, node_info=NotImplemented):
754
    self._node_info = node_info
755

    
756
  def GetNodeInfo(self, _):
757
    return self._node_info
758

    
759

    
760
class TestCheckTargetNodeIPolicy(unittest.TestCase):
761
  def setUp(self):
762
    self.instance = objects.Instance(primary_node="blubb")
763
    self.target_node = objects.Node(group="bar")
764
    node_info = objects.Node(group="foo")
765
    fake_cfg = _FakeConfigForTargetNodeIPolicy(node_info=node_info)
766
    self.lu = _FakeLU(cfg=fake_cfg)
767

    
768
  def testNoViolation(self):
769
    compute_recoder = _CallRecorder(return_value=[])
770
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
771
                                   self.target_node,
772
                                   _compute_fn=compute_recoder)
773
    self.assertTrue(compute_recoder.called)
774
    self.assertEqual(self.lu.warning_log, [])
775

    
776
  def testNoIgnore(self):
777
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
778
    self.assertRaises(errors.OpPrereqError, cmdlib._CheckTargetNodeIPolicy,
779
                      self.lu, NotImplemented, self.instance, self.target_node,
780
                      _compute_fn=compute_recoder)
781
    self.assertTrue(compute_recoder.called)
782
    self.assertEqual(self.lu.warning_log, [])
783

    
784
  def testIgnoreViolation(self):
785
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
786
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
787
                                   self.target_node, ignore=True,
788
                                   _compute_fn=compute_recoder)
789
    self.assertTrue(compute_recoder.called)
790
    msg = ("Instance does not meet target node group's (bar) instance policy:"
791
           " mem_size not in range")
792
    self.assertEqual(self.lu.warning_log, [(msg, ())])
793

    
794

    
795
class TestApplyContainerMods(unittest.TestCase):
796
  def testEmptyContainer(self):
797
    container = []
798
    chgdesc = []
799
    cmdlib.ApplyContainerMods("test", container, chgdesc, [], None, None, None)
800
    self.assertEqual(container, [])
801
    self.assertEqual(chgdesc, [])
802

    
803
  def testAdd(self):
804
    container = []
805
    chgdesc = []
806
    mods = cmdlib.PrepareContainerMods([
807
      (constants.DDM_ADD, -1, "Hello"),
808
      (constants.DDM_ADD, -1, "World"),
809
      (constants.DDM_ADD, 0, "Start"),
810
      (constants.DDM_ADD, -1, "End"),
811
      ], None)
812
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
813
                              None, None, None)
814
    self.assertEqual(container, ["Start", "Hello", "World", "End"])
815
    self.assertEqual(chgdesc, [])
816

    
817
    mods = cmdlib.PrepareContainerMods([
818
      (constants.DDM_ADD, 0, "zero"),
819
      (constants.DDM_ADD, 3, "Added"),
820
      (constants.DDM_ADD, 5, "four"),
821
      (constants.DDM_ADD, 7, "xyz"),
822
      ], None)
823
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
824
                              None, None, None)
825
    self.assertEqual(container,
826
                     ["zero", "Start", "Hello", "Added", "World", "four",
827
                      "End", "xyz"])
828
    self.assertEqual(chgdesc, [])
829

    
830
    for idx in [-2, len(container) + 1]:
831
      mods = cmdlib.PrepareContainerMods([
832
        (constants.DDM_ADD, idx, "error"),
833
        ], None)
834
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
835
                        "test", container, None, mods, None, None, None)
836

    
837
  def testRemoveError(self):
838
    for idx in [0, 1, 2, 100, -1, -4]:
839
      mods = cmdlib.PrepareContainerMods([
840
        (constants.DDM_REMOVE, idx, None),
841
        ], None)
842
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
843
                        "test", [], None, mods, None, None, None)
844

    
845
    mods = cmdlib.PrepareContainerMods([
846
      (constants.DDM_REMOVE, 0, object()),
847
      ], None)
848
    self.assertRaises(AssertionError, cmdlib.ApplyContainerMods,
849
                      "test", [""], None, mods, None, None, None)
850

    
851
  def testAddError(self):
852
    for idx in range(-100, -1) + [100]:
853
      mods = cmdlib.PrepareContainerMods([
854
        (constants.DDM_ADD, idx, None),
855
        ], None)
856
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
857
                        "test", [], None, mods, None, None, None)
858

    
859
  def testRemove(self):
860
    container = ["item 1", "item 2"]
861
    mods = cmdlib.PrepareContainerMods([
862
      (constants.DDM_ADD, -1, "aaa"),
863
      (constants.DDM_REMOVE, -1, None),
864
      (constants.DDM_ADD, -1, "bbb"),
865
      ], None)
866
    chgdesc = []
867
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
868
                              None, None, None)
869
    self.assertEqual(container, ["item 1", "item 2", "bbb"])
870
    self.assertEqual(chgdesc, [
871
      ("test/2", "remove"),
872
      ])
873

    
874
  def testModify(self):
875
    container = ["item 1", "item 2"]
876
    mods = cmdlib.PrepareContainerMods([
877
      (constants.DDM_MODIFY, -1, "a"),
878
      (constants.DDM_MODIFY, 0, "b"),
879
      (constants.DDM_MODIFY, 1, "c"),
880
      ], None)
881
    chgdesc = []
882
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
883
                              None, None, None)
884
    self.assertEqual(container, ["item 1", "item 2"])
885
    self.assertEqual(chgdesc, [])
886

    
887
    for idx in [-2, len(container) + 1]:
888
      mods = cmdlib.PrepareContainerMods([
889
        (constants.DDM_MODIFY, idx, "error"),
890
        ], None)
891
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
892
                        "test", container, None, mods, None, None, None)
893

    
894
  class _PrivateData:
895
    def __init__(self):
896
      self.data = None
897

    
898
  @staticmethod
899
  def _CreateTestFn(idx, params, private):
900
    private.data = ("add", idx, params)
901
    return ((100 * idx, params), [
902
      ("test/%s" % idx, hex(idx)),
903
      ])
904

    
905
  @staticmethod
906
  def _ModifyTestFn(idx, item, params, private):
907
    private.data = ("modify", idx, params)
908
    return [
909
      ("test/%s" % idx, "modify %s" % params),
910
      ]
911

    
912
  @staticmethod
913
  def _RemoveTestFn(idx, item, private):
914
    private.data = ("remove", idx, item)
915

    
916
  def testAddWithCreateFunction(self):
917
    container = []
918
    chgdesc = []
919
    mods = cmdlib.PrepareContainerMods([
920
      (constants.DDM_ADD, -1, "Hello"),
921
      (constants.DDM_ADD, -1, "World"),
922
      (constants.DDM_ADD, 0, "Start"),
923
      (constants.DDM_ADD, -1, "End"),
924
      (constants.DDM_REMOVE, 2, None),
925
      (constants.DDM_MODIFY, -1, "foobar"),
926
      (constants.DDM_REMOVE, 2, None),
927
      (constants.DDM_ADD, 1, "More"),
928
      ], self._PrivateData)
929
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
930
      self._CreateTestFn, self._ModifyTestFn, self._RemoveTestFn)
931
    self.assertEqual(container, [
932
      (000, "Start"),
933
      (100, "More"),
934
      (000, "Hello"),
935
      ])
936
    self.assertEqual(chgdesc, [
937
      ("test/0", "0x0"),
938
      ("test/1", "0x1"),
939
      ("test/0", "0x0"),
940
      ("test/3", "0x3"),
941
      ("test/2", "remove"),
942
      ("test/2", "modify foobar"),
943
      ("test/2", "remove"),
944
      ("test/1", "0x1")
945
      ])
946
    self.assertTrue(compat.all(op == private.data[0]
947
                               for (op, _, _, private) in mods))
948
    self.assertEqual([private.data for (op, _, _, private) in mods], [
949
      ("add", 0, "Hello"),
950
      ("add", 1, "World"),
951
      ("add", 0, "Start"),
952
      ("add", 3, "End"),
953
      ("remove", 2, (100, "World")),
954
      ("modify", 2, "foobar"),
955
      ("remove", 2, (300, "End")),
956
      ("add", 1, "More"),
957
      ])
958

    
959

    
960
class _FakeConfigForGenDiskTemplate:
961
  def __init__(self):
962
    self._unique_id = itertools.count()
963
    self._drbd_minor = itertools.count(20)
964
    self._port = itertools.count(constants.FIRST_DRBD_PORT)
965
    self._secret = itertools.count()
966

    
967
  def GetVGName(self):
968
    return "testvg"
969

    
970
  def GenerateUniqueID(self, ec_id):
971
    return "ec%s-uq%s" % (ec_id, self._unique_id.next())
972

    
973
  def AllocateDRBDMinor(self, nodes, instance):
974
    return [self._drbd_minor.next()
975
            for _ in nodes]
976

    
977
  def AllocatePort(self):
978
    return self._port.next()
979

    
980
  def GenerateDRBDSecret(self, ec_id):
981
    return "ec%s-secret%s" % (ec_id, self._secret.next())
982

    
983
  def GetInstanceInfo(self, _):
984
    return "foobar"
985

    
986

    
987
class _FakeProcForGenDiskTemplate:
988
  def GetECId(self):
989
    return 0
990

    
991

    
992
class TestGenerateDiskTemplate(unittest.TestCase):
993
  def setUp(self):
994
    nodegroup = objects.NodeGroup(name="ng")
995
    nodegroup.UpgradeConfig()
996

    
997
    cfg = _FakeConfigForGenDiskTemplate()
998
    proc = _FakeProcForGenDiskTemplate()
999

    
1000
    self.lu = _FakeLU(cfg=cfg, proc=proc)
1001
    self.nodegroup = nodegroup
1002

    
1003
  @staticmethod
1004
  def GetDiskParams():
1005
    return copy.deepcopy(constants.DISK_DT_DEFAULTS)
1006

    
1007
  def testWrongDiskTemplate(self):
1008
    gdt = cmdlib._GenerateDiskTemplate
1009
    disk_template = "##unknown##"
1010

    
1011
    assert disk_template not in constants.DISK_TEMPLATES
1012

    
1013
    self.assertRaises(errors.ProgrammerError, gdt, self.lu, disk_template,
1014
                      "inst26831.example.com", "node30113.example.com", [], [],
1015
                      NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1016
                      self.GetDiskParams())
1017

    
1018
  def testDiskless(self):
1019
    gdt = cmdlib._GenerateDiskTemplate
1020

    
1021
    result = gdt(self.lu, constants.DT_DISKLESS, "inst27734.example.com",
1022
                 "node30113.example.com", [], [],
1023
                 NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1024
                 self.GetDiskParams())
1025
    self.assertEqual(result, [])
1026

    
1027
  def _TestTrivialDisk(self, template, disk_info, base_index, exp_dev_type,
1028
                       file_storage_dir=NotImplemented,
1029
                       file_driver=NotImplemented,
1030
                       req_file_storage=NotImplemented,
1031
                       req_shr_file_storage=NotImplemented):
1032
    gdt = cmdlib._GenerateDiskTemplate
1033

    
1034
    map(lambda params: utils.ForceDictType(params,
1035
                                           constants.IDISK_PARAMS_TYPES),
1036
        disk_info)
1037

    
1038
    # Check if non-empty list of secondaries is rejected
1039
    self.assertRaises(errors.ProgrammerError, gdt, self.lu,
1040
                      template, "inst25088.example.com",
1041
                      "node185.example.com", ["node323.example.com"], [],
1042
                      NotImplemented, NotImplemented, base_index,
1043
                      self.lu.LogInfo, self.GetDiskParams(),
1044
                      _req_file_storage=req_file_storage,
1045
                      _req_shr_file_storage=req_shr_file_storage)
1046

    
1047
    result = gdt(self.lu, template, "inst21662.example.com",
1048
                 "node21741.example.com", [],
1049
                 disk_info, file_storage_dir, file_driver, base_index,
1050
                 self.lu.LogInfo, self.GetDiskParams(),
1051
                 _req_file_storage=req_file_storage,
1052
                 _req_shr_file_storage=req_shr_file_storage)
1053

    
1054
    for (idx, disk) in enumerate(result):
1055
      self.assertTrue(isinstance(disk, objects.Disk))
1056
      self.assertEqual(disk.dev_type, exp_dev_type)
1057
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1058
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1059
      self.assertTrue(disk.children is None)
1060

    
1061
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1062
    cmdlib._UpdateIvNames(base_index, result)
1063
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1064

    
1065
    return result
1066

    
1067
  def _CheckIvNames(self, disks, base_index, end_index):
1068
    self.assertEqual(map(operator.attrgetter("iv_name"), disks),
1069
                     ["disk/%s" % i for i in range(base_index, end_index)])
1070

    
1071
  def testPlain(self):
1072
    disk_info = [{
1073
      constants.IDISK_SIZE: 1024,
1074
      constants.IDISK_MODE: constants.DISK_RDWR,
1075
      }, {
1076
      constants.IDISK_SIZE: 4096,
1077
      constants.IDISK_VG: "othervg",
1078
      constants.IDISK_MODE: constants.DISK_RDWR,
1079
      }]
1080

    
1081
    result = self._TestTrivialDisk(constants.DT_PLAIN, disk_info, 3,
1082
                                   constants.LD_LV)
1083

    
1084
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1085
      ("testvg", "ec0-uq0.disk3"),
1086
      ("othervg", "ec0-uq1.disk4"),
1087
      ])
1088

    
1089
  @staticmethod
1090
  def _AllowFileStorage():
1091
    pass
1092

    
1093
  @staticmethod
1094
  def _ForbidFileStorage():
1095
    raise errors.OpPrereqError("Disallowed in test")
1096

    
1097
  def testFile(self):
1098
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1099
                      constants.DT_FILE, [], 0, NotImplemented,
1100
                      req_file_storage=self._ForbidFileStorage)
1101
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1102
                      constants.DT_SHARED_FILE, [], 0, NotImplemented,
1103
                      req_shr_file_storage=self._ForbidFileStorage)
1104

    
1105
    for disk_template in [constants.DT_FILE, constants.DT_SHARED_FILE]:
1106
      disk_info = [{
1107
        constants.IDISK_SIZE: 80 * 1024,
1108
        constants.IDISK_MODE: constants.DISK_RDONLY,
1109
        }, {
1110
        constants.IDISK_SIZE: 4096,
1111
        constants.IDISK_MODE: constants.DISK_RDWR,
1112
        }, {
1113
        constants.IDISK_SIZE: 6 * 1024,
1114
        constants.IDISK_MODE: constants.DISK_RDWR,
1115
        }]
1116

    
1117
      result = self._TestTrivialDisk(disk_template, disk_info, 2,
1118
        constants.LD_FILE, file_storage_dir="/tmp",
1119
        file_driver=constants.FD_BLKTAP,
1120
        req_file_storage=self._AllowFileStorage,
1121
        req_shr_file_storage=self._AllowFileStorage)
1122

    
1123
      self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1124
        (constants.FD_BLKTAP, "/tmp/disk2"),
1125
        (constants.FD_BLKTAP, "/tmp/disk3"),
1126
        (constants.FD_BLKTAP, "/tmp/disk4"),
1127
        ])
1128

    
1129
  def testBlock(self):
1130
    disk_info = [{
1131
      constants.IDISK_SIZE: 8 * 1024,
1132
      constants.IDISK_MODE: constants.DISK_RDWR,
1133
      constants.IDISK_ADOPT: "/tmp/some/block/dev",
1134
      }]
1135

    
1136
    result = self._TestTrivialDisk(constants.DT_BLOCK, disk_info, 10,
1137
                                   constants.LD_BLOCKDEV)
1138

    
1139
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1140
      (constants.BLOCKDEV_DRIVER_MANUAL, "/tmp/some/block/dev"),
1141
      ])
1142

    
1143
  def testRbd(self):
1144
    disk_info = [{
1145
      constants.IDISK_SIZE: 8 * 1024,
1146
      constants.IDISK_MODE: constants.DISK_RDONLY,
1147
      }, {
1148
      constants.IDISK_SIZE: 100 * 1024,
1149
      constants.IDISK_MODE: constants.DISK_RDWR,
1150
      }]
1151

    
1152
    result = self._TestTrivialDisk(constants.DT_RBD, disk_info, 0,
1153
                                   constants.LD_RBD)
1154

    
1155
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1156
      ("rbd", "ec0-uq0.rbd.disk0"),
1157
      ("rbd", "ec0-uq1.rbd.disk1"),
1158
      ])
1159

    
1160
  def testDrbd8(self):
1161
    gdt = cmdlib._GenerateDiskTemplate
1162
    drbd8_defaults = constants.DISK_LD_DEFAULTS[constants.LD_DRBD8]
1163
    drbd8_default_metavg = drbd8_defaults[constants.LDP_DEFAULT_METAVG]
1164

    
1165
    disk_info = [{
1166
      constants.IDISK_SIZE: 1024,
1167
      constants.IDISK_MODE: constants.DISK_RDWR,
1168
      }, {
1169
      constants.IDISK_SIZE: 100 * 1024,
1170
      constants.IDISK_MODE: constants.DISK_RDONLY,
1171
      constants.IDISK_METAVG: "metavg",
1172
      }, {
1173
      constants.IDISK_SIZE: 4096,
1174
      constants.IDISK_MODE: constants.DISK_RDWR,
1175
      constants.IDISK_VG: "vgxyz",
1176
      },
1177
      ]
1178

    
1179
    exp_logical_ids = [[
1180
      (self.lu.cfg.GetVGName(), "ec0-uq0.disk0_data"),
1181
      (drbd8_default_metavg, "ec0-uq0.disk0_meta"),
1182
      ], [
1183
      (self.lu.cfg.GetVGName(), "ec0-uq1.disk1_data"),
1184
      ("metavg", "ec0-uq1.disk1_meta"),
1185
      ], [
1186
      ("vgxyz", "ec0-uq2.disk2_data"),
1187
      (drbd8_default_metavg, "ec0-uq2.disk2_meta"),
1188
      ]]
1189

    
1190
    assert len(exp_logical_ids) == len(disk_info)
1191

    
1192
    map(lambda params: utils.ForceDictType(params,
1193
                                           constants.IDISK_PARAMS_TYPES),
1194
        disk_info)
1195

    
1196
    # Check if empty list of secondaries is rejected
1197
    self.assertRaises(errors.ProgrammerError, gdt, self.lu, constants.DT_DRBD8,
1198
                      "inst827.example.com", "node1334.example.com", [],
1199
                      disk_info, NotImplemented, NotImplemented, 0,
1200
                      self.lu.LogInfo, self.GetDiskParams())
1201

    
1202
    result = gdt(self.lu, constants.DT_DRBD8, "inst827.example.com",
1203
                 "node1334.example.com", ["node12272.example.com"],
1204
                 disk_info, NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1205
                 self.GetDiskParams())
1206

    
1207
    for (idx, disk) in enumerate(result):
1208
      self.assertTrue(isinstance(disk, objects.Disk))
1209
      self.assertEqual(disk.dev_type, constants.LD_DRBD8)
1210
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1211
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1212

    
1213
      for child in disk.children:
1214
        self.assertTrue(isinstance(disk, objects.Disk))
1215
        self.assertEqual(child.dev_type, constants.LD_LV)
1216
        self.assertTrue(child.children is None)
1217

    
1218
      self.assertEqual(map(operator.attrgetter("logical_id"), disk.children),
1219
                       exp_logical_ids[idx])
1220

    
1221
      self.assertEqual(len(disk.children), 2)
1222
      self.assertEqual(disk.children[0].size, disk.size)
1223
      self.assertEqual(disk.children[1].size, constants.DRBD_META_SIZE)
1224

    
1225
    self._CheckIvNames(result, 0, len(disk_info))
1226
    cmdlib._UpdateIvNames(0, result)
1227
    self._CheckIvNames(result, 0, len(disk_info))
1228

    
1229
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1230
      ("node1334.example.com", "node12272.example.com",
1231
       constants.FIRST_DRBD_PORT, 20, 21, "ec0-secret0"),
1232
      ("node1334.example.com", "node12272.example.com",
1233
       constants.FIRST_DRBD_PORT + 1, 22, 23, "ec0-secret1"),
1234
      ("node1334.example.com", "node12272.example.com",
1235
       constants.FIRST_DRBD_PORT + 2, 24, 25, "ec0-secret2"),
1236
      ])
1237

    
1238

    
1239
if __name__ == "__main__":
1240
  testutils.GanetiTestProgram()