Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.cmdlib_unittest.py @ 2096d068

History | View | Annotate | Download (26.7 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):
386
    self.warning_log = []
387
    self.info_log = []
388
    self.cfg = cfg
389

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

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

    
396

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

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

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

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

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

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

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

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

    
450

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

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

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

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

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

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

    
524

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

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

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

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

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

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

    
572

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

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

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

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

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

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

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

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

    
629

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

    
634

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

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

    
642

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

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

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

    
662

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

    
671
  def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes):
672
    assert self.mem_size == mem_size
673
    assert self.cpu_count == cpu_count
674
    assert self.disk_count == disk_count
675
    assert self.nic_count == nic_count
676
    assert self.disk_sizes == disk_sizes
677

    
678
    return []
679

    
680

    
681
class TestComputeIPolicyInstanceViolation(unittest.TestCase):
682
  def test(self):
683
    beparams = {
684
      constants.BE_MAXMEM: 2048,
685
      constants.BE_VCPUS: 2,
686
      }
687
    disks = [objects.Disk(size=512)]
688
    instance = objects.Instance(beparams=beparams, disks=disks, nics=[])
689
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512])
690
    ret = cmdlib._ComputeIPolicyInstanceViolation(NotImplemented, instance,
691
                                                  _compute_fn=stub)
692
    self.assertEqual(ret, [])
693

    
694

    
695
class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
696
  def test(self):
697
    ispec = {
698
      constants.ISPEC_MEM_SIZE: 2048,
699
      constants.ISPEC_CPU_COUNT: 2,
700
      constants.ISPEC_DISK_COUNT: 1,
701
      constants.ISPEC_DISK_SIZE: [512],
702
      constants.ISPEC_NIC_COUNT: 0,
703
      }
704
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512])
705
    ret = cmdlib._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
706
                                                      _compute_fn=stub)
707
    self.assertEqual(ret, [])
708

    
709

    
710
class _CallRecorder:
711
  def __init__(self, return_value=None):
712
    self.called = False
713
    self.return_value = return_value
714

    
715
  def __call__(self, *args):
716
    self.called = True
717
    return self.return_value
718

    
719

    
720
class TestComputeIPolicyNodeViolation(unittest.TestCase):
721
  def setUp(self):
722
    self.recorder = _CallRecorder(return_value=[])
723

    
724
  def testSameGroup(self):
725
    ret = cmdlib._ComputeIPolicyNodeViolation(NotImplemented, NotImplemented,
726
                                              "foo", "foo",
727
                                              _compute_fn=self.recorder)
728
    self.assertFalse(self.recorder.called)
729
    self.assertEqual(ret, [])
730

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

    
738

    
739
class _FakeConfigForTargetNodeIPolicy:
740
  def __init__(self, node_info=NotImplemented):
741
    self._node_info = node_info
742

    
743
  def GetNodeInfo(self, _):
744
    return self._node_info
745

    
746

    
747
class TestCheckTargetNodeIPolicy(unittest.TestCase):
748
  def setUp(self):
749
    self.instance = objects.Instance(primary_node="blubb")
750
    self.target_node = objects.Node(group="bar")
751
    node_info = objects.Node(group="foo")
752
    fake_cfg = _FakeConfigForTargetNodeIPolicy(node_info=node_info)
753
    self.lu = _FakeLU(cfg=fake_cfg)
754

    
755
  def testNoViolation(self):
756
    compute_recoder = _CallRecorder(return_value=[])
757
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
758
                                   self.target_node,
759
                                   _compute_fn=compute_recoder)
760
    self.assertTrue(compute_recoder.called)
761
    self.assertEqual(self.lu.warning_log, [])
762

    
763
  def testNoIgnore(self):
764
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
765
    self.assertRaises(errors.OpPrereqError, cmdlib._CheckTargetNodeIPolicy,
766
                      self.lu, NotImplemented, self.instance, self.target_node,
767
                      _compute_fn=compute_recoder)
768
    self.assertTrue(compute_recoder.called)
769
    self.assertEqual(self.lu.warning_log, [])
770

    
771
  def testIgnoreViolation(self):
772
    compute_recoder = _CallRecorder(return_value=["mem_size not in range"])
773
    cmdlib._CheckTargetNodeIPolicy(self.lu, NotImplemented, self.instance,
774
                                   self.target_node, ignore=True,
775
                                   _compute_fn=compute_recoder)
776
    self.assertTrue(compute_recoder.called)
777
    msg = ("Instance does not meet target node group's (bar) instance policy:"
778
           " mem_size not in range")
779
    self.assertEqual(self.lu.warning_log, [(msg, ())])
780

    
781

    
782
if __name__ == "__main__":
783
  testutils.GanetiTestProgram()