Statistics
| Branch: | Tag: | Revision:

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

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.masterd import iallocator
46
from ganeti.hypervisor import hv_xen
47

    
48
import testutils
49
import mocks
50

    
51

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

    
56
    self.tmpdir = tempfile.mkdtemp()
57

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

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

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

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

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

    
74

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

    
87

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

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

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

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

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

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

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

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

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

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

    
141

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

    
149

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

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

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

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

    
165

    
166
class TestLUGroupAssignNodes(unittest.TestCase):
167

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

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

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

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

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

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

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

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

    
216

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

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

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

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

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

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

    
275

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

    
284
    if args:
285
      msg = msg % args
286

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

    
290
  _VerifyFiles = cmdlib.LUClusterVerifyGroup._VerifyFiles
291

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

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

    
385

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

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

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

    
399

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

    
412
          alloc_result = (moved, [], jobs)
413
          assert iallocator._NEVAC_RESULT(alloc_result)
414

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

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

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

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

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

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

    
453

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

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

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

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

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

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

    
527

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

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

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

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

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

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

    
575

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

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

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

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

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

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

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

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

    
637

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

    
642

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

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

    
650

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

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

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

    
670

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

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

    
690
    return []
691

    
692

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

    
707

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

    
723

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

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

    
733

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

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

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

    
752

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

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

    
760

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

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

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

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

    
795

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
960

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

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

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

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

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

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

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

    
987

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

    
992

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

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

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

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

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

    
1012
    assert disk_template not in constants.DISK_TEMPLATES
1013

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

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

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

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

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

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

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

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

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

    
1066
    return result
1067

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1239

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