
This is the changelog between this and the previous pathset (v1): - PATCH 01/02: The documentation has been updated; The parameter names have been updated; The values None and '' are not valid size units, thus, DEFAULT_UNIT is not needed; An optimization for when 'to_unit' == 'from_unit' has been added; Test cases have been added; Crístian Viana (2): Add function to convert data sizes issue #595: Return correct memory value when VM is shutoff src/kimchi/i18n.py | 2 + src/kimchi/model/vms.py | 20 ++++++- src/kimchi/utils.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 69 +++++++++++++++++++++++ 4 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 tests/test_utils.py -- 2.1.0

The new function "kimchi.utils.convert_data_size" can be used to convert values from different units, e.g. converting 5 GiB to MiB, 1 GiB to B. Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com> --- src/kimchi/i18n.py | 2 + src/kimchi/utils.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 69 +++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 tests/test_utils.py diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 2af0be6..df5422f 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -267,6 +267,8 @@ messages = { "KCHUTILS0001E": _("Invalid URI %(uri)s"), "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), "KCHUTILS0003E": _("Unable to choose a virtual machine name"), + "KCHUTILS0004E": _("Invalid data value '%(value)s'"), + "KCHUTILS0005E": _("Invalid data unit '%(unit)s'"), "KCHVMSTOR0002E": _("Invalid storage type. Types supported: 'cdrom', 'disk'"), "KCHVMSTOR0003E": _("The path '%(value)s' is not a valid local/remote path for the device"), diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index fc5245f..f1ef12c 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -388,3 +388,148 @@ def get_unique_file_name(all_names, name): max_num = max(max_num, int(match.group(re_group_num))) return u'%s (%d)' % (name, max_num + 1) + + +def convert_data_size(value, from_unit, to_unit='B'): + """Convert a data value from one unit to another unit + (e.g. 'MiB' -> 'GiB'). + + The data units supported by this function are made up of one prefix and one + suffix. The valid prefixes are those defined in the SI (i.e. metric system) + and those defined by the IEC, and the valid suffixes indicate if the base + unit is bit or byte. + Take a look at the tables below for the possible values: + + Prefixes: + + ================================== =================================== + PREFIX (SI) | DESCRIPTION | VALUE PREFIX (IEC) | DESCRIPTION | VALUE + ================================== =================================== + k | kilo | 1000 Ki | kibi | 1024 + ---------------------------------- ----------------------------------- + M | mega | 1000^2 Mi | mebi | 1024^2 + ---------------------------------- ----------------------------------- + G | giga | 1000^3 Gi | gibi | 1024^3 + ---------------------------------- ----------------------------------- + T | tera | 1000^4 Ti | tebi | 1024^4 + ---------------------------------- ----------------------------------- + P | peta | 1000^5 Pi | pebi | 1024^5 + ---------------------------------- ----------------------------------- + E | exa | 1000^6 Ei | exbi | 1024^6 + ---------------------------------- ----------------------------------- + Z | zetta | 1000^7 Zi | zebi | 1024^7 + ---------------------------------- ----------------------------------- + Y | yotta | 1000^8 Yi | yobi | 1024^8 + ================================== =================================== + + Suffixes: + + ======================= + SUFFIX | DESCRIPTION + ======================= + b | bit + ----------------------- + B | byte (default) + ======================= + + See http://en.wikipedia.org/wiki/Binary_prefix for more details on + those units. + + If a wrong unit is provided, an error will be raised. + + Examples: + convert_data_size(5, 'MiB', 'KiB') -> 5120.0 + convert_data_size(5, 'MiB', 'M') -> 5.24288 + convert_data_size(5, 'MiB', 'GiB') -> 0.0048828125 + convert_data_size(5, 'MiB', 'Tb') -> 4.194304e-05 + convert_data_size(5, 'MiB') -> 5242880.0 + convert_data_size(5, 'mib') -> #ERROR# (invalid from_unit) + + Parameters: + value -- the value to be converted, in the unit specified by 'from_unit'. + this parameter can be of any type which can be cast to float + (e.g. int, float, str). + from_unit -- the unit of 'value', as described above. + to_unit -- the unit of the return value, as described above. + + Return: + A float number representing 'value' (in 'from_unit') converted + to 'to_unit'. + """ + SI_PREFIXES = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] + # The IEC prefixes are the equivalent SI prefixes + 'i' + # but, exceptionally, 'k' becomes 'Ki' instead of 'ki'. + IEC_PREFIXES = map(lambda p: 'Ki' if p == 'k' else p + 'i', SI_PREFIXES) + PREFIXES_BY_BASE = {1000: SI_PREFIXES, + 1024: IEC_PREFIXES} + + SUFFIXES_WITH_MULT = {'b': 1, + 'B': 8} + DEFAULT_SUFFIX = 'B' + + if not from_unit: + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if not to_unit: + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + + # set the default suffix + if from_unit[-1] not in SUFFIXES_WITH_MULT: + from_unit += DEFAULT_SUFFIX + if to_unit[-1] not in SUFFIXES_WITH_MULT: + to_unit += DEFAULT_SUFFIX + + # split prefix and suffix for better parsing + from_p = from_unit[:-1] + from_s = from_unit[-1] + to_p = to_unit[:-1] + to_s = to_unit[-1] + + # validate parameters + try: + value = float(value) + except TypeError: + raise InvalidParameter('KCHUTILS0004E', {'value': value}) + if from_p != '' and from_p not in (SI_PREFIXES + IEC_PREFIXES): + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if from_s not in SUFFIXES_WITH_MULT: + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if to_p != '' and to_p not in (SI_PREFIXES + IEC_PREFIXES): + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + if to_s not in SUFFIXES_WITH_MULT: + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + + # if the units are the same, return the input value + if from_unit == to_unit: + return value + + # convert 'value' to the most basic unit (bits)... + bits = value + + for suffix, mult in SUFFIXES_WITH_MULT.iteritems(): + if from_s == suffix: + bits *= mult + break + + if from_p != '': + for base, prefixes in PREFIXES_BY_BASE.iteritems(): + for i, p in enumerate(prefixes): + if from_p == p: + bits *= base**(i + 1) + break + + # ...then convert the value in bits to the destination unit + ret = bits + + for suffix, mult in SUFFIXES_WITH_MULT.iteritems(): + if to_s == suffix: + ret /= float(mult) + break + + if to_p != '': + for base, prefixes in PREFIXES_BY_BASE.iteritems(): + for i, p in enumerate(prefixes): + if to_p == p: + ret /= float(base)**(i + 1) + break + + return ret diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..b8ff621 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest + +from kimchi.exception import InvalidParameter +from kimchi.utils import convert_data_size + + +class UtilsTests(unittest.TestCase): + def test_convert_data_size(self): + failure_data = [{'val': None, 'from': 'MiB'}, + {'val': self, 'from': 'MiB'}, + {'val': 1, 'from': None}, + {'val': 1, 'from': ''}, + {'val': 1, 'from': 'foo'}, + {'val': 1, 'from': 'kib'}, + {'val': 1, 'from': 'MiB', 'to': None}, + {'val': 1, 'from': 'MiB', 'to': ''}, + {'val': 1, 'from': 'MiB', 'to': 'foo'}, + {'val': 1, 'from': 'MiB', 'to': 'kib'}] + + for d in failure_data: + if 'to' in d: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from'], d['to']) + else: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from']) + + success_data = [{'got': convert_data_size(5, 'MiB', 'MiB'), + 'want': 5}, + {'got': convert_data_size(5, 'MiB', 'KiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'MiB', 'M'), + 'want': 5.24288}, + {'got': convert_data_size(5, 'MiB', 'GiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'MiB', 'Tb'), + 'want': 4.194304e-05}, + {'got': convert_data_size(5, 'KiB', 'MiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'M', 'MiB'), + 'want': 4.76837158203125}, + {'got': convert_data_size(5, 'GiB', 'MiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'Tb', 'MiB'), + 'want': 596046.4477539062}, + {'got': convert_data_size(5, 'MiB'), + 'want': convert_data_size(5, 'MiB', 'B')}] + + for d in success_data: + self.assertEquals(d['got'], d['want']) -- 2.1.0

Reviewed-by: Paulo Vital <pvital@gmail.com> Tested-by: Paulo Vital <pvital@gmail.com> On Tue, 2015-03-03 at 16:42 -0300, Crístian Viana wrote:
The new function "kimchi.utils.convert_data_size" can be used to convert values from different units, e.g. converting 5 GiB to MiB, 1 GiB to B.
Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com> --- src/kimchi/i18n.py | 2 + src/kimchi/utils.py | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test_utils.py | 69 +++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 tests/test_utils.py
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 2af0be6..df5422f 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -267,6 +267,8 @@ messages = { "KCHUTILS0001E": _("Invalid URI %(uri)s"), "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), "KCHUTILS0003E": _("Unable to choose a virtual machine name"), + "KCHUTILS0004E": _("Invalid data value '%(value)s'"), + "KCHUTILS0005E": _("Invalid data unit '%(unit)s'"),
"KCHVMSTOR0002E": _("Invalid storage type. Types supported: 'cdrom', 'disk'"), "KCHVMSTOR0003E": _("The path '%(value)s' is not a valid local/remote path for the device"), diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index fc5245f..f1ef12c 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -388,3 +388,148 @@ def get_unique_file_name(all_names, name): max_num = max(max_num, int(match.group(re_group_num)))
return u'%s (%d)' % (name, max_num + 1) + + +def convert_data_size(value, from_unit, to_unit='B'): + """Convert a data value from one unit to another unit + (e.g. 'MiB' -> 'GiB'). + + The data units supported by this function are made up of one prefix and one + suffix. The valid prefixes are those defined in the SI (i.e. metric system) + and those defined by the IEC, and the valid suffixes indicate if the base + unit is bit or byte. + Take a look at the tables below for the possible values: + + Prefixes: + + ================================== =================================== + PREFIX (SI) | DESCRIPTION | VALUE PREFIX (IEC) | DESCRIPTION | VALUE + ================================== =================================== + k | kilo | 1000 Ki | kibi | 1024 + ---------------------------------- ----------------------------------- + M | mega | 1000^2 Mi | mebi | 1024^2 + ---------------------------------- ----------------------------------- + G | giga | 1000^3 Gi | gibi | 1024^3 + ---------------------------------- ----------------------------------- + T | tera | 1000^4 Ti | tebi | 1024^4 + ---------------------------------- ----------------------------------- + P | peta | 1000^5 Pi | pebi | 1024^5 + ---------------------------------- ----------------------------------- + E | exa | 1000^6 Ei | exbi | 1024^6 + ---------------------------------- ----------------------------------- + Z | zetta | 1000^7 Zi | zebi | 1024^7 + ---------------------------------- ----------------------------------- + Y | yotta | 1000^8 Yi | yobi | 1024^8 + ================================== =================================== + + Suffixes: + + ======================= + SUFFIX | DESCRIPTION + ======================= + b | bit + ----------------------- + B | byte (default) + ======================= + + See http://en.wikipedia.org/wiki/Binary_prefix for more details on + those units. + + If a wrong unit is provided, an error will be raised. + + Examples: + convert_data_size(5, 'MiB', 'KiB') -> 5120.0 + convert_data_size(5, 'MiB', 'M') -> 5.24288 + convert_data_size(5, 'MiB', 'GiB') -> 0.0048828125 + convert_data_size(5, 'MiB', 'Tb') -> 4.194304e-05 + convert_data_size(5, 'MiB') -> 5242880.0 + convert_data_size(5, 'mib') -> #ERROR# (invalid from_unit) + + Parameters: + value -- the value to be converted, in the unit specified by 'from_unit'. + this parameter can be of any type which can be cast to float + (e.g. int, float, str). + from_unit -- the unit of 'value', as described above. + to_unit -- the unit of the return value, as described above. + + Return: + A float number representing 'value' (in 'from_unit') converted + to 'to_unit'. + """ + SI_PREFIXES = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] + # The IEC prefixes are the equivalent SI prefixes + 'i' + # but, exceptionally, 'k' becomes 'Ki' instead of 'ki'. + IEC_PREFIXES = map(lambda p: 'Ki' if p == 'k' else p + 'i', SI_PREFIXES) + PREFIXES_BY_BASE = {1000: SI_PREFIXES, + 1024: IEC_PREFIXES} + + SUFFIXES_WITH_MULT = {'b': 1, + 'B': 8} + DEFAULT_SUFFIX = 'B' + + if not from_unit: + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if not to_unit: + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + + # set the default suffix + if from_unit[-1] not in SUFFIXES_WITH_MULT: + from_unit += DEFAULT_SUFFIX + if to_unit[-1] not in SUFFIXES_WITH_MULT: + to_unit += DEFAULT_SUFFIX + + # split prefix and suffix for better parsing + from_p = from_unit[:-1] + from_s = from_unit[-1] + to_p = to_unit[:-1] + to_s = to_unit[-1] + + # validate parameters + try: + value = float(value) + except TypeError: + raise InvalidParameter('KCHUTILS0004E', {'value': value}) + if from_p != '' and from_p not in (SI_PREFIXES + IEC_PREFIXES): + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if from_s not in SUFFIXES_WITH_MULT: + raise InvalidParameter('KCHUTILS0005E', {'unit': from_unit}) + if to_p != '' and to_p not in (SI_PREFIXES + IEC_PREFIXES): + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + if to_s not in SUFFIXES_WITH_MULT: + raise InvalidParameter('KCHUTILS0005E', {'unit': to_unit}) + + # if the units are the same, return the input value + if from_unit == to_unit: + return value + + # convert 'value' to the most basic unit (bits)... + bits = value + + for suffix, mult in SUFFIXES_WITH_MULT.iteritems(): + if from_s == suffix: + bits *= mult + break + + if from_p != '': + for base, prefixes in PREFIXES_BY_BASE.iteritems(): + for i, p in enumerate(prefixes): + if from_p == p: + bits *= base**(i + 1) + break + + # ...then convert the value in bits to the destination unit + ret = bits + + for suffix, mult in SUFFIXES_WITH_MULT.iteritems(): + if to_s == suffix: + ret /= float(mult) + break + + if to_p != '': + for base, prefixes in PREFIXES_BY_BASE.iteritems(): + for i, p in enumerate(prefixes): + if to_p == p: + ret /= float(base)**(i + 1) + break + + return ret diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..b8ff621 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2015 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import unittest + +from kimchi.exception import InvalidParameter +from kimchi.utils import convert_data_size + + +class UtilsTests(unittest.TestCase): + def test_convert_data_size(self): + failure_data = [{'val': None, 'from': 'MiB'}, + {'val': self, 'from': 'MiB'}, + {'val': 1, 'from': None}, + {'val': 1, 'from': ''}, + {'val': 1, 'from': 'foo'}, + {'val': 1, 'from': 'kib'}, + {'val': 1, 'from': 'MiB', 'to': None}, + {'val': 1, 'from': 'MiB', 'to': ''}, + {'val': 1, 'from': 'MiB', 'to': 'foo'}, + {'val': 1, 'from': 'MiB', 'to': 'kib'}] + + for d in failure_data: + if 'to' in d: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from'], d['to']) + else: + self.assertRaises(InvalidParameter, convert_data_size, + d['val'], d['from']) + + success_data = [{'got': convert_data_size(5, 'MiB', 'MiB'), + 'want': 5}, + {'got': convert_data_size(5, 'MiB', 'KiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'MiB', 'M'), + 'want': 5.24288}, + {'got': convert_data_size(5, 'MiB', 'GiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'MiB', 'Tb'), + 'want': 4.194304e-05}, + {'got': convert_data_size(5, 'KiB', 'MiB'), + 'want': 0.0048828125}, + {'got': convert_data_size(5, 'M', 'MiB'), + 'want': 4.76837158203125}, + {'got': convert_data_size(5, 'GiB', 'MiB'), + 'want': 5120}, + {'got': convert_data_size(5, 'Tb', 'MiB'), + 'want': 596046.4477539062}, + {'got': convert_data_size(5, 'MiB'), + 'want': convert_data_size(5, 'MiB', 'B')}] + + for d in success_data: + self.assertEquals(d['got'], d['want'])

Newer libvirt versions report 0 when reading the current memory of a shutoff VM by calling the method "domain.info()". So when the VM is shutoff, the REST command "GET /vms/<vm>" is returning an invalid memory value. Read the memory value from the VM's XML descriptor when it is shutoff, and keep returning the value from "domain.info()" otherwise. Fix issue #595 (Memory is set to 0 (null) when editing guest). Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 018df9e..4c5f443 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -41,8 +41,8 @@ from kimchi.model.utils import get_metadata_node from kimchi.model.utils import set_metadata_node from kimchi.rollbackcontext import RollbackContext from kimchi.screenshot import VMScreenshot -from kimchi.utils import add_task, get_next_clone_name, import_class -from kimchi.utils import kimchi_log, run_setfacl_set_attr +from kimchi.utils import add_task, convert_data_size, get_next_clone_name +from kimchi.utils import import_class, kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update from kimchi.xmlutils.utils import dictize @@ -70,6 +70,8 @@ XPATH_DOMAIN_NAME = '/domain/name' XPATH_DOMAIN_MAC = "/domain/devices/interface[@type='network']/mac/@address" XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface[@type='network']/"\ "mac[@address='%s']" +XPATH_DOMAIN_MEMORY = '/domain/memory' +XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit' XPATH_DOMAIN_UUID = '/domain/uuid' @@ -819,11 +821,23 @@ class VMModel(object): res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100) users, groups = self._get_access_info(dom) + if state == 'shutoff': + xml = dom.XMLDesc(0) + val = xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0] + unit_list = xpath_get_text(xml, XPATH_DOMAIN_MEMORY_UNIT) + if len(unit_list) > 0: + unit = unit_list[0] + else: + unit = 'KiB' + memory = convert_data_size(val, unit, 'MiB') + else: + memory = info[2] >> 10 + return {'name': name, 'state': state, 'stats': res, 'uuid': dom.UUIDString(), - 'memory': info[2] >> 10, + 'memory': memory, 'cpus': info[3], 'screenshot': screenshot, 'icon': icon, -- 2.1.0

Reviewed-by: Paulo Vital <pvital@gmail.com> Tested-by: Paulo Vital <pvital@gmail.com> On Tue, 2015-03-03 at 16:42 -0300, Crístian Viana wrote:
Newer libvirt versions report 0 when reading the current memory of a shutoff VM by calling the method "domain.info()". So when the VM is shutoff, the REST command "GET /vms/<vm>" is returning an invalid memory value.
Read the memory value from the VM's XML descriptor when it is shutoff, and keep returning the value from "domain.info()" otherwise.
Fix issue #595 (Memory is set to 0 (null) when editing guest).
Signed-off-by: Crístian Viana <vianac@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 018df9e..4c5f443 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -41,8 +41,8 @@ from kimchi.model.utils import get_metadata_node from kimchi.model.utils import set_metadata_node from kimchi.rollbackcontext import RollbackContext from kimchi.screenshot import VMScreenshot -from kimchi.utils import add_task, get_next_clone_name, import_class -from kimchi.utils import kimchi_log, run_setfacl_set_attr +from kimchi.utils import add_task, convert_data_size, get_next_clone_name +from kimchi.utils import import_class, kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update from kimchi.xmlutils.utils import dictize @@ -70,6 +70,8 @@ XPATH_DOMAIN_NAME = '/domain/name' XPATH_DOMAIN_MAC = "/domain/devices/interface[@type='network']/mac/@address" XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface[@type='network']/"\ "mac[@address='%s']" +XPATH_DOMAIN_MEMORY = '/domain/memory' +XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit' XPATH_DOMAIN_UUID = '/domain/uuid'
@@ -819,11 +821,23 @@ class VMModel(object): res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100) users, groups = self._get_access_info(dom)
+ if state == 'shutoff': + xml = dom.XMLDesc(0) + val = xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0] + unit_list = xpath_get_text(xml, XPATH_DOMAIN_MEMORY_UNIT) + if len(unit_list) > 0: + unit = unit_list[0] + else: + unit = 'KiB' + memory = convert_data_size(val, unit, 'MiB') + else: + memory = info[2] >> 10 + return {'name': name, 'state': state, 'stats': res, 'uuid': dom.UUIDString(), - 'memory': info[2] >> 10, + 'memory': memory, 'cpus': info[3], 'screenshot': screenshot, 'icon': icon,
participants (3)
-
Aline Manera
-
Crístian Viana
-
Paulo Ricardo Paz Vital