octavia 14.0.0.0rc1__py3-none-any.whl → 14.0.2__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 (61) hide show
  1. octavia/amphorae/backends/agent/api_server/keepalivedlvs.py +9 -0
  2. octavia/amphorae/backends/agent/api_server/osutils.py +4 -2
  3. octavia/amphorae/backends/agent/api_server/plug.py +5 -4
  4. octavia/amphorae/backends/agent/api_server/server.py +3 -2
  5. octavia/amphorae/backends/agent/api_server/util.py +35 -2
  6. octavia/amphorae/backends/utils/interface.py +2 -37
  7. octavia/amphorae/backends/utils/interface_file.py +23 -10
  8. octavia/amphorae/backends/utils/nftable_utils.py +33 -11
  9. octavia/amphorae/drivers/keepalived/jinja/jinja_cfg.py +0 -1
  10. octavia/amphorae/drivers/keepalived/jinja/templates/keepalived_base.template +0 -1
  11. octavia/api/common/pagination.py +1 -1
  12. octavia/api/v2/controllers/health_monitor.py +3 -1
  13. octavia/api/v2/controllers/load_balancer.py +7 -0
  14. octavia/api/v2/controllers/member.py +12 -2
  15. octavia/common/clients.py +7 -1
  16. octavia/common/constants.py +3 -3
  17. octavia/controller/worker/v2/controller_worker.py +2 -2
  18. octavia/controller/worker/v2/flows/amphora_flows.py +14 -3
  19. octavia/controller/worker/v2/flows/flow_utils.py +6 -4
  20. octavia/controller/worker/v2/flows/listener_flows.py +17 -5
  21. octavia/controller/worker/v2/tasks/database_tasks.py +10 -6
  22. octavia/controller/worker/v2/tasks/network_tasks.py +27 -16
  23. octavia/db/base_models.py +16 -4
  24. octavia/network/drivers/neutron/allowed_address_pairs.py +3 -2
  25. octavia/tests/functional/amphorae/backend/agent/api_server/test_server.py +1 -1
  26. octavia/tests/functional/api/v2/test_health_monitor.py +18 -0
  27. octavia/tests/functional/api/v2/test_member.py +32 -0
  28. octavia/tests/unit/amphorae/backends/agent/api_server/test_osutils.py +1 -1
  29. octavia/tests/unit/amphorae/backends/agent/api_server/test_plug.py +4 -3
  30. octavia/tests/unit/amphorae/backends/agent/api_server/test_util.py +89 -1
  31. octavia/tests/unit/amphorae/backends/utils/test_interface.py +3 -64
  32. octavia/tests/unit/amphorae/backends/utils/test_nftable_utils.py +28 -22
  33. octavia/tests/unit/amphorae/drivers/keepalived/jinja/test_jinja_cfg.py +0 -4
  34. octavia/tests/unit/api/common/test_pagination.py +78 -1
  35. octavia/tests/unit/cmd/test_prometheus_proxy.py +8 -1
  36. octavia/tests/unit/controller/worker/v2/flows/test_listener_flows.py +10 -15
  37. octavia/tests/unit/controller/worker/v2/flows/test_load_balancer_flows.py +4 -6
  38. octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks.py +28 -6
  39. octavia/tests/unit/controller/worker/v2/tasks/test_network_tasks.py +71 -2
  40. octavia/tests/unit/controller/worker/v2/test_controller_worker.py +56 -1
  41. octavia/tests/unit/network/drivers/neutron/test_allowed_address_pairs.py +2 -1
  42. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/AUTHORS +5 -0
  43. octavia-14.0.2.dist-info/METADATA +156 -0
  44. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/RECORD +59 -59
  45. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/WHEEL +1 -1
  46. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/entry_points.txt +0 -1
  47. octavia-14.0.2.dist-info/pbr.json +1 -0
  48. octavia-14.0.0.0rc1.dist-info/METADATA +0 -158
  49. octavia-14.0.0.0rc1.dist-info/pbr.json +0 -1
  50. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/LICENSE +0 -0
  51. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/README.rst +0 -0
  52. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/README.rst +0 -0
  53. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/diskimage-create.sh +0 -0
  54. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/image-tests.sh +0 -0
  55. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/requirements.txt +0 -0
  56. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/test-requirements.txt +0 -0
  57. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/tox.ini +0 -0
  58. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/data/share/octavia/diskimage-create/version.txt +0 -0
  59. {octavia-14.0.0.0rc1.data → octavia-14.0.2.data}/scripts/octavia-wsgi +0 -0
  60. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/LICENSE +0 -0
  61. {octavia-14.0.0.0rc1.dist-info → octavia-14.0.2.dist-info}/top_level.txt +0 -0
@@ -103,6 +103,16 @@ class TestPaginationHelper(base.TestCase):
103
103
  helper.apply(query_mock, models.LoadBalancer)
104
104
  self.assertEqual(params, helper.filters)
105
105
 
106
+ @mock.patch('octavia.api.common.pagination.request')
107
+ def test_filter_with_booleans(self, request_mock):
108
+ params = {'backup': 'True', 'admin_state_up': 'false'}
109
+ expected_params = {'backup': True, 'enabled': False}
110
+ helper = pagination.PaginationHelper(params)
111
+ query_mock = mock.MagicMock()
112
+
113
+ helper.apply(query_mock, models.Member)
114
+ self.assertEqual(expected_params, helper.filters)
115
+
106
116
  @mock.patch('octavia.api.common.pagination.request')
107
117
  def test_filter_mismatched_params(self, request_mock):
108
118
  params = {
@@ -227,12 +237,46 @@ class TestPaginationHelper(base.TestCase):
227
237
  helper = pagination.PaginationHelper(params)
228
238
  links = helper._make_links(model_list)
229
239
  self.assertEqual(links[0].rel, "previous")
240
+ self.assertEqual(
241
+ links[0].href,
242
+ ("{base_uri}{path}?limit={limit}&marker={marker}"
243
+ "&page_reverse=True").format(
244
+ base_uri=api_base_uri,
245
+ path=request_mock.path,
246
+ limit=params['limit'],
247
+ marker=member1.id
248
+ ))
249
+ self.assertEqual(links[1].rel, "next")
230
250
  self.assertEqual(
231
251
  links[1].href,
232
252
  "{base_uri}{path}?limit={limit}&marker={marker}".format(
233
253
  base_uri=api_base_uri,
234
254
  path=request_mock.path,
235
255
  limit=params['limit'],
256
+ marker=member1.id))
257
+
258
+ @mock.patch('octavia.api.common.pagination.request')
259
+ def test_make_links_with_zero_limit(self, request_mock):
260
+ request_mock.path = "/lbaas/v2/pools/1/members"
261
+ request_mock.path_url = "http://localhost" + request_mock.path
262
+ api_base_uri = "https://127.0.0.1"
263
+ conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
264
+ conf.config(group='api_settings', api_base_uri=api_base_uri)
265
+ member1 = models.Member()
266
+ member1.id = uuidutils.generate_uuid()
267
+ model_list = [member1]
268
+
269
+ params = {'limit': 0, 'marker': member1.id}
270
+ helper = pagination.PaginationHelper(params)
271
+ links = helper._make_links(model_list)
272
+ self.assertEqual(links[0].rel, "previous")
273
+ self.assertEqual(
274
+ links[0].href,
275
+ ("{base_uri}{path}?limit={limit}&marker={marker}"
276
+ "&page_reverse=True").format(
277
+ base_uri=api_base_uri,
278
+ path=request_mock.path,
279
+ limit=None,
236
280
  marker=member1.id
237
281
  ))
238
282
  self.assertEqual(links[1].rel, "next")
@@ -241,5 +285,38 @@ class TestPaginationHelper(base.TestCase):
241
285
  "{base_uri}{path}?limit={limit}&marker={marker}".format(
242
286
  base_uri=api_base_uri,
243
287
  path=request_mock.path,
244
- limit=params['limit'],
288
+ limit=None,
289
+ marker=member1.id))
290
+
291
+ @mock.patch('octavia.api.common.pagination.request')
292
+ def test_make_links_with_negative_limit(self, request_mock):
293
+ request_mock.path = "/lbaas/v2/pools/1/members"
294
+ request_mock.path_url = "http://localhost" + request_mock.path
295
+ api_base_uri = "https://127.0.0.1"
296
+ conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
297
+ conf.config(group='api_settings', api_base_uri=api_base_uri)
298
+ member1 = models.Member()
299
+ member1.id = uuidutils.generate_uuid()
300
+ model_list = [member1]
301
+
302
+ params = {'limit': -1, 'marker': member1.id}
303
+ helper = pagination.PaginationHelper(params)
304
+ links = helper._make_links(model_list)
305
+ self.assertEqual(links[0].rel, "previous")
306
+ self.assertEqual(
307
+ links[0].href,
308
+ ("{base_uri}{path}?limit={limit}&marker={marker}"
309
+ "&page_reverse=True").format(
310
+ base_uri=api_base_uri,
311
+ path=request_mock.path,
312
+ limit=None,
313
+ marker=member1.id
314
+ ))
315
+ self.assertEqual(links[1].rel, "next")
316
+ self.assertEqual(
317
+ links[1].href,
318
+ "{base_uri}{path}?limit={limit}&marker={marker}".format(
319
+ base_uri=api_base_uri,
320
+ path=request_mock.path,
321
+ limit=None,
245
322
  marker=member1.id))
@@ -147,6 +147,7 @@ class TestPrometheusProxyCMD(base.TestCase):
147
147
  mock_http.shutdown.assert_called_once()
148
148
 
149
149
  @mock.patch('threading.Thread')
150
+ @mock.patch('http.server.ThreadingHTTPServer.__init__')
150
151
  @mock.patch('http.server.ThreadingHTTPServer.serve_forever')
151
152
  @mock.patch('octavia.amphorae.backends.utils.network_namespace.'
152
153
  'NetworkNamespace.__exit__')
@@ -155,12 +156,18 @@ class TestPrometheusProxyCMD(base.TestCase):
155
156
  @mock.patch('octavia.cmd.prometheus_proxy.EXIT_EVENT')
156
157
  @mock.patch('octavia.cmd.prometheus_proxy.SignalHandler')
157
158
  def test_main(self, mock_signal_handler, mock_exit_event, mock_netns_enter,
158
- mock_netns_exit, mock_serve_forever, mock_thread):
159
+ mock_netns_exit, mock_serve_forever, mock_server_init,
160
+ mock_thread):
159
161
 
160
162
  mock_exit_event.is_set.side_effect = [False, False, True]
161
163
  mock_netns_enter.side_effect = [Exception('boom'), True]
162
164
 
165
+ mock_server_init.return_value = None
166
+
163
167
  prometheus_proxy.main()
164
168
 
165
169
  mock_signal_handler.assert_called_once()
170
+ mock_server_init.assert_called_once_with(
171
+ ('127.0.0.1', 9102),
172
+ prometheus_proxy.PrometheusProxy)
166
173
  mock_serve_forever.assert_called_once()
@@ -44,15 +44,14 @@ class TestListenerFlows(base.TestCase):
44
44
 
45
45
  self.assertIn(constants.LISTENERS, listener_flow.requires)
46
46
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
47
- self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
48
47
 
49
48
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
50
49
  listener_flow.provides)
51
50
  self.assertIn(constants.AMPHORAE, listener_flow.provides)
52
51
  self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
53
52
 
54
- self.assertEqual(3, len(listener_flow.requires))
55
- self.assertEqual(3, len(listener_flow.provides))
53
+ self.assertEqual(2, len(listener_flow.requires))
54
+ self.assertEqual(4, len(listener_flow.provides))
56
55
 
57
56
  def test_get_delete_listener_flow(self, mock_get_net_driver):
58
57
  flavor_dict = {
@@ -66,15 +65,14 @@ class TestListenerFlows(base.TestCase):
66
65
  self.assertIn(constants.LISTENER, listener_flow.requires)
67
66
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
68
67
  self.assertIn(constants.PROJECT_ID, listener_flow.requires)
69
- self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
70
68
 
71
69
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
72
70
  listener_flow.provides)
73
71
  self.assertIn(constants.AMPHORAE, listener_flow.provides)
74
72
  self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
75
73
 
76
- self.assertEqual(4, len(listener_flow.requires))
77
- self.assertEqual(3, len(listener_flow.provides))
74
+ self.assertEqual(3, len(listener_flow.requires))
75
+ self.assertEqual(4, len(listener_flow.provides))
78
76
 
79
77
  def test_get_delete_listener_internal_flow(self, mock_get_net_driver):
80
78
  flavor_dict = {
@@ -88,15 +86,14 @@ class TestListenerFlows(base.TestCase):
88
86
 
89
87
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
90
88
  self.assertIn(constants.PROJECT_ID, listener_flow.requires)
91
- self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
92
89
 
93
90
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
94
91
  listener_flow.provides)
95
92
  self.assertIn(constants.AMPHORAE, listener_flow.provides)
96
93
  self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
97
94
 
98
- self.assertEqual(3, len(listener_flow.requires))
99
- self.assertEqual(3, len(listener_flow.provides))
95
+ self.assertEqual(2, len(listener_flow.requires))
96
+ self.assertEqual(4, len(listener_flow.provides))
100
97
 
101
98
  def test_get_update_listener_flow(self, mock_get_net_driver):
102
99
  flavor_dict = {
@@ -112,15 +109,14 @@ class TestListenerFlows(base.TestCase):
112
109
  self.assertIn(constants.UPDATE_DICT, listener_flow.requires)
113
110
  self.assertIn(constants.LISTENERS, listener_flow.requires)
114
111
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
115
- self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
116
112
 
117
113
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
118
114
  listener_flow.provides)
119
115
  self.assertIn(constants.AMPHORAE, listener_flow.provides)
120
116
  self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
121
117
 
122
- self.assertEqual(5, len(listener_flow.requires))
123
- self.assertEqual(3, len(listener_flow.provides))
118
+ self.assertEqual(4, len(listener_flow.requires))
119
+ self.assertEqual(4, len(listener_flow.provides))
124
120
 
125
121
  def test_get_create_all_listeners_flow(self, mock_get_net_driver):
126
122
  flavor_dict = {
@@ -131,12 +127,11 @@ class TestListenerFlows(base.TestCase):
131
127
  self.assertIsInstance(listeners_flow, flow.Flow)
132
128
  self.assertIn(constants.LOADBALANCER, listeners_flow.requires)
133
129
  self.assertIn(constants.LOADBALANCER_ID, listeners_flow.requires)
134
- self.assertIn(constants.AMPHORAE_STATUS, listeners_flow.requires)
135
130
  self.assertIn(constants.LOADBALANCER, listeners_flow.provides)
136
131
  self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
137
132
  listeners_flow.provides)
138
133
  self.assertIn(constants.AMPHORAE, listeners_flow.provides)
139
134
  self.assertIn(constants.AMPHORA_FIREWALL_RULES,
140
135
  listeners_flow.provides)
141
- self.assertEqual(3, len(listeners_flow.requires))
142
- self.assertEqual(5, len(listeners_flow.provides))
136
+ self.assertEqual(2, len(listeners_flow.requires))
137
+ self.assertEqual(6, len(listeners_flow.provides))
@@ -344,7 +344,6 @@ class TestLoadBalancerFlows(base.TestCase):
344
344
  self.assertIn(constants.FLAVOR, failover_flow.requires)
345
345
  self.assertIn(constants.LOADBALANCER, failover_flow.requires)
346
346
  self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
347
- self.assertIn(constants.AMPHORAE_STATUS, failover_flow.requires)
348
347
 
349
348
  self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
350
349
  self.assertIn(constants.AMPHORA, failover_flow.provides)
@@ -364,9 +363,9 @@ class TestLoadBalancerFlows(base.TestCase):
364
363
  self.assertIn(constants.SUBNET, failover_flow.provides)
365
364
  self.assertIn(constants.NEW_AMPHORAE, failover_flow.provides)
366
365
 
367
- self.assertEqual(7, len(failover_flow.requires),
366
+ self.assertEqual(6, len(failover_flow.requires),
368
367
  failover_flow.requires)
369
- self.assertEqual(16, len(failover_flow.provides),
368
+ self.assertEqual(17, len(failover_flow.provides),
370
369
  failover_flow.provides)
371
370
 
372
371
  @mock.patch('octavia.common.rpc.NOTIFIER',
@@ -424,7 +423,6 @@ class TestLoadBalancerFlows(base.TestCase):
424
423
  self.assertIn(constants.FLAVOR, failover_flow.requires)
425
424
  self.assertIn(constants.LOADBALANCER, failover_flow.requires)
426
425
  self.assertIn(constants.LOADBALANCER_ID, failover_flow.requires)
427
- self.assertIn(constants.AMPHORAE_STATUS, failover_flow.requires)
428
426
 
429
427
  self.assertIn(constants.UPDATED_PORTS, failover_flow.provides)
430
428
  self.assertIn(constants.AMPHORA, failover_flow.provides)
@@ -445,9 +443,9 @@ class TestLoadBalancerFlows(base.TestCase):
445
443
  self.assertIn(constants.SUBNET, failover_flow.provides)
446
444
  self.assertIn(constants.NEW_AMPHORAE, failover_flow.provides)
447
445
 
448
- self.assertEqual(7, len(failover_flow.requires),
446
+ self.assertEqual(6, len(failover_flow.requires),
449
447
  failover_flow.requires)
450
- self.assertEqual(16, len(failover_flow.provides),
448
+ self.assertEqual(17, len(failover_flow.provides),
451
449
  failover_flow.provides)
452
450
 
453
451
  @mock.patch('octavia.common.rpc.NOTIFIER',
@@ -184,7 +184,9 @@ class TestDatabaseTasks(base.TestCase):
184
184
 
185
185
  @mock.patch('octavia.db.repositories.AmphoraRepository.create',
186
186
  return_value=_db_amphora_mock)
187
+ @mock.patch('octavia.db.repositories.AmphoraHealthRepository.delete')
187
188
  def test_create_amphora_in_db(self,
189
+ mock_amphora_health_repo_delete,
188
190
  mock_create,
189
191
  mock_generate_uuid,
190
192
  mock_LOG,
@@ -210,23 +212,43 @@ class TestDatabaseTasks(base.TestCase):
210
212
 
211
213
  # Test the revert
212
214
  create_amp_in_db.revert(_tf_failure_mock)
213
- self.assertFalse(mock_amphora_repo_delete.called)
215
+ mock_amphora_repo_delete.assert_not_called()
216
+ mock_amphora_health_repo_delete.assert_not_called()
214
217
 
218
+ amp_id = 'AMP'
215
219
  mock_amphora_repo_delete.reset_mock()
216
- create_amp_in_db.revert(result='AMP')
220
+ mock_amphora_health_repo_delete.reset_mock()
221
+ create_amp_in_db.revert(result=amp_id)
217
222
  self.assertTrue(mock_amphora_repo_delete.called)
223
+ self.assertTrue(mock_amphora_health_repo_delete.called)
218
224
  mock_amphora_repo_delete.assert_called_once_with(
219
225
  mock_session,
220
- id='AMP')
226
+ id=amp_id)
227
+ mock_amphora_health_repo_delete.assert_called_once_with(
228
+ mock_session,
229
+ amphora_id=amp_id)
230
+ mock_LOG.error.assert_not_called()
231
+ mock_LOG.debug.assert_not_called()
221
232
 
222
233
  # Test revert with exception
223
234
  mock_amphora_repo_delete.reset_mock()
224
- mock_amphora_repo_delete.side_effect = Exception('fail')
225
- create_amp_in_db.revert(result='AMP')
235
+ mock_amphora_health_repo_delete.reset_mock()
236
+ err1_msg, err2_msg = ('fail', 'fail2')
237
+ mock_amphora_repo_delete.side_effect = Exception(err1_msg)
238
+ mock_amphora_health_repo_delete.side_effect = Exception(err2_msg)
239
+ create_amp_in_db.revert(result=amp_id)
226
240
  self.assertTrue(mock_amphora_repo_delete.called)
241
+ self.assertTrue(mock_amphora_health_repo_delete.called)
227
242
  mock_amphora_repo_delete.assert_called_once_with(
228
243
  mock_session,
229
- id='AMP')
244
+ id=amp_id)
245
+ mock_amphora_health_repo_delete.assert_called_once_with(
246
+ mock_session,
247
+ amphora_id=amp_id)
248
+ mock_LOG.error.assert_called_once_with(
249
+ "Failed to delete amphora %(amp)s "
250
+ "in the database due to: "
251
+ "%(except)s", {'amp': amp_id, 'except': err1_msg})
230
252
 
231
253
  @mock.patch('octavia.db.repositories.ListenerRepository.delete')
232
254
  def test_delete_listener_in_db(self,
@@ -1380,6 +1380,10 @@ class TestNetworkTasks(base.TestCase):
1380
1380
  AMP_ID = uuidutils.generate_uuid()
1381
1381
  mock_driver = mock.MagicMock()
1382
1382
  mock_get_net_driver.return_value = mock_driver
1383
+ amphora_config_mock = mock.MagicMock()
1384
+ mock_driver.get_network_configs.return_value = {
1385
+ "amphora_uuid1": amphora_config_mock
1386
+ }
1383
1387
  mock_amp_get.return_value = 'mock amphora'
1384
1388
  mock_lb_get.return_value = 'mock load balancer'
1385
1389
 
@@ -1391,6 +1395,9 @@ class TestNetworkTasks(base.TestCase):
1391
1395
  'mock load balancer', amphora='mock amphora')
1392
1396
  mock_amp_get.assert_called_once_with(mock_get_session(), id=AMP_ID)
1393
1397
  mock_lb_get.assert_called_once_with(mock_get_session(), id=LB_ID)
1398
+ amphora_config_mock.to_dict.assert_called_once_with(
1399
+ recurse=True, calling_classes=[o_data_models.LoadBalancer]
1400
+ )
1394
1401
 
1395
1402
  @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
1396
1403
  @mock.patch('octavia.db.api.get_session', return_value=_session_mock)
@@ -1399,10 +1406,17 @@ class TestNetworkTasks(base.TestCase):
1399
1406
  mock_driver = mock.MagicMock()
1400
1407
  mock_lb_get.return_value = LB
1401
1408
  mock_get_net_driver.return_value = mock_driver
1409
+ amphora_config_mock = mock.MagicMock()
1410
+ mock_driver.get_network_configs.return_value = {
1411
+ "amphora_uuid1": amphora_config_mock
1412
+ }
1402
1413
  lb = o_data_models.LoadBalancer()
1403
1414
  net_task = network_tasks.GetAmphoraeNetworkConfigs()
1404
1415
  net_task.execute(self.load_balancer_mock)
1405
1416
  mock_driver.get_network_configs.assert_called_once_with(lb)
1417
+ amphora_config_mock.to_dict.assert_called_once_with(
1418
+ recurse=True, calling_classes=[o_data_models.LoadBalancer]
1419
+ )
1406
1420
 
1407
1421
  def test_retrieve_portids_on_amphora_except_lb_network(
1408
1422
  self, mock_get_net_driver):
@@ -1526,6 +1540,57 @@ class TestNetworkTasks(base.TestCase):
1526
1540
  mock_driver.unplug_aap_port.assert_called_once_with(
1527
1541
  LB.vip, self.db_amphora_mock, mockSubnet)
1528
1542
 
1543
+ @mock.patch('octavia.db.repositories.AmphoraRepository.get')
1544
+ @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
1545
+ @mock.patch('octavia.db.api.get_session', return_value=_session_mock)
1546
+ def test_revert_plug_vip_amphora_subnet_not_found(
1547
+ self, mock_session, mock_lb_get, mock_get, mock_get_net_driver):
1548
+ mock_driver = mock.MagicMock()
1549
+ mock_lb_get.return_value = LB
1550
+ mock_get.return_value = self.db_amphora_mock
1551
+ mock_get_net_driver.return_value = mock_driver
1552
+ net = network_tasks.PlugVIPAmphora()
1553
+ amphora = {constants.ID: AMPHORA_ID,
1554
+ constants.LB_NETWORK_IP: IP_ADDRESS}
1555
+ subnet = {constants.ID: SUBNET_ID}
1556
+ err_msg = 'Subnet not found'
1557
+ mock_driver.get_subnet.side_effect = net_base.SubnetNotFound(err_msg)
1558
+ result = AMPS_DATA[0].to_dict()
1559
+ net.revert(result, self.load_balancer_mock, amphora, subnet)
1560
+ mock_driver.unplug_aap_port.assert_not_called()
1561
+ network_tasks.LOG.error.assert_called_once_with(
1562
+ 'Failed to unplug AAP port for load balancer: %s. '
1563
+ 'Resources may still be in use for VRRP port: %s. '
1564
+ 'Due to error: %s',
1565
+ self.load_balancer_mock[constants.LOADBALANCER_ID],
1566
+ result[constants.VRRP_PORT_ID], err_msg
1567
+ )
1568
+
1569
+ @mock.patch('octavia.db.repositories.AmphoraRepository.get')
1570
+ @mock.patch('octavia.db.repositories.LoadBalancerRepository.get')
1571
+ @mock.patch('octavia.db.api.get_session', return_value=_session_mock)
1572
+ def test_revert_plug_vip_amphora_raise_db_error(
1573
+ self, mock_session, mock_lb_get, mock_get, mock_get_net_driver):
1574
+ mock_driver = mock.MagicMock()
1575
+ mock_lb_get.return_value = LB
1576
+ err_msg = 'Some Error'
1577
+ mock_get.side_effect = Exception(err_msg)
1578
+ net = network_tasks.PlugVIPAmphora()
1579
+ amphora = {constants.ID: AMPHORA_ID,
1580
+ constants.LB_NETWORK_IP: IP_ADDRESS}
1581
+ subnet = {constants.ID: SUBNET_ID}
1582
+ result = AMPS_DATA[0].to_dict()
1583
+ net.revert(result, self.load_balancer_mock, amphora, subnet)
1584
+ mock_driver.unplug_aap_port.assert_not_called()
1585
+ mock_lb_get.assert_not_called()
1586
+ network_tasks.LOG.error.assert_called_once_with(
1587
+ 'Failed to unplug AAP port for load balancer: %s. '
1588
+ 'Resources may still be in use for VRRP port: %s. '
1589
+ 'Due to error: %s',
1590
+ self.load_balancer_mock[constants.LOADBALANCER_ID],
1591
+ result[constants.VRRP_PORT_ID], err_msg
1592
+ )
1593
+
1529
1594
  @mock.patch('octavia.controller.worker.v2.tasks.network_tasks.DeletePort.'
1530
1595
  'update_progress')
1531
1596
  def test_delete_port(self, mock_update_progress, mock_get_net_driver):
@@ -1670,7 +1735,11 @@ class TestNetworkTasks(base.TestCase):
1670
1735
  # Test revert
1671
1736
  mock_driver.reset_mock()
1672
1737
 
1673
- net_task.revert([port_mock], vip_dict, VIP_SG_ID, AMP_ID,
1738
+ # The execute path generates a port dict, so this will be the result
1739
+ # passed into the revert method by Taskflow
1740
+ port_dict = {constants.ID: PORT_ID}
1741
+
1742
+ net_task.revert(port_dict, vip_dict, VIP_SG_ID, AMP_ID,
1674
1743
  additional_vips)
1675
1744
 
1676
1745
  mock_driver.delete_port.assert_called_once_with(PORT_ID)
@@ -1678,7 +1747,7 @@ class TestNetworkTasks(base.TestCase):
1678
1747
  # Test revert exception
1679
1748
  mock_driver.reset_mock()
1680
1749
 
1681
- net_task.revert([port_mock], vip_dict, VIP_SG_ID, AMP_ID,
1750
+ net_task.revert(port_dict, vip_dict, VIP_SG_ID, AMP_ID,
1682
1751
  additional_vips)
1683
1752
 
1684
1753
  mock_driver.delete_port.assert_called_once_with(PORT_ID)
@@ -27,7 +27,7 @@ from octavia.controller.worker.v2 import controller_worker
27
27
  from octavia.controller.worker.v2.flows import flow_utils
28
28
  import octavia.tests.unit.base as base
29
29
 
30
-
30
+ TLS_CERT_ID = uuidutils.generate_uuid()
31
31
  AMP_ID = uuidutils.generate_uuid()
32
32
  LB_ID = uuidutils.generate_uuid()
33
33
  LISTENER_ID = uuidutils.generate_uuid()
@@ -804,6 +804,61 @@ class TestControllerWorker(base.TestCase):
804
804
  })
805
805
  )
806
806
 
807
+ @mock.patch(
808
+ "octavia.common.tls_utils.cert_parser.load_certificates_data",
809
+ side_effect=RuntimeError
810
+ )
811
+ def test_delete_load_balancer_with_cascade_tls_unavailable(
812
+ self,
813
+ mock_load_tls_cert,
814
+ mock_api_get_session,
815
+ mock_dyn_log_listener,
816
+ mock_taskflow_load,
817
+ mock_pool_repo_get,
818
+ mock_member_repo_get,
819
+ mock_l7rule_repo_get,
820
+ mock_l7policy_repo_get,
821
+ mock_listener_repo_get,
822
+ mock_lb_repo_get,
823
+ mock_health_mon_repo_get,
824
+ mock_amp_repo_get
825
+ ):
826
+ _flow_mock.reset_mock()
827
+
828
+ _listener_mock.tls_certificate_id = TLS_CERT_ID
829
+ _listener_mock.to_dict.return_value[
830
+ constants.TLS_CERTIFICATE_ID] = TLS_CERT_ID
831
+
832
+ cw = controller_worker.ControllerWorker()
833
+ cw.delete_load_balancer(_load_balancer_mock, cascade=True)
834
+
835
+ mock_lb_repo_get.assert_called_once_with(
836
+ _db_session,
837
+ id=LB_ID)
838
+
839
+ # Check load_certificates_data called and error is raised
840
+ # Error must be ignored because it is not critical for current flow
841
+ mock_load_tls_cert.assert_called_once()
842
+
843
+ listener_list = [{constants.LISTENER_ID: LISTENER_ID,
844
+ constants.LOADBALANCER_ID: LB_ID,
845
+ constants.PROJECT_ID: PROJECT_ID,
846
+ "default_tls_container_ref": TLS_CERT_ID}]
847
+
848
+ (cw.services_controller.run_poster.
849
+ assert_called_once_with(
850
+ flow_utils.get_cascade_delete_load_balancer_flow,
851
+ _load_balancer_mock, listener_list, [],
852
+ store={constants.LOADBALANCER: _load_balancer_mock,
853
+ constants.LOADBALANCER_ID: LB_ID,
854
+ constants.SERVER_GROUP_ID:
855
+ _db_load_balancer_mock.server_group_id,
856
+ constants.PROJECT_ID: _db_load_balancer_mock.project_id,
857
+ })
858
+ )
859
+
860
+ _listener_mock.reset_mock()
861
+
807
862
  @mock.patch('octavia.db.repositories.ListenerRepository.get_all',
808
863
  return_value=([_listener_mock], None))
809
864
  def test_update_load_balancer(self,
@@ -1071,7 +1071,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
1071
1071
  fake_rules = [
1072
1072
  {'id': 'rule-80', 'port_range_max': 80, 'protocol': 'tcp',
1073
1073
  'remote_ip_prefix': '10.0.101.0/24'},
1074
- {'id': 'rule-22', 'port_range_max': 22, 'protocol': 'tcp'}
1074
+ {'id': 'rule-22', 'port_range_max': 22, 'protocol': 'tcp'},
1075
+ {'id': 'rule-None', 'port_range_max': 22},
1075
1076
  ]
1076
1077
  list_rules = self.driver.network_proxy.security_group_rules
1077
1078
  list_rules.return_value = fake_rules
@@ -69,6 +69,7 @@ Elena Ezhova <eezhova@mirantis.com>
69
69
  EranRaichstein <eranra@il.ibm.com>
70
70
  Erik Olof Gunnar Andersson <eandersson@blizzard.com>
71
71
  Evan Gray <evanscottgray@gmail.com>
72
+ Evgeniy Bykov <chypakabre@gmail.com>
72
73
  Evgeny Fedoruk <evgenyf@radware.com>
73
74
  Fei Long Wang <flwang@catalyst.net.nz>
74
75
  Fernando Royo <froyo@redhat.com>
@@ -101,6 +102,7 @@ Hongbin Lu <hongbin.lu@huawei.com>
101
102
  Ian Wienand <iwienand@redhat.com>
102
103
  Ihar Hrachyshka <ihrachys@redhat.com>
103
104
  Ildar Iskhakov <iiskhako@cisco.com>
105
+ Ilia Kerbs <ikerbs@protonmail.com>
104
106
  Itzik Brown <itzikb@redhat.com>
105
107
  Jacky Hu <hudayou@hotmail.com>
106
108
  James Arendt <james.arendt@hp.com>
@@ -145,6 +147,7 @@ Martin Chlumsky <martin.chlumsky@ubisoft.com>
145
147
  Masayuki Igawa <masayuki@igawa.io>
146
148
  Matt Alline <matt.alline@gmail.com>
147
149
  Maximilian Stinsky <maximilian.stinsky@gec.io>
150
+ Michael Johnson <johnosmor@gmail.com>
148
151
  Michael Johnson <johnsom@hp.com>
149
152
  Michael Johnson <johnsomor@gmail.com>
150
153
  Michal Arbet <michal.arbet@ultimum.io>
@@ -188,6 +191,8 @@ Santhosh Fernandes <santhosh.fernandes@gmail.com>
188
191
  Sean McGinnis <sean.mcginnis@gmail.com>
189
192
  Selvakumar S <selvakumar.s2@hp.com>
190
193
  Sergey Belous <sbelous@mirantis.com>
194
+ Sergey Kraynev <sergejyit@gmail.com>
195
+ Seunghun Lee <seunghun@stackhpc.com>
191
196
  ShangXiao <shangxiaobj@inspur.com>
192
197
  Shashank Kumar Shankar <shashank.kumar.shankar@intel.com>
193
198
  Sherif Abdelwahab <sherif.abdelwahab@hp.com>