octavia 13.0.0__py3-none-any.whl → 13.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. octavia/amphorae/backends/agent/api_server/keepalivedlvs.py +9 -0
  2. octavia/amphorae/backends/agent/api_server/osutils.py +1 -2
  3. octavia/amphorae/backends/agent/api_server/util.py +35 -2
  4. octavia/amphorae/backends/utils/interface.py +4 -5
  5. octavia/amphorae/drivers/driver_base.py +16 -0
  6. octavia/amphorae/drivers/haproxy/rest_api_driver.py +13 -8
  7. octavia/amphorae/drivers/keepalived/jinja/jinja_cfg.py +0 -1
  8. octavia/amphorae/drivers/keepalived/jinja/templates/keepalived_base.template +0 -1
  9. octavia/amphorae/drivers/keepalived/vrrp_rest_driver.py +2 -1
  10. octavia/amphorae/drivers/noop_driver/driver.py +3 -0
  11. octavia/api/common/pagination.py +1 -1
  12. octavia/api/v2/controllers/health_monitor.py +3 -2
  13. octavia/api/v2/controllers/l7policy.py +0 -1
  14. octavia/api/v2/controllers/l7rule.py +0 -1
  15. octavia/api/v2/controllers/listener.py +0 -1
  16. octavia/api/v2/controllers/load_balancer.py +13 -7
  17. octavia/api/v2/controllers/member.py +18 -5
  18. octavia/api/v2/controllers/pool.py +6 -7
  19. octavia/api/v2/types/pool.py +1 -1
  20. octavia/certificates/common/pkcs12.py +9 -9
  21. octavia/certificates/manager/barbican.py +24 -16
  22. octavia/certificates/manager/castellan_mgr.py +12 -7
  23. octavia/certificates/manager/noop.py +106 -0
  24. octavia/common/clients.py +22 -4
  25. octavia/common/config.py +21 -5
  26. octavia/common/constants.py +4 -0
  27. octavia/common/exceptions.py +6 -0
  28. octavia/common/jinja/haproxy/combined_listeners/templates/macros.j2 +7 -5
  29. octavia/common/keystone.py +7 -7
  30. octavia/common/tls_utils/cert_parser.py +23 -9
  31. octavia/controller/worker/task_utils.py +28 -6
  32. octavia/controller/worker/v2/controller_worker.py +2 -2
  33. octavia/controller/worker/v2/flows/amphora_flows.py +41 -10
  34. octavia/controller/worker/v2/flows/flow_utils.py +6 -4
  35. octavia/controller/worker/v2/flows/load_balancer_flows.py +17 -3
  36. octavia/controller/worker/v2/tasks/amphora_driver_tasks.py +114 -23
  37. octavia/controller/worker/v2/tasks/database_tasks.py +36 -47
  38. octavia/controller/worker/v2/tasks/lifecycle_tasks.py +96 -40
  39. octavia/controller/worker/v2/tasks/network_tasks.py +12 -13
  40. octavia/db/base_models.py +16 -4
  41. octavia/db/repositories.py +34 -33
  42. octavia/network/drivers/neutron/allowed_address_pairs.py +10 -8
  43. octavia/network/drivers/noop_driver/driver.py +1 -2
  44. octavia/tests/common/sample_certs.py +115 -0
  45. octavia/tests/functional/api/v2/base.py +1 -1
  46. octavia/tests/functional/api/v2/test_health_monitor.py +18 -0
  47. octavia/tests/functional/api/v2/test_listener.py +45 -0
  48. octavia/tests/functional/api/v2/test_member.py +32 -0
  49. octavia/tests/functional/db/base.py +9 -0
  50. octavia/tests/functional/db/test_repositories.py +45 -98
  51. octavia/tests/unit/amphorae/backends/agent/api_server/test_util.py +89 -1
  52. octavia/tests/unit/amphorae/backends/utils/test_interface.py +3 -1
  53. octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver.py +3 -3
  54. octavia/tests/unit/amphorae/drivers/keepalived/jinja/test_jinja_cfg.py +0 -4
  55. octavia/tests/unit/amphorae/drivers/keepalived/test_vrrp_rest_driver.py +17 -0
  56. octavia/tests/unit/api/common/test_pagination.py +78 -1
  57. octavia/tests/unit/api/v2/types/test_pool.py +71 -0
  58. octavia/tests/unit/certificates/manager/test_barbican.py +3 -3
  59. octavia/tests/unit/certificates/manager/test_noop.py +53 -0
  60. octavia/tests/unit/cmd/test_prometheus_proxy.py +8 -1
  61. octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py +16 -17
  62. octavia/tests/unit/common/test_config.py +35 -0
  63. octavia/tests/unit/common/test_keystone.py +32 -0
  64. octavia/tests/unit/controller/worker/test_task_utils.py +58 -2
  65. octavia/tests/unit/controller/worker/v2/flows/test_amphora_flows.py +28 -5
  66. octavia/tests/unit/controller/worker/v2/flows/test_load_balancer_flows.py +10 -5
  67. octavia/tests/unit/controller/worker/v2/tasks/test_amphora_driver_tasks.py +234 -17
  68. octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks.py +28 -6
  69. octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks_quota.py +19 -19
  70. octavia/tests/unit/controller/worker/v2/tasks/test_network_tasks.py +57 -2
  71. octavia/tests/unit/controller/worker/v2/test_controller_worker.py +56 -1
  72. octavia/tests/unit/network/drivers/neutron/test_allowed_address_pairs.py +24 -1
  73. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/AUTHORS +8 -0
  74. octavia-13.0.1.dist-info/METADATA +155 -0
  75. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/RECORD +90 -88
  76. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/WHEEL +1 -1
  77. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/entry_points.txt +1 -1
  78. octavia-13.0.1.dist-info/pbr.json +1 -0
  79. octavia-13.0.0.dist-info/METADATA +0 -158
  80. octavia-13.0.0.dist-info/pbr.json +0 -1
  81. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/LICENSE +0 -0
  82. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/README.rst +0 -0
  83. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/README.rst +0 -0
  84. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/diskimage-create.sh +0 -0
  85. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/image-tests.sh +0 -0
  86. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/requirements.txt +0 -0
  87. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/test-requirements.txt +0 -0
  88. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/tox.ini +0 -0
  89. {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/version.txt +0 -0
  90. {octavia-13.0.0.data → octavia-13.0.1.data}/scripts/octavia-wsgi +0 -0
  91. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/LICENSE +0 -0
  92. {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,7 @@
14
14
  from unittest import mock
15
15
 
16
16
  from oslo_utils import uuidutils
17
+ import tenacity
17
18
 
18
19
  from octavia.common import constants
19
20
  from octavia.controller.worker import task_utils as task_utilities
@@ -183,7 +184,13 @@ class TestTaskUtils(base.TestCase):
183
184
 
184
185
  @mock.patch('octavia.db.api.session')
185
186
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.update')
187
+ @mock.patch('tenacity.nap.time')
188
+ # mock LOG so we don't fill the console with log messages from
189
+ # tenacity.retry
190
+ @mock.patch('octavia.controller.worker.task_utils.LOG')
186
191
  def test_mark_loadbalancer_prov_status_active(self,
192
+ mock_LOG,
193
+ mock_time,
187
194
  mock_lb_repo_update,
188
195
  mock_get_session):
189
196
 
@@ -202,14 +209,42 @@ class TestTaskUtils(base.TestCase):
202
209
  mock_lb_repo_update.reset_mock()
203
210
  mock_get_session.side_effect = Exception('fail')
204
211
 
205
- self.task_utils.mark_loadbalancer_prov_status_active(
212
+ self.assertRaises(
213
+ tenacity.RetryError,
214
+ self.task_utils.mark_loadbalancer_prov_status_active,
206
215
  self.LOADBALANCER_ID)
207
216
 
208
217
  self.assertFalse(mock_lb_repo_update.called)
209
218
 
219
+ # Exceptions then happy path
220
+ mock_get_session.reset_mock(side_effect=True)
221
+ mock_lb_repo_update.reset_mock()
222
+
223
+ mock_session = mock_get_session()
224
+ mock_session_context = mock_session.begin().__enter__()
225
+ mock_get_session.side_effect = [
226
+ Exception('fail'),
227
+ Exception('fail'),
228
+ Exception('fail'),
229
+ mock_session]
230
+
231
+ self.task_utils.mark_loadbalancer_prov_status_active(
232
+ self.LOADBALANCER_ID)
233
+
234
+ mock_lb_repo_update.assert_called_once_with(
235
+ mock_session_context,
236
+ id=self.LOADBALANCER_ID,
237
+ provisioning_status=constants.ACTIVE)
238
+
210
239
  @mock.patch('octavia.db.api.session')
211
240
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.update')
241
+ @mock.patch('tenacity.nap.time')
242
+ # mock LOG so we don't fill the console with log messages from
243
+ # tenacity.retry
244
+ @mock.patch('octavia.controller.worker.task_utils.LOG')
212
245
  def test_mark_loadbalancer_prov_status_error(self,
246
+ mock_LOG,
247
+ mock_time,
213
248
  mock_lb_repo_update,
214
249
  mock_get_session):
215
250
 
@@ -228,10 +263,31 @@ class TestTaskUtils(base.TestCase):
228
263
  mock_lb_repo_update.reset_mock()
229
264
  mock_get_session.side_effect = Exception('fail')
230
265
 
266
+ self.assertRaises(tenacity.RetryError,
267
+ self.task_utils.mark_loadbalancer_prov_status_error,
268
+ self.LOADBALANCER_ID)
269
+
270
+ self.assertFalse(mock_lb_repo_update.called)
271
+
272
+ # Exceptions then happy path
273
+ mock_get_session.reset_mock(side_effect=True)
274
+ mock_lb_repo_update.reset_mock()
275
+
276
+ mock_session = mock_get_session()
277
+ mock_session_context = mock_session.begin().__enter__()
278
+ mock_get_session.side_effect = [
279
+ Exception('fail'),
280
+ Exception('fail'),
281
+ Exception('fail'),
282
+ mock_session]
283
+
231
284
  self.task_utils.mark_loadbalancer_prov_status_error(
232
285
  self.LOADBALANCER_ID)
233
286
 
234
- self.assertFalse(mock_lb_repo_update.called)
287
+ mock_lb_repo_update.assert_called_once_with(
288
+ mock_session_context,
289
+ id=self.LOADBALANCER_ID,
290
+ provisioning_status=constants.ERROR)
235
291
 
236
292
  @mock.patch('octavia.db.api.session')
237
293
  @mock.patch('octavia.db.repositories.MemberRepository.update')
@@ -286,6 +286,7 @@ class TestAmphoraFlows(base.TestCase):
286
286
  self.assertIn(constants.AMPHORA, amp_flow.provides)
287
287
  self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
288
288
  self.assertIn(constants.AMPHORAE, amp_flow.provides)
289
+ self.assertIn(constants.AMPHORAE_STATUS, amp_flow.provides)
289
290
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, amp_flow.provides)
290
291
  self.assertIn(constants.BASE_PORT, amp_flow.provides)
291
292
  self.assertIn(constants.COMPUTE_ID, amp_flow.provides)
@@ -296,7 +297,7 @@ class TestAmphoraFlows(base.TestCase):
296
297
  self.assertIn(constants.VIP_SG_ID, amp_flow.provides)
297
298
 
298
299
  self.assertEqual(8, len(amp_flow.requires))
299
- self.assertEqual(13, len(amp_flow.provides))
300
+ self.assertEqual(14, len(amp_flow.provides))
300
301
 
301
302
  def test_get_failover_flow_standalone(self, mock_get_net_driver):
302
303
  failed_amphora = data_models.Amphora(
@@ -320,6 +321,7 @@ class TestAmphoraFlows(base.TestCase):
320
321
  self.assertIn(constants.AMPHORA, amp_flow.provides)
321
322
  self.assertIn(constants.AMPHORA_ID, amp_flow.provides)
322
323
  self.assertIn(constants.AMPHORAE, amp_flow.provides)
324
+ self.assertIn(constants.AMPHORAE_STATUS, amp_flow.provides)
323
325
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, amp_flow.provides)
324
326
  self.assertIn(constants.BASE_PORT, amp_flow.provides)
325
327
  self.assertIn(constants.COMPUTE_ID, amp_flow.provides)
@@ -330,7 +332,7 @@ class TestAmphoraFlows(base.TestCase):
330
332
  self.assertIn(constants.VIP_SG_ID, amp_flow.provides)
331
333
 
332
334
  self.assertEqual(8, len(amp_flow.requires))
333
- self.assertEqual(12, len(amp_flow.provides))
335
+ self.assertEqual(13, len(amp_flow.provides))
334
336
 
335
337
  def test_get_failover_flow_bogus_role(self, mock_get_net_driver):
336
338
  failed_amphora = data_models.Amphora(id=uuidutils.generate_uuid(),
@@ -366,14 +368,33 @@ class TestAmphoraFlows(base.TestCase):
366
368
 
367
369
  self.assertIsInstance(vrrp_subflow, flow.Flow)
368
370
 
371
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, vrrp_subflow.provides)
372
+ self.assertIn(constants.AMP_VRRP_INT, vrrp_subflow.provides)
373
+ self.assertIn(constants.AMPHORAE_STATUS, vrrp_subflow.provides)
374
+
375
+ self.assertIn(constants.LOADBALANCER_ID, vrrp_subflow.requires)
376
+ self.assertIn(constants.AMPHORAE, vrrp_subflow.requires)
377
+ self.assertIn(constants.AMPHORA_ID, vrrp_subflow.requires)
378
+
379
+ self.assertEqual(3, len(vrrp_subflow.provides))
380
+ self.assertEqual(3, len(vrrp_subflow.requires))
381
+
382
+ def test_get_vrrp_subflow_dont_get_status(self, mock_get_net_driver):
383
+ vrrp_subflow = self.AmpFlow.get_vrrp_subflow('123',
384
+ get_amphorae_status=False)
385
+
386
+ self.assertIsInstance(vrrp_subflow, flow.Flow)
387
+
369
388
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, vrrp_subflow.provides)
370
389
  self.assertIn(constants.AMP_VRRP_INT, vrrp_subflow.provides)
371
390
 
372
391
  self.assertIn(constants.LOADBALANCER_ID, vrrp_subflow.requires)
373
392
  self.assertIn(constants.AMPHORAE, vrrp_subflow.requires)
393
+ self.assertIn(constants.AMPHORA_ID, vrrp_subflow.requires)
394
+ self.assertIn(constants.AMPHORAE_STATUS, vrrp_subflow.requires)
374
395
 
375
396
  self.assertEqual(2, len(vrrp_subflow.provides))
376
- self.assertEqual(2, len(vrrp_subflow.requires))
397
+ self.assertEqual(4, len(vrrp_subflow.requires))
377
398
 
378
399
  def test_get_vrrp_subflow_dont_create_vrrp_group(
379
400
  self, mock_get_net_driver):
@@ -384,12 +405,14 @@ class TestAmphoraFlows(base.TestCase):
384
405
 
385
406
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, vrrp_subflow.provides)
386
407
  self.assertIn(constants.AMP_VRRP_INT, vrrp_subflow.provides)
408
+ self.assertIn(constants.AMPHORAE_STATUS, vrrp_subflow.provides)
387
409
 
388
410
  self.assertIn(constants.LOADBALANCER_ID, vrrp_subflow.requires)
389
411
  self.assertIn(constants.AMPHORAE, vrrp_subflow.requires)
412
+ self.assertIn(constants.AMPHORA_ID, vrrp_subflow.requires)
390
413
 
391
- self.assertEqual(2, len(vrrp_subflow.provides))
392
- self.assertEqual(2, len(vrrp_subflow.requires))
414
+ self.assertEqual(3, len(vrrp_subflow.provides))
415
+ self.assertEqual(3, len(vrrp_subflow.requires))
393
416
 
394
417
  def test_update_amphora_config_flow(self, mock_get_net_driver):
395
418
 
@@ -199,14 +199,16 @@ class TestLoadBalancerFlows(base.TestCase):
199
199
 
200
200
  self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
201
201
  self.assertIn(constants.UPDATE_DICT, amp_flow.requires)
202
+ self.assertIn(constants.AMPHORA_ID, amp_flow.requires)
202
203
 
203
204
  self.assertIn(constants.AMPHORAE, amp_flow.provides)
205
+ self.assertIn(constants.AMPHORAE_STATUS, amp_flow.provides)
204
206
  self.assertIn(constants.AMP_VRRP_INT, amp_flow.provides)
205
207
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, amp_flow.provides)
206
208
  self.assertIn(constants.LOADBALANCER, amp_flow.provides)
207
209
 
208
- self.assertEqual(2, len(amp_flow.requires), amp_flow.requires)
209
- self.assertEqual(4, len(amp_flow.provides), amp_flow.provides)
210
+ self.assertEqual(3, len(amp_flow.requires), amp_flow.requires)
211
+ self.assertEqual(5, len(amp_flow.provides), amp_flow.provides)
210
212
 
211
213
  amp_flow = self.LBFlow.get_post_lb_amp_association_flow(
212
214
  '123', constants.TOPOLOGY_ACTIVE_STANDBY)
@@ -215,14 +217,16 @@ class TestLoadBalancerFlows(base.TestCase):
215
217
 
216
218
  self.assertIn(constants.LOADBALANCER_ID, amp_flow.requires)
217
219
  self.assertIn(constants.UPDATE_DICT, amp_flow.requires)
220
+ self.assertIn(constants.AMPHORA_ID, amp_flow.requires)
218
221
 
219
222
  self.assertIn(constants.AMPHORAE, amp_flow.provides)
223
+ self.assertIn(constants.AMPHORAE_STATUS, amp_flow.provides)
220
224
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, amp_flow.provides)
221
225
  self.assertIn(constants.AMP_VRRP_INT, amp_flow.provides)
222
226
  self.assertIn(constants.LOADBALANCER, amp_flow.provides)
223
227
 
224
- self.assertEqual(2, len(amp_flow.requires), amp_flow.requires)
225
- self.assertEqual(4, len(amp_flow.provides), amp_flow.provides)
228
+ self.assertEqual(3, len(amp_flow.requires), amp_flow.requires)
229
+ self.assertEqual(5, len(amp_flow.provides), amp_flow.provides)
226
230
 
227
231
  @mock.patch('octavia.common.rpc.NOTIFIER',
228
232
  new_callable=MockNOTIFIER)
@@ -285,6 +289,7 @@ class TestLoadBalancerFlows(base.TestCase):
285
289
  self.assertIn(constants.AMPHORA_ID, create_flow.provides)
286
290
  self.assertIn(constants.AMPHORA_NETWORK_CONFIG, create_flow.provides)
287
291
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG, create_flow.provides)
292
+ self.assertIn(constants.AMPHORAE_STATUS, create_flow.provides)
288
293
  self.assertIn(constants.COMPUTE_ID, create_flow.provides)
289
294
  self.assertIn(constants.COMPUTE_OBJ, create_flow.provides)
290
295
  self.assertIn(constants.DELTAS, create_flow.provides)
@@ -296,7 +301,7 @@ class TestLoadBalancerFlows(base.TestCase):
296
301
  self.assertIn(constants.ADDITIONAL_VIPS, create_flow.provides)
297
302
 
298
303
  self.assertEqual(6, len(create_flow.requires), create_flow.requires)
299
- self.assertEqual(17, len(create_flow.provides),
304
+ self.assertEqual(18, len(create_flow.provides),
300
305
  create_flow.provides)
301
306
 
302
307
  def _test_get_failover_LB_flow_single(self, amphorae):
@@ -132,21 +132,54 @@ class TestAmphoraDriverTasks(base.TestCase):
132
132
 
133
133
  mock_amphora_repo_get.return_value = _db_amphora_mock
134
134
  mock_lb_get.return_value = _db_load_balancer_mock
135
+ amphorae_status = {
136
+ _amphora_mock[constants.ID]: {
137
+ constants.UNREACHABLE: False
138
+ }
139
+ }
140
+
135
141
  amp_list_update_obj = amphora_driver_tasks.AmphoraIndexListenerUpdate()
136
142
  amp_list_update_obj.execute(_LB_mock, 0, [_amphora_mock],
143
+ amphorae_status,
144
+ _amphora_mock[constants.ID],
137
145
  self.timeout_dict)
138
146
 
139
147
  mock_driver.update_amphora_listeners.assert_called_once_with(
140
148
  _db_load_balancer_mock, _db_amphora_mock, self.timeout_dict)
141
149
 
150
+ # Unreachable amp
151
+ mock_driver.reset_mock()
152
+ amphorae_status = {
153
+ _amphora_mock[constants.ID]: {
154
+ constants.UNREACHABLE: True
155
+ }
156
+ }
157
+ amp_list_update_obj.execute(_LB_mock, 0, [_amphora_mock],
158
+ amphorae_status,
159
+ _amphora_mock[constants.ID],
160
+ self.timeout_dict)
161
+ mock_driver.update_amphora_listeners.assert_not_called()
162
+
163
+ # Test exception
142
164
  mock_driver.update_amphora_listeners.side_effect = Exception('boom')
143
165
 
144
- amp_list_update_obj.execute(_LB_mock, 0,
145
- [_amphora_mock], self.timeout_dict)
166
+ amp_list_update_obj.execute(_LB_mock, 0, [_amphora_mock], {},
167
+ _amphora_mock[constants.ID],
168
+ self.timeout_dict)
146
169
 
147
170
  mock_amphora_repo_update.assert_called_once_with(
148
171
  _session_mock, AMP_ID, status=constants.ERROR)
149
172
 
173
+ # Test exception, secondary amp
174
+ mock_amphora_repo_update.reset_mock()
175
+ mock_driver.update_amphora_listeners.side_effect = Exception('boom')
176
+
177
+ amp_list_update_obj.execute(_LB_mock, 0, [_amphora_mock], {},
178
+ '1234',
179
+ self.timeout_dict)
180
+
181
+ mock_amphora_repo_update.assert_not_called()
182
+
150
183
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
151
184
  @mock.patch('octavia.db.api.session')
152
185
  def test_listeners_update(self,
@@ -198,39 +231,70 @@ class TestAmphoraDriverTasks(base.TestCase):
198
231
  mock_driver, mock_generate_uuid, mock_log, mock_get_session,
199
232
  mock_listener_repo_get, mock_listener_repo_update,
200
233
  mock_amphora_repo_get, mock_amphora_repo_update):
201
- amphora_mock = mock.MagicMock()
202
234
  listeners_reload_obj = (
203
235
  amphora_driver_tasks.AmphoraIndexListenersReload())
204
236
  mock_lb = mock.MagicMock()
205
237
  mock_listener = mock.MagicMock()
206
238
  mock_listener.id = '12345'
207
- mock_amphora_repo_get.return_value = amphora_mock
239
+ mock_amphora_repo_get.return_value = _amphora_mock
208
240
  mock_lb_repo_get.return_value = mock_lb
209
241
  mock_driver.reload.side_effect = [mock.DEFAULT, Exception('boom')]
210
242
 
211
243
  # Test no listeners
212
244
  mock_lb.listeners = None
213
- listeners_reload_obj.execute(mock_lb, 0, None)
245
+ listeners_reload_obj.execute(mock_lb, 0, None, {},
246
+ _amphora_mock[constants.ID])
214
247
  mock_driver.reload.assert_not_called()
215
248
 
216
249
  # Test with listeners
217
- mock_driver.start.reset_mock()
250
+ amphorae_status = {
251
+ _amphora_mock[constants.ID]: {
252
+ constants.UNREACHABLE: False
253
+ }
254
+ }
255
+ mock_driver.reload.reset_mock()
218
256
  mock_lb.listeners = [mock_listener]
219
- listeners_reload_obj.execute(mock_lb, 0, [amphora_mock],
257
+ listeners_reload_obj.execute(mock_lb, 0, [_amphora_mock],
258
+ amphorae_status,
259
+ _amphora_mock[constants.ID],
220
260
  timeout_dict=self.timeout_dict)
221
- mock_driver.reload.assert_called_once_with(mock_lb, amphora_mock,
261
+ mock_driver.reload.assert_called_once_with(mock_lb, _amphora_mock,
222
262
  self.timeout_dict)
223
263
 
264
+ # Unreachable amp
265
+ amphorae_status = {
266
+ _amphora_mock[constants.ID]: {
267
+ constants.UNREACHABLE: True
268
+ }
269
+ }
270
+ mock_driver.reload.reset_mock()
271
+ listeners_reload_obj.execute(mock_lb, 0, [_amphora_mock],
272
+ amphorae_status,
273
+ _amphora_mock[constants.ID],
274
+ timeout_dict=self.timeout_dict)
275
+ mock_driver.reload.assert_not_called()
276
+
224
277
  # Test with reload exception
225
278
  mock_driver.reload.reset_mock()
226
- listeners_reload_obj.execute(mock_lb, 0, [amphora_mock],
279
+ listeners_reload_obj.execute(mock_lb, 0, [_amphora_mock], {},
280
+ _amphora_mock[constants.ID],
227
281
  timeout_dict=self.timeout_dict)
228
- mock_driver.reload.assert_called_once_with(mock_lb, amphora_mock,
282
+ mock_driver.reload.assert_called_once_with(mock_lb, _amphora_mock,
229
283
  self.timeout_dict)
230
284
  mock_amphora_repo_update.assert_called_once_with(
231
- _session_mock, amphora_mock[constants.ID],
285
+ _session_mock, _amphora_mock[constants.ID],
232
286
  status=constants.ERROR)
233
287
 
288
+ # Test with reload exception, secondary amp
289
+ mock_driver.reload.reset_mock()
290
+ mock_amphora_repo_update.reset_mock()
291
+ listeners_reload_obj.execute(mock_lb, 0, [_amphora_mock], {},
292
+ '1234',
293
+ timeout_dict=self.timeout_dict)
294
+ mock_driver.reload.assert_called_once_with(mock_lb, _amphora_mock,
295
+ self.timeout_dict)
296
+ mock_amphora_repo_update.assert_not_called()
297
+
234
298
  @mock.patch('octavia.controller.worker.task_utils.TaskUtils.'
235
299
  'mark_listener_prov_status_error')
236
300
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
@@ -827,6 +891,11 @@ class TestAmphoraDriverTasks(base.TestCase):
827
891
  FAKE_INTERFACE = 'fake0'
828
892
  mock_driver.get_interface_from_ip.side_effect = [FAKE_INTERFACE,
829
893
  Exception('boom')]
894
+ amphorae_status = {
895
+ _amphora_mock[constants.ID]: {
896
+ constants.UNREACHABLE: False
897
+ }
898
+ }
830
899
 
831
900
  timeout_dict = {constants.CONN_MAX_RETRIES: CONN_MAX_RETRIES,
832
901
  constants.CONN_RETRY_INTERVAL: CONN_RETRY_INTERVAL}
@@ -834,20 +903,39 @@ class TestAmphoraDriverTasks(base.TestCase):
834
903
  amphora_update_vrrp_interface_obj = (
835
904
  amphora_driver_tasks.AmphoraIndexUpdateVRRPInterface())
836
905
  amphora_update_vrrp_interface_obj.execute(
837
- 0, [_amphora_mock], timeout_dict)
906
+ 0, [_amphora_mock], amphorae_status, _amphora_mock[constants.ID],
907
+ timeout_dict)
838
908
  mock_driver.get_interface_from_ip.assert_called_once_with(
839
909
  _db_amphora_mock, _db_amphora_mock.vrrp_ip,
840
910
  timeout_dict=timeout_dict)
841
911
  mock_amphora_repo_update.assert_called_once_with(
842
912
  _session_mock, _db_amphora_mock.id, vrrp_interface=FAKE_INTERFACE)
843
913
 
914
+ # Unreachable amp
915
+ mock_driver.reset_mock()
916
+ amphorae_status = {
917
+ _amphora_mock[constants.ID]: {
918
+ constants.UNREACHABLE: True
919
+ }
920
+ }
921
+ amphora_update_vrrp_interface_obj.execute(
922
+ 0, [_amphora_mock], amphorae_status, _amphora_mock[constants.ID],
923
+ timeout_dict)
924
+ mock_driver.get_interface_from_ip.assert_not_called()
925
+
844
926
  # Test with an exception
845
927
  mock_amphora_repo_update.reset_mock()
846
928
  amphora_update_vrrp_interface_obj.execute(
847
- 0, [_amphora_mock], timeout_dict)
929
+ 0, [_amphora_mock], {}, _amphora_mock[constants.ID], timeout_dict)
848
930
  mock_amphora_repo_update.assert_called_once_with(
849
931
  _session_mock, _db_amphora_mock.id, status=constants.ERROR)
850
932
 
933
+ # Test with an exception, secondary amp
934
+ mock_amphora_repo_update.reset_mock()
935
+ amphora_update_vrrp_interface_obj.execute(
936
+ 0, [_amphora_mock], {}, '1234', timeout_dict)
937
+ mock_amphora_repo_update.assert_not_called()
938
+
851
939
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
852
940
  def test_amphora_vrrp_update(self,
853
941
  mock_lb_get,
@@ -895,23 +983,52 @@ class TestAmphoraDriverTasks(base.TestCase):
895
983
  Exception('boom')]
896
984
  mock_lb_get.return_value = _db_load_balancer_mock
897
985
  mock_amphora_repo_get.return_value = _db_amphora_mock
986
+ amphorae_status = {
987
+ _amphora_mock[constants.ID]: {
988
+ constants.UNREACHABLE: False
989
+ }
990
+ }
991
+
898
992
  amphora_vrrp_update_obj = (
899
993
  amphora_driver_tasks.AmphoraIndexVRRPUpdate())
900
994
 
901
995
  amphora_vrrp_update_obj.execute(LB_ID, amphorae_network_config,
902
- 0, [_amphora_mock], 'fakeint0',
996
+ 0, [_amphora_mock], amphorae_status,
997
+ 'fakeint0',
998
+ _amphora_mock[constants.ID],
903
999
  timeout_dict=self.timeout_dict)
904
1000
  mock_driver.update_vrrp_conf.assert_called_once_with(
905
1001
  _db_load_balancer_mock, amphorae_network_config, _db_amphora_mock,
906
1002
  self.timeout_dict)
907
1003
 
1004
+ # Unreachable amp
1005
+ amphorae_status = {
1006
+ _amphora_mock[constants.ID]: {
1007
+ constants.UNREACHABLE: True
1008
+ }
1009
+ }
1010
+ mock_amphora_repo_update.reset_mock()
1011
+ mock_driver.update_vrrp_conf.reset_mock()
1012
+ amphora_vrrp_update_obj.execute(LB_ID, amphorae_network_config,
1013
+ 0, [_amphora_mock], amphorae_status,
1014
+ None, _amphora_mock[constants.ID])
1015
+ mock_driver.update_vrrp_conf.assert_not_called()
1016
+
908
1017
  # Test with an exception
909
1018
  mock_amphora_repo_update.reset_mock()
910
1019
  amphora_vrrp_update_obj.execute(LB_ID, amphorae_network_config,
911
- 0, [_amphora_mock], 'fakeint0')
1020
+ 0, [_amphora_mock], {}, 'fakeint0',
1021
+ _amphora_mock[constants.ID])
912
1022
  mock_amphora_repo_update.assert_called_once_with(
913
1023
  _session_mock, _db_amphora_mock.id, status=constants.ERROR)
914
1024
 
1025
+ # Test with an exception, secondary amp
1026
+ mock_amphora_repo_update.reset_mock()
1027
+ amphora_vrrp_update_obj.execute(LB_ID, amphorae_network_config,
1028
+ 0, [_amphora_mock], {}, 'fakeint0',
1029
+ '1234')
1030
+ mock_amphora_repo_update.assert_not_called()
1031
+
915
1032
  def test_amphora_vrrp_start(self,
916
1033
  mock_driver,
917
1034
  mock_generate_uuid,
@@ -939,25 +1056,54 @@ class TestAmphoraDriverTasks(base.TestCase):
939
1056
  mock_amphora_repo_get,
940
1057
  mock_amphora_repo_update):
941
1058
  mock_amphora_repo_get.return_value = _db_amphora_mock
1059
+ amphorae_status = {
1060
+ _amphora_mock[constants.ID]: {
1061
+ constants.UNREACHABLE: False
1062
+ }
1063
+ }
1064
+
942
1065
  amphora_vrrp_start_obj = (
943
1066
  amphora_driver_tasks.AmphoraIndexVRRPStart())
944
1067
  mock_driver.start_vrrp_service.side_effect = [mock.DEFAULT,
945
1068
  Exception('boom')]
946
1069
 
947
- amphora_vrrp_start_obj.execute(0, [_amphora_mock],
1070
+ amphora_vrrp_start_obj.execute(0, [_amphora_mock], amphorae_status,
1071
+ _amphora_mock[constants.ID],
948
1072
  timeout_dict=self.timeout_dict)
949
1073
  mock_driver.start_vrrp_service.assert_called_once_with(
950
1074
  _db_amphora_mock, self.timeout_dict)
951
1075
 
1076
+ # Unreachable amp
1077
+ mock_driver.start_vrrp_service.reset_mock()
1078
+ amphorae_status = {
1079
+ _amphora_mock[constants.ID]: {
1080
+ constants.UNREACHABLE: True
1081
+ }
1082
+ }
1083
+ amphora_vrrp_start_obj.execute(0, [_amphora_mock], amphorae_status,
1084
+ _amphora_mock[constants.ID],
1085
+ timeout_dict=self.timeout_dict)
1086
+ mock_driver.start_vrrp_service.assert_not_called()
1087
+
952
1088
  # Test with a start exception
953
1089
  mock_driver.start_vrrp_service.reset_mock()
954
- amphora_vrrp_start_obj.execute(0, [_amphora_mock],
1090
+ amphora_vrrp_start_obj.execute(0, [_amphora_mock], {},
1091
+ _amphora_mock[constants.ID],
955
1092
  timeout_dict=self.timeout_dict)
956
1093
  mock_driver.start_vrrp_service.assert_called_once_with(
957
1094
  _db_amphora_mock, self.timeout_dict)
958
1095
  mock_amphora_repo_update.assert_called_once_with(
959
1096
  _session_mock, _db_amphora_mock.id, status=constants.ERROR)
960
1097
 
1098
+ # Test with a start exception, secondary amp
1099
+ mock_driver.start_vrrp_service.reset_mock()
1100
+ mock_amphora_repo_update.reset_mock()
1101
+ amphora_vrrp_start_obj.execute(0, [_amphora_mock], {}, '1234',
1102
+ timeout_dict=self.timeout_dict)
1103
+ mock_driver.start_vrrp_service.assert_called_once_with(
1104
+ _db_amphora_mock, self.timeout_dict)
1105
+ mock_amphora_repo_update.assert_not_called()
1106
+
961
1107
  def test_amphora_compute_connectivity_wait(self,
962
1108
  mock_driver,
963
1109
  mock_generate_uuid,
@@ -1029,3 +1175,74 @@ class TestAmphoraDriverTasks(base.TestCase):
1029
1175
  self.assertRaises(driver_except.TimeOutException,
1030
1176
  amp_config_update_obj.execute,
1031
1177
  _amphora_mock, flavor)
1178
+
1179
+ def test_amphorae_get_connectivity_status(self,
1180
+ mock_driver,
1181
+ mock_generate_uuid,
1182
+ mock_log,
1183
+ mock_get_session,
1184
+ mock_listener_repo_get,
1185
+ mock_listener_repo_update,
1186
+ mock_amphora_repo_get,
1187
+ mock_amphora_repo_update):
1188
+ amphora1_mock = mock.MagicMock()
1189
+ amphora1_mock[constants.ID] = 'id1'
1190
+ amphora2_mock = mock.MagicMock()
1191
+ amphora2_mock[constants.ID] = 'id2'
1192
+ db_amphora1_mock = mock.Mock()
1193
+ db_amphora2_mock = mock.Mock()
1194
+
1195
+ amp_get_connectivity_status = (
1196
+ amphora_driver_tasks.AmphoraeGetConnectivityStatus())
1197
+
1198
+ # All amphorae reachable
1199
+ mock_amphora_repo_get.side_effect = [
1200
+ db_amphora1_mock,
1201
+ db_amphora2_mock]
1202
+ mock_driver.check.return_value = None
1203
+
1204
+ ret = amp_get_connectivity_status.execute(
1205
+ [amphora1_mock, amphora2_mock],
1206
+ amphora1_mock[constants.ID],
1207
+ timeout_dict=self.timeout_dict)
1208
+ mock_driver.check.assert_has_calls(
1209
+ [mock.call(db_amphora1_mock, timeout_dict=self.timeout_dict),
1210
+ mock.call(db_amphora2_mock, timeout_dict=self.timeout_dict)])
1211
+ self.assertFalse(
1212
+ ret[amphora1_mock[constants.ID]][constants.UNREACHABLE])
1213
+ self.assertFalse(
1214
+ ret[amphora2_mock[constants.ID]][constants.UNREACHABLE])
1215
+
1216
+ # amphora1 unreachable
1217
+ mock_driver.check.reset_mock()
1218
+ mock_amphora_repo_get.side_effect = [
1219
+ db_amphora1_mock,
1220
+ db_amphora2_mock]
1221
+ mock_driver.check.side_effect = [
1222
+ driver_except.TimeOutException, None]
1223
+ self.assertRaises(driver_except.TimeOutException,
1224
+ amp_get_connectivity_status.execute,
1225
+ [amphora1_mock, amphora2_mock],
1226
+ amphora1_mock[constants.ID],
1227
+ timeout_dict=self.timeout_dict)
1228
+ mock_driver.check.assert_called_with(
1229
+ db_amphora1_mock, timeout_dict=self.timeout_dict)
1230
+
1231
+ # amphora2 unreachable
1232
+ mock_driver.check.reset_mock()
1233
+ mock_amphora_repo_get.side_effect = [
1234
+ db_amphora1_mock,
1235
+ db_amphora2_mock]
1236
+ mock_driver.check.side_effect = [
1237
+ None, driver_except.TimeOutException]
1238
+ ret = amp_get_connectivity_status.execute(
1239
+ [amphora1_mock, amphora2_mock],
1240
+ amphora1_mock[constants.ID],
1241
+ timeout_dict=self.timeout_dict)
1242
+ mock_driver.check.assert_has_calls(
1243
+ [mock.call(db_amphora1_mock, timeout_dict=self.timeout_dict),
1244
+ mock.call(db_amphora2_mock, timeout_dict=self.timeout_dict)])
1245
+ self.assertFalse(
1246
+ ret[amphora1_mock[constants.ID]][constants.UNREACHABLE])
1247
+ self.assertTrue(
1248
+ ret[amphora2_mock[constants.ID]][constants.UNREACHABLE])
@@ -181,7 +181,9 @@ class TestDatabaseTasks(base.TestCase):
181
181
 
182
182
  @mock.patch('octavia.db.repositories.AmphoraRepository.create',
183
183
  return_value=_db_amphora_mock)
184
+ @mock.patch('octavia.db.repositories.AmphoraHealthRepository.delete')
184
185
  def test_create_amphora_in_db(self,
186
+ mock_amphora_health_repo_delete,
185
187
  mock_create,
186
188
  mock_generate_uuid,
187
189
  mock_LOG,
@@ -207,23 +209,43 @@ class TestDatabaseTasks(base.TestCase):
207
209
 
208
210
  # Test the revert
209
211
  create_amp_in_db.revert(_tf_failure_mock)
210
- self.assertFalse(mock_amphora_repo_delete.called)
212
+ mock_amphora_repo_delete.assert_not_called()
213
+ mock_amphora_health_repo_delete.assert_not_called()
211
214
 
215
+ amp_id = 'AMP'
212
216
  mock_amphora_repo_delete.reset_mock()
213
- create_amp_in_db.revert(result='AMP')
217
+ mock_amphora_health_repo_delete.reset_mock()
218
+ create_amp_in_db.revert(result=amp_id)
214
219
  self.assertTrue(mock_amphora_repo_delete.called)
220
+ self.assertTrue(mock_amphora_health_repo_delete.called)
215
221
  mock_amphora_repo_delete.assert_called_once_with(
216
222
  mock_session,
217
- id='AMP')
223
+ id=amp_id)
224
+ mock_amphora_health_repo_delete.assert_called_once_with(
225
+ mock_session,
226
+ amphora_id=amp_id)
227
+ mock_LOG.error.assert_not_called()
228
+ mock_LOG.debug.assert_not_called()
218
229
 
219
230
  # Test revert with exception
220
231
  mock_amphora_repo_delete.reset_mock()
221
- mock_amphora_repo_delete.side_effect = Exception('fail')
222
- create_amp_in_db.revert(result='AMP')
232
+ mock_amphora_health_repo_delete.reset_mock()
233
+ err1_msg, err2_msg = ('fail', 'fail2')
234
+ mock_amphora_repo_delete.side_effect = Exception(err1_msg)
235
+ mock_amphora_health_repo_delete.side_effect = Exception(err2_msg)
236
+ create_amp_in_db.revert(result=amp_id)
223
237
  self.assertTrue(mock_amphora_repo_delete.called)
238
+ self.assertTrue(mock_amphora_health_repo_delete.called)
224
239
  mock_amphora_repo_delete.assert_called_once_with(
225
240
  mock_session,
226
- id='AMP')
241
+ id=amp_id)
242
+ mock_amphora_health_repo_delete.assert_called_once_with(
243
+ mock_session,
244
+ amphora_id=amp_id)
245
+ mock_LOG.error.assert_called_once_with(
246
+ "Failed to delete amphora %(amp)s "
247
+ "in the database due to: "
248
+ "%(except)s", {'amp': amp_id, 'except': err1_msg})
227
249
 
228
250
  @mock.patch('octavia.db.repositories.ListenerRepository.delete')
229
251
  def test_delete_listener_in_db(self,