Skip to content

Commit b033bfd

Browse files
committed
Remove old lookup/heartbeat from IPA
Lookup/Heartbeat via vendor passthru was deprecated in Newton. This patch removes the corresponding functionality from IPA, and also removes handling of 'ipa-driver-name' kernel parameter, as it was only used in code related to old passthru. Change-Id: I2c7989063ab3e4c0bae33f05d6d2ed857a2d9944 Closes-Bug: #1640533
1 parent dca181a commit b033bfd

8 files changed

Lines changed: 26 additions & 198 deletions

File tree

ironic_python_agent/agent.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class IronicPythonAgent(base.ExecuteCommandMixin):
159159

160160
def __init__(self, api_url, advertise_address, listen_address,
161161
ip_lookup_attempts, ip_lookup_sleep, network_interface,
162-
lookup_timeout, lookup_interval, driver_name, standalone,
162+
lookup_timeout, lookup_interval, standalone,
163163
hardware_initialization_delay=0):
164164
super(IronicPythonAgent, self).__init__()
165165
self.ext_mgr = extension.ExtensionManager(
@@ -169,9 +169,7 @@ def __init__(self, api_url, advertise_address, listen_address,
169169
invoke_kwds={'agent': self},
170170
)
171171
self.api_url = api_url
172-
self.driver_name = driver_name
173-
self.api_client = ironic_api_client.APIClient(self.api_url,
174-
self.driver_name)
172+
self.api_client = ironic_api_client.APIClient(self.api_url)
175173
self.listen_address = listen_address
176174
self.advertise_address = advertise_address
177175
self.version = pkg_resources.get_distribution('ironic-python-agent')\

ironic_python_agent/cmd/agent.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,5 @@ def run():
4444
CONF.network_interface,
4545
CONF.lookup_timeout,
4646
CONF.lookup_interval,
47-
CONF.driver_name,
4847
CONF.standalone,
4948
CONF.hardware_initialization_delay).run()

ironic_python_agent/config.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,6 @@
8282
'doubled after each failure until timeout is '
8383
'exceeded.'),
8484

85-
cfg.StrOpt('driver_name',
86-
default=APARAMS.get('ipa-driver-name', 'agent_ipmitool'),
87-
deprecated_name='driver-name',
88-
help='The Ironic driver in use for this node'),
89-
9085
cfg.FloatOpt('lldp_timeout',
9186
default=APARAMS.get('ipa-lldp-timeout',
9287
APARAMS.get('lldp-timeout', 30.0)),

ironic_python_agent/ironic_api_client.py

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,12 @@
2727

2828
class APIClient(object):
2929
api_version = 'v1'
30-
payload_version = '2'
31-
use_ramdisk_api = True
3230
lookup_api = '/%s/lookup' % api_version
3331
heartbeat_api = '/%s/heartbeat/{uuid}' % api_version
34-
# TODO(dtanstur): drop support for old passthru in Ocata
35-
lookup_passthru = ('/%s/drivers/{driver}/vendor_passthru/lookup'
36-
% api_version)
37-
heartbeat_passthru = ('/%s/nodes/{uuid}/vendor_passthru/heartbeat'
38-
% api_version)
3932
ramdisk_api_headers = {'X-OpenStack-Ironic-API-Version': '1.22'}
4033

41-
def __init__(self, api_url, driver_name):
34+
def __init__(self, api_url):
4235
self.api_url = api_url.rstrip('/')
43-
self.driver_name = driver_name
4436

4537
# Only keep alive a maximum of 2 connections to the API. More will be
4638
# opened if they are needed, but they will be closed immediately after
@@ -70,22 +62,12 @@ def _request(self, method, path, data=None, headers=None, **kwargs):
7062
data=data,
7163
**kwargs)
7264

73-
def _heartbeat_request(self, uuid, agent_url):
74-
if self.use_ramdisk_api:
75-
path = self.heartbeat_api.format(uuid=uuid)
76-
data = {'callback_url': agent_url}
77-
headers = self.ramdisk_api_headers
78-
else:
79-
path = self.heartbeat_passthru.format(uuid=uuid)
80-
data = {'agent_url': agent_url}
81-
headers = None
82-
83-
return self._request('POST', path, data=data, headers=headers)
84-
8565
def heartbeat(self, uuid, advertise_address):
86-
agent_url = self._get_agent_url(advertise_address)
66+
path = self.heartbeat_api.format(uuid=uuid)
67+
data = {'callback_url': self._get_agent_url(advertise_address)}
8768
try:
88-
response = self._heartbeat_request(uuid, agent_url)
69+
response = self._request('POST', path, data=data,
70+
headers=self.ramdisk_api_headers)
8971
except Exception as e:
9072
raise errors.HeartbeatError(str(e))
9173

@@ -110,7 +92,11 @@ def lookup_node(self, hardware_info, timeout, starting_interval,
11092
'logs for details.')
11193
return node_content
11294

113-
def _do_new_lookup(self, hardware_info, node_uuid):
95+
def _do_lookup(self, hardware_info, node_uuid):
96+
"""The actual call to lookup a node.
97+
98+
Should be called as a `loopingcall.BackOffLoopingCall`.
99+
"""
114100
params = {
115101
'addresses': ','.join(iface.mac_address
116102
for iface in hardware_info['interfaces']
@@ -119,45 +105,10 @@ def _do_new_lookup(self, hardware_info, node_uuid):
119105
if node_uuid:
120106
params['node_uuid'] = node_uuid
121107

122-
response = self._request('GET', self.lookup_api,
123-
headers=self.ramdisk_api_headers,
124-
params=params)
125-
if response.status_code in (requests.codes.NOT_FOUND,
126-
requests.codes.UNAUTHORIZED,
127-
requests.codes.NOT_ACCEPTABLE):
128-
# Assume that new API is not available and retry
129-
LOG.warning('New API is not available, falling back to old '
130-
'agent vendor passthru')
131-
self.use_ramdisk_api = False
132-
return self._do_passthru_lookup(hardware_info, node_uuid)
133-
134-
return response
135-
136-
def _do_passthru_lookup(self, hardware_info, node_uuid):
137-
path = self.lookup_passthru.format(driver=self.driver_name)
138-
# This hardware won't be saved on the node currently, because of
139-
# how driver_vendor_passthru is implemented (no node saving).
140-
data = {
141-
'version': self.payload_version,
142-
'inventory': hardware_info
143-
}
144-
if node_uuid:
145-
data['node_uuid'] = node_uuid
146-
147-
# Make the POST, make sure we get back normal data/status codes and
148-
# content
149-
return self._request('POST', path, data=data)
150-
151-
def _do_lookup(self, hardware_info, node_uuid):
152-
"""The actual call to lookup a node.
153-
154-
Should be called as a `loopingcall.BackOffLoopingCall`.
155-
"""
156108
try:
157-
response = (self._do_new_lookup(hardware_info, node_uuid)
158-
if self.use_ramdisk_api
159-
else self._do_passthru_lookup(hardware_info,
160-
node_uuid))
109+
response = self._request('GET', self.lookup_api,
110+
headers=self.ramdisk_api_headers,
111+
params=params)
161112
except Exception:
162113
LOG.exception('Lookup failed')
163114
return False

ironic_python_agent/tests/functional/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def setUp(self):
4646
network_interface=None,
4747
lookup_timeout=300,
4848
lookup_interval=1,
49-
driver_name='agent_ipmitool',
5049
standalone=True)
5150
self.process = multiprocessing.Process(
5251
target=self.agent.run)

ironic_python_agent/tests/unit/test_agent.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ def setUp(self):
144144
'eth0',
145145
300,
146146
1,
147-
'agent_ipmitool',
148147
False)
149148
self.agent.ext_mgr = extension.ExtensionManager.\
150149
make_test_instance([extension.Extension('fake', None,
@@ -438,7 +437,6 @@ def setUp(self):
438437
network_interface=None,
439438
lookup_timeout=300,
440439
lookup_interval=1,
441-
driver_name='agent_ipmitool',
442440
standalone=False)
443441

444442
def test_advertise_address_provided(self, mock_exec, mock_gethostbyname):

ironic_python_agent/tests/unit/test_ironic_api_client.py

Lines changed: 1 addition & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@
1717
import mock
1818
from oslo_service import loopingcall
1919
from oslotest import base as test_base
20-
import requests
2120

2221
from ironic_python_agent import errors
2322
from ironic_python_agent import hardware
2423
from ironic_python_agent import ironic_api_client
2524

2625
API_URL = 'http://agent-api.ironic.example.org/'
27-
DRIVER = 'agent_ipmitool'
2826

2927

3028
class FakeResponse(object):
@@ -38,7 +36,7 @@ def __init__(self, content=None, status_code=200, headers=None):
3836
class TestBaseIronicPythonAgent(test_base.BaseTestCase):
3937
def setUp(self):
4038
super(TestBaseIronicPythonAgent, self).setUp()
41-
self.api_client = ironic_api_client.APIClient(API_URL, DRIVER)
39+
self.api_client = ironic_api_client.APIClient(API_URL)
4240
self.hardware_info = {
4341
'interfaces': [
4442
hardware.NetworkInterface(
@@ -76,24 +74,6 @@ def test_successful_heartbeat(self):
7674
self.assertEqual('POST', request_args[0])
7775
self.assertEqual(API_URL + heartbeat_path, request_args[1])
7876

79-
def test_successful_heartbeat_old_api(self):
80-
response = FakeResponse(status_code=202)
81-
82-
self.api_client.session.request = mock.Mock()
83-
self.api_client.session.request.return_value = response
84-
85-
self.api_client.use_ramdisk_api = False
86-
self.api_client.heartbeat(
87-
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
88-
advertise_address=('192.0.2.1', '9999')
89-
)
90-
91-
heartbeat_path = ('v1/nodes/deadbeef-dabb-ad00-b105-f00d00bab10c/'
92-
'vendor_passthru/heartbeat')
93-
request_args = self.api_client.session.request.call_args[0]
94-
self.assertEqual('POST', request_args[0])
95-
self.assertEqual(API_URL + heartbeat_path, request_args[1])
96-
9777
def test_heartbeat_requests_exception(self):
9878
self.api_client.session.request = mock.Mock()
9979
self.api_client.session.request.side_effect = Exception('api is down!')
@@ -178,7 +158,6 @@ def test_do_lookup(self):
178158
params = self.api_client.session.request.call_args[1]['params']
179159
self.assertEqual({'addresses': '00:0c:29:8c:11:b1,00:0c:29:8c:11:b2'},
180160
params)
181-
self.assertTrue(self.api_client.use_ramdisk_api)
182161

183162
def test_do_lookup_with_uuid(self):
184163
response = FakeResponse(status_code=200, content={
@@ -262,104 +241,3 @@ def test_do_lookup_bad_response_body(self):
262241
node_uuid=None)
263242

264243
self.assertFalse(error)
265-
266-
def _test_do_lookup_fallback(self, error_code):
267-
response0 = FakeResponse(status_code=error_code)
268-
response = FakeResponse(status_code=200, content={
269-
'node': {
270-
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
271-
},
272-
'heartbeat_timeout': 300
273-
})
274-
275-
self.api_client.session.request = mock.Mock()
276-
self.api_client.session.request.side_effect = [response0,
277-
response]
278-
279-
self.assertRaises(loopingcall.LoopingCallDone,
280-
self.api_client._do_lookup,
281-
hardware_info=self.hardware_info,
282-
node_uuid=None)
283-
284-
url = '{api_url}v1/drivers/{driver}/vendor_passthru/lookup'.format(
285-
api_url=API_URL, driver=DRIVER)
286-
self.assertEqual(2, self.api_client.session.request.call_count)
287-
request_args = self.api_client.session.request.call_args_list[1][0]
288-
self.assertEqual('POST', request_args[0])
289-
self.assertEqual(url, request_args[1])
290-
291-
data = self.api_client.session.request.call_args_list[1][1]['data']
292-
content = json.loads(data)
293-
self.assertEqual(self.api_client.payload_version, content['version'])
294-
self.assertEqual({
295-
u'interfaces': [
296-
{
297-
u'mac_address': u'00:0c:29:8c:11:b1',
298-
u'name': u'eth0',
299-
u'ipv4_address': None,
300-
u'switch_chassis_descr': None,
301-
u'switch_port_descr': None,
302-
u'has_carrier': True,
303-
u'lldp': None,
304-
u'vendor': u'0x15b3',
305-
u'product': u'0x1014'
306-
},
307-
{
308-
u'mac_address': u'00:0c:29:8c:11:b2',
309-
u'name': u'eth1',
310-
u'ipv4_address': None,
311-
u'switch_chassis_descr': None,
312-
u'switch_port_descr': None,
313-
u'has_carrier': True,
314-
u'lldp': [[1, u'04885a92ec5459'],
315-
[2, u'0545746865726e6574312f3138']],
316-
u'vendor': u'0x15b3',
317-
u'product': u'0x1014'
318-
}
319-
],
320-
u'cpu': {
321-
u'model_name': u'Awesome Jay CPU x10 9001',
322-
u'frequency': u'9001',
323-
u'count': u'10',
324-
u'architecture': u'ARMv9',
325-
u'flags': [],
326-
},
327-
u'disks': [
328-
{
329-
u'model': u'small',
330-
u'name': u'/dev/sdj',
331-
u'rotational': False,
332-
u'size': u'9001',
333-
u'serial': None,
334-
u'wwn': None,
335-
u'wwn_with_extension': None,
336-
u'wwn_vendor_extension': None,
337-
u'vendor': None,
338-
},
339-
{
340-
u'model': u'big',
341-
u'name': u'/dev/hdj',
342-
u'rotational': False,
343-
u'size': u'9002',
344-
u'serial': None,
345-
u'wwn': None,
346-
u'wwn_with_extension': None,
347-
u'wwn_vendor_extension': None,
348-
u'vendor': None,
349-
}
350-
],
351-
u'memory': {
352-
u'total': u'8675309',
353-
u'physical_mb': u'8675'
354-
},
355-
}, content['inventory'])
356-
self.assertFalse(self.api_client.use_ramdisk_api)
357-
358-
def test_do_lookup_fallback_not_found(self):
359-
self._test_do_lookup_fallback(error_code=requests.codes.NOT_FOUND)
360-
361-
def test_do_lookup_fallback_unauthorized(self):
362-
self._test_do_lookup_fallback(error_code=requests.codes.UNAUTHORIZED)
363-
364-
def test_do_lookup_fallback_not_acceptable(self):
365-
self._test_do_lookup_fallback(error_code=requests.codes.NOT_ACCEPTABLE)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
upgrade:
3+
- Ironic Python Agent no longer supports Ironic API lookup and heartbeat
4+
actions via agent vendor passthru methods,
5+
and uses only the new, top-level lookup and heartbeat endpoints of
6+
Ironic API v1.22 (introduced in Newton release, Ironic version 6.1.0).
7+
8+
This effectively means that Ironic Python Agent becomes incompatible
9+
with Ironic API < 1.22 (Ironic version 6.0.0 or older,
10+
integrated OpenStack release Mitaka or older).

0 commit comments

Comments
 (0)