[Kimchi-devel] [PATCH V2] [Ginger-Base 1/1] Issue 728 - Processor Info in s390 architecture
Suresh Babu Angadi
sureshab at linux.vnet.ibm.com
Thu Nov 26 10:44:33 UTC 2015
On 11/25/2015 11:18 PM, Rodrigo Trujillo wrote:
> Minor issue below
>
> Rodrigo
>
> On 11/24/2015 09:59 AM, sureshab at linux.vnet.ibm.com wrote:
>> From: Suresh Babu Angadi <sureshab at in.ibm.com>
>>
>> Fix for issue 728: processor info displays blank for system z
>> this patch set also adds additional capability:
>> retrieving architecture and host name (for all architecture)
>> split CPUs to show online and offline cpus also
>> includes shared and dedicated cpus for s390x
>> split memory to show online and offline
>> additional virtualization details(for s390x):
>> virtualization will have hypervisor details and lpar details
>>
>> Signed-off-by: Suresh Babu Angadi <sureshab at in.ibm.com>
>> ---
>> src/wok/plugins/gingerbase/docs/API.md | 18 +-
>> src/wok/plugins/gingerbase/i18n.py | 1 +
>> src/wok/plugins/gingerbase/lscpu.py | 60 ++++++
>> src/wok/plugins/gingerbase/model/host.py | 259
>> ++++++++++++++++++++++----
>> src/wok/plugins/gingerbase/tests/test_host.py | 12 +-
>> 5 files changed, 307 insertions(+), 43 deletions(-)
>>
>> diff --git a/src/wok/plugins/gingerbase/docs/API.md
>> b/src/wok/plugins/gingerbase/docs/API.md
>> index 8f37ddc..30b0c8f 100644
>> --- a/src/wok/plugins/gingerbase/docs/API.md
>> +++ b/src/wok/plugins/gingerbase/docs/API.md
>> @@ -95,13 +95,25 @@ Contains information of host.
>> **Methods:**
>>
>> * **GET**: Retrieve host static information
>> - * memory: Total size of host physical memory
>> - The unit is Bytes
>> + * memory: Memory details of the host. The unit is Bytes
>> + * online: Total size of physical memory currently
>> available to host
>> + * offline: Total offline memory(for s390x), zero for
>> other architectures.
>> * cpu_model: The model name of host CPU
>> - * cpus: The number of online CPUs available on host
>> + * cpus: The host cpus information
>> + * online: Number of online CPUs
>> + * offline: Number of offline CPUs
>> + * shared *(s390x only)*: Number of shared CPUs
>> + * dedicated *(s390x only)*: Number of dedicated CPUs
>> * os_distro: The OS distribution that runs on host
>> * os_version: The version of OS distribution
>> * os_codename: The code name of OS distribution
>> + * host: Host name of the network node
>> + * architecture: Architecture of the host
>> + * virtualization *(s390x only)*: This is a json with following keys
>> + * hypervisor: Hypervisor name of the host
>> + * hypervisor_vendor: Hypervisor Vendor name
>> + * lpar_number: LPAR Number of host
>> + * lpar_name: Name of host LPAR
>>
>> * **POST**: *See Host Actions*
>>
>> diff --git a/src/wok/plugins/gingerbase/i18n.py
>> b/src/wok/plugins/gingerbase/i18n.py
>> index af75c70..a0a8c36 100644
>> --- a/src/wok/plugins/gingerbase/i18n.py
>> +++ b/src/wok/plugins/gingerbase/i18n.py
>> @@ -88,5 +88,6 @@ messages = {
>> "GGBCPUINF0005E": _("This host (or current configuration) does
>> not provide Socket(s) information."),
>> "GGBCPUINF0006E": _("This host (or current configuration) does
>> not provide Core(s) per socket information."),
>> "GGBCPUINF0007E": _("This host (or current configuration) does
>> not provide Thread(s) per core information."),
>> + "GGBCPUINF0008E": _("This host (or current configuration) does
>> not provide CPU(s) information."),
>>
>> }
>> diff --git a/src/wok/plugins/gingerbase/lscpu.py
>> b/src/wok/plugins/gingerbase/lscpu.py
>> index 0fc1e72..4686049 100644
>> --- a/src/wok/plugins/gingerbase/lscpu.py
>> +++ b/src/wok/plugins/gingerbase/lscpu.py
>> @@ -17,10 +17,13 @@
>> # 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 logging
>> +import platform
>>
>> from wok.utils import run_command
>> from wok.exception import NotFoundError
>>
>> +ARCH = platform.machine()
>> +
>>
>> class LsCpu(object):
>> """
>> @@ -64,6 +67,28 @@ class LsCpu(object):
>> # L2 cache: 256K
>> # L3 cache: 3072K
>> # NUMA node0 CPU(s): 0-3
>> + #
>> + # Output of lscpu in s390x is expected to be
>> + # Architecture: s390x
>> + # CPU op-mode(s): 32-bit, 64-bit
>> + # Byte Order: Big Endian
>> + # CPU(s): 4
>> + # On-line CPU(s) list: 0,1
>> + # Off-line CPU(s) list: 2,3
>> + # Thread(s) per core: 1
>> + # Core(s) per socket: 6
>> + # Socket(s) per book: 6
>> + # Book(s): 4
>> + # Vendor ID: IBM/S390
>> + # BogoMIPS: 18115.00
>> + # Hypervisor: PR/SM
>> + # Hypervisor vendor: IBM
>> + # Virtualization type: full
>> + # Dispatching mode: horizontal
>> + # L1d cache: 96K
>> + # L1i cache: 64K
>> + # L2d cache: 1024K
>> + # L2i cache: 1024K
>>
>> if not rc and (not out.isspace()):
>> lscpuout = out.split('\n')
>> @@ -85,6 +110,8 @@ class LsCpu(object):
>> """
>> try:
>> sockets = "Socket(s)"
>> + if ARCH.startswith('s390x'):
>> + sockets = "Socket(s) per book"
>> if len(self.lsCpuInfo) > 0 and sockets in
>> self.lsCpuInfo.keys():
>> return int(self.lsCpuInfo[sockets])
>> else:
>> @@ -124,3 +151,36 @@ class LsCpu(object):
>> except IndexError, e:
>> self.log_error(e)
>> raise NotFoundError("GGBCPUINF0007E")
>> +
>> + def get_total_cpus(self):
>> + """
> Missing information here
good catch. Will add the description :-)
>> +
>> + :return:
>> + """
>> + total_cpus = 'CPU(s)'
>> + if len(self.lsCpuInfo) > 0 and total_cpus in
>> self.lsCpuInfo.keys():
>> + return int(self.lsCpuInfo[total_cpus])
>> + else:
>> + self.log_error("Failed to fetch total cpus count in
>> lscpu output")
>> + raise NotFoundError("GGBCPUINF0008E")
>> +
>> + def get_hypervisor(self):
>> + """
>> + method to get hypervisor name if present in lscpu o/p
>> + :return: Hypervisor Name
>> + """
>> + hypervisor = 'Hypervisor'
>> + if len(self.lsCpuInfo) > 0 and hypervisor in
>> self.lsCpuInfo.keys():
>> + return self.lsCpuInfo[hypervisor]
>> + return None
>> +
>> + def get_hypervisor_vendor(self):
>> + """
>> + method to get hypervisor vendor if present in lscpu o/p
>> + :return: Hypervisor Vendor
>> + """
>> + hypervisor_vendor = 'Hypervisor vendor'
>> + if len(self.lsCpuInfo) > 0 and hypervisor_vendor in \
>> + self.lsCpuInfo.keys():
>> + return self.lsCpuInfo[hypervisor_vendor]
>> + return None
>> diff --git a/src/wok/plugins/gingerbase/model/host.py
>> b/src/wok/plugins/gingerbase/model/host.py
>> index a58bada..fd4db29 100644
>> --- a/src/wok/plugins/gingerbase/model/host.py
>> +++ b/src/wok/plugins/gingerbase/model/host.py
>> @@ -22,6 +22,7 @@
>> import os
>> import platform
>> import psutil
>> +import re
>> import time
>> from cherrypy.process.plugins import BackgroundTask
>> from collections import defaultdict
>> @@ -31,9 +32,10 @@ from wok.basemodel import Singleton
>> from wok.config import config as kconfig
>> from wok.exception import InvalidOperation
>> from wok.exception import OperationFailed
>> -from wok.utils import add_task, wok_log
>> +from wok.utils import add_task, run_command, wok_log
>> from wok.model.tasks import TaskModel
>>
>> +from wok.plugins.gingerbase.lscpu import LsCpu
>> from wok.plugins.gingerbase.model.debugreports import
>> DebugReportsModel
>> from wok.plugins.gingerbase.repositories import Repositories
>> from wok.plugins.gingerbase.swupdate import SoftwareUpdate
>> @@ -48,17 +50,29 @@ DOM_STATE_MAP = {0: 'nostate',
>> 6: 'crashed',
>> 7: 'pmsuspended'}
>>
>> +ARCH = platform.machine()
>> +PROC_CPUINFO = '/proc/cpuinfo'
>> +PROC_SYSINFO = '/proc/sysinfo'
>> +LSMEM = 'lsmem'
>> +CPUS_DEDICATED = 'cpus_dedicated'
>> +CPUS_SHARED = 'cpus_shared'
>> +LPAR_NAME = 'lpar_name'
>> +LPAR_NUMBER = 'lpar_number'
>> +
>>
>> class HostModel(object):
>> def __init__(self, **kargs):
>> # self.conn = kargs['conn']
>> self.objstore = kargs['objstore']
>> self.task = TaskModel(**kargs)
>> - self.host_info = self._get_host_info()
>> + self.lscpu = LsCpu()
>>
>> - def _get_ppc_cpu_info(self):
>> + def _get_ppc_cpu_model(self):
>> + """
>> + method to get cpu_model for ppc architecture
>> + """
>> res = {}
>> - with open('/proc/cpuinfo') as f:
>> + with open(PROC_CPUINFO) as f:
>> for line in f.xreadlines():
>> # Parse CPU, CPU's revision and CPU's clock
>> information
>> for key in ['cpu', 'revision', 'clock']:
>> @@ -81,56 +95,227 @@ class HostModel(object):
>>
>> return ""
>>
>> - def _get_host_info(self):
>> - res = {}
>> - if platform.machine().startswith('ppc'):
>> - res['cpu_model'] = self._get_ppc_cpu_info()
>> - else:
>> - with open('/proc/cpuinfo') as f:
>> + def _get_x86_cpu_model(self):
>> + """
>> + method to get cpu_model for x86 architecture
>> + """
>> + try:
>> + with open(PROC_CPUINFO) as f:
>> for line in f.xreadlines():
>> if "model name" in line:
>> - res['cpu_model'] = line.split(':')[1].strip()
>> + return line.split(':')[1].strip()
>> break
>> + except Exception as e:
>> + wok_log.error("Failed to retrive cpu_model for "
>> + "%s. Error: %s", ARCH, e.__str__())
>> + return ""
>>
>> - res['cpus'] = 0
>> - res['memory'] = 0L
>> -
>> - # Include IBM PowerKVM name to supported distro names
>> - _sup_distros = platform._supported_dists + ('ibm_powerkvm',)
>> - # 'fedora' '17' 'Beefy Miracle'
>> - distro, version, codename = platform.linux_distribution(
>> - supported_dists=_sup_distros)
>> - res['os_distro'] = distro
>> - res['os_version'] = version
>> - res['os_codename'] = unicode(codename, "utf-8")
>> -
>> - return res
>> -
>> - def lookup(self, *name):
>> - cpus = psutil.NUM_CPUS
>> -
>> + def _get_s390x_host_info(self):
>> + """
>> + method to get additional host details
>> + specific to s390x architecture
>> + :return: dictionary
>> + """
>> + host_info = {}
>> + host_info['cpus'] = self._get_cpus()
>> + host_info['cpus']['dedicated'] = 0
>> + host_info['cpus']['shared'] = 0
>> + host_info['cpu_model'] = ""
>> + host_info['virtualization'] = {}
>> + s390x_sysinfo = self._get_s390x_sysinfo()
>> + if 'manufacturer' in s390x_sysinfo.keys():
>> + host_info['cpu_model'] = s390x_sysinfo['manufacturer']
>> + if 'type' in s390x_sysinfo.keys():
>> + host_info['cpu_model'] = \
>> + host_info['cpu_model'] + "/" + s390x_sysinfo['type']
>> + if 'model' in s390x_sysinfo.keys():
>> + host_info['cpu_model'] = \
>> + host_info['cpu_model'] + "/" + s390x_sysinfo['model']
>> + if CPUS_DEDICATED in s390x_sysinfo.keys():
>> + host_info['cpus']['dedicated'] =
>> s390x_sysinfo[CPUS_DEDICATED]
>> + if CPUS_SHARED in s390x_sysinfo.keys():
>> + host_info['cpus']['shared'] = s390x_sysinfo[CPUS_SHARED]
>> + host_info['virtualization']['hypervisor'] = \
>> + self.lscpu.get_hypervisor()
>> + host_info['virtualization']['hypervisor_vendor'] = \
>> + self.lscpu.get_hypervisor_vendor()
>> + host_info['virtualization'][LPAR_NAME] = ''
>> + host_info['virtualization'][LPAR_NUMBER] = ''
>> + if LPAR_NAME in s390x_sysinfo.keys():
>> + host_info['virtualization'][LPAR_NAME] =
>> s390x_sysinfo[LPAR_NAME]
>> + if LPAR_NUMBER in s390x_sysinfo.keys():
>> + host_info['virtualization'][LPAR_NUMBER] = \
>> + s390x_sysinfo[LPAR_NUMBER]
>> +
>> + return host_info
>> +
>> + def _get_s390x_sysinfo(self):
>> + """
>> + This method retrieves following system information
>> + for s390 architecture
>> + * manufacturer: Manufacturer of host machine
>> + * type: Type of the host machine
>> + * model:Model of host machine
>> + * LPAR_NUMBER: LPAR Number of host
>> + * LPAR_NAME: Name of host LPAR
>> + * CPUS_DEDICATED: LPAR CPUs Dedicated
>> + * CPUS_SHARED: LPAR CPUs Shared
>> +
>> + :param self: object of the class self
>> + :return: dictionary with following keys -
>> + 'manufacturer', 'type', 'model', CPUS_SHARED,
>> + CPUS_DEDICATED, LPAR_NUMBER, LPAR_NAME
>> + """
>> + s390x_sysinfo = {}
>> + try:
>> + with open(PROC_SYSINFO) as f:
>> + for line in f.xreadlines():
>> + if ":" in line and (len(line.split(':')) == 2):
>> + info = line.split(':')
>> + if info[0] == 'Model' and
>> (len(info[1].split()) == 2):
>> + s390x_sysinfo['model'] = \
>> + info[1].split()[0].strip() +\
>> + " "+info[1].split()[1].strip()
>> + elif info[0] == 'Manufacturer':
>> + s390x_sysinfo['manufacturer'] =
>> info[1].strip()
>> + elif info[0] == 'Type':
>> + s390x_sysinfo['type'] = info[1].strip()
>> + elif info[0] == 'LPAR Number':
>> + s390x_sysinfo[LPAR_NUMBER] =
>> int(info[1].strip())
>> + elif info[0] == 'LPAR Name':
>> + s390x_sysinfo[LPAR_NAME] = info[1].strip()
>> + elif info[0] == 'LPAR CPUs Dedicated':
>> + s390x_sysinfo[CPUS_DEDICATED] =\
>> + int(info[1].strip())
>> + elif info[0] == 'LPAR CPUs Shared':
>> + s390x_sysinfo[CPUS_SHARED] =
>> int(info[1].strip())
>> + except Exception as e:
>> + wok_log.error("Failed to retrieve information from %s
>> file. "
>> + "Error: %s", PROC_SYSINFO, e.__str__())
>> +
>> + return s390x_sysinfo
>> +
>> + def _get_memory(self):
>> + """
>> + method to retrieve memory information for all architecture
>> + :return: dictionary with keys "online" and "offline"
>> + """
>> + memory = {}
>> + online_memory = 0
>> + offline_memory = 0
>> + if ARCH.startswith('s390x'):
>> + online_mem_pat = r'^Total online memory :\s+(\d+)\s+MB$'
>> + offline_mem_pat = r'^Total offline memory:\s+(\d+)\s+MB$'
>> + out, err, rc = run_command(LSMEM)
>> + # output of lsmem in s390x architecture is expected to be
>> + # Address Range Size (MB) State\
>> + # Removable Device
>> + # ========================================================\
>> + # =======================
>> + # 0x0000000000000000-0x000000000fffffff 256 online\
>> + # no 0
>> + # 0x0000000010000000-0x000000002fffffff 512 online\
>> + # yes 1-2
>> + # 0x0000000030000000-0x000000007fffffff 1280 online\
>> + # no 3-7
>> + # 0x0000000080000000-0x00000000ffffffff 2048 offline\
>> + # - 8-15
>> + #
>> + # Memory device size : 256 MB
>> + # Memory block size : 256 MB
>> + # Total online memory : 2048 MB
>> + # Total offline memory: 2048 MB
>> + if not rc:
>> + online_mem =\
>> + re.search(online_mem_pat, out.strip(), re.M | re.I)
>> + offline_mem =\
>> + re.search(offline_mem_pat, out.strip(), re.M |
>> re.I)
>> + if online_mem and len(online_mem.groups()) == 1:
>> + online_memory = int(online_mem.group(1)) * 1024
>> * 1024
>> + # converting MB to bytes
>> + # lsmem always returns memory in MB
>> + if offline_mem and len(offline_mem.groups()) == 1:
>> + offline_memory = int(offline_mem.group(1)) *
>> 1024 * 1024
>> + else:
>> + wok_log.error('Failed to retrieve memory information
>> with'
>> + ' command %s. Error: %s' % (LSMEM, err))
>> + else:
>> + if hasattr(psutil, 'phymem_usage'):
>> + online_memory = psutil.phymem_usage().total
>> + elif hasattr(psutil, 'virtual_memory'):
>> + online_memory = psutil.virtual_memory().total
>> +
>> + memory['online'] = online_memory
>> + memory['offline'] = offline_memory
>> + return memory
>> +
>> + def _get_cpus_(self):
>> + """
>> + method to retrieve online cpus count and offline cpus
>> + count for all architecture
>> + :return: dictionary with keys "online" and "offline"
>> + """
>> + cpus = {}
>> + total_cpus = int(self.lscpu.get_total_cpus())
>> + offline_cpus = 0
>> +
>> + online_cpus = psutil.NUM_CPUS
>> # psutil is unstable on how to get the number of
>> # cpus, different versions call it differently
>> if hasattr(psutil, 'cpu_count'):
>> - cpus = psutil.cpu_count()
>> + online_cpus = psutil.cpu_count()
>>
>> elif hasattr(psutil, 'NUM_CPUS'):
>> - cpus = psutil.NUM_CPUS
>> + online_cpus = psutil.NUM_CPUS
>>
>> elif hasattr(psutil, '_psplatform'):
>> for method_name in ['_get_num_cpus', 'get_num_cpus']:
>>
>> method = getattr(psutil._psplatform, method_name,
>> None)
>> if method is not None:
>> - cpus = method()
>> + online_cpus = method()
>> break
>> + if total_cpus >= online_cpus:
>> + offline_cpus = total_cpus - online_cpus
>> + cpus['online'] = online_cpus
>> + cpus['offline'] = offline_cpus
>> + return cpus
>> +
>> + def _get_base_info(self):
>> + """
>> + method to retrieve common host information for all
>> architectures
>> + :return: dictionary with keys 'os_distro', 'os_version',
>> 'os_codename'
>> + 'architecture', 'host', memory
>> + """
>> + common_info = {}
>> + # Include IBM PowerKVM name to supported distro names
>> + _sup_distros = platform._supported_dists + ('ibm_powerkvm',)
>> + # 'fedora' '17' 'Beefy Miracle'
>> + distro, version, codename = platform.linux_distribution(
>> + supported_dists=_sup_distros)
>> + common_info['os_distro'] = distro
>> + common_info['os_version'] = version
>> + common_info['os_codename'] = unicode(codename, "utf-8")
>> + common_info['architecture'] = ARCH
>> + common_info['host'] = platform.node()
>> + common_info['memory'] = self._get_memory()
>>
>> - self.host_info['cpus'] = cpus
>> - if hasattr(psutil, 'phymem_usage'):
>> - self.host_info['memory'] = psutil.phymem_usage().total
>> - elif hasattr(psutil, 'virtual_memory'):
>> - self.host_info['memory'] = psutil.virtual_memory().total
>> - return self.host_info
>> + return common_info
>> +
>> + def lookup(self, *name):
>> + """
>> + method to get basic information for host
>> + """
>> + host_info = self._get_base_info()
>> + if ARCH.startswith('s390x'):
>> + host_info.update(self._get_s390x_host_info())
>> + elif ARCH.startswith('ppc'):
>> + host_info['cpus'] = self._get_cpus_()
>> + host_info['cpu_model'] = self._get_ppc_cpu_model()
>> + else:
>> + host_info['cpus'] = self._get_cpus_()
>> + host_info['cpu_model'] = self._get_x86_cpu_model()
>> + return host_info
>>
>> def swupdate(self, *name):
>> try:
>> diff --git a/src/wok/plugins/gingerbase/tests/test_host.py
>> b/src/wok/plugins/gingerbase/tests/test_host.py
>> index 5d158bb..a994177 100644
>> --- a/src/wok/plugins/gingerbase/tests/test_host.py
>> +++ b/src/wok/plugins/gingerbase/tests/test_host.py
>> @@ -68,15 +68,21 @@ class HostTests(unittest.TestCase):
>> def test_hostinfo(self):
>> resp = self.request('/plugins/gingerbase/host').read()
>> info = json.loads(resp)
>> - keys = ['os_distro', 'os_version', 'os_codename', 'cpu_model',
>> - 'memory', 'cpus']
>> + if platform.machine().startswith('s390x'):
>> + keys = ['os_distro', 'os_version', 'os_codename',
>> 'cpu_model',
>> + 'memory', 'cpus', 'architecture', 'host',
>> 'virtualization']
>> + else:
>> + keys = ['os_distro', 'os_version', 'os_codename',
>> 'cpu_model',
>> + 'memory', 'cpus', 'architecture', 'host']
>> + self.assertEquals(psutil.TOTAL_PHYMEM, info['memory'])
>> self.assertEquals(sorted(keys), sorted(info.keys()))
>>
>> distro, version, codename = platform.linux_distribution()
>> self.assertEquals(distro, info['os_distro'])
>> self.assertEquals(version, info['os_version'])
>> self.assertEquals(unicode(codename, "utf-8"),
>> info['os_codename'])
>> - self.assertEquals(psutil.TOTAL_PHYMEM, info['memory'])
>> + self.assertEqual(platform.node(), info['host'])
>> + self.assertEqual(platform.machine(), info['architecture'])
>>
>> def test_hoststats(self):
>> time.sleep(1)
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel at ovirt.org
> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>
--
Regards,
Suresh Babu Angadi
More information about the Kimchi-devel
mailing list