Adapated plugin infrastructure to allow API to pass options to plugins
Now using in-memory sqlite db for tests on FakePlugin teardown() now 'resets' the in-memory db Adding unit tests for APIs
This commit is contained in:
commit
8af12499a8
@ -24,6 +24,7 @@ import routes
|
||||
import webob.dec
|
||||
import webob.exc
|
||||
|
||||
from quantum import manager
|
||||
from quantum.api import faults
|
||||
from quantum.api import networks
|
||||
from quantum.api import ports
|
||||
@ -40,38 +41,38 @@ class APIRouterV01(wsgi.Router):
|
||||
Routes requests on the Quantum API to the appropriate controller
|
||||
"""
|
||||
|
||||
def __init__(self, ext_mgr=None):
|
||||
def __init__(self, options=None):
|
||||
mapper = routes.Mapper()
|
||||
self._setup_routes(mapper)
|
||||
self._setup_routes(mapper, options)
|
||||
super(APIRouterV01, self).__init__(mapper)
|
||||
|
||||
def _setup_routes(self, mapper):
|
||||
|
||||
def _setup_routes(self, mapper, options):
|
||||
# Loads the quantum plugin
|
||||
plugin = manager.QuantumManager(options).get_plugin()
|
||||
uri_prefix = '/tenants/{tenant_id}/'
|
||||
mapper.resource('network', 'networks',
|
||||
controller=networks.Controller(),
|
||||
controller=networks.Controller(plugin),
|
||||
path_prefix=uri_prefix)
|
||||
mapper.resource('port', 'ports',
|
||||
controller=ports.Controller(),
|
||||
controller=ports.Controller(plugin),
|
||||
parent_resource=dict(member_name='network',
|
||||
collection_name=uri_prefix +\
|
||||
'networks'))
|
||||
|
||||
mapper.connect("get_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(),
|
||||
controller=ports.Controller(plugin),
|
||||
action="get_resource",
|
||||
conditions=dict(method=['GET']))
|
||||
mapper.connect("attach_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(),
|
||||
controller=ports.Controller(plugin),
|
||||
action="attach_resource",
|
||||
conditions=dict(method=['PUT']))
|
||||
mapper.connect("detach_resource",
|
||||
uri_prefix + 'networks/{network_id}/' \
|
||||
'ports/{id}/attachment{.format}',
|
||||
controller=ports.Controller(),
|
||||
controller=ports.Controller(plugin),
|
||||
action="detach_resource",
|
||||
conditions=dict(method=['DELETE']))
|
||||
|
@ -19,7 +19,6 @@ import logging
|
||||
|
||||
from webob import exc
|
||||
|
||||
from quantum import manager
|
||||
from quantum.common import wsgi
|
||||
|
||||
XML_NS_V01 = 'http://netstack.org/quantum/api/v0.1'
|
||||
@ -30,8 +29,8 @@ LOG = logging.getLogger('quantum.api.api_common')
|
||||
class QuantumController(wsgi.Controller):
|
||||
""" Base controller class for Quantum API """
|
||||
|
||||
def __init__(self, plugin_conf_file=None):
|
||||
self._setup_network_manager()
|
||||
def __init__(self, plugin):
|
||||
self._plugin = plugin
|
||||
super(QuantumController, self).__init__()
|
||||
|
||||
def _parse_request_params(self, req, params):
|
||||
@ -65,6 +64,3 @@ class QuantumController(wsgi.Controller):
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
results[param_name] = param_value or param.get('default-value')
|
||||
return results
|
||||
|
||||
def _setup_network_manager(self):
|
||||
self.network_manager = manager.QuantumManager().get_manager()
|
||||
|
@ -40,9 +40,9 @@ class Controller(common.QuantumController):
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, plugin_conf_file=None):
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'network'
|
||||
super(Controller, self).__init__()
|
||||
super(Controller, self).__init__(plugin)
|
||||
|
||||
def index(self, request, tenant_id):
|
||||
""" Returns a list of network ids """
|
||||
@ -51,7 +51,7 @@ class Controller(common.QuantumController):
|
||||
|
||||
def _items(self, request, tenant_id, is_detail):
|
||||
""" Returns a list of networks. """
|
||||
networks = self.network_manager.get_all_networks(tenant_id)
|
||||
networks = self._plugin.get_all_networks(tenant_id)
|
||||
builder = networks_view.get_view_builder(request)
|
||||
result = [builder.build(network, is_detail)['network']
|
||||
for network in networks]
|
||||
@ -60,7 +60,7 @@ class Controller(common.QuantumController):
|
||||
def show(self, request, tenant_id, id):
|
||||
""" Returns network details for the given network id """
|
||||
try:
|
||||
network = self.network_manager.get_network_details(
|
||||
network = self._plugin.get_network_details(
|
||||
tenant_id, id)
|
||||
builder = networks_view.get_view_builder(request)
|
||||
#build response with details
|
||||
@ -78,7 +78,7 @@ class Controller(common.QuantumController):
|
||||
self._network_ops_param_list)
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
network = self.network_manager.\
|
||||
network = self._plugin.\
|
||||
create_network(tenant_id,
|
||||
request_params['net-name'])
|
||||
builder = networks_view.get_view_builder(request)
|
||||
@ -94,7 +94,7 @@ class Controller(common.QuantumController):
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
network = self.network_manager.rename_network(tenant_id,
|
||||
network = self._plugin.rename_network(tenant_id,
|
||||
id, request_params['network-name'])
|
||||
|
||||
builder = networks_view.get_view_builder(request)
|
||||
@ -106,7 +106,7 @@ class Controller(common.QuantumController):
|
||||
def delete(self, request, tenant_id, id):
|
||||
""" Destroys the network with the given id """
|
||||
try:
|
||||
self.network_manager.delete_network(tenant_id, id)
|
||||
self._plugin.delete_network(tenant_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
except exception.NetworkNotFound as e:
|
||||
return faults.Fault(faults.NetworkNotFound(e))
|
||||
|
@ -42,9 +42,9 @@ class Controller(common.QuantumController):
|
||||
"attributes": {
|
||||
"port": ["id", "state"], }, }, }
|
||||
|
||||
def __init__(self, plugin_conf_file=None):
|
||||
def __init__(self, plugin):
|
||||
self._resource_name = 'port'
|
||||
super(Controller, self).__init__()
|
||||
super(Controller, self).__init__(plugin)
|
||||
|
||||
def index(self, request, tenant_id, network_id):
|
||||
""" Returns a list of port ids for a given network """
|
||||
@ -53,7 +53,7 @@ class Controller(common.QuantumController):
|
||||
def _items(self, request, tenant_id, network_id, is_detail):
|
||||
""" Returns a list of networks. """
|
||||
try:
|
||||
ports = self.network_manager.get_all_ports(tenant_id, network_id)
|
||||
ports = self._plugin.get_all_ports(tenant_id, network_id)
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = [builder.build(port, is_detail)['port']
|
||||
for port in ports]
|
||||
@ -64,7 +64,7 @@ class Controller(common.QuantumController):
|
||||
def show(self, request, tenant_id, network_id, id):
|
||||
""" Returns port details for given port and network """
|
||||
try:
|
||||
port = self.network_manager.get_port_details(
|
||||
port = self._plugin.get_port_details(
|
||||
tenant_id, network_id, id)
|
||||
builder = ports_view.get_view_builder(request)
|
||||
#build response with details
|
||||
@ -84,7 +84,7 @@ class Controller(common.QuantumController):
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
port = self.network_manager.create_port(tenant_id,
|
||||
port = self._plugin.create_port(tenant_id,
|
||||
network_id,
|
||||
request_params['port-state'])
|
||||
builder = ports_view.get_view_builder(request)
|
||||
@ -104,7 +104,7 @@ class Controller(common.QuantumController):
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
port = self.network_manager.update_port(tenant_id, network_id, id,
|
||||
port = self._plugin.update_port(tenant_id, network_id, id,
|
||||
request_params['port-state'])
|
||||
builder = ports_view.get_view_builder(request)
|
||||
result = builder.build(port, True)
|
||||
@ -120,7 +120,7 @@ class Controller(common.QuantumController):
|
||||
""" Destroys the port with the given id """
|
||||
#look for port state in request
|
||||
try:
|
||||
self.network_manager.delete_port(tenant_id, network_id, id)
|
||||
self._plugin.delete_port(tenant_id, network_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
#TODO(salvatore-orlando): Handle portInUse error
|
||||
except exception.NetworkNotFound as e:
|
||||
@ -141,9 +141,7 @@ class Controller(common.QuantumController):
|
||||
except exception.PortNotFound as e:
|
||||
return faults.Fault(faults.PortNotFound(e))
|
||||
|
||||
#TODO - Complete implementation of these APIs
|
||||
def attach_resource(self, request, tenant_id, network_id, id):
|
||||
content_type = request.best_match_content_type()
|
||||
try:
|
||||
request_params = \
|
||||
self._parse_request_params(request,
|
||||
@ -151,7 +149,7 @@ class Controller(common.QuantumController):
|
||||
except exc.HTTPError as e:
|
||||
return faults.Fault(e)
|
||||
try:
|
||||
self.network_manager.plug_interface(tenant_id,
|
||||
self._plugin.plug_interface(tenant_id,
|
||||
network_id, id,
|
||||
request_params['attachment-id'])
|
||||
return exc.HTTPAccepted()
|
||||
@ -167,7 +165,7 @@ class Controller(common.QuantumController):
|
||||
#TODO - Complete implementation of these APIs
|
||||
def detach_resource(self, request, tenant_id, network_id, id):
|
||||
try:
|
||||
self.network_manager.unplug_interface(tenant_id,
|
||||
self._plugin.unplug_interface(tenant_id,
|
||||
network_id, id)
|
||||
return exc.HTTPAccepted()
|
||||
except exception.NetworkNotFound as e:
|
||||
|
@ -240,6 +240,7 @@ def api_create_port(client, *args):
|
||||
|
||||
def delete_port(manager, *args):
|
||||
tid, nid, pid = args
|
||||
manager.delete_port(tid, nid, pid)
|
||||
LOG.info("Deleted Virtual Port:%s " \
|
||||
"on Virtual Network:%s" % (pid, nid))
|
||||
|
||||
@ -319,8 +320,8 @@ def api_unplug_iface(client, *args):
|
||||
output = res.read()
|
||||
LOG.debug(output)
|
||||
if res.status != 202:
|
||||
LOG.error("Failed to unplug iface from port \"%s\": %s" % (pid,
|
||||
output))
|
||||
LOG.error("Failed to unplug iface from port \"%s\": %s" % \
|
||||
(pid, output))
|
||||
return
|
||||
print "Unplugged interface from port:%s on network:%s" % (pid, nid)
|
||||
|
||||
|
@ -190,7 +190,7 @@ def parse_isotime(timestr):
|
||||
return datetime.datetime.strptime(timestr, TIME_FORMAT)
|
||||
|
||||
|
||||
def getPluginFromConfig(file="config.ini"):
|
||||
def get_plugin_from_config(file="config.ini"):
|
||||
Config = ConfigParser.ConfigParser()
|
||||
Config.read(file)
|
||||
return Config.get("PLUGIN", "provider")
|
||||
|
@ -42,6 +42,13 @@ def configure_db(options):
|
||||
register_models()
|
||||
|
||||
|
||||
def unconfigure_db():
|
||||
unregister_models()
|
||||
# Unset the engine
|
||||
global _ENGINE
|
||||
_ENGINE = None
|
||||
|
||||
|
||||
def get_session(autocommit=True, expire_on_commit=False):
|
||||
"""Helper method to grab session"""
|
||||
global _MAKER, _ENGINE
|
||||
@ -72,7 +79,7 @@ def network_create(tenant_id, name):
|
||||
net = None
|
||||
try:
|
||||
net = session.query(models.Network).\
|
||||
filter_by(name=name, tenant_id=tenant_id).\
|
||||
filter_by(tenant_id=tenant_id, name=name).\
|
||||
one()
|
||||
raise Exception("Network with name %(name)s already " \
|
||||
"exists for tenant %(tenant_id)s" % locals())
|
||||
@ -105,7 +112,7 @@ def network_rename(net_id, tenant_id, new_name):
|
||||
session = get_session()
|
||||
try:
|
||||
res = session.query(models.Network).\
|
||||
filter_by(name=new_name).\
|
||||
filter_by(tenant_id=tenant_id, name=new_name).\
|
||||
one()
|
||||
except exc.NoResultFound:
|
||||
net = network_get(net_id)
|
||||
@ -167,13 +174,14 @@ def port_set_state(port_id, new_state):
|
||||
|
||||
def port_set_attachment(port_id, new_interface_id):
|
||||
session = get_session()
|
||||
ports = None
|
||||
try:
|
||||
ports = session.query(models.Port).\
|
||||
filter_by(interface_id=new_interface_id).\
|
||||
all()
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
ports = []
|
||||
if new_interface_id != "":
|
||||
try:
|
||||
ports = session.query(models.Port).\
|
||||
filter_by(interface_id=new_interface_id).\
|
||||
all()
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
if len(ports) == 0:
|
||||
port = port_get(port_id)
|
||||
port.interface_id = new_interface_id
|
||||
|
@ -27,6 +27,7 @@ The caller should make sure that QuantumManager is a singleton.
|
||||
import gettext
|
||||
import logging
|
||||
import os
|
||||
|
||||
gettext.install('quantum', unicode=1)
|
||||
|
||||
from common import utils
|
||||
@ -44,22 +45,27 @@ def find_config(basepath):
|
||||
|
||||
|
||||
class QuantumManager(object):
|
||||
def __init__(self, config=None):
|
||||
if config == None:
|
||||
def __init__(self, options=None, config_file=None):
|
||||
if config_file == None:
|
||||
self.configuration_file = find_config(
|
||||
os.path.abspath(os.path.dirname(__file__)))
|
||||
else:
|
||||
self.configuration_file = config
|
||||
plugin_location = utils.getPluginFromConfig(self.configuration_file)
|
||||
plugin_klass = utils.import_class(plugin_location)
|
||||
LOG.debug("Plugin location:%s", plugin_location)
|
||||
self.configuration_file = config_file
|
||||
# If no options have been provided, create an empty dict
|
||||
if not options:
|
||||
options = {}
|
||||
if not 'plugin_provider' in options:
|
||||
options['plugin_provider'] = \
|
||||
utils.get_plugin_from_config(self.configuration_file)
|
||||
LOG.debug("Plugin location:%s", options['plugin_provider'])
|
||||
plugin_klass = utils.import_class(options['plugin_provider'])
|
||||
if not issubclass(plugin_klass, QuantumPluginBase):
|
||||
raise Exception("Configured Quantum plug-in " \
|
||||
"didn't pass compatibility test")
|
||||
else:
|
||||
LOG.debug("Successfully imported Quantum plug-in." \
|
||||
"All compatibility tests passed")
|
||||
self.plugin = plugin_klass()
|
||||
self.plugin = plugin_klass(options)
|
||||
|
||||
def get_manager(self):
|
||||
def get_plugin(self):
|
||||
return self.plugin
|
||||
|
@ -233,9 +233,13 @@ class FakePlugin(object):
|
||||
client/cli/api development
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
db_options = {"sql_connection": "sqlite:///fake_plugin.sqllite"}
|
||||
db.configure_db(db_options)
|
||||
def __init__(self, options):
|
||||
# use supplied options for configuring db
|
||||
if not options:
|
||||
options = {"sql_connection": "sqlite:///fake_plugin.sqllite"}
|
||||
elif not 'sql_connection' in options:
|
||||
options['sql_connection'] = "sqlite:///fake_plugin.sqllite"
|
||||
db.configure_db(options)
|
||||
FakePlugin._net_counter = 0
|
||||
|
||||
def _get_network(self, tenant_id, network_id):
|
||||
@ -246,7 +250,7 @@ class FakePlugin(object):
|
||||
|
||||
def _get_port(self, tenant_id, network_id, port_id):
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
try:
|
||||
try:
|
||||
port = db.port_get(port_id)
|
||||
except:
|
||||
raise exc.PortNotFound(net_id=network_id, port_id=port_id)
|
||||
|
@ -62,20 +62,25 @@ mysql> FLUSH PRIVILEGES;
|
||||
distribution tarball (see below) and the agent will use the credentials here
|
||||
to access the database.
|
||||
|
||||
# -- Agent configuration
|
||||
# -- XenServer Agent configuration
|
||||
|
||||
- Create the agent distribution tarball
|
||||
|
||||
$ make agent-dist
|
||||
- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova
|
||||
compute node)
|
||||
- Unpack the tarball and run install.sh. This will install all of the
|
||||
- Unpack the tarball and run xenserver_install.sh. This will install all of the
|
||||
necessary pieces into /etc/xapi.d/plugins. It will also spit out the name
|
||||
of the integration bridge that you'll need for your nova configuration.
|
||||
Make sure to specify this in your nova flagfile as --flat_network_bridge.
|
||||
- Run the agent [on your hypervisor (dom0)]:
|
||||
$ /etc/xapi.d/plugins/ovs_quantum_agent.py /etc/xapi.d/plugins/ovs_quantum_plugin.ini
|
||||
|
||||
# -- KVM Agent configuration
|
||||
|
||||
- Copy ovs_quantum_agent.py and ovs_quantum_plugin.ini to the Linux host and run:
|
||||
$ python ovs_quantum_agent.py ovs_quantum_plugin.ini
|
||||
|
||||
# -- Getting quantum up and running
|
||||
|
||||
- Start quantum [on the quantum service host]:
|
||||
|
@ -130,40 +130,40 @@ class OVSBridge:
|
||||
def get_port_stats(self, port_name):
|
||||
return self.db_get_map("Interface", port_name, "statistics")
|
||||
|
||||
# this is a hack that should go away once nova properly reports bindings
|
||||
# to quantum. We have this here for now as it lets us work with
|
||||
# unmodified nova
|
||||
def xapi_get_port(self, name):
|
||||
external_ids = self.db_get_map("Interface", name, "external_ids")
|
||||
if "attached-mac" not in external_ids:
|
||||
return None
|
||||
vm_uuid = external_ids.get("xs-vm-uuid", "")
|
||||
if len(vm_uuid) == 0:
|
||||
return None
|
||||
LOG.debug("iface-id not set, got xs-vm-uuid: %s" % vm_uuid)
|
||||
res = os.popen("xe vm-list uuid=%s params=name-label --minimal" \
|
||||
% vm_uuid).readline().strip()
|
||||
if len(res) == 0:
|
||||
return None
|
||||
external_ids["iface-id"] = res
|
||||
LOG.info("Setting interface \"%s\" iface-id to \"%s\"" % (name, res))
|
||||
self.set_db_attribute("Interface", name,
|
||||
"external-ids:iface-id", res)
|
||||
ofport = self.db_get_val("Interface", name, "ofport")
|
||||
return VifPort(name, ofport, external_ids["iface-id"],
|
||||
external_ids["attached-mac"], self)
|
||||
|
||||
# returns a VIF object for each VIF port
|
||||
def get_vif_ports(self):
|
||||
edge_ports = []
|
||||
port_names = self.get_port_name_list()
|
||||
for name in port_names:
|
||||
external_ids = self.db_get_map("Interface", name, "external_ids")
|
||||
if "iface-id" in external_ids and "attached-mac" in external_ids:
|
||||
ofport = self.db_get_val("Interface", name, "ofport")
|
||||
p = VifPort(name, ofport, external_ids["iface-id"],
|
||||
external_ids["attached-mac"], self)
|
||||
edge_ports.append(p)
|
||||
else:
|
||||
# iface-id might not be set. See if we can figure it out and
|
||||
# set it here.
|
||||
external_ids = self.db_get_map("Interface", name,
|
||||
"external_ids")
|
||||
if "attached-mac" not in external_ids:
|
||||
continue
|
||||
vif_uuid = external_ids.get("xs-vif-uuid", "")
|
||||
if len(vif_uuid) == 0:
|
||||
continue
|
||||
LOG.debug("iface-id not set, got vif-uuid: %s" % vif_uuid)
|
||||
res = os.popen("xe vif-param-get param-name=other-config "
|
||||
"uuid=%s | grep nicira-iface-id | "
|
||||
"awk '{print $2}'"
|
||||
% vif_uuid).readline()
|
||||
res = res.strip()
|
||||
if len(res) == 0:
|
||||
continue
|
||||
external_ids["iface-id"] = res
|
||||
LOG.info("Setting interface \"%s\" iface-id to \"%s\""
|
||||
% (name, res))
|
||||
self.set_db_attribute("Interface", name,
|
||||
"external-ids:iface-id", res)
|
||||
if "xs-vm-uuid" in external_ids:
|
||||
p = xapi_get_port(name)
|
||||
if p is not None:
|
||||
edge_ports.append(p)
|
||||
elif "iface-id" in external_ids and "attached-mac" in external_ids:
|
||||
ofport = self.db_get_val("Interface", name, "ofport")
|
||||
p = VifPort(name, ofport, external_ids["iface-id"],
|
||||
external_ids["attached-mac"], self)
|
||||
@ -171,13 +171,15 @@ class OVSBridge:
|
||||
return edge_ports
|
||||
|
||||
|
||||
class OVSNaaSPlugin:
|
||||
class OVSQuantumAgent:
|
||||
|
||||
def __init__(self, integ_br):
|
||||
self.setup_integration_br(integ_br)
|
||||
|
||||
def port_bound(self, port, vlan_id):
|
||||
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
||||
str(vlan_id))
|
||||
str(vlan_id))
|
||||
self.int_br.delete_flows(match="in_port=%s" % port.ofport)
|
||||
|
||||
def port_unbound(self, port, still_exists):
|
||||
if still_exists:
|
||||
@ -186,13 +188,8 @@ class OVSNaaSPlugin:
|
||||
def setup_integration_br(self, integ_br):
|
||||
self.int_br = OVSBridge(integ_br)
|
||||
self.int_br.remove_all_flows()
|
||||
# drop all traffic on the 'dead vlan'
|
||||
self.int_br.add_flow(priority=2, match="dl_vlan=4095", actions="drop")
|
||||
# switch all other traffic using L2 learning
|
||||
# switch all traffic using L2 learning
|
||||
self.int_br.add_flow(priority=1, actions="normal")
|
||||
# FIXME send broadcast everywhere, regardless of tenant
|
||||
#int_br.add_flow(priority=3, match="dl_dst=ff:ff:ff:ff:ff:ff",
|
||||
# actions="normal")
|
||||
|
||||
def daemon_loop(self, conn):
|
||||
self.local_vlan_map = {}
|
||||
@ -201,7 +198,7 @@ class OVSNaaSPlugin:
|
||||
|
||||
while True:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT * FROM network_bindings")
|
||||
cursor.execute("SELECT * FROM ports")
|
||||
rows = cursor.fetchall()
|
||||
cursor.close()
|
||||
all_bindings = {}
|
||||
@ -226,22 +223,26 @@ class OVSNaaSPlugin:
|
||||
else:
|
||||
# no binding, put him on the 'dead vlan'
|
||||
self.int_br.set_db_attribute("Port", p.port_name, "tag",
|
||||
"4095")
|
||||
"4095")
|
||||
self.int_br.add_flow(priority=2,
|
||||
match="in_port=%s" % p.ofport, actions="drop")
|
||||
|
||||
old_b = old_local_bindings.get(p.vif_id, None)
|
||||
new_b = new_local_bindings.get(p.vif_id, None)
|
||||
|
||||
if old_b != new_b:
|
||||
if old_b is not None:
|
||||
LOG.info("Removing binding to net-id = %s for %s"
|
||||
% (old_b, str(p)))
|
||||
self.port_unbound(p, True)
|
||||
if new_b is not None:
|
||||
LOG.info("Adding binding to net-id = %s for %s" \
|
||||
% (new_b, str(p)))
|
||||
# If we don't have a binding we have to stick it on
|
||||
# the dead vlan
|
||||
vlan_id = vlan_bindings.get(all_bindings[p.vif_id],
|
||||
"4095")
|
||||
self.port_bound(p, vlan_id)
|
||||
LOG.info("Adding binding to net-id = %s " \
|
||||
"for %s on vlan %s" % (new_b, str(p), vlan_id))
|
||||
for vif_id in old_vif_ports.keys():
|
||||
if vif_id not in new_vif_ports:
|
||||
LOG.info("Port Disappeared: %s" % vif_id)
|
||||
@ -251,8 +252,6 @@ class OVSNaaSPlugin:
|
||||
|
||||
old_vif_ports = new_vif_ports
|
||||
old_local_bindings = new_local_bindings
|
||||
self.int_br.run_cmd(["bash",
|
||||
"/etc/xapi.d/plugins/set_external_ids.sh"])
|
||||
time.sleep(2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -291,7 +290,7 @@ if __name__ == "__main__":
|
||||
LOG.info("Connecting to database \"%s\" on %s" % (db_name, db_host))
|
||||
conn = MySQLdb.connect(host=db_host, user=db_user,
|
||||
passwd=db_pass, db=db_name)
|
||||
plugin = OVSNaaSPlugin(integ_br)
|
||||
plugin = OVSQuantumAgent(integ_br)
|
||||
plugin.daemon_loop(conn)
|
||||
finally:
|
||||
if conn:
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
VIFLIST=`xe vif-list params=uuid --minimal | sed s/,/" "/g`
|
||||
for VIF_UUID in $VIFLIST; do
|
||||
DEVICE_NUM=`xe vif-list params=device uuid=$VIF_UUID --minimal`
|
||||
VM_NAME=`xe vif-list params=vm-name-label uuid=$VIF_UUID --minimal`
|
||||
NAME="$VM_NAME-eth$DEVICE_NUM"
|
||||
echo "Vif: $VIF_UUID is '$NAME'"
|
||||
xe vif-param-set uuid=$VIF_UUID other-config:nicira-iface-id="$NAME"
|
||||
done
|
||||
|
||||
ps auxw | grep -v grep | grep ovs-xapi-sync > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
killall -HUP ovs-xapi-sync
|
||||
fi
|
||||
|
@ -56,21 +56,3 @@ def remove_vlan_binding(netid):
|
||||
except exc.NoResultFound:
|
||||
pass
|
||||
session.flush()
|
||||
|
||||
|
||||
def update_network_binding(netid, ifaceid):
|
||||
session = db.get_session()
|
||||
# Add to or delete from the bindings table
|
||||
if ifaceid == None:
|
||||
try:
|
||||
binding = session.query(ovs_models.NetworkBinding).\
|
||||
filter_by(network_id=netid).\
|
||||
one()
|
||||
session.delete(binding)
|
||||
except exc.NoResultFound:
|
||||
raise Exception("No binding found with network_id = %s" % netid)
|
||||
else:
|
||||
binding = ovs_models.NetworkBinding(netid, ifaceid)
|
||||
session.add(binding)
|
||||
|
||||
session.flush()
|
||||
|
@ -26,23 +26,6 @@ from sqlalchemy.orm import relation
|
||||
from quantum.db.models import BASE
|
||||
|
||||
|
||||
class NetworkBinding(BASE):
|
||||
"""Represents a binding of network_id, vif_id"""
|
||||
__tablename__ = 'network_bindings'
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
network_id = Column(String(255))
|
||||
vif_id = Column(String(255))
|
||||
|
||||
def __init__(self, network_id, vif_id):
|
||||
self.network_id = network_id
|
||||
self.vif_id = vif_id
|
||||
|
||||
def __repr__(self):
|
||||
return "<NetworkBinding(%s,%s)>" % \
|
||||
(self.network_id, self.vif_id)
|
||||
|
||||
|
||||
class VlanBinding(BASE):
|
||||
"""Represents a binding of network_id, vlan_id"""
|
||||
__tablename__ = 'vlan_bindings'
|
||||
|
@ -1,9 +1,9 @@
|
||||
[DATABASE]
|
||||
name = ovs_naas
|
||||
name = ovs_quantum
|
||||
user = root
|
||||
pass = foobar
|
||||
pass = nova
|
||||
host = 127.0.0.1
|
||||
port = 3306
|
||||
|
||||
[OVS]
|
||||
integration-bridge = xapi1
|
||||
integration-bridge = br100
|
||||
|
@ -200,11 +200,9 @@ class OVSQuantumPlugin(QuantumPluginBase):
|
||||
|
||||
def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):
|
||||
db.port_set_attachment(port_id, remote_iface_id)
|
||||
ovs_db.update_network_binding(net_id, remote_iface_id)
|
||||
|
||||
def unplug_interface(self, tenant_id, net_id, port_id):
|
||||
db.port_set_attachment(port_id, "")
|
||||
ovs_db.update_network_binding(net_id, None)
|
||||
|
||||
def get_interface_details(self, tenant_id, net_id, port_id):
|
||||
res = db.port_get(port_id)
|
||||
|
@ -22,6 +22,7 @@ QuantumPluginBase provides the definition of minimum set of
|
||||
methods that needs to be implemented by a Quantum Plug-in.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
@ -29,6 +30,14 @@ class QuantumPluginBase(object):
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, options):
|
||||
"""
|
||||
Initializes the Quantum plugin using provided options.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_all_networks(self, tenant_id):
|
||||
"""
|
||||
@ -242,7 +251,17 @@ class QuantumPluginBase(object):
|
||||
"""
|
||||
if cls is QuantumPluginBase:
|
||||
for method in cls.__abstractmethods__:
|
||||
if any(method in base.__dict__ for base in klass.__mro__):
|
||||
method_ok = False
|
||||
for base in klass.__mro__:
|
||||
if method in base.__dict__:
|
||||
fn_obj = base.__dict__[method]
|
||||
if inspect.isfunction(fn_obj):
|
||||
abstract_fn_obj = cls.__dict__[method]
|
||||
arg_count = fn_obj.func_code.co_argcount
|
||||
expected_arg_count = \
|
||||
abstract_fn_obj.func_code.co_argcount
|
||||
method_ok = arg_count == expected_arg_count
|
||||
if method_ok:
|
||||
continue
|
||||
return NotImplemented
|
||||
return True
|
||||
|
@ -23,28 +23,9 @@ import unittest
|
||||
import tests.unit.testlib as testlib
|
||||
|
||||
from quantum import api as server
|
||||
from quantum.db import api as db
|
||||
from quantum.common.wsgi import Serializer
|
||||
|
||||
LOG = logging.getLogger('quantum.tests.test_api')
|
||||
|
||||
|
||||
class APIPortsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.api = server.APIRouterV01()
|
||||
self.tenant_id = "test_tenant"
|
||||
self.network_name = "test_network"
|
||||
|
||||
def tearDown(self):
|
||||
"""Clear the test environment"""
|
||||
# Remove all the networks.
|
||||
network_req = testlib.create_network_list_request(self.tenant_id)
|
||||
network_res = network_req.get_response(self.api)
|
||||
network_data = Serializer().deserialize(network_res.body,
|
||||
"application/xml")
|
||||
for network in network_data["networks"].values():
|
||||
network_delete_req = testlib. \
|
||||
create_network_delete_request(self.tenant_id, network['id'])
|
||||
network_delete_req.get_response(self.api)
|
||||
|
||||
# Fault names copied here for reference
|
||||
#
|
||||
@ -60,37 +41,140 @@ class APIPortsTest(unittest.TestCase):
|
||||
# 470: "serviceUnavailable",
|
||||
# 471: "pluginFault"}
|
||||
|
||||
def _test_delete_port(self, format):
|
||||
LOG.debug("_test_delete_port - format:%s - START", format)
|
||||
|
||||
LOG = logging.getLogger('quantum.tests.test_api')
|
||||
|
||||
|
||||
class APITest(unittest.TestCase):
|
||||
|
||||
def _create_network(self, format):
|
||||
LOG.debug("Creating network")
|
||||
content_type = "application/" + format
|
||||
port_state = "ACTIVE"
|
||||
LOG.debug("Creating network and port")
|
||||
network_req = testlib.create_new_network_request(self.tenant_id,
|
||||
self.network_name,
|
||||
format)
|
||||
network_req = testlib.new_network_request(self.tenant_id,
|
||||
self.network_name,
|
||||
format)
|
||||
network_res = network_req.get_response(self.api)
|
||||
self.assertEqual(network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(network_res.body,
|
||||
content_type)
|
||||
network_id = network_data['networks']['network']['id']
|
||||
port_req = testlib.create_new_port_request(self.tenant_id,
|
||||
network_id, port_state,
|
||||
format)
|
||||
return network_data['networks']['network']['id']
|
||||
|
||||
def _create_port(self, network_id, port_state, format):
|
||||
LOG.debug("Creating port for network %s", network_id)
|
||||
content_type = "application/%s" % format
|
||||
port_req = testlib.new_port_request(self.tenant_id, network_id,
|
||||
port_state, format)
|
||||
port_res = port_req.get_response(self.api)
|
||||
self.assertEqual(port_res.status_int, 200)
|
||||
port_data = Serializer().deserialize(port_res.body, content_type)
|
||||
port_id = port_data['ports']['port']['id']
|
||||
return port_data['ports']['port']['id']
|
||||
|
||||
def _test_create_network(self, format):
|
||||
LOG.debug("_test_create_network - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
network_id = self._create_network(format)
|
||||
show_network_req = testlib.show_network_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
show_network_res = show_network_req.get_response(self.api)
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual(network_id,
|
||||
network_data['networks']['network']['id'])
|
||||
LOG.debug("_test_create_network - format:%s - END", format)
|
||||
|
||||
def _test_show_network(self, format):
|
||||
LOG.debug("_test_show_network - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
network_id = self._create_network(format)
|
||||
show_network_req = testlib.show_network_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
show_network_res = show_network_req.get_response(self.api)
|
||||
self.assertEqual(show_network_res.status_int, 200)
|
||||
print show_network_res.body
|
||||
network_data = Serializer().deserialize(show_network_res.body,
|
||||
content_type)
|
||||
self.assertEqual({'id': network_id, 'name': self.network_name},
|
||||
network_data['networks']['network'])
|
||||
LOG.debug("_test_show_network - format:%s - END", format)
|
||||
|
||||
def _test_delete_network(self, format):
|
||||
LOG.debug("_test_delete_network - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
network_id = self._create_network(format)
|
||||
LOG.debug("Deleting network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
delete_network_req = testlib.network_delete_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
delete_network_res = delete_network_req.get_response(self.api)
|
||||
self.assertEqual(delete_network_res.status_int, 202)
|
||||
list_network_req = testlib.network_list_request(self.tenant_id, format)
|
||||
list_network_res = list_network_req.get_response(self.api)
|
||||
network_list_data = Serializer().deserialize(list_network_res.body,
|
||||
content_type)
|
||||
network_count = len(network_list_data['networks'])
|
||||
self.assertEqual(network_count, 0)
|
||||
LOG.debug("_test_delete_network - format:%s - END", format)
|
||||
|
||||
def _test_delete_network_in_use(self, format):
|
||||
LOG.debug("_test_delete_network_in_use - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
port_state = "ACTIVE"
|
||||
attachment_id = "test_attachment"
|
||||
network_id = self._create_network(format)
|
||||
LOG.debug("Deleting network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
port_id = self._create_port(network_id, port_state, format)
|
||||
#plug an attachment into the port
|
||||
LOG.debug("Putting attachment into port %s", port_id)
|
||||
attachment_req = testlib.put_attachment_request(self.tenant_id,
|
||||
network_id,
|
||||
port_id,
|
||||
attachment_id)
|
||||
attachment_res = attachment_req.get_response(self.api)
|
||||
self.assertEquals(attachment_res.status_int, 202)
|
||||
|
||||
LOG.debug("Deleting network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
delete_network_req = testlib.network_delete_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
delete_network_res = delete_network_req.get_response(self.api)
|
||||
self.assertEqual(delete_network_res.status_int, 421)
|
||||
LOG.debug("_test_delete_network_in_use - format:%s - END", format)
|
||||
|
||||
def _test_create_port(self, format):
|
||||
LOG.debug("_test_create_port - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
port_state = "ACTIVE"
|
||||
network_id = self._create_network(format)
|
||||
port_id = self._create_port(network_id, port_state, format)
|
||||
show_port_req = testlib.show_port_request(self.tenant_id, network_id,
|
||||
port_id, format)
|
||||
show_port_res = show_port_req.get_response(self.api)
|
||||
self.assertEqual(show_port_res.status_int, 200)
|
||||
port_data = Serializer().deserialize(show_port_res.body, content_type)
|
||||
self.assertEqual(port_id, port_data['ports']['port']['id'])
|
||||
LOG.debug("_test_create_port - format:%s - END", format)
|
||||
|
||||
def _test_delete_port(self, format):
|
||||
LOG.debug("_test_delete_port - format:%s - START", format)
|
||||
content_type = "application/%s" % format
|
||||
port_state = "ACTIVE"
|
||||
network_id = self._create_network(format)
|
||||
port_id = self._create_port(network_id, port_state, format)
|
||||
LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
delete_port_req = testlib.create_port_delete_request(self.tenant_id,
|
||||
network_id,
|
||||
port_id,
|
||||
format)
|
||||
delete_port_req = testlib.port_delete_request(self.tenant_id,
|
||||
network_id, port_id,
|
||||
format)
|
||||
delete_port_res = delete_port_req.get_response(self.api)
|
||||
self.assertEqual(delete_port_res.status_int, 202)
|
||||
list_port_req = testlib.create_port_list_request(self.tenant_id,
|
||||
network_id,
|
||||
format)
|
||||
list_port_req = testlib.port_list_request(self.tenant_id, network_id,
|
||||
format)
|
||||
list_port_res = list_port_req.get_response(self.api)
|
||||
port_list_data = Serializer().deserialize(list_port_res.body,
|
||||
content_type)
|
||||
@ -98,55 +182,102 @@ class APIPortsTest(unittest.TestCase):
|
||||
self.assertEqual(port_count, 0)
|
||||
LOG.debug("_test_delete_port - format:%s - END", format)
|
||||
|
||||
def _test_delete_port_in_use(self, format):
|
||||
LOG.debug("_test_delete_port_in_use - format:%s - START", format)
|
||||
content_type = "application/" + format
|
||||
port_state = "ACTIVE"
|
||||
attachment_id = "test_attachment"
|
||||
network_id = self._create_network(format)
|
||||
port_id = self._create_port(network_id, port_state, format)
|
||||
#plug an attachment into the port
|
||||
LOG.debug("Putting attachment into port %s", port_id)
|
||||
attachment_req = testlib.put_attachment_request(self.tenant_id,
|
||||
network_id,
|
||||
port_id,
|
||||
attachment_id)
|
||||
attachment_res = attachment_req.get_response(self.api)
|
||||
self.assertEquals(attachment_res.status_int, 202)
|
||||
LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
|
||||
" of tenant %(tenant_id)s", locals())
|
||||
delete_port_req = testlib.port_delete_request(self.tenant_id,
|
||||
network_id, port_id,
|
||||
format)
|
||||
delete_port_res = delete_port_req.get_response(self.api)
|
||||
self.assertEqual(delete_port_res.status_int, 432)
|
||||
LOG.debug("_test_delete_port_in_use - format:%s - END", format)
|
||||
pass
|
||||
|
||||
def _test_delete_port_with_bad_id(self, format):
|
||||
LOG.debug("_test_delete_port_with_bad_id - format:%s - START", format)
|
||||
port_state = "ACTIVE"
|
||||
network_id = self._create_network(format)
|
||||
self._create_port(network_id, port_state, format)
|
||||
# Test for portnotfound
|
||||
delete_port_req = testlib.port_delete_request(self.tenant_id,
|
||||
network_id, "A_BAD_ID",
|
||||
format)
|
||||
delete_port_res = delete_port_req.get_response(self.api)
|
||||
self.assertEqual(delete_port_res.status_int, 430)
|
||||
LOG.debug("_test_delete_port_with_bad_id - format:%s - END", format)
|
||||
|
||||
def setUp(self):
|
||||
self.db_file = ':memory'
|
||||
options = {}
|
||||
options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin'
|
||||
options['sql_connection'] = 'sqlite:///%s' % self.db_file
|
||||
self.api = server.APIRouterV01(options)
|
||||
self.tenant_id = "test_tenant"
|
||||
self.network_name = "test_network"
|
||||
|
||||
def tearDown(self):
|
||||
"""Clear the test environment"""
|
||||
# Unconfigure database engine
|
||||
db.unconfigure_db()
|
||||
|
||||
def test_create_network_json(self):
|
||||
self._test_create_network('json')
|
||||
|
||||
def test_create_network_xml(self):
|
||||
self._test_create_network('xml')
|
||||
|
||||
def test_show_network_json(self):
|
||||
self._test_show_network('json')
|
||||
|
||||
def test_show_network_xml(self):
|
||||
self._test_show_network('xml')
|
||||
|
||||
def test_delete_network_json(self):
|
||||
self._test_delete_network('json')
|
||||
|
||||
def test_delete_network_xml(self):
|
||||
self._test_delete_network('xml')
|
||||
|
||||
def test_delete_network_in_use_json(self):
|
||||
self._test_delete_network_in_use('json')
|
||||
|
||||
def test_delete_network_in_use_xml(self):
|
||||
self._test_delete_network_in_use('xml')
|
||||
|
||||
def test_create_port_json(self):
|
||||
self._test_create_port('json')
|
||||
|
||||
def test_create_port_xml(self):
|
||||
self._test_create_port('xml')
|
||||
|
||||
def test_delete_port_xml(self):
|
||||
self._test_delete_port('xml')
|
||||
|
||||
def test_delete_port_json(self):
|
||||
self._test_delete_port('json')
|
||||
|
||||
def _test_delete_port_in_use(self):
|
||||
# Test for portinuse
|
||||
#rv = self.port.create(req, tenant, network_id)
|
||||
#port_id = rv["ports"]["port"]["id"]
|
||||
#req = testlib.create_attachment_request(tenant, network_id,
|
||||
# port_id, "fudd")
|
||||
#rv = self.port.attach_resource(req, tenant, network_id, port_id)
|
||||
#self.assertEqual(rv.status_int, 202)
|
||||
#rv = self.port.delete("", tenant, network_id, port_id)
|
||||
#self.assertEqual(rv.wrapped_exc.status_int, 432)
|
||||
pass
|
||||
def test_delete_port_in_use_xml(self):
|
||||
self._test_delete_port_in_use('xml')
|
||||
|
||||
def test_delete_port_in_use_json(self):
|
||||
self._test_delete_port_in_use('json')
|
||||
|
||||
def _test_delete_port_with_bad_id(self,format):
|
||||
LOG.debug("_test_delete_port - format:%s - START", format)
|
||||
content_type = "application/" + format
|
||||
port_state = "ACTIVE"
|
||||
LOG.debug("Creating network and port")
|
||||
network_req = testlib.create_new_network_request(self.tenant_id,
|
||||
self.network_name,
|
||||
format)
|
||||
network_res = network_req.get_response(self.api)
|
||||
self.assertEqual(network_res.status_int, 200)
|
||||
network_data = Serializer().deserialize(network_res.body,
|
||||
content_type)
|
||||
network_id = network_data['networks']['network']['id']
|
||||
port_req = testlib.create_new_port_request(self.tenant_id,
|
||||
network_id, port_state,
|
||||
format)
|
||||
port_res = port_req.get_response(self.api)
|
||||
self.assertEqual(port_res.status_int, 200)
|
||||
|
||||
# Test for portnotfound
|
||||
delete_port_req = testlib.create_port_delete_request(self.tenant_id,
|
||||
network_id,
|
||||
"A_BAD_ID",
|
||||
format)
|
||||
delete_port_res = delete_port_req.get_response(self.api)
|
||||
self.assertEqual(delete_port_res.status_int, 430)
|
||||
|
||||
def test_delete_port_with_bad_id_xml(self):
|
||||
self._test_delete_port_wth_bad_id('xml')
|
||||
self._test_delete_port_with_bad_id('xml')
|
||||
|
||||
def test_delete_port_with_bad_id_json(self):
|
||||
self._test_delete_port_with_bad_id('json')
|
||||
|
||||
|
@ -12,60 +12,78 @@ def create_request(path, body, content_type, method='GET'):
|
||||
return req
|
||||
|
||||
|
||||
def create_network_list_request(tenant_id, format='xml'):
|
||||
def network_list_request(tenant_id, format='xml'):
|
||||
method = 'GET'
|
||||
path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def create_new_network_request(tenant_id, network_name, format='xml'):
|
||||
def show_network_request(tenant_id, network_id, format='xml'):
|
||||
method = 'GET'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s.%(format)s" % locals()
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def new_network_request(tenant_id, network_name, format='xml'):
|
||||
method = 'POST'
|
||||
path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
|
||||
data = {'network': {'net-name': '%s' % network_name}}
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
body = Serializer().serialize(data, content_type)
|
||||
return create_request(path, body, content_type, method)
|
||||
|
||||
|
||||
def create_network_delete_request(tenant_id, network_id, format='xml'):
|
||||
def network_delete_request(tenant_id, network_id, format='xml'):
|
||||
method = 'DELETE'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s.%(format)s" % locals()
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def create_port_list_request(tenant_id, network_id, format='xml'):
|
||||
def port_list_request(tenant_id, network_id, format='xml'):
|
||||
method = 'GET'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports.%(format)s" % locals()
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def create_new_port_request(tenant_id, network_id, port_state, format='xml'):
|
||||
def show_port_request(tenant_id, network_id, port_id, format='xml'):
|
||||
method = 'GET'
|
||||
path = "/tenants/%(tenant_id)s/networks/%(network_id)s" \
|
||||
"/ports/%(port_id)s.%(format)s" % locals()
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def new_port_request(tenant_id, network_id, port_state, format='xml'):
|
||||
method = 'POST'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports.%(format)s" % locals()
|
||||
data = {'port': {'port-state': '%s' % port_state}}
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
body = Serializer().serialize(data, content_type)
|
||||
return create_request(path, body, content_type, method)
|
||||
|
||||
|
||||
def create_port_delete_request(tenant_id, network_id, port_id, format='xml'):
|
||||
def port_delete_request(tenant_id, network_id, port_id, format='xml'):
|
||||
method = 'DELETE'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
|
||||
content_type = "application/" + format
|
||||
content_type = "application/%s" % format
|
||||
return create_request(path, None, content_type, method)
|
||||
|
||||
|
||||
def create_attachment_request(tid, nid, pid, attachment_id):
|
||||
path = "/v0.1/tenants/%s/networks/%s/ports/%s/attachment.json" % (tid,
|
||||
nid, pid)
|
||||
def put_attachment_request(tenant_id, network_id, port_id,
|
||||
attachment_id, format='xml'):
|
||||
method = 'PUT'
|
||||
path = "/tenants/%(tenant_id)s/networks/" \
|
||||
"%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
|
||||
data = {'port': {'attachment-id': attachment_id}}
|
||||
content_type = "application/json"
|
||||
content_type = "application/%s" % format
|
||||
body = Serializer().serialize(data, content_type)
|
||||
return create_request(path, body)
|
||||
return create_request(path, body, content_type, method)
|
||||
|
174
tools/batch_config.py
Normal file
174
tools/batch_config.py
Normal file
@ -0,0 +1,174 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 Nicira Networks, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# @author: Dan Wendlandt, Nicira Networks, Inc.
|
||||
|
||||
import httplib
|
||||
import logging as LOG
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
import urllib
|
||||
|
||||
from quantum.manager import QuantumManager
|
||||
from optparse import OptionParser
|
||||
from quantum.common.wsgi import Serializer
|
||||
from quantum.cli import MiniClient
|
||||
|
||||
FORMAT = "json"
|
||||
CONTENT_TYPE = "application/" + FORMAT
|
||||
|
||||
|
||||
def delete_all_nets(client, tenant_id):
|
||||
res = client.do_request(tenant_id, 'GET', "/networks." + FORMAT)
|
||||
resdict = json.loads(res.read())
|
||||
LOG.debug(resdict)
|
||||
for n in resdict["networks"]:
|
||||
nid = n["id"]
|
||||
|
||||
res = client.do_request(tenant_id, 'GET',
|
||||
"/networks/%s/ports.%s" % (nid, FORMAT))
|
||||
output = res.read()
|
||||
if res.status != 200:
|
||||
LOG.error("Failed to list ports: %s" % output)
|
||||
continue
|
||||
rd = json.loads(output)
|
||||
LOG.debug(rd)
|
||||
for port in rd["ports"]:
|
||||
pid = port["id"]
|
||||
|
||||
data = {'port': {'attachment-id': ''}}
|
||||
body = Serializer().serialize(data, CONTENT_TYPE)
|
||||
res = client.do_request(tenant_id, 'DELETE',
|
||||
"/networks/%s/ports/%s/attachment.%s" % \
|
||||
(nid, pid, FORMAT), body=body)
|
||||
output = res.read()
|
||||
LOG.debug(output)
|
||||
if res.status != 202:
|
||||
LOG.error("Failed to unplug iface from port \"%s\": %s" % (vid,
|
||||
pid, output))
|
||||
continue
|
||||
LOG.info("Unplugged interface from port:%s on network:%s" % (pid,
|
||||
nid))
|
||||
|
||||
res = client.do_request(tenant_id, 'DELETE',
|
||||
"/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
|
||||
output = res.read()
|
||||
if res.status != 202:
|
||||
LOG.error("Failed to delete port: %s" % output)
|
||||
continue
|
||||
print "Deleted Virtual Port:%s " \
|
||||
"on Virtual Network:%s" % (pid, nid)
|
||||
|
||||
res = client.do_request(tenant_id, 'DELETE',
|
||||
"/networks/" + nid + "." + FORMAT)
|
||||
status = res.status
|
||||
if status != 202:
|
||||
Log.error("Failed to delete network: %s" % nid)
|
||||
output = res.read()
|
||||
print output
|
||||
else:
|
||||
print "Deleted Virtual Network with ID:%s" % nid
|
||||
|
||||
|
||||
def create_net_with_attachments(net_name, iface_ids):
|
||||
data = {'network': {'network-name': '%s' % net_name}}
|
||||
body = Serializer().serialize(data, CONTENT_TYPE)
|
||||
res = client.do_request(tenant_id, 'POST',
|
||||
"/networks." + FORMAT, body=body)
|
||||
rd = json.loads(res.read())
|
||||
LOG.debug(rd)
|
||||
nid = rd["networks"]["network"]["id"]
|
||||
print "Created a new Virtual Network %s with ID:%s" % (net_name, nid)
|
||||
|
||||
for iface_id in iface_ids:
|
||||
res = client.do_request(tenant_id, 'POST',
|
||||
"/networks/%s/ports.%s" % (nid, FORMAT))
|
||||
output = res.read()
|
||||
if res.status != 200:
|
||||
LOG.error("Failed to create port: %s" % output)
|
||||
continue
|
||||
rd = json.loads(output)
|
||||
new_port_id = rd["ports"]["port"]["id"]
|
||||
print "Created Virtual Port:%s " \
|
||||
"on Virtual Network:%s" % (new_port_id, nid)
|
||||
data = {'port': {'attachment-id': '%s' % iface_id}}
|
||||
body = Serializer().serialize(data, CONTENT_TYPE)
|
||||
res = client.do_request(tenant_id, 'PUT',
|
||||
"/networks/%s/ports/%s/attachment.%s" %\
|
||||
(nid, new_port_id, FORMAT), body=body)
|
||||
output = res.read()
|
||||
LOG.debug(output)
|
||||
if res.status != 202:
|
||||
LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % \
|
||||
(iface_id, new_port_id, output))
|
||||
continue
|
||||
print "Plugged interface \"%s\" to port:%s on network:%s" % \
|
||||
(iface_id, new_port_id, nid)
|
||||
|
||||
if __name__ == "__main__":
|
||||
usagestr = "Usage: %prog [OPTIONS] <tenant-id> <config-string> [args]\n" \
|
||||
"Example config-string: net1=instance-1,instance-2"\
|
||||
":net2=instance-3,instance-4\n" \
|
||||
"This string would create two networks: \n" \
|
||||
"'net1' would have two ports, with iface-ids "\
|
||||
"instance-1 and instance-2 attached\n" \
|
||||
"'net2' would have two ports, with iface-ids"\
|
||||
" instance-3 and instance-4 attached\n"
|
||||
parser = OptionParser(usage=usagestr)
|
||||
parser.add_option("-H", "--host", dest="host",
|
||||
type="string", default="127.0.0.1", help="ip address of api host")
|
||||
parser.add_option("-p", "--port", dest="port",
|
||||
type="int", default=9696, help="api poort")
|
||||
parser.add_option("-s", "--ssl", dest="ssl",
|
||||
action="store_true", default=False, help="use ssl")
|
||||
parser.add_option("-v", "--verbose", dest="verbose",
|
||||
action="store_true", default=False, help="turn on verbose logging")
|
||||
parser.add_option("-d", "--delete", dest="delete",
|
||||
action="store_true", default=False, \
|
||||
help="delete existing tenants networks")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.verbose:
|
||||
LOG.basicConfig(level=LOG.DEBUG)
|
||||
else:
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
|
||||
if len(args) < 1:
|
||||
parser.print_help()
|
||||
help()
|
||||
sys.exit(1)
|
||||
|
||||
nets = {}
|
||||
tenant_id = args[0]
|
||||
if len(args) > 1:
|
||||
config_str = args[1]
|
||||
for net_str in config_str.split(":"):
|
||||
arr = net_str.split("=")
|
||||
net_name = arr[0]
|
||||
nets[net_name] = arr[1].split(",")
|
||||
|
||||
print "nets: %s" % str(nets)
|
||||
|
||||
client = MiniClient(options.host, options.port, options.ssl)
|
||||
|
||||
if options.delete:
|
||||
delete_all_nets(client, tenant_id)
|
||||
|
||||
for net_name, iface_ids in nets.items():
|
||||
create_net_with_attachments(net_name, iface_ids)
|
||||
|
||||
sys.exit(0)
|
Loading…
x
Reference in New Issue
Block a user