Merge "Skip API related work if no api url configured" into stable/newton

This commit is contained in:
Jenkins 2017-01-18 23:59:26 +00:00 committed by Gerrit Code Review
commit 442950be3e
4 changed files with 141 additions and 27 deletions

View File

@ -170,14 +170,15 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
)
self.api_url = api_url
self.driver_name = driver_name
self.api_client = ironic_api_client.APIClient(self.api_url,
self.driver_name)
if self.api_url:
self.api_client = ironic_api_client.APIClient(self.api_url,
self.driver_name)
self.heartbeater = IronicPythonAgentHeartbeater(self)
self.listen_address = listen_address
self.advertise_address = advertise_address
self.version = pkg_resources.get_distribution('ironic-python-agent')\
.version
self.api = app.VersionSelectorApplication(self)
self.heartbeater = IronicPythonAgentHeartbeater(self)
self.heartbeat_timeout = None
self.started_at = None
self.node = None
@ -331,30 +332,40 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
if not self.standalone:
# Inspection should be started before call to lookup, otherwise
# lookup will fail due to unknown MAC.
uuid = inspector.inspect()
uuid = None
if cfg.CONF.inspection_callback_url:
uuid = inspector.inspect()
self._wait_for_interface()
content = self.api_client.lookup_node(
hardware_info=hardware.dispatch_to_managers(
'list_hardware_info'),
timeout=self.lookup_timeout,
starting_interval=self.lookup_interval,
node_uuid=uuid)
if self.api_url:
self._wait_for_interface()
content = self.api_client.lookup_node(
hardware_info=hardware.dispatch_to_managers(
'list_hardware_info'),
timeout=self.lookup_timeout,
starting_interval=self.lookup_interval,
node_uuid=uuid)
LOG.debug('Received lookup results: %s', content)
self.node = content['node']
LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid'])
hardware.cache_node(self.node)
self.heartbeat_timeout = content['config']['heartbeat_timeout']
LOG.debug('Received lookup results: %s', content)
self.node = content['node']
LOG.info('Lookup succeeded, node UUID is %s',
self.node['uuid'])
hardware.cache_node(self.node)
self.heartbeat_timeout = content['config']['heartbeat_timeout']
# Update config with values from Ironic
config = content.get('config', {})
if config.get('metrics'):
for opt, val in config.items():
setattr(cfg.CONF.metrics, opt, val)
if config.get('metrics_statsd'):
for opt, val in config.items():
setattr(cfg.CONF.metrics_statsd, opt, val)
# Update config with values from Ironic
config = content.get('config', {})
if config.get('metrics'):
for opt, val in config.items():
setattr(cfg.CONF.metrics, opt, val)
if config.get('metrics_statsd'):
for opt, val in config.items():
setattr(cfg.CONF.metrics_statsd, opt, val)
elif cfg.CONF.inspection_callback_url:
LOG.info('No ipa-api-url configured, Heartbeat and lookup '
'skipped for inspector.')
else:
LOG.error('Neither ipa-api-url nor inspection_callback_url'
'found, please check your pxe append parameters.')
wsgi = simple_server.make_server(
self.listen_address.hostname,
@ -362,7 +373,7 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
self.api,
server_class=simple_server.WSGIServer)
if not self.standalone:
if not self.standalone and self.api_url:
# Don't start heartbeating until the server is listening
self.heartbeater.start()
@ -371,5 +382,5 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
except BaseException:
LOG.exception('shutting down')
if not self.standalone:
if not self.standalone and self.api_url:
self.heartbeater.stop()

View File

@ -23,7 +23,7 @@ APARAMS = utils.get_agent_params()
cli_opts = [
cfg.StrOpt('api_url',
default=APARAMS.get('ipa-api-url', 'http://127.0.0.1:6385'),
default=APARAMS.get('ipa-api-url'),
deprecated_name='api-url',
help='URL of the Ironic API'),

View File

@ -249,6 +249,104 @@ class TestBaseAgent(test_base.BaseTestCase):
mocked_dispatch.assert_called_once_with("list_hardware_info")
self.agent.heartbeater.start.assert_called_once_with()
@mock.patch.object(agent.IronicPythonAgent,
'_wait_for_interface')
@mock.patch.object(inspector, 'inspect', autospec=True)
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
@mock.patch('wsgiref.simple_server.make_server', autospec=True)
@mock.patch.object(hardware.HardwareManager, 'list_hardware_info')
def test_run_with_inspection_without_apiurl(self,
mocked_list_hardware,
mocked_server_maker,
mocked_dispatch,
mocked_inspector,
mocked_wait):
# If inspection_callback_url is configured and api_url is not when the
# agent starts, ensure that the inspection will be called and wsgi
# server will work as usual. Also, make sure api_client and heartbeater
# will not be initialized in this case.
CONF.set_override('inspection_callback_url', 'http://foo/bar',
enforce_type=True)
self.agent = agent.IronicPythonAgent(None,
agent.Host('203.0.113.1', 9990),
agent.Host('192.0.2.1', 9999),
3,
10,
'eth0',
300,
1,
'agent_ssh',
False)
self.assertFalse(hasattr(self.agent, 'api_client'))
self.assertFalse(hasattr(self.agent, 'heartbeater'))
wsgi_server = mocked_server_maker.return_value
wsgi_server.start.side_effect = KeyboardInterrupt()
self.agent.run()
listen_addr = agent.Host('192.0.2.1', 9999)
mocked_server_maker.assert_called_once_with(
listen_addr.hostname,
listen_addr.port,
self.agent.api,
server_class=simple_server.WSGIServer)
wsgi_server.serve_forever.assert_called_once_with()
mocked_inspector.assert_called_once_with()
self.assertFalse(mocked_wait.called)
self.assertFalse(mocked_dispatch.called)
@mock.patch.object(agent.IronicPythonAgent,
'_wait_for_interface')
@mock.patch.object(inspector, 'inspect', autospec=True)
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
@mock.patch('wsgiref.simple_server.make_server', autospec=True)
@mock.patch.object(hardware.HardwareManager, 'list_hardware_info')
def test_run_without_inspection_and_apiurl(self,
mocked_list_hardware,
mocked_server_maker,
mocked_dispatch,
mocked_inspector,
mocked_wait):
# If both api_url and inspection_callback_url are not configured when
# the agent starts, ensure that the inspection will be skipped and wsgi
# server will work as usual. Also, make sure api_client and heartbeater
# will not be initialized in this case.
CONF.set_override('inspection_callback_url', None,
enforce_type=True)
self.agent = agent.IronicPythonAgent(None,
agent.Host('203.0.113.1', 9990),
agent.Host('192.0.2.1', 9999),
3,
10,
'eth0',
300,
1,
'agent_ssh',
False)
self.assertFalse(hasattr(self.agent, 'api_client'))
self.assertFalse(hasattr(self.agent, 'heartbeater'))
wsgi_server = mocked_server_maker.return_value
wsgi_server.start.side_effect = KeyboardInterrupt()
self.agent.run()
listen_addr = agent.Host('192.0.2.1', 9999)
mocked_server_maker.assert_called_once_with(
listen_addr.hostname,
listen_addr.port,
self.agent.api,
server_class=simple_server.WSGIServer)
wsgi_server.serve_forever.assert_called_once_with()
self.assertFalse(mocked_inspector.called)
self.assertFalse(mocked_wait.called)
self.assertFalse(mocked_dispatch.called)
@mock.patch.object(time, 'time', autospec=True)
@mock.patch.object(time, 'sleep', autospec=True)
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)

View File

@ -0,0 +1,5 @@
---
fixes:
- If ipa-api-url is not configured in pxe parameters, skip lookup and heartbeat
to avoid ConnectionError when the IPA starts. See https://bugs.launchpad.net/bugs/1643966
for details.