1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
17
# @author: Sumit Naiksatam, Cisco Systems, Inc.
22
from quantum.common import exceptions as exc
23
from quantum.openstack.common import importutils
24
from quantum.plugins.cisco.common import cisco_constants as const
25
from quantum.plugins.cisco.common import cisco_credentials as cred
26
from quantum.plugins.cisco.common import cisco_exceptions as cexc
27
from quantum.plugins.cisco.common import cisco_utils as cutil
28
from quantum.plugins.cisco.db import api as db
29
from quantum.plugins.cisco.db import l2network_db as cdb
30
from quantum.plugins.cisco import l2network_plugin_configuration as conf
31
from quantum.quantum_plugin_base import QuantumPluginBase
34
LOG = logging.getLogger(__name__)
37
class L2Network(QuantumPluginBase):
38
""" L2 Network Framework Plugin """
39
supported_extension_aliases = ["Cisco Multiport", "Cisco Credential",
40
"Cisco Port Profile", "Cisco qos",
45
cred.Store.initialize()
46
self._model = importutils.import_object(conf.MODEL_CLASS)
47
self._vlan_mgr = importutils.import_object(conf.MANAGER_CLASS)
48
LOG.debug("L2Network plugin initialization done successfully\n")
51
Core API implementation
53
def get_all_networks(self, tenant_id, **kwargs):
55
Returns a dictionary containing all
56
<network_uuid, network_name> for
59
LOG.debug("get_all_networks() called\n")
60
self._invoke_device_plugins(self._func_name(), [tenant_id])
61
networks_list = db.network_list(tenant_id)
62
new_networks_list = []
63
for network in networks_list:
64
new_network_dict = cutil.make_net_dict(network[const.UUID],
65
network[const.NETWORKNAME],
67
new_networks_list.append(new_network_dict)
69
return new_networks_list
71
def create_network(self, tenant_id, net_name, **kwargs):
73
Creates a new Virtual Network, and assigns it
76
LOG.debug("create_network() called\n")
77
new_network = db.network_create(tenant_id, net_name)
78
new_net_id = new_network[const.UUID]
79
vlan_id = self._get_vlan_for_tenant(tenant_id, net_name)
80
vlan_name = self._get_vlan_name(new_net_id, str(vlan_id))
81
self._invoke_device_plugins(self._func_name(), [tenant_id, net_name,
82
new_net_id, vlan_name,
84
cdb.add_vlan_binding(vlan_id, vlan_name, new_net_id)
85
new_net_dict = {const.NET_ID: new_net_id,
86
const.NET_NAME: net_name,
90
def delete_network(self, tenant_id, net_id):
92
Deletes the network with the specified network identifier
93
belonging to the specified tenant.
95
LOG.debug("delete_network() called\n")
96
db.validate_network_ownership(tenant_id, net_id)
97
net = db.network_get(net_id)
99
if len(net[const.NETWORKPORTS]) > 0:
100
ports_on_net = db.port_list(net_id)
101
for port in ports_on_net:
102
if port[const.INTERFACEID]:
103
raise exc.NetworkInUse(net_id=net_id)
104
for port in ports_on_net:
105
self.delete_port(tenant_id, net_id, port[const.UUID])
107
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
108
net_dict = cutil.make_net_dict(net[const.UUID],
109
net[const.NETWORKNAME],
111
self._release_vlan_for_tenant(tenant_id, net_id)
112
cdb.remove_vlan_binding(net_id)
113
db.network_destroy(net_id)
116
raise exc.NetworkNotFound(net_id=net_id)
118
def get_network_details(self, tenant_id, net_id):
120
Gets the details of a particular network
122
LOG.debug("get_network_details() called\n")
123
db.validate_network_ownership(tenant_id, net_id)
124
network = db.network_get(net_id)
125
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
126
ports_list = network[const.NETWORKPORTS]
128
for port in ports_list:
129
new_port = cutil.make_port_dict(port[const.UUID],
130
port[const.PORTSTATE],
131
port[const.NETWORKID],
132
port[const.INTERFACEID])
133
ports_on_net.append(new_port)
135
new_network = cutil.make_net_dict(network[const.UUID],
136
network[const.NETWORKNAME],
141
def update_network(self, tenant_id, net_id, **kwargs):
143
Updates the symbolic name belonging to a particular
146
LOG.debug("update_network() called\n")
147
db.validate_network_ownership(tenant_id, net_id)
148
network = db.network_update(net_id, tenant_id, **kwargs)
149
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
151
net_dict = cutil.make_net_dict(network[const.UUID],
152
network[const.NETWORKNAME],
156
def get_all_ports(self, tenant_id, net_id, **kwargs):
158
Retrieves all port identifiers belonging to the
159
specified Virtual Network.
161
LOG.debug("get_all_ports() called\n")
162
db.validate_network_ownership(tenant_id, net_id)
163
network = db.network_get(net_id)
164
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id])
165
ports_list = network[const.NETWORKPORTS]
167
for port in ports_list:
168
new_port = cutil.make_port_dict(port[const.UUID],
169
port[const.PORTSTATE],
170
port[const.NETWORKID],
171
port[const.INTERFACEID])
172
ports_on_net.append(new_port)
176
def create_port(self, tenant_id, net_id, port_state=None, **kwargs):
178
Creates a port on the specified Virtual Network.
180
LOG.debug("create_port() called\n")
182
db.validate_network_ownership(tenant_id, net_id)
183
port = db.port_create(net_id, port_state)
184
unique_port_id_string = port[const.UUID]
185
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
187
unique_port_id_string])
188
new_port_dict = cutil.make_port_dict(port[const.UUID],
189
port[const.PORTSTATE],
190
port[const.NETWORKID],
191
port[const.INTERFACEID])
194
def delete_port(self, tenant_id, net_id, port_id):
196
Deletes a port on a specified Virtual Network,
197
if the port contains a remote interface attachment,
198
the remote interface should first be un-plugged and
199
then the port can be deleted.
201
LOG.debug("delete_port() called\n")
202
db.validate_port_ownership(tenant_id, net_id, port_id)
203
network = db.network_get(net_id)
204
port = db.port_get(net_id, port_id)
205
attachment_id = port[const.INTERFACEID]
206
if not attachment_id:
207
self._invoke_device_plugins(self._func_name(), [tenant_id,
210
db.port_destroy(net_id, port_id)
211
new_port_dict = cutil.make_port_dict(port_id, None, None, None)
214
raise exc.PortInUse(port_id=port_id, net_id=net_id,
215
att_id=attachment_id)
217
def update_port(self, tenant_id, net_id, port_id, **kwargs):
219
Updates the state of a port on the specified Virtual Network.
221
LOG.debug("update_port() called\n")
222
db.validate_port_ownership(tenant_id, net_id, port_id)
223
network = db.network_get(net_id)
224
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
226
self._validate_port_state(kwargs["state"])
227
db.port_update(port_id, net_id, **kwargs)
229
new_port_dict = cutil.make_port_dict(port_id, kwargs["state"], net_id,
233
def get_port_details(self, tenant_id, net_id, port_id):
235
This method allows the user to retrieve a remote interface
236
that is attached to this particular port.
238
LOG.debug("get_port_details() called\n")
239
db.validate_port_ownership(tenant_id, net_id, port_id)
240
network = db.network_get(net_id)
241
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
243
port = db.port_get(net_id, port_id)
244
new_port_dict = cutil.make_port_dict(port[const.UUID],
245
port[const.PORTSTATE],
246
port[const.NETWORKID],
247
port[const.INTERFACEID])
250
def plug_interface(self, tenant_id, net_id, port_id,
251
remote_interface_id):
253
Provides connectivity to a remote interface to the
254
specified Virtual Network.
256
LOG.debug("plug_interface() called\n")
257
db.validate_port_ownership(tenant_id, net_id, port_id)
258
network = db.network_get(net_id)
259
port = db.port_get(net_id, port_id)
260
attachment_id = port[const.INTERFACEID]
261
if attachment_id is None:
262
raise cexc.InvalidAttach(port_id=port_id, net_id=net_id,
263
att_id=remote_interface_id)
264
attachment_id = attachment_id[:const.UUID_LENGTH]
265
remote_interface_id = remote_interface_id[:const.UUID_LENGTH]
266
if remote_interface_id != attachment_id:
267
LOG.debug("Existing attachment_id:%s, remote_interface_id:%s" %
268
(attachment_id, remote_interface_id))
269
raise exc.PortInUse(port_id=port_id, net_id=net_id,
270
att_id=attachment_id)
271
self._invoke_device_plugins(self._func_name(), [tenant_id,
274
db.port_unset_attachment(net_id, port_id)
275
db.port_set_attachment(net_id, port_id, attachment_id)
276
#Note: The remote_interface_id gets associated with the port
277
# when the VM is instantiated. The plug interface call results
278
# in putting the port on the VLAN associated with this network
280
def unplug_interface(self, tenant_id, net_id, port_id):
282
Removes connectivity of a remote interface to the
283
specified Virtual Network.
285
LOG.debug("unplug_interface() called\n")
286
db.validate_port_ownership(tenant_id, net_id, port_id)
287
network = db.network_get(net_id)
288
port = db.port_get(net_id, port_id)
289
attachment_id = port[const.INTERFACEID]
290
if attachment_id is None:
291
raise cexc.InvalidDetach(port_id=port_id, net_id=net_id,
292
att_id=remote_interface_id)
293
self._invoke_device_plugins(self._func_name(), [tenant_id, net_id,
295
attachment_id = attachment_id[:const.UUID_LENGTH]
296
attachment_id = attachment_id + const.UNPLUGGED
297
db.port_unset_attachment(net_id, port_id)
298
db.port_set_attachment(net_id, port_id, attachment_id)
301
Extension API implementation
303
def get_all_portprofiles(self, tenant_id):
304
"""Get all port profiles"""
305
LOG.debug("get_all_portprofiles() called\n")
306
pplist = cdb.get_all_portprofiles()
308
for portprofile in pplist:
309
new_pp = cutil.make_portprofile_dict(tenant_id,
310
portprofile[const.UUID],
311
portprofile[const.PPNAME],
312
portprofile[const.PPQOS])
313
new_pplist.append(new_pp)
317
def get_portprofile_details(self, tenant_id, profile_id):
318
"""Get port profile details"""
319
LOG.debug("get_portprofile_details() called\n")
321
portprofile = cdb.get_portprofile(tenant_id, profile_id)
323
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
324
portprofile_id=profile_id)
326
new_pp = cutil.make_portprofile_dict(tenant_id,
327
portprofile[const.UUID],
328
portprofile[const.PPNAME],
329
portprofile[const.PPQOS])
332
def create_portprofile(self, tenant_id, profile_name, qos):
333
"""Create port profile"""
334
LOG.debug("create_portprofile() called\n")
335
portprofile = cdb.add_portprofile(tenant_id, profile_name,
336
const.NO_VLAN_ID, qos)
337
new_pp = cutil.make_portprofile_dict(tenant_id,
338
portprofile[const.UUID],
339
portprofile[const.PPNAME],
340
portprofile[const.PPQOS])
343
def delete_portprofile(self, tenant_id, profile_id):
344
"""Delete portprofile"""
345
LOG.debug("delete_portprofile() called\n")
347
portprofile = cdb.get_portprofile(tenant_id, profile_id)
349
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
350
portprofile_id=profile_id)
352
plist = cdb.get_pp_binding(tenant_id, profile_id)
354
raise cexc.PortProfileInvalidDelete(tenant_id=tenant_id,
355
profile_id=profile_id)
357
cdb.remove_portprofile(tenant_id, profile_id)
359
def rename_portprofile(self, tenant_id, profile_id, new_name):
360
"""Rename port profile"""
361
LOG.debug("rename_portprofile() called\n")
363
portprofile = cdb.get_portprofile(tenant_id, profile_id)
365
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
366
portprofile_id=profile_id)
367
portprofile = cdb.update_portprofile(tenant_id, profile_id, new_name)
368
new_pp = cutil.make_portprofile_dict(tenant_id,
369
portprofile[const.UUID],
370
portprofile[const.PPNAME],
371
portprofile[const.PPQOS])
374
def associate_portprofile(self, tenant_id, net_id,
375
port_id, portprofile_id):
376
"""Associate port profile"""
377
LOG.debug("associate_portprofile() called\n")
379
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
381
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
382
portprofile_id=portprofile_id)
384
cdb.add_pp_binding(tenant_id, port_id, portprofile_id, False)
386
def disassociate_portprofile(self, tenant_id, net_id,
387
port_id, portprofile_id):
388
"""Disassociate port profile"""
389
LOG.debug("disassociate_portprofile() called\n")
391
portprofile = cdb.get_portprofile(tenant_id, portprofile_id)
393
raise cexc.PortProfileNotFound(tenant_id=tenant_id,
394
portprofile_id=portprofile_id)
396
cdb.remove_pp_binding(tenant_id, port_id, portprofile_id)
398
def get_all_qoss(self, tenant_id):
399
"""Get all QoS levels"""
400
LOG.debug("get_all_qoss() called\n")
401
qoslist = cdb.get_all_qoss(tenant_id)
404
def get_qos_details(self, tenant_id, qos_id):
405
"""Get QoS Details"""
406
LOG.debug("get_qos_details() called\n")
408
qos_level = cdb.get_qos(tenant_id, qos_id)
410
raise cexc.QosNotFound(tenant_id=tenant_id,
414
def create_qos(self, tenant_id, qos_name, qos_desc):
415
"""Create a QoS level"""
416
LOG.debug("create_qos() called\n")
417
qos = cdb.add_qos(tenant_id, qos_name, str(qos_desc))
420
def delete_qos(self, tenant_id, qos_id):
421
"""Delete a QoS level"""
422
LOG.debug("delete_qos() called\n")
424
qos_level = cdb.get_qos(tenant_id, qos_id)
426
raise cexc.QosNotFound(tenant_id=tenant_id,
428
return cdb.remove_qos(tenant_id, qos_id)
430
def rename_qos(self, tenant_id, qos_id, new_name):
431
"""Rename QoS level"""
432
LOG.debug("rename_qos() called\n")
434
qos_level = cdb.get_qos(tenant_id, qos_id)
436
raise cexc.QosNotFound(tenant_id=tenant_id,
438
qos = cdb.update_qos(tenant_id, qos_id, new_name)
441
def get_all_credentials(self, tenant_id):
442
"""Get all credentials"""
443
LOG.debug("get_all_credentials() called\n")
444
credential_list = cdb.get_all_credentials(tenant_id)
445
return credential_list
447
def get_credential_details(self, tenant_id, credential_id):
448
"""Get a particular credential"""
449
LOG.debug("get_credential_details() called\n")
451
credential = cdb.get_credential(tenant_id, credential_id)
453
raise cexc.CredentialNotFound(tenant_id=tenant_id,
454
credential_id=credential_id)
457
def create_credential(self, tenant_id, credential_name, user_name,
459
"""Create a new credential"""
460
LOG.debug("create_credential() called\n")
461
credential = cdb.add_credential(tenant_id, credential_name,
465
def delete_credential(self, tenant_id, credential_id):
466
"""Delete a credential"""
467
LOG.debug("delete_credential() called\n")
469
credential = cdb.get_credential(tenant_id, credential_id)
471
raise cexc.CredentialNotFound(tenant_id=tenant_id,
472
credential_id=credential_id)
473
credential = cdb.remove_credential(tenant_id, credential_id)
476
def rename_credential(self, tenant_id, credential_id, new_name):
477
"""Rename the particular credential resource"""
478
LOG.debug("rename_credential() called\n")
480
credential = cdb.get_credential(tenant_id, credential_id)
482
raise cexc.CredentialNotFound(tenant_id=tenant_id,
483
credential_id=credential_id)
484
credential = cdb.update_credential(tenant_id, credential_id, new_name)
487
def schedule_host(self, tenant_id, instance_id, instance_desc):
488
"""Provides the hostname on which a dynamic vnic is reserved"""
489
LOG.debug("schedule_host() called\n")
490
host_list = self._invoke_device_plugins(self._func_name(),
496
def associate_port(self, tenant_id, instance_id, instance_desc):
498
Get the portprofile name and the device name for the dynamic vnic
500
LOG.debug("associate_port() called\n")
501
return self._invoke_device_plugins(self._func_name(), [tenant_id,
505
def detach_port(self, tenant_id, instance_id, instance_desc):
507
Remove the association of the VIF with the dynamic vnic
509
LOG.debug("detach_port() called\n")
510
return self._invoke_device_plugins(self._func_name(), [tenant_id,
514
def create_multiport(self, tenant_id, net_id_list, port_state, ports_desc):
516
Creates multiple ports on the specified Virtual Network.
518
LOG.debug("create_ports() called\n")
519
ports_num = len(net_id_list)
523
for net_id in net_id_list:
524
db.validate_network_ownership(tenant_id, net_id)
525
port = db.port_create(net_id, port_state)
526
ports_id_list.append(port[const.UUID])
527
port_dict = {const.PORT_ID: port[const.UUID]}
528
ports_dict_list.append(port_dict)
530
self._invoke_device_plugins(self._func_name(), [tenant_id,
534
return ports_dict_list
539
def _invoke_device_plugins(self, function_name, args):
541
All device-specific calls are delegated to the model
543
return getattr(self._model, function_name)(args)
545
def _get_vlan_for_tenant(self, tenant_id, net_name):
547
return self._vlan_mgr.reserve_segmentation_id(tenant_id, net_name)
549
def _release_vlan_for_tenant(self, tenant_id, net_id):
551
return self._vlan_mgr.release_segmentation_id(tenant_id, net_id)
553
def _get_vlan_name(self, net_id, vlan):
554
"""Getting the vlan name from the tenant and vlan"""
555
vlan_name = conf.VLAN_NAME_PREFIX + vlan
558
def _validate_port_state(self, port_state):
559
"""Checking the port state"""
560
if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN):
561
raise exc.StateInvalid(port_state=port_state)
564
def _func_name(self, offset=0):
565
"""Getting the name of the calling funciton"""
566
return inspect.stack()[1 + offset][3]