65
71
self.ipam = utils.import_object(ipam_lib).get_ipam_lib(self)
67
73
super(QuantumManager, self).__init__(*args, **kwargs)
74
self.driver.init_host()
75
self.driver.ensure_metadata_ip()
76
self.driver.metadata_forward()
69
78
def create_networks(self, context, label, cidr, multi_host, num_networks,
70
network_size, cidr_v6, gateway_v6, bridge,
79
network_size, cidr_v6, gateway, gateway_v6, bridge,
71
80
bridge_interface, dns1=None, dns2=None, uuid=None,
73
82
"""Unlike other NetworkManagers, with QuantumManager, each
98
107
ipam_tenant_id = kwargs.get("project_id", None)
99
108
priority = kwargs.get("priority", 0)
100
109
self.ipam.create_subnet(context, label, ipam_tenant_id, quantum_net_id,
101
priority, cidr, gateway_v6, cidr_v6, dns1, dns2)
110
priority, cidr, gateway, gateway_v6,
103
113
def delete_network(self, context, fixed_range):
104
114
"""Lookup network by IPv4 cidr, delete both the IPAM
105
115
subnet and the corresponding Quantum network.
117
quantum_net_id = None
107
118
project_id = context.project_id
108
quantum_net_id = self.ipam.get_network_id_by_cidr(
109
context, fixed_range, project_id)
119
# TODO(bgh): The project_id isn't getting populated here for some
120
# reason.. I'm not sure if it's an invalid assumption or just a bug.
121
# In order to get the right quantum_net_id we'll have to query all the
122
# project_ids for now.
123
if project_id is None:
124
projects = db.project_get_all(context)
127
quantum_net_id = self.ipam.get_network_id_by_cidr(
128
context, fixed_range, p['id'])
129
except exception.NotFound:
130
continue # Guess it wasn't that one!
132
if project_id is None:
133
raise Exception("Unable to find network for cidr: %s" %
135
LOG.debug("Deleting network for tenant: %s" % project_id)
110
136
self.ipam.delete_subnets_by_net_id(context, quantum_net_id,
112
138
q_tenant_id = project_id or FLAGS.quantum_default_tenant_id
113
139
self.q_conn.delete_network(q_tenant_id, quantum_net_id)
141
@utils.synchronized('quantum_allocate')
115
142
def allocate_for_instance(self, context, **kwargs):
116
143
"""Called by compute when it is creating a new VM.
150
177
net_proj_pairs = self.ipam.get_project_and_global_net_ids(context,
180
# Quantum may also know about networks that aren't in the networks
181
# table so we need to query Quanutm for any tenant networks and add
182
# them to net_proj_pairs.
183
qnets = self.q_conn.get_networks(project_id)
184
for qn in qnets['networks']:
185
net_proj_pairs.append((qn['id'], project_id))
153
187
# Create a port via quantum and attach the vif
154
188
for (quantum_net_id, project_id) in net_proj_pairs:
156
189
# FIXME(danwent): We'd like to have the manager be
157
190
# completely decoupled from the nova networks table.
158
191
# However, other parts of nova sometimes go behind our
163
196
# solution, but this would require significant work
165
198
admin_context = context.elevated()
200
# We may not be able to get a network_ref here if this network
201
# isn't in the database (i.e. it came from Quantum). In that case
202
# we need to create it in the db (for now) since the
203
# virtual_interfaces table has a fkey pointing to networks.
166
204
network_ref = db.network_get_by_uuid(admin_context,
206
if network_ref is None:
208
network_ref = {"uuid": quantum_net_id,
209
"project_id": project_id,
210
# NOTE(bgh): We need to document this somewhere but since
211
# we don't know the priority of any networks we get from
212
# quantum we just give them a priority of 0. If its
213
# necessary to specify the order of the vifs and what
214
# network they map to then the user will have to use the
215
# OSCreateServer extension and specify them explicitly.
217
"label": "quantum-net-%s" % quantum_net_id}
218
network_ref = self.db.network_create_safe(admin_context,
220
LOG.debug("Created new network: %s" % network_ref)
169
222
vif_rec = manager.FlatManager.add_virtual_interface(self,
170
223
context, instance_id, network_ref['id'])
173
226
q_tenant_id = project_id or FLAGS.quantum_default_tenant_id
174
227
self.q_conn.create_and_attach_port(q_tenant_id, quantum_net_id,
176
self.ipam.allocate_fixed_ip(context, project_id, quantum_net_id,
230
ip = self.ipam.allocate_fixed_ip(context, project_id,
231
quantum_net_id, vif_rec)
233
if FLAGS.quantum_use_dhcp:
234
LOG.info("Using DHCP for network: %s" % network_ref['label'])
235
# Figure out the ipam tenant id for this subnet: We need to
236
# query for the tenant_id since the network could be created
237
# with the project_id as the tenant or the default tenant.
238
ipam_tenant_id = self.ipam.get_tenant_id_by_net_id(context,
239
quantum_net_id, vif_rec['uuid'], project_id)
240
# Figure out what subnets correspond to this network
241
v4_subnet, v6_subnet = self.ipam.get_subnets_by_net_id(context,
242
ipam_tenant_id, quantum_net_id, vif_rec['uuid'])
243
# Set up (or find) the dhcp server for each of the subnets
244
# returned above (both v4 and v6).
245
for subnet in [v4_subnet, v6_subnet]:
248
# Fill in some of the network fields that we would have
249
# previously gotten from the network table (they'll be
250
# passed to the linux_net functions).
251
network_ref['cidr'] = subnet['cidr']
252
n = IPNetwork(subnet['cidr'])
253
network_ref['dhcp_server'] = IPAddress(n.first + 1)
254
network_ref['dhcp_start'] = IPAddress(n.first + 2)
255
network_ref['broadcast'] = IPAddress(n.broadcast)
256
# TODO(bgh): We need to account for the case where the
257
# user doesn't want a gateway and tell linux_net to add
258
# the appropriate flows to make the dhcp server not act as
259
# a gateway. The call to initialize_gateway_device will
260
# need to be conditional and that call will probably need
262
if network_ref['gateway'] is None:
263
network_ref['gateway'] = IPAddress(n.first + 1)
264
# Construct the interface id that we'll use for the bridge
265
interface_id = "gw-%x" % n.network
266
network_ref['bridge'] = interface_id
267
# Query quantum to see if we've already created a port for
268
# the gateway device and attached the device to the port.
269
# If we haven't then we need to intiialize it and create
270
# it. This device will be the one serving dhcp via
272
port = self.q_conn.get_port_by_attachment(project_id,
273
quantum_net_id, interface_id)
274
if not port: # No dhcp server has been started
275
mac_address = self.generate_mac_address()
276
dev = self.driver.plug(network_ref, mac_address)
277
self.driver.initialize_gateway_device(dev, network_ref)
278
LOG.debug("Intializing DHCP for network: %s" %
280
self.q_conn.create_and_attach_port(project_id,
281
quantum_net_id, interface_id)
282
else: # We've already got one and its plugged in
285
hosts = self.ipam.get_dhcp_hosts_text(context,
286
subnet['network_id'], project_id)
287
self.driver.update_dhcp_hostfile_with_text(dev, hosts)
288
self.driver.restart_dhcp(dev, network_ref)
179
290
return self.get_instance_nw_info(context, instance_id,
180
291
instance_type_id, host)
293
def get_dhcp_leases_text(self, context, network_ref):
294
return self.ipam.get_dhcp_leases_text(context, network_ref)
182
296
def get_instance_nw_info(self, context, instance_id,
183
297
instance_type_id, host):
184
298
"""This method is used by compute to fetch all network data
214
328
raise Exception(_("No network for for virtual interface %s") %
217
ipam_tenant_id = project_id
218
(v4_subnet, v6_subnet) = self.ipam.get_subnets_by_net_id(context,
219
ipam_tenant_id, net_id, vif['uuid'])
220
# There isn't a good way of figuring out what the ipam
221
# tenant id should be before hand so we have to try both
222
# (project_id and None).
223
if not v4_subnet and not v6_subnet:
224
ipam_tenant_id = None
225
(v4_subnet, v6_subnet) = \
331
ipam_tenant_id = self.ipam.get_tenant_id_by_net_id(context,
332
net_id, vif['uuid'], project_id)
333
v4_subnet, v6_subnet = \
226
334
self.ipam.get_subnets_by_net_id(context,
335
ipam_tenant_id, net_id, vif['uuid'])
229
337
v4_ips = self.ipam.get_v4_ips_by_interface(context,
230
338
net_id, vif['uuid'],
231
339
project_id=ipam_tenant_id)
306
415
self.q_conn.detach_and_delete_port(q_tenant_id,
309
# Figure out which ipam tenant id we need here, either the project
310
# id or None (which corresponds to the provider address space).
311
if self.ipam.verify_subnet_exists(context, project_id, net_id):
312
ipam_tenant_id = project_id
314
ipam_tenant_id = None
418
ipam_tenant_id = self.ipam.get_tenant_id_by_net_id(context,
419
net_id, vif_ref['uuid'], project_id)
316
421
self.ipam.deallocate_ips_by_vif(context, ipam_tenant_id,
424
# If DHCP is enabled on this network then we need to update the
425
# leases and restart the server.
426
if FLAGS.quantum_use_dhcp:
427
# Figure out what subnet corresponds to this network/vif
428
v4_subnet, v6_subnet = self.ipam.get_subnets_by_net_id(context,
429
ipam_tenant_id, net_id, vif_ref['uuid'])
430
for subnet in [v4_subnet, v6_subnet]:
433
# Fill in some of the network fields that we would have
434
# previously gotten from the network table (they'll be
435
# passed to the linux_net functions).
436
net['cidr'] = subnet['cidr']
437
n = IPNetwork(subnet['cidr'])
438
net['dhcp_server'] = IPAddress(n.first + 1)
439
net['dhcp_start'] = IPAddress(n.first + 2)
440
net['broadcast'] = IPAddress(n.broadcast)
441
net['gateway'] = IPAddress(n.first + 1)
442
dev = "gw-%x" % n.network
443
# And remove the dhcp mappings for the subnet
444
hosts = self.ipam.get_dhcp_hosts_text(context,
445
subnet['network_id'], project_id)
446
self.driver.update_dhcp_hostfile_with_text(dev, hosts)
448
self.driver.restart_dhcp(dev, net)
320
451
db.virtual_interface_delete_by_instance(admin_context,