diff --git a/teeth_agent/agent.py b/teeth_agent/agent.py index a9c8ab34a..dc218fbd0 100644 --- a/teeth_agent/agent.py +++ b/teeth_agent/agent.py @@ -67,6 +67,7 @@ class TeethAgentHeartbeater(threading.Thread): def __init__(self, agent): super(TeethAgentHeartbeater, self).__init__() self.agent = agent + self.hardware = hardware.get_manager() self.api = overlord_agent_api.APIClient(agent.api_url) self.log = structlog.get_logger(api_url=agent.api_url) self.stop_event = threading.Event() @@ -87,8 +88,7 @@ class TeethAgentHeartbeater(threading.Thread): def do_heartbeat(self): try: deadline = self.api.heartbeat( - mac_addr=self.agent.get_agent_mac_addr(), - url=self.agent.get_agent_url(), + hardware_info=self.hardware.list_hardware_info(), version=self.agent.version, mode=self.agent.get_mode_name()) self.error_delay = self.initial_delay diff --git a/teeth_agent/hardware.py b/teeth_agent/hardware.py index 2d8b8a195..e37cea7cd 100644 --- a/teeth_agent/hardware.py +++ b/teeth_agent/hardware.py @@ -15,12 +15,15 @@ limitations under the License. """ import abc +import collections import os import plumbum import stevedore import structlog +from teeth_rest import encoding + _global_manager = None @@ -37,6 +40,22 @@ class HardwareSupport(object): SERVICE_PROVIDER = 3 +class HardwareType(object): + MAC_ADDRESS = 'mac_address' + + +class HardwareInfo(encoding.Serializable): + def __init__(self, type, id): + self.type = type + self.id = id + + def serialize(self, view): + return collections.OrderedDict([ + ('type', self.type), + ('id', self.id), + ]) + + class BlockDevice(object): def __init__(self, name, size, start_sector): self.name = name @@ -66,6 +85,13 @@ class HardwareManager(object): def get_os_install_device(self): 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)) + return hardware_info + class GenericHardwareManager(HardwareManager): def __init__(self): diff --git a/teeth_agent/overlord_agent_api.py b/teeth_agent/overlord_agent_api.py index 209ec8920..7fa41ade5 100644 --- a/teeth_agent/overlord_agent_api.py +++ b/teeth_agent/overlord_agent_api.py @@ -47,13 +47,11 @@ class APIClient(object): headers=request_headers, data=data) - def heartbeat(self, mac_addr, url, mode, version): - path = '/{api_version}/agents/{mac_addr}'.format( - api_version=self.api_version, - mac_addr=mac_addr) + def heartbeat(self, hardware_info, mode, version): + path = '/{api_version}/agents'.format(api_version=self.api_version) data = { - 'url': url, + 'hardware': hardware_info, 'mode': mode, 'version': version, } diff --git a/teeth_agent/tests/hardware.py b/teeth_agent/tests/hardware.py index 180a564c7..6435b683d 100644 --- a/teeth_agent/tests/hardware.py +++ b/teeth_agent/tests/hardware.py @@ -53,3 +53,17 @@ class TestGenericHardwareManager(unittest.TestCase): self.assertEqual(self.hardware.get_os_install_device(), '/dev/sdb') self.hardware._cmd.assert_called_once_with('blockdev') blockdev.assert_called_once_with('--report') + + def test_list_hardwre_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'), + ] + + 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') diff --git a/teeth_agent/tests/overlord_agent_api.py b/teeth_agent/tests/overlord_agent_api.py index 82669c1a4..3abbc9675 100644 --- a/teeth_agent/tests/overlord_agent_api.py +++ b/teeth_agent/tests/overlord_agent_api.py @@ -21,6 +21,7 @@ import time import unittest from teeth_agent import errors +from teeth_agent import hardware from teeth_agent import overlord_agent_api API_URL = 'http://agent-api.overlord.example.org/' @@ -29,6 +30,12 @@ API_URL = 'http://agent-api.overlord.example.org/' class TestBaseTeethAgent(unittest.TestCase): def setUp(self): self.api_client = overlord_agent_api.APIClient(API_URL) + self.hardware_info = [ + hardware.HardwareInfo(hardware.HardwareType.MAC_ADDRESS, + 'a:b:c:d'), + hardware.HardwareInfo(hardware.HardwareType.MAC_ADDRESS, + '0:1:2:3'), + ] def test_successful_heartbeat(self): expected_heartbeat_before = time.time() + 120 @@ -40,8 +47,7 @@ class TestBaseTeethAgent(unittest.TestCase): self.api_client.session.request.return_value = response heartbeat_before = self.api_client.heartbeat( - url='http://1.2.3.4:9999/', - mac_addr='a:b:c:d', + hardware_info=self.hardware_info, version='15', mode='STANDBY') @@ -49,13 +55,22 @@ class TestBaseTeethAgent(unittest.TestCase): request_args = self.api_client.session.request.call_args[0] self.assertEqual(request_args[0], 'PUT') - self.assertEqual(request_args[1], API_URL + 'v1/agents/a:b:c:d') + self.assertEqual(request_args[1], API_URL + 'v1/agents') data = self.api_client.session.request.call_args[1]['data'] content = json.loads(data) - self.assertEqual(content['url'], 'http://1.2.3.4:9999/') self.assertEqual(content['mode'], 'STANDBY') self.assertEqual(content['version'], '15') + self.assertEqual(content['hardware'], [ + { + 'type': 'mac_address', + 'id': 'a:b:c:d', + }, + { + 'type': 'mac_address', + 'id': '0:1:2:3', + }, + ]) def test_heartbeat_requests_exception(self): self.api_client.session.request = mock.Mock() @@ -63,8 +78,7 @@ class TestBaseTeethAgent(unittest.TestCase): self.assertRaises(errors.HeartbeatError, self.api_client.heartbeat, - url='http://1.2.3.4:9999/', - mac_addr='a:b:c:d', + hardware_info=self.hardware_info, version='15', mode='STANDBY') @@ -75,8 +89,7 @@ class TestBaseTeethAgent(unittest.TestCase): self.assertRaises(errors.HeartbeatError, self.api_client.heartbeat, - url='http://1.2.3.4:9999/', - mac_addr='a:b:c:d', + hardware_info=self.hardware_info, version='15', mode='STANDBY') @@ -87,8 +100,7 @@ class TestBaseTeethAgent(unittest.TestCase): self.assertRaises(errors.HeartbeatError, self.api_client.heartbeat, - url='http://1.2.3.4:9999/', - mac_addr='a:b:c:d', + hardware_info=self.hardware_info, version='15', mode='STANDBY') @@ -101,7 +113,6 @@ class TestBaseTeethAgent(unittest.TestCase): self.assertRaises(errors.HeartbeatError, self.api_client.heartbeat, - url='http://1.2.3.4:9999/', - mac_addr='a:b:c:d', + hardware_info=self.hardware_info, version='15', mode='STANDBY')