diff options
| author | Josh Gachnang <josh@pcsforeducation.com> | 2014-12-15 17:29:14 -0800 |
|---|---|---|
| committer | Josh Gachnang <josh@pcsforeducation.com> | 2014-12-16 17:59:29 -0800 |
| commit | 417bf086a53da995fbf93cc2c04990f9c5f87c9f (patch) | |
| tree | eea61aed87cd0f021b05eeae526098abae9c0250 /ironic_python_agent | |
| parent | 86d4b41709548cb304ab9cc0b627b39449eef121 (diff) | |
| download | ironic-python-agent-417bf086a53da995fbf93cc2c04990f9c5f87c9f.tar.gz | |
Add standalone mode for IPA
This allows a developer to run IPA without an Ironic API. This can
be useful for testing (especially functional testing) or testing
integration of things like hardware managers.
Change-Id: I2dc49fbe306430bf5b05a36fe56de5275fc128b2
Diffstat (limited to 'ironic_python_agent')
| -rw-r--r-- | ironic_python_agent/agent.py | 21 | ||||
| -rw-r--r-- | ironic_python_agent/cmd/agent.py | 14 | ||||
| -rw-r--r-- | ironic_python_agent/tests/agent.py | 50 |
3 files changed, 70 insertions, 15 deletions
diff --git a/ironic_python_agent/agent.py b/ironic_python_agent/agent.py index 5bf2eeca..ab4593b8 100644 --- a/ironic_python_agent/agent.py +++ b/ironic_python_agent/agent.py @@ -137,7 +137,7 @@ class IronicPythonAgent(base.ExecuteCommandMixin): def __init__(self, api_url, advertise_address, listen_address, ip_lookup_attempts, ip_lookup_sleep, network_interface, - lookup_timeout, lookup_interval, driver_name): + lookup_timeout, lookup_interval, driver_name, standalone): super(IronicPythonAgent, self).__init__() self.ext_mgr = extension.ExtensionManager( namespace='ironic_python_agent.extensions', @@ -166,6 +166,7 @@ class IronicPythonAgent(base.ExecuteCommandMixin): self.ip_lookup_attempts = ip_lookup_attempts self.ip_lookup_sleep = ip_lookup_sleep self.network_interface = network_interface + self.standalone = standalone def get_status(self): """Retrieve a serializable status. @@ -267,20 +268,22 @@ class IronicPythonAgent(base.ExecuteCommandMixin): result_id) def force_heartbeat(self): - self.heartbeater.force_heartbeat() + if not self.standalone: + self.heartbeater.force_heartbeat() def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() - content = self.api_client.lookup_node( + if not self.standalone: + content = self.api_client.lookup_node( hardware_info=self.hardware.list_hardware_info(), timeout=self.lookup_timeout, starting_interval=self.lookup_interval) - self.node = content['node'] - self.heartbeat_timeout = content['heartbeat_timeout'] + self.node = content['node'] + self.heartbeat_timeout = content['heartbeat_timeout'] wsgi = simple_server.make_server( self.listen_address[0], @@ -288,12 +291,14 @@ class IronicPythonAgent(base.ExecuteCommandMixin): self.api, server_class=simple_server.WSGIServer) - # Don't start heartbeating until the server is listening - self.heartbeater.start() + if not self.standalone: + # Don't start heartbeating until the server is listening + self.heartbeater.start() try: wsgi.serve_forever() except BaseException: self.log.exception('shutting down') - self.heartbeater.stop() + if not self.standalone: + self.heartbeater.stop() diff --git a/ironic_python_agent/cmd/agent.py b/ironic_python_agent/cmd/agent.py index 6b26ed37..e9f38105 100644 --- a/ironic_python_agent/cmd/agent.py +++ b/ironic_python_agent/cmd/agent.py @@ -128,8 +128,7 @@ APARAMS = _get_agent_params() cli_opts = [ cfg.StrOpt('api_url', - required=('ipa-api-url' not in APARAMS), - default=APARAMS.get('ipa-api-url'), + default=APARAMS.get('ipa-api-url', 'http://127.0.0.1:6835'), deprecated_name='api-url', help='URL of the Ironic API'), @@ -195,7 +194,12 @@ cli_opts = [ cfg.FloatOpt('lldp_timeout', default=APARAMS.get('lldp-timeout', 30.0), - help='The amount of seconds to wait for LLDP packets.') + help='The amount of seconds to wait for LLDP packets.'), + + cfg.BoolOpt('standalone', + default=False, + help='Note: for debugging only. Start the Agent but suppress ' + 'any calls to Ironic API.'), ] CONF.register_cli_opts(cli_opts) @@ -204,7 +208,6 @@ CONF.register_cli_opts(cli_opts) def run(): CONF() log.setup('ironic-python-agent') - agent.IronicPythonAgent(CONF.api_url, (CONF.advertise_host, CONF.advertise_port), (CONF.listen_host, CONF.listen_port), @@ -213,4 +216,5 @@ def run(): CONF.network_interface, CONF.lookup_timeout, CONF.lookup_interval, - CONF.driver_name).run() + CONF.driver_name, + CONF.standalone).run() diff --git a/ironic_python_agent/tests/agent.py b/ironic_python_agent/tests/agent.py index 32c79f85..705172bc 100644 --- a/ironic_python_agent/tests/agent.py +++ b/ironic_python_agent/tests/agent.py @@ -146,7 +146,8 @@ class TestBaseAgent(test_base.BaseTestCase): 'eth0', 300, 1, - 'agent_ipmitool') + 'agent_ipmitool', + False) self.agent.ext_mgr = extension.ExtensionManager.\ make_test_instance([extension.Extension('fake', None, FakeExtension, @@ -210,7 +211,8 @@ class TestBaseAgent(test_base.BaseTestCase): None, 300, 1, - 'agent_ipmitool') + 'agent_ipmitool', + False) homeless_agent.hardware = mock.Mock() mock_list_net = homeless_agent.hardware.list_network_interfaces @@ -303,6 +305,50 @@ class TestBaseAgent(test_base.BaseTestCase): self.agent.get_node_uuid) +class TestAgentStandalone(test_base.BaseTestCase): + + def setUp(self): + super(TestAgentStandalone, self).setUp() + self.agent = agent.IronicPythonAgent('https://fake_api.example.' + 'org:8081/', + ('203.0.113.1', 9990), + ('192.0.2.1', 9999), + 3, + 10, + 'eth0', + 300, + 1, + 'agent_ipmitool', + True) + + @mock.patch('wsgiref.simple_server.make_server', autospec=True) + @mock.patch.object(hardware.HardwareManager, 'list_hardware_info') + def test_run(self, mocked_list_hardware, wsgi_server_cls): + wsgi_server = wsgi_server_cls.return_value + wsgi_server.start.side_effect = KeyboardInterrupt() + + self.agent.heartbeater = mock.Mock() + self.agent.api_client.lookup_node = mock.Mock() + self.agent.api_client.lookup_node.return_value = { + 'node': { + 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' + }, + 'heartbeat_timeout': 300 + } + self.agent.run() + + listen_addr = ('192.0.2.1', 9999) + wsgi_server_cls.assert_called_once_with( + listen_addr[0], + listen_addr[1], + self.agent.api, + server_class=simple_server.WSGIServer) + wsgi_server.serve_forever.assert_called_once() + + self.assertFalse(self.agent.heartbeater.called) + self.assertFalse(self.agent.api_client.lookup_node.called) + + class TestAgentCmd(test_base.BaseTestCase): @mock.patch('ironic_python_agent.openstack.common.log.getLogger') @mock.patch(OPEN_FUNCTION_NAME) |
