5ed520df89
If the node is locked, a lookup cannot be performed when an agent token needs to be generated, which tends to error like this: ironic_python_agent.ironic_api_client [-] Failed looking up node with addresses '00:6f:bb:34:b3:4d,00:6f:bb:34:b3:4b' at https://172.22.0.2:6385. Error 409: Node c25e451b-d2fb-4168-b690-f15bc8365520 is locked by host 172.22.0.2, please retry after the current operation is completed.. Check if inspection has completed. Problem is, if we keep pounding on the door, we can actually worsen the situation, and previously we would just just let tenacity retry. We will now hold for 30 seconds before proceeding, so we have hopefully allowed the operation to complete. Also fixes the error logging to help human's sanity. Change-Id: I97d3e27e2adb731794a7746737d3788c6e7977a0
581 lines
24 KiB
Python
581 lines
24 KiB
Python
# Copyright 2013 Rackspace, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import json
|
|
import time
|
|
from unittest import mock
|
|
|
|
from oslo_config import cfg
|
|
import requests
|
|
|
|
from ironic_python_agent import errors
|
|
from ironic_python_agent import hardware
|
|
from ironic_python_agent import ironic_api_client
|
|
from ironic_python_agent.tests.unit import base
|
|
from ironic_python_agent import version
|
|
|
|
API_URL = 'http://agent-api.ironic.example.org/'
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
|
class FakeResponse(object):
|
|
def __init__(self, content=None, status_code=200, headers=None):
|
|
content = content or {}
|
|
self.text = json.dumps(content)
|
|
# TODO(dtantsur): remove in favour of using text/json()
|
|
self.content = self.text.encode('utf-8')
|
|
self._json = content
|
|
self.status_code = status_code
|
|
self.headers = headers or {}
|
|
|
|
def json(self):
|
|
return self._json
|
|
|
|
|
|
class TestBaseIronicPythonAgent(base.IronicAgentTest):
|
|
def setUp(self):
|
|
super(TestBaseIronicPythonAgent, self).setUp()
|
|
self.api_client = ironic_api_client.APIClient(API_URL)
|
|
self.api_client._ironic_api_version = (
|
|
ironic_api_client.MIN_IRONIC_VERSION)
|
|
self.hardware_info = {
|
|
'interfaces': [
|
|
hardware.NetworkInterface(
|
|
'eth0', '00:0c:29:8c:11:b1', vendor='0x15b3',
|
|
product='0x1014'),
|
|
hardware.NetworkInterface(
|
|
'eth1', '00:0c:29:8c:11:b2',
|
|
lldp=[(1, '04885a92ec5459'),
|
|
(2, '0545746865726e6574312f3138')],
|
|
vendor='0x15b3', product='0x1014'),
|
|
],
|
|
'cpu': hardware.CPU('Awesome Jay CPU x10 9001', '9001', '10',
|
|
'ARMv9'),
|
|
'disks': [
|
|
hardware.BlockDevice('/dev/sdj', 'small', '9001', False),
|
|
hardware.BlockDevice('/dev/hdj', 'big', '9002', False),
|
|
],
|
|
'memory': hardware.Memory(total='8675309',
|
|
physical_mb='8675'),
|
|
}
|
|
|
|
def test__get_ironic_api_version_already_set(self):
|
|
self.api_client.session.request = mock.create_autospec(
|
|
self.api_client.session.request,
|
|
return_value=None)
|
|
|
|
self.assertFalse(self.api_client.session.request.called)
|
|
self.assertEqual(ironic_api_client.MIN_IRONIC_VERSION,
|
|
self.api_client._get_ironic_api_version())
|
|
|
|
def test__get_ironic_api_version_set_via_conf(self):
|
|
self.api_client._ironic_api_version = None
|
|
CONF.set_override('ironic_api_version', "1.47")
|
|
self.api_client.session.request = mock.create_autospec(
|
|
self.api_client.session.request,
|
|
return_value=None)
|
|
|
|
self.assertEqual((1, 47), self.api_client._get_ironic_api_version())
|
|
self.assertFalse(self.api_client.session.request.called)
|
|
|
|
def test__get_ironic_api_version_error(self):
|
|
self.api_client._ironic_api_version = None
|
|
self.api_client.session.request = mock.create_autospec(
|
|
self.api_client.session.request,
|
|
return_value=None)
|
|
self.api_client.session.request.side_effect = Exception("Boom")
|
|
|
|
self.assertEqual(ironic_api_client.MIN_IRONIC_VERSION,
|
|
self.api_client._get_ironic_api_version())
|
|
|
|
def test__get_ironic_api_version_fresh(self):
|
|
self.api_client._ironic_api_version = None
|
|
response = FakeResponse(status_code=200, content={
|
|
"default_version": {
|
|
"id": "v1",
|
|
"links": [
|
|
{
|
|
"href": "http://127.0.0.1:6385/v1/",
|
|
"rel": "self"
|
|
}
|
|
],
|
|
"min_version": "1.1",
|
|
"status": "CURRENT",
|
|
"version": "1.31"
|
|
}
|
|
})
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertEqual((1, 31), self.api_client._get_ironic_api_version())
|
|
self.assertEqual((1, 31), self.api_client._ironic_api_version)
|
|
|
|
def test_successful_heartbeat(self):
|
|
response = FakeResponse(status_code=202)
|
|
req_id = "req-14c99bd0-1bb5-4d74-972b-e282a50ce441"
|
|
self.config(global_request_id=req_id)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.api_client._ironic_api_version = (
|
|
ironic_api_client.AGENT_VERSION_IRONIC_VERSION)
|
|
|
|
self.api_client.heartbeat(
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999')
|
|
)
|
|
|
|
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
request_kwargs = self.api_client.session.request.call_args[1]
|
|
data = request_kwargs["data"]
|
|
self.assertEqual('POST', request_args[0])
|
|
request_headers = request_kwargs["headers"]
|
|
self.assertEqual(
|
|
req_id, request_headers["X-OpenStack-Request-ID"])
|
|
self.assertEqual(API_URL + heartbeat_path, request_args[1])
|
|
expected_data = {
|
|
'callback_url': 'http://192.0.2.1:9999',
|
|
'agent_version': version.__version__}
|
|
self.assertEqual(json.dumps(expected_data), data)
|
|
|
|
def test_successful_heartbeat_ip6(self):
|
|
response = FakeResponse(status_code=202)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.api_client._ironic_api_version = (
|
|
ironic_api_client.AGENT_VERSION_IRONIC_VERSION)
|
|
|
|
self.api_client.heartbeat(
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('fc00:1111::4', '9999')
|
|
)
|
|
|
|
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
data = self.api_client.session.request.call_args[1]['data']
|
|
self.assertEqual('POST', request_args[0])
|
|
self.assertEqual(API_URL + heartbeat_path, request_args[1])
|
|
expected_data = {
|
|
'callback_url': 'http://[fc00:1111::4]:9999',
|
|
'agent_version': version.__version__}
|
|
self.assertEqual(json.dumps(expected_data), data)
|
|
|
|
def test_successful_heartbeat_with_token(self):
|
|
response = FakeResponse(status_code=202)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.api_client._ironic_api_version = (
|
|
ironic_api_client.AGENT_TOKEN_IRONIC_VERSION)
|
|
self.api_client.agent_token = 'magical'
|
|
|
|
self.api_client.heartbeat(
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999')
|
|
)
|
|
|
|
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
data = self.api_client.session.request.call_args[1]['data']
|
|
self.assertEqual('POST', request_args[0])
|
|
self.assertEqual(API_URL + heartbeat_path, request_args[1])
|
|
expected_data = {
|
|
'callback_url': 'http://192.0.2.1:9999',
|
|
'agent_token': 'magical',
|
|
'agent_version': version.__version__}
|
|
self.assertEqual(json.dumps(expected_data), data)
|
|
|
|
def test_heartbeat_agent_version_unsupported(self):
|
|
response = FakeResponse(status_code=202)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.api_client._ironic_api_version = (1, 31)
|
|
|
|
self.api_client.heartbeat(
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('fc00:1111::4', '9999')
|
|
)
|
|
|
|
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
data = self.api_client.session.request.call_args[1]['data']
|
|
self.assertEqual('POST', request_args[0])
|
|
self.assertEqual(API_URL + heartbeat_path, request_args[1])
|
|
expected_data = {
|
|
'callback_url': 'http://[fc00:1111::4]:9999'}
|
|
self.assertEqual(json.dumps(expected_data), data)
|
|
|
|
def test_successful_heartbeat_with_verify_ca(self):
|
|
response = FakeResponse(status_code=202)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.api_client._ironic_api_version = (
|
|
ironic_api_client.AGENT_VERIFY_CA_IRONIC_VERSION)
|
|
self.api_client.agent_token = 'magical'
|
|
|
|
self.api_client.heartbeat(
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'),
|
|
advertise_protocol='https',
|
|
generated_cert='I am a cert',
|
|
)
|
|
|
|
heartbeat_path = 'v1/heartbeat/deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
data = self.api_client.session.request.call_args[1]['data']
|
|
self.assertEqual('POST', request_args[0])
|
|
self.assertEqual(API_URL + heartbeat_path, request_args[1])
|
|
expected_data = {
|
|
'callback_url': 'https://192.0.2.1:9999',
|
|
'agent_token': 'magical',
|
|
'agent_version': version.__version__,
|
|
'agent_verify_ca': 'I am a cert'}
|
|
self.assertEqual(json.dumps(expected_data), data)
|
|
headers = self.api_client.session.request.call_args[1]['headers']
|
|
self.assertEqual(
|
|
'%d.%d' % ironic_api_client.AGENT_VERIFY_CA_IRONIC_VERSION,
|
|
headers['X-OpenStack-Ironic-API-Version'])
|
|
|
|
def test_heartbeat_requests_exception(self):
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.side_effect = Exception('api is down!')
|
|
|
|
self.assertRaises(errors.HeartbeatError,
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_invalid_status_code(self):
|
|
response = FakeResponse(status_code=404)
|
|
response.text = 'Not a JSON'
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertRaisesRegex(errors.HeartbeatError,
|
|
'Error 404: Not a JSON',
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_error_format_1(self):
|
|
response = FakeResponse(
|
|
status_code=404,
|
|
content={'error_message': '{"faultcode": "Client", '
|
|
'"faultstring": "Resource could not be found.", '
|
|
'"debuginfo": null}'})
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertRaisesRegex(errors.HeartbeatError,
|
|
'Error 404: Resource could not be found',
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_error_format_2(self):
|
|
response = FakeResponse(
|
|
status_code=404,
|
|
content={'error_message': {
|
|
"faultcode\\": "Client",
|
|
"faultstring": "Resource could not be found.",
|
|
"debuginfo": None}})
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertRaisesRegex(errors.HeartbeatError,
|
|
'Error 404: Resource could not be found',
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_error_format_3(self):
|
|
response = FakeResponse(
|
|
status_code=404,
|
|
content={'error_message': {
|
|
"code": 404,
|
|
"title": "Resource could not be found.",
|
|
"description": None}})
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertRaisesRegex(errors.HeartbeatError,
|
|
'Error 404: Resource could not be found',
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_409_status_code(self):
|
|
response = FakeResponse(status_code=409)
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertRaises(errors.HeartbeatConflictError,
|
|
self.api_client.heartbeat,
|
|
uuid='deadbeef-dabb-ad00-b105-f00d00bab10c',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
def test_heartbeat_requests_connection_error(self):
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.side_effect = \
|
|
requests.exceptions.ConnectionError
|
|
self.assertRaisesRegex(errors.HeartbeatConnectionError,
|
|
'transitory network failure or blocking port',
|
|
self.api_client.heartbeat,
|
|
uuid='meow',
|
|
advertise_address=('192.0.2.1', '9999'))
|
|
|
|
@mock.patch('time.sleep', autospec=True)
|
|
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
|
|
autospec=True)
|
|
def test_lookup_node(self, lookup_mock, sleep_mock):
|
|
content = {
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
},
|
|
'config': {
|
|
'heartbeat_timeout': 300
|
|
}
|
|
}
|
|
lookup_mock.return_value = content
|
|
returned_content = self.api_client.lookup_node(
|
|
hardware_info=self.hardware_info,
|
|
timeout=300,
|
|
starting_interval=1)
|
|
|
|
self.assertEqual(content, returned_content)
|
|
|
|
@mock.patch('time.sleep', autospec=True)
|
|
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
|
|
autospec=True)
|
|
def test_lookup_node_retries(self, lookup_mock, sleep_mock):
|
|
content = {
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
},
|
|
'config': {
|
|
'heartbeat_timeout': 300
|
|
}
|
|
}
|
|
lookup_mock.side_effect = [False, content]
|
|
returned_content = self.api_client.lookup_node(
|
|
hardware_info=self.hardware_info,
|
|
timeout=300,
|
|
starting_interval=0.001)
|
|
|
|
self.assertEqual(content, returned_content)
|
|
|
|
@mock.patch('time.sleep', autospec=True)
|
|
@mock.patch('ironic_python_agent.ironic_api_client.APIClient._do_lookup',
|
|
autospec=True)
|
|
def test_lookup_timeout(self, lookup_mock, sleep_mock):
|
|
lookup_mock.return_value = False
|
|
self.assertRaises(errors.LookupNodeError,
|
|
self.api_client.lookup_node,
|
|
hardware_info=self.hardware_info,
|
|
timeout=0.1,
|
|
starting_interval=0.001)
|
|
|
|
def test_do_lookup(self):
|
|
content = {
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
},
|
|
'config': {
|
|
'heartbeat_timeout': 300
|
|
}
|
|
}
|
|
response = FakeResponse(status_code=200, content=content)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertEqual(content, self.api_client._do_lookup(
|
|
hardware_info=self.hardware_info,
|
|
node_uuid=None))
|
|
|
|
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
self.assertEqual('GET', request_args[0])
|
|
self.assertEqual(url, request_args[1])
|
|
params = self.api_client.session.request.call_args[1]['params']
|
|
self.assertEqual({'addresses': '00:0c:29:8c:11:b1,00:0c:29:8c:11:b2'},
|
|
params)
|
|
|
|
def test_do_lookup_with_uuid(self):
|
|
content = {
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
},
|
|
'config': {
|
|
'heartbeat_timeout': 300
|
|
}
|
|
}
|
|
response = FakeResponse(status_code=200, content=content)
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
self.assertEqual(content, self.api_client._do_lookup(
|
|
hardware_info=self.hardware_info,
|
|
node_uuid='someuuid'))
|
|
|
|
url = '{api_url}v1/lookup'.format(api_url=API_URL)
|
|
request_args = self.api_client.session.request.call_args[0]
|
|
self.assertEqual('GET', request_args[0])
|
|
self.assertEqual(url, request_args[1])
|
|
params = self.api_client.session.request.call_args[1]['params']
|
|
self.assertEqual({'addresses': '00:0c:29:8c:11:b1,00:0c:29:8c:11:b2',
|
|
'node_uuid': 'someuuid'},
|
|
params)
|
|
|
|
@mock.patch.object(ironic_api_client, 'LOG', autospec=True)
|
|
def test_do_lookup_transient_exceptions(self, mock_log):
|
|
exc_list = [requests.exceptions.ConnectionError,
|
|
requests.exceptions.ReadTimeout,
|
|
requests.exceptions.HTTPError,
|
|
requests.exceptions.Timeout,
|
|
requests.exceptions.ConnectTimeout]
|
|
self.api_client.session.request = mock.Mock()
|
|
for exc in exc_list:
|
|
self.api_client.session.request.reset_mock()
|
|
mock_log.reset_mock()
|
|
self.api_client.session.request.side_effect = exc
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertFalse(error)
|
|
mock_log.error.assert_has_calls([])
|
|
self.assertEqual(1, mock_log.warning.call_count)
|
|
|
|
@mock.patch.object(time, 'sleep', autospec=True)
|
|
@mock.patch.object(ironic_api_client, 'LOG', autospec=True)
|
|
def test_do_lookup_node_locked(self, mock_log, mock_sleep):
|
|
response = FakeResponse(status_code=409, content={})
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
self.assertEqual(0, self.api_client.lookup_lock_pause)
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertFalse(error)
|
|
mock_log.error.assert_has_calls([])
|
|
self.assertEqual(1, mock_log.warning.call_count)
|
|
self.assertEqual(1, mock_sleep.call_count)
|
|
self.assertEqual(5, self.api_client.lookup_lock_pause)
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertEqual(10, self.api_client.lookup_lock_pause)
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertFalse(error)
|
|
self.assertEqual(30, self.api_client.lookup_lock_pause)
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertFalse(error)
|
|
self.assertEqual(30, self.api_client.lookup_lock_pause)
|
|
|
|
@mock.patch.object(ironic_api_client, 'LOG', autospec=True)
|
|
def test_do_lookup_unknown_exception(self, mock_log):
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.side_effect = \
|
|
requests.exceptions.RequestException('meow')
|
|
self.assertFalse(
|
|
self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None))
|
|
self.assertEqual(1, mock_log.exception.call_count)
|
|
|
|
@mock.patch.object(ironic_api_client, 'LOG', autospec=True)
|
|
def test_do_lookup_unknown_exception_fallback(self, mock_log):
|
|
mock_log.exception.side_effect = TypeError
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.side_effect = \
|
|
requests.exceptions.RequestException('meow')
|
|
self.assertRaises(errors.LookupNodeError,
|
|
self.api_client._do_lookup,
|
|
self.hardware_info,
|
|
node_uuid=None)
|
|
self.assertEqual(1, mock_log.exception.call_count)
|
|
self.assertEqual(2, mock_log.error.call_count)
|
|
|
|
def test_do_lookup_bad_response_code(self):
|
|
response = FakeResponse(status_code=400, content={
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
}
|
|
})
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
|
|
self.assertFalse(error)
|
|
|
|
def test_do_lookup_bad_response_data(self):
|
|
response = FakeResponse(status_code=200, content={
|
|
'heartbeat_timeout': 300
|
|
})
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
|
|
self.assertFalse(error)
|
|
|
|
def test_do_lookup_no_heartbeat_timeout(self):
|
|
response = FakeResponse(status_code=200, content={
|
|
'node': {
|
|
'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c'
|
|
}
|
|
})
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
|
|
self.assertFalse(error)
|
|
|
|
def test_do_lookup_bad_response_body(self):
|
|
response = FakeResponse(status_code=200, content={
|
|
'node_node': 'also_not_node'
|
|
})
|
|
|
|
self.api_client.session.request = mock.Mock()
|
|
self.api_client.session.request.return_value = response
|
|
|
|
error = self.api_client._do_lookup(self.hardware_info,
|
|
node_uuid=None)
|
|
|
|
self.assertFalse(error)
|
|
|
|
def test_get_agent_url_ipv4(self):
|
|
url = self.api_client._get_agent_url(('1.2.3.4', '9999'))
|
|
self.assertEqual('http://1.2.3.4:9999', url)
|
|
|
|
def test_get_agent_url_ipv6(self):
|
|
url = self.api_client._get_agent_url(('1:2::3:4', '9999'))
|
|
self.assertEqual('http://[1:2::3:4]:9999', url)
|
|
|
|
def test_get_agent_url_protocol(self):
|
|
url = self.api_client._get_agent_url(('1:2::3:4', '9999'), 'https')
|
|
self.assertEqual('https://[1:2::3:4]:9999', url)
|