Revision a2d2e1a7
b/lib/cmdlib.py | ||
---|---|---|
32 | 32 |
import platform |
33 | 33 |
import logging |
34 | 34 |
import copy |
35 |
import itertools |
|
36 | 35 |
|
37 | 36 |
from ganeti import ssh |
38 | 37 |
from ganeti import utils |
... | ... | |
323 | 322 |
HTYPE = None |
324 | 323 |
|
325 | 324 |
|
326 |
class _FieldSet(object): |
|
327 |
"""A simple field set. |
|
328 |
|
|
329 |
Among the features are: |
|
330 |
- checking if a string is among a list of static string or regex objects |
|
331 |
- checking if a whole list of string matches |
|
332 |
- returning the matching groups from a regex match |
|
333 |
|
|
334 |
Internally, all fields are held as regular expression objects. |
|
335 |
|
|
336 |
""" |
|
337 |
def __init__(self, *items): |
|
338 |
self.items = [re.compile("^%s$" % value) for value in items] |
|
339 |
|
|
340 |
def Extend(self, other_set): |
|
341 |
"""Extend the field set with the items from another one""" |
|
342 |
self.items.extend(other_set.items) |
|
343 |
|
|
344 |
def Matches(self, field): |
|
345 |
"""Checks if a field matches the current set |
|
346 |
|
|
347 |
@type field: str |
|
348 |
@param field: the string to match |
|
349 |
@return: either False or a regular expression match object |
|
350 |
|
|
351 |
""" |
|
352 |
for m in itertools.ifilter(None, (val.match(field) for val in self.items)): |
|
353 |
return m |
|
354 |
return False |
|
355 |
|
|
356 |
def NonMatching(self, items): |
|
357 |
"""Returns the list of fields not matching the current set |
|
358 |
|
|
359 |
@type items: list |
|
360 |
@param items: the list of fields to check |
|
361 |
@rtype: list |
|
362 |
@return: list of non-matching fields |
|
363 |
|
|
364 |
""" |
|
365 |
return [val for val in items if not self.Matches(val)] |
|
366 |
|
|
367 |
|
|
368 | 325 |
def _GetWantedNodes(lu, nodes): |
369 | 326 |
"""Returns list of checked and expanded node names. |
370 | 327 |
|
... | ... | |
416 | 373 |
def _CheckOutputFields(static, dynamic, selected): |
417 | 374 |
"""Checks whether all selected fields are valid. |
418 | 375 |
|
419 |
@type static: L{_FieldSet}
|
|
376 |
@type static: L{utils.FieldSet}
|
|
420 | 377 |
@param static: static fields set |
421 |
@type dynamic: L{_FieldSet}
|
|
378 |
@type dynamic: L{utils.FieldSet}
|
|
422 | 379 |
@param dynamic: dynamic fields set |
423 | 380 |
|
424 | 381 |
""" |
425 |
f = _FieldSet()
|
|
382 |
f = utils.FieldSet()
|
|
426 | 383 |
f.Extend(static) |
427 | 384 |
f.Extend(dynamic) |
428 | 385 |
|
... | ... | |
1362 | 1319 |
""" |
1363 | 1320 |
_OP_REQP = ["output_fields", "names"] |
1364 | 1321 |
REQ_BGL = False |
1365 |
_FIELDS_STATIC = _FieldSet()
|
|
1366 |
_FIELDS_DYNAMIC = _FieldSet("name", "valid", "node_status")
|
|
1322 |
_FIELDS_STATIC = utils.FieldSet()
|
|
1323 |
_FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status")
|
|
1367 | 1324 |
|
1368 | 1325 |
def ExpandNames(self): |
1369 | 1326 |
if self.op.names: |
... | ... | |
1518 | 1475 |
""" |
1519 | 1476 |
_OP_REQP = ["output_fields", "names"] |
1520 | 1477 |
REQ_BGL = False |
1521 |
_FIELDS_DYNAMIC = _FieldSet(
|
|
1478 |
_FIELDS_DYNAMIC = utils.FieldSet(
|
|
1522 | 1479 |
"dtotal", "dfree", |
1523 | 1480 |
"mtotal", "mnode", "mfree", |
1524 | 1481 |
"bootid", |
1525 | 1482 |
"ctotal", |
1526 | 1483 |
) |
1527 | 1484 |
|
1528 |
_FIELDS_STATIC = _FieldSet(
|
|
1485 |
_FIELDS_STATIC = utils.FieldSet(
|
|
1529 | 1486 |
"name", "pinst_cnt", "sinst_cnt", |
1530 | 1487 |
"pinst_list", "sinst_list", |
1531 | 1488 |
"pip", "sip", "tags", |
... | ... | |
1657 | 1614 |
""" |
1658 | 1615 |
_OP_REQP = ["nodes", "output_fields"] |
1659 | 1616 |
REQ_BGL = False |
1660 |
_FIELDS_DYNAMIC = _FieldSet("phys", "vg", "name", "size", "instance")
|
|
1661 |
_FIELDS_STATIC = _FieldSet("node")
|
|
1617 |
_FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
|
|
1618 |
_FIELDS_STATIC = utils.FieldSet("node")
|
|
1662 | 1619 |
|
1663 | 1620 |
def ExpandNames(self): |
1664 | 1621 |
_CheckOutputFields(static=self._FIELDS_STATIC, |
... | ... | |
1979 | 1936 |
""" |
1980 | 1937 |
_OP_REQP = [] |
1981 | 1938 |
REQ_BGL = False |
1982 |
_FIELDS_DYNAMIC = _FieldSet()
|
|
1983 |
_FIELDS_STATIC = _FieldSet("cluster_name", "master_node", "drain_flag")
|
|
1939 |
_FIELDS_DYNAMIC = utils.FieldSet()
|
|
1940 |
_FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag")
|
|
1984 | 1941 |
|
1985 | 1942 |
def ExpandNames(self): |
1986 | 1943 |
self.needed_locks = {} |
... | ... | |
2714 | 2671 |
""" |
2715 | 2672 |
_OP_REQP = ["output_fields", "names"] |
2716 | 2673 |
REQ_BGL = False |
2717 |
_FIELDS_STATIC = _FieldSet(*["name", "os", "pnode", "snodes",
|
|
2718 |
"admin_state", "admin_ram", |
|
2719 |
"disk_template", "ip", "mac", "bridge", |
|
2720 |
"sda_size", "sdb_size", "vcpus", "tags", |
|
2721 |
"network_port", "beparams", |
|
2722 |
"(disk).(size)/([0-9]+)", |
|
2723 |
"(disk).(sizes)", |
|
2724 |
"(nic).(mac|ip|bridge)/([0-9]+)", |
|
2725 |
"(nic).(macs|ips|bridges)", |
|
2726 |
"(disk|nic).(count)", |
|
2727 |
"serial_no", "hypervisor", "hvparams",] + |
|
2728 |
["hv/%s" % name |
|
2729 |
for name in constants.HVS_PARAMETERS] + |
|
2730 |
["be/%s" % name |
|
2731 |
for name in constants.BES_PARAMETERS]) |
|
2732 |
_FIELDS_DYNAMIC = _FieldSet("oper_state", "oper_ram", "status")
|
|
2674 |
_FIELDS_STATIC = utils.FieldSet(*["name", "os", "pnode", "snodes",
|
|
2675 |
"admin_state", "admin_ram",
|
|
2676 |
"disk_template", "ip", "mac", "bridge",
|
|
2677 |
"sda_size", "sdb_size", "vcpus", "tags",
|
|
2678 |
"network_port", "beparams",
|
|
2679 |
"(disk).(size)/([0-9]+)",
|
|
2680 |
"(disk).(sizes)",
|
|
2681 |
"(nic).(mac|ip|bridge)/([0-9]+)",
|
|
2682 |
"(nic).(macs|ips|bridges)",
|
|
2683 |
"(disk|nic).(count)",
|
|
2684 |
"serial_no", "hypervisor", "hvparams",] +
|
|
2685 |
["hv/%s" % name
|
|
2686 |
for name in constants.HVS_PARAMETERS] +
|
|
2687 |
["be/%s" % name
|
|
2688 |
for name in constants.BES_PARAMETERS])
|
|
2689 |
_FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
|
|
2733 | 2690 |
|
2734 | 2691 |
|
2735 | 2692 |
def ExpandNames(self): |
b/lib/utils.py | ||
---|---|---|
1818 | 1818 |
# This is not nice and not absolutely atomic, but it appears to be the only |
1819 | 1819 |
# solution in Python -- there are no atomic types. |
1820 | 1820 |
self.called = True |
1821 |
|
|
1822 |
|
|
1823 |
class FieldSet(object): |
|
1824 |
"""A simple field set. |
|
1825 |
|
|
1826 |
Among the features are: |
|
1827 |
- checking if a string is among a list of static string or regex objects |
|
1828 |
- checking if a whole list of string matches |
|
1829 |
- returning the matching groups from a regex match |
|
1830 |
|
|
1831 |
Internally, all fields are held as regular expression objects. |
|
1832 |
|
|
1833 |
""" |
|
1834 |
def __init__(self, *items): |
|
1835 |
self.items = [re.compile("^%s$" % value) for value in items] |
|
1836 |
|
|
1837 |
def Extend(self, other_set): |
|
1838 |
"""Extend the field set with the items from another one""" |
|
1839 |
self.items.extend(other_set.items) |
|
1840 |
|
|
1841 |
def Matches(self, field): |
|
1842 |
"""Checks if a field matches the current set |
|
1843 |
|
|
1844 |
@type field: str |
|
1845 |
@param field: the string to match |
|
1846 |
@return: either False or a regular expression match object |
|
1847 |
|
|
1848 |
""" |
|
1849 |
for m in itertools.ifilter(None, (val.match(field) for val in self.items)): |
|
1850 |
return m |
|
1851 |
return False |
|
1852 |
|
|
1853 |
def NonMatching(self, items): |
|
1854 |
"""Returns the list of fields not matching the current set |
|
1855 |
|
|
1856 |
@type items: list |
|
1857 |
@param items: the list of fields to check |
|
1858 |
@rtype: list |
|
1859 |
@return: list of non-matching fields |
|
1860 |
|
|
1861 |
""" |
|
1862 |
return [val for val in items if not self.Matches(val)] |
b/test/ganeti.cmdlib_unittest.py | ||
---|---|---|
31 | 31 |
from ganeti import errors |
32 | 32 |
|
33 | 33 |
|
34 |
class FieldSetTestCase(unittest.TestCase): |
|
35 |
"""Test case for FieldSets""" |
|
36 |
|
|
37 |
def testSimpleMatch(self): |
|
38 |
f = cmdlib._FieldSet("a", "b", "c", "def") |
|
39 |
self.failUnless(f.Matches("a")) |
|
40 |
self.failIf(f.Matches("d"), "Substring matched") |
|
41 |
self.failIf(f.Matches("defghi"), "Prefix string matched") |
|
42 |
self.failIf(f.NonMatching(["b", "c"])) |
|
43 |
self.failIf(f.NonMatching(["a", "b", "c", "def"])) |
|
44 |
self.failUnless(f.NonMatching(["a", "d"])) |
|
45 |
|
|
46 |
def testRegexMatch(self): |
|
47 |
f = cmdlib._FieldSet("a", "b([0-9]+)", "c") |
|
48 |
self.failUnless(f.Matches("b1")) |
|
49 |
self.failUnless(f.Matches("b99")) |
|
50 |
self.failIf(f.Matches("b/1")) |
|
51 |
self.failIf(f.NonMatching(["b12", "c"])) |
|
52 |
self.failUnless(f.NonMatching(["a", "1"])) |
|
53 |
|
|
54 | 34 |
if __name__ == '__main__': |
55 | 35 |
unittest.main() |
b/test/ganeti.utils_unittest.py | ||
---|---|---|
824 | 824 |
self.assertRaises(AssertionError, utils.MergeTime, (-9999, 0)) |
825 | 825 |
|
826 | 826 |
|
827 |
class FieldSetTestCase(unittest.TestCase): |
|
828 |
"""Test case for FieldSets""" |
|
829 |
|
|
830 |
def testSimpleMatch(self): |
|
831 |
f = utils.FieldSet("a", "b", "c", "def") |
|
832 |
self.failUnless(f.Matches("a")) |
|
833 |
self.failIf(f.Matches("d"), "Substring matched") |
|
834 |
self.failIf(f.Matches("defghi"), "Prefix string matched") |
|
835 |
self.failIf(f.NonMatching(["b", "c"])) |
|
836 |
self.failIf(f.NonMatching(["a", "b", "c", "def"])) |
|
837 |
self.failUnless(f.NonMatching(["a", "d"])) |
|
838 |
|
|
839 |
def testRegexMatch(self): |
|
840 |
f = utils.FieldSet("a", "b([0-9]+)", "c") |
|
841 |
self.failUnless(f.Matches("b1")) |
|
842 |
self.failUnless(f.Matches("b99")) |
|
843 |
self.failIf(f.Matches("b/1")) |
|
844 |
self.failIf(f.NonMatching(["b12", "c"])) |
|
845 |
self.failUnless(f.NonMatching(["a", "1"])) |
|
846 |
|
|
847 |
|
|
827 | 848 |
if __name__ == '__main__': |
828 | 849 |
unittest.main() |
Also available in: Unified diff