Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cmdlib_unittest.py @ 34700f5b

History | View | Annotate | Download (42.1 kB)

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

    
4
# Copyright (C) 2008, 2011 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

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

    
46
import testutils
47
import mocks
48

    
49

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

    
54
    self.tmpdir = tempfile.mkdtemp()
55

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

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

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

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

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

    
72

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

    
85

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

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

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

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

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

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

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

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

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

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

    
139

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

    
147

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

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

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

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

    
163

    
164
class TestLUGroupAssignNodes(unittest.TestCase):
165

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

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

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

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

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

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

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

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

    
214

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

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

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

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

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

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

    
273

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

    
282
    if args:
283
      msg = msg % args
284

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

    
288
  _VerifyFiles = cmdlib.LUClusterVerifyGroup._VerifyFiles
289

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

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

    
383

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

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

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

    
397

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

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

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

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

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

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

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

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

    
451

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

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

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

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

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

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

    
525

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

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

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

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

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

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

    
573

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

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

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

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

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

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

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

    
619
  def test(self):
620
    for (name, val) in ((constants.ISPEC_MEM_SIZE, 256),
621
                        (constants.ISPEC_MEM_SIZE, 128),
622
                        (constants.ISPEC_MEM_SIZE, 512),
623
                        (constants.ISPEC_DISK_SIZE, 1024),
624
                        (constants.ISPEC_DISK_SIZE, 0),
625
                        (constants.ISPEC_DISK_COUNT, 1),
626
                        (constants.ISPEC_DISK_COUNT, 5)):
627
      self.assertTrue(cmdlib._ComputeMinMaxSpec(name, self.ipolicy, val)
628
                      is None)
629

    
630

    
631
def _ValidateComputeMinMaxSpec(name, *_):
632
  assert name in constants.ISPECS_PARAMETERS
633
  return None
634

    
635

    
636
class _SpecWrapper:
637
  def __init__(self, spec):
638
    self.spec = spec
639

    
640
  def ComputeMinMaxSpec(self, *args):
641
    return self.spec.pop(0)
642

    
643

    
644
class TestComputeIPolicySpecViolation(unittest.TestCase):
645
  def test(self):
646
    compute_fn = _ValidateComputeMinMaxSpec
647
    ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
648
                                              [1024], 1, _compute_fn=compute_fn)
649
    self.assertEqual(ret, [])
650

    
651
  def testInvalidArguments(self):
652
    self.assertRaises(AssertionError, cmdlib._ComputeIPolicySpecViolation,
653
                      NotImplemented, 1024, 1, 1, 1, [], 1)
654

    
655
  def testInvalidSpec(self):
656
    spec = _SpecWrapper([None, False, "foo", None, "bar", None])
657
    compute_fn = spec.ComputeMinMaxSpec
658
    ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
659
                                              [1024], 1, _compute_fn=compute_fn)
660
    self.assertEqual(ret, ["foo", "bar"])
661
    self.assertFalse(spec.spec)
662

    
663

    
664
class _StubComputeIPolicySpecViolation:
665
  def __init__(self, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
666
               spindle_use):
667
    self.mem_size = mem_size
668
    self.cpu_count = cpu_count
669
    self.disk_count = disk_count
670
    self.nic_count = nic_count
671
    self.disk_sizes = disk_sizes
672
    self.spindle_use = spindle_use
673

    
674
  def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
675
               spindle_use):
676
    assert self.mem_size == mem_size
677
    assert self.cpu_count == cpu_count
678
    assert self.disk_count == disk_count
679
    assert self.nic_count == nic_count
680
    assert self.disk_sizes == disk_sizes
681
    assert self.spindle_use == spindle_use
682

    
683
    return []
684

    
685

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

    
700

    
701
class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
702
  def test(self):
703
    ispec = {
704
      constants.ISPEC_MEM_SIZE: 2048,
705
      constants.ISPEC_CPU_COUNT: 2,
706
      constants.ISPEC_DISK_COUNT: 1,
707
      constants.ISPEC_DISK_SIZE: [512],
708
      constants.ISPEC_NIC_COUNT: 0,
709
      constants.ISPEC_SPINDLE_USE: 1,
710
      }
711
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 1)
712
    ret = cmdlib._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
713
                                                      _compute_fn=stub)
714
    self.assertEqual(ret, [])
715

    
716

    
717
class _CallRecorder:
718
  def __init__(self, return_value=None):
719
    self.called = False
720
    self.return_value = return_value
721

    
722
  def __call__(self, *args):
723
    self.called = True
724
    return self.return_value
725

    
726

    
727
class TestComputeIPolicyNodeViolation(unittest.TestCase):
728
  def setUp(self):
729
    self.recorder = _CallRecorder(return_value=[])
730

    
731
  def testSameGroup(self):
732
    ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
733
                                              "foo", "foo",
734
                                              _compute_fn=self.recorder)
735
    self.assertFalse(self.recorder.called)
736
    self.assertEqual(ret, [])
737

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

    
745

    
746
class _FakeConfigForTargetNodeIPolicy:
747
  def __init__(self, node_info=NotImplemented):
748
    self._node_info = node_info
749

    
750
  def GetNodeInfo(self, _):
751
    return self._node_info
752

    
753

    
754
class TestCheckTargetNodeIPolicy(unittest.TestCase):
755
  def setUp(self):
756
    self.instance = objects.Instance(primary_node="blubb")
757
    self.target_node = objects.Node(group="bar")
758
    node_info = objects.Node(group="foo")
759
    fake_cfg = _FakeConfigForTargetNodeIPolicy(node_info=node_info)
760
    self.lu = _FakeLU(cfg=fake_cfg)
761

    
762
  def testNoViolation(self):
763
    compute_recoder = _CallRecorder(return_value=[])
764
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
765
                                   self.target_node,
766
                                   _compute_fn=compute_recoder)
767
    self.assertTrue(compute_recoder.called)
768
    self.assertEqual(self.lu.warning_log, [])
769

    
770
  def testNoIgnore(self):
771
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
772
    self.assertRaises(errors.OpPrereqError, cmdlib._CheckTargetNodeIPolicy,
773
                      self.lu, NotImplemented, self.instance, self.target_node,
774
                      _compute_fn=compute_recoder)
775
    self.assertTrue(compute_recoder.called)
776
    self.assertEqual(self.lu.warning_log, [])
777

    
778
  def testIgnoreViolation(self):
779
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
780
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
781
                                   self.target_node, ignore=True,
782
                                   _compute_fn=compute_recoder)
783
    self.assertTrue(compute_recoder.called)
784
    msg = ("Instance does not meet target node group's (bar) instance policy:"
785
           " mem_size not in range")
786
    self.assertEqual(self.lu.warning_log, [(msg, ())])
787

    
788

    
789
class TestApplyContainerMods(unittest.TestCase):
790
  def testEmptyContainer(self):
791
    container = []
792
    chgdesc = []
793
    cmdlib.ApplyContainerMods("test", container, chgdesc, [], None, None, None)
794
    self.assertEqual(container, [])
795
    self.assertEqual(chgdesc, [])
796

    
797
  def testAdd(self):
798
    container = []
799
    chgdesc = []
800
    mods = cmdlib.PrepareContainerMods([
801
      (constants.DDM_ADD, -1, "Hello"),
802
      (constants.DDM_ADD, -1, "World"),
803
      (constants.DDM_ADD, 0, "Start"),
804
      (constants.DDM_ADD, -1, "End"),
805
      ], None)
806
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
807
                              None, None, None)
808
    self.assertEqual(container, ["Start", "Hello", "World", "End"])
809
    self.assertEqual(chgdesc, [])
810

    
811
    mods = cmdlib.PrepareContainerMods([
812
      (constants.DDM_ADD, 0, "zero"),
813
      (constants.DDM_ADD, 3, "Added"),
814
      (constants.DDM_ADD, 5, "four"),
815
      (constants.DDM_ADD, 7, "xyz"),
816
      ], None)
817
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
818
                              None, None, None)
819
    self.assertEqual(container,
820
                     ["zero", "Start", "Hello", "Added", "World", "four",
821
                      "End", "xyz"])
822
    self.assertEqual(chgdesc, [])
823

    
824
    for idx in [-2, len(container) + 1]:
825
      mods = cmdlib.PrepareContainerMods([
826
        (constants.DDM_ADD, idx, "error"),
827
        ], None)
828
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
829
                        "test", container, None, mods, None, None, None)
830

    
831
  def testRemoveError(self):
832
    for idx in [0, 1, 2, 100, -1, -4]:
833
      mods = cmdlib.PrepareContainerMods([
834
        (constants.DDM_REMOVE, idx, None),
835
        ], None)
836
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
837
                        "test", [], None, mods, None, None, None)
838

    
839
    mods = cmdlib.PrepareContainerMods([
840
      (constants.DDM_REMOVE, 0, object()),
841
      ], None)
842
    self.assertRaises(AssertionError, cmdlib.ApplyContainerMods,
843
                      "test", [""], None, mods, None, None, None)
844

    
845
  def testAddError(self):
846
    for idx in range(-100, -1) + [100]:
847
      mods = cmdlib.PrepareContainerMods([
848
        (constants.DDM_ADD, idx, None),
849
        ], None)
850
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
851
                        "test", [], None, mods, None, None, None)
852

    
853
  def testRemove(self):
854
    container = ["item 1", "item 2"]
855
    mods = cmdlib.PrepareContainerMods([
856
      (constants.DDM_ADD, -1, "aaa"),
857
      (constants.DDM_REMOVE, -1, None),
858
      (constants.DDM_ADD, -1, "bbb"),
859
      ], None)
860
    chgdesc = []
861
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
862
                              None, None, None)
863
    self.assertEqual(container, ["item 1", "item 2", "bbb"])
864
    self.assertEqual(chgdesc, [
865
      ("test/2", "remove"),
866
      ])
867

    
868
  def testModify(self):
869
    container = ["item 1", "item 2"]
870
    mods = cmdlib.PrepareContainerMods([
871
      (constants.DDM_MODIFY, -1, "a"),
872
      (constants.DDM_MODIFY, 0, "b"),
873
      (constants.DDM_MODIFY, 1, "c"),
874
      ], None)
875
    chgdesc = []
876
    cmdlib.ApplyContainerMods("test", container, chgdesc, mods,
877
                              None, None, None)
878
    self.assertEqual(container, ["item 1", "item 2"])
879
    self.assertEqual(chgdesc, [])
880

    
881
    for idx in [-2, len(container) + 1]:
882
      mods = cmdlib.PrepareContainerMods([
883
        (constants.DDM_MODIFY, idx, "error"),
884
        ], None)
885
      self.assertRaises(IndexError, cmdlib.ApplyContainerMods,
886
                        "test", container, None, mods, None, None, None)
887

    
888
  class _PrivateData:
889
    def __init__(self):
890
      self.data = None
891

    
892
  @staticmethod
893
  def _CreateTestFn(idx, params, private):
894
    private.data = ("add", idx, params)
895
    return ((100 * idx, params), [
896
      ("test/%s" % idx, hex(idx)),
897
      ])
898

    
899
  @staticmethod
900
  def _ModifyTestFn(idx, item, params, private):
901
    private.data = ("modify", idx, params)
902
    return [
903
      ("test/%s" % idx, "modify %s" % params),
904
      ]
905

    
906
  @staticmethod
907
  def _RemoveTestFn(idx, item, private):
908
    private.data = ("remove", idx, item)
909

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

    
953

    
954
class _FakeConfigForGenDiskTemplate:
955
  def __init__(self):
956
    self._unique_id = itertools.count()
957
    self._drbd_minor = itertools.count(20)
958
    self._port = itertools.count(constants.FIRST_DRBD_PORT)
959
    self._secret = itertools.count()
960

    
961
  def GetVGName(self):
962
    return "testvg"
963

    
964
  def GenerateUniqueID(self, ec_id):
965
    return "ec%s-uq%s" % (ec_id, self._unique_id.next())
966

    
967
  def AllocateDRBDMinor(self, nodes, instance):
968
    return [self._drbd_minor.next()
969
            for _ in nodes]
970

    
971
  def AllocatePort(self):
972
    return self._port.next()
973

    
974
  def GenerateDRBDSecret(self, ec_id):
975
    return "ec%s-secret%s" % (ec_id, self._secret.next())
976

    
977

    
978
class _FakeProcForGenDiskTemplate:
979
  def GetECId(self):
980
    return 0
981

    
982

    
983
class TestGenerateDiskTemplate(unittest.TestCase):
984
  def setUp(self):
985
    nodegroup = objects.NodeGroup(name="ng")
986
    nodegroup.UpgradeConfig()
987

    
988
    cfg = _FakeConfigForGenDiskTemplate()
989
    proc = _FakeProcForGenDiskTemplate()
990

    
991
    self.lu = _FakeLU(cfg=cfg, proc=proc)
992
    self.nodegroup = nodegroup
993

    
994
  def testWrongDiskTemplate(self):
995
    gdt = cmdlib._GenerateDiskTemplate
996
    disk_template = "##unknown##"
997

    
998
    assert disk_template not in constants.DISK_TEMPLATES
999

    
1000
    self.assertRaises(errors.ProgrammerError, gdt, self.lu, disk_template,
1001
                      "inst26831.example.com", "node30113.example.com", [], [],
1002
                      NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1003
                      self.nodegroup.diskparams)
1004

    
1005
  def testDiskless(self):
1006
    gdt = cmdlib._GenerateDiskTemplate
1007

    
1008
    result = gdt(self.lu, constants.DT_DISKLESS, "inst27734.example.com",
1009
                 "node30113.example.com", [], [],
1010
                 NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1011
                 self.nodegroup.diskparams)
1012
    self.assertEqual(result, [])
1013

    
1014
  def _TestTrivialDisk(self, template, disk_info, base_index, exp_dev_type,
1015
                       file_storage_dir=NotImplemented,
1016
                       file_driver=NotImplemented,
1017
                       req_file_storage=NotImplemented,
1018
                       req_shr_file_storage=NotImplemented):
1019
    gdt = cmdlib._GenerateDiskTemplate
1020

    
1021
    map(lambda params: utils.ForceDictType(params,
1022
                                           constants.IDISK_PARAMS_TYPES),
1023
        disk_info)
1024

    
1025
    # Check if non-empty list of secondaries is rejected
1026
    self.assertRaises(errors.ProgrammerError, gdt, self.lu,
1027
                      template, "inst25088.example.com",
1028
                      "node185.example.com", ["node323.example.com"], [],
1029
                      NotImplemented, NotImplemented, base_index,
1030
                      self.lu.LogInfo, self.nodegroup.diskparams,
1031
                      _req_file_storage=req_file_storage,
1032
                      _req_shr_file_storage=req_shr_file_storage)
1033

    
1034
    result = gdt(self.lu, template, "inst21662.example.com",
1035
                 "node21741.example.com", [],
1036
                 disk_info, file_storage_dir, file_driver, base_index,
1037
                 self.lu.LogInfo, self.nodegroup.diskparams,
1038
                 _req_file_storage=req_file_storage,
1039
                 _req_shr_file_storage=req_shr_file_storage)
1040

    
1041
    for (idx, disk) in enumerate(result):
1042
      self.assertTrue(isinstance(disk, objects.Disk))
1043
      self.assertEqual(disk.dev_type, exp_dev_type)
1044
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1045
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1046
      self.assertTrue(disk.children is None)
1047

    
1048
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1049
    cmdlib._UpdateIvNames(base_index, result)
1050
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1051

    
1052
    return result
1053

    
1054
  def _CheckIvNames(self, disks, base_index, end_index):
1055
    self.assertEqual(map(operator.attrgetter("iv_name"), disks),
1056
                     ["disk/%s" % i for i in range(base_index, end_index)])
1057

    
1058
  def testPlain(self):
1059
    disk_info = [{
1060
      constants.IDISK_SIZE: 1024,
1061
      constants.IDISK_MODE: constants.DISK_RDWR,
1062
      }, {
1063
      constants.IDISK_SIZE: 4096,
1064
      constants.IDISK_VG: "othervg",
1065
      constants.IDISK_MODE: constants.DISK_RDWR,
1066
      }]
1067

    
1068
    result = self._TestTrivialDisk(constants.DT_PLAIN, disk_info, 3,
1069
                                   constants.LD_LV)
1070

    
1071
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1072
      ("testvg", "ec0-uq0.disk3"),
1073
      ("othervg", "ec0-uq1.disk4"),
1074
      ])
1075

    
1076
  @staticmethod
1077
  def _AllowFileStorage():
1078
    pass
1079

    
1080
  @staticmethod
1081
  def _ForbidFileStorage():
1082
    raise errors.OpPrereqError("Disallowed in test")
1083

    
1084
  def testFile(self):
1085
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1086
                      constants.DT_FILE, [], 0, NotImplemented,
1087
                      req_file_storage=self._ForbidFileStorage)
1088
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1089
                      constants.DT_SHARED_FILE, [], 0, NotImplemented,
1090
                      req_shr_file_storage=self._ForbidFileStorage)
1091

    
1092
    for disk_template in [constants.DT_FILE, constants.DT_SHARED_FILE]:
1093
      disk_info = [{
1094
        constants.IDISK_SIZE: 80 * 1024,
1095
        constants.IDISK_MODE: constants.DISK_RDONLY,
1096
        }, {
1097
        constants.IDISK_SIZE: 4096,
1098
        constants.IDISK_MODE: constants.DISK_RDWR,
1099
        }, {
1100
        constants.IDISK_SIZE: 6 * 1024,
1101
        constants.IDISK_MODE: constants.DISK_RDWR,
1102
        }]
1103

    
1104
      result = self._TestTrivialDisk(disk_template, disk_info, 2,
1105
        constants.LD_FILE, file_storage_dir="/tmp",
1106
        file_driver=constants.FD_BLKTAP,
1107
        req_file_storage=self._AllowFileStorage,
1108
        req_shr_file_storage=self._AllowFileStorage)
1109

    
1110
      self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1111
        (constants.FD_BLKTAP, "/tmp/disk2"),
1112
        (constants.FD_BLKTAP, "/tmp/disk3"),
1113
        (constants.FD_BLKTAP, "/tmp/disk4"),
1114
        ])
1115

    
1116
  def testBlock(self):
1117
    disk_info = [{
1118
      constants.IDISK_SIZE: 8 * 1024,
1119
      constants.IDISK_MODE: constants.DISK_RDWR,
1120
      constants.IDISK_ADOPT: "/tmp/some/block/dev",
1121
      }]
1122

    
1123
    result = self._TestTrivialDisk(constants.DT_BLOCK, disk_info, 10,
1124
                                   constants.LD_BLOCKDEV)
1125

    
1126
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1127
      (constants.BLOCKDEV_DRIVER_MANUAL, "/tmp/some/block/dev"),
1128
      ])
1129

    
1130
  def testRbd(self):
1131
    disk_info = [{
1132
      constants.IDISK_SIZE: 8 * 1024,
1133
      constants.IDISK_MODE: constants.DISK_RDONLY,
1134
      }, {
1135
      constants.IDISK_SIZE: 100 * 1024,
1136
      constants.IDISK_MODE: constants.DISK_RDWR,
1137
      }]
1138

    
1139
    result = self._TestTrivialDisk(constants.DT_RBD, disk_info, 0,
1140
                                   constants.LD_RBD)
1141

    
1142
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1143
      ("rbd", "ec0-uq0.rbd.disk0"),
1144
      ("rbd", "ec0-uq1.rbd.disk1"),
1145
      ])
1146

    
1147
  def testDrbd8(self):
1148
    gdt = cmdlib._GenerateDiskTemplate
1149
    drbd8_defaults = constants.DISK_LD_DEFAULTS[constants.LD_DRBD8]
1150
    drbd8_default_metavg = drbd8_defaults[constants.LDP_DEFAULT_METAVG]
1151

    
1152
    disk_info = [{
1153
      constants.IDISK_SIZE: 1024,
1154
      constants.IDISK_MODE: constants.DISK_RDWR,
1155
      }, {
1156
      constants.IDISK_SIZE: 100 * 1024,
1157
      constants.IDISK_MODE: constants.DISK_RDONLY,
1158
      constants.IDISK_METAVG: "metavg",
1159
      }, {
1160
      constants.IDISK_SIZE: 4096,
1161
      constants.IDISK_MODE: constants.DISK_RDWR,
1162
      constants.IDISK_VG: "vgxyz",
1163
      },
1164
      ]
1165

    
1166
    exp_logical_ids = [[
1167
      (self.lu.cfg.GetVGName(), "ec0-uq0.disk0_data"),
1168
      (drbd8_default_metavg, "ec0-uq0.disk0_meta"),
1169
      ], [
1170
      (self.lu.cfg.GetVGName(), "ec0-uq1.disk1_data"),
1171
      ("metavg", "ec0-uq1.disk1_meta"),
1172
      ], [
1173
      ("vgxyz", "ec0-uq2.disk2_data"),
1174
      (drbd8_default_metavg, "ec0-uq2.disk2_meta"),
1175
      ]]
1176

    
1177
    assert len(exp_logical_ids) == len(disk_info)
1178

    
1179
    map(lambda params: utils.ForceDictType(params,
1180
                                           constants.IDISK_PARAMS_TYPES),
1181
        disk_info)
1182

    
1183
    # Check if empty list of secondaries is rejected
1184
    self.assertRaises(errors.ProgrammerError, gdt, self.lu, constants.DT_DRBD8,
1185
                      "inst827.example.com", "node1334.example.com", [],
1186
                      disk_info, NotImplemented, NotImplemented, 0,
1187
                      self.lu.LogInfo, self.nodegroup.diskparams)
1188

    
1189
    result = gdt(self.lu, constants.DT_DRBD8, "inst827.example.com",
1190
                 "node1334.example.com", ["node12272.example.com"],
1191
                 disk_info, NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1192
                 self.nodegroup.diskparams)
1193

    
1194
    for (idx, disk) in enumerate(result):
1195
      self.assertTrue(isinstance(disk, objects.Disk))
1196
      self.assertEqual(disk.dev_type, constants.LD_DRBD8)
1197
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1198
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1199

    
1200
      for child in disk.children:
1201
        self.assertTrue(isinstance(disk, objects.Disk))
1202
        self.assertEqual(child.dev_type, constants.LD_LV)
1203
        self.assertTrue(child.children is None)
1204

    
1205
      self.assertEqual(map(operator.attrgetter("logical_id"), disk.children),
1206
                       exp_logical_ids[idx])
1207

    
1208
      self.assertEqual(len(disk.children), 2)
1209
      self.assertEqual(disk.children[0].size, disk.size)
1210
      self.assertEqual(disk.children[1].size, cmdlib.DRBD_META_SIZE)
1211

    
1212
    self._CheckIvNames(result, 0, len(disk_info))
1213
    cmdlib._UpdateIvNames(0, result)
1214
    self._CheckIvNames(result, 0, len(disk_info))
1215

    
1216
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1217
      ("node1334.example.com", "node12272.example.com",
1218
       constants.FIRST_DRBD_PORT, 20, 21, "ec0-secret0"),
1219
      ("node1334.example.com", "node12272.example.com",
1220
       constants.FIRST_DRBD_PORT + 1, 22, 23, "ec0-secret1"),
1221
      ("node1334.example.com", "node12272.example.com",
1222
       constants.FIRST_DRBD_PORT + 2, 24, 25, "ec0-secret2"),
1223
      ])
1224

    
1225

    
1226
if __name__ == "__main__":
1227
  testutils.GanetiTestProgram()