Skip to content

Commit e082bdc

Browse files
guangyeemriedem
authored andcommitted
pass endpoint interface to Ironic client
Via change [1], ironicclient began to use endpoint_filter in the version negotiation code path, whereas it was previously unused if a fully-qualified endpoint had already been determined. Suddenly it was important that the `interface` part of this endpoint_filter be correct. Prior to ironicclient change [2], there was no way to pass an appropriate `interface` value through ironicclient's initialization, so the ironicclient used from nova would always end up with the default value, `public`, in the endpoint_filter. This would break in clouds lacking a public ironic API endpoint (see the referenced bug). With this change, we pass the value of the (standard, per ksa) `valid_interfaces` ironic config option into the ironicclient initialization, where (if and only if the ironicclient fix [2] is also present) it eventually gets passed through to the ksa Adapter initialization (which is set up to accept values from exactly that conf option) to wind up in the endpoint_filter. The effect is that nova's ironicclient will actually be using the interface from nova.conf throughout. (Because `valid_interfaces` is also used in recommended configuration setups - i.e. those that use the service catalog to determine API endpoints - to construct the endpoint_override used to initialize the ironicclient, the value used during version negotiation should be in sync with that used for regular API calls.) [1] I42b66daea1f4397273a3f4eb1638abafb3bb28ce [2] I610836e5038774621690aca88b2aee25670f0262 Change-Id: I5f78d21c39ed2fd58d2a0f3649116e39883d5a2c closes-bug: 1818295
1 parent c7db20d commit e082bdc

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

nova/tests/unit/virt/ironic/test_client_wrapper.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ def test__get_client_session(self, mock_ir_cli, mock_session):
8888
'retry_interval': CONF.ironic.api_retry_interval,
8989
'os_ironic_api_version': ['1.46', '1.38'],
9090
'endpoint':
91-
self.get_ksa_adapter.return_value.get_endpoint.return_value}
91+
self.get_ksa_adapter.return_value.get_endpoint.return_value,
92+
'interface': ['internal', 'public']}
9293
mock_ir_cli.assert_called_once_with(1, **expected)
9394

9495
@mock.patch.object(keystoneauth1.session, 'Session')
@@ -113,7 +114,8 @@ def test__get_client_session_service_not_found(self, mock_ir_cli,
113114
'max_retries': CONF.ironic.api_max_retries,
114115
'retry_interval': CONF.ironic.api_retry_interval,
115116
'os_ironic_api_version': ['1.46', '1.38'],
116-
'endpoint': None}
117+
'endpoint': None,
118+
'interface': ['internal', 'public']}
117119
mock_ir_cli.assert_called_once_with(1, **expected)
118120

119121
@mock.patch.object(keystoneauth1.session, 'Session')
@@ -131,7 +133,28 @@ def test__get_client_session_legacy(self, mock_ir_cli, mock_session):
131133
'max_retries': CONF.ironic.api_max_retries,
132134
'retry_interval': CONF.ironic.api_retry_interval,
133135
'os_ironic_api_version': ['1.46', '1.38'],
134-
'endpoint': endpoint}
136+
'endpoint': endpoint,
137+
'interface': ['internal', 'public']}
138+
mock_ir_cli.assert_called_once_with(1, **expected)
139+
140+
@mock.patch.object(keystoneauth1.session, 'Session')
141+
@mock.patch.object(ironic_client, 'get_client')
142+
def test__get_client_and_valid_interfaces(self, mock_ir_cli, mock_session):
143+
"""Endpoint discovery via legacy api_endpoint conf option."""
144+
mock_session.return_value = 'session'
145+
endpoint = 'https://baremetal.example.com/endpoint'
146+
self.flags(api_endpoint=endpoint, group='ironic')
147+
self.flags(valid_interfaces='admin', group='ironic')
148+
ironicclient = client_wrapper.IronicClientWrapper()
149+
# dummy call to have _get_client() called
150+
ironicclient.call("node.list")
151+
self.get_ksa_adapter.assert_not_called()
152+
expected = {'session': 'session',
153+
'max_retries': CONF.ironic.api_max_retries,
154+
'retry_interval': CONF.ironic.api_retry_interval,
155+
'os_ironic_api_version': ['1.46', '1.38'],
156+
'endpoint': endpoint,
157+
'interface': ['admin']}
135158
mock_ir_cli.assert_called_once_with(1, **expected)
136159

137160
@mock.patch.object(client_wrapper.IronicClientWrapper, '_multi_getattr')

nova/virt/ironic/client_wrapper.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ def _get_client(self, retry_on_conflict=True):
9999
kwargs['os_ironic_api_version'] = [
100100
'%d.%d' % IRONIC_API_VERSION, '%d.%d' % PRIOR_IRONIC_API_VERSION]
101101

102+
ironic_conf = CONF[IRONIC_GROUP.name]
103+
# valid_interfaces is a list. ironicclient passes this kwarg through to
104+
# ksa, which is set up to handle 'interface' as either a list or a
105+
# single value.
106+
kwargs['interface'] = ironic_conf.valid_interfaces
107+
102108
# NOTE(clenimar/efried): by default, the endpoint is taken from the
103109
# service catalog. Use `endpoint_override` if you want to override it.
104110
if CONF.ironic.api_endpoint:
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
[`bug 1818295 <https://bugs.launchpad.net/nova/+bug/1818295>`_]
5+
Fixes the problem with endpoint lookup in Ironic driver where only public
6+
endpoint is possible, which breaks deployments where the controllers have
7+
no route to the public network per security requirement. Note that
8+
python-ironicclient fix I610836e5038774621690aca88b2aee25670f0262 must
9+
also be present to resolve the bug.

0 commit comments

Comments
 (0)