octavia 13.0.0__py3-none-any.whl → 14.0.0__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 (135) hide show
  1. octavia/amphorae/backends/agent/api_server/lvs_listener_base.py +1 -1
  2. octavia/amphorae/backends/agent/api_server/osutils.py +5 -5
  3. octavia/amphorae/backends/agent/api_server/plug.py +3 -2
  4. octavia/amphorae/backends/agent/api_server/rules_schema.py +52 -0
  5. octavia/amphorae/backends/agent/api_server/server.py +28 -1
  6. octavia/amphorae/backends/utils/interface.py +45 -6
  7. octavia/amphorae/backends/utils/interface_file.py +9 -6
  8. octavia/amphorae/backends/utils/nftable_utils.py +125 -0
  9. octavia/amphorae/drivers/driver_base.py +27 -0
  10. octavia/amphorae/drivers/haproxy/rest_api_driver.py +42 -10
  11. octavia/amphorae/drivers/health/heartbeat_udp.py +2 -2
  12. octavia/amphorae/drivers/keepalived/vrrp_rest_driver.py +2 -1
  13. octavia/amphorae/drivers/noop_driver/driver.py +25 -0
  14. octavia/api/app.py +3 -0
  15. octavia/api/common/pagination.py +2 -2
  16. octavia/api/drivers/amphora_driver/flavor_schema.py +6 -1
  17. octavia/api/root_controller.py +4 -1
  18. octavia/api/v2/controllers/health_monitor.py +0 -1
  19. octavia/api/v2/controllers/l7policy.py +0 -1
  20. octavia/api/v2/controllers/l7rule.py +0 -1
  21. octavia/api/v2/controllers/listener.py +0 -1
  22. octavia/api/v2/controllers/load_balancer.py +13 -7
  23. octavia/api/v2/controllers/member.py +6 -3
  24. octavia/api/v2/controllers/pool.py +6 -7
  25. octavia/api/v2/types/load_balancer.py +5 -1
  26. octavia/api/v2/types/pool.py +1 -1
  27. octavia/certificates/common/pkcs12.py +9 -9
  28. octavia/certificates/manager/barbican.py +24 -16
  29. octavia/certificates/manager/castellan_mgr.py +12 -7
  30. octavia/certificates/manager/local.py +4 -4
  31. octavia/certificates/manager/noop.py +106 -0
  32. octavia/cmd/driver_agent.py +1 -1
  33. octavia/cmd/health_checker.py +0 -4
  34. octavia/cmd/health_manager.py +1 -5
  35. octavia/cmd/house_keeping.py +1 -1
  36. octavia/cmd/interface.py +0 -4
  37. octavia/cmd/octavia_worker.py +0 -4
  38. octavia/cmd/prometheus_proxy.py +0 -5
  39. octavia/cmd/status.py +0 -6
  40. octavia/common/base_taskflow.py +1 -1
  41. octavia/common/clients.py +15 -3
  42. octavia/common/config.py +24 -6
  43. octavia/common/constants.py +34 -0
  44. octavia/common/data_models.py +3 -1
  45. octavia/common/exceptions.py +11 -0
  46. octavia/common/jinja/haproxy/combined_listeners/templates/macros.j2 +7 -5
  47. octavia/common/keystone.py +7 -7
  48. octavia/common/tls_utils/cert_parser.py +24 -10
  49. octavia/common/utils.py +6 -0
  50. octavia/common/validate.py +2 -2
  51. octavia/compute/drivers/nova_driver.py +23 -5
  52. octavia/controller/worker/task_utils.py +28 -6
  53. octavia/controller/worker/v2/controller_worker.py +49 -15
  54. octavia/controller/worker/v2/flows/amphora_flows.py +120 -21
  55. octavia/controller/worker/v2/flows/flow_utils.py +15 -13
  56. octavia/controller/worker/v2/flows/listener_flows.py +95 -5
  57. octavia/controller/worker/v2/flows/load_balancer_flows.py +74 -30
  58. octavia/controller/worker/v2/taskflow_jobboard_driver.py +17 -1
  59. octavia/controller/worker/v2/tasks/amphora_driver_tasks.py +145 -24
  60. octavia/controller/worker/v2/tasks/compute_tasks.py +1 -1
  61. octavia/controller/worker/v2/tasks/database_tasks.py +72 -41
  62. octavia/controller/worker/v2/tasks/lifecycle_tasks.py +97 -41
  63. octavia/controller/worker/v2/tasks/network_tasks.py +57 -60
  64. octavia/controller/worker/v2/tasks/shim_tasks.py +28 -0
  65. octavia/db/migration/alembic_migrations/versions/55874a4ceed6_add_l7policy_action_redirect_prefix.py +1 -1
  66. octavia/db/migration/alembic_migrations/versions/5a3ee5472c31_add_cert_expiration__infor_in_amphora_table.py +1 -1
  67. octavia/db/migration/alembic_migrations/versions/6742ca1b27c2_add_l7policy_redirect_http_code.py +1 -1
  68. octavia/db/migration/alembic_migrations/versions/db2a73e82626_add_vnic_type_for_vip.py +36 -0
  69. octavia/db/models.py +1 -0
  70. octavia/db/prepare.py +1 -1
  71. octavia/db/repositories.py +53 -34
  72. octavia/distributor/drivers/driver_base.py +1 -1
  73. octavia/network/base.py +3 -16
  74. octavia/network/data_models.py +4 -1
  75. octavia/network/drivers/neutron/allowed_address_pairs.py +27 -26
  76. octavia/network/drivers/noop_driver/driver.py +10 -23
  77. octavia/tests/common/sample_certs.py +115 -0
  78. octavia/tests/common/sample_haproxy_prometheus +1 -1
  79. octavia/tests/functional/amphorae/backend/agent/api_server/test_server.py +37 -0
  80. octavia/tests/functional/api/test_healthcheck.py +2 -2
  81. octavia/tests/functional/api/v2/base.py +1 -1
  82. octavia/tests/functional/api/v2/test_listener.py +45 -0
  83. octavia/tests/functional/api/v2/test_load_balancer.py +17 -0
  84. octavia/tests/functional/db/base.py +9 -0
  85. octavia/tests/functional/db/test_models.py +2 -1
  86. octavia/tests/functional/db/test_repositories.py +55 -99
  87. octavia/tests/unit/amphorae/backends/agent/api_server/test_osutils.py +4 -2
  88. octavia/tests/unit/amphorae/backends/utils/test_interface.py +201 -1
  89. octavia/tests/unit/amphorae/backends/utils/test_keepalivedlvs_query.py +1 -1
  90. octavia/tests/unit/amphorae/backends/utils/test_nftable_utils.py +194 -0
  91. octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver.py +27 -5
  92. octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver_1_0.py +15 -2
  93. octavia/tests/unit/amphorae/drivers/keepalived/test_vrrp_rest_driver.py +17 -0
  94. octavia/tests/unit/amphorae/drivers/noop_driver/test_driver.py +2 -1
  95. octavia/tests/unit/api/v2/types/test_pool.py +71 -0
  96. octavia/tests/unit/certificates/manager/test_barbican.py +3 -3
  97. octavia/tests/unit/certificates/manager/test_noop.py +53 -0
  98. octavia/tests/unit/common/jinja/haproxy/combined_listeners/test_jinja_cfg.py +16 -17
  99. octavia/tests/unit/common/sample_configs/sample_configs_combined.py +5 -3
  100. octavia/tests/unit/common/test_config.py +35 -0
  101. octavia/tests/unit/common/test_keystone.py +32 -0
  102. octavia/tests/unit/common/test_utils.py +39 -0
  103. octavia/tests/unit/compute/drivers/test_nova_driver.py +22 -0
  104. octavia/tests/unit/controller/worker/test_task_utils.py +58 -2
  105. octavia/tests/unit/controller/worker/v2/flows/test_amphora_flows.py +28 -5
  106. octavia/tests/unit/controller/worker/v2/flows/test_listener_flows.py +64 -16
  107. octavia/tests/unit/controller/worker/v2/flows/test_load_balancer_flows.py +49 -9
  108. octavia/tests/unit/controller/worker/v2/tasks/test_amphora_driver_tasks.py +265 -17
  109. octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks.py +101 -1
  110. octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks_quota.py +19 -19
  111. octavia/tests/unit/controller/worker/v2/tasks/test_network_tasks.py +105 -42
  112. octavia/tests/unit/controller/worker/v2/tasks/test_shim_tasks.py +33 -0
  113. octavia/tests/unit/controller/worker/v2/test_controller_worker.py +85 -42
  114. octavia/tests/unit/network/drivers/neutron/test_allowed_address_pairs.py +48 -51
  115. octavia/tests/unit/network/drivers/neutron/test_utils.py +2 -0
  116. octavia/tests/unit/network/drivers/noop_driver/test_driver.py +0 -7
  117. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/README.rst +6 -1
  118. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/diskimage-create.sh +10 -4
  119. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/requirements.txt +0 -2
  120. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/tox.ini +30 -13
  121. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/AUTHORS +5 -0
  122. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/METADATA +6 -6
  123. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/RECORD +134 -126
  124. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/entry_points.txt +1 -1
  125. octavia-14.0.0.dist-info/pbr.json +1 -0
  126. octavia-13.0.0.dist-info/pbr.json +0 -1
  127. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/LICENSE +0 -0
  128. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/README.rst +0 -0
  129. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/image-tests.sh +0 -0
  130. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/test-requirements.txt +0 -0
  131. {octavia-13.0.0.data → octavia-14.0.0.data}/data/share/octavia/diskimage-create/version.txt +0 -0
  132. {octavia-13.0.0.data → octavia-14.0.0.data}/scripts/octavia-wsgi +0 -0
  133. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/LICENSE +0 -0
  134. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/WHEEL +0 -0
  135. {octavia-13.0.0.dist-info → octavia-14.0.0.dist-info}/top_level.txt +0 -0
@@ -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('OpenSSL.crypto.load_pkcs12')
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 = [crypto.Error]
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)
@@ -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 sample_member_id_1 "
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 sample_member_id_2 "
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 sample_member_id_1 "
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 sample_member_id_2 "
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 sample_member_id_1 "
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 sample_member_id_2 "
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 sample_member_id_1 "
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 sample_member_id_2 "
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,
@@ -670,9 +670,11 @@ def sample_vrrp_group_tuple():
670
670
  smtp_connect_timeout='')
671
671
 
672
672
 
673
- def sample_vip_tuple(ip_address='10.0.0.2', subnet_id='vip_subnet_uuid'):
674
- vip = collections.namedtuple('vip', ('ip_address', 'subnet_id'))
675
- return vip(ip_address=ip_address, subnet_id=subnet_id)
673
+ def sample_vip_tuple(ip_address='10.0.0.2', subnet_id='vip_subnet_uuid',
674
+ vnic_type='normal'):
675
+ vip = collections.namedtuple('vip', ('ip_address', 'subnet_id',
676
+ 'vnic_type'))
677
+ return vip(ip_address=ip_address, subnet_id=subnet_id, vnic_type=vnic_type)
676
678
 
677
679
 
678
680
  def sample_listener_tuple(proto=None, monitor=True, alloc_default_pool=True,
@@ -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)
@@ -13,6 +13,7 @@
13
13
  # under the License.
14
14
  from unittest import mock
15
15
 
16
+ from octavia_lib.common import constants as lib_consts
16
17
  from oslo_utils import uuidutils
17
18
 
18
19
  from octavia.common import constants
@@ -139,3 +140,41 @@ class TestConfig(base.TestCase):
139
140
  expected_sg_name = constants.VIP_SECURITY_GROUP_PREFIX + FAKE_LB_ID
140
141
  self.assertEqual(expected_sg_name,
141
142
  utils.get_vip_security_group_name(FAKE_LB_ID))
143
+
144
+ def test_map_protocol_to_nftable_protocol(self):
145
+ result = utils.map_protocol_to_nftable_protocol(
146
+ {constants.PROTOCOL: lib_consts.PROTOCOL_TCP})
147
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
148
+
149
+ result = utils.map_protocol_to_nftable_protocol(
150
+ {constants.PROTOCOL: lib_consts.PROTOCOL_HTTP})
151
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
152
+
153
+ result = utils.map_protocol_to_nftable_protocol(
154
+ {constants.PROTOCOL: lib_consts.PROTOCOL_HTTPS})
155
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
156
+
157
+ result = utils.map_protocol_to_nftable_protocol(
158
+ {constants.PROTOCOL: lib_consts.PROTOCOL_TERMINATED_HTTPS})
159
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
160
+
161
+ result = utils.map_protocol_to_nftable_protocol(
162
+ {constants.PROTOCOL: lib_consts.PROTOCOL_PROXY})
163
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
164
+
165
+ result = utils.map_protocol_to_nftable_protocol(
166
+ {constants.PROTOCOL: lib_consts.PROTOCOL_PROXYV2})
167
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
168
+
169
+ result = utils.map_protocol_to_nftable_protocol(
170
+ {constants.PROTOCOL: lib_consts.PROTOCOL_UDP})
171
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_UDP}, result)
172
+
173
+ result = utils.map_protocol_to_nftable_protocol(
174
+ {constants.PROTOCOL: lib_consts.PROTOCOL_SCTP})
175
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_SCTP},
176
+ result)
177
+
178
+ result = utils.map_protocol_to_nftable_protocol(
179
+ {constants.PROTOCOL: lib_consts.PROTOCOL_PROMETHEUS})
180
+ self.assertEqual({constants.PROTOCOL: lib_consts.PROTOCOL_TCP}, result)
@@ -457,6 +457,28 @@ class TestNovaClient(base.TestCase):
457
457
  self.manager.attach_network_or_port,
458
458
  self.compute_id, self.network_id)
459
459
 
460
+ def test_attach_network_or_port_fail_claim_pci_exception(self):
461
+ self.manager.manager.interface_attach.side_effect = [
462
+ nova_exceptions.BadRequest('Failed to claim PCI device'),
463
+ nova_exceptions.BadRequest('NotAClaimFailure')]
464
+ self.assertRaises(exceptions.ComputeNoResourcesException,
465
+ self.manager.attach_network_or_port,
466
+ self.compute_id, self.network_id)
467
+ self.assertRaises(nova_exceptions.BadRequest,
468
+ self.manager.attach_network_or_port,
469
+ self.compute_id, self.network_id)
470
+
471
+ def test_attach_network_or_port_port_bind_fail_exception(self):
472
+ self.manager.manager.interface_attach.side_effect = [
473
+ nova_exceptions.ClientException('PortBindingFailed'),
474
+ nova_exceptions.ClientException('NotABindFailure')]
475
+ self.assertRaises(exceptions.ComputeNoResourcesException,
476
+ self.manager.attach_network_or_port,
477
+ self.compute_id, self.network_id)
478
+ self.assertRaises(nova_exceptions.ClientException,
479
+ self.manager.attach_network_or_port,
480
+ self.compute_id, self.network_id)
481
+
460
482
  def test_attach_network_or_port_unknown_exception(self):
461
483
  self.manager.manager.interface_attach.side_effect = [Exception('boom')]
462
484
  self.assertRaises(exceptions.ComputeUnknownException,
@@ -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
 
@@ -34,45 +34,77 @@ class TestListenerFlows(base.TestCase):
34
34
 
35
35
  def test_get_create_listener_flow(self, mock_get_net_driver):
36
36
 
37
- listener_flow = self.ListenerFlow.get_create_listener_flow()
37
+ flavor_dict = {
38
+ constants.SRIOV_VIP: True,
39
+ constants.LOADBALANCER_TOPOLOGY: constants.TOPOLOGY_SINGLE}
40
+ listener_flow = self.ListenerFlow.get_create_listener_flow(
41
+ flavor_dict=flavor_dict)
38
42
 
39
43
  self.assertIsInstance(listener_flow, flow.Flow)
40
44
 
41
45
  self.assertIn(constants.LISTENERS, listener_flow.requires)
42
46
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
47
+ self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
43
48
 
44
- self.assertEqual(2, len(listener_flow.requires))
45
- self.assertEqual(0, len(listener_flow.provides))
49
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
50
+ listener_flow.provides)
51
+ self.assertIn(constants.AMPHORAE, listener_flow.provides)
52
+ self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
46
53
 
47
- def test_get_delete_listener_flow(self, mock_get_net_driver):
54
+ self.assertEqual(3, len(listener_flow.requires))
55
+ self.assertEqual(3, len(listener_flow.provides))
48
56
 
49
- listener_flow = self.ListenerFlow.get_delete_listener_flow()
57
+ def test_get_delete_listener_flow(self, mock_get_net_driver):
58
+ flavor_dict = {
59
+ constants.SRIOV_VIP: True,
60
+ constants.LOADBALANCER_TOPOLOGY: constants.TOPOLOGY_SINGLE}
61
+ listener_flow = self.ListenerFlow.get_delete_listener_flow(
62
+ flavor_dict=flavor_dict)
50
63
 
51
64
  self.assertIsInstance(listener_flow, flow.Flow)
52
65
 
53
66
  self.assertIn(constants.LISTENER, listener_flow.requires)
54
67
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
55
68
  self.assertIn(constants.PROJECT_ID, listener_flow.requires)
69
+ self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
56
70
 
57
- self.assertEqual(3, len(listener_flow.requires))
58
- self.assertEqual(0, len(listener_flow.provides))
71
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
72
+ listener_flow.provides)
73
+ self.assertIn(constants.AMPHORAE, listener_flow.provides)
74
+ self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
75
+
76
+ self.assertEqual(4, len(listener_flow.requires))
77
+ self.assertEqual(3, len(listener_flow.provides))
59
78
 
60
79
  def test_get_delete_listener_internal_flow(self, mock_get_net_driver):
80
+ flavor_dict = {
81
+ constants.SRIOV_VIP: True,
82
+ constants.LOADBALANCER_TOPOLOGY: constants.TOPOLOGY_SINGLE}
61
83
  fake_listener = {constants.LISTENER_ID: uuidutils.generate_uuid()}
62
84
  listener_flow = self.ListenerFlow.get_delete_listener_internal_flow(
63
- fake_listener)
85
+ fake_listener, flavor_dict=flavor_dict)
64
86
 
65
87
  self.assertIsInstance(listener_flow, flow.Flow)
66
88
 
67
89
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
68
90
  self.assertIn(constants.PROJECT_ID, listener_flow.requires)
91
+ self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
92
+
93
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
94
+ listener_flow.provides)
95
+ self.assertIn(constants.AMPHORAE, listener_flow.provides)
96
+ self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
69
97
 
70
- self.assertEqual(2, len(listener_flow.requires))
71
- self.assertEqual(0, len(listener_flow.provides))
98
+ self.assertEqual(3, len(listener_flow.requires))
99
+ self.assertEqual(3, len(listener_flow.provides))
72
100
 
73
101
  def test_get_update_listener_flow(self, mock_get_net_driver):
102
+ flavor_dict = {
103
+ constants.SRIOV_VIP: True,
104
+ constants.LOADBALANCER_TOPOLOGY: constants.TOPOLOGY_SINGLE}
74
105
 
75
- listener_flow = self.ListenerFlow.get_update_listener_flow()
106
+ listener_flow = self.ListenerFlow.get_update_listener_flow(
107
+ flavor_dict=flavor_dict)
76
108
 
77
109
  self.assertIsInstance(listener_flow, flow.Flow)
78
110
 
@@ -80,15 +112,31 @@ class TestListenerFlows(base.TestCase):
80
112
  self.assertIn(constants.UPDATE_DICT, listener_flow.requires)
81
113
  self.assertIn(constants.LISTENERS, listener_flow.requires)
82
114
  self.assertIn(constants.LOADBALANCER_ID, listener_flow.requires)
115
+ self.assertIn(constants.AMPHORAE_STATUS, listener_flow.requires)
83
116
 
84
- self.assertEqual(4, len(listener_flow.requires))
85
- self.assertEqual(0, len(listener_flow.provides))
117
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
118
+ listener_flow.provides)
119
+ self.assertIn(constants.AMPHORAE, listener_flow.provides)
120
+ self.assertIn(constants.AMPHORA_FIREWALL_RULES, listener_flow.provides)
121
+
122
+ self.assertEqual(5, len(listener_flow.requires))
123
+ self.assertEqual(3, len(listener_flow.provides))
86
124
 
87
125
  def test_get_create_all_listeners_flow(self, mock_get_net_driver):
88
- listeners_flow = self.ListenerFlow.get_create_all_listeners_flow()
126
+ flavor_dict = {
127
+ constants.SRIOV_VIP: True,
128
+ constants.LOADBALANCER_TOPOLOGY: constants.TOPOLOGY_ACTIVE_STANDBY}
129
+ listeners_flow = self.ListenerFlow.get_create_all_listeners_flow(
130
+ flavor_dict=flavor_dict)
89
131
  self.assertIsInstance(listeners_flow, flow.Flow)
90
132
  self.assertIn(constants.LOADBALANCER, listeners_flow.requires)
91
133
  self.assertIn(constants.LOADBALANCER_ID, listeners_flow.requires)
134
+ self.assertIn(constants.AMPHORAE_STATUS, listeners_flow.requires)
92
135
  self.assertIn(constants.LOADBALANCER, listeners_flow.provides)
93
- self.assertEqual(2, len(listeners_flow.requires))
94
- self.assertEqual(2, len(listeners_flow.provides))
136
+ self.assertIn(constants.AMPHORAE_NETWORK_CONFIG,
137
+ listeners_flow.provides)
138
+ self.assertIn(constants.AMPHORAE, listeners_flow.provides)
139
+ self.assertIn(constants.AMPHORA_FIREWALL_RULES,
140
+ listeners_flow.provides)
141
+ self.assertEqual(3, len(listeners_flow.requires))
142
+ self.assertEqual(5, len(listeners_flow.provides))