Merge "If listen_tls is true, enable TLS on wsgi server"
This commit is contained in:
@@ -12,8 +12,16 @@
|
||||
|
||||
import os
|
||||
|
||||
import eventlet
|
||||
|
||||
# NOTE(TheJulia): Eventlet, when monkey patching occurs, replaces the base
|
||||
# dns resolver methods. This can lead to compatability issues,
|
||||
# and un-expected exceptions being raised during the process
|
||||
# of monkey patching. Such as one if there are no resolvers.
|
||||
os.environ['EVENTLET_NO_GREENDNS'] = "yes"
|
||||
|
||||
# NOTE(JayF) Without monkey_patching socket, API requests will hang with TLS
|
||||
# enabled. Enabling more than just socket for monkey patching causes failures
|
||||
# in image streaming. In an ideal world, we track down all those errors and
|
||||
# monkey patch everything as suggested in eventlet documentation.
|
||||
eventlet.monkey_patch(all=False, socket=True)
|
||||
|
@@ -130,7 +130,8 @@ class Application(object):
|
||||
"""Start the API service in the background."""
|
||||
self.service = wsgi.Server(self._conf, 'ironic-python-agent', app=self,
|
||||
host=self.agent.listen_address.hostname,
|
||||
port=self.agent.listen_address.port)
|
||||
port=self.agent.listen_address.port,
|
||||
use_ssl=self._conf.listen_tls)
|
||||
self.service.start()
|
||||
LOG.info('Started API service on port %s',
|
||||
self.agent.listen_address.port)
|
||||
|
@@ -54,6 +54,18 @@ cli_opts = [
|
||||
help='The port to listen on. '
|
||||
'Can be supplied as "ipa-listen-port" kernel parameter.'),
|
||||
|
||||
# This is intentionally not settable via kernel command line, as it
|
||||
# requires configuration parameters from oslo_service which are not
|
||||
# configurable over the command line and require files-on-disk.
|
||||
# Operators who want to use this support should configure it statically
|
||||
# as part of a ramdisk build.
|
||||
cfg.BoolOpt('listen_tls',
|
||||
default=False,
|
||||
help='When true, IPA will host API behind TLS. You will also '
|
||||
'need to configure [ssl] group options for cert_file, '
|
||||
'key_file, and, if desired, ca_file to validate client '
|
||||
'certificates.'),
|
||||
|
||||
cfg.StrOpt('advertise_host',
|
||||
default=APARAMS.get('ipa-advertise-host', None),
|
||||
help='The host to tell Ironic to reply and send '
|
||||
|
@@ -208,7 +208,51 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
mock.call('wait_for_disks')],
|
||||
mock_dispatch.call_args_list)
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
|
||||
@mock.patch(
|
||||
'ironic_python_agent.hardware_managers.cna._detect_cna_card',
|
||||
mock.Mock())
|
||||
@mock.patch.object(hardware, 'dispatch_to_managers', autospec=True)
|
||||
@mock.patch.object(agent.IronicPythonAgent,
|
||||
'_wait_for_interface', autospec=True)
|
||||
@mock.patch('oslo_service.wsgi.Server', autospec=True)
|
||||
@mock.patch.object(hardware, 'get_managers', autospec=True)
|
||||
def test_run_with_ssl(self, mock_get_managers, mock_wsgi,
|
||||
mock_wait, mock_dispatch):
|
||||
CONF.set_override('inspection_callback_url', '')
|
||||
CONF.set_override('listen_tls', True)
|
||||
|
||||
wsgi_server = mock_wsgi.return_value
|
||||
|
||||
def set_serve_api():
|
||||
self.agent.serve_api = False
|
||||
|
||||
wsgi_server.start.side_effect = set_serve_api
|
||||
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'
|
||||
},
|
||||
'config': {
|
||||
'heartbeat_timeout': 300
|
||||
}
|
||||
}
|
||||
|
||||
self.agent.run()
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=True)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
@@ -262,7 +306,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
@@ -320,7 +365,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
@@ -365,7 +411,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
@@ -412,7 +459,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host='2001:db8:dead:beef::cafe',
|
||||
port=9998)
|
||||
port=9998,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
@@ -455,7 +503,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
mock_dispatch.call_args_list)
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
|
||||
@@ -494,7 +543,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
|
||||
mock_inspector.assert_called_once_with()
|
||||
@@ -557,7 +607,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
|
||||
mock_inspector.assert_called_once_with()
|
||||
@@ -613,7 +664,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
|
||||
self.assertFalse(mock_inspector.called)
|
||||
@@ -674,7 +726,8 @@ class TestBaseAgent(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
|
||||
self.agent.heartbeater.start.assert_called_once_with()
|
||||
@@ -827,7 +880,8 @@ class TestAgentStandalone(ironic_agent_base.IronicAgentTest):
|
||||
self.assertTrue(mock_get_managers.called)
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server_request.start.assert_called_once_with()
|
||||
|
||||
self.assertFalse(self.agent.heartbeater.called)
|
||||
@@ -1051,7 +1105,8 @@ class TestBaseAgentVMediaToken(ironic_agent_base.IronicAgentTest):
|
||||
|
||||
mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent',
|
||||
app=self.agent.api,
|
||||
host=mock.ANY, port=9999)
|
||||
host=mock.ANY, port=9999,
|
||||
use_ssl=False)
|
||||
wsgi_server.start.assert_called_once_with()
|
||||
mock_wait.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual([mock.call('list_hardware_info'),
|
||||
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Enables support in IPA for hosting the API server over TLS. Using this
|
||||
support requires setting ``[DEFAULT]listen_tls`` to True, and then setting
|
||||
``[ssl]cert_file``, ``[ssl]key_file``, and optionally ``[ssl]ca_file`` to
|
||||
files embedded in the ramdisk IPA runs inside.
|
||||
|
Reference in New Issue
Block a user