octavia 15.0.0__py3-none-any.whl → 16.0.0.0rc1__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/loadbalancer.py +6 -6
- octavia/amphorae/backends/agent/api_server/plug.py +1 -1
- octavia/amphorae/backends/agent/api_server/util.py +35 -2
- octavia/amphorae/backends/health_daemon/status_message.py +1 -2
- octavia/amphorae/drivers/haproxy/rest_api_driver.py +12 -7
- octavia/api/drivers/amphora_driver/flavor_schema.py +5 -0
- octavia/api/drivers/noop_driver/driver.py +2 -1
- octavia/api/drivers/utils.py +12 -0
- octavia/api/root_controller.py +8 -2
- octavia/api/v2/controllers/base.py +8 -4
- octavia/api/v2/controllers/listener.py +12 -2
- octavia/api/v2/controllers/load_balancer.py +33 -1
- octavia/api/v2/controllers/member.py +58 -4
- octavia/api/v2/types/load_balancer.py +7 -1
- octavia/api/v2/types/member.py +3 -0
- octavia/common/base_taskflow.py +19 -10
- octavia/common/clients.py +8 -2
- octavia/common/config.py +17 -2
- octavia/common/constants.py +6 -0
- octavia/common/data_models.py +32 -2
- octavia/common/exceptions.py +5 -0
- octavia/common/utils.py +4 -1
- octavia/common/validate.py +16 -0
- octavia/compute/drivers/noop_driver/driver.py +30 -1
- octavia/controller/healthmanager/health_manager.py +7 -0
- octavia/controller/worker/v2/flows/amphora_flows.py +3 -5
- octavia/controller/worker/v2/flows/listener_flows.py +2 -1
- octavia/controller/worker/v2/flows/load_balancer_flows.py +38 -0
- octavia/controller/worker/v2/taskflow_jobboard_driver.py +34 -6
- octavia/controller/worker/v2/tasks/compute_tasks.py +9 -5
- octavia/controller/worker/v2/tasks/database_tasks.py +26 -6
- octavia/controller/worker/v2/tasks/network_tasks.py +118 -70
- octavia/db/base_models.py +29 -5
- octavia/db/migration/alembic_migrations/versions/3097e55493ae_add_sg_id_to_vip_table.py +39 -0
- octavia/db/migration/alembic_migrations/versions/8db7a6443785_add_member_vnic_type.py +36 -0
- octavia/db/migration/alembic_migrations/versions/fabf4983846b_add_member_port_table.py +40 -0
- octavia/db/models.py +43 -1
- octavia/db/repositories.py +88 -9
- octavia/network/base.py +29 -12
- octavia/network/data_models.py +2 -1
- octavia/network/drivers/neutron/allowed_address_pairs.py +55 -46
- octavia/network/drivers/neutron/base.py +28 -16
- octavia/network/drivers/neutron/utils.py +2 -2
- octavia/network/drivers/noop_driver/driver.py +150 -29
- octavia/policies/__init__.py +4 -0
- octavia/policies/advanced_rbac.py +95 -0
- octavia/policies/base.py +5 -101
- octavia/policies/keystone_default_roles.py +81 -0
- octavia/policies/loadbalancer.py +13 -0
- octavia/tests/common/constants.py +2 -1
- octavia/tests/common/sample_data_models.py +27 -14
- octavia/tests/functional/amphorae/backend/agent/api_server/test_server.py +5 -4
- octavia/tests/functional/api/drivers/driver_agent/test_driver_agent.py +2 -1
- octavia/tests/functional/api/v2/test_health_monitor.py +1 -1
- octavia/tests/functional/api/v2/test_l7policy.py +1 -1
- octavia/tests/functional/api/v2/test_listener.py +1 -1
- octavia/tests/functional/api/v2/test_load_balancer.py +150 -4
- octavia/tests/functional/api/v2/test_member.py +50 -0
- octavia/tests/functional/api/v2/test_pool.py +1 -1
- octavia/tests/functional/api/v2/test_quotas.py +5 -8
- octavia/tests/functional/db/base.py +6 -6
- octavia/tests/functional/db/test_models.py +124 -1
- octavia/tests/functional/db/test_repositories.py +237 -19
- octavia/tests/unit/amphorae/backends/agent/api_server/test_util.py +89 -1
- octavia/tests/unit/amphorae/drivers/haproxy/test_rest_api_driver_1_0.py +10 -7
- octavia/tests/unit/api/drivers/test_utils.py +6 -1
- octavia/tests/unit/certificates/generator/test_local.py +1 -1
- octavia/tests/unit/common/test_base_taskflow.py +4 -3
- octavia/tests/unit/compute/drivers/noop_driver/test_driver.py +28 -2
- octavia/tests/unit/controller/worker/v2/flows/test_load_balancer_flows.py +27 -1
- octavia/tests/unit/controller/worker/v2/tasks/test_database_tasks.py +28 -6
- octavia/tests/unit/controller/worker/v2/tasks/test_network_tasks.py +100 -79
- octavia/tests/unit/controller/worker/v2/test_taskflow_jobboard_driver.py +8 -0
- octavia/tests/unit/network/drivers/neutron/test_allowed_address_pairs.py +62 -45
- octavia/tests/unit/network/drivers/neutron/test_base.py +7 -7
- octavia/tests/unit/network/drivers/noop_driver/test_driver.py +55 -42
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/tox.ini +0 -1
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/AUTHORS +3 -0
- octavia-16.0.0.0rc1.dist-info/METADATA +156 -0
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/RECORD +95 -90
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/WHEEL +1 -1
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/entry_points.txt +1 -1
- octavia-16.0.0.0rc1.dist-info/pbr.json +1 -0
- octavia-15.0.0.dist-info/METADATA +0 -156
- octavia-15.0.0.dist-info/pbr.json +0 -1
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/LICENSE +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/README.rst +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/README.rst +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/diskimage-create.sh +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/image-tests.sh +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/requirements.txt +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/test-requirements.txt +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/data/share/octavia/diskimage-create/version.txt +0 -0
- {octavia-15.0.0.data → octavia-16.0.0.0rc1.data}/scripts/octavia-wsgi +0 -0
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/LICENSE +0 -0
- {octavia-15.0.0.dist-info → octavia-16.0.0.0rc1.dist-info}/top_level.txt +0 -0
octavia/db/repositories.py
CHANGED
@@ -115,10 +115,19 @@ class BaseRepository:
|
|
115
115
|
session.query(self.model_class).filter_by(
|
116
116
|
id=id).update(model_kwargs)
|
117
117
|
|
118
|
-
def get(self, session, **filters):
|
118
|
+
def get(self, session, limited_graph=False, **filters):
|
119
119
|
"""Retrieves an entity from the database.
|
120
120
|
|
121
121
|
:param session: A Sql Alchemy database session.
|
122
|
+
:param limited_graph: Option controls number of processed nodes
|
123
|
+
in the graph. Default (with False) behaviour
|
124
|
+
is recursion iteration through all nodes
|
125
|
+
in the graph via to_data_model. With True value
|
126
|
+
recursion will stop at the first child node.
|
127
|
+
It means, that only limited number of nodes be
|
128
|
+
converted. This logic could be used for specific
|
129
|
+
cases, where information about full graph
|
130
|
+
is unnecessary.
|
122
131
|
:param filters: Filters to decide which entity should be retrieved.
|
123
132
|
:returns: octavia.common.data_model
|
124
133
|
"""
|
@@ -138,16 +147,26 @@ class BaseRepository:
|
|
138
147
|
if not model:
|
139
148
|
return None
|
140
149
|
|
141
|
-
|
150
|
+
recursion_depth = 0 if limited_graph else None
|
151
|
+
return model.to_data_model(recursion_depth=recursion_depth)
|
142
152
|
|
143
153
|
def get_all(self, session, pagination_helper=None,
|
144
|
-
query_options=None, **filters):
|
154
|
+
query_options=None, limited_graph=False, **filters):
|
145
155
|
|
146
156
|
"""Retrieves a list of entities from the database.
|
147
157
|
|
148
158
|
:param session: A Sql Alchemy database session.
|
149
159
|
:param pagination_helper: Helper to apply pagination and sorting.
|
150
160
|
:param query_options: Optional query options to apply.
|
161
|
+
:param limited_graph: Option controls number of processed nodes
|
162
|
+
in the graph. Default (with False) behaviour
|
163
|
+
is recursion iteration through all nodes
|
164
|
+
in the graph via to_data_model. With True value
|
165
|
+
recursion will stop at the first child node.
|
166
|
+
It means, that only limited number of nodes be
|
167
|
+
converted. This logic could be used for specific
|
168
|
+
cases, where information about full graph
|
169
|
+
is unnecessary.
|
151
170
|
:param filters: Filters to decide which entities should be retrieved.
|
152
171
|
:returns: [octavia.common.data_model]
|
153
172
|
"""
|
@@ -170,8 +189,11 @@ class BaseRepository:
|
|
170
189
|
else:
|
171
190
|
links = None
|
172
191
|
model_list = query.all()
|
173
|
-
|
174
|
-
data_model_list = [
|
192
|
+
recursion_depth = 1 if limited_graph else None
|
193
|
+
data_model_list = [
|
194
|
+
model.to_data_model(recursion_depth=recursion_depth)
|
195
|
+
for model in model_list
|
196
|
+
]
|
175
197
|
return data_model_list, links
|
176
198
|
|
177
199
|
def exists(self, session, id):
|
@@ -234,6 +256,7 @@ class Repositories:
|
|
234
256
|
self.flavor_profile = FlavorProfileRepository()
|
235
257
|
self.availability_zone = AvailabilityZoneRepository()
|
236
258
|
self.availability_zone_profile = AvailabilityZoneProfileRepository()
|
259
|
+
self.amphora_member_port = AmphoraMemberPortRepository()
|
237
260
|
|
238
261
|
def create_load_balancer_and_vip(self, session, lb_dict, vip_dict,
|
239
262
|
additional_vip_dicts=None):
|
@@ -253,9 +276,17 @@ class Repositories:
|
|
253
276
|
lb_dict['id'] = uuidutils.generate_uuid()
|
254
277
|
lb = models.LoadBalancer(**lb_dict)
|
255
278
|
session.add(lb)
|
279
|
+
vip_sg_ids = vip_dict.pop(consts.SG_IDS, [])
|
256
280
|
vip_dict['load_balancer_id'] = lb_dict['id']
|
257
281
|
vip = models.Vip(**vip_dict)
|
258
282
|
session.add(vip)
|
283
|
+
if vip_sg_ids:
|
284
|
+
vip_dict[consts.SG_IDS] = vip_sg_ids
|
285
|
+
for vip_sg_id in vip_sg_ids:
|
286
|
+
vip_sg = models.VipSecurityGroup(
|
287
|
+
load_balancer_id=lb_dict['id'],
|
288
|
+
sg_id=vip_sg_id)
|
289
|
+
session.add(vip_sg)
|
259
290
|
for add_vip_dict in additional_vip_dicts:
|
260
291
|
add_vip_dict['load_balancer_id'] = lb_dict['id']
|
261
292
|
add_vip_dict['network_id'] = vip_dict.get('network_id')
|
@@ -712,6 +743,8 @@ class LoadBalancerRepository(BaseRepository):
|
|
712
743
|
query_options = (
|
713
744
|
subqueryload(models.LoadBalancer.vip),
|
714
745
|
subqueryload(models.LoadBalancer.additional_vips),
|
746
|
+
(subqueryload(models.LoadBalancer.vip).
|
747
|
+
subqueryload(models.Vip.sgs)),
|
715
748
|
subqueryload(models.LoadBalancer.amphorae),
|
716
749
|
subqueryload(models.LoadBalancer.pools),
|
717
750
|
subqueryload(models.LoadBalancer.listeners),
|
@@ -789,8 +822,24 @@ class VipRepository(BaseRepository):
|
|
789
822
|
|
790
823
|
def update(self, session, load_balancer_id, **model_kwargs):
|
791
824
|
"""Updates a vip entity in the database by load_balancer_id."""
|
792
|
-
|
793
|
-
|
825
|
+
sg_ids = model_kwargs.pop(consts.SG_IDS, None)
|
826
|
+
|
827
|
+
vip = session.query(self.model_class).filter_by(
|
828
|
+
load_balancer_id=load_balancer_id)
|
829
|
+
if model_kwargs:
|
830
|
+
vip.update(model_kwargs)
|
831
|
+
|
832
|
+
# NOTE(gthiemonge) the vip must be updated when sg_ids is []
|
833
|
+
# (removal of current sg_ids)
|
834
|
+
if sg_ids is not None:
|
835
|
+
vip = vip.first()
|
836
|
+
vip.sgs = [
|
837
|
+
models.VipSecurityGroup(
|
838
|
+
load_balancer_id=load_balancer_id,
|
839
|
+
sg_id=sg_id)
|
840
|
+
for sg_id in sg_ids]
|
841
|
+
|
842
|
+
session.flush()
|
794
843
|
|
795
844
|
|
796
845
|
class AdditionalVipRepository(BaseRepository):
|
@@ -916,7 +965,8 @@ class PoolRepository(BaseRepository):
|
|
916
965
|
class MemberRepository(BaseRepository):
|
917
966
|
model_class = models.Member
|
918
967
|
|
919
|
-
def get_all_API_list(self, session, pagination_helper=None,
|
968
|
+
def get_all_API_list(self, session, pagination_helper=None,
|
969
|
+
limited_graph=False, **filters):
|
920
970
|
"""Get a list of members for the API list call.
|
921
971
|
|
922
972
|
This get_all returns a data set that is only one level deep
|
@@ -925,6 +975,8 @@ class MemberRepository(BaseRepository):
|
|
925
975
|
|
926
976
|
:param session: A Sql Alchemy database session.
|
927
977
|
:param pagination_helper: Helper to apply pagination and sorting.
|
978
|
+
:param limited_graph: Option to avoid recursion iteration through all
|
979
|
+
nodes in the graph via to_data_model
|
928
980
|
:param filters: Filters to decide which entities should be retrieved.
|
929
981
|
:returns: [octavia.common.data_model]
|
930
982
|
"""
|
@@ -938,7 +990,8 @@ class MemberRepository(BaseRepository):
|
|
938
990
|
|
939
991
|
return super().get_all(
|
940
992
|
session, pagination_helper=pagination_helper,
|
941
|
-
query_options=query_options,
|
993
|
+
query_options=query_options, limited_graph=limited_graph,
|
994
|
+
**filters)
|
942
995
|
|
943
996
|
def delete_members(self, session, member_ids):
|
944
997
|
"""Batch deletes members from a pool."""
|
@@ -1402,6 +1455,20 @@ class AmphoraRepository(BaseRepository):
|
|
1402
1455
|
amp.status = consts.PENDING_DELETE
|
1403
1456
|
lock_session.flush()
|
1404
1457
|
|
1458
|
+
def get_amphorae_ids_on_lb(self, session, lb_id):
|
1459
|
+
"""Returns a list of amphora IDs associated with the load balancer
|
1460
|
+
|
1461
|
+
:param session: A Sql Alchemy database session.
|
1462
|
+
:param lb_id: A load balancer ID.
|
1463
|
+
:returns: A list of amphora IDs
|
1464
|
+
"""
|
1465
|
+
return session.scalars(
|
1466
|
+
select(
|
1467
|
+
self.model_class.id
|
1468
|
+
).where(
|
1469
|
+
self.model_class.load_balancer_id == lb_id
|
1470
|
+
)).all()
|
1471
|
+
|
1405
1472
|
|
1406
1473
|
class AmphoraBuildReqRepository(BaseRepository):
|
1407
1474
|
model_class = models.AmphoraBuildRequest
|
@@ -2081,3 +2148,15 @@ class AvailabilityZoneRepository(_GetALLExceptDELETEDIdMixin, BaseRepository):
|
|
2081
2148
|
class AvailabilityZoneProfileRepository(_GetALLExceptDELETEDIdMixin,
|
2082
2149
|
BaseRepository):
|
2083
2150
|
model_class = models.AvailabilityZoneProfile
|
2151
|
+
|
2152
|
+
|
2153
|
+
class AmphoraMemberPortRepository(BaseRepository):
|
2154
|
+
model_class = models.AmphoraMemberPort
|
2155
|
+
|
2156
|
+
def get_port_ids(self, session, amphora_id):
|
2157
|
+
return session.scalars(
|
2158
|
+
select(
|
2159
|
+
self.model_class.port_id
|
2160
|
+
).where(
|
2161
|
+
self.model_class.amphora_id == amphora_id
|
2162
|
+
)).all()
|
octavia/network/base.py
CHANGED
@@ -13,10 +13,16 @@
|
|
13
13
|
# under the License.
|
14
14
|
|
15
15
|
import abc
|
16
|
+
import typing
|
16
17
|
|
17
18
|
from octavia.common import constants
|
19
|
+
from octavia.common import data_models
|
18
20
|
from octavia.common import exceptions
|
19
21
|
|
22
|
+
if typing.TYPE_CHECKING:
|
23
|
+
from octavia.common import context
|
24
|
+
import octavia.network.data_models as n_data_models
|
25
|
+
|
20
26
|
|
21
27
|
class NetworkException(exceptions.OctaviaException):
|
22
28
|
pass
|
@@ -94,7 +100,8 @@ class AbstractNetworkDriver(metaclass=abc.ABCMeta):
|
|
94
100
|
"""
|
95
101
|
|
96
102
|
@abc.abstractmethod
|
97
|
-
def allocate_vip(self, load_balancer)
|
103
|
+
def allocate_vip(self, load_balancer: data_models.LoadBalancer) -> (
|
104
|
+
tuple[data_models.Vip, list[data_models.AdditionalVip]]):
|
98
105
|
"""Allocates a virtual ip.
|
99
106
|
|
100
107
|
Reserves it for later use as the frontend connection of a load
|
@@ -156,16 +163,6 @@ class AbstractNetworkDriver(metaclass=abc.ABCMeta):
|
|
156
163
|
:raises: UnplugVIPException, PluggedVIPNotFound
|
157
164
|
"""
|
158
165
|
|
159
|
-
@abc.abstractmethod
|
160
|
-
def plug_network(self, compute_id, network_id):
|
161
|
-
"""Connects an existing amphora to an existing network.
|
162
|
-
|
163
|
-
:param compute_id: id of an amphora in the compute service
|
164
|
-
:param network_id: id of a network
|
165
|
-
:return: octavia.network.data_models.Interface instance
|
166
|
-
:raises: PlugNetworkException, AmphoraNotFound, NetworkNotFound
|
167
|
-
"""
|
168
|
-
|
169
166
|
@abc.abstractmethod
|
170
167
|
def unplug_network(self, compute_id, network_id):
|
171
168
|
"""Disconnects an existing amphora from an existing network.
|
@@ -294,13 +291,25 @@ class AbstractNetworkDriver(metaclass=abc.ABCMeta):
|
|
294
291
|
|
295
292
|
@abc.abstractmethod
|
296
293
|
def get_security_group(self, sg_name):
|
297
|
-
"""Retrieves the security group by
|
294
|
+
"""Retrieves the security group by its name.
|
298
295
|
|
299
296
|
:param sg_name: The security group name.
|
300
297
|
:return: octavia.network.data_models.SecurityGroup, None if not enabled
|
301
298
|
:raises: NetworkException, SecurityGroupNotFound
|
302
299
|
"""
|
303
300
|
|
301
|
+
@abc.abstractmethod
|
302
|
+
def get_security_group_by_id(self, sg_id: str,
|
303
|
+
context: 'context.RequestContext' = None) -> (
|
304
|
+
'n_data_models.SecurityGroup'):
|
305
|
+
"""Retrieves the security group by its id.
|
306
|
+
|
307
|
+
:param sg_id: The security group ID.
|
308
|
+
:param context: A request context
|
309
|
+
:return: octavia.network.data_models.SecurityGroup, None if not enabled
|
310
|
+
:raises: NetworkException, SecurityGroupNotFound
|
311
|
+
"""
|
312
|
+
|
304
313
|
@abc.abstractmethod
|
305
314
|
def failover_preparation(self, amphora):
|
306
315
|
"""Prepare an amphora for failover.
|
@@ -349,6 +358,14 @@ class AbstractNetworkDriver(metaclass=abc.ABCMeta):
|
|
349
358
|
:param vip: The VIP to plug
|
350
359
|
"""
|
351
360
|
|
361
|
+
@abc.abstractmethod
|
362
|
+
def update_aap_port_sg(self, load_balancer: data_models.LoadBalancer,
|
363
|
+
amphora: data_models.Amphora,
|
364
|
+
vip: data_models.Vip):
|
365
|
+
"""Updates the security group of the AAP port of an amphora
|
366
|
+
|
367
|
+
"""
|
368
|
+
|
352
369
|
@abc.abstractmethod
|
353
370
|
def plug_aap_port(self, load_balancer, vip, amphora, subnet):
|
354
371
|
"""Plugs the AAP port to the amp
|
octavia/network/data_models.py
CHANGED
@@ -19,12 +19,13 @@ from octavia.common import data_models
|
|
19
19
|
class Interface(data_models.BaseDataModel):
|
20
20
|
|
21
21
|
def __init__(self, id=None, compute_id=None, network_id=None,
|
22
|
-
fixed_ips=None, port_id=None):
|
22
|
+
fixed_ips=None, port_id=None, vnic_type=None):
|
23
23
|
self.id = id
|
24
24
|
self.compute_id = compute_id
|
25
25
|
self.network_id = network_id
|
26
26
|
self.port_id = port_id
|
27
27
|
self.fixed_ips = fixed_ips
|
28
|
+
self.vnic_type = vnic_type
|
28
29
|
|
29
30
|
|
30
31
|
class Delta(data_models.BaseDataModel):
|
@@ -80,7 +80,7 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
80
80
|
return interface
|
81
81
|
return None
|
82
82
|
|
83
|
-
def _plug_amphora_vip(self, amphora, subnet):
|
83
|
+
def _plug_amphora_vip(self, amphora, subnet, vip: data_models.Vip):
|
84
84
|
# We need a vip port owned by Octavia for Act/Stby and failover
|
85
85
|
try:
|
86
86
|
port = {
|
@@ -89,7 +89,9 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
89
89
|
constants.FIXED_IPS: [{'subnet_id': subnet.id}],
|
90
90
|
constants.ADMIN_STATE_UP: True,
|
91
91
|
constants.DEVICE_OWNER: constants.OCTAVIA_OWNER,
|
92
|
+
constants.SECURITY_GROUP_IDS: vip.sg_ids
|
92
93
|
}
|
94
|
+
|
93
95
|
new_port = self.network_proxy.create_port(**port)
|
94
96
|
new_port = utils.convert_port_to_model(new_port)
|
95
97
|
|
@@ -149,7 +151,12 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
149
151
|
net = ipaddress.ip_network(cidr)
|
150
152
|
return 'IPv6' if net.version == 6 else 'IPv4'
|
151
153
|
|
152
|
-
def _update_security_group_rules(self,
|
154
|
+
def _update_security_group_rules(self,
|
155
|
+
load_balancer: data_models.LoadBalancer,
|
156
|
+
sec_grp_id):
|
157
|
+
# Skip adding listener rules if sgs is not None or not empty
|
158
|
+
skip_listener_rules = load_balancer.vip.sg_ids
|
159
|
+
|
153
160
|
rules = tuple(self.network_proxy.security_group_rules(
|
154
161
|
security_group_id=sec_grp_id))
|
155
162
|
|
@@ -160,19 +167,20 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
160
167
|
constants.DELETED]):
|
161
168
|
continue
|
162
169
|
|
163
|
-
|
164
|
-
|
165
|
-
protocol
|
166
|
-
|
167
|
-
protocol
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
170
|
+
if not skip_listener_rules:
|
171
|
+
protocol = constants.PROTOCOL_TCP.lower()
|
172
|
+
if listener.protocol == constants.PROTOCOL_UDP:
|
173
|
+
protocol = constants.PROTOCOL_UDP.lower()
|
174
|
+
elif listener.protocol == lib_consts.PROTOCOL_SCTP:
|
175
|
+
protocol = lib_consts.PROTOCOL_SCTP.lower()
|
176
|
+
|
177
|
+
if listener.allowed_cidrs:
|
178
|
+
for ac in listener.allowed_cidrs:
|
179
|
+
port = (listener.protocol_port, protocol, ac.cidr)
|
180
|
+
updated_ports.append(port)
|
181
|
+
else:
|
182
|
+
port = (listener.protocol_port, protocol, None)
|
172
183
|
updated_ports.append(port)
|
173
|
-
else:
|
174
|
-
port = (listener.protocol_port, protocol, None)
|
175
|
-
updated_ports.append(port)
|
176
184
|
|
177
185
|
listener_peer_ports.append(listener.peer_port)
|
178
186
|
|
@@ -194,12 +202,13 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
194
202
|
# Don't remove egress rules and don't confuse other protocols with
|
195
203
|
# None ports with the egress rules. VRRP uses protocol 51 and 112
|
196
204
|
if (rule.get('direction') == 'egress' or
|
197
|
-
rule.get('protocol')
|
205
|
+
rule.get('protocol') is None or
|
206
|
+
rule['protocol'].upper() not in
|
198
207
|
[constants.PROTOCOL_TCP, constants.PROTOCOL_UDP,
|
199
208
|
lib_consts.PROTOCOL_SCTP]):
|
200
209
|
continue
|
201
210
|
old_ports.append((rule.get('port_range_max'),
|
202
|
-
rule
|
211
|
+
rule['protocol'].lower(),
|
203
212
|
rule.get('remote_ip_prefix')))
|
204
213
|
|
205
214
|
add_ports = set(updated_ports) - set(old_ports)
|
@@ -262,12 +271,15 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
262
271
|
raise base.PlugVIPException(str(e))
|
263
272
|
|
264
273
|
def _add_vip_security_group_to_port(self, load_balancer_id, port_id,
|
265
|
-
sec_grp_id=None
|
266
|
-
|
267
|
-
|
268
|
-
|
274
|
+
sec_grp_id: str = None,
|
275
|
+
vip_sg_ids: list[str] = None):
|
276
|
+
sec_grp_ids = [sec_grp_id or
|
277
|
+
self._get_lb_security_group(load_balancer_id).get(
|
278
|
+
constants.ID)]
|
279
|
+
if vip_sg_ids:
|
280
|
+
sec_grp_ids += vip_sg_ids
|
269
281
|
try:
|
270
|
-
self.
|
282
|
+
self._update_security_groups(sec_grp_ids, port_id)
|
271
283
|
except base.PortNotFound:
|
272
284
|
raise
|
273
285
|
except base.NetworkException as e:
|
@@ -409,15 +421,28 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
409
421
|
self._update_security_group_rules(load_balancer,
|
410
422
|
sec_grp.get(constants.ID))
|
411
423
|
self._add_vip_security_group_to_port(load_balancer.id, vip.port_id,
|
412
|
-
sec_grp.get(constants.ID)
|
424
|
+
sec_grp.get(constants.ID),
|
425
|
+
vip_sg_ids=vip.sg_ids)
|
413
426
|
return sec_grp.get(constants.ID)
|
414
427
|
return None
|
415
428
|
|
429
|
+
def update_aap_port_sg(self,
|
430
|
+
load_balancer: data_models.LoadBalancer,
|
431
|
+
amphora: data_models.Amphora,
|
432
|
+
vip: data_models.Vip):
|
433
|
+
if self.sec_grp_enabled:
|
434
|
+
sec_grp = self._get_lb_security_group(load_balancer.id)
|
435
|
+
if sec_grp:
|
436
|
+
self._add_vip_security_group_to_port(load_balancer.id,
|
437
|
+
amphora.vrrp_port_id,
|
438
|
+
sec_grp.get(constants.ID),
|
439
|
+
vip_sg_ids=vip.sg_ids)
|
440
|
+
|
416
441
|
def plug_aap_port(self, load_balancer, vip, amphora, subnet):
|
417
442
|
interface = self._get_plugged_interface(
|
418
443
|
amphora.compute_id, subnet.network_id, amphora.lb_network_ip)
|
419
444
|
if not interface:
|
420
|
-
interface = self._plug_amphora_vip(amphora, subnet)
|
445
|
+
interface = self._plug_amphora_vip(amphora, subnet, vip)
|
421
446
|
|
422
447
|
aap_address_list = [vip.ip_address]
|
423
448
|
for add_vip in load_balancer.additional_vips:
|
@@ -426,7 +451,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
426
451
|
|
427
452
|
if self.sec_grp_enabled:
|
428
453
|
self._add_vip_security_group_to_port(load_balancer.id,
|
429
|
-
interface.port_id
|
454
|
+
interface.port_id,
|
455
|
+
vip_sg_ids=vip.sg_ids)
|
430
456
|
vrrp_ip = None
|
431
457
|
for fixed_ip in interface.fixed_ips:
|
432
458
|
is_correct_subnet = fixed_ip.subnet_id == subnet.id
|
@@ -466,7 +492,7 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
466
492
|
list_of_dicts.append(fixed_ip.to_dict())
|
467
493
|
return list_of_dicts
|
468
494
|
|
469
|
-
def allocate_vip(self, load_balancer):
|
495
|
+
def allocate_vip(self, load_balancer: data_models.LoadBalancer):
|
470
496
|
"""Allocates a virtual ip.
|
471
497
|
|
472
498
|
Reserves the IP for later use as the frontend connection of a load
|
@@ -558,6 +584,9 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
558
584
|
constants.DEVICE_OWNER: constants.OCTAVIA_OWNER,
|
559
585
|
project_id_key: load_balancer.project_id}
|
560
586
|
|
587
|
+
if load_balancer.vip.sg_ids:
|
588
|
+
port[constants.SECURITY_GROUP_IDS] = load_balancer.vip.sg_ids
|
589
|
+
|
561
590
|
if fixed_ips:
|
562
591
|
port[constants.FIXED_IPS] = fixed_ips
|
563
592
|
try:
|
@@ -626,26 +655,6 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
626
655
|
load_balancer.amphorae):
|
627
656
|
self.unplug_aap_port(vip, amphora, subnet)
|
628
657
|
|
629
|
-
def plug_network(self, compute_id, network_id):
|
630
|
-
try:
|
631
|
-
interface = self.compute.attach_network_or_port(
|
632
|
-
compute_id=compute_id, network_id=network_id)
|
633
|
-
except exceptions.NotFound as e:
|
634
|
-
if 'Instance' in str(e):
|
635
|
-
raise base.AmphoraNotFound(str(e))
|
636
|
-
if 'Network' in str(e):
|
637
|
-
raise base.NetworkNotFound(str(e))
|
638
|
-
raise base.PlugNetworkException(str(e))
|
639
|
-
except Exception as e:
|
640
|
-
message = _('Error plugging amphora (compute_id: {compute_id}) '
|
641
|
-
'into network {network_id}.').format(
|
642
|
-
compute_id=compute_id,
|
643
|
-
network_id=network_id)
|
644
|
-
LOG.exception(message)
|
645
|
-
raise base.PlugNetworkException(message) from e
|
646
|
-
|
647
|
-
return self._nova_interface_to_octavia_interface(compute_id, interface)
|
648
|
-
|
649
658
|
def unplug_network(self, compute_id, network_id):
|
650
659
|
interfaces = self.get_plugged_networks(compute_id)
|
651
660
|
if not interfaces:
|
@@ -876,7 +885,7 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
|
|
876
885
|
raise base.CreatePortException(message)
|
877
886
|
|
878
887
|
def get_security_group(self, sg_name):
|
879
|
-
"""Retrieves the security group by
|
888
|
+
"""Retrieves the security group by its name.
|
880
889
|
|
881
890
|
:param sg_name: The security group name.
|
882
891
|
:return: octavia.network.data_models.SecurityGroup, None if not enabled
|
@@ -12,6 +12,8 @@
|
|
12
12
|
# License for the specific language governing permissions and limitations
|
13
13
|
# under the License.
|
14
14
|
|
15
|
+
import typing
|
16
|
+
|
15
17
|
from openstack.connection import Connection
|
16
18
|
import openstack.exceptions as os_exceptions
|
17
19
|
from openstack.network.v2._proxy import Proxy
|
@@ -25,6 +27,9 @@ from octavia.network import base
|
|
25
27
|
from octavia.network import data_models as network_models
|
26
28
|
from octavia.network.drivers.neutron import utils
|
27
29
|
|
30
|
+
if typing.TYPE_CHECKING:
|
31
|
+
from octavia.common import context
|
32
|
+
|
28
33
|
LOG = logging.getLogger(__name__)
|
29
34
|
DNS_INT_EXT_ALIAS = 'dns-integration'
|
30
35
|
SEC_GRP_EXT_ALIAS = 'security-group'
|
@@ -76,21 +81,22 @@ class BaseNeutronDriver(base.AbstractNetworkDriver):
|
|
76
81
|
fixed_ip = port_fixed_ip
|
77
82
|
else:
|
78
83
|
additional_ips.append(port_fixed_ip)
|
84
|
+
kwargs = {
|
85
|
+
'ip_address': None,
|
86
|
+
'subnet_id': None
|
87
|
+
}
|
79
88
|
if fixed_ip:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
load_balancer=load_balancer,
|
92
|
-
load_balancer_id=load_balancer.id,
|
93
|
-
octavia_owned=octavia_owned)
|
89
|
+
kwargs['ip_address'] = fixed_ip.ip_address
|
90
|
+
kwargs['subnet_id'] = fixed_ip.subnet_id
|
91
|
+
|
92
|
+
primary_vip = data_models.Vip(
|
93
|
+
network_id=port.network_id,
|
94
|
+
port_id=port.id,
|
95
|
+
load_balancer=load_balancer,
|
96
|
+
load_balancer_id=load_balancer.id,
|
97
|
+
octavia_owned=octavia_owned,
|
98
|
+
sg_ids=load_balancer.vip.sg_ids,
|
99
|
+
**kwargs)
|
94
100
|
additional_vips = [
|
95
101
|
data_models.AdditionalVip(
|
96
102
|
ip_address=add_fixed_ip.ip_address,
|
@@ -123,11 +129,12 @@ class BaseNeutronDriver(base.AbstractNetworkDriver):
|
|
123
129
|
self.network_proxy.update_port(port_id,
|
124
130
|
allowed_address_pairs=aap)
|
125
131
|
|
126
|
-
def
|
132
|
+
def _update_security_groups(self, sec_grp_ids: list[str],
|
133
|
+
port_id: str):
|
127
134
|
# Note: Neutron accepts the SG even if it already exists
|
128
135
|
try:
|
129
136
|
self.network_proxy.update_port(
|
130
|
-
port_id, security_groups=
|
137
|
+
port_id, security_groups=sec_grp_ids)
|
131
138
|
except os_exceptions.NotFoundException as e:
|
132
139
|
raise base.PortNotFound(str(e))
|
133
140
|
except Exception as e:
|
@@ -252,6 +259,11 @@ class BaseNeutronDriver(base.AbstractNetworkDriver):
|
|
252
259
|
def get_port(self, port_id, context=None):
|
253
260
|
return self._get_resource('port', port_id, context=context)
|
254
261
|
|
262
|
+
def get_security_group_by_id(self, sg_id: str,
|
263
|
+
context: 'context.RequestContext' = None) -> (
|
264
|
+
'network_models.SecurityGroup'):
|
265
|
+
return self._get_resource('security_group', sg_id, context=context)
|
266
|
+
|
255
267
|
def get_network_by_name(self, network_name):
|
256
268
|
return self._get_resources_by_filters(
|
257
269
|
'network', unique_item=True, name=network_name)
|
@@ -12,7 +12,6 @@
|
|
12
12
|
# License for the specific language governing permissions and limitations
|
13
13
|
# under the License.
|
14
14
|
|
15
|
-
|
16
15
|
from openstack.network.v2.network_ip_availability import NetworkIPAvailability
|
17
16
|
|
18
17
|
from octavia.network import data_models as network_models
|
@@ -52,7 +51,8 @@ def convert_port_to_model(port):
|
|
52
51
|
admin_state_up=port.is_admin_state_up,
|
53
52
|
fixed_ips=fixed_ips,
|
54
53
|
qos_policy_id=port.qos_policy_id,
|
55
|
-
security_group_ids=port.security_group_ids
|
54
|
+
security_group_ids=port.security_group_ids,
|
55
|
+
vnic_type=port.binding_vnic_type
|
56
56
|
)
|
57
57
|
|
58
58
|
|