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.
- octavia/amphorae/backends/agent/api_server/keepalivedlvs.py +9 -0
- octavia/amphorae/backends/agent/api_server/osutils.py +1 -2
- octavia/amphorae/backends/agent/api_server/util.py +35 -2
- octavia/amphorae/backends/utils/interface.py +4 -5
- octavia/amphorae/drivers/driver_base.py +16 -0
- octavia/amphorae/drivers/haproxy/rest_api_driver.py +13 -8
- octavia/amphorae/drivers/keepalived/jinja/jinja_cfg.py +0 -1
- octavia/amphorae/drivers/keepalived/jinja/templates/keepalived_base.template +0 -1
- octavia/amphorae/drivers/keepalived/vrrp_rest_driver.py +2 -1
- octavia/amphorae/drivers/noop_driver/driver.py +3 -0
- octavia/api/common/pagination.py +1 -1
- octavia/api/v2/controllers/health_monitor.py +3 -2
- octavia/api/v2/controllers/l7policy.py +0 -1
- octavia/api/v2/controllers/l7rule.py +0 -1
- octavia/api/v2/controllers/listener.py +0 -1
- octavia/api/v2/controllers/load_balancer.py +13 -7
- octavia/api/v2/controllers/member.py +18 -5
- octavia/api/v2/controllers/pool.py +6 -7
- octavia/api/v2/types/pool.py +1 -1
- octavia/certificates/common/pkcs12.py +9 -9
- octavia/certificates/manager/barbican.py +24 -16
- octavia/certificates/manager/castellan_mgr.py +12 -7
- octavia/certificates/manager/noop.py +106 -0
- octavia/common/clients.py +22 -4
- octavia/common/config.py +21 -5
- octavia/common/constants.py +4 -0
- octavia/common/exceptions.py +6 -0
- octavia/common/jinja/haproxy/combined_listeners/templates/macros.j2 +7 -5
- octavia/common/keystone.py +7 -7
- octavia/common/tls_utils/cert_parser.py +23 -9
- octavia/controller/worker/task_utils.py +28 -6
- octavia/controller/worker/v2/controller_worker.py +2 -2
- octavia/controller/worker/v2/flows/amphora_flows.py +41 -10
- octavia/controller/worker/v2/flows/flow_utils.py +6 -4
- octavia/controller/worker/v2/flows/load_balancer_flows.py +17 -3
- octavia/controller/worker/v2/tasks/amphora_driver_tasks.py +114 -23
- octavia/controller/worker/v2/tasks/database_tasks.py +36 -47
- octavia/controller/worker/v2/tasks/lifecycle_tasks.py +96 -40
- octavia/controller/worker/v2/tasks/network_tasks.py +12 -13
- octavia/db/base_models.py +16 -4
- octavia/db/repositories.py +34 -33
- octavia/network/drivers/neutron/allowed_address_pairs.py +10 -8
- octavia/network/drivers/noop_driver/driver.py +1 -2
- octavia/tests/common/sample_certs.py +115 -0
- octavia/tests/functional/api/v2/base.py +1 -1
- octavia/tests/functional/api/v2/test_health_monitor.py +18 -0
- octavia/tests/functional/api/v2/test_listener.py +45 -0
- octavia/tests/functional/api/v2/test_member.py +32 -0
- octavia/tests/functional/db/base.py +9 -0
- octavia/tests/functional/db/test_repositories.py +45 -98
- octavia/tests/unit/amphorae/backends/agent/api_server/test_util.py +89 -1
- octavia/tests/unit/amphorae/backends/utils/test_interface.py +3 -1
- octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver.py +3 -3
- octavia/tests/unit/amphorae/drivers/keepalived/jinja/test_jinja_cfg.py +0 -4
- octavia/tests/unit/amphorae/drivers/keepalived/test_vrrp_rest_driver.py +17 -0
- octavia/tests/unit/api/common/test_pagination.py +78 -1
- octavia/tests/unit/api/v2/types/test_pool.py +71 -0
- octavia/tests/unit/certificates/manager/test_barbican.py +3 -3
- octavia/tests/unit/certificates/manager/test_noop.py +53 -0
- octavia/tests/unit/cmd/test_prometheus_proxy.py +8 -1
- octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py +16 -17
- octavia/tests/unit/common/test_config.py +35 -0
- octavia/tests/unit/common/test_keystone.py +32 -0
- octavia/tests/unit/controller/worker/test_task_utils.py +58 -2
- octavia/tests/unit/controller/worker/v2/flows/test_amphora_flows.py +28 -5
- octavia/tests/unit/controller/worker/v2/flows/test_load_balancer_flows.py +10 -5
- octavia/tests/unit/controller/worker/v2/tasks/test_amphora_driver_tasks.py +234 -17
- octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks.py +28 -6
- octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks_quota.py +19 -19
- octavia/tests/unit/controller/worker/v2/tasks/test_network_tasks.py +57 -2
- octavia/tests/unit/controller/worker/v2/test_controller_worker.py +56 -1
- octavia/tests/unit/network/drivers/neutron/test_allowed_address_pairs.py +24 -1
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/AUTHORS +8 -0
- octavia-13.0.1.dist-info/METADATA +155 -0
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/RECORD +90 -88
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/WHEEL +1 -1
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/entry_points.txt +1 -1
- octavia-13.0.1.dist-info/pbr.json +1 -0
- octavia-13.0.0.dist-info/METADATA +0 -158
- octavia-13.0.0.dist-info/pbr.json +0 -1
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/LICENSE +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/README.rst +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/README.rst +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/diskimage-create.sh +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/image-tests.sh +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/requirements.txt +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/test-requirements.txt +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/tox.ini +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/data/share/octavia/diskimage-create/version.txt +0 -0
- {octavia-13.0.0.data → octavia-13.0.1.data}/scripts/octavia-wsgi +0 -0
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/LICENSE +0 -0
- {octavia-13.0.0.dist-info → octavia-13.0.1.dist-info}/top_level.txt +0 -0
@@ -370,13 +370,57 @@ class TestUtil(base.TestCase):
|
|
370
370
|
self.assertEqual([], util.get_haproxy_vip_addresses(LB_ID1))
|
371
371
|
mock_cfg_path.assert_called_once_with(LB_ID1)
|
372
372
|
|
373
|
+
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
374
|
+
'keepalived_lvs_cfg_path')
|
375
|
+
def test_get_lvs_vip_addresses(self, mock_cfg_path):
|
376
|
+
FAKE_PATH = 'fake_path'
|
377
|
+
mock_cfg_path.return_value = FAKE_PATH
|
378
|
+
self.useFixture(
|
379
|
+
test_utils.OpenFixture(FAKE_PATH, 'no match')).mock_open()
|
380
|
+
|
381
|
+
# Test with no matching lines in the config file
|
382
|
+
self.assertEqual([], util.get_lvs_vip_addresses(LB_ID1))
|
383
|
+
mock_cfg_path.assert_called_once_with(LB_ID1)
|
384
|
+
|
385
|
+
# Test with 2 matching lines
|
386
|
+
mock_cfg_path.reset_mock()
|
387
|
+
test_data = ('virtual_server_group ipv4-group {\n'
|
388
|
+
' 203.0.113.43 1\n'
|
389
|
+
' 203.0.113.44 1\n'
|
390
|
+
'}\n')
|
391
|
+
self.useFixture(
|
392
|
+
test_utils.OpenFixture(FAKE_PATH, test_data)).mock_open()
|
393
|
+
expected_result = ['203.0.113.43', '203.0.113.44']
|
394
|
+
self.assertEqual(expected_result,
|
395
|
+
util.get_lvs_vip_addresses(LB_ID1))
|
396
|
+
mock_cfg_path.assert_called_once_with(LB_ID1)
|
397
|
+
|
398
|
+
# Test with 2 groups
|
399
|
+
mock_cfg_path.reset_mock()
|
400
|
+
test_data = ('virtual_server_group ipv4-group {\n'
|
401
|
+
' 203.0.113.43 1\n'
|
402
|
+
'}\n'
|
403
|
+
'virtual_server_group ipv6-group {\n'
|
404
|
+
' 2d01:27::1 2\n'
|
405
|
+
' 2d01:27::2 2\n'
|
406
|
+
'}\n')
|
407
|
+
self.useFixture(
|
408
|
+
test_utils.OpenFixture(FAKE_PATH, test_data)).mock_open()
|
409
|
+
expected_result = ['203.0.113.43', '2d01:27::1', '2d01:27::2']
|
410
|
+
self.assertEqual(expected_result,
|
411
|
+
util.get_lvs_vip_addresses(LB_ID1))
|
412
|
+
mock_cfg_path.assert_called_once_with(LB_ID1)
|
413
|
+
|
373
414
|
@mock.patch('octavia.amphorae.backends.utils.ip_advertisement.'
|
374
415
|
'send_ip_advertisement')
|
375
416
|
@mock.patch('octavia.amphorae.backends.utils.network_utils.'
|
376
417
|
'get_interface_name')
|
377
418
|
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
378
419
|
'get_haproxy_vip_addresses')
|
379
|
-
|
420
|
+
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
421
|
+
'get_lvs_vip_addresses')
|
422
|
+
def test_send_vip_advertisements(self, mock_get_lvs_vip_addrs,
|
423
|
+
mock_get_vip_addrs,
|
380
424
|
mock_get_int_name, mock_send_advert):
|
381
425
|
mock_get_vip_addrs.side_effect = [[], ['203.0.113.46'],
|
382
426
|
Exception('boom')]
|
@@ -385,6 +429,7 @@ class TestUtil(base.TestCase):
|
|
385
429
|
# Test no VIPs
|
386
430
|
util.send_vip_advertisements(LB_ID1)
|
387
431
|
mock_get_vip_addrs.assert_called_once_with(LB_ID1)
|
432
|
+
mock_get_lvs_vip_addrs.assert_not_called()
|
388
433
|
mock_get_int_name.assert_not_called()
|
389
434
|
mock_send_advert.assert_not_called()
|
390
435
|
|
@@ -394,6 +439,7 @@ class TestUtil(base.TestCase):
|
|
394
439
|
mock_send_advert.reset_mock()
|
395
440
|
util.send_vip_advertisements(LB_ID1)
|
396
441
|
mock_get_vip_addrs.assert_called_once_with(LB_ID1)
|
442
|
+
mock_get_lvs_vip_addrs.assert_not_called()
|
397
443
|
mock_get_int_name.assert_called_once_with(
|
398
444
|
'203.0.113.46', net_ns=consts.AMPHORA_NAMESPACE)
|
399
445
|
mock_send_advert.assert_called_once_with(
|
@@ -407,6 +453,48 @@ class TestUtil(base.TestCase):
|
|
407
453
|
mock_get_int_name.assert_not_called()
|
408
454
|
mock_send_advert.assert_not_called()
|
409
455
|
|
456
|
+
@mock.patch('octavia.amphorae.backends.utils.ip_advertisement.'
|
457
|
+
'send_ip_advertisement')
|
458
|
+
@mock.patch('octavia.amphorae.backends.utils.network_utils.'
|
459
|
+
'get_interface_name')
|
460
|
+
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
461
|
+
'get_haproxy_vip_addresses')
|
462
|
+
@mock.patch('octavia.amphorae.backends.agent.api_server.util.'
|
463
|
+
'get_lvs_vip_addresses')
|
464
|
+
def test_send_vip_advertisements_udp(self, mock_get_lvs_vip_addrs,
|
465
|
+
mock_get_vip_addrs,
|
466
|
+
mock_get_int_name, mock_send_advert):
|
467
|
+
mock_get_lvs_vip_addrs.side_effect = [[], ['203.0.113.46'],
|
468
|
+
Exception('boom')]
|
469
|
+
mock_get_int_name.return_value = 'fake0'
|
470
|
+
|
471
|
+
# Test no VIPs
|
472
|
+
util.send_vip_advertisements(listener_id=LISTENER_ID1)
|
473
|
+
mock_get_lvs_vip_addrs.assert_called_once_with(LISTENER_ID1)
|
474
|
+
mock_get_vip_addrs.assert_not_called()
|
475
|
+
mock_get_int_name.assert_not_called()
|
476
|
+
mock_send_advert.assert_not_called()
|
477
|
+
|
478
|
+
# Test with a VIP
|
479
|
+
mock_get_lvs_vip_addrs.reset_mock()
|
480
|
+
mock_get_int_name.reset_mock()
|
481
|
+
mock_send_advert.reset_mock()
|
482
|
+
util.send_vip_advertisements(listener_id=LISTENER_ID1)
|
483
|
+
mock_get_lvs_vip_addrs.assert_called_once_with(LISTENER_ID1)
|
484
|
+
mock_get_vip_addrs.assert_not_called()
|
485
|
+
mock_get_int_name.assert_called_once_with(
|
486
|
+
'203.0.113.46', net_ns=consts.AMPHORA_NAMESPACE)
|
487
|
+
mock_send_advert.assert_called_once_with(
|
488
|
+
'fake0', '203.0.113.46', net_ns=consts.AMPHORA_NAMESPACE)
|
489
|
+
|
490
|
+
# Test with an exception (should not raise)
|
491
|
+
mock_get_lvs_vip_addrs.reset_mock()
|
492
|
+
mock_get_int_name.reset_mock()
|
493
|
+
mock_send_advert.reset_mock()
|
494
|
+
util.send_vip_advertisements(listener_id=LISTENER_ID1)
|
495
|
+
mock_get_int_name.assert_not_called()
|
496
|
+
mock_send_advert.assert_not_called()
|
497
|
+
|
410
498
|
@mock.patch('octavia.amphorae.backends.utils.ip_advertisement.'
|
411
499
|
'send_ip_advertisement')
|
412
500
|
@mock.patch('octavia.amphorae.backends.utils.network_utils.'
|
@@ -714,7 +714,9 @@ class TestInterface(base.TestCase):
|
|
714
714
|
table=254,
|
715
715
|
family=socket.AF_INET)])
|
716
716
|
|
717
|
-
mock_check_output.
|
717
|
+
mock_check_output.assert_has_calls([
|
718
|
+
mock.call(["post-up", "eth1"])
|
719
|
+
])
|
718
720
|
|
719
721
|
@mock.patch('pyroute2.IPRoute.rule')
|
720
722
|
@mock.patch('pyroute2.IPRoute.route')
|
@@ -76,9 +76,9 @@ class TestHAProxyAmphoraDriver(base.TestCase):
|
|
76
76
|
mock_api_version.reset_mock()
|
77
77
|
client_mock.reset_mock()
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
self.assertRaises(
|
80
|
+
exc.NotFound,
|
81
|
+
self.driver.get_interface_from_ip, amphora_mock, IP_ADDRESS)
|
82
82
|
mock_api_version.assert_called_once_with(amphora_mock, None)
|
83
83
|
client_mock.get_interface.assert_called_once_with(
|
84
84
|
amphora_mock, IP_ADDRESS, None, log_error=False)
|
@@ -71,7 +71,6 @@ class TestVRRPRestDriver(base.TestCase):
|
|
71
71
|
"}\n"
|
72
72
|
"\n"
|
73
73
|
"vrrp_instance TESTGROUP {\n"
|
74
|
-
" state MASTER\n"
|
75
74
|
" interface eth1\n"
|
76
75
|
" virtual_router_id 1\n"
|
77
76
|
" priority 100\n"
|
@@ -124,7 +123,6 @@ class TestVRRPRestDriver(base.TestCase):
|
|
124
123
|
"}\n"
|
125
124
|
"\n"
|
126
125
|
"vrrp_instance TESTGROUP {\n"
|
127
|
-
" state MASTER\n"
|
128
126
|
" interface eth1\n"
|
129
127
|
" virtual_router_id 1\n"
|
130
128
|
" priority 100\n"
|
@@ -170,7 +168,6 @@ class TestVRRPRestDriver(base.TestCase):
|
|
170
168
|
"}\n"
|
171
169
|
"\n"
|
172
170
|
"vrrp_instance TESTGROUP {\n"
|
173
|
-
" state MASTER\n"
|
174
171
|
" interface eth1\n"
|
175
172
|
" virtual_router_id 1\n"
|
176
173
|
" priority 100\n"
|
@@ -220,7 +217,6 @@ class TestVRRPRestDriver(base.TestCase):
|
|
220
217
|
"}\n"
|
221
218
|
"\n"
|
222
219
|
"vrrp_instance TESTGROUP {\n"
|
223
|
-
" state MASTER\n"
|
224
220
|
" interface eth1\n"
|
225
221
|
" virtual_router_id 1\n"
|
226
222
|
" priority 100\n"
|
@@ -107,6 +107,9 @@ class TestVRRPRestDriver(base.TestCase):
|
|
107
107
|
|
108
108
|
self.keepalived_mixin.start_vrrp_service(self.amphora_mock)
|
109
109
|
|
110
|
+
populate_mock = self.keepalived_mixin._populate_amphora_api_version
|
111
|
+
populate_mock.assert_called_once_with(self.amphora_mock,
|
112
|
+
timeout_dict=None)
|
110
113
|
self.clients[API_VERSION].start_vrrp.assert_called_once_with(
|
111
114
|
self.amphora_mock, timeout_dict=None)
|
112
115
|
|
@@ -121,6 +124,20 @@ class TestVRRPRestDriver(base.TestCase):
|
|
121
124
|
|
122
125
|
self.clients[API_VERSION].start_vrrp.assert_not_called()
|
123
126
|
|
127
|
+
# With timeout_dict
|
128
|
+
self.clients[API_VERSION].start_vrrp.reset_mock()
|
129
|
+
populate_mock.reset_mock()
|
130
|
+
|
131
|
+
timeout_dict = mock.Mock()
|
132
|
+
self.keepalived_mixin.start_vrrp_service(self.amphora_mock,
|
133
|
+
timeout_dict=timeout_dict)
|
134
|
+
|
135
|
+
populate_mock = self.keepalived_mixin._populate_amphora_api_version
|
136
|
+
populate_mock.assert_called_once_with(self.amphora_mock,
|
137
|
+
timeout_dict=timeout_dict)
|
138
|
+
self.clients[API_VERSION].start_vrrp.assert_called_once_with(
|
139
|
+
self.amphora_mock, timeout_dict=timeout_dict)
|
140
|
+
|
124
141
|
def test_reload_vrrp_service(self):
|
125
142
|
|
126
143
|
self.keepalived_mixin.reload_vrrp_service(self.lb_mock)
|
@@ -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=
|
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))
|
@@ -17,8 +17,12 @@ from wsme import exc
|
|
17
17
|
from wsme.rest import json as wsme_json
|
18
18
|
from wsme import types as wsme_types
|
19
19
|
|
20
|
+
from octavia.api.common import types
|
21
|
+
from octavia.api.v2.types import health_monitor as health_monitor_type
|
22
|
+
from octavia.api.v2.types import member as member_type
|
20
23
|
from octavia.api.v2.types import pool as pool_type
|
21
24
|
from octavia.common import constants
|
25
|
+
from octavia.common import data_models
|
22
26
|
from octavia.tests.unit.api.common import base
|
23
27
|
|
24
28
|
|
@@ -224,3 +228,70 @@ class TestSessionPersistencePUT(base.BaseTypesTest, TestSessionPersistence):
|
|
224
228
|
body = {"cookie_name": "cookie\nmonster"}
|
225
229
|
self.assertRaises(exc.InvalidInput, wsme_json.fromjson, self._type,
|
226
230
|
body)
|
231
|
+
|
232
|
+
|
233
|
+
class TestPoolResponse(base.BaseTypesTest):
|
234
|
+
|
235
|
+
_type = pool_type.PoolResponse
|
236
|
+
|
237
|
+
def test_pool_response_with_health_monitor(self):
|
238
|
+
health_monitor_id = uuidutils.generate_uuid()
|
239
|
+
health_monitor_model = data_models.HealthMonitor(id=health_monitor_id)
|
240
|
+
pool_model = data_models.Pool(health_monitor=health_monitor_model)
|
241
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
242
|
+
self.assertEqual(pool.healthmonitor_id, health_monitor_id)
|
243
|
+
|
244
|
+
def test_pool_response_with_members(self):
|
245
|
+
member_id = uuidutils.generate_uuid()
|
246
|
+
members = [data_models.Member(id=member_id)]
|
247
|
+
pool_model = data_models.Pool(members=members)
|
248
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
249
|
+
self.assertIsInstance(pool.members[0], types.IdOnlyType)
|
250
|
+
self.assertEqual(pool.members[0].id, member_id)
|
251
|
+
|
252
|
+
def test_pool_response_with_load_balancer(self):
|
253
|
+
load_balancer_id = uuidutils.generate_uuid()
|
254
|
+
load_balancer = data_models.LoadBalancer(id=load_balancer_id)
|
255
|
+
pool_model = data_models.Pool(load_balancer=load_balancer)
|
256
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
257
|
+
self.assertIsInstance(pool.loadbalancers[0], types.IdOnlyType)
|
258
|
+
self.assertEqual(pool.loadbalancers[0].id, load_balancer_id)
|
259
|
+
|
260
|
+
def test_pool_response_with_session_persistence(self):
|
261
|
+
session_persistence = data_models.SessionPersistence(
|
262
|
+
cookie_name="test"
|
263
|
+
)
|
264
|
+
pool_model = data_models.Pool(session_persistence=session_persistence)
|
265
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
266
|
+
self.assertEqual(pool.session_persistence.cookie_name, "test")
|
267
|
+
|
268
|
+
def test_pool_response_without_children(self):
|
269
|
+
pool = self._type.from_data_model(data_model=data_models.Pool())
|
270
|
+
self.assertEqual(len(pool.loadbalancers), 0)
|
271
|
+
self.assertIsNone(pool.session_persistence)
|
272
|
+
self.assertEqual(len(pool.members), 0)
|
273
|
+
self.assertEqual(len(pool.listeners), 0)
|
274
|
+
self.assertEqual(pool.healthmonitor_id, wsme_types.Unset)
|
275
|
+
|
276
|
+
|
277
|
+
class TestPoolFullResponse(base.BaseTypesTest):
|
278
|
+
|
279
|
+
_type = pool_type.PoolFullResponse
|
280
|
+
|
281
|
+
def test_pool_full_response_with_health_monitor(self):
|
282
|
+
health_monitor_model = data_models.HealthMonitor()
|
283
|
+
pool_model = data_models.Pool(health_monitor=health_monitor_model)
|
284
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
285
|
+
self.assertIsInstance(
|
286
|
+
pool.healthmonitor, health_monitor_type.HealthMonitorFullResponse
|
287
|
+
)
|
288
|
+
|
289
|
+
def test_pool_full_response_with_members(self):
|
290
|
+
members = [data_models.Member()]
|
291
|
+
pool_model = data_models.Pool(members=members)
|
292
|
+
pool = self._type.from_data_model(data_model=pool_model)
|
293
|
+
self.assertIsInstance(pool.members[0], member_type.MemberFullResponse)
|
294
|
+
|
295
|
+
def test_pool_full_response_without_children(self):
|
296
|
+
pool = self._type.from_data_model(data_model=data_models.Pool())
|
297
|
+
self.assertIsNone(pool.healthmonitor)
|
@@ -15,7 +15,6 @@ from unittest import mock
|
|
15
15
|
import uuid
|
16
16
|
|
17
17
|
from barbicanclient.v1 import secrets
|
18
|
-
from OpenSSL import crypto
|
19
18
|
|
20
19
|
import octavia.certificates.common.barbican as barbican_common
|
21
20
|
import octavia.certificates.common.cert as cert
|
@@ -138,10 +137,11 @@ class TestBarbicanManager(base.TestCase):
|
|
138
137
|
sorted(data.get_intermediates()))
|
139
138
|
self.assertIsNone(data.get_private_key_passphrase())
|
140
139
|
|
141
|
-
@mock.patch('
|
140
|
+
@mock.patch('cryptography.hazmat.primitives.serialization.pkcs12.'
|
141
|
+
'load_pkcs12')
|
142
142
|
def test_get_cert_bad_pkcs12(self, mock_load_pkcs12):
|
143
143
|
|
144
|
-
mock_load_pkcs12.side_effect = [
|
144
|
+
mock_load_pkcs12.side_effect = [ValueError]
|
145
145
|
|
146
146
|
# Mock out the client
|
147
147
|
self.bc.secrets.get.return_value = self.secret_pkcs12
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Copyright 2023 Red Hat
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
4
|
+
# not use this file except in compliance with the License. You may obtain
|
5
|
+
# a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
11
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
12
|
+
# License for the specific language governing permissions and limitations
|
13
|
+
# under the License.
|
14
|
+
|
15
|
+
from oslo_utils import uuidutils
|
16
|
+
|
17
|
+
from octavia.certificates.common import cert
|
18
|
+
from octavia.certificates.manager import noop as noop_cert_mgr
|
19
|
+
from octavia.tests.common import sample_certs
|
20
|
+
import octavia.tests.unit.base as base
|
21
|
+
|
22
|
+
|
23
|
+
class TestNoopManager(base.TestCase):
|
24
|
+
|
25
|
+
def setUp(self):
|
26
|
+
super().setUp()
|
27
|
+
self.manager = noop_cert_mgr.NoopCertManager()
|
28
|
+
|
29
|
+
def test_store_cert(self):
|
30
|
+
certificate = self.manager.store_cert(
|
31
|
+
None,
|
32
|
+
sample_certs.X509_CERT,
|
33
|
+
sample_certs.X509_CERT_KEY_ENCRYPTED,
|
34
|
+
sample_certs.X509_IMDS,
|
35
|
+
private_key_passphrase=sample_certs.X509_CERT_KEY_PASSPHRASE)
|
36
|
+
self.assertIsNotNone(certificate)
|
37
|
+
self.assertIsInstance(certificate, cert.Cert)
|
38
|
+
|
39
|
+
def test_get_cert(self):
|
40
|
+
cert_ref = uuidutils.generate_uuid()
|
41
|
+
certificate = self.manager.get_cert(
|
42
|
+
context=None,
|
43
|
+
cert_ref=cert_ref)
|
44
|
+
self.assertIsNotNone(certificate)
|
45
|
+
self.assertIsInstance(certificate, cert.Cert)
|
46
|
+
|
47
|
+
def test_get_secret(self):
|
48
|
+
secret_ref = uuidutils.generate_uuid()
|
49
|
+
secret = self.manager.get_secret(
|
50
|
+
context=None,
|
51
|
+
secret_ref=secret_ref)
|
52
|
+
self.assertIsNotNone(secret)
|
53
|
+
self.assertIsInstance(secret, cert.Cert)
|
@@ -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,
|
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()
|
@@ -813,7 +813,6 @@ class TestHaproxyCfg(base.TestCase):
|
|
813
813
|
" balance roundrobin\n"
|
814
814
|
" cookie SRV insert indirect nocache\n"
|
815
815
|
" timeout check 31s\n"
|
816
|
-
" option ssl-hello-chk\n"
|
817
816
|
" fullconn {maxconn}\n"
|
818
817
|
" option allbackups\n"
|
819
818
|
" timeout connect 5000\n"
|
@@ -1331,11 +1330,11 @@ class TestHaproxyCfg(base.TestCase):
|
|
1331
1330
|
" timeout connect 5000\n"
|
1332
1331
|
" timeout server 50000\n"
|
1333
1332
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
1334
|
-
"check inter 30s fall 3 rise 2 cookie
|
1335
|
-
"{opts} alpn {alpn}\n"
|
1333
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1334
|
+
"sample_member_id_1 {opts} alpn {alpn}\n"
|
1336
1335
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
1337
|
-
"check inter 30s fall 3 rise 2 cookie
|
1338
|
-
"{opts} alpn {alpn}\n\n").format(
|
1336
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1337
|
+
"sample_member_id_2 {opts} alpn {alpn}\n\n").format(
|
1339
1338
|
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
|
1340
1339
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
1341
1340
|
" ciphers " + constants.CIPHERS_OWASP_SUITE_B +
|
@@ -1410,11 +1409,11 @@ class TestHaproxyCfg(base.TestCase):
|
|
1410
1409
|
" timeout connect 5000\n"
|
1411
1410
|
" timeout server 50000\n"
|
1412
1411
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
1413
|
-
"check inter 30s fall 3 rise 2 cookie
|
1414
|
-
"{opts} alpn {alpn}\n"
|
1412
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1413
|
+
"sample_member_id_1 {opts} alpn {alpn}\n"
|
1415
1414
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
1416
|
-
"check inter 30s fall 3 rise 2 cookie
|
1417
|
-
"{opts} alpn {alpn}\n\n").format(
|
1415
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1416
|
+
"sample_member_id_2 {opts} alpn {alpn}\n\n").format(
|
1418
1417
|
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
|
1419
1418
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
1420
1419
|
" ciphers " + constants.CIPHERS_OWASP_SUITE_B,
|
@@ -1450,11 +1449,11 @@ class TestHaproxyCfg(base.TestCase):
|
|
1450
1449
|
" timeout connect 5000\n"
|
1451
1450
|
" timeout server 50000\n"
|
1452
1451
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
1453
|
-
"check inter 30s fall 3 rise 2 cookie
|
1454
|
-
"{opts} alpn {alpn}\n"
|
1452
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1453
|
+
"sample_member_id_1 {opts} alpn {alpn}\n"
|
1455
1454
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
1456
|
-
"check inter 30s fall 3 rise 2 cookie
|
1457
|
-
"{opts} alpn {alpn}\n\n").format(
|
1455
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1456
|
+
"sample_member_id_2 {opts} alpn {alpn}\n\n").format(
|
1458
1457
|
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
|
1459
1458
|
opts="ssl crt %s verify none sni ssl_fc_sni" % cert_file_path +
|
1460
1459
|
" no-sslv3 no-tlsv10 no-tlsv11",
|
@@ -1550,11 +1549,11 @@ class TestHaproxyCfg(base.TestCase):
|
|
1550
1549
|
" timeout connect 5000\n"
|
1551
1550
|
" timeout server 50000\n"
|
1552
1551
|
" server sample_member_id_1 10.0.0.99:82 weight 13 "
|
1553
|
-
"check inter 30s fall 3 rise 2 cookie
|
1554
|
-
"{opts} alpn {alpn}\n"
|
1552
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1553
|
+
"sample_member_id_1 {opts} alpn {alpn}\n"
|
1555
1554
|
" server sample_member_id_2 10.0.0.98:82 weight 13 "
|
1556
|
-
"check inter 30s fall 3 rise 2 cookie
|
1557
|
-
"{opts} alpn {alpn}\n\n").format(
|
1555
|
+
"check check-alpn {alpn} inter 30s fall 3 rise 2 cookie "
|
1556
|
+
"sample_member_id_2 {opts} alpn {alpn}\n\n").format(
|
1558
1557
|
maxconn=constants.HAPROXY_DEFAULT_MAXCONN,
|
1559
1558
|
opts="%s %s %s %s %s %s" % (
|
1560
1559
|
"ssl", "crt", pool_client_cert,
|
@@ -78,3 +78,38 @@ class TestConfig(base.TestCase):
|
|
78
78
|
self.assertEqual(
|
79
79
|
3,
|
80
80
|
conf.conf.haproxy_amphora.active_connection_retry_interval)
|
81
|
+
|
82
|
+
def test_handle_neutron_deprecations(self):
|
83
|
+
conf = self.useFixture(oslo_fixture.Config(config.cfg.CONF))
|
84
|
+
|
85
|
+
# The deprecated settings are copied to the new settings
|
86
|
+
conf.config(endpoint='my_endpoint',
|
87
|
+
endpoint_type='internal',
|
88
|
+
ca_certificates_file='/path/to/certs',
|
89
|
+
group='neutron')
|
90
|
+
|
91
|
+
config.handle_neutron_deprecations()
|
92
|
+
|
93
|
+
self.assertEqual('my_endpoint', conf.conf.neutron.endpoint_override)
|
94
|
+
self.assertEqual(['internal'], conf.conf.neutron.valid_interfaces)
|
95
|
+
self.assertEqual('/path/to/certs', conf.conf.neutron.cafile)
|
96
|
+
|
97
|
+
# Test case for https://bugs.launchpad.net/octavia/+bug/2051604
|
98
|
+
def test_handle_neutron_deprecations_with_precedence(self):
|
99
|
+
conf = self.useFixture(oslo_fixture.Config(config.cfg.CONF))
|
100
|
+
|
101
|
+
# The deprecated settings should not override the new settings when
|
102
|
+
# they exist
|
103
|
+
conf.config(endpoint='my_old_endpoint',
|
104
|
+
endpoint_type='old_type',
|
105
|
+
ca_certificates_file='/path/to/old_certs',
|
106
|
+
endpoint_override='my_endpoint',
|
107
|
+
valid_interfaces=['internal'],
|
108
|
+
cafile='/path/to/certs',
|
109
|
+
group='neutron')
|
110
|
+
|
111
|
+
config.handle_neutron_deprecations()
|
112
|
+
|
113
|
+
self.assertEqual('my_endpoint', conf.conf.neutron.endpoint_override)
|
114
|
+
self.assertEqual(['internal'], conf.conf.neutron.valid_interfaces)
|
115
|
+
self.assertEqual('/path/to/certs', conf.conf.neutron.cafile)
|
@@ -52,3 +52,35 @@ class TestKeystoneSession(base.TestCase):
|
|
52
52
|
[call("Overriding [%s].%s with '%s'", 'neutron', 'cafile',
|
53
53
|
'bar')]
|
54
54
|
)
|
55
|
+
|
56
|
+
# Test case for https://bugs.launchpad.net/octavia/+bug/2051604
|
57
|
+
@mock.patch("octavia.common.keystone.ks_loading"
|
58
|
+
".load_auth_from_conf_options")
|
59
|
+
@mock.patch("octavia.common.keystone.LOG")
|
60
|
+
def test_get_auth_neutron_override_endpoint(self,
|
61
|
+
mock_log,
|
62
|
+
mock_load_auth):
|
63
|
+
opt_mock = mock.MagicMock()
|
64
|
+
opt_mock.dest = "foo"
|
65
|
+
conf = oslo_fixture.Config(cfg.CONF)
|
66
|
+
conf.conf.set_default('endpoint_override', 'default_endpoint',
|
67
|
+
'service_auth')
|
68
|
+
conf.conf.set_default('endpoint_override', 'new_endpoint',
|
69
|
+
'neutron')
|
70
|
+
|
71
|
+
mock_load_auth.side_effect = [
|
72
|
+
ks_exceptions.auth_plugins.MissingRequiredOptions(
|
73
|
+
[opt_mock]),
|
74
|
+
None,
|
75
|
+
None
|
76
|
+
]
|
77
|
+
|
78
|
+
sess = ks.KeystoneSession("neutron")
|
79
|
+
sess.get_auth()
|
80
|
+
|
81
|
+
# [service_auth].endpoint_override should not override
|
82
|
+
# [neutron].endpoint_override
|
83
|
+
self.assertNotIn(
|
84
|
+
call("Overriding [%s].%s with '%s'", 'neutron',
|
85
|
+
'endpoint_override', 'default_endpoint'),
|
86
|
+
mock_log.debug.mock_calls)
|