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