19 # @author: Dan Wendlandt, Nicira, Inc |
19 # @author: Dan Wendlandt, Nicira, Inc |
20 # @author: Girish Moodalbail, Oracle, Inc. |
20 # @author: Girish Moodalbail, Oracle, Inc. |
21 # |
21 # |
22 |
22 |
23 """ |
23 """ |
24 Based off generic l3_agent (quantum/agent/l3_agent) code |
24 Based off generic l3_agent (neutron/agent/l3_agent) code |
25 """ |
25 """ |
26 |
26 |
27 import sqlalchemy as sa |
27 import sqlalchemy as sa |
28 |
28 |
29 from quantum.api.v2 import attributes |
29 from neutron.api.v2 import attributes |
30 from quantum.common import constants as l3_constants |
30 from neutron.common import constants as l3_constants |
31 from quantum.common import exceptions as q_exc |
31 from neutron.common import exceptions as q_exc |
32 from quantum.db import l3_db |
32 from neutron.db import l3_db |
33 from quantum.extensions import l3 |
33 from neutron.extensions import l3 |
34 from quantum.openstack.common import log as logging |
34 from neutron.extensions import external_net |
35 from quantum.openstack.common import uuidutils |
35 from neutron.openstack.common import log as logging |
36 from quantum.plugins.evs.db import api as evs_db |
36 from neutron.openstack.common import uuidutils |
|
37 from neutron.plugins.evs.db import api as evs_db |
37 |
38 |
38 |
39 |
39 LOG = logging.getLogger(__name__) |
40 LOG = logging.getLogger(__name__) |
40 |
41 |
41 DEVICE_OWNER_ROUTER_INTF = l3_constants.DEVICE_OWNER_ROUTER_INTF |
42 DEVICE_OWNER_ROUTER_INTF = l3_constants.DEVICE_OWNER_ROUTER_INTF |
42 DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW |
43 DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW |
43 DEVICE_OWNER_FLOATINGIP = l3_constants.DEVICE_OWNER_FLOATINGIP |
44 DEVICE_OWNER_FLOATINGIP = l3_constants.DEVICE_OWNER_FLOATINGIP |
44 |
45 |
45 |
46 |
46 class Router(evs_db.EVS_DB_BASE): |
47 class Router(evs_db.EVS_DB_BASE): |
47 """Represents a v2 quantum router.""" |
48 """Represents a v2 neutron router.""" |
48 |
49 |
49 id = sa.Column(sa.String(36), primary_key=True, |
50 id = sa.Column(sa.String(36), primary_key=True, |
50 default=uuidutils.generate_uuid) |
51 default=uuidutils.generate_uuid) |
51 name = sa.Column(sa.String(255)) |
52 name = sa.Column(sa.String(255)) |
52 status = sa.Column(sa.String(16)) |
53 status = sa.Column(sa.String(16)) |
55 gw_port_id = sa.Column(sa.String(36)) |
56 gw_port_id = sa.Column(sa.String(36)) |
56 gw_port_network_id = sa.Column(sa.String(36)) |
57 gw_port_network_id = sa.Column(sa.String(36)) |
57 |
58 |
58 |
59 |
59 class FloatingIP(evs_db.EVS_DB_BASE): |
60 class FloatingIP(evs_db.EVS_DB_BASE): |
60 """Represents a floating IP, which may or many not be |
61 """Represents a floating IP address. |
61 allocated to a tenant, and may or may not be associated with |
62 |
62 an internal port/ip address/router.""" |
63 This IP address may or may not be allocated to a tenant, and may or |
|
64 may not be associated with an internal port/ip address/router. |
|
65 """ |
63 |
66 |
64 id = sa.Column(sa.String(36), primary_key=True, |
67 id = sa.Column(sa.String(36), primary_key=True, |
65 default=uuidutils.generate_uuid) |
68 default=uuidutils.generate_uuid) |
66 floating_ip_address = sa.Column(sa.String(64), nullable=False) |
69 floating_ip_address = sa.Column(sa.String(64), nullable=False) |
67 floating_network_id = sa.Column(sa.String(36), nullable=False) |
70 floating_network_id = sa.Column(sa.String(36), nullable=False) |
76 """Mixin class to add L3/NAT router methods""" |
79 """Mixin class to add L3/NAT router methods""" |
77 |
80 |
78 Router = Router |
81 Router = Router |
79 FloatingIP = FloatingIP |
82 FloatingIP = FloatingIP |
80 |
83 |
81 def _make_router_dict(self, router, fields=None): |
84 def _make_router_dict(self, router, fields=None, |
|
85 process_extensions=True): |
82 res = {'id': router['id'], |
86 res = {'id': router['id'], |
83 'name': router['name'], |
87 'name': router['name'], |
84 'tenant_id': router['tenant_id'], |
88 'tenant_id': router['tenant_id'], |
85 'admin_state_up': router['admin_state_up'], |
89 'admin_state_up': router['admin_state_up'], |
86 'status': router['status'], |
90 'status': router['status'], |
87 'external_gateway_info': None} |
91 'external_gateway_info': None, |
|
92 'gw_port_id': router['gw_port_id']} |
88 if router['gw_port_id']: |
93 if router['gw_port_id']: |
89 nw_id = router['gw_port_network_id'] |
94 nw_id = router['gw_port_network_id'] |
90 res['external_gateway_info'] = {'network_id': nw_id} |
95 res['external_gateway_info'] = {'network_id': nw_id} |
|
96 if process_extensions: |
|
97 self._apply_dict_extend_functions( |
|
98 l3.ROUTERS, res, router) |
91 return self._fields(res, fields) |
99 return self._fields(res, fields) |
92 |
100 |
93 def create_router(self, context, router): |
101 def create_router(self, context, router): |
94 return super(EVS_L3_NAT_db_mixin, self).\ |
102 return super(EVS_L3_NAT_db_mixin, self).\ |
95 create_router(evs_db.get_evs_context(context), router) |
103 create_router(evs_db.get_evs_context(context), router) |
96 |
104 |
97 def update_router(self, context, id, router): |
105 def update_router(self, context, id, router): |
98 return super(EVS_L3_NAT_db_mixin, self).\ |
106 return super(EVS_L3_NAT_db_mixin, self).\ |
99 update_router(evs_db.get_evs_context(context), id, router) |
107 update_router(evs_db.get_evs_context(context), id, router) |
100 |
108 |
101 def _update_router_gw_info(self, context, router_id, info): |
109 def _update_router_gw_info(self, context, router_id, info, router=None): |
102 """This method overrides the base class method and it's contents |
110 """This method overrides the base class method and it's contents |
103 are exactly same as the base class method except that the Router |
111 are exactly same as the base class method except that the Router |
104 DB columns are different for EVS and OVS""" |
112 DB columns are different for EVS and OVS""" |
105 |
113 |
106 router = self._get_router(context, router_id) |
114 router = router or self._get_router(context, router_id) |
107 gw_port_id = router['gw_port_id'] |
115 gw_port_id = router['gw_port_id'] |
|
116 # network_id attribute is required by API, so it must be present |
108 gw_port_network_id = router['gw_port_network_id'] |
117 gw_port_network_id = router['gw_port_network_id'] |
109 |
118 |
110 network_id = info.get('network_id', None) if info else None |
119 network_id = info.get('network_id', None) if info else None |
111 if network_id: |
120 if network_id: |
112 self._get_network(context, network_id) |
121 self._get_network(context, network_id) |
137 self._check_for_dup_router_subnet(context, router_id, |
146 self._check_for_dup_router_subnet(context, router_id, |
138 network_id, subnet['id'], |
147 network_id, subnet['id'], |
139 subnet['cidr']) |
148 subnet['cidr']) |
140 |
149 |
141 # Port has no 'tenant-id', as it is hidden from user |
150 # Port has no 'tenant-id', as it is hidden from user |
142 gw_port = self.create_port(context.elevated(), { |
151 gw_port = self._core_plugin.create_port(context.elevated(), { |
143 'port': |
152 'port': |
144 {'tenant_id': '', # intentionally not set |
153 {'tenant_id': '', # intentionally not set |
145 'network_id': network_id, |
154 'network_id': network_id, |
146 'mac_address': attributes.ATTR_NOT_SPECIFIED, |
155 'mac_address': attributes.ATTR_NOT_SPECIFIED, |
147 'fixed_ips': attributes.ATTR_NOT_SPECIFIED, |
156 'fixed_ips': attributes.ATTR_NOT_SPECIFIED, |
148 'device_id': router_id, |
157 'device_id': router_id, |
149 'device_owner': DEVICE_OWNER_ROUTER_GW, |
158 'device_owner': DEVICE_OWNER_ROUTER_GW, |
150 'admin_state_up': True, |
159 'admin_state_up': True, |
151 'name': ''}}) |
160 'name': ''}}) |
152 |
161 |
153 if not len(gw_port['fixed_ips']): |
162 if not gw_port['fixed_ips']: |
154 self.delete_port(context.elevated(), gw_port['id'], |
163 self._core_plugin.delete_port(context.elevated(), |
155 l3_port_check=False) |
164 gw_port['id'], |
|
165 l3_port_check=False) |
156 msg = (_('No IPs available for external network %s') % |
166 msg = (_('No IPs available for external network %s') % |
157 network_id) |
167 network_id) |
158 raise q_exc.BadRequest(resource='router', msg=msg) |
168 raise q_exc.BadRequest(resource='router', msg=msg) |
159 |
169 |
160 with context.session.begin(subtransactions=True): |
170 with context.session.begin(subtransactions=True): |
193 return super(EVS_L3_NAT_db_mixin, self).\ |
203 return super(EVS_L3_NAT_db_mixin, self).\ |
194 add_router_interface(evs_db.get_evs_context(context), |
204 add_router_interface(evs_db.get_evs_context(context), |
195 router_id, interface_info) |
205 router_id, interface_info) |
196 |
206 |
197 def remove_router_interface(self, context, router_id, interface_info): |
207 def remove_router_interface(self, context, router_id, interface_info): |
198 super(EVS_L3_NAT_db_mixin, self).\ |
208 return super(EVS_L3_NAT_db_mixin, self).\ |
199 remove_router_interface(evs_db.get_evs_context(context), |
209 remove_router_interface(evs_db.get_evs_context(context), |
200 router_id, interface_info) |
210 router_id, interface_info) |
201 |
211 |
202 def create_floatingip(self, context, floatingip): |
212 def create_floatingip(self, context, floatingip): |
203 return super(EVS_L3_NAT_db_mixin, self).\ |
213 return super(EVS_L3_NAT_db_mixin, self).\ |
252 |
262 |
253 def disassociate_floatingips(self, context, port_id): |
263 def disassociate_floatingips(self, context, port_id): |
254 super(EVS_L3_NAT_db_mixin, self).\ |
264 super(EVS_L3_NAT_db_mixin, self).\ |
255 disassociate_floatingips(evs_db.get_evs_context(context), port_id) |
265 disassociate_floatingips(evs_db.get_evs_context(context), port_id) |
256 |
266 |
257 def _network_is_external(self, context, net_id): |
|
258 try: |
|
259 evs = self.get_network(context, net_id) |
|
260 return evs[l3.EXTERNAL] |
|
261 except: |
|
262 return False |
|
263 |
|
264 def get_sync_data(self, context, router_ids=None, active=None): |
267 def get_sync_data(self, context, router_ids=None, active=None): |
265 return super(EVS_L3_NAT_db_mixin, self).\ |
268 return super(EVS_L3_NAT_db_mixin, self).\ |
266 get_sync_data(evs_db.get_evs_context(context), router_ids, active) |
269 get_sync_data(evs_db.get_evs_context(context), router_ids, active) |
267 |
|
268 def get_external_network_id(self, context): |
|
269 return super(EVS_L3_NAT_db_mixin, self).\ |
|
270 get_external_network_id(evs_db.get_evs_context(context)) |
|
271 |
|
272 def _get_tenant_id_for_create(self, context, resource): |
|
273 if context.is_admin and 'tenant_id' in resource: |
|
274 tenant_id = resource['tenant_id'] |
|
275 elif ('tenant_id' in resource and |
|
276 resource['tenant_id'] != context.tenant_id): |
|
277 reason = _('Cannot create resource for another tenant') |
|
278 raise q_exc.AdminRequired(reason=reason) |
|
279 else: |
|
280 tenant_id = context.tenant_id |
|
281 return tenant_id |
|
282 |
270 |
283 def _get_by_id(self, context, model, id): |
271 def _get_by_id(self, context, model, id): |
284 return context.session.query(model).\ |
272 return context.session.query(model).\ |
285 filter(model.id == id).one() |
273 filter(model.id == id).one() |
286 |
|
287 def _get_network(self, context, network_id): |
|
288 return self.get_network(context, network_id) |
|
289 |
|
290 def _get_subnet(self, context, subnet_id): |
|
291 return self.get_subnet(context, subnet_id) |
|
292 |
|
293 def _get_port(self, context, port_id): |
|
294 return self.get_port(context, port_id) |
|
295 |
|
296 def _delete_port(self, context, port_id): |
|
297 return self.delete_port(context, port_id) |
|
298 |
|
299 def _get_subnets_by_network(self, context, network_id): |
|
300 return self.get_subnets(context, filters={'network_id': network_id}) |
|
301 |
274 |
302 def allow_l3_port_deletion(self, context, port_id): |
275 def allow_l3_port_deletion(self, context, port_id): |
303 """ If an L3 agent is using this port, then we need to send |
276 """ If an L3 agent is using this port, then we need to send |
304 a notification to L3 agent to release the port before we can |
277 a notification to L3 agent to release the port before we can |
305 delete the port""" |
278 delete the port""" |