Load Balancing as a Service (LBaaS) for OpenStack
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1278 lines
56KB

  1. # Copyright 2015 Hewlett-Packard Development Company, L.P.
  2. # Copyright (c) 2015 Rackspace
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. import hashlib
  16. import mock
  17. from oslo_config import cfg
  18. from oslo_config import fixture as oslo_fixture
  19. from oslo_utils import uuidutils
  20. import requests
  21. import requests_mock
  22. import six
  23. from octavia.amphorae.driver_exceptions import exceptions as driver_except
  24. from octavia.amphorae.drivers.haproxy import exceptions as exc
  25. from octavia.amphorae.drivers.haproxy import rest_api_driver as driver
  26. from octavia.common import constants
  27. from octavia.db import models
  28. from octavia.network import data_models as network_models
  29. from octavia.tests.common import sample_certs
  30. from octavia.tests.unit import base
  31. from octavia.tests.unit.common.sample_configs import sample_configs_split
  32. API_VERSION = '0.5'
  33. FAKE_CIDR = '198.51.100.0/24'
  34. FAKE_GATEWAY = '192.51.100.1'
  35. FAKE_IP = '192.0.2.10'
  36. FAKE_IPV6 = '2001:db8::cafe'
  37. FAKE_IPV6_LLA = 'fe80::00ff:fe00:cafe'
  38. FAKE_PEM_FILENAME = "file_name"
  39. FAKE_UUID_1 = uuidutils.generate_uuid()
  40. FAKE_VRRP_IP = '10.1.0.1'
  41. FAKE_MAC_ADDRESS = '123'
  42. FAKE_MTU = 1450
  43. FAKE_MEMBER_IP_PORT_NAME_1 = "10.0.0.10:1003"
  44. FAKE_MEMBER_IP_PORT_NAME_2 = "10.0.0.11:1004"
  45. class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
  46. def setUp(self):
  47. super(TestHaproxyAmphoraLoadBalancerDriverTest, self).setUp()
  48. DEST1 = '198.51.100.0/24'
  49. DEST2 = '203.0.113.0/24'
  50. NEXTHOP = '192.0.2.1'
  51. self.driver = driver.HaproxyAmphoraLoadBalancerDriver()
  52. self.driver.cert_manager = mock.MagicMock()
  53. self.driver.cert_parser = mock.MagicMock()
  54. self.driver.clients = {
  55. 'base': mock.MagicMock(),
  56. API_VERSION: mock.MagicMock()}
  57. self.driver.clients['base'].get_api_version.return_value = {
  58. 'api_version': API_VERSION}
  59. self.driver.clients[
  60. API_VERSION].get_info.return_value = {
  61. 'haproxy_version': u'1.6.3-1ubuntu0.1',
  62. 'api_version': API_VERSION}
  63. self.driver.jinja_split = mock.MagicMock()
  64. self.driver.udp_jinja = mock.MagicMock()
  65. # Build sample Listener and VIP configs
  66. self.sl = sample_configs_split.sample_listener_tuple(
  67. tls=True, sni=True, client_ca_cert=True, client_crl_cert=True,
  68. recursive_nest=True)
  69. self.sl_udp = sample_configs_split.sample_listener_tuple(
  70. proto=constants.PROTOCOL_UDP,
  71. persistence_type=constants.SESSION_PERSISTENCE_SOURCE_IP,
  72. persistence_timeout=33,
  73. persistence_granularity='255.255.0.0',
  74. monitor_proto=constants.HEALTH_MONITOR_UDP_CONNECT)
  75. self.pool_has_cert = sample_configs_split.sample_pool_tuple(
  76. pool_cert=True, pool_ca_cert=True, pool_crl=True)
  77. self.amp = self.sl.load_balancer.amphorae[0]
  78. self.sv = sample_configs_split.sample_vip_tuple()
  79. self.lb = self.sl.load_balancer
  80. self.lb_udp = (
  81. sample_configs_split.sample_lb_with_udp_listener_tuple())
  82. self.fixed_ip = mock.MagicMock()
  83. self.fixed_ip.ip_address = '198.51.100.5'
  84. self.fixed_ip.subnet.cidr = '198.51.100.0/24'
  85. self.network = network_models.Network(mtu=FAKE_MTU)
  86. self.port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
  87. fixed_ips=[self.fixed_ip],
  88. network=self.network)
  89. self.host_routes = [network_models.HostRoute(destination=DEST1,
  90. nexthop=NEXTHOP),
  91. network_models.HostRoute(destination=DEST2,
  92. nexthop=NEXTHOP)]
  93. host_routes_data = [{'destination': DEST1, 'nexthop': NEXTHOP},
  94. {'destination': DEST2, 'nexthop': NEXTHOP}]
  95. self.subnet_info = {'subnet_cidr': FAKE_CIDR,
  96. 'gateway': FAKE_GATEWAY,
  97. 'mac_address': FAKE_MAC_ADDRESS,
  98. 'vrrp_ip': self.amp.vrrp_ip,
  99. 'mtu': FAKE_MTU,
  100. 'host_routes': host_routes_data}
  101. self.timeout_dict = {constants.REQ_CONN_TIMEOUT: 1,
  102. constants.REQ_READ_TIMEOUT: 2,
  103. constants.CONN_MAX_RETRIES: 3,
  104. constants.CONN_RETRY_INTERVAL: 4}
  105. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  106. 'HaproxyAmphoraLoadBalancerDriver._process_secret')
  107. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  108. def test_update_amphora_listeners(self, mock_load_cert, mock_secret):
  109. mock_amphora = mock.MagicMock()
  110. mock_amphora.id = 'mock_amphora_id'
  111. mock_amphora.api_version = API_VERSION
  112. # mock_listener = mock.MagicMock()
  113. # mock_listener.id = 'mock_listener_id'
  114. # mock_listener.protocol = constants.PROTOCOL_HTTP
  115. # mock_listener.connection_limit = constants.DEFAULT_CONNECTION_LIMIT
  116. # mock_listener.tls_certificate_id = None
  117. # mock_loadbalancer = mock.MagicMock()
  118. # mock_loadbalancer.id = 'mock_lb_id'
  119. # mock_loadbalancer.project_id = 'mock_lb_project'
  120. # mock_loadbalancer.listeners = [mock_listener]
  121. # mock_listener.load_balancer = mock_loadbalancer
  122. mock_secret.return_value = 'filename.pem'
  123. mock_load_cert.return_value = {
  124. 'tls_cert': self.sl.default_tls_container, 'sni_certs': [],
  125. 'client_ca_cert': None}
  126. self.driver.jinja_split.build_config.return_value = 'the_config'
  127. mock_empty_lb = mock.MagicMock()
  128. mock_empty_lb.listeners = []
  129. self.driver.update_amphora_listeners(mock_empty_lb, mock_amphora,
  130. self.timeout_dict)
  131. mock_load_cert.assert_not_called()
  132. self.driver.jinja_split.build_config.assert_not_called()
  133. self.driver.clients[API_VERSION].upload_config.assert_not_called()
  134. self.driver.clients[API_VERSION].reload_listener.assert_not_called()
  135. self.driver.update_amphora_listeners(self.lb,
  136. mock_amphora, self.timeout_dict)
  137. self.driver.clients[API_VERSION].upload_config.assert_called_once_with(
  138. mock_amphora, self.sl.id, 'the_config',
  139. timeout_dict=self.timeout_dict)
  140. self.driver.clients[API_VERSION].reload_listener(
  141. mock_amphora, self.sl.id, timeout_dict=self.timeout_dict)
  142. mock_load_cert.reset_mock()
  143. self.driver.jinja_split.build_config.reset_mock()
  144. self.driver.clients[API_VERSION].upload_config.reset_mock()
  145. self.driver.clients[API_VERSION].reload_listener.reset_mock()
  146. mock_amphora.status = constants.DELETED
  147. self.driver.update_amphora_listeners(self.lb,
  148. mock_amphora, self.timeout_dict)
  149. mock_load_cert.assert_not_called()
  150. self.driver.jinja_split.build_config.assert_not_called()
  151. self.driver.clients[API_VERSION].upload_config.assert_not_called()
  152. self.driver.clients[API_VERSION].reload_listener.assert_not_called()
  153. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  154. 'HaproxyAmphoraLoadBalancerDriver._process_secret')
  155. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  156. @mock.patch('octavia.common.tls_utils.cert_parser.get_host_names')
  157. def test_update(self, mock_cert, mock_load_crt, mock_secret):
  158. mock_cert.return_value = {'cn': sample_certs.X509_CERT_CN}
  159. mock_secret.side_effect = ['filename.pem', 'crl-filename.pem']
  160. sconts = []
  161. for sni_container in self.sl.sni_containers:
  162. sconts.append(sni_container.tls_container)
  163. mock_load_crt.side_effect = [{
  164. 'tls_cert': self.sl.default_tls_container, 'sni_certs': sconts},
  165. {'tls_cert': None, 'sni_certs': []}]
  166. self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [
  167. exc.NotFound, 'Fake_MD5', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
  168. 'CA_CERT_MD5']
  169. self.driver.jinja_split.build_config.side_effect = ['fake_config']
  170. # Execute driver method
  171. self.driver.update(self.lb)
  172. # verify result
  173. gcm_calls = [
  174. mock.call(self.amp, self.sl.id,
  175. self.sl.default_tls_container.id + '.pem',
  176. ignore=(404,)),
  177. mock.call(self.amp, self.sl.id,
  178. sconts[0].id + '.pem', ignore=(404,)),
  179. mock.call(self.amp, self.sl.id,
  180. sconts[1].id + '.pem', ignore=(404,)),
  181. ]
  182. self.driver.clients[API_VERSION].get_cert_md5sum.assert_has_calls(
  183. gcm_calls, any_order=True)
  184. # this is called three times (last MD5 matches)
  185. fp1 = b'\n'.join([sample_certs.X509_CERT,
  186. sample_certs.X509_CERT_KEY,
  187. sample_certs.X509_IMDS]) + b'\n'
  188. fp2 = b'\n'.join([sample_certs.X509_CERT_2,
  189. sample_certs.X509_CERT_KEY_2,
  190. sample_certs.X509_IMDS]) + b'\n'
  191. fp3 = b'\n'.join([sample_certs.X509_CERT_3,
  192. sample_certs.X509_CERT_KEY_3,
  193. sample_certs.X509_IMDS]) + b'\n'
  194. ucp_calls = [
  195. mock.call(self.amp, self.sl.id,
  196. self.sl.default_tls_container.id + '.pem', fp1),
  197. mock.call(self.amp, self.sl.id,
  198. sconts[0].id + '.pem', fp2),
  199. mock.call(self.amp, self.sl.id,
  200. sconts[1].id + '.pem', fp3),
  201. ]
  202. self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls(
  203. ucp_calls, any_order=True)
  204. # upload only one config file
  205. self.driver.clients[API_VERSION].upload_config.assert_called_once_with(
  206. self.amp, self.sl.id, 'fake_config', timeout_dict=None)
  207. # start should be called once
  208. self.driver.clients[
  209. API_VERSION].reload_listener.assert_called_once_with(
  210. self.amp, self.sl.id, timeout_dict=None)
  211. secret_calls = [
  212. mock.call(self.sl, self.sl.client_ca_tls_certificate_id, self.amp,
  213. self.sl.id),
  214. mock.call(self.sl, self.sl.client_crl_container_id, self.amp,
  215. self.sl.id)
  216. ]
  217. mock_secret.assert_has_calls(secret_calls)
  218. def test_udp_update(self):
  219. self.driver.udp_jinja.build_config.side_effect = ['fake_udp_config']
  220. # Execute driver method
  221. self.driver.update(self.lb_udp)
  222. # upload only one config file
  223. self.driver.clients[
  224. API_VERSION].upload_udp_config.assert_called_once_with(
  225. self.amp, self.sl_udp.id, 'fake_udp_config', timeout_dict=None)
  226. # start should be called once
  227. self.driver.clients[
  228. API_VERSION].reload_listener.assert_called_once_with(
  229. self.amp, self.sl_udp.id, timeout_dict=None)
  230. def test_upload_cert_amp(self):
  231. self.driver.upload_cert_amp(self.amp, six.b('test'))
  232. self.driver.clients[
  233. API_VERSION].update_cert_for_rotation.assert_called_once_with(
  234. self.amp, six.b('test'))
  235. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  236. def test__process_tls_certificates_no_ca_cert(self, mock_load_crt):
  237. sample_listener = sample_configs_split.sample_listener_tuple(
  238. tls=True, sni=True)
  239. sconts = []
  240. for sni_container in sample_listener.sni_containers:
  241. sconts.append(sni_container.tls_container)
  242. mock_load_crt.return_value = {
  243. 'tls_cert': self.sl.default_tls_container,
  244. 'sni_certs': sconts
  245. }
  246. self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [
  247. exc.NotFound, 'Fake_MD5', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']
  248. self.driver._process_tls_certificates(
  249. sample_listener, self.amp, sample_listener.load_balancer.id)
  250. gcm_calls = [
  251. mock.call(self.amp, self.lb.id,
  252. self.sl.default_tls_container.id + '.pem',
  253. ignore=(404,)),
  254. mock.call(self.amp, self.lb.id,
  255. sconts[0].id + '.pem', ignore=(404,)),
  256. mock.call(self.amp, self.lb.id,
  257. sconts[1].id + '.pem', ignore=(404,))
  258. ]
  259. self.driver.clients[API_VERSION].get_cert_md5sum.assert_has_calls(
  260. gcm_calls, any_order=True)
  261. fp1 = b'\n'.join([sample_certs.X509_CERT,
  262. sample_certs.X509_CERT_KEY,
  263. sample_certs.X509_IMDS]) + b'\n'
  264. fp2 = b'\n'.join([sample_certs.X509_CERT_2,
  265. sample_certs.X509_CERT_KEY_2,
  266. sample_certs.X509_IMDS]) + b'\n'
  267. fp3 = b'\n'.join([sample_certs.X509_CERT_3,
  268. sample_certs.X509_CERT_KEY_3,
  269. sample_certs.X509_IMDS]) + b'\n'
  270. ucp_calls = [
  271. mock.call(self.amp, self.lb.id,
  272. self.sl.default_tls_container.id + '.pem', fp1),
  273. mock.call(self.amp, self.lb.id,
  274. sconts[0].id + '.pem', fp2),
  275. mock.call(self.amp, self.lb.id,
  276. sconts[1].id + '.pem', fp3)
  277. ]
  278. self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls(
  279. ucp_calls, any_order=True)
  280. self.assertEqual(
  281. 3, self.driver.clients[API_VERSION].upload_cert_pem.call_count)
  282. @mock.patch('oslo_context.context.RequestContext')
  283. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  284. 'HaproxyAmphoraLoadBalancerDriver._upload_cert')
  285. def test_process_secret(self, mock_upload_cert, mock_oslo):
  286. # Test bypass if no secret_ref
  287. sample_listener = sample_configs_split.sample_listener_tuple(
  288. tls=True, sni=True)
  289. result = self.driver._process_secret(sample_listener, None)
  290. self.assertIsNone(result)
  291. self.driver.cert_manager.get_secret.assert_not_called()
  292. # Test the secret process
  293. sample_listener = sample_configs_split.sample_listener_tuple(
  294. tls=True, sni=True, client_ca_cert=True)
  295. fake_context = 'fake context'
  296. fake_secret = b'fake cert'
  297. mock_oslo.return_value = fake_context
  298. self.driver.cert_manager.get_secret.reset_mock()
  299. self.driver.cert_manager.get_secret.return_value = fake_secret
  300. ref_md5 = hashlib.md5(fake_secret).hexdigest() # nosec
  301. ref_id = hashlib.sha1(fake_secret).hexdigest() # nosec
  302. ref_name = '{id}.pem'.format(id=ref_id)
  303. result = self.driver._process_secret(
  304. sample_listener, sample_listener.client_ca_tls_certificate_id,
  305. self.amp, sample_listener.id)
  306. mock_oslo.assert_called_once_with(
  307. project_id=sample_listener.project_id)
  308. self.driver.cert_manager.get_secret.assert_called_once_with(
  309. fake_context, sample_listener.client_ca_tls_certificate_id)
  310. mock_upload_cert.assert_called_once_with(
  311. self.amp, sample_listener.id, pem=fake_secret,
  312. md5=ref_md5, name=ref_name)
  313. self.assertEqual(ref_name, result)
  314. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  315. 'HaproxyAmphoraLoadBalancerDriver._process_pool_certs')
  316. def test__process_listener_pool_certs(self, mock_pool_cert):
  317. sample_listener = sample_configs_split.sample_listener_tuple(
  318. l7=True)
  319. ref_pool_cert_1 = {'client_cert': '/some/fake/cert-1.pem'}
  320. ref_pool_cert_2 = {'client_cert': '/some/fake/cert-2.pem'}
  321. mock_pool_cert.side_effect = [ref_pool_cert_1, ref_pool_cert_2]
  322. ref_cert_dict = {'sample_pool_id_1': ref_pool_cert_1,
  323. 'sample_pool_id_2': ref_pool_cert_2}
  324. result = self.driver._process_listener_pool_certs(
  325. sample_listener, self.amp, sample_listener.load_balancer.id)
  326. pool_certs_calls = [
  327. mock.call(sample_listener, sample_listener.default_pool,
  328. self.amp, sample_listener.load_balancer.id),
  329. mock.call(sample_listener, sample_listener.pools[1],
  330. self.amp, sample_listener.load_balancer.id)
  331. ]
  332. mock_pool_cert.assert_has_calls(pool_certs_calls, any_order=True)
  333. self.assertEqual(ref_cert_dict, result)
  334. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  335. 'HaproxyAmphoraLoadBalancerDriver._process_secret')
  336. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  337. 'HaproxyAmphoraLoadBalancerDriver._upload_cert')
  338. @mock.patch('octavia.common.tls_utils.cert_parser.build_pem')
  339. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  340. def test__process_pool_certs(self, mock_load_certs, mock_build_pem,
  341. mock_upload_cert, mock_secret):
  342. fake_cert_dir = '/fake/cert/dir'
  343. conf = oslo_fixture.Config(cfg.CONF)
  344. conf.config(group="haproxy_amphora", base_cert_dir=fake_cert_dir)
  345. sample_listener = sample_configs_split.sample_listener_tuple(
  346. pool_cert=True, pool_ca_cert=True, pool_crl=True)
  347. cert_data_mock = mock.MagicMock()
  348. cert_data_mock.id = uuidutils.generate_uuid()
  349. mock_load_certs.return_value = cert_data_mock
  350. fake_pem = b'fake pem'
  351. mock_build_pem.return_value = fake_pem
  352. ref_md5 = hashlib.md5(fake_pem).hexdigest() # nosec
  353. ref_name = '{id}.pem'.format(id=cert_data_mock.id)
  354. ref_path = '{cert_dir}/{list_id}/{name}'.format(
  355. cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name)
  356. ref_ca_name = 'fake_ca.pem'
  357. ref_ca_path = '{cert_dir}/{list_id}/{name}'.format(
  358. cert_dir=fake_cert_dir, list_id=sample_listener.id,
  359. name=ref_ca_name)
  360. ref_crl_name = 'fake_crl.pem'
  361. ref_crl_path = '{cert_dir}/{list_id}/{name}'.format(
  362. cert_dir=fake_cert_dir, list_id=sample_listener.id,
  363. name=ref_crl_name)
  364. ref_result = {'client_cert': ref_path, 'ca_cert': ref_ca_path,
  365. 'crl': ref_crl_path}
  366. mock_secret.side_effect = [ref_ca_name, ref_crl_name]
  367. result = self.driver._process_pool_certs(
  368. sample_listener, sample_listener.default_pool, self.amp,
  369. sample_listener.load_balancer.id)
  370. secret_calls = [
  371. mock.call(sample_listener,
  372. sample_listener.default_pool.ca_tls_certificate_id,
  373. self.amp, sample_listener.load_balancer.id),
  374. mock.call(sample_listener,
  375. sample_listener.default_pool.crl_container_id,
  376. self.amp, sample_listener.load_balancer.id)]
  377. mock_build_pem.assert_called_once_with(cert_data_mock)
  378. mock_upload_cert.assert_called_once_with(
  379. self.amp, sample_listener.load_balancer.id, pem=fake_pem,
  380. md5=ref_md5, name=ref_name)
  381. mock_secret.assert_has_calls(secret_calls)
  382. self.assertEqual(ref_result, result)
  383. def test_start(self):
  384. amp1 = mock.MagicMock()
  385. amp1.api_version = API_VERSION
  386. amp2 = mock.MagicMock()
  387. amp2.api_version = API_VERSION
  388. amp2.status = constants.DELETED
  389. loadbalancer = mock.MagicMock()
  390. loadbalancer.id = uuidutils.generate_uuid()
  391. loadbalancer.amphorae = [amp1, amp2]
  392. loadbalancer.vip = self.sv
  393. listener = mock.MagicMock()
  394. listener.id = uuidutils.generate_uuid()
  395. listener.protocol = constants.PROTOCOL_HTTP
  396. loadbalancer.listeners = [listener]
  397. listener.load_balancer = loadbalancer
  398. self.driver.clients[
  399. API_VERSION].start_listener.__name__ = 'start_listener'
  400. # Execute driver method
  401. self.driver.start(loadbalancer)
  402. self.driver.clients[
  403. API_VERSION].start_listener.assert_called_once_with(
  404. amp1, listener.id)
  405. def test_start_with_amphora(self):
  406. # Execute driver method
  407. amp = mock.MagicMock()
  408. self.driver.clients[
  409. API_VERSION].start_listener.__name__ = 'start_listener'
  410. self.driver.start(self.lb, self.amp)
  411. self.driver.clients[
  412. API_VERSION].start_listener.assert_called_once_with(
  413. self.amp, self.sl.id)
  414. self.driver.clients[API_VERSION].start_listener.reset_mock()
  415. amp.status = constants.DELETED
  416. self.driver.start(self.lb, amp)
  417. self.driver.clients[API_VERSION].start_listener.assert_not_called()
  418. def test_udp_start(self):
  419. self.driver.clients[
  420. API_VERSION].start_listener.__name__ = 'start_listener'
  421. # Execute driver method
  422. self.driver.start(self.lb_udp)
  423. self.driver.clients[
  424. API_VERSION].start_listener.assert_called_once_with(
  425. self.amp, self.sl_udp.id)
  426. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.'
  427. 'HaproxyAmphoraLoadBalancerDriver._process_secret')
  428. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  429. @mock.patch('octavia.common.tls_utils.cert_parser.get_host_names')
  430. def test_delete_second_listener(self, mock_cert, mock_load_crt,
  431. mock_secret):
  432. self.driver.clients[
  433. API_VERSION].delete_listener.__name__ = 'delete_listener'
  434. sl = sample_configs_split.sample_listener_tuple(
  435. tls=True, sni=True, client_ca_cert=True, client_crl_cert=True,
  436. recursive_nest=True)
  437. sl2 = sample_configs_split.sample_listener_tuple(
  438. id='sample_listener_id_2')
  439. sl.load_balancer.listeners.append(sl2)
  440. mock_cert.return_value = {'cn': sample_certs.X509_CERT_CN}
  441. mock_secret.side_effect = ['filename.pem', 'crl-filename.pem']
  442. sconts = []
  443. for sni_container in self.sl.sni_containers:
  444. sconts.append(sni_container.tls_container)
  445. mock_load_crt.side_effect = [{
  446. 'tls_cert': self.sl.default_tls_container, 'sni_certs': sconts},
  447. {'tls_cert': None, 'sni_certs': []}]
  448. self.driver.jinja_split.build_config.side_effect = ['fake_config']
  449. # Execute driver method
  450. self.driver.delete(sl)
  451. # Now just make sure we did a delete
  452. self.driver.clients[
  453. API_VERSION].delete_listener.assert_called_once_with(
  454. self.amp, self.sl.id)
  455. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  456. def test_delete_last_listener(self, mock_load_crt):
  457. self.driver.clients[
  458. API_VERSION].delete_listener.__name__ = 'delete_listener'
  459. sl = sample_configs_split.sample_listener_tuple(
  460. tls=True, sni=True, client_ca_cert=True, client_crl_cert=True,
  461. recursive_nest=True)
  462. mock_load_crt.side_effect = [{
  463. 'tls_cert': sl.default_tls_container, 'sni_certs': None}]
  464. # Execute driver method
  465. self.driver.delete(sl)
  466. self.driver.clients[
  467. API_VERSION].delete_listener.assert_called_once_with(
  468. self.amp, sl.id)
  469. def test_udp_delete(self):
  470. self.driver.clients[
  471. API_VERSION].delete_listener.__name__ = 'delete_listener'
  472. # Execute driver method
  473. self.driver.delete(self.sl_udp)
  474. self.driver.clients[
  475. API_VERSION].delete_listener.assert_called_once_with(
  476. self.amp, self.sl_udp.id)
  477. def test_get_info(self):
  478. expected_info = {'haproxy_version': '1.6.3-1ubuntu0.1',
  479. 'api_version': API_VERSION}
  480. result = self.driver.get_info(self.amp)
  481. self.assertEqual(expected_info, result)
  482. def test_get_diagnostics(self):
  483. # TODO(johnsom) Implement once this exists on the amphora agent.
  484. result = self.driver.get_diagnostics(self.amp)
  485. self.assertIsNone(result)
  486. def test_finalize_amphora(self):
  487. # TODO(johnsom) Implement once this exists on the amphora agent.
  488. result = self.driver.finalize_amphora(self.amp)
  489. self.assertIsNone(result)
  490. def test_post_vip_plug(self):
  491. amphorae_network_config = mock.MagicMock()
  492. amphorae_network_config.get().vip_subnet.cidr = FAKE_CIDR
  493. amphorae_network_config.get().vip_subnet.gateway_ip = FAKE_GATEWAY
  494. amphorae_network_config.get().vip_subnet.host_routes = self.host_routes
  495. amphorae_network_config.get().vrrp_port = self.port
  496. self.driver.post_vip_plug(self.amp, self.lb, amphorae_network_config)
  497. self.driver.clients[API_VERSION].plug_vip.assert_called_once_with(
  498. self.amp, self.lb.vip.ip_address, self.subnet_info)
  499. def test_post_network_plug(self):
  500. # Test dhcp path
  501. port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
  502. fixed_ips=[],
  503. network=self.network)
  504. self.driver.post_network_plug(self.amp, port)
  505. self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
  506. self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
  507. fixed_ips=[],
  508. mtu=FAKE_MTU))
  509. self.driver.clients[API_VERSION].plug_network.reset_mock()
  510. # Test fixed IP path
  511. self.driver.post_network_plug(self.amp, self.port)
  512. self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
  513. self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
  514. fixed_ips=[dict(ip_address='198.51.100.5',
  515. subnet_cidr='198.51.100.0/24',
  516. host_routes=[])],
  517. mtu=FAKE_MTU))
  518. def test_post_network_plug_with_host_routes(self):
  519. SUBNET_ID = 'SUBNET_ID'
  520. FIXED_IP1 = '192.0.2.2'
  521. FIXED_IP2 = '192.0.2.3'
  522. SUBNET_CIDR = '192.0.2.0/24'
  523. DEST1 = '198.51.100.0/24'
  524. DEST2 = '203.0.113.0/24'
  525. NEXTHOP = '192.0.2.1'
  526. host_routes = [network_models.HostRoute(destination=DEST1,
  527. nexthop=NEXTHOP),
  528. network_models.HostRoute(destination=DEST2,
  529. nexthop=NEXTHOP)]
  530. subnet = network_models.Subnet(id=SUBNET_ID, cidr=SUBNET_CIDR,
  531. ip_version=4, host_routes=host_routes)
  532. fixed_ips = [
  533. network_models.FixedIP(subnet_id=subnet.id, ip_address=FIXED_IP1,
  534. subnet=subnet),
  535. network_models.FixedIP(subnet_id=subnet.id, ip_address=FIXED_IP2,
  536. subnet=subnet)
  537. ]
  538. port = network_models.Port(mac_address=FAKE_MAC_ADDRESS,
  539. fixed_ips=fixed_ips,
  540. network=self.network)
  541. self.driver.post_network_plug(self.amp, port)
  542. expected_fixed_ips = [
  543. {'ip_address': FIXED_IP1, 'subnet_cidr': SUBNET_CIDR,
  544. 'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
  545. {'destination': DEST2, 'nexthop': NEXTHOP}]},
  546. {'ip_address': FIXED_IP2, 'subnet_cidr': SUBNET_CIDR,
  547. 'host_routes': [{'destination': DEST1, 'nexthop': NEXTHOP},
  548. {'destination': DEST2, 'nexthop': NEXTHOP}]}
  549. ]
  550. self.driver.clients[API_VERSION].plug_network.assert_called_once_with(
  551. self.amp, dict(mac_address=FAKE_MAC_ADDRESS,
  552. fixed_ips=expected_fixed_ips,
  553. mtu=FAKE_MTU))
  554. def test_get_vrrp_interface(self):
  555. self.driver.get_vrrp_interface(self.amp)
  556. self.driver.clients[API_VERSION].get_interface.assert_called_once_with(
  557. self.amp, self.amp.vrrp_ip, timeout_dict=None)
  558. def test_get_haproxy_versions(self):
  559. ref_haproxy_versions = ['1', '6']
  560. result = self.driver._get_haproxy_versions(self.amp)
  561. self.driver.clients[API_VERSION].get_info.assert_called_once_with(
  562. self.amp)
  563. self.assertEqual(ref_haproxy_versions, result)
  564. def test_populate_amphora_api_version(self):
  565. # Normal path, populate the version
  566. # clear out any previous values
  567. ref_haproxy_version = list(map(int, API_VERSION.split('.')))
  568. mock_amp = mock.MagicMock()
  569. mock_amp.api_version = None
  570. result = self.driver._populate_amphora_api_version(mock_amp)
  571. self.assertEqual(API_VERSION, mock_amp.api_version)
  572. self.assertEqual(ref_haproxy_version, result)
  573. # Existing version passed in
  574. fake_version = '9999.9999'
  575. ref_haproxy_version = list(map(int, fake_version.split('.')))
  576. mock_amp = mock.MagicMock()
  577. mock_amp.api_version = fake_version
  578. result = self.driver._populate_amphora_api_version(mock_amp)
  579. self.assertEqual(fake_version, mock_amp.api_version)
  580. self.assertEqual(ref_haproxy_version, result)
  581. def test_update_amphora_agent_config(self):
  582. self.driver.update_amphora_agent_config(self.amp, six.b('test'))
  583. self.driver.clients[
  584. API_VERSION].update_agent_config.assert_called_once_with(
  585. self.amp, six.b('test'), timeout_dict=None)
  586. class TestAmphoraAPIClientTest(base.TestCase):
  587. def setUp(self):
  588. super(TestAmphoraAPIClientTest, self).setUp()
  589. self.driver = driver.AmphoraAPIClient0_5()
  590. self.base_url = "https://192.0.2.77:9443/"
  591. self.base_url_ver = self.base_url + API_VERSION
  592. self.amp = models.Amphora(lb_network_ip='192.0.2.77', compute_id='123')
  593. self.amp.api_version = API_VERSION
  594. self.port_info = dict(mac_address=FAKE_MAC_ADDRESS)
  595. # Override with much lower values for testing purposes..
  596. conf = oslo_fixture.Config(cfg.CONF)
  597. conf.config(group="haproxy_amphora", connection_max_retries=2)
  598. self.subnet_info = {'subnet_cidr': FAKE_CIDR,
  599. 'gateway': FAKE_GATEWAY,
  600. 'mac_address': FAKE_MAC_ADDRESS,
  601. 'vrrp_ip': self.amp.vrrp_ip}
  602. patcher = mock.patch('time.sleep').start()
  603. self.addCleanup(patcher.stop)
  604. self.timeout_dict = {constants.REQ_CONN_TIMEOUT: 1,
  605. constants.REQ_READ_TIMEOUT: 2,
  606. constants.CONN_MAX_RETRIES: 3,
  607. constants.CONN_RETRY_INTERVAL: 4}
  608. def test_base_url(self):
  609. url = self.driver._base_url(FAKE_IP)
  610. self.assertEqual('https://192.0.2.10:9443/', url)
  611. url = self.driver._base_url(FAKE_IPV6, self.amp.api_version)
  612. self.assertEqual('https://[2001:db8::cafe]:9443/0.5/', url)
  613. url = self.driver._base_url(FAKE_IPV6_LLA, self.amp.api_version)
  614. self.assertEqual('https://[fe80::00ff:fe00:cafe%o-hm0]:9443/0.5/', url)
  615. @mock.patch('requests.Session.get', side_effect=requests.ConnectionError)
  616. @mock.patch('octavia.amphorae.drivers.haproxy.rest_api_driver.time.sleep')
  617. def test_request(self, mock_sleep, mock_get):
  618. self.assertRaises(driver_except.TimeOutException,
  619. self.driver.request, 'get', self.amp,
  620. 'unavailableURL', self.timeout_dict)
  621. @requests_mock.mock()
  622. def test_get_api_version(self, mock_requests):
  623. ref_api_version = {'api_version': '0.1'}
  624. mock_requests.get('{base}/'.format(base=self.base_url),
  625. json=ref_api_version)
  626. result = self.driver.get_api_version(self.amp)
  627. self.assertEqual(ref_api_version, result)
  628. @requests_mock.mock()
  629. def test_get_api_version_not_found(self, mock_requests):
  630. mock_requests.get('{base}/'.format(base=self.base_url),
  631. status_code=404)
  632. self.assertRaises(exc.NotFound, self.driver.get_api_version, self.amp)
  633. @requests_mock.mock()
  634. def test_get_info(self, m):
  635. info = {"hostname": "some_hostname", "version": "some_version",
  636. "api_version": "0.5", "uuid": FAKE_UUID_1}
  637. m.get("{base}/info".format(base=self.base_url_ver),
  638. json=info)
  639. information = self.driver.get_info(self.amp)
  640. self.assertEqual(info, information)
  641. @requests_mock.mock()
  642. def test_get_info_unauthorized(self, m):
  643. m.get("{base}/info".format(base=self.base_url_ver),
  644. status_code=401)
  645. self.assertRaises(exc.Unauthorized, self.driver.get_info, self.amp)
  646. @requests_mock.mock()
  647. def test_get_info_missing(self, m):
  648. m.get("{base}/info".format(base=self.base_url_ver),
  649. status_code=404,
  650. headers={'content-type': 'application/json'})
  651. self.assertRaises(exc.NotFound, self.driver.get_info, self.amp)
  652. @requests_mock.mock()
  653. def test_get_info_server_error(self, m):
  654. m.get("{base}/info".format(base=self.base_url_ver),
  655. status_code=500)
  656. self.assertRaises(exc.InternalServerError, self.driver.get_info,
  657. self.amp)
  658. @requests_mock.mock()
  659. def test_get_info_service_unavailable(self, m):
  660. m.get("{base}/info".format(base=self.base_url_ver),
  661. status_code=503)
  662. self.assertRaises(exc.ServiceUnavailable, self.driver.get_info,
  663. self.amp)
  664. @requests_mock.mock()
  665. def test_get_details(self, m):
  666. details = {"hostname": "some_hostname", "version": "some_version",
  667. "api_version": "0.5", "uuid": FAKE_UUID_1,
  668. "network_tx": "some_tx", "network_rx": "some_rx",
  669. "active": True, "haproxy_count": 10}
  670. m.get("{base}/details".format(base=self.base_url_ver),
  671. json=details)
  672. amp_details = self.driver.get_details(self.amp)
  673. self.assertEqual(details, amp_details)
  674. @requests_mock.mock()
  675. def test_get_details_unauthorized(self, m):
  676. m.get("{base}/details".format(base=self.base_url_ver),
  677. status_code=401)
  678. self.assertRaises(exc.Unauthorized, self.driver.get_details, self.amp)
  679. @requests_mock.mock()
  680. def test_get_details_missing(self, m):
  681. m.get("{base}/details".format(base=self.base_url_ver),
  682. status_code=404,
  683. headers={'content-type': 'application/json'})
  684. self.assertRaises(exc.NotFound, self.driver.get_details, self.amp)
  685. @requests_mock.mock()
  686. def test_get_details_server_error(self, m):
  687. m.get("{base}/details".format(base=self.base_url_ver),
  688. status_code=500)
  689. self.assertRaises(exc.InternalServerError, self.driver.get_details,
  690. self.amp)
  691. @requests_mock.mock()
  692. def test_get_details_service_unavailable(self, m):
  693. m.get("{base}/details".format(base=self.base_url_ver),
  694. status_code=503)
  695. self.assertRaises(exc.ServiceUnavailable, self.driver.get_details,
  696. self.amp)
  697. @requests_mock.mock()
  698. def test_get_all_listeners(self, m):
  699. listeners = [{"status": "ONLINE", "provisioning_status": "ACTIVE",
  700. "type": "PASSIVE", "uuid": FAKE_UUID_1}]
  701. m.get("{base}/listeners".format(base=self.base_url_ver),
  702. json=listeners)
  703. all_listeners = self.driver.get_all_listeners(self.amp)
  704. self.assertEqual(listeners, all_listeners)
  705. @requests_mock.mock()
  706. def test_get_all_listeners_unauthorized(self, m):
  707. m.get("{base}/listeners".format(base=self.base_url_ver),
  708. status_code=401)
  709. self.assertRaises(exc.Unauthorized, self.driver.get_all_listeners,
  710. self.amp)
  711. @requests_mock.mock()
  712. def test_get_all_listeners_missing(self, m):
  713. m.get("{base}/listeners".format(base=self.base_url_ver),
  714. status_code=404,
  715. headers={'content-type': 'application/json'})
  716. self.assertRaises(exc.NotFound, self.driver.get_all_listeners,
  717. self.amp)
  718. @requests_mock.mock()
  719. def test_get_all_listeners_server_error(self, m):
  720. m.get("{base}/listeners".format(base=self.base_url_ver),
  721. status_code=500)
  722. self.assertRaises(exc.InternalServerError,
  723. self.driver.get_all_listeners, self.amp)
  724. @requests_mock.mock()
  725. def test_get_all_listeners_service_unavailable(self, m):
  726. m.get("{base}/listeners".format(base=self.base_url_ver),
  727. status_code=503)
  728. self.assertRaises(exc.ServiceUnavailable,
  729. self.driver.get_all_listeners, self.amp)
  730. @requests_mock.mock()
  731. def test_start_listener(self, m):
  732. m.put("{base}/listeners/{listener_id}/start".format(
  733. base=self.base_url_ver, listener_id=FAKE_UUID_1))
  734. self.driver.start_listener(self.amp, FAKE_UUID_1)
  735. self.assertTrue(m.called)
  736. @requests_mock.mock()
  737. def test_start_listener_missing(self, m):
  738. m.put("{base}/listeners/{listener_id}/start".format(
  739. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  740. status_code=404,
  741. headers={'content-type': 'application/json'})
  742. self.assertRaises(exc.NotFound, self.driver.start_listener,
  743. self.amp, FAKE_UUID_1)
  744. @requests_mock.mock()
  745. def test_start_listener_unauthorized(self, m):
  746. m.put("{base}/listeners/{listener_id}/start".format(
  747. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  748. status_code=401)
  749. self.assertRaises(exc.Unauthorized, self.driver.start_listener,
  750. self.amp, FAKE_UUID_1)
  751. @requests_mock.mock()
  752. def test_start_listener_server_error(self, m):
  753. m.put("{base}/listeners/{listener_id}/start".format(
  754. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  755. status_code=500)
  756. self.assertRaises(exc.InternalServerError, self.driver.start_listener,
  757. self.amp, FAKE_UUID_1)
  758. @requests_mock.mock()
  759. def test_start_listener_service_unavailable(self, m):
  760. m.put("{base}/listeners/{listener_id}/start".format(
  761. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  762. status_code=503)
  763. self.assertRaises(exc.ServiceUnavailable, self.driver.start_listener,
  764. self.amp, FAKE_UUID_1)
  765. @requests_mock.mock()
  766. def test_delete_listener(self, m):
  767. m.delete("{base}/listeners/{listener_id}".format(
  768. base=self.base_url_ver, listener_id=FAKE_UUID_1), json={})
  769. self.driver.delete_listener(self.amp, FAKE_UUID_1)
  770. self.assertTrue(m.called)
  771. @requests_mock.mock()
  772. def test_delete_listener_missing(self, m):
  773. m.delete("{base}/listeners/{listener_id}".format(
  774. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  775. status_code=404,
  776. headers={'content-type': 'application/json'})
  777. self.driver.delete_listener(self.amp, FAKE_UUID_1)
  778. self.assertTrue(m.called)
  779. @requests_mock.mock()
  780. def test_delete_listener_unauthorized(self, m):
  781. m.delete("{base}/listeners/{listener_id}".format(
  782. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  783. status_code=401)
  784. self.assertRaises(exc.Unauthorized, self.driver.delete_listener,
  785. self.amp, FAKE_UUID_1)
  786. @requests_mock.mock()
  787. def test_delete_listener_server_error(self, m):
  788. m.delete("{base}/listeners/{listener_id}".format(
  789. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  790. status_code=500)
  791. self.assertRaises(exc.InternalServerError, self.driver.delete_listener,
  792. self.amp, FAKE_UUID_1)
  793. @requests_mock.mock()
  794. def test_delete_listener_service_unavailable(self, m):
  795. m.delete("{base}/listeners/{listener_id}".format(
  796. base=self.base_url_ver, listener_id=FAKE_UUID_1),
  797. status_code=503)
  798. self.assertRaises(exc.ServiceUnavailable, self.driver.delete_listener,
  799. self.amp, FAKE_UUID_1)
  800. @requests_mock.mock()
  801. def test_upload_cert_pem(self, m):
  802. m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
  803. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  804. filename=FAKE_PEM_FILENAME))
  805. self.driver.upload_cert_pem(self.amp, FAKE_UUID_1,
  806. FAKE_PEM_FILENAME,
  807. "some_file")
  808. self.assertTrue(m.called)
  809. @requests_mock.mock()
  810. def test_upload_invalid_cert_pem(self, m):
  811. m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
  812. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  813. filename=FAKE_PEM_FILENAME), status_code=400)
  814. self.assertRaises(exc.InvalidRequest, self.driver.upload_cert_pem,
  815. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
  816. "some_file")
  817. @requests_mock.mock()
  818. def test_upload_cert_pem_unauthorized(self, m):
  819. m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
  820. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  821. filename=FAKE_PEM_FILENAME), status_code=401)
  822. self.assertRaises(exc.Unauthorized, self.driver.upload_cert_pem,
  823. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
  824. "some_file")
  825. @requests_mock.mock()
  826. def test_upload_cert_pem_server_error(self, m):
  827. m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
  828. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  829. filename=FAKE_PEM_FILENAME), status_code=500)
  830. self.assertRaises(exc.InternalServerError, self.driver.upload_cert_pem,
  831. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
  832. "some_file")
  833. @requests_mock.mock()
  834. def test_upload_cert_pem_service_unavailable(self, m):
  835. m.put("{base}/listeners/{listener_id}/certificates/{filename}".format(
  836. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  837. filename=FAKE_PEM_FILENAME), status_code=503)
  838. self.assertRaises(exc.ServiceUnavailable, self.driver.upload_cert_pem,
  839. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME,
  840. "some_file")
  841. @requests_mock.mock()
  842. def test_update_cert_for_rotation(self, m):
  843. m.put("{base}/certificate".format(base=self.base_url_ver))
  844. resp_body = self.driver.update_cert_for_rotation(self.amp,
  845. "some_file")
  846. self.assertEqual(200, resp_body.status_code)
  847. @requests_mock.mock()
  848. def test_update_invalid_cert_for_rotation(self, m):
  849. m.put("{base}/certificate".format(base=self.base_url_ver),
  850. status_code=400)
  851. self.assertRaises(exc.InvalidRequest,
  852. self.driver.update_cert_for_rotation, self.amp,
  853. "some_file")
  854. @requests_mock.mock()
  855. def test_update_cert_for_rotation_unauthorized(self, m):
  856. m.put("{base}/certificate".format(base=self.base_url_ver),
  857. status_code=401)
  858. self.assertRaises(exc.Unauthorized,
  859. self.driver.update_cert_for_rotation, self.amp,
  860. "some_file")
  861. @requests_mock.mock()
  862. def test_update_cert_for_rotation_error(self, m):
  863. m.put("{base}/certificate".format(base=self.base_url_ver),
  864. status_code=500)
  865. self.assertRaises(exc.InternalServerError,
  866. self.driver.update_cert_for_rotation, self.amp,
  867. "some_file")
  868. @requests_mock.mock()
  869. def test_update_cert_for_rotation_unavailable(self, m):
  870. m.put("{base}/certificate".format(base=self.base_url_ver),
  871. status_code=503)
  872. self.assertRaises(exc.ServiceUnavailable,
  873. self.driver.update_cert_for_rotation, self.amp,
  874. "some_file")
  875. @requests_mock.mock()
  876. def test_get_cert_5sum(self, m):
  877. md5sum = {"md5sum": "some_real_sum"}
  878. m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
  879. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  880. filename=FAKE_PEM_FILENAME), json=md5sum)
  881. sum_test = self.driver.get_cert_md5sum(self.amp, FAKE_UUID_1,
  882. FAKE_PEM_FILENAME)
  883. self.assertIsNotNone(sum_test)
  884. @requests_mock.mock()
  885. def test_get_cert_5sum_missing(self, m):
  886. m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
  887. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  888. filename=FAKE_PEM_FILENAME), status_code=404,
  889. headers={'content-type': 'application/json'})
  890. self.assertRaises(exc.NotFound, self.driver.get_cert_md5sum,
  891. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  892. @requests_mock.mock()
  893. def test_get_cert_5sum_unauthorized(self, m):
  894. m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
  895. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  896. filename=FAKE_PEM_FILENAME), status_code=401)
  897. self.assertRaises(exc.Unauthorized, self.driver.get_cert_md5sum,
  898. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  899. @requests_mock.mock()
  900. def test_get_cert_5sum_server_error(self, m):
  901. m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
  902. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  903. filename=FAKE_PEM_FILENAME), status_code=500)
  904. self.assertRaises(exc.InternalServerError, self.driver.get_cert_md5sum,
  905. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  906. @requests_mock.mock()
  907. def test_get_cert_5sum_service_unavailable(self, m):
  908. m.get("{base}/listeners/{listener_id}/certificates/{filename}".format(
  909. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  910. filename=FAKE_PEM_FILENAME), status_code=503)
  911. self.assertRaises(exc.ServiceUnavailable, self.driver.get_cert_md5sum,
  912. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  913. @requests_mock.mock()
  914. def test_delete_cert_pem(self, m):
  915. m.delete(
  916. "{base}/listeners/{listener_id}/certificates/{filename}".format(
  917. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  918. filename=FAKE_PEM_FILENAME))
  919. self.driver.delete_cert_pem(self.amp, FAKE_UUID_1,
  920. FAKE_PEM_FILENAME)
  921. self.assertTrue(m.called)
  922. @requests_mock.mock()
  923. def test_delete_cert_pem_missing(self, m):
  924. m.delete(
  925. "{base}/listeners/{listener_id}/certificates/{filename}".format(
  926. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  927. filename=FAKE_PEM_FILENAME), status_code=404,
  928. headers={'content-type': 'application/json'})
  929. self.driver.delete_cert_pem(self.amp, FAKE_UUID_1,
  930. FAKE_PEM_FILENAME)
  931. self.assertTrue(m.called)
  932. @requests_mock.mock()
  933. def test_delete_cert_pem_unauthorized(self, m):
  934. m.delete(
  935. "{base}/listeners/{listener_id}/certificates/{filename}".format(
  936. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  937. filename=FAKE_PEM_FILENAME), status_code=401)
  938. self.assertRaises(exc.Unauthorized, self.driver.delete_cert_pem,
  939. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  940. @requests_mock.mock()
  941. def test_delete_cert_pem_server_error(self, m):
  942. m.delete(
  943. "{base}/listeners/{listener_id}/certificates/{filename}".format(
  944. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  945. filename=FAKE_PEM_FILENAME), status_code=500)
  946. self.assertRaises(exc.InternalServerError, self.driver.delete_cert_pem,
  947. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  948. @requests_mock.mock()
  949. def test_delete_cert_pem_service_unavailable(self, m):
  950. m.delete(
  951. "{base}/listeners/{listener_id}/certificates/{filename}".format(
  952. base=self.base_url_ver, listener_id=FAKE_UUID_1,
  953. filename=FAKE_PEM_FILENAME), status_code=503)
  954. self.assertRaises(exc.ServiceUnavailable, self.driver.delete_cert_pem,
  955. self.amp, FAKE_UUID_1, FAKE_PEM_FILENAME)
  956. @requests_mock.mock()
  957. def test_upload_config(self, m):
  958. config = {"name": "fake_config"}
  959. m.put(
  960. "{base}/listeners/{"
  961. "amphora_id}/{listener_id}/haproxy".format(
  962. amphora_id=self.amp.id, base=self.base_url_ver,
  963. listener_id=FAKE_UUID_1),
  964. json=config)
  965. self.driver.upload_config(self.amp, FAKE_UUID_1,
  966. config)
  967. self.assertTrue(m.called)
  968. @requests_mock.mock()
  969. def test_upload_invalid_config(self, m):
  970. config = '{"name": "bad_config"}'
  971. m.put(
  972. "{base}/listeners/{"
  973. "amphora_id}/{listener_id}/haproxy".format(
  974. amphora_id=self.amp.id, base=self.base_url_ver,
  975. listener_id=FAKE_UUID_1),
  976. status_code=400)
  977. self.assertRaises(exc.InvalidRequest, self.driver.upload_config,
  978. self.amp, FAKE_UUID_1, config)
  979. @requests_mock.mock()
  980. def test_upload_config_unauthorized(self, m):
  981. config = '{"name": "bad_config"}'
  982. m.put(
  983. "{base}/listeners/{"
  984. "amphora_id}/{listener_id}/haproxy".format(
  985. amphora_id=self.amp.id, base=self.base_url_ver,
  986. listener_id=FAKE_UUID_1),
  987. status_code=401)
  988. self.assertRaises(exc.Unauthorized, self.driver.upload_config,
  989. self.amp, FAKE_UUID_1, config)
  990. @requests_mock.mock()
  991. def test_upload_config_server_error(self, m):
  992. config = '{"name": "bad_config"}'
  993. m.put(
  994. "{base}/listeners/{"
  995. "amphora_id}/{listener_id}/haproxy".format(
  996. amphora_id=self.amp.id, base=self.base_url_ver,
  997. listener_id=FAKE_UUID_1),
  998. status_code=500)
  999. self.assertRaises(exc.InternalServerError, self.driver.upload_config,
  1000. self.amp, FAKE_UUID_1, config)
  1001. @requests_mock.mock()
  1002. def test_upload_config_service_unavailable(self, m):
  1003. config = '{"name": "bad_config"}'
  1004. m.put(
  1005. "{base}/listeners/{"
  1006. "amphora_id}/{listener_id}/haproxy".format(
  1007. amphora_id=self.amp.id, base=self.base_url_ver,
  1008. listener_id=FAKE_UUID_1),
  1009. status_code=503)
  1010. self.assertRaises(exc.ServiceUnavailable, self.driver.upload_config,
  1011. self.amp, FAKE_UUID_1, config)
  1012. @requests_mock.mock()
  1013. def test_upload_udp_config(self, m):
  1014. config = {"name": "fake_config"}
  1015. m.put(
  1016. "{base}/listeners/"
  1017. "{amphora_id}/{listener_id}/udp_listener".format(
  1018. amphora_id=self.amp.id, base=self.base_url_ver,
  1019. listener_id=FAKE_UUID_1),
  1020. json=config)
  1021. self.driver.upload_udp_config(self.amp, FAKE_UUID_1, config)
  1022. self.assertTrue(m.called)
  1023. @requests_mock.mock()
  1024. def test_upload_udp_invalid_config(self, m):
  1025. config = '{"name": "bad_config"}'
  1026. m.put(
  1027. "{base}/listeners/"
  1028. "{amphora_id}/{listener_id}/udp_listener".format(
  1029. amphora_id=self.amp.id, base=self.base_url_ver,
  1030. listener_id=FAKE_UUID_1),
  1031. status_code=400)
  1032. self.assertRaises(exc.InvalidRequest, self.driver.upload_udp_config,
  1033. self.amp, FAKE_UUID_1, config)
  1034. @requests_mock.mock()
  1035. def test_upload_udp_config_unauthorized(self, m):
  1036. config = '{"name": "bad_config"}'
  1037. m.put(
  1038. "{base}/listeners/"
  1039. "{amphora_id}/{listener_id}/udp_listener".format(
  1040. amphora_id=self.amp.id, base=self.base_url_ver,
  1041. listener_id=FAKE_UUID_1),
  1042. status_code=401)
  1043. self.assertRaises(exc.Unauthorized, self.driver.upload_udp_config,
  1044. self.amp, FAKE_UUID_1, config)
  1045. @requests_mock.mock()
  1046. def test_upload_udp_config_server_error(self, m):
  1047. config = '{"name": "bad_config"}'
  1048. m.put(
  1049. "{base}/listeners/"
  1050. "{amphora_id}/{listener_id}/udp_listener".format(
  1051. amphora_id=self.amp.id, base=self.base_url_ver,
  1052. listener_id=FAKE_UUID_1),
  1053. status_code=500)
  1054. self.assertRaises(exc.InternalServerError,
  1055. self.driver.upload_udp_config,
  1056. self.amp, FAKE_UUID_1, config)
  1057. @requests_mock.mock()
  1058. def test_upload_udp_config_service_unavailable(self, m):
  1059. config = '{"name": "bad_config"}'
  1060. m.put(
  1061. "{base}/listeners/"
  1062. "{amphora_id}/{listener_id}/udp_listener".format(
  1063. amphora_id=self.amp.id, base=self.base_url_ver,
  1064. listener_id=FAKE_UUID_1),
  1065. status_code=503)
  1066. self.assertRaises(exc.ServiceUnavailable,
  1067. self.driver.upload_udp_config,
  1068. self.amp, FAKE_UUID_1, config)
  1069. @requests_mock.mock()
  1070. def test_plug_vip(self, m):
  1071. m.post("{base}/plug/vip/{vip}".format(
  1072. base=self.base_url_ver, vip=FAKE_IP)
  1073. )
  1074. self.driver.plug_vip(self.amp, FAKE_IP, self.subnet_info)
  1075. self.assertTrue(m.called)
  1076. @requests_mock.mock()
  1077. def test_plug_vip_api_not_ready(self, m):
  1078. m.post("{base}/plug/vip/{vip}".format(
  1079. base=self.base_url_ver, vip=FAKE_IP),
  1080. status_code=404, headers={'content-type': 'text/html'}
  1081. )
  1082. self.assertRaises(driver_except.TimeOutException,
  1083. self.driver.plug_vip,
  1084. self.amp, FAKE_IP, self.subnet_info)
  1085. self.assertTrue(m.called)
  1086. @requests_mock.mock()
  1087. def test_plug_network(self, m):
  1088. m.post("{base}/plug/network".format(
  1089. base=self.base_url_ver)
  1090. )
  1091. self.driver.plug_network(self.amp, self.port_info)
  1092. self.assertTrue(m.called)
  1093. @requests_mock.mock()
  1094. def test_upload_vrrp_config(self, m):
  1095. config = '{"name": "bad_config"}'
  1096. m.put("{base}/vrrp/upload".format(
  1097. base=self.base_url_ver)
  1098. )
  1099. self.driver.upload_vrrp_config(self.amp, config)
  1100. self.assertTrue(m.called)
  1101. @requests_mock.mock()
  1102. def test_vrrp_action(self, m):
  1103. action = 'start'
  1104. m.put("{base}/vrrp/{action}".format(base=self.base_url_ver,
  1105. action=action))
  1106. self.driver._vrrp_action(action, self.amp)
  1107. self.assertTrue(m.called)
  1108. @requests_mock.mock()
  1109. def test_get_interface(self, m):
  1110. interface = [{"interface": "eth1"}]
  1111. ip_addr = '192.51.100.1'
  1112. m.get("{base}/interface/{ip_addr}".format(base=self.base_url_ver,
  1113. ip_addr=ip_addr),
  1114. json=interface)
  1115. self.driver.get_interface(self.amp, ip_addr)
  1116. self.assertTrue(m.called)
  1117. m.register_uri('GET',
  1118. self.base_url_ver + '/interface/' + ip_addr,
  1119. status_code=500, reason='FAIL', json='FAIL')
  1120. self.assertRaises(exc.InternalServerError,
  1121. self.driver.get_interface,
  1122. self.amp, ip_addr)
  1123. @requests_mock.mock()
  1124. def test_update_agent_config(self, m):
  1125. m.put("{base}/config".format(base=self.base_url_ver))
  1126. resp_body = self.driver.update_agent_config(self.amp, "some_file")
  1127. self.assertEqual(200, resp_body.status_code)
  1128. @requests_mock.mock()
  1129. def test_update_agent_config_error(self, m):
  1130. m.put("{base}/config".format(base=self.base_url_ver), status_code=500)
  1131. self.assertRaises(exc.InternalServerError,
  1132. self.driver.update_agent_config, self.amp,
  1133. "some_file")