1
# Copyright (C) 2015 Midokura SARL.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
16
from neutron.common import constants as n_const
17
from neutron.common import exceptions as n_exc
18
from neutron.db import l3_db
19
from neutron.db import models_v2
20
from neutron import i18n
21
from sqlalchemy.orm import exc
26
class LoadBalancerDriverDbMixin(object):
28
def _check_and_get_router_id_for_pool(self, context, subnet_id):
30
subnet = self.core_plugin._get_subnet(context, subnet_id)
32
# Check whether the network is external
33
if self._is_subnet_external(context, subnet):
34
msg = (_LE("pool subnet must not be public"))
35
raise n_exc.BadRequest(resource='pool', msg=msg)
37
router_id = self._get_router_from_subnet(context, subnet)
39
msg = (_LE("pool subnet must be associated with router"))
40
raise n_exc.BadRequest(resource='pool', msg=msg)
43
def _get_router_from_pool(self, context, pool):
44
subnet = self.core_plugin._get_subnet(context, pool['subnet_id'])
45
return self._get_router_from_subnet(context, subnet)
47
def _get_router_from_port(self, context, port_id):
48
routers = context.session.query(l3_db.Router)
49
routers = routers.join(models_v2.Port,
50
l3_db.Router.id == models_v2.Port.device_id)
51
routers = routers.filter(models_v2.Port.id == port_id)
53
return routers.one().id
54
except exc.NoResultFound:
57
def _get_router_from_subnet(self, context, subnet):
58
iport = self._get_router_interface_port(context, subnet)
62
return self._get_router_from_port(context, iport)
64
def _get_router_interface_port(self, context, subnet):
65
all_ports = context.session.query(models_v2.Port).join(
66
models_v2.Port.fixed_ips)
67
ports = all_ports.filter(
68
models_v2.Port.device_owner == n_const.DEVICE_OWNER_ROUTER_INTF)
69
ports = ports.filter(models_v2.Port.network_id == subnet['network_id'])
71
models_v2.IPAllocation.ip_address == subnet['gateway_ip'])
74
except exc.NoResultFound:
77
def _is_subnet_external(self, context, subnet):
78
network = self.core_plugin._get_network(context, subnet['network_id'])
79
return network.external
81
def _validate_vip_subnet(self, context, vip):
82
subnet = self.core_plugin._get_subnet(context, vip['subnet_id'])
83
pool = self.plugin.get_pool(context, vip['pool_id'])
85
# VIP and pool must not be on the same subnet if pool is associated
86
# with a health monitor. Health monitor would not work in that case.
87
if pool['health_monitors'] and pool['subnet_id'] == subnet['id']:
88
msg = (_LE("The VIP and pool cannot be on the same subnet if"
89
"health monitor is associated"))
90
raise n_exc.BadRequest(resource='vip', msg=msg)
92
if not self._is_subnet_external(context, subnet):
95
# ensure that if the vip subnet is public, the router has its
97
router_id = self._get_router_from_pool(context, pool)
99
# router_id should never be None because it was already validated
100
# when we created the pool
101
assert router_id is not None
103
router = self.core_plugin._get_router(context, router_id)
104
if router.get('gw_port_id') is None:
105
msg = (_LE("The router must have its gateway set if the "
106
"VIP subnet is external"))
107
raise n_exc.BadRequest(resource='vip', msg=msg)
109
def _validate_pool_hm_assoc(self, context, pool_id, hm_id):
110
pool = self.plugin.get_pool(context, pool_id)
111
assoc = next((x for x in pool['health_monitors'] if x != hm_id), None)
113
# There is an association with a different health monitor
115
msg = (_LE("The pool is already associated with a different "
117
raise n_exc.BadRequest(resource='pool_monitor_association',
120
# When associating health monitor, the subnet of VIP and Pool must not
123
vip = self.plugin.get_vip(context, pool['vip_id'])
124
if vip['subnet_id'] == pool['subnet_id']:
125
msg = (_LE("The VIP and pool cannot be on the same subnet if"
126
"health monitor is associated"))
127
raise n_exc.BadRequest(resource='pool_monitor_association',