Introduce os-capability parsing
This patch introduces a way to parse cpuset information by looking into the 'lscpu' output. The implementation is presently done for linux but given docker or some such container runtimes can work on other operating systems too, a more generic approach has been taken. Eventually host_capabilities module should expose general purpose methods leaving the details of the os inside the respective dir. Change-Id: I0f92594d8e5ce013f47174c09bc941ea1de3f0a8
This commit is contained in:
parent
b51b114f13
commit
236ffb9bae
|
@ -388,5 +388,9 @@ class EntityNotFound(ZunException):
|
|||
message = _("The %(entity)s (%(name)s) could not be found.")
|
||||
|
||||
|
||||
class CommandError(ZunException):
|
||||
message = _("The command: %(cmd)s failed on the system.")
|
||||
|
||||
|
||||
class NoValidHost(ZunException):
|
||||
message = _("No valid host was found. %(reason)s")
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2017 IBM Corp
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class Host(object):
|
||||
|
||||
def __init__(self):
|
||||
self.capabilities = None
|
||||
|
||||
def get_cpu_numa_info(self):
|
||||
"""This method returns a dict containing the cpuset info for a host"""
|
||||
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright 2017 IBM Corp
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from collections import defaultdict
|
||||
import re
|
||||
import six
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
from zun.common import exception
|
||||
from zun.common.i18n import _LE
|
||||
from zun.container.os_capability import host_capability
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinuxHost(host_capability.Host):
|
||||
|
||||
def get_cpu_numa_info(self):
|
||||
# TODO(sbiswas7): rootwrap changes for zun required.
|
||||
old_lscpu = False
|
||||
try:
|
||||
output = processutils.execute('lscpu', '-p=socket,cpu,online')
|
||||
except processutils.ProcessExecutionError as e:
|
||||
LOG.exception(_LE("There was a problem while executing lscpu "
|
||||
"-p=socket,cpu,online : %s"), six.text_type(e))
|
||||
# There is a possibility that an older version of lscpu is used
|
||||
# So let's try without the online column
|
||||
try:
|
||||
output = processutils.execute('lscpu', '-p=socket,cpu')
|
||||
old_lscpu = True
|
||||
except processutils.ProcessExecutionError as e:
|
||||
LOG.exception(_LE("There was a problem while executing lscpu "
|
||||
"-p=socket,cpu : %s"), six.text_type(e))
|
||||
raise exception.CommandError(cmd="lscpu")
|
||||
if old_lscpu:
|
||||
cpu_sock_pair = re.findall("\d+(?:,\d+)?", str(output))
|
||||
else:
|
||||
cpu_sock_pair = re.findall("\d+(?:,\d+,[Y/N])?", str(output))
|
||||
sock_map = defaultdict(list)
|
||||
for value in cpu_sock_pair:
|
||||
val = value.split(",")
|
||||
if len(val) == 3 and val[2] == 'Y':
|
||||
sock_map[val[0]].append(val[1])
|
||||
elif len(val) == 2 and old_lscpu:
|
||||
sock_map[val[0]].append(val[1])
|
||||
return sock_map
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright 2017 IBM Corp.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from zun.common import exception
|
||||
from zun.container.os_capability.linux import os_capability_linux
|
||||
from zun.tests import base
|
||||
|
||||
LSCPU_ON = """# The following is the parsable format, which can be fed to other
|
||||
# programs. Each different item in every column has an unique ID
|
||||
# starting from zero.
|
||||
# Socket,CPU,Online
|
||||
0,0,Y
|
||||
0,8,Y
|
||||
1,16,Y
|
||||
1,24,Y
|
||||
2,32,Y"""
|
||||
|
||||
LSCPU_NO_ONLINE = """# The following is the parsable format, which can be fed to
|
||||
# programs. Each different item in every column has an unique ID
|
||||
# starting from zero.
|
||||
# Socket,CPU
|
||||
0,0
|
||||
0,1
|
||||
1,2
|
||||
1,3"""
|
||||
|
||||
|
||||
class TestOSCapability(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestOSCapability, self).setUp()
|
||||
|
||||
@mock.patch('oslo_concurrency.processutils.execute')
|
||||
def test_get_cpu_numa_info_with_online(self, mock_output):
|
||||
mock_output.return_value = LSCPU_ON
|
||||
output = os_capability_linux.LinuxHost().get_cpu_numa_info()
|
||||
expected_output = {'0': ['0', '8'], '1': ['16', '24'], '2': ['32']}
|
||||
self.assertEqual(expected_output, output)
|
||||
|
||||
@mock.patch('oslo_concurrency.processutils.execute')
|
||||
def test_get_cpu_numa_info_exception(self, mock_output):
|
||||
mock_output.side_effect = processutils.ProcessExecutionError()
|
||||
self.assertRaises(exception.CommandError,
|
||||
os_capability_linux.LinuxHost().get_cpu_numa_info)
|
||||
|
||||
@mock.patch('oslo_concurrency.processutils.execute')
|
||||
def test_get_cpu_numa_info_without_online(self, mock_output):
|
||||
mock_output.side_effect = [processutils.ProcessExecutionError(),
|
||||
LSCPU_NO_ONLINE]
|
||||
expected_output = {'0': ['0', '1'], '1': ['2', '3']}
|
||||
output = os_capability_linux.LinuxHost().get_cpu_numa_info()
|
||||
self.assertEqual(expected_output, output)
|
Loading…
Reference in New Issue