Revision 23d95cff

b/Makefile.am
1032 1032
	test/py/ganeti.utils.io_unittest-runasroot.py \
1033 1033
	test/py/ganeti.utils.io_unittest.py \
1034 1034
	test/py/ganeti.utils.log_unittest.py \
1035
	test/py/ganeti.utils.lvm_unittest.py \
1035 1036
	test/py/ganeti.utils.mlock_unittest.py \
1036 1037
	test/py/ganeti.utils.nodesetup_unittest.py \
1037 1038
	test/py/ganeti.utils.process_unittest.py \
b/lib/bdev.py
542 542
    """Compute the number of PVs needed for an LV (with exclusive storage).
543 543

  
544 544
    @type size: float
545
    @param size: LV size
545
    @param size: LV size in MiB
546 546
    @param pvs_info: list of objects.LvmPvInfo, cannot be empty
547 547
    @rtype: integer
548 548
    @return: number of PVs needed
b/test/py/ganeti.bdev_unittest.py
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007, 2010, 2012 Google Inc.
4
# Copyright (C) 2006, 2007, 2010, 2012, 2013 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
23 23

  
24 24

  
25 25
import os
26
import random
26 27
import unittest
27 28

  
28 29
from ganeti import bdev
29
from ganeti import errors
30
from ganeti import compat
30 31
from ganeti import constants
32
from ganeti import errors
33
from ganeti import objects
31 34
from ganeti import utils
32
from ganeti import pathutils
33 35

  
34 36
import testutils
35 37

  
......
493 495
      ])
494 496

  
495 497

  
498
class TestExclusiveStoragePvs(unittest.TestCase):
499
  """Test cases for functions dealing with LVM PV and exclusive storage"""
500
  # Allowance for rounding
501
  _EPS = 1e-4
502
  _MARGIN = constants.PART_MARGIN + constants.PART_RESERVED + _EPS
503

  
504
  @staticmethod
505
  def _GenerateRandomPvInfo(rnd, name, vg):
506
    # Granularity is .01 MiB
507
    size = rnd.randint(1024 * 100, 10 * 1024 * 1024 * 100)
508
    if rnd.choice([False, True]):
509
      free = float(rnd.randint(0, size)) / 100.0
510
    else:
511
      free = float(size) / 100.0
512
    size = float(size) / 100.0
513
    attr = "a-"
514
    return objects.LvmPvInfo(name=name, vg_name=vg, size=size, free=free,
515
                             attributes=attr)
516

  
517
  def testGetStdPvSize(self):
518
    """Test cases for bdev.LogicalVolume._GetStdPvSize()"""
519
    rnd = random.Random(9517)
520
    for _ in range(0, 50):
521
      # Identical volumes
522
      pvi = self._GenerateRandomPvInfo(rnd, "disk", "myvg")
523
      onesize = bdev.LogicalVolume._GetStdPvSize([pvi])
524
      self.assertTrue(onesize <= pvi.size)
525
      self.assertTrue(onesize > pvi.size * (1 - self._MARGIN))
526
      for length in range(2, 10):
527
        n_size = bdev.LogicalVolume._GetStdPvSize([pvi] * length)
528
        self.assertEqual(onesize, n_size)
529

  
530
      # Mixed volumes
531
      for length in range(1, 10):
532
        pvlist = [self._GenerateRandomPvInfo(rnd, "disk", "myvg")
533
                  for _ in range(0, length)]
534
        std_size = bdev.LogicalVolume._GetStdPvSize(pvlist)
535
        self.assertTrue(compat.all(std_size <= pvi.size for pvi in pvlist))
536
        self.assertTrue(compat.any(std_size > pvi.size * (1 - self._MARGIN)
537
                                   for pvi in pvlist))
538
        pvlist.append(pvlist[0])
539
        p1_size = bdev.LogicalVolume._GetStdPvSize(pvlist)
540
        self.assertEqual(std_size, p1_size)
541

  
542
  def testComputeNumPvs(self):
543
    """Test cases for bdev.LogicalVolume._ComputeNumPvs()"""
544
    rnd = random.Random(8067)
545
    for _ in range(0, 1000):
546
      pvlist = [self._GenerateRandomPvInfo(rnd, "disk", "myvg")]
547
      lv_size = float(rnd.randint(10 * 100, 1024 * 1024 * 100)) / 100.0
548
      num_pv = bdev.LogicalVolume._ComputeNumPvs(lv_size, pvlist)
549
      std_size = bdev.LogicalVolume._GetStdPvSize(pvlist)
550
      self.assertTrue(num_pv >= 1)
551
      self.assertTrue(num_pv * std_size >= lv_size)
552
      self.assertTrue((num_pv - 1) * std_size < lv_size * (1 + self._EPS))
553

  
554
  def testGetEmptyPvNames(self):
555
    """Test cases for bdev.LogicalVolume._GetEmptyPvNames()"""
556
    rnd = random.Random(21126)
557
    for _ in range(0, 100):
558
      num_pvs = rnd.randint(1, 20)
559
      pvlist = [self._GenerateRandomPvInfo(rnd, "disk%d" % n, "myvg")
560
                for n in range(0, num_pvs)]
561
      for num_req in range(1, num_pvs + 2):
562
        epvs = bdev.LogicalVolume._GetEmptyPvNames(pvlist, num_req)
563
        epvs_set = compat.UniqueFrozenset(epvs)
564
        if len(epvs) > 1:
565
          self.assertEqual(len(epvs), len(epvs_set))
566
        for pvi in pvlist:
567
          if pvi.name in epvs_set:
568
            self.assertEqual(pvi.size, pvi.free)
569
          else:
570
            # There should be no remaining empty PV when less than the
571
            # requeste number of PVs has been returned
572
            self.assertTrue(len(epvs) == num_req or pvi.free != pvi.size)
573

  
574

  
496 575
if __name__ == "__main__":
497 576
  testutils.GanetiTestProgram()
b/test/py/ganeti.utils.lvm_unittest.py
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Script for testing ganeti.utils.lvm"""
23

  
24
import unittest
25

  
26
from ganeti import constants
27
from ganeti import utils
28
from ganeti.objects import LvmPvInfo
29

  
30
import testutils
31

  
32

  
33
class TestLvmExclusiveCheckNodePvs(unittest.TestCase):
34
  """Test cases for LvmExclusiveCheckNodePvs()"""
35
  _VG = "vg"
36
  _SMALL_PV = LvmPvInfo(name="small", vg_name=_VG, size=100e3, free=40e3,
37
                        attributes="a-")
38
  _MED_PV = LvmPvInfo(name="medium", vg_name=_VG, size=400e3, free=40e3,
39
                      attributes="a-")
40
  _BIG_PV = LvmPvInfo(name="big", vg_name=_VG, size=1e6, free=400e3,
41
                      attributes="a-")
42
  # Allowance for rounding
43
  _EPS = 1e-4
44

  
45
  def testOnePv(self):
46
    errmsgs = utils.LvmExclusiveCheckNodePvs([self._MED_PV])
47
    self.assertFalse(errmsgs)
48

  
49
  def testEqualPvs(self):
50
    errmsgs = utils.LvmExclusiveCheckNodePvs([self._MED_PV] * 2)
51
    self.assertFalse(errmsgs)
52
    errmsgs = utils.LvmExclusiveCheckNodePvs([self._SMALL_PV] * 3)
53
    self.assertFalse(errmsgs)
54

  
55
  def testTooDifferentPvs(self):
56
    errmsgs = utils.LvmExclusiveCheckNodePvs([self._MED_PV, self._BIG_PV])
57
    self.assertEqual(len(errmsgs), 1)
58
    errmsgs = utils.LvmExclusiveCheckNodePvs([self._MED_PV, self._SMALL_PV])
59
    self.assertEqual(len(errmsgs), 1)
60

  
61
  def testBoundarySizeCases(self):
62
    medpv1 = self._MED_PV.Copy()
63
    medpv2 = self._MED_PV.Copy()
64
    errmsgs = utils.LvmExclusiveCheckNodePvs([medpv1, medpv2, self._MED_PV])
65
    self.assertFalse(errmsgs)
66
    # Just within the margins
67
    medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN + self._EPS)
68
    medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN - self._EPS)
69
    errmsgs = utils.LvmExclusiveCheckNodePvs([medpv1, medpv2, self._MED_PV])
70
    self.assertFalse(errmsgs)
71
    # Just outside the margins
72
    medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN - self._EPS)
73
    medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN)
74
    errmsgs = utils.LvmExclusiveCheckNodePvs([medpv1, medpv2, self._MED_PV])
75
    self.assertTrue(errmsgs)
76
    medpv1.size = self._MED_PV.size * (1 - constants.PART_MARGIN)
77
    medpv2.size = self._MED_PV.size * (1 + constants.PART_MARGIN + self._EPS)
78
    errmsgs = utils.LvmExclusiveCheckNodePvs([medpv1, medpv2, self._MED_PV])
79
    self.assertTrue(errmsgs)
80

  
81

  
82
if __name__ == "__main__":
83
  testutils.GanetiTestProgram()

Also available in: Unified diff