Merge "Implement version 2 payload with more hw info"

This commit is contained in:
Jenkins 2014-04-11 16:01:25 +00:00 committed by Gerrit Code Review
commit 7d4621eb13
5 changed files with 206 additions and 48 deletions

View File

@ -18,6 +18,7 @@ import abc
import functools
import os
import psutil
import six
import stevedore
@ -45,26 +46,19 @@ class HardwareType(object):
MAC_ADDRESS = 'mac_address'
class HardwareInfo(encoding.Serializable):
def __init__(self, type, id):
self.type = type
self.id = id
class BlockDevice(encoding.Serializable):
def __init__(self, name, size):
self.name = name
self.size = size
def serialize(self):
return utils.get_ordereddict([
('type', self.type),
('id', self.id),
('name', self.name),
('size', self.size),
])
class BlockDevice(object):
def __init__(self, name, size, start_sector):
self.name = name
self.size = size
self.start_sector = start_sector
class NetworkInterface(object):
class NetworkInterface(encoding.Serializable):
def __init__(self, name, mac_addr):
self.name = name
self.mac_address = mac_addr
@ -72,6 +66,38 @@ class NetworkInterface(object):
self.switch_port_descr = None
self.switch_chassis_descr = None
def serialize(self):
return utils.get_ordereddict([
('name', self.name),
('mac_address', self.mac_address),
('switch_port_descr', self.switch_port_descr),
('switch_chassis_descr', self.switch_port_descr),
])
class CPU(encoding.Serializable):
def __init__(self, model_name, frequency, count):
self.model_name = model_name
self.frequency = frequency
self.count = count
def serialize(self):
return utils.get_ordereddict([
('model_name', self.model_name),
('frequency', self.frequency),
('count', self.count),
])
class Memory(encoding.Serializable):
def __init__(self, total):
self.total = total
def serialize(self):
return utils.get_ordereddict([
('total', self.total),
])
class HardwareManager(object):
@abc.abstractmethod
@ -87,10 +113,11 @@ class HardwareManager(object):
pass
def list_hardware_info(self):
hardware_info = []
for interface in self.list_network_interfaces():
hardware_info.append(HardwareInfo(HardwareType.MAC_ADDRESS,
interface.mac_address))
hardware_info = {}
hardware_info['interfaces'] = self.list_network_interfaces()
hardware_info['cpu'] = self.get_cpus()
hardware_info['disks'] = self.list_block_devices()
hardware_info['memory'] = self.get_memory()
return hardware_info
@ -123,7 +150,26 @@ class GenericHardwareManager(HardwareManager):
for name in iface_names
if self._is_device(name)]
def _list_block_devices(self):
def get_cpus(self):
model = None
freq = None
with open('/proc/cpuinfo') as f:
lines = f.read()
for line in lines.split('\n'):
if model and freq:
break
if not model and line.startswith('model name'):
model = line.split(':')[1].strip()
if not freq and line.startswith('cpu MHz'):
freq = line.split(':')[1].strip()
return CPU(model, freq, psutil.cpu_count())
def get_memory(self):
# psutil returns a long, force it to an int
return Memory(int(psutil.phymem_usage().total))
def list_block_devices(self):
report = utils.execute('blockdev', '--report',
check_exit_code=[0])[0]
lines = report.split('\n')
@ -131,20 +177,17 @@ class GenericHardwareManager(HardwareManager):
startsec_idx = lines[0].index('StartSec')
device_idx = lines[0].index('Device')
size_idx = lines[0].index('Size')
# If a device doesn't start at sector 0, assume it is a partition
return [BlockDevice(line[device_idx],
int(line[size_idx]),
int(line[startsec_idx]))
int(line[size_idx]))
for line
in lines[1:]]
in lines[1:] if int(line[startsec_idx]) == 0]
def get_os_install_device(self):
# Assume anything with a start sector other than 0, is a partition
block_devices = [device for device in self._list_block_devices()
if device.start_sector == 0]
# Find the first device larger than 4GB, assume it is the OS disk
# TODO(russellhaering): This isn't a valid assumption in all cases,
# is there a more reasonable default behavior?
block_devices = self.list_block_devices()
block_devices.sort(key=lambda device: device.size)
for device in block_devices:
if device.size >= (4 * pow(1024, 3)):

View File

@ -30,7 +30,7 @@ LOG = log.getLogger(__name__)
class APIClient(object):
api_version = 'v1'
payload_version = '1'
payload_version = '2'
def __init__(self, api_url):
self.api_url = api_url.rstrip('/')

View File

@ -65,16 +65,100 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
'--report',
check_exit_code=[0])
def test_list_hardwre_info(self):
@mock.patch('psutil.cpu_count')
@mock.patch(OPEN_FUNCTION_NAME)
def test_get_cpus(self, mocked_open, mocked_cpucount):
mocked_open.return_value.__enter__ = lambda s: s
mocked_open.return_value.__exit__ = mock.Mock()
read_mock = mocked_open.return_value.read
read_mock.return_value = (
'processor : 0\n'
'vendor_id : GenuineIntel\n'
'cpu family : 6\n'
'model : 58\n'
'model name : Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz\n'
'stepping : 9\n'
'microcode : 0x15\n'
'cpu MHz : 2594.685\n'
'cache size : 6144 KB\n'
'fpu : yes\n'
'fpu_exception : yes\n'
'cpuid level : 13\n'
'wp : yes\n'
'flags : fpu vme de pse tsc msr pae mce cx8 apic sep '
'mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss '
'syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl '
'xtopology tsc_reliable nonstop_tsc aperfmperf eagerfpu pni '
'pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave '
'avx f16c rdrand hypervisor lahf_lm ida arat epb xsaveopt pln pts '
'dtherm fsgsbase smep\n'
'bogomips : 5189.37\n'
'clflush size : 64\n'
'cache_alignment : 64\n'
'address sizes : 40 bits physical, 48 bits virtual\n'
'power management:\n'
'\n'
'processor : 1\n'
'vendor_id : GenuineIntel\n'
'cpu family : 6\n'
'model : 58\n'
'model name : Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz\n'
'stepping : 9\n'
'microcode : 0x15\n'
'cpu MHz : 2594.685\n'
'cache size : 6144 KB\n'
'fpu : yes\n'
'fpu_exception : yes\n'
'cpuid level : 13\n'
'wp : yes\n'
'flags : fpu vme de pse tsc msr pae mce cx8 apic sep '
'mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss '
'syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl '
'xtopology tsc_reliable nonstop_tsc aperfmperf eagerfpu pni '
'pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave '
'avx f16c rdrand hypervisor lahf_lm ida arat epb xsaveopt pln pts '
'dtherm fsgsbase smep\n'
'bogomips : 5189.37\n'
'clflush size : 64\n'
'cache_alignment : 64\n'
'address sizes : 40 bits physical, 48 bits virtual\n'
'power management:\n'
)
mocked_cpucount.return_value = 2
cpus = self.hardware.get_cpus()
self.assertEqual(cpus.model_name,
'Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz')
self.assertEqual(cpus.frequency, '2594.685')
self.assertEqual(cpus.count, 2)
def test_list_hardware_info(self):
self.hardware.list_network_interfaces = mock.Mock()
self.hardware.list_network_interfaces.return_value = [
hardware.NetworkInterface('eth0', '00:0c:29:8c:11:b1'),
hardware.NetworkInterface('eth1', '00:0c:29:8c:11:b2'),
]
self.hardware.get_cpus = mock.Mock()
self.hardware.get_cpus.return_value = hardware.CPU(
'Awesome CPU x14 9001',
9001,
14)
self.hardware.get_memory = mock.Mock()
self.hardware.get_memory.return_value = hardware.Memory(1017012)
self.hardware.list_block_devices = mock.Mock()
self.hardware.list_block_devices.return_value = [
hardware.BlockDevice('/dev/sdj', 1073741824),
hardware.BlockDevice('/dev/hdaa', 65535),
]
hardware_info = self.hardware.list_hardware_info()
self.assertEqual(len(hardware_info), 2)
self.assertEqual(hardware_info[0].type, 'mac_address')
self.assertEqual(hardware_info[1].type, 'mac_address')
self.assertEqual(hardware_info[0].id, '00:0c:29:8c:11:b1')
self.assertEqual(hardware_info[1].id, '00:0c:29:8c:11:b2')
self.assertEqual(hardware_info['memory'], self.hardware.get_memory())
self.assertEqual(hardware_info['cpu'], self.hardware.get_cpus())
self.assertEqual(hardware_info['disks'],
self.hardware.list_block_devices())
self.assertEqual(hardware_info['interfaces'],
self.hardware.list_network_interfaces())

View File

@ -41,12 +41,18 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
def setUp(self):
super(TestBaseIronicPythonAgent, self).setUp()
self.api_client = ironic_api_client.APIClient(API_URL)
self.hardware_info = [
hardware.HardwareInfo(hardware.HardwareType.MAC_ADDRESS,
'aa:bb:cc:dd:ee:ff'),
hardware.HardwareInfo(hardware.HardwareType.MAC_ADDRESS,
'ff:ee:dd:cc:bb:aa'),
]
self.hardware_info = {
'interfaces': [
hardware.NetworkInterface('eth0', '00:0c:29:8c:11:b1'),
hardware.NetworkInterface('eth1', '00:0c:29:8c:11:b2'),
],
'cpu': hardware.CPU('Awesome Jay CPU x10 9001', '9001', '10'),
'disks': [
hardware.BlockDevice('/dev/sdj', '9001'),
hardware.BlockDevice('/dev/hdj', '9002'),
],
'memory': hardware.Memory('8675309'),
}
def test_successful_heartbeat(self):
expected_heartbeat_before = time.time() + 120
@ -65,7 +71,7 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
self.assertEqual(heartbeat_before, expected_heartbeat_before)
heartbeat_path = 'v1/nodes/deadbeef-dabb-ad00-b105-f00d00bab10c/' \
'vendor_passthru/heartbeat'
'vendor_passthru/heartbeat'
request_args = self.api_client.session.request.call_args[0]
self.assertEqual(request_args[0], 'POST')
self.assertEqual(request_args[1], API_URL + heartbeat_path)
@ -162,16 +168,40 @@ class TestBaseIronicPythonAgent(test_base.BaseTestCase):
data = self.api_client.session.request.call_args[1]['data']
content = json.loads(data)
self.assertEqual(content['version'], self.api_client.payload_version)
self.assertEqual(content['inventory'], [
{
'type': 'mac_address',
'id': 'aa:bb:cc:dd:ee:ff',
self.assertEqual(content['inventory'], {
u'interfaces': [
{
u'mac_address': u'00:0c:29:8c:11:b1',
u'name': u'eth0',
u'switch_chassis_descr': None,
u'switch_port_descr': None
},
{
u'mac_address': u'00:0c:29:8c:11:b2',
u'name': u'eth1',
u'switch_chassis_descr': None,
'switch_port_descr': None
}
],
u'cpu': {
u'model_name': u'Awesome Jay CPU x10 9001',
u'frequency': u'9001',
u'count': u'10',
},
{
'type': 'mac_address',
'id': 'ff:ee:dd:cc:bb:aa',
u'disks': [
{
u'name': u'/dev/sdj',
u'size': u'9001',
},
{
u'name': u'/dev/hdj',
u'size': u'9002',
},
],
u'memory': {
u'total': u'8675309',
},
])
})
def test_do_lookup_bad_response_code(self):
response = FakeResponse(status_code=400, content={

View File

@ -9,3 +9,4 @@ oslo.config>=1.2.0
Babel>=1.3
iso8601>=0.1.9
oslotest==1.0
psutil>=1.1.1