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.

2375 lines
113KB

  1. # Copyright 2014 Rackspace
  2. # Copyright 2016 Blue Box, an IBM Company
  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 copy
  16. import random
  17. import mock
  18. from oslo_config import cfg
  19. from oslo_config import fixture as oslo_fixture
  20. from oslo_utils import uuidutils
  21. from octavia.common import constants
  22. import octavia.common.context
  23. from octavia.common import data_models
  24. from octavia.common import exceptions
  25. from octavia.db import api as db_api
  26. from octavia.tests.functional.api.v2 import base
  27. from octavia.tests.unit.common.sample_configs import sample_certs
  28. class TestListener(base.BaseAPITest):
  29. root_tag = 'listener'
  30. root_tag_list = 'listeners'
  31. root_tag_links = 'listeners_links'
  32. def setUp(self):
  33. super(TestListener, self).setUp()
  34. self.lb = self.create_load_balancer(uuidutils.generate_uuid())
  35. self.lb_id = self.lb.get('loadbalancer').get('id')
  36. self.project_id = self.lb.get('loadbalancer').get('project_id')
  37. self.set_lb_status(self.lb_id)
  38. self.listener_path = self.LISTENERS_PATH + '/{listener_id}'
  39. self.pool = self.create_pool(
  40. self.lb_id, constants.PROTOCOL_HTTP,
  41. constants.LB_ALGORITHM_ROUND_ROBIN)
  42. self.pool_id = self.pool.get('pool').get('id')
  43. self.set_lb_status(self.lb_id)
  44. def test_get_all_admin(self):
  45. project_id = uuidutils.generate_uuid()
  46. lb1 = self.create_load_balancer(uuidutils.generate_uuid(),
  47. name='lb1', project_id=project_id)
  48. lb1_id = lb1.get('loadbalancer').get('id')
  49. self.set_lb_status(lb1_id)
  50. listener1 = self.create_listener(
  51. constants.PROTOCOL_HTTP, 80, lb1_id,
  52. tags=['test_tag1']).get(self.root_tag)
  53. self.set_lb_status(lb1_id)
  54. listener2 = self.create_listener(
  55. constants.PROTOCOL_HTTP, 81, lb1_id,
  56. tags=['test_tag2']).get(self.root_tag)
  57. self.set_lb_status(lb1_id)
  58. listener3 = self.create_listener(
  59. constants.PROTOCOL_HTTP, 82, lb1_id,
  60. tags=['test_tag3']).get(self.root_tag)
  61. self.set_lb_status(lb1_id)
  62. listeners = self.get(self.LISTENERS_PATH).json.get(self.root_tag_list)
  63. self.assertEqual(3, len(listeners))
  64. listener_id_ports = [(l.get('id'), l.get('protocol_port'),
  65. l.get('tags'))
  66. for l in listeners]
  67. self.assertIn((listener1.get('id'), listener1.get('protocol_port'),
  68. listener1.get('tags')),
  69. listener_id_ports)
  70. self.assertIn((listener2.get('id'), listener2.get('protocol_port'),
  71. listener2.get('tags')),
  72. listener_id_ports)
  73. self.assertIn((listener3.get('id'), listener3.get('protocol_port'),
  74. listener3.get('tags')),
  75. listener_id_ports)
  76. def test_get_all_non_admin(self):
  77. project_id = uuidutils.generate_uuid()
  78. lb1 = self.create_load_balancer(uuidutils.generate_uuid(),
  79. name='lb1', project_id=project_id)
  80. lb1_id = lb1.get('loadbalancer').get('id')
  81. self.set_lb_status(lb1_id)
  82. self.create_listener(constants.PROTOCOL_HTTP, 80,
  83. lb1_id)
  84. self.set_lb_status(lb1_id)
  85. self.create_listener(constants.PROTOCOL_HTTP, 81,
  86. lb1_id)
  87. self.set_lb_status(lb1_id)
  88. listener3 = self.create_listener(constants.PROTOCOL_HTTP, 82,
  89. self.lb_id).get(self.root_tag)
  90. self.set_lb_status(self.lb_id)
  91. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  92. self.conf.config(group='api_settings',
  93. auth_strategy=constants.KEYSTONE)
  94. with mock.patch.object(octavia.common.context.Context, 'project_id',
  95. listener3['project_id']):
  96. override_credentials = {
  97. 'service_user_id': None,
  98. 'user_domain_id': None,
  99. 'is_admin_project': True,
  100. 'service_project_domain_id': None,
  101. 'service_project_id': None,
  102. 'roles': ['load-balancer_member'],
  103. 'user_id': None,
  104. 'is_admin': False,
  105. 'service_user_domain_id': None,
  106. 'project_domain_id': None,
  107. 'service_roles': [],
  108. 'project_id': self.project_id}
  109. with mock.patch(
  110. "oslo_context.context.RequestContext.to_policy_values",
  111. return_value=override_credentials):
  112. listeners = self.get(
  113. self.LISTENERS_PATH).json.get(self.root_tag_list)
  114. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  115. self.assertEqual(1, len(listeners))
  116. listener_id_ports = [(l.get('id'), l.get('protocol_port'))
  117. for l in listeners]
  118. self.assertIn((listener3.get('id'), listener3.get('protocol_port')),
  119. listener_id_ports)
  120. def test_get_all_non_admin_global_observer(self):
  121. project_id = uuidutils.generate_uuid()
  122. lb1 = self.create_load_balancer(uuidutils.generate_uuid(),
  123. name='lb1', project_id=project_id)
  124. lb1_id = lb1.get('loadbalancer').get('id')
  125. self.set_lb_status(lb1_id)
  126. listener1 = self.create_listener(
  127. constants.PROTOCOL_HTTP, 80, lb1_id).get(self.root_tag)
  128. self.set_lb_status(lb1_id)
  129. listener2 = self.create_listener(
  130. constants.PROTOCOL_HTTP, 81, lb1_id).get(self.root_tag)
  131. self.set_lb_status(lb1_id)
  132. listener3 = self.create_listener(
  133. constants.PROTOCOL_HTTP, 82, lb1_id).get(self.root_tag)
  134. self.set_lb_status(lb1_id)
  135. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  136. self.conf.config(group='api_settings',
  137. auth_strategy=constants.KEYSTONE)
  138. with mock.patch.object(octavia.common.context.Context, 'project_id',
  139. self.project_id):
  140. override_credentials = {
  141. 'service_user_id': None,
  142. 'user_domain_id': None,
  143. 'is_admin_project': True,
  144. 'service_project_domain_id': None,
  145. 'service_project_id': None,
  146. 'roles': ['load-balancer_global_observer'],
  147. 'user_id': None,
  148. 'is_admin': False,
  149. 'service_user_domain_id': None,
  150. 'project_domain_id': None,
  151. 'service_roles': [],
  152. 'project_id': self.project_id}
  153. with mock.patch(
  154. "oslo_context.context.RequestContext.to_policy_values",
  155. return_value=override_credentials):
  156. listeners = self.get(self.LISTENERS_PATH)
  157. listeners = listeners.json.get(self.root_tag_list)
  158. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  159. self.assertEqual(3, len(listeners))
  160. listener_id_ports = [(l.get('id'), l.get('protocol_port'))
  161. for l in listeners]
  162. self.assertIn((listener1.get('id'), listener1.get('protocol_port')),
  163. listener_id_ports)
  164. self.assertIn((listener2.get('id'), listener2.get('protocol_port')),
  165. listener_id_ports)
  166. self.assertIn((listener3.get('id'), listener3.get('protocol_port')),
  167. listener_id_ports)
  168. def test_get_all_not_authorized(self):
  169. project_id = uuidutils.generate_uuid()
  170. lb1 = self.create_load_balancer(uuidutils.generate_uuid(),
  171. name='lb1', project_id=project_id)
  172. lb1_id = lb1.get('loadbalancer').get('id')
  173. self.set_lb_status(lb1_id)
  174. self.create_listener(constants.PROTOCOL_HTTP, 80,
  175. lb1_id)
  176. self.set_lb_status(lb1_id)
  177. self.create_listener(constants.PROTOCOL_HTTP, 81,
  178. lb1_id)
  179. self.set_lb_status(lb1_id)
  180. self.create_listener(constants.PROTOCOL_HTTP, 82,
  181. self.lb_id).get(self.root_tag)
  182. self.set_lb_status(self.lb_id)
  183. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  184. self.conf.config(group='api_settings',
  185. auth_strategy=constants.KEYSTONE)
  186. with mock.patch.object(octavia.common.context.Context, 'project_id',
  187. uuidutils.generate_uuid()):
  188. listeners = self.get(self.LISTENERS_PATH, status=403).json
  189. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  190. self.assertEqual(self.NOT_AUTHORIZED_BODY, listeners)
  191. def test_get_all_by_project_id(self):
  192. project1_id = uuidutils.generate_uuid()
  193. project2_id = uuidutils.generate_uuid()
  194. lb1 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb1',
  195. project_id=project1_id)
  196. lb1_id = lb1.get('loadbalancer').get('id')
  197. self.set_lb_status(lb1_id)
  198. lb2 = self.create_load_balancer(uuidutils.generate_uuid(), name='lb2',
  199. project_id=project2_id)
  200. lb2_id = lb2.get('loadbalancer').get('id')
  201. self.set_lb_status(lb2_id)
  202. listener1 = self.create_listener(constants.PROTOCOL_HTTP, 80, lb1_id,
  203. name='listener1').get(self.root_tag)
  204. self.set_lb_status(lb1_id)
  205. listener2 = self.create_listener(constants.PROTOCOL_HTTP, 81, lb1_id,
  206. name='listener2').get(self.root_tag)
  207. self.set_lb_status(lb1_id)
  208. listener3 = self.create_listener(constants.PROTOCOL_HTTP, 82, lb2_id,
  209. name='listener3').get(self.root_tag)
  210. self.set_lb_status(lb2_id)
  211. listeners = self.get(
  212. self.LISTENERS_PATH,
  213. params={'project_id': project1_id}).json.get(self.root_tag_list)
  214. self.assertEqual(2, len(listeners))
  215. listener_id_ports = [(l.get('id'), l.get('protocol_port'))
  216. for l in listeners]
  217. self.assertIn((listener1.get('id'), listener1.get('protocol_port')),
  218. listener_id_ports)
  219. self.assertIn((listener2.get('id'), listener2.get('protocol_port')),
  220. listener_id_ports)
  221. listeners = self.get(
  222. self.LISTENERS_PATH,
  223. params={'project_id': project2_id}).json.get(self.root_tag_list)
  224. listener_id_ports = [(l.get('id'), l.get('protocol_port'))
  225. for l in listeners]
  226. self.assertEqual(1, len(listeners))
  227. self.assertIn((listener3.get('id'), listener3.get('protocol_port')),
  228. listener_id_ports)
  229. def test_get_all_sorted(self):
  230. self.create_listener(constants.PROTOCOL_HTTP, 80,
  231. self.lb_id,
  232. name='listener1')
  233. self.set_lb_status(self.lb_id)
  234. self.create_listener(constants.PROTOCOL_HTTP, 81,
  235. self.lb_id,
  236. name='listener2')
  237. self.set_lb_status(self.lb_id)
  238. self.create_listener(constants.PROTOCOL_HTTP, 82,
  239. self.lb_id,
  240. name='listener3')
  241. self.set_lb_status(self.lb_id)
  242. response = self.get(self.LISTENERS_PATH,
  243. params={'sort': 'name:desc'})
  244. listeners_desc = response.json.get(self.root_tag_list)
  245. response = self.get(self.LISTENERS_PATH,
  246. params={'sort': 'name:asc'})
  247. listeners_asc = response.json.get(self.root_tag_list)
  248. self.assertEqual(3, len(listeners_desc))
  249. self.assertEqual(3, len(listeners_asc))
  250. listener_id_names_desc = [(listener.get('id'), listener.get('name'))
  251. for listener in listeners_desc]
  252. listener_id_names_asc = [(listener.get('id'), listener.get('name'))
  253. for listener in listeners_asc]
  254. self.assertEqual(listener_id_names_asc,
  255. list(reversed(listener_id_names_desc)))
  256. def test_get_all_limited(self):
  257. self.create_listener(constants.PROTOCOL_HTTP, 80,
  258. self.lb_id,
  259. name='listener1')
  260. self.set_lb_status(self.lb_id)
  261. self.create_listener(constants.PROTOCOL_HTTP, 81,
  262. self.lb_id,
  263. name='listener2')
  264. self.set_lb_status(self.lb_id)
  265. self.create_listener(constants.PROTOCOL_HTTP, 82,
  266. self.lb_id,
  267. name='listener3')
  268. self.set_lb_status(self.lb_id)
  269. # First two -- should have 'next' link
  270. first_two = self.get(self.LISTENERS_PATH, params={'limit': 2}).json
  271. objs = first_two[self.root_tag_list]
  272. links = first_two[self.root_tag_links]
  273. self.assertEqual(2, len(objs))
  274. self.assertEqual(1, len(links))
  275. self.assertEqual('next', links[0]['rel'])
  276. # Third + off the end -- should have previous link
  277. third = self.get(self.LISTENERS_PATH, params={
  278. 'limit': 2,
  279. 'marker': first_two[self.root_tag_list][1]['id']}).json
  280. objs = third[self.root_tag_list]
  281. links = third[self.root_tag_links]
  282. self.assertEqual(1, len(objs))
  283. self.assertEqual(1, len(links))
  284. self.assertEqual('previous', links[0]['rel'])
  285. # Middle -- should have both links
  286. middle = self.get(self.LISTENERS_PATH, params={
  287. 'limit': 1,
  288. 'marker': first_two[self.root_tag_list][0]['id']}).json
  289. objs = middle[self.root_tag_list]
  290. links = middle[self.root_tag_links]
  291. self.assertEqual(1, len(objs))
  292. self.assertEqual(2, len(links))
  293. self.assertItemsEqual(['previous', 'next'], [l['rel'] for l in links])
  294. def test_get_all_fields_filter(self):
  295. self.create_listener(constants.PROTOCOL_HTTP, 80,
  296. self.lb_id,
  297. name='listener1')
  298. self.set_lb_status(self.lb_id)
  299. self.create_listener(constants.PROTOCOL_HTTP, 81,
  300. self.lb_id,
  301. name='listener2')
  302. self.set_lb_status(self.lb_id)
  303. self.create_listener(constants.PROTOCOL_HTTP, 82,
  304. self.lb_id,
  305. name='listener3')
  306. self.set_lb_status(self.lb_id)
  307. lis = self.get(self.LISTENERS_PATH, params={
  308. 'fields': ['id', 'project_id']}).json
  309. for li in lis['listeners']:
  310. self.assertIn(u'id', li)
  311. self.assertIn(u'project_id', li)
  312. self.assertNotIn(u'description', li)
  313. def test_get_one_fields_filter(self):
  314. listener1 = self.create_listener(
  315. constants.PROTOCOL_HTTP, 80, self.lb_id,
  316. name='listener1').get(self.root_tag)
  317. self.set_lb_status(self.lb_id)
  318. li = self.get(
  319. self.LISTENER_PATH.format(listener_id=listener1.get('id')),
  320. params={'fields': ['id', 'project_id']}).json.get(self.root_tag)
  321. self.assertIn(u'id', li)
  322. self.assertIn(u'project_id', li)
  323. self.assertNotIn(u'description', li)
  324. def test_get_all_filter(self):
  325. li1 = self.create_listener(constants.PROTOCOL_HTTP,
  326. 80,
  327. self.lb_id,
  328. name='listener1').get(self.root_tag)
  329. self.set_lb_status(self.lb_id)
  330. self.create_listener(constants.PROTOCOL_HTTP,
  331. 81,
  332. self.lb_id,
  333. name='listener2').get(self.root_tag)
  334. self.set_lb_status(self.lb_id)
  335. self.create_listener(constants.PROTOCOL_HTTP,
  336. 82,
  337. self.lb_id,
  338. name='listener3').get(self.root_tag)
  339. self.set_lb_status(self.lb_id)
  340. lis = self.get(self.LISTENERS_PATH, params={
  341. 'id': li1['id']}).json
  342. self.assertEqual(1, len(lis['listeners']))
  343. self.assertEqual(li1['id'],
  344. lis['listeners'][0]['id'])
  345. def test_get_all_tags_filter(self):
  346. listener1 = self.create_listener(
  347. constants.PROTOCOL_HTTP,
  348. 80,
  349. self.lb_id,
  350. name='listener1',
  351. tags=['test_tag1', 'test_tag2']
  352. ).get(self.root_tag)
  353. self.set_lb_status(self.lb_id)
  354. listener2 = self.create_listener(
  355. constants.PROTOCOL_HTTP,
  356. 81,
  357. self.lb_id,
  358. name='listener2',
  359. tags=['test_tag2', 'test_tag3']
  360. ).get(self.root_tag)
  361. self.set_lb_status(self.lb_id)
  362. listener3 = self.create_listener(
  363. constants.PROTOCOL_HTTP,
  364. 82,
  365. self.lb_id,
  366. name='listener3',
  367. tags=['test_tag4', 'test_tag5']
  368. ).get(self.root_tag)
  369. self.set_lb_status(self.lb_id)
  370. listeners = self.get(
  371. self.LISTENERS_PATH,
  372. params={'tags': 'test_tag2'}
  373. ).json.get(self.root_tag_list)
  374. self.assertIsInstance(listeners, list)
  375. self.assertEqual(2, len(listeners))
  376. self.assertEqual(
  377. [listener1.get('id'), listener2.get('id')],
  378. [listener.get('id') for listener in listeners]
  379. )
  380. listeners = self.get(
  381. self.LISTENERS_PATH,
  382. params={'tags': ['test_tag2', 'test_tag3']}
  383. ).json.get(self.root_tag_list)
  384. self.assertIsInstance(listeners, list)
  385. self.assertEqual(1, len(listeners))
  386. self.assertEqual(
  387. [listener2.get('id')],
  388. [listener.get('id') for listener in listeners]
  389. )
  390. listeners = self.get(
  391. self.LISTENERS_PATH,
  392. params={'tags-any': 'test_tag2'}
  393. ).json.get(self.root_tag_list)
  394. self.assertIsInstance(listeners, list)
  395. self.assertEqual(2, len(listeners))
  396. self.assertEqual(
  397. [listener1.get('id'), listener2.get('id')],
  398. [listener.get('id') for listener in listeners]
  399. )
  400. listeners = self.get(
  401. self.LISTENERS_PATH,
  402. params={'not-tags': 'test_tag2'}
  403. ).json.get(self.root_tag_list)
  404. self.assertIsInstance(listeners, list)
  405. self.assertEqual(1, len(listeners))
  406. self.assertEqual(
  407. [listener3.get('id')],
  408. [listener.get('id') for listener in listeners]
  409. )
  410. listeners = self.get(
  411. self.LISTENERS_PATH,
  412. params={'not-tags-any': ['test_tag2', 'test_tag4']}
  413. ).json.get(self.root_tag_list)
  414. self.assertIsInstance(listeners, list)
  415. self.assertEqual(0, len(listeners))
  416. listeners = self.get(
  417. self.LISTENERS_PATH,
  418. params={'tags': 'test_tag2',
  419. 'tags-any': ['test_tag1', 'test_tag3']}
  420. ).json.get(self.root_tag_list)
  421. self.assertIsInstance(listeners, list)
  422. self.assertEqual(2, len(listeners))
  423. self.assertEqual(
  424. [listener1.get('id'), listener2.get('id')],
  425. [listener.get('id') for listener in listeners]
  426. )
  427. listeners = self.get(
  428. self.LISTENERS_PATH,
  429. params={'tags': 'test_tag2', 'not-tags': 'test_tag2'}
  430. ).json.get(self.root_tag_list)
  431. self.assertIsInstance(listeners, list)
  432. self.assertEqual(0, len(listeners))
  433. def test_get_all_hides_deleted(self):
  434. api_listener = self.create_listener(
  435. constants.PROTOCOL_HTTP, 80, self.lb_id).get(self.root_tag)
  436. response = self.get(self.LISTENERS_PATH)
  437. objects = response.json.get(self.root_tag_list)
  438. self.assertEqual(len(objects), 1)
  439. self.set_object_status(self.listener_repo, api_listener.get('id'),
  440. provisioning_status=constants.DELETED)
  441. response = self.get(self.LISTENERS_PATH)
  442. objects = response.json.get(self.root_tag_list)
  443. self.assertEqual(len(objects), 0)
  444. def test_get(self):
  445. listener = self.create_listener(
  446. constants.PROTOCOL_HTTP, 80, self.lb_id).get(self.root_tag)
  447. response = self.get(self.listener_path.format(
  448. listener_id=listener['id']))
  449. api_listener = response.json.get(self.root_tag)
  450. self.assertEqual(listener, api_listener)
  451. self.assertEqual([], api_listener['tags'])
  452. def test_get_authorized(self):
  453. listener = self.create_listener(
  454. constants.PROTOCOL_HTTP, 80, self.lb_id).get(self.root_tag)
  455. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  456. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  457. self.conf.config(group='api_settings',
  458. auth_strategy=constants.TESTING)
  459. with mock.patch.object(octavia.common.context.Context, 'project_id',
  460. self.project_id):
  461. override_credentials = {
  462. 'service_user_id': None,
  463. 'user_domain_id': None,
  464. 'is_admin_project': True,
  465. 'service_project_domain_id': None,
  466. 'service_project_id': None,
  467. 'roles': ['load-balancer_member'],
  468. 'user_id': None,
  469. 'is_admin': False,
  470. 'service_user_domain_id': None,
  471. 'project_domain_id': None,
  472. 'service_roles': [],
  473. 'project_id': self.project_id}
  474. with mock.patch(
  475. "oslo_context.context.RequestContext.to_policy_values",
  476. return_value=override_credentials):
  477. response = self.get(self.listener_path.format(
  478. listener_id=listener['id']))
  479. api_listener = response.json.get(self.root_tag)
  480. self.assertEqual(listener, api_listener)
  481. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  482. def test_get_not_authorized(self):
  483. listener = self.create_listener(
  484. constants.PROTOCOL_HTTP, 80, self.lb_id).get(self.root_tag)
  485. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  486. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  487. self.conf.config(group='api_settings',
  488. auth_strategy=constants.TESTING)
  489. with mock.patch.object(octavia.common.context.Context, 'project_id',
  490. uuidutils.generate_uuid()):
  491. response = self.get(self.listener_path.format(
  492. listener_id=listener['id']), status=403)
  493. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  494. self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
  495. def test_get_deleted_gives_404(self):
  496. api_listener = self.create_listener(
  497. constants.PROTOCOL_HTTP, 80, self.lb_id).get(self.root_tag)
  498. self.set_object_status(self.listener_repo, api_listener.get('id'),
  499. provisioning_status=constants.DELETED)
  500. self.get(self.LISTENER_PATH.format(listener_id=api_listener.get('id')),
  501. status=404)
  502. def test_get_bad_listener_id(self):
  503. listener_path = self.listener_path
  504. self.get(listener_path.format(listener_id='SEAN-CONNERY'), status=404)
  505. # TODO(johnsom) Fix this when there is a noop certificate manager
  506. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  507. def test_create(self, mock_cert_data,
  508. response_status=201, **optionals):
  509. cert1 = data_models.TLSContainer(certificate='cert 1')
  510. cert2 = data_models.TLSContainer(certificate='cert 2')
  511. cert3 = data_models.TLSContainer(certificate='cert 3')
  512. mock_cert_data.return_value = {'tls_cert': cert1,
  513. 'sni_certs': [cert2, cert3]}
  514. sni1 = uuidutils.generate_uuid()
  515. sni2 = uuidutils.generate_uuid()
  516. lb_listener = {'name': 'listener1', 'default_pool_id': None,
  517. 'description': 'desc1',
  518. 'admin_state_up': False,
  519. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  520. 'protocol_port': 80, 'connection_limit': 10,
  521. 'default_tls_container_ref': uuidutils.generate_uuid(),
  522. 'sni_container_refs': [sni1, sni2],
  523. 'insert_headers': {},
  524. 'project_id': self.project_id,
  525. 'loadbalancer_id': self.lb_id,
  526. 'tags': ['test_tag']}
  527. lb_listener.update(optionals)
  528. body = self._build_body(lb_listener)
  529. response = self.post(self.LISTENERS_PATH, body, status=response_status)
  530. if response_status >= 300:
  531. return response
  532. listener_api = response.json['listener']
  533. extra_expects = {'provisioning_status': constants.PENDING_CREATE,
  534. 'operating_status': constants.OFFLINE}
  535. lb_listener.update(extra_expects)
  536. self.assertTrue(uuidutils.is_uuid_like(listener_api.get('id')))
  537. for key, value in optionals.items():
  538. self.assertEqual(value, lb_listener.get(key))
  539. lb_listener['id'] = listener_api.get('id')
  540. lb_listener.pop('sni_container_refs')
  541. sni_ex = [sni1, sni2]
  542. sni_resp = listener_api.pop('sni_container_refs')
  543. self.assertEqual(2, len(sni_resp))
  544. for sni in sni_resp:
  545. self.assertIn(sni, sni_ex)
  546. self.assertIsNotNone(listener_api.pop('created_at'))
  547. self.assertIsNone(listener_api.pop('updated_at'))
  548. self.assertEqual(['test_tag'], listener_api['tags'])
  549. self.assertNotEqual(lb_listener, listener_api)
  550. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  551. constants.PENDING_UPDATE)
  552. self.assert_final_listener_statuses(self.lb_id, listener_api.get('id'))
  553. return listener_api
  554. def test_create_with_timeouts(self):
  555. optionals = {
  556. 'timeout_client_data': 1,
  557. 'timeout_member_connect': 2,
  558. 'timeout_member_data': constants.MIN_TIMEOUT,
  559. 'timeout_tcp_inspect': constants.MAX_TIMEOUT,
  560. }
  561. listener_api = self.test_create(**optionals)
  562. self.assertEqual(1, listener_api.get('timeout_client_data'))
  563. self.assertEqual(2, listener_api.get('timeout_member_connect'))
  564. self.assertEqual(constants.MIN_TIMEOUT,
  565. listener_api.get('timeout_member_data'))
  566. self.assertEqual(constants.MAX_TIMEOUT,
  567. listener_api.get('timeout_tcp_inspect'))
  568. def test_create_with_timeouts_too_high(self):
  569. optionals = {
  570. 'timeout_client_data': 1,
  571. 'timeout_member_connect': 2,
  572. 'timeout_member_data': 3,
  573. 'timeout_tcp_inspect': constants.MAX_TIMEOUT + 1,
  574. }
  575. resp = self.test_create(response_status=400, **optionals).json
  576. fault = resp.get('faultstring')
  577. self.assertIn(
  578. 'Invalid input for field/attribute timeout_tcp_inspect', fault)
  579. self.assertIn(
  580. 'Value should be lower or equal to {0}'.format(
  581. constants.MAX_TIMEOUT), fault)
  582. def test_create_with_timeouts_too_low(self):
  583. optionals = {
  584. 'timeout_client_data': 1,
  585. 'timeout_member_connect': 2,
  586. 'timeout_member_data': 3,
  587. 'timeout_tcp_inspect': constants.MIN_TIMEOUT - 1,
  588. }
  589. resp = self.test_create(response_status=400, **optionals).json
  590. fault = resp.get('faultstring')
  591. self.assertIn(
  592. 'Invalid input for field/attribute timeout_tcp_inspect', fault)
  593. self.assertIn(
  594. 'Value should be greater or equal to {0}'.format(
  595. constants.MIN_TIMEOUT), fault)
  596. def test_create_udp_case(self):
  597. api_listener = self.create_listener(constants.PROTOCOL_UDP, 6666,
  598. self.lb_id).get(self.root_tag)
  599. self.assertEqual(constants.PROTOCOL_UDP, api_listener.get('protocol'))
  600. self.assertEqual(6666, api_listener.get('protocol_port'))
  601. self.assert_correct_status(
  602. lb_id=self.lb_id, listener_id=api_listener.get('id'),
  603. lb_prov_status=constants.PENDING_UPDATE,
  604. listener_prov_status=constants.PENDING_CREATE,
  605. listener_op_status=constants.OFFLINE)
  606. def test_negative_create_udp_case(self):
  607. sni1 = uuidutils.generate_uuid()
  608. sni2 = uuidutils.generate_uuid()
  609. req_dict = {'name': 'listener1', 'default_pool_id': None,
  610. 'description': 'desc1',
  611. 'admin_state_up': False,
  612. 'protocol': constants.PROTOCOL_UDP,
  613. 'protocol_port': 6666, 'connection_limit': 10,
  614. 'default_tls_container_ref': uuidutils.generate_uuid(),
  615. 'sni_container_refs': [sni1, sni2],
  616. 'insert_headers': {
  617. "X-Forwarded-Port": "true",
  618. "X-Forwarded-For": "true"},
  619. 'loadbalancer_id': self.lb_id}
  620. expect_error_msg = (
  621. "Validation failure: %s protocol listener does not support TLS or "
  622. "header insertion.") % constants.PROTOCOL_UDP
  623. res = self.post(self.LISTENERS_PATH, self._build_body(req_dict),
  624. status=400, expect_errors=True)
  625. self.assertEqual(expect_error_msg, res.json['faultstring'])
  626. self.assert_correct_status(lb_id=self.lb_id)
  627. # Default pool protocol is udp which is different with listener
  628. # protocol.
  629. udp_pool_id = self.create_pool(
  630. self.lb_id, constants.PROTOCOL_UDP,
  631. constants.LB_ALGORITHM_ROUND_ROBIN).get('pool').get('id')
  632. self.set_lb_status(self.lb_id)
  633. lb_listener = {'name': 'listener1',
  634. 'default_pool_id': udp_pool_id,
  635. 'description': 'desc1',
  636. 'admin_state_up': False,
  637. 'protocol': constants.PROTOCOL_HTTP,
  638. 'protocol_port': 80,
  639. 'loadbalancer_id': self.lb_id}
  640. expect_error_msg = ("Validation failure: Listeners of type %s can "
  641. "only have pools of "
  642. "type UDP.") % constants.PROTOCOL_UDP
  643. res = self.post(self.LISTENERS_PATH, self._build_body(lb_listener),
  644. status=400, expect_errors=True)
  645. self.assertEqual(expect_error_msg, res.json['faultstring'])
  646. self.assert_correct_status(lb_id=self.lb_id)
  647. def test_create_duplicate_fails(self):
  648. self.create_listener(constants.PROTOCOL_HTTP, 80, self.lb_id)
  649. self.set_lb_status(self.lb_id)
  650. self.create_listener(constants.PROTOCOL_HTTP, 80, self.lb_id,
  651. status=409)
  652. def test_create_bad_tls_ref(self):
  653. sni1 = uuidutils.generate_uuid()
  654. sni2 = uuidutils.generate_uuid()
  655. tls_ref = uuidutils.generate_uuid()
  656. lb_listener = {'name': 'listener1', 'default_pool_id': None,
  657. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  658. 'protocol_port': 80,
  659. 'sni_container_refs': [sni1, sni2],
  660. 'default_tls_container_ref': tls_ref,
  661. 'loadbalancer_id': self.lb_id}
  662. body = self._build_body(lb_listener)
  663. self.cert_manager_mock().get_cert.side_effect = [
  664. Exception("bad cert"), None, Exception("bad_cert")]
  665. response = self.post(self.LISTENERS_PATH, body, status=400).json
  666. self.assertIn(sni1, response['faultstring'])
  667. self.assertNotIn(sni2, response['faultstring'])
  668. self.assertIn(tls_ref, response['faultstring'])
  669. def test_create_with_certs_not_terminated_https(self):
  670. optionals = {
  671. 'default_tls_container_ref': uuidutils.generate_uuid(),
  672. 'protocol': constants.PROTOCOL_TCP
  673. }
  674. resp = self.test_create(response_status=400, **optionals).json
  675. fault = resp.get('faultstring')
  676. self.assertIn(
  677. 'Certificate container references are only allowed on ', fault)
  678. self.assertIn(
  679. '{} protocol listeners.'.format(
  680. constants.PROTOCOL_TERMINATED_HTTPS), fault)
  681. def test_create_without_certs_if_terminated_https(self):
  682. optionals = {
  683. 'default_tls_container_ref': None,
  684. 'sni_container_refs': None,
  685. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS
  686. }
  687. resp = self.test_create(response_status=400, **optionals).json
  688. fault = resp.get('faultstring')
  689. self.assertIn(
  690. 'An SNI or default certificate container reference must ', fault)
  691. self.assertIn(
  692. 'be provided for {} protocol listeners.'.format(
  693. constants.PROTOCOL_TERMINATED_HTTPS), fault)
  694. def test_create_client_ca_cert_without_tls_cert(self):
  695. optionals = {
  696. 'default_tls_container_ref': None,
  697. 'sni_container_refs': None,
  698. 'client_ca_tls_container_ref': uuidutils.generate_uuid(),
  699. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS
  700. }
  701. resp = self.test_create(response_status=400, **optionals).json
  702. fault = resp.get('faultstring')
  703. self.assertIn(
  704. 'An SNI or default certificate container reference must ', fault)
  705. self.assertIn(
  706. 'be provided with a client CA container reference.', fault)
  707. def test_create_crl_without_ca_cert(self):
  708. optionals = {
  709. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  710. 'client_ca_tls_container_ref': None,
  711. 'client_crl_container_ref': uuidutils.generate_uuid()
  712. }
  713. resp = self.test_create(response_status=400, **optionals).json
  714. fault = resp.get('faultstring')
  715. self.assertIn(
  716. 'A client authentication CA reference is required to specify a '
  717. 'client authentication revocation list.', fault)
  718. def test_create_with_default_pool_id(self):
  719. lb_listener = {'name': 'listener1',
  720. 'default_pool_id': self.pool_id,
  721. 'description': 'desc1',
  722. 'admin_state_up': False,
  723. 'protocol': constants.PROTOCOL_HTTP,
  724. 'protocol_port': 80,
  725. 'loadbalancer_id': self.lb_id}
  726. body = self._build_body(lb_listener)
  727. response = self.post(self.LISTENERS_PATH, body)
  728. api_listener = response.json['listener']
  729. self.assertEqual(api_listener.get('default_pool_id'),
  730. self.pool_id)
  731. def test_create_with_bad_default_pool_id(self):
  732. lb_listener = {'name': 'listener1',
  733. 'default_pool_id': uuidutils.generate_uuid(),
  734. 'description': 'desc1',
  735. 'admin_state_up': False,
  736. 'protocol': constants.PROTOCOL_HTTP,
  737. 'protocol_port': 80,
  738. 'loadbalancer_id': self.lb_id}
  739. body = self._build_body(lb_listener)
  740. self.post(self.LISTENERS_PATH, body, status=404)
  741. def test_create_with_shared_default_pool_id(self):
  742. lb_listener1 = {'name': 'listener1',
  743. 'default_pool_id': self.pool_id,
  744. 'description': 'desc1',
  745. 'admin_state_up': False,
  746. 'protocol': constants.PROTOCOL_HTTP,
  747. 'protocol_port': 80,
  748. 'loadbalancer_id': self.lb_id}
  749. lb_listener2 = {'name': 'listener2',
  750. 'default_pool_id': self.pool_id,
  751. 'description': 'desc2',
  752. 'admin_state_up': False,
  753. 'protocol': constants.PROTOCOL_HTTP,
  754. 'protocol_port': 81,
  755. 'loadbalancer_id': self.lb_id}
  756. body1 = self._build_body(lb_listener1)
  757. body2 = self._build_body(lb_listener2)
  758. listener1 = self.post(self.LISTENERS_PATH, body1).json['listener']
  759. self.set_lb_status(self.lb_id, constants.ACTIVE)
  760. listener2 = self.post(self.LISTENERS_PATH, body2).json['listener']
  761. self.assertEqual(listener1['default_pool_id'], self.pool_id)
  762. self.assertEqual(listener1['default_pool_id'],
  763. listener2['default_pool_id'])
  764. def test_create_with_project_id(self):
  765. self.test_create(project_id=self.project_id)
  766. def test_create_defaults(self):
  767. defaults = {'name': None, 'default_pool_id': None,
  768. 'description': None, 'admin_state_up': True,
  769. 'connection_limit': None,
  770. 'default_tls_container_ref': None,
  771. 'sni_container_refs': [], 'project_id': None,
  772. 'insert_headers': {}}
  773. lb_listener = {'protocol': constants.PROTOCOL_HTTP,
  774. 'protocol_port': 80,
  775. 'loadbalancer_id': self.lb_id}
  776. body = self._build_body(lb_listener)
  777. response = self.post(self.LISTENERS_PATH, body)
  778. listener_api = response.json['listener']
  779. extra_expects = {'provisioning_status': constants.PENDING_CREATE,
  780. 'operating_status': constants.OFFLINE}
  781. lb_listener.update(extra_expects)
  782. lb_listener.update(defaults)
  783. self.assertTrue(uuidutils.is_uuid_like(listener_api.get('id')))
  784. lb_listener['id'] = listener_api.get('id')
  785. self.assertIsNotNone(listener_api.pop('created_at'))
  786. self.assertIsNone(listener_api.pop('updated_at'))
  787. self.assertNotEqual(lb_listener, listener_api)
  788. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  789. constants.PENDING_UPDATE)
  790. self.assert_final_listener_statuses(self.lb_id, listener_api['id'])
  791. def test_create_over_quota(self):
  792. self.start_quota_mock(data_models.Listener)
  793. lb_listener = {'name': 'listener1',
  794. 'protocol': constants.PROTOCOL_HTTP,
  795. 'protocol_port': 80,
  796. 'loadbalancer_id': self.lb_id}
  797. body = self._build_body(lb_listener)
  798. self.post(self.LISTENERS_PATH, body, status=403)
  799. @mock.patch('octavia.api.drivers.utils.call_provider')
  800. def test_create_with_bad_provider(self, mock_provider):
  801. mock_provider.side_effect = exceptions.ProviderDriverError(
  802. prov='bad_driver', user_msg='broken')
  803. lb_listener = {'name': 'listener1',
  804. 'protocol': constants.PROTOCOL_HTTP,
  805. 'protocol_port': 80,
  806. 'loadbalancer_id': self.lb_id}
  807. body = self._build_body(lb_listener)
  808. response = self.post(self.LISTENERS_PATH, body, status=500)
  809. self.assertIn('Provider \'bad_driver\' reports error: broken',
  810. response.json.get('faultstring'))
  811. def test_create_authorized(self, **optionals):
  812. lb_listener = {'name': 'listener1', 'default_pool_id': None,
  813. 'description': 'desc1',
  814. 'admin_state_up': False,
  815. 'protocol': constants.PROTOCOL_HTTP,
  816. 'protocol_port': 80, 'connection_limit': 10,
  817. 'default_tls_container_ref': None,
  818. 'sni_container_refs': None,
  819. 'insert_headers': {},
  820. 'project_id': self.project_id,
  821. 'loadbalancer_id': self.lb_id}
  822. lb_listener.update(optionals)
  823. body = self._build_body(lb_listener)
  824. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  825. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  826. self.conf.config(group='api_settings',
  827. auth_strategy=constants.TESTING)
  828. with mock.patch.object(octavia.common.context.Context, 'project_id',
  829. self.project_id):
  830. override_credentials = {
  831. 'service_user_id': None,
  832. 'user_domain_id': None,
  833. 'is_admin_project': True,
  834. 'service_project_domain_id': None,
  835. 'service_project_id': None,
  836. 'roles': ['load-balancer_member'],
  837. 'user_id': None,
  838. 'is_admin': False,
  839. 'service_user_domain_id': None,
  840. 'project_domain_id': None,
  841. 'service_roles': [],
  842. 'project_id': self.project_id}
  843. with mock.patch(
  844. "oslo_context.context.RequestContext.to_policy_values",
  845. return_value=override_credentials):
  846. response = self.post(self.LISTENERS_PATH, body)
  847. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  848. listener_api = response.json['listener']
  849. extra_expects = {'provisioning_status': constants.PENDING_CREATE,
  850. 'operating_status': constants.OFFLINE}
  851. lb_listener.update(extra_expects)
  852. self.assertTrue(uuidutils.is_uuid_like(listener_api.get('id')))
  853. for key, value in optionals.items():
  854. self.assertEqual(value, lb_listener.get(key))
  855. lb_listener['id'] = listener_api.get('id')
  856. self.assertIsNotNone(listener_api.pop('created_at'))
  857. self.assertIsNone(listener_api.pop('updated_at'))
  858. self.assertNotEqual(lb_listener, listener_api)
  859. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  860. constants.PENDING_UPDATE)
  861. self.assert_final_listener_statuses(self.lb_id, listener_api.get('id'))
  862. def test_create_not_authorized(self, **optionals):
  863. lb_listener = {'name': 'listener1', 'default_pool_id': None,
  864. 'description': 'desc1',
  865. 'admin_state_up': False,
  866. 'protocol': constants.PROTOCOL_HTTP,
  867. 'protocol_port': 80, 'connection_limit': 10,
  868. 'default_tls_container_ref': None,
  869. 'sni_container_refs': None,
  870. 'insert_headers': {},
  871. 'project_id': self.project_id,
  872. 'loadbalancer_id': self.lb_id}
  873. lb_listener.update(optionals)
  874. body = self._build_body(lb_listener)
  875. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  876. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  877. self.conf.config(group='api_settings',
  878. auth_strategy=constants.TESTING)
  879. with mock.patch.object(octavia.common.context.Context, 'project_id',
  880. uuidutils.generate_uuid()):
  881. response = self.post(self.LISTENERS_PATH, body, status=403)
  882. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  883. self.assertEqual(self.NOT_AUTHORIZED_BODY, response.json)
  884. def test_create_with_ca_cert(self):
  885. self.cert_manager_mock().get_secret.return_value = (
  886. sample_certs.X509_CA_CERT)
  887. optionals = {
  888. 'client_ca_tls_container_ref': uuidutils.generate_uuid()
  889. }
  890. listener_api = self.test_create(**optionals)
  891. self.assertEqual(optionals['client_ca_tls_container_ref'],
  892. listener_api.get('client_ca_tls_container_ref'))
  893. self.assertEqual(constants.CLIENT_AUTH_NONE,
  894. listener_api.get('client_authentication'))
  895. def test_create_with_ca_cert_and_option(self):
  896. self.cert_manager_mock().get_secret.return_value = (
  897. sample_certs.X509_CA_CERT)
  898. optionals = {
  899. 'client_ca_tls_container_ref': uuidutils.generate_uuid(),
  900. 'client_authentication': constants.CLIENT_AUTH_MANDATORY
  901. }
  902. listener_api = self.test_create(**optionals)
  903. self.assertEqual(optionals['client_ca_tls_container_ref'],
  904. listener_api.get('client_ca_tls_container_ref'))
  905. self.assertEqual(optionals['client_authentication'],
  906. listener_api.get('client_authentication'))
  907. def test_create_with_ca_cert_and_crl(self):
  908. # Load up sample certs to test the validation
  909. self.cert_manager_mock().get_secret.side_effect = [
  910. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  911. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
  912. optionals = {
  913. 'client_ca_tls_container_ref': uuidutils.generate_uuid(),
  914. 'client_crl_container_ref': uuidutils.generate_uuid()
  915. }
  916. listener_api = self.test_create(**optionals)
  917. self.assertEqual(optionals['client_ca_tls_container_ref'],
  918. listener_api.get('client_ca_tls_container_ref'))
  919. self.assertEqual(constants.CLIENT_AUTH_NONE,
  920. listener_api.get('client_authentication'))
  921. self.assertEqual(optionals['client_crl_container_ref'],
  922. listener_api.get('client_crl_container_ref'))
  923. # TODO(johnsom) Fix this when there is a noop certificate manager
  924. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  925. def test_create_with_crl_mismatch_ca_cert(self, mock_cert_data):
  926. cert1 = data_models.TLSContainer(certificate='cert 1')
  927. cert2 = data_models.TLSContainer(certificate='cert 2')
  928. cert3 = data_models.TLSContainer(certificate='cert 3')
  929. mock_cert_data.return_value = {'tls_cert': cert1,
  930. 'sni_certs': [cert2, cert3]}
  931. self.cert_manager_mock().get_secret.side_effect = [
  932. sample_certs.X509_CERT, sample_certs.X509_CA_CRL,
  933. sample_certs.X509_CERT, sample_certs.X509_CA_CRL]
  934. sni1 = uuidutils.generate_uuid()
  935. sni2 = uuidutils.generate_uuid()
  936. lb_listener = {
  937. 'name': 'listener1', 'default_pool_id': None,
  938. 'description': 'desc1',
  939. 'admin_state_up': False,
  940. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  941. 'protocol_port': 80,
  942. 'default_tls_container_ref': uuidutils.generate_uuid(),
  943. 'sni_container_refs': [sni1, sni2],
  944. 'project_id': self.project_id,
  945. 'loadbalancer_id': self.lb_id,
  946. 'client_ca_tls_container_ref': uuidutils.generate_uuid(),
  947. 'client_crl_container_ref': uuidutils.generate_uuid()
  948. }
  949. body = self._build_body(lb_listener)
  950. response = self.post(self.LISTENERS_PATH, body, status=400).json
  951. self.assertEqual(
  952. "Validation failure: The CRL specified is not valid for client "
  953. "certificate authority reference supplied.",
  954. response['faultstring'])
  955. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  956. def test_create_with_ca_cert_negative_cases(self, mock_load_cert):
  957. # create just with option or crl,
  958. # no client_ca_tls_container_ref specified.
  959. sni1 = uuidutils.generate_uuid()
  960. sni2 = uuidutils.generate_uuid()
  961. for opt in [{'client_authentication': constants.CLIENT_AUTH_MANDATORY,
  962. 'client_crl_container_ref': uuidutils.generate_uuid()},
  963. {'client_authentication': constants.CLIENT_AUTH_OPTIONAL,
  964. 'client_crl_container_ref': uuidutils.generate_uuid()}]:
  965. lb_listener = {
  966. 'name': 'listener1', 'default_pool_id': None,
  967. 'description': 'desc1',
  968. 'admin_state_up': False,
  969. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  970. 'protocol_port': 80,
  971. 'default_tls_container_ref': uuidutils.generate_uuid(),
  972. 'sni_container_refs': [sni1, sni2],
  973. 'project_id': self.project_id,
  974. 'loadbalancer_id': self.lb_id}
  975. lb_listener.update(opt)
  976. body = self._build_body(lb_listener)
  977. response = self.post(self.LISTENERS_PATH, body, status=400).json
  978. self.assertEqual(
  979. "Validation failure: Client authentication setting %s "
  980. "requires a client CA container reference." %
  981. opt['client_authentication'], response['faultstring'])
  982. def test_create_with_bad_ca_cert_ref(self):
  983. sni1 = uuidutils.generate_uuid()
  984. sni2 = uuidutils.generate_uuid()
  985. lb_listener = {
  986. 'name': 'listener1', 'default_pool_id': None,
  987. 'description': 'desc1',
  988. 'admin_state_up': False,
  989. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  990. 'protocol_port': 80,
  991. 'default_tls_container_ref': uuidutils.generate_uuid(),
  992. 'sni_container_refs': [sni1, sni2],
  993. 'project_id': self.project_id,
  994. 'loadbalancer_id': self.lb_id,
  995. 'client_ca_tls_container_ref': uuidutils.generate_uuid()}
  996. body = self._build_body(lb_listener)
  997. self.cert_manager_mock().get_cert.side_effect = [
  998. 'cert 1', 'cert 2', 'cert 3']
  999. self.cert_manager_mock().get_secret.side_effect = [
  1000. Exception('bad ca cert')]
  1001. response = self.post(self.LISTENERS_PATH, body, status=400).json
  1002. self.assertEqual("Could not retrieve certificate: ['%s']" %
  1003. lb_listener['client_ca_tls_container_ref'],
  1004. response['faultstring'])
  1005. def test_create_with_unreachable_crl(self):
  1006. sni1 = uuidutils.generate_uuid()
  1007. sni2 = uuidutils.generate_uuid()
  1008. lb_listener = {
  1009. 'name': 'listener1', 'default_pool_id': None,
  1010. 'description': 'desc1',
  1011. 'admin_state_up': False,
  1012. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  1013. 'protocol_port': 80,
  1014. 'default_tls_container_ref': uuidutils.generate_uuid(),
  1015. 'sni_container_refs': [sni1, sni2],
  1016. 'project_id': self.project_id,
  1017. 'loadbalancer_id': self.lb_id,
  1018. 'client_ca_tls_container_ref': uuidutils.generate_uuid(),
  1019. 'client_crl_container_ref': uuidutils.generate_uuid()}
  1020. body = self._build_body(lb_listener)
  1021. self.cert_manager_mock().get_secret.side_effect = Exception(
  1022. 'bad CRL ref')
  1023. response = self.post(self.LISTENERS_PATH, body, status=400).json
  1024. self.assertIn(lb_listener['client_crl_container_ref'],
  1025. response['faultstring'])
  1026. def test_create_with_bad_ca_cert(self):
  1027. sni1 = uuidutils.generate_uuid()
  1028. sni2 = uuidutils.generate_uuid()
  1029. lb_listener = {
  1030. 'name': 'listener1', 'default_pool_id': None,
  1031. 'description': 'desc1',
  1032. 'admin_state_up': False,
  1033. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  1034. 'protocol_port': 80,
  1035. 'default_tls_container_ref': uuidutils.generate_uuid(),
  1036. 'sni_container_refs': [sni1, sni2],
  1037. 'project_id': self.project_id,
  1038. 'loadbalancer_id': self.lb_id,
  1039. 'client_ca_tls_container_ref': uuidutils.generate_uuid()}
  1040. body = self._build_body(lb_listener)
  1041. self.cert_manager_mock().get_cert.side_effect = [
  1042. 'cert 1', 'cert 2', 'cert 3']
  1043. self.cert_manager_mock().get_secret.return_value = 'bad cert'
  1044. response = self.post(self.LISTENERS_PATH, body, status=400).json
  1045. self.assertIn("The client authentication CA certificate is invalid. "
  1046. "It must be a valid x509 PEM format certificate.",
  1047. response['faultstring'])
  1048. @mock.patch('octavia.api.drivers.utils.call_provider')
  1049. def test_update_with_bad_provider(self, mock_provider):
  1050. api_listener = self.create_listener(
  1051. constants.PROTOCOL_HTTP, 80,
  1052. self.lb_id).get(self.root_tag)
  1053. self.set_lb_status(lb_id=self.lb_id)
  1054. new_listener = {'name': 'new_name'}
  1055. mock_provider.side_effect = exceptions.ProviderDriverError(
  1056. prov='bad_driver', user_msg='broken')
  1057. response = self.put(
  1058. self.LISTENER_PATH.format(listener_id=api_listener.get('id')),
  1059. self._build_body(new_listener), status=500)
  1060. self.assertIn('Provider \'bad_driver\' reports error: broken',
  1061. response.json.get('faultstring'))
  1062. @mock.patch('octavia.api.drivers.utils.call_provider')
  1063. def test_delete_with_bad_provider(self, mock_provider):
  1064. api_listener = self.create_listener(
  1065. constants.PROTOCOL_HTTP, 80,
  1066. self.lb_id).get(self.root_tag)
  1067. self.set_lb_status(lb_id=self.lb_id)
  1068. # Set status to ACTIVE/ONLINE because set_lb_status did it in the db
  1069. api_listener['provisioning_status'] = constants.ACTIVE
  1070. api_listener['operating_status'] = constants.ONLINE
  1071. response = self.get(self.LISTENER_PATH.format(
  1072. listener_id=api_listener.get('id'))).json.get(self.root_tag)
  1073. self.assertIsNone(api_listener.pop('updated_at'))
  1074. self.assertIsNotNone(response.pop('updated_at'))
  1075. self.assertEqual(api_listener, response)
  1076. mock_provider.side_effect = exceptions.ProviderDriverError(
  1077. prov='bad_driver', user_msg='broken')
  1078. self.delete(self.LISTENER_PATH.format(
  1079. listener_id=api_listener.get('id')), status=500)
  1080. # TODO(johnsom) Fix this when there is a noop certificate manager
  1081. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1082. def test_update(self, mock_cert_data, **options):
  1083. cert1 = data_models.TLSContainer(certificate='cert 1')
  1084. mock_cert_data.return_value = {'tls_cert': cert1}
  1085. self.cert_manager_mock().get_secret.return_value = (
  1086. sample_certs.X509_CA_CERT)
  1087. tls_uuid = uuidutils.generate_uuid()
  1088. ca_tls_uuid = uuidutils.generate_uuid()
  1089. listener = self.create_listener(
  1090. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1091. name='listener1', description='desc1',
  1092. admin_state_up=False, connection_limit=10,
  1093. default_tls_container_ref=tls_uuid,
  1094. default_pool_id=None, tags=['old_tag'],
  1095. client_ca_tls_container_ref=ca_tls_uuid).get(self.root_tag)
  1096. ori_listener = copy.deepcopy(listener)
  1097. self.set_lb_status(self.lb_id)
  1098. new_listener = {'name': 'listener2', 'admin_state_up': True,
  1099. 'default_pool_id': self.pool_id,
  1100. 'timeout_client_data': 1,
  1101. 'timeout_member_connect': 2,
  1102. 'timeout_member_data': 3,
  1103. 'timeout_tcp_inspect': 4,
  1104. 'tags': ['new_tag']}
  1105. new_listener.update(options)
  1106. body = self._build_body(new_listener)
  1107. listener_path = self.LISTENER_PATH.format(
  1108. listener_id=listener['id'])
  1109. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1110. update_expect = {'provisioning_status': constants.PENDING_UPDATE,
  1111. 'operating_status': constants.ONLINE}
  1112. update_expect.update(new_listener)
  1113. listener.update(update_expect)
  1114. self.assertEqual(listener['created_at'], api_listener['created_at'])
  1115. self.assertNotEqual(listener['updated_at'], api_listener['updated_at'])
  1116. self.assertEqual(['new_tag'], api_listener['tags'])
  1117. self.assertNotEqual(listener, api_listener)
  1118. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1119. constants.PENDING_UPDATE)
  1120. self.assert_final_listener_statuses(self.lb_id,
  1121. api_listener['id'])
  1122. return ori_listener, api_listener
  1123. def test_update_with_bad_tls_ref(self):
  1124. listener = self.create_listener(constants.PROTOCOL_TCP,
  1125. 443, self.lb_id)
  1126. tls_uuid = uuidutils.generate_uuid()
  1127. self.set_lb_status(self.lb_id)
  1128. self.listener_repo.update(db_api.get_session(),
  1129. listener['listener']['id'],
  1130. tls_certificate_id=tls_uuid,
  1131. protocol=constants.PROTOCOL_TERMINATED_HTTPS)
  1132. listener_path = self.LISTENER_PATH.format(
  1133. listener_id=listener['listener']['id'])
  1134. update_data = {'name': 'listener2'}
  1135. body = self._build_body(update_data)
  1136. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1137. response = self.get(self.listener_path.format(
  1138. listener_id=listener['listener']['id']))
  1139. api_listener = response.json.get(self.root_tag)
  1140. self.assertEqual('listener2', api_listener['name'])
  1141. def test_negative_update_udp_case(self):
  1142. api_listener = self.create_listener(constants.PROTOCOL_UDP, 6666,
  1143. self.lb_id).get(self.root_tag)
  1144. self.set_lb_status(self.lb_id)
  1145. sni1 = uuidutils.generate_uuid()
  1146. sni2 = uuidutils.generate_uuid()
  1147. new_listener = {'name': 'new-listener',
  1148. 'admin_state_up': True,
  1149. 'connection_limit': 10,
  1150. 'default_tls_container_ref':
  1151. uuidutils.generate_uuid(),
  1152. 'sni_container_refs': [sni1, sni2],
  1153. 'insert_headers': {
  1154. "X-Forwarded-Port": "true",
  1155. "X-Forwarded-For": "true"}}
  1156. listener_path = self.LISTENER_PATH.format(
  1157. listener_id=api_listener['id'])
  1158. expect_error_msg = (
  1159. "Validation failure: %s protocol listener does not support TLS or "
  1160. "header insertion.") % constants.PROTOCOL_UDP
  1161. res = self.put(listener_path, self._build_body(new_listener),
  1162. status=400, expect_errors=True)
  1163. self.assertEqual(expect_error_msg, res.json['faultstring'])
  1164. self.assert_correct_status(lb_id=self.lb_id)
  1165. def test_update_bad_listener_id(self):
  1166. self.put(self.listener_path.format(listener_id='SEAN-CONNERY'),
  1167. body={}, status=404)
  1168. def test_update_with_bad_default_pool_id(self):
  1169. bad_pool_uuid = uuidutils.generate_uuid()
  1170. listener = self.create_listener(
  1171. constants.PROTOCOL_TCP, 80, self.lb_id,
  1172. name='listener1', description='desc1',
  1173. admin_state_up=False, connection_limit=10,
  1174. default_pool_id=self.pool_id)
  1175. self.set_lb_status(self.lb_id)
  1176. new_listener = {'name': 'listener2', 'admin_state_up': True,
  1177. 'default_pool_id': bad_pool_uuid}
  1178. body = self._build_body(new_listener)
  1179. listener_path = self.LISTENER_PATH.format(
  1180. listener_id=listener['listener']['id'])
  1181. self.put(listener_path, body, status=404)
  1182. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1183. constants.ACTIVE)
  1184. self.assert_final_listener_statuses(self.lb_id,
  1185. listener['listener']['id'])
  1186. def test_update_with_certs_not_terminated_https(self):
  1187. listener = self.create_listener(
  1188. constants.PROTOCOL_TCP, 80, self.lb_id,
  1189. name='listener1', description='desc1',
  1190. admin_state_up=False, connection_limit=10,
  1191. default_pool_id=None,).get(self.root_tag)
  1192. self.set_lb_status(self.lb_id)
  1193. lb_listener = {
  1194. 'default_tls_container_ref': uuidutils.generate_uuid()}
  1195. body = self._build_body(lb_listener)
  1196. listener_path = self.LISTENER_PATH.format(
  1197. listener_id=listener['id'])
  1198. response = self.put(listener_path, body, status=400).json
  1199. fault = response.get('faultstring')
  1200. self.assertIn(
  1201. 'Certificate container references are only allowed on ', fault)
  1202. self.assertIn(
  1203. '{} protocol listeners.'.format(
  1204. constants.PROTOCOL_TERMINATED_HTTPS), fault)
  1205. def test_update_with_ca_cert(self):
  1206. self.cert_manager_mock().get_secret.return_value = (
  1207. sample_certs.X509_CA_CERT)
  1208. optionals = {
  1209. 'client_ca_tls_container_ref': uuidutils.generate_uuid()
  1210. }
  1211. ori_listener, update_listener = self.test_update(**optionals)
  1212. self.assertEqual(optionals['client_ca_tls_container_ref'],
  1213. update_listener.get('client_ca_tls_container_ref'))
  1214. self.assertNotEqual(ori_listener['client_ca_tls_container_ref'],
  1215. optionals['client_ca_tls_container_ref'])
  1216. def test_update_with_only_client_auth_option(self):
  1217. optionals = {
  1218. 'client_authentication': constants.CLIENT_AUTH_OPTIONAL
  1219. }
  1220. ori_listener, update_listener = self.test_update(**optionals)
  1221. self.assertEqual(optionals['client_authentication'],
  1222. update_listener.get('client_authentication'))
  1223. self.assertNotEqual(ori_listener['client_authentication'],
  1224. optionals['client_authentication'])
  1225. def test_update_with_crl(self):
  1226. # Load up sample certs to test the validation
  1227. self.cert_manager_mock().get_secret.side_effect = [
  1228. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1229. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1230. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
  1231. optionals = {
  1232. 'client_crl_container_ref': uuidutils.generate_uuid()
  1233. }
  1234. ori_listener, update_listener = self.test_update(**optionals)
  1235. self.assertEqual(optionals['client_crl_container_ref'],
  1236. update_listener.get('client_crl_container_ref'))
  1237. self.assertNotEqual(ori_listener['client_crl_container_ref'],
  1238. optionals['client_crl_container_ref'])
  1239. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1240. def test_update_from_nonexist_ca_cert_to_new_ca_cert(self, mock_cert_data):
  1241. cert1 = data_models.TLSContainer(certificate='cert 1')
  1242. mock_cert_data.return_value = {'tls_cert': cert1}
  1243. self.cert_manager_mock().get_secret.return_value = (
  1244. sample_certs.X509_CA_CERT)
  1245. tls_uuid = uuidutils.generate_uuid()
  1246. listener = self.create_listener(
  1247. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1248. name='listener1', description='desc1',
  1249. admin_state_up=False, connection_limit=10,
  1250. default_tls_container_ref=tls_uuid,
  1251. default_pool_id=None).get(self.root_tag)
  1252. self.set_lb_status(self.lb_id)
  1253. ca_tls_uuid = uuidutils.generate_uuid()
  1254. new_listener = {
  1255. 'client_ca_tls_container_ref': ca_tls_uuid}
  1256. body = self._build_body(new_listener)
  1257. listener_path = self.LISTENER_PATH.format(
  1258. listener_id=listener['id'])
  1259. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1260. update_expect = {'provisioning_status': constants.PENDING_UPDATE,
  1261. 'operating_status': constants.ONLINE}
  1262. update_expect.update(new_listener)
  1263. listener.update(update_expect)
  1264. self.assertEqual(ca_tls_uuid,
  1265. api_listener['client_ca_tls_container_ref'])
  1266. self.assertEqual(constants.CLIENT_AUTH_NONE,
  1267. api_listener['client_authentication'])
  1268. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1269. def test_update_with_ca_cert_missing(self, mock_cert_data):
  1270. # update a listener, no ca cert exist
  1271. cert1 = data_models.TLSContainer(certificate='cert 1')
  1272. mock_cert_data.return_value = {'tls_cert': cert1}
  1273. tls_uuid = uuidutils.generate_uuid()
  1274. listener = self.create_listener(
  1275. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1276. name='listener1', description='desc1',
  1277. admin_state_up=False, connection_limit=10,
  1278. default_tls_container_ref=tls_uuid,
  1279. default_pool_id=None).get(self.root_tag)
  1280. self.set_lb_status(self.lb_id)
  1281. for opt in [{'client_authentication': constants.CLIENT_AUTH_OPTIONAL,
  1282. 'client_crl_container_ref': uuidutils.generate_uuid()},
  1283. {'client_authentication': constants.CLIENT_AUTH_MANDATORY,
  1284. 'client_crl_container_ref': uuidutils.generate_uuid()}]:
  1285. body = self._build_body(opt)
  1286. listener_path = self.LISTENER_PATH.format(
  1287. listener_id=listener['id'])
  1288. response = self.put(listener_path, body, status=400).json
  1289. self.assertEqual(
  1290. "Validation failure: Client authentication setting %s "
  1291. "requires a client CA container reference." %
  1292. opt['client_authentication'], response['faultstring'])
  1293. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1294. def test_update_with_crl_but_ca_cert_missing(self, mock_cert_data):
  1295. # update a listener, no ca cert exist
  1296. cert1 = data_models.TLSContainer(certificate='cert 1')
  1297. mock_cert_data.return_value = {'tls_cert': cert1,
  1298. 'client_ca_cert': None}
  1299. tls_uuid = uuidutils.generate_uuid()
  1300. listener = self.create_listener(
  1301. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1302. name='listener1', description='desc1',
  1303. admin_state_up=False, connection_limit=10,
  1304. default_tls_container_ref=tls_uuid,
  1305. default_pool_id=None).get(self.root_tag)
  1306. self.set_lb_status(self.lb_id)
  1307. body = self._build_body(
  1308. {'client_crl_container_ref': uuidutils.generate_uuid()})
  1309. listener_path = self.LISTENER_PATH.format(
  1310. listener_id=listener['id'])
  1311. response = self.put(listener_path, body, status=400).json
  1312. self.assertEqual(
  1313. "Validation failure: A client authentication CA reference is "
  1314. "required to specify a client authentication revocation list.",
  1315. response['faultstring'])
  1316. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1317. def test_update_unset_ca_cert(self, mock_cert_data):
  1318. cert1 = data_models.TLSContainer(certificate='cert 1')
  1319. mock_cert_data.return_value = {'tls_cert': cert1}
  1320. self.cert_manager_mock().get_secret.return_value = (
  1321. sample_certs.X509_CA_CERT)
  1322. tls_uuid = uuidutils.generate_uuid()
  1323. ca_tls_uuid = uuidutils.generate_uuid()
  1324. listener = self.create_listener(
  1325. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1326. name='listener1', description='desc1',
  1327. admin_state_up=False, connection_limit=10,
  1328. default_tls_container_ref=tls_uuid,
  1329. default_pool_id=None,
  1330. client_ca_tls_container_ref=ca_tls_uuid).get(self.root_tag)
  1331. self.set_lb_status(self.lb_id)
  1332. lb_listener = {'client_ca_tls_container_ref': None}
  1333. body = self._build_body(lb_listener)
  1334. listener_path = self.LISTENER_PATH.format(
  1335. listener_id=listener['id'])
  1336. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1337. self.assertIsNone(api_listener.get('client_ca_tls_container_ref'))
  1338. self.assertIsNone(api_listener.get('client_auth_option'))
  1339. self.assertIsNone(api_listener.get('client_crl_container_ref'))
  1340. @mock.patch(
  1341. 'octavia.common.tls_utils.cert_parser.load_certificates_data')
  1342. def test_update_unset_crl(self, mock_cert_data):
  1343. # Load up sample certs to test the validation
  1344. self.cert_manager_mock().get_secret.side_effect = [
  1345. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1346. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1347. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1348. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
  1349. cert1 = data_models.TLSContainer(certificate='cert 1')
  1350. mock_cert_data.return_value = {'tls_cert': cert1}
  1351. listener = self.create_listener(
  1352. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1353. name='listener1', description='desc1',
  1354. admin_state_up=False, connection_limit=10,
  1355. default_tls_container_ref=uuidutils.generate_uuid(),
  1356. default_pool_id=None,
  1357. client_ca_tls_container_ref=uuidutils.generate_uuid(),
  1358. client_crl_container_ref=uuidutils.generate_uuid(),
  1359. client_authentication=constants.CLIENT_AUTH_MANDATORY).get(
  1360. self.root_tag)
  1361. self.set_lb_status(self.lb_id)
  1362. lb_listener = {'client_crl_container_ref': None}
  1363. body = self._build_body(lb_listener)
  1364. listener_path = self.LISTENER_PATH.format(
  1365. listener_id=listener['id'])
  1366. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1367. self.assertEqual(listener.get('client_ca_tls_container_ref'),
  1368. api_listener.get('client_ca_tls_container_ref'))
  1369. self.assertEqual(listener.get('client_authentication'),
  1370. api_listener.get('client_authentication'))
  1371. self.assertIsNone(api_listener.get('client_crl_container_ref'))
  1372. # TODO(johnsom) Fix this when there is a noop certificate manager
  1373. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1374. def test_update_unset_defaults(self, mock_cert_data):
  1375. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  1376. self.conf.config(group='haproxy_amphora', timeout_client_data=20)
  1377. self.conf.config(group='haproxy_amphora', timeout_member_connect=21)
  1378. self.conf.config(group='haproxy_amphora', timeout_member_data=22)
  1379. self.conf.config(group='haproxy_amphora', timeout_tcp_inspect=23)
  1380. self.cert_manager_mock().get_secret.side_effect = [
  1381. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1382. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1383. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1384. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL]
  1385. cert1 = data_models.TLSContainer(certificate='cert 1')
  1386. mock_cert_data.return_value = {'tls_cert': cert1}
  1387. self.cert_manager_mock().get_secret.return_value = (
  1388. sample_certs.X509_CA_CERT)
  1389. tls_uuid = uuidutils.generate_uuid()
  1390. ca_tls_uuid = uuidutils.generate_uuid()
  1391. crl_tls_uuid = uuidutils.generate_uuid()
  1392. listener = self.create_listener(
  1393. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1394. name='listener1', description='desc1',
  1395. admin_state_up=False, connection_limit=10,
  1396. default_tls_container_ref=tls_uuid,
  1397. default_pool_id=self.pool_id, tags=['old_tag'],
  1398. insert_headers={'X-Forwarded-For': 'true'},
  1399. timeout_client_data=1, timeout_member_connect=2,
  1400. timeout_member_data=3, timeout_tcp_inspect=4,
  1401. client_authentication=constants.CLIENT_AUTH_OPTIONAL,
  1402. client_crl_container_ref=crl_tls_uuid,
  1403. client_ca_tls_container_ref=ca_tls_uuid).get(self.root_tag)
  1404. self.set_lb_status(self.lb_id)
  1405. unset_params = {
  1406. 'name': None, 'description': None, 'connection_limit': None,
  1407. 'default_tls_container_ref': None, 'sni_container_refs': None,
  1408. 'insert_headers': None, 'timeout_client_data': None,
  1409. 'timeout_member_connect': None, 'timeout_member_data': None,
  1410. 'timeout_tcp_inspect': None, 'client_ca_tls_container_ref': None,
  1411. 'client_authentication': None, 'default_pool_id': None,
  1412. 'client_crl_container_ref': None}
  1413. body = self._build_body(unset_params)
  1414. listener_path = self.LISTENER_PATH.format(
  1415. listener_id=listener['id'])
  1416. api_listener = self.put(listener_path, body).json.get(self.root_tag)
  1417. self.assertEqual('', api_listener['name'])
  1418. self.assertEqual('', api_listener['description'])
  1419. self.assertEqual(constants.DEFAULT_CONNECTION_LIMIT,
  1420. api_listener['connection_limit'])
  1421. self.assertIsNone(api_listener['default_tls_container_ref'])
  1422. self.assertEqual([], api_listener['sni_container_refs'])
  1423. self.assertEqual({}, api_listener['insert_headers'])
  1424. self.assertEqual(20, api_listener['timeout_client_data'])
  1425. self.assertEqual(21, api_listener['timeout_member_connect'])
  1426. self.assertEqual(22, api_listener['timeout_member_data'])
  1427. self.assertEqual(23, api_listener['timeout_tcp_inspect'])
  1428. self.assertIsNone(api_listener['client_ca_tls_container_ref'])
  1429. self.assertIsNone(api_listener['client_crl_container_ref'])
  1430. self.assertEqual(constants.CLIENT_AUTH_NONE,
  1431. api_listener['client_authentication'])
  1432. self.assertIsNone(api_listener['default_pool_id'])
  1433. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1434. def test_update_with_bad_ca_cert(self, mock_cert_data):
  1435. cert1 = data_models.TLSContainer(certificate='cert 1')
  1436. mock_cert_data.return_value = {'tls_cert': cert1}
  1437. self.cert_manager_mock().get_secret.return_value = (
  1438. sample_certs.X509_CA_CERT)
  1439. tls_uuid = uuidutils.generate_uuid()
  1440. ca_tls_uuid = uuidutils.generate_uuid()
  1441. listener = self.create_listener(
  1442. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1443. name='listener1', description='desc1',
  1444. admin_state_up=False, connection_limit=10,
  1445. default_tls_container_ref=tls_uuid,
  1446. default_pool_id=None,
  1447. client_ca_tls_container_ref=ca_tls_uuid).get(self.root_tag)
  1448. self.set_lb_status(self.lb_id)
  1449. self.cert_manager_mock().get_secret.side_effect = Exception(
  1450. 'bad ca cert')
  1451. self.cert_manager_mock().get_secret.side_effect = Exception(
  1452. 'bad secret')
  1453. lb_listener = {
  1454. 'client_ca_tls_container_ref': uuidutils.generate_uuid()}
  1455. body = self._build_body(lb_listener)
  1456. listener_path = self.LISTENER_PATH.format(
  1457. listener_id=listener['id'])
  1458. response = self.put(listener_path, body, status=400).json
  1459. self.assertIn(lb_listener['client_ca_tls_container_ref'],
  1460. response['faultstring'])
  1461. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1462. def test_update_with_unreachable_crl(self, mock_cert_data):
  1463. # Load up sample certs to test the validation
  1464. tls_cert_mock = mock.MagicMock()
  1465. tls_cert_mock.get_certificate.return_value = sample_certs.X509_CA_CERT
  1466. self.cert_manager_mock().get_cert.return_value = tls_cert_mock
  1467. self.cert_manager_mock().get_secret.side_effect = [
  1468. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1469. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1470. sample_certs.X509_CA_CERT, Exception('bad CRL ref')]
  1471. cert1 = data_models.TLSContainer(certificate='cert 1')
  1472. mock_cert_data.return_value = {'tls_cert': cert1}
  1473. listener = self.create_listener(
  1474. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1475. name='listener1', description='desc1',
  1476. admin_state_up=False, connection_limit=10,
  1477. default_tls_container_ref=uuidutils.generate_uuid(),
  1478. default_pool_id=None,
  1479. client_ca_tls_container_ref=uuidutils.generate_uuid(),
  1480. client_crl_container_ref=uuidutils.generate_uuid()).get(
  1481. self.root_tag)
  1482. self.set_lb_status(self.lb_id)
  1483. lb_listener = {
  1484. 'client_crl_container_ref': uuidutils.generate_uuid()}
  1485. body = self._build_body(lb_listener)
  1486. listener_path = self.LISTENER_PATH.format(
  1487. listener_id=listener['id'])
  1488. response = self.put(listener_path, body, status=400).json
  1489. self.assertIn(lb_listener['client_crl_container_ref'],
  1490. response['faultstring'])
  1491. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1492. def test_update_with_bad_crl(self, mock_cert_data):
  1493. # Load up sample certs to test the validation
  1494. tls_cert_mock = mock.MagicMock()
  1495. tls_cert_mock.get_certificate.return_value = sample_certs.X509_CA_CERT
  1496. self.cert_manager_mock().get_cert.return_value = tls_cert_mock
  1497. self.cert_manager_mock().get_secret.side_effect = [
  1498. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1499. sample_certs.X509_CA_CERT, sample_certs.X509_CA_CRL,
  1500. sample_certs.X509_CA_CERT, 'bad CRL']
  1501. cert1 = data_models.TLSContainer(certificate='cert 1')
  1502. mock_cert_data.return_value = {'tls_cert': cert1}
  1503. listener = self.create_listener(
  1504. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1505. name='listener1', description='desc1',
  1506. admin_state_up=False, connection_limit=10,
  1507. default_tls_container_ref=uuidutils.generate_uuid(),
  1508. default_pool_id=None,
  1509. client_ca_tls_container_ref=uuidutils.generate_uuid(),
  1510. client_crl_container_ref=uuidutils.generate_uuid()).get(
  1511. self.root_tag)
  1512. self.set_lb_status(self.lb_id)
  1513. lb_listener = {
  1514. 'client_crl_container_ref': uuidutils.generate_uuid()}
  1515. body = self._build_body(lb_listener)
  1516. listener_path = self.LISTENER_PATH.format(
  1517. listener_id=listener['id'])
  1518. response = self.put(listener_path, body, status=400).json
  1519. self.assertIn("The client authentication certificate revocation list "
  1520. "is invalid. It must be a valid x509 PEM format "
  1521. "certificate revocation list.",
  1522. response['faultstring'])
  1523. def test_update_authorized(self):
  1524. listener = self.create_listener(
  1525. constants.PROTOCOL_TCP, 80, self.lb_id,
  1526. name='listener1', description='desc1',
  1527. admin_state_up=False, connection_limit=10,
  1528. default_pool_id=None).get(self.root_tag)
  1529. self.set_lb_status(self.lb_id)
  1530. new_listener = {'name': 'listener2', 'admin_state_up': True,
  1531. 'default_pool_id': self.pool_id}
  1532. body = self._build_body(new_listener)
  1533. listener_path = self.LISTENER_PATH.format(
  1534. listener_id=listener['id'])
  1535. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  1536. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  1537. self.conf.config(group='api_settings',
  1538. auth_strategy=constants.TESTING)
  1539. with mock.patch.object(octavia.common.context.Context, 'project_id',
  1540. self.project_id):
  1541. override_credentials = {
  1542. 'service_user_id': None,
  1543. 'user_domain_id': None,
  1544. 'is_admin_project': True,
  1545. 'service_project_domain_id': None,
  1546. 'service_project_id': None,
  1547. 'roles': ['load-balancer_member'],
  1548. 'user_id': None,
  1549. 'is_admin': False,
  1550. 'service_user_domain_id': None,
  1551. 'project_domain_id': None,
  1552. 'service_roles': [],
  1553. 'project_id': self.project_id}
  1554. with mock.patch(
  1555. "oslo_context.context.RequestContext.to_policy_values",
  1556. return_value=override_credentials):
  1557. api_listener = self.put(listener_path, body)
  1558. api_listener = api_listener.json.get(self.root_tag)
  1559. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  1560. update_expect = {'name': 'listener2', 'admin_state_up': True,
  1561. 'default_pool_id': self.pool_id,
  1562. 'provisioning_status': constants.PENDING_UPDATE,
  1563. 'operating_status': constants.ONLINE}
  1564. listener.update(update_expect)
  1565. self.assertEqual(listener['created_at'], api_listener['created_at'])
  1566. self.assertNotEqual(listener['updated_at'], api_listener['updated_at'])
  1567. self.assertNotEqual(listener, api_listener)
  1568. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1569. constants.PENDING_UPDATE)
  1570. self.assert_final_listener_statuses(self.lb_id,
  1571. api_listener['id'])
  1572. def test_update_not_authorized(self):
  1573. listener = self.create_listener(
  1574. constants.PROTOCOL_TCP, 80, self.lb_id,
  1575. name='listener1', description='desc1',
  1576. admin_state_up=False, connection_limit=10,
  1577. default_pool_id=None).get(self.root_tag)
  1578. self.set_lb_status(self.lb_id)
  1579. new_listener = {'name': 'listener2', 'admin_state_up': True,
  1580. 'default_pool_id': self.pool_id}
  1581. body = self._build_body(new_listener)
  1582. listener_path = self.LISTENER_PATH.format(
  1583. listener_id=listener['id'])
  1584. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  1585. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  1586. self.conf.config(group='api_settings',
  1587. auth_strategy=constants.TESTING)
  1588. with mock.patch.object(octavia.common.context.Context, 'project_id',
  1589. uuidutils.generate_uuid()):
  1590. api_listener = self.put(listener_path, body, status=403)
  1591. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  1592. self.assertEqual(self.NOT_AUTHORIZED_BODY, api_listener.json)
  1593. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1594. constants.ACTIVE)
  1595. def test_create_listeners_same_port(self):
  1596. listener1 = self.create_listener(constants.PROTOCOL_TCP, 80,
  1597. self.lb_id)
  1598. self.set_lb_status(self.lb_id)
  1599. listener2_post = {'protocol': listener1['listener']['protocol'],
  1600. 'protocol_port':
  1601. listener1['listener']['protocol_port'],
  1602. 'loadbalancer_id': self.lb_id}
  1603. body = self._build_body(listener2_post)
  1604. self.post(self.LISTENERS_PATH, body, status=409)
  1605. def test_delete(self):
  1606. listener = self.create_listener(constants.PROTOCOL_HTTP, 80,
  1607. self.lb_id)
  1608. self.set_lb_status(self.lb_id)
  1609. listener_path = self.LISTENER_PATH.format(
  1610. listener_id=listener['listener']['id'])
  1611. self.delete(listener_path)
  1612. response = self.get(listener_path)
  1613. api_listener = response.json['listener']
  1614. expected = {'name': None, 'default_pool_id': None,
  1615. 'description': None, 'admin_state_up': True,
  1616. 'operating_status': constants.ONLINE,
  1617. 'provisioning_status': constants.PENDING_DELETE,
  1618. 'connection_limit': None}
  1619. listener['listener'].update(expected)
  1620. self.assertIsNone(listener['listener'].pop('updated_at'))
  1621. self.assertIsNotNone(api_listener.pop('updated_at'))
  1622. self.assertNotEqual(listener, api_listener)
  1623. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1624. constants.PENDING_UPDATE)
  1625. self.assert_final_listener_statuses(self.lb_id, api_listener['id'],
  1626. delete=True)
  1627. # Problems with TLS certs should not block a delete
  1628. def test_delete_with_bad_tls_ref(self):
  1629. listener = self.create_listener(constants.PROTOCOL_TCP,
  1630. 443, self.lb_id)
  1631. tls_uuid = uuidutils.generate_uuid()
  1632. self.set_lb_status(self.lb_id)
  1633. self.listener_repo.update(db_api.get_session(),
  1634. listener['listener']['id'],
  1635. tls_certificate_id=tls_uuid,
  1636. protocol=constants.PROTOCOL_TERMINATED_HTTPS)
  1637. listener_path = self.LISTENER_PATH.format(
  1638. listener_id=listener['listener']['id'])
  1639. self.delete(listener_path)
  1640. response = self.get(listener_path)
  1641. api_listener = response.json['listener']
  1642. expected = {'name': None, 'default_pool_id': None,
  1643. 'description': None, 'admin_state_up': True,
  1644. 'operating_status': constants.ONLINE,
  1645. 'provisioning_status': constants.PENDING_DELETE,
  1646. 'connection_limit': None}
  1647. listener['listener'].update(expected)
  1648. self.assertIsNone(listener['listener'].pop('updated_at'))
  1649. self.assertIsNotNone(api_listener.pop('updated_at'))
  1650. self.assertNotEqual(listener, api_listener)
  1651. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1652. constants.PENDING_UPDATE)
  1653. self.assert_final_listener_statuses(self.lb_id, api_listener['id'],
  1654. delete=True)
  1655. def test_delete_authorized(self):
  1656. listener = self.create_listener(constants.PROTOCOL_HTTP, 80,
  1657. self.lb_id)
  1658. self.set_lb_status(self.lb_id)
  1659. listener_path = self.LISTENER_PATH.format(
  1660. listener_id=listener['listener']['id'])
  1661. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  1662. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  1663. self.conf.config(group='api_settings',
  1664. auth_strategy=constants.TESTING)
  1665. with mock.patch.object(octavia.common.context.Context, 'project_id',
  1666. self.project_id):
  1667. override_credentials = {
  1668. 'service_user_id': None,
  1669. 'user_domain_id': None,
  1670. 'is_admin_project': True,
  1671. 'service_project_domain_id': None,
  1672. 'service_project_id': None,
  1673. 'roles': ['load-balancer_member'],
  1674. 'user_id': None,
  1675. 'is_admin': False,
  1676. 'service_user_domain_id': None,
  1677. 'project_domain_id': None,
  1678. 'service_roles': [],
  1679. 'project_id': self.project_id}
  1680. with mock.patch(
  1681. "oslo_context.context.RequestContext.to_policy_values",
  1682. return_value=override_credentials):
  1683. self.delete(listener_path)
  1684. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  1685. response = self.get(listener_path)
  1686. api_listener = response.json['listener']
  1687. expected = {'name': None, 'default_pool_id': None,
  1688. 'description': None, 'admin_state_up': True,
  1689. 'operating_status': constants.ONLINE,
  1690. 'provisioning_status': constants.PENDING_DELETE,
  1691. 'connection_limit': None}
  1692. listener['listener'].update(expected)
  1693. self.assertIsNone(listener['listener'].pop('updated_at'))
  1694. self.assertIsNotNone(api_listener.pop('updated_at'))
  1695. self.assertNotEqual(listener, api_listener)
  1696. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1697. constants.PENDING_UPDATE)
  1698. self.assert_final_listener_statuses(self.lb_id, api_listener['id'],
  1699. delete=True)
  1700. def test_delete_not_authorized(self):
  1701. listener = self.create_listener(constants.PROTOCOL_HTTP, 80,
  1702. self.lb_id)
  1703. self.set_lb_status(self.lb_id)
  1704. listener_path = self.LISTENER_PATH.format(
  1705. listener_id=listener['listener']['id'])
  1706. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  1707. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  1708. self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
  1709. with mock.patch.object(octavia.common.context.Context, 'project_id',
  1710. uuidutils.generate_uuid()):
  1711. self.delete(listener_path, status=403)
  1712. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  1713. self.assert_correct_lb_status(self.lb_id, constants.ONLINE,
  1714. constants.ACTIVE)
  1715. def test_delete_bad_listener_id(self):
  1716. listener_path = self.LISTENER_PATH.format(listener_id='SEAN-CONNERY')
  1717. self.delete(listener_path, status=404)
  1718. def test_create_listener_bad_protocol(self):
  1719. lb_listener = {'protocol': 'SEAN_CONNERY',
  1720. 'protocol_port': 80}
  1721. self.post(self.LISTENERS_PATH, lb_listener, status=400)
  1722. def test_update_listener_bad_protocol(self):
  1723. listener = self.create_listener(constants.PROTOCOL_TCP, 80, self.lb_id)
  1724. self.set_lb_status(self.lb_id)
  1725. new_listener = {'protocol': 'SEAN_CONNERY',
  1726. 'protocol_port': 80}
  1727. listener_path = self.LISTENER_PATH.format(
  1728. listener_id=listener['listener'].get('id'))
  1729. self.put(listener_path, new_listener, status=400)
  1730. def test_update_pending_create(self):
  1731. lb = self.create_load_balancer(uuidutils.generate_uuid())
  1732. optionals = {'name': 'lb1', 'description': 'desc1',
  1733. 'admin_state_up': False}
  1734. lb.update(optionals)
  1735. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1736. 'admin_state_up': False,
  1737. 'protocol': constants.PROTOCOL_HTTP,
  1738. 'protocol_port': 80, 'connection_limit': 10,
  1739. 'loadbalancer_id': lb['loadbalancer']['id']}
  1740. body = self._build_body(lb_listener)
  1741. self.post(self.LISTENERS_PATH, body, status=409)
  1742. def test_delete_pending_update(self):
  1743. lb = self.create_load_balancer(uuidutils.generate_uuid())
  1744. optionals = {'name': 'lb1', 'description': 'desc1',
  1745. 'admin_state_up': False}
  1746. lb.update(optionals)
  1747. self.set_lb_status(lb['loadbalancer']['id'])
  1748. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1749. 'admin_state_up': False,
  1750. 'protocol': constants.PROTOCOL_HTTP,
  1751. 'protocol_port': 80, 'connection_limit': 10,
  1752. 'loadbalancer_id': lb['loadbalancer']['id']}
  1753. body = self._build_body(lb_listener)
  1754. api_listener = self.post(
  1755. self.LISTENERS_PATH, body).json['listener']
  1756. listener_path = self.LISTENER_PATH.format(
  1757. listener_id=api_listener['id'])
  1758. self.delete(listener_path, status=409)
  1759. def test_update_empty_body(self):
  1760. listener = self.create_listener(constants.PROTOCOL_TCP, 80, self.lb_id)
  1761. self.set_lb_status(self.lb_id)
  1762. listener_path = self.LISTENER_PATH.format(
  1763. listener_id=listener['listener'].get('id'))
  1764. self.put(listener_path, {}, status=400)
  1765. # TODO(johnsom) Fix this when there is a noop certificate manager
  1766. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1767. def test_update_bad_tls_ref(self, mock_cert_data):
  1768. cert2 = data_models.TLSContainer(certificate='cert 2')
  1769. cert3 = data_models.TLSContainer(certificate='cert 3')
  1770. mock_cert_data.return_value = {'sni_certs': [cert2, cert3]}
  1771. sni1 = uuidutils.generate_uuid()
  1772. sni2 = uuidutils.generate_uuid()
  1773. tls_ref = uuidutils.generate_uuid()
  1774. tls_ref2 = uuidutils.generate_uuid()
  1775. lb_listener = {'name': 'listener1', 'default_pool_id': None,
  1776. 'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  1777. 'protocol_port': 80,
  1778. 'sni_container_refs': [sni1, sni2],
  1779. 'default_tls_container_ref': tls_ref,
  1780. 'loadbalancer_id': self.lb_id}
  1781. body = self._build_body(lb_listener)
  1782. api_listener = self.post(
  1783. self.LISTENERS_PATH, body).json['listener']
  1784. self.set_lb_status(self.lb_id)
  1785. lb_listener_put = {
  1786. 'default_tls_container_ref': tls_ref2,
  1787. 'sni_container_refs': [sni1, sni2]
  1788. }
  1789. body = self._build_body(lb_listener_put)
  1790. listener_path = self.LISTENER_PATH.format(
  1791. listener_id=api_listener['id'])
  1792. self.cert_manager_mock().get_cert.side_effect = [
  1793. Exception("bad cert"), None, Exception("bad cert")]
  1794. self.cert_manager_mock().get_secret.side_effect = [
  1795. Exception("bad secret"), Exception("bad secret")]
  1796. response = self.put(listener_path, body, status=400).json
  1797. self.assertIn(tls_ref2, response['faultstring'])
  1798. self.assertIn(sni1, response['faultstring'])
  1799. self.assertNotIn(sni2, response['faultstring'])
  1800. self.assertNotIn(tls_ref, response['faultstring'])
  1801. def test_update_pending_update(self):
  1802. lb = self.create_load_balancer(uuidutils.generate_uuid())
  1803. optionals = {'name': 'lb1', 'description': 'desc1',
  1804. 'admin_state_up': False}
  1805. lb.update(optionals)
  1806. self.set_lb_status(lb['loadbalancer']['id'])
  1807. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1808. 'admin_state_up': False,
  1809. 'protocol': constants.PROTOCOL_HTTP,
  1810. 'protocol_port': 80, 'connection_limit': 10,
  1811. 'loadbalancer_id': lb['loadbalancer']['id']}
  1812. body = self._build_body(lb_listener)
  1813. api_listener = self.post(
  1814. self.LISTENERS_PATH, body).json['listener']
  1815. self.set_lb_status(lb['loadbalancer']['id'])
  1816. self.put(self.LB_PATH.format(lb_id=lb['loadbalancer']['id']),
  1817. {'loadbalancer': {'name': 'hi'}})
  1818. lb_listener_put = {'name': 'listener1_updated'}
  1819. body = self._build_body(lb_listener_put)
  1820. listener_path = self.LISTENER_PATH.format(
  1821. listener_id=api_listener['id'])
  1822. self.put(listener_path, body, status=409)
  1823. def test_update_pending_delete(self):
  1824. lb = self.create_load_balancer(uuidutils.generate_uuid(),
  1825. name='lb1', description='desc1',
  1826. admin_state_up=False)
  1827. lb_id = lb['loadbalancer'].get('id')
  1828. self.set_lb_status(lb_id)
  1829. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1830. 'admin_state_up': False,
  1831. 'protocol': constants.PROTOCOL_HTTP,
  1832. 'protocol_port': 80, 'connection_limit': 10,
  1833. 'loadbalancer_id': lb_id}
  1834. body = self._build_body(lb_listener)
  1835. api_listener = self.post(
  1836. self.LISTENERS_PATH, body).json.get(self.root_tag)
  1837. self.set_lb_status(lb_id)
  1838. self.delete(self.LB_PATH.format(lb_id=lb_id),
  1839. params={'cascade': "true"})
  1840. lb_listener_put = {'name': 'listener1_updated'}
  1841. body = self._build_body(lb_listener_put)
  1842. listener_path = self.LISTENER_PATH.format(
  1843. listener_id=api_listener['id'])
  1844. self.put(listener_path, body, status=409)
  1845. def test_update_deleted(self):
  1846. lb = self.create_load_balancer(uuidutils.generate_uuid(),
  1847. name='lb1', description='desc1',
  1848. admin_state_up=False)
  1849. lb_id = lb['loadbalancer'].get('id')
  1850. self.set_lb_status(lb_id)
  1851. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1852. 'admin_state_up': False,
  1853. 'protocol': constants.PROTOCOL_HTTP,
  1854. 'protocol_port': 80, 'connection_limit': 10,
  1855. 'loadbalancer_id': lb_id}
  1856. body = self._build_body(lb_listener)
  1857. api_listener = self.post(
  1858. self.LISTENERS_PATH, body).json.get(self.root_tag)
  1859. # This updates the child objects
  1860. self.set_lb_status(lb_id, status=constants.DELETED)
  1861. lb_listener_put = {'name': 'listener1_updated'}
  1862. body = self._build_body(lb_listener_put)
  1863. listener_path = self.LISTENER_PATH.format(
  1864. listener_id=api_listener['id'])
  1865. self.put(listener_path, body, status=404)
  1866. def test_delete_pending_delete(self):
  1867. lb = self.create_load_balancer(uuidutils.generate_uuid(),
  1868. name='lb1', description='desc1',
  1869. admin_state_up=False)
  1870. lb_id = lb['loadbalancer'].get('id')
  1871. self.set_lb_status(lb_id)
  1872. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1873. 'admin_state_up': False,
  1874. 'protocol': constants.PROTOCOL_HTTP,
  1875. 'protocol_port': 80, 'connection_limit': 10,
  1876. 'loadbalancer_id': lb_id}
  1877. body = self._build_body(lb_listener)
  1878. api_listener = self.post(
  1879. self.LISTENERS_PATH, body).json.get(self.root_tag)
  1880. self.set_lb_status(lb_id)
  1881. self.delete(self.LB_PATH.format(lb_id=lb_id),
  1882. params={'cascade': "true"})
  1883. listener_path = self.LISTENER_PATH.format(
  1884. listener_id=api_listener['id'])
  1885. self.delete(listener_path, status=409)
  1886. def test_delete_already_deleted(self):
  1887. lb = self.create_load_balancer(uuidutils.generate_uuid(),
  1888. name='lb1', description='desc1',
  1889. admin_state_up=False)
  1890. lb_id = lb['loadbalancer'].get('id')
  1891. self.set_lb_status(lb_id)
  1892. lb_listener = {'name': 'listener1', 'description': 'desc1',
  1893. 'admin_state_up': False,
  1894. 'protocol': constants.PROTOCOL_HTTP,
  1895. 'protocol_port': 80, 'connection_limit': 10,
  1896. 'loadbalancer_id': lb_id}
  1897. body = self._build_body(lb_listener)
  1898. api_listener = self.post(
  1899. self.LISTENERS_PATH, body).json.get(self.root_tag)
  1900. # This updates the child objects
  1901. self.set_lb_status(lb_id, status=constants.DELETED)
  1902. listener_path = self.LISTENER_PATH.format(
  1903. listener_id=api_listener['id'])
  1904. self.delete(listener_path, status=404)
  1905. # TODO(johnsom) Fix this when there is a noop certificate manager
  1906. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1907. def test_create_with_tls_termination_data(self, mock_cert_data):
  1908. cert1 = data_models.TLSContainer(certificate='cert 1')
  1909. cert2 = data_models.TLSContainer(certificate='cert 2')
  1910. cert3 = data_models.TLSContainer(certificate='cert 3')
  1911. mock_cert_data.return_value = {'tls_cert': cert1,
  1912. 'sni_certs': [cert2, cert3]}
  1913. cert_id = uuidutils.generate_uuid()
  1914. listener = self.create_listener(constants.PROTOCOL_TERMINATED_HTTPS,
  1915. 80, self.lb_id,
  1916. default_tls_container_ref=cert_id)
  1917. listener_path = self.LISTENER_PATH.format(
  1918. listener_id=listener['listener']['id'])
  1919. get_listener = self.get(listener_path).json['listener']
  1920. self.assertEqual(cert_id, get_listener['default_tls_container_ref'])
  1921. # TODO(johnsom) Fix this when there is a noop certificate manager
  1922. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1923. def test_update_with_tls_termination_data(self, mock_cert_data):
  1924. cert_id_orig = uuidutils.generate_uuid()
  1925. cert1 = data_models.TLSContainer(certificate='cert 1')
  1926. mock_cert_data.return_value = {'tls_cert': cert1}
  1927. cert_id = uuidutils.generate_uuid()
  1928. listener = self.create_listener(
  1929. constants.PROTOCOL_TERMINATED_HTTPS, 80, self.lb_id,
  1930. default_tls_container_ref=cert_id_orig)
  1931. self.set_lb_status(self.lb_id)
  1932. listener_path = self.LISTENER_PATH.format(
  1933. listener_id=listener['listener']['id'])
  1934. get_listener = self.get(listener_path).json['listener']
  1935. self.assertEqual(cert_id_orig,
  1936. get_listener.get('default_tls_container_ref'))
  1937. self.put(listener_path,
  1938. self._build_body({'default_tls_container_ref': cert_id}))
  1939. get_listener = self.get(listener_path).json['listener']
  1940. self.assertEqual(cert_id,
  1941. get_listener.get('default_tls_container_ref'))
  1942. def test_create_with_tls_termination_disabled(self):
  1943. self.conf.config(group='api_settings',
  1944. allow_tls_terminated_listeners=False)
  1945. cert_id = uuidutils.generate_uuid()
  1946. listener = self.create_listener(constants.PROTOCOL_TERMINATED_HTTPS,
  1947. 80, self.lb_id,
  1948. default_tls_container_ref=cert_id,
  1949. status=400)
  1950. self.assertIn(
  1951. 'The selected protocol is not allowed in this deployment: {0}'
  1952. .format(constants.PROTOCOL_TERMINATED_HTTPS),
  1953. listener.get('faultstring'))
  1954. # TODO(johnsom) Fix this when there is a noop certificate manager
  1955. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1956. def test_create_with_sni_data(self, mock_cert_data):
  1957. cert1 = data_models.TLSContainer(certificate='cert 1')
  1958. cert2 = data_models.TLSContainer(certificate='cert 2')
  1959. cert3 = data_models.TLSContainer(certificate='cert 3')
  1960. mock_cert_data.return_value = {'tls_cert': cert1,
  1961. 'sni_certs': [cert2, cert3]}
  1962. sni_id1 = uuidutils.generate_uuid()
  1963. sni_id2 = uuidutils.generate_uuid()
  1964. listener = self.create_listener(constants.PROTOCOL_TERMINATED_HTTPS,
  1965. 80, self.lb_id,
  1966. sni_container_refs=[sni_id1, sni_id2])
  1967. listener_path = self.LISTENER_PATH.format(
  1968. listener_id=listener['listener']['id'])
  1969. get_listener = self.get(listener_path).json['listener']
  1970. self.assertItemsEqual([sni_id1, sni_id2],
  1971. get_listener['sni_container_refs'])
  1972. # TODO(johnsom) Fix this when there is a noop certificate manager
  1973. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1974. def test_update_with_sni_data(self, mock_cert_data):
  1975. cert2 = data_models.TLSContainer(certificate='cert 2')
  1976. cert3 = data_models.TLSContainer(certificate='cert 3')
  1977. mock_cert_data.return_value = {'sni_certs': [cert2, cert3]}
  1978. sni_id1 = uuidutils.generate_uuid()
  1979. sni_id2 = uuidutils.generate_uuid()
  1980. listener = self.create_listener(constants.PROTOCOL_HTTP, 80,
  1981. self.lb_id)
  1982. self.set_lb_status(self.lb_id)
  1983. listener_path = self.LISTENER_PATH.format(
  1984. listener_id=listener['listener']['id'])
  1985. get_listener = self.get(listener_path).json['listener']
  1986. self.assertEqual([], get_listener.get('sni_container_refs'))
  1987. self.put(listener_path,
  1988. self._build_body({'sni_container_refs': [sni_id1, sni_id2]}))
  1989. get_listener = self.get(listener_path).json['listener']
  1990. self.assertEqual([], get_listener.get('sni_container_refs'))
  1991. # TODO(johnsom) Fix this when there is a noop certificate manager
  1992. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  1993. def test_create_with_valid_insert_headers(self, mock_cert_data):
  1994. cert1 = data_models.TLSContainer(certificate='cert 1')
  1995. mock_cert_data.return_value = {'tls_cert': cert1}
  1996. lb_listener = {'protocol': 'HTTP',
  1997. 'protocol_port': 80,
  1998. 'loadbalancer_id': self.lb_id,
  1999. 'insert_headers': {'X-Forwarded-For': 'true'}}
  2000. body = self._build_body(lb_listener)
  2001. self.post(self.LISTENERS_PATH, body, status=201)
  2002. # test client certificate http headers
  2003. self.set_lb_status(self.lb_id)
  2004. header = {}
  2005. for name in constants.SUPPORTED_SSL_HEADERS:
  2006. header[name] = 'true'
  2007. lb_listener = {'protocol': constants.PROTOCOL_TERMINATED_HTTPS,
  2008. 'protocol_port': 1801,
  2009. 'loadbalancer_id': self.lb_id,
  2010. 'insert_headers': header,
  2011. 'default_tls_container_ref': uuidutils.generate_uuid()}
  2012. body = self._build_body(lb_listener)
  2013. self.post(self.LISTENERS_PATH, body, status=201)
  2014. def test_create_with_bad_insert_headers(self):
  2015. lb_listener = {'protocol': constants.PROTOCOL_HTTP,
  2016. 'protocol_port': 80,
  2017. 'loadbalancer_id': self.lb_id,
  2018. 'insert_headers': {'X-Forwarded-Four': 'true'}}
  2019. body = self._build_body(lb_listener)
  2020. self.post(self.LISTENERS_PATH, body, status=400)
  2021. # test client certificate http headers
  2022. for name in constants.SUPPORTED_SSL_HEADERS:
  2023. header = {}
  2024. header[name] = 'true'
  2025. lb_listener['insert_headers'] = header
  2026. body = self._build_body(lb_listener)
  2027. listener = self.post(self.LISTENERS_PATH, body, status=400).json
  2028. self.assertIn('{0} is not a valid option for {1}'.format(
  2029. [name],
  2030. '%s protocol listener.' % constants.PROTOCOL_HTTP),
  2031. listener.get('faultstring'))
  2032. @mock.patch('octavia.common.tls_utils.cert_parser.load_certificates_data')
  2033. def test_update_with_valid_insert_headers(self, mock_cert_data):
  2034. cert1 = data_models.TLSContainer(certificate='cert 1')
  2035. mock_cert_data.return_value = {'tls_cert': cert1}
  2036. listener = self.create_listener(
  2037. constants.PROTOCOL_HTTP, 80, self.lb_id)
  2038. self.set_lb_status(self.lb_id)
  2039. new_listener = self._build_body(
  2040. {'insert_headers': {'X-Forwarded-For': 'true'}})
  2041. listener_path = self.LISTENER_PATH.format(
  2042. listener_id=listener['listener'].get('id'))
  2043. update_listener = self.put(
  2044. listener_path, new_listener, status=200).json
  2045. self.assertNotEqual(
  2046. listener[self.root_tag]['insert_headers'],
  2047. update_listener[self.root_tag]['insert_headers'])
  2048. self.set_lb_status(self.lb_id)
  2049. # test client certificate http headers
  2050. cert1_id = uuidutils.generate_uuid()
  2051. listener = self.create_listener(
  2052. constants.PROTOCOL_TERMINATED_HTTPS, 443, self.lb_id,
  2053. default_tls_container_ref=cert1_id)
  2054. self.set_lb_status(self.lb_id)
  2055. header = {}
  2056. for name in constants.SUPPORTED_SSL_HEADERS:
  2057. header[name] = 'true'
  2058. new_listener[self.root_tag]['insert_headers'] = header
  2059. listener_path = self.LISTENER_PATH.format(
  2060. listener_id=listener['listener'].get('id'))
  2061. update_listener = self.put(
  2062. listener_path, new_listener, status=200).json
  2063. self.assertNotEqual(
  2064. listener[self.root_tag]['insert_headers'],
  2065. update_listener[self.root_tag]['insert_headers'])
  2066. def test_update_with_bad_insert_headers(self):
  2067. listener = self.create_listener(
  2068. constants.PROTOCOL_HTTP, 80, self.lb_id)
  2069. self.set_lb_status(self.lb_id)
  2070. new_listener = self._build_body(
  2071. {'insert_headers': {'X-Bad-Header': 'true'}})
  2072. listener_path = self.LISTENER_PATH.format(
  2073. listener_id=listener['listener'].get('id'))
  2074. update_listener = self.put(
  2075. listener_path, new_listener, status=400).json
  2076. self.assertIn('{0} is not a valid option for {1}'.format(
  2077. '[\'X-Bad-Header\']', 'insert_headers'),
  2078. update_listener.get('faultstring'))
  2079. # test client certificate http headers
  2080. header = {}
  2081. for name in constants.SUPPORTED_SSL_HEADERS:
  2082. header[name] = 'true'
  2083. new_listener[self.root_tag]['insert_headers'] = header
  2084. # as the order of output faultstring is not stable, so we just check
  2085. # the status.
  2086. self.put(listener_path, new_listener, status=400).json
  2087. def _getStats(self, listener_id):
  2088. res = self.get(self.LISTENER_PATH.format(
  2089. listener_id=listener_id + "/stats"))
  2090. return res.json.get('stats')
  2091. def test_statistics(self):
  2092. lb = self.create_load_balancer(
  2093. uuidutils.generate_uuid()).get('loadbalancer')
  2094. self.set_lb_status(lb['id'])
  2095. li = self.create_listener(
  2096. constants.PROTOCOL_HTTP, 80, lb.get('id')).get('listener')
  2097. amphora = self.create_amphora(uuidutils.generate_uuid(), lb['id'])
  2098. ls = self.create_listener_stats_dynamic(
  2099. listener_id=li.get('id'),
  2100. amphora_id=amphora.id,
  2101. bytes_in=random.randint(1, 9),
  2102. bytes_out=random.randint(1, 9),
  2103. total_connections=random.randint(1, 9),
  2104. request_errors=random.randint(1, 9))
  2105. response = self._getStats(li['id'])
  2106. self.assertEqual(ls['bytes_in'], response['bytes_in'])
  2107. self.assertEqual(ls['bytes_out'], response['bytes_out'])
  2108. self.assertEqual(ls['total_connections'],
  2109. response['total_connections'])
  2110. self.assertEqual(ls['active_connections'],
  2111. response['active_connections'])
  2112. self.assertEqual(ls['request_errors'],
  2113. response['request_errors'])
  2114. def test_statistics_authorized(self):
  2115. project_id = uuidutils.generate_uuid()
  2116. lb = self.create_load_balancer(
  2117. uuidutils.generate_uuid(),
  2118. project_id=project_id).get('loadbalancer')
  2119. self.set_lb_status(lb['id'])
  2120. li = self.create_listener(
  2121. constants.PROTOCOL_HTTP, 80, lb.get('id')).get('listener')
  2122. amphora = self.create_amphora(uuidutils.generate_uuid(), lb['id'])
  2123. ls = self.create_listener_stats_dynamic(
  2124. listener_id=li.get('id'),
  2125. amphora_id=amphora.id,
  2126. bytes_in=random.randint(1, 9),
  2127. bytes_out=random.randint(1, 9),
  2128. total_connections=random.randint(1, 9),
  2129. request_errors=random.randint(1, 9))
  2130. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  2131. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  2132. self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
  2133. with mock.patch.object(octavia.common.context.Context, 'project_id',
  2134. project_id):
  2135. override_credentials = {
  2136. 'service_user_id': None,
  2137. 'user_domain_id': None,
  2138. 'is_admin_project': True,
  2139. 'service_project_domain_id': None,
  2140. 'service_project_id': None,
  2141. 'roles': ['load-balancer_member'],
  2142. 'user_id': None,
  2143. 'is_admin': False,
  2144. 'service_user_domain_id': None,
  2145. 'project_domain_id': None,
  2146. 'service_roles': [],
  2147. 'project_id': project_id}
  2148. with mock.patch(
  2149. "oslo_context.context.RequestContext.to_policy_values",
  2150. return_value=override_credentials):
  2151. response = self._getStats(li['id'])
  2152. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  2153. self.assertEqual(ls['bytes_in'], response['bytes_in'])
  2154. self.assertEqual(ls['bytes_out'], response['bytes_out'])
  2155. self.assertEqual(ls['total_connections'],
  2156. response['total_connections'])
  2157. self.assertEqual(ls['active_connections'],
  2158. response['active_connections'])
  2159. self.assertEqual(ls['request_errors'],
  2160. response['request_errors'])
  2161. def test_statistics_not_authorized(self):
  2162. lb = self.create_load_balancer(
  2163. uuidutils.generate_uuid()).get('loadbalancer')
  2164. self.set_lb_status(lb['id'])
  2165. li = self.create_listener(
  2166. constants.PROTOCOL_HTTP, 80, lb.get('id')).get('listener')
  2167. amphora = self.create_amphora(uuidutils.generate_uuid(), lb['id'])
  2168. self.create_listener_stats_dynamic(
  2169. listener_id=li.get('id'),
  2170. amphora_id=amphora.id,
  2171. bytes_in=random.randint(1, 9),
  2172. bytes_out=random.randint(1, 9),
  2173. total_connections=random.randint(1, 9),
  2174. request_errors=random.randint(1, 9))
  2175. self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
  2176. auth_strategy = self.conf.conf.api_settings.get('auth_strategy')
  2177. self.conf.config(group='api_settings', auth_strategy=constants.TESTING)
  2178. with mock.patch.object(octavia.common.context.Context, 'project_id',
  2179. uuidutils.generate_uuid()):
  2180. res = self.get(self.LISTENER_PATH.format(
  2181. listener_id=li['id'] + "/stats"), status=403)
  2182. self.conf.config(group='api_settings', auth_strategy=auth_strategy)
  2183. self.assertEqual(self.NOT_AUTHORIZED_BODY, res.json)
  2184. def test_statistics_get_deleted(self):
  2185. lb = self.create_load_balancer(
  2186. uuidutils.generate_uuid()).get('loadbalancer')
  2187. self.set_lb_status(lb['id'])
  2188. li = self.create_listener(
  2189. constants.PROTOCOL_HTTP, 80, lb.get('id')).get('listener')
  2190. amphora = self.create_amphora(uuidutils.generate_uuid(), lb['id'])
  2191. self.create_listener_stats_dynamic(
  2192. listener_id=li.get('id'),
  2193. amphora_id=amphora.id,
  2194. bytes_in=random.randint(1, 9),
  2195. bytes_out=random.randint(1, 9),
  2196. total_connections=random.randint(1, 9),
  2197. request_errors=random.randint(1, 9))
  2198. self.set_lb_status(lb['id'], status=constants.DELETED)
  2199. self.get(self.LISTENER_PATH.format(
  2200. listener_id=li.get('id') + "/stats"), status=404)