Merging dan wendlandt's bugfixes for Bug #800466 and improvements that enable Quantum to seamlessly
run on KVM! removed: quantum/plugins/openvswitch/agent/set_external_ids.sh added: tools/batch_config.py renamed: quantum/plugins/openvswitch/agent/install.sh => quantum/plugins/openvswitch/agent/xenserver_install.sh modified: quantum/cli.py quantum/db/api.py quantum/plugins/openvswitch/README quantum/plugins/openvswitch/agent/ovs_quantum_agent.py quantum/plugins/openvswitch/ovs_db.py quantum/plugins/openvswitch/ovs_models.py quantum/plugins/openvswitch/ovs_quantum_plugin.ini quantum/plugins/openvswitch/ovs_quantum_plugin.py pending merges: Dan Wendlandt 2011-06-27 fix pep8 introduced by trunk merge Dan Wendlandt 2011-06-27 [merge] merge Dan Wendlandt 2011-06-27 more pep8 goodness Dan Wendlandt 2011-06-25 refactor batch_config, allow multiple attaches with the empty string Dan Wendlandt 2011-06-21 [merge] merge and pep8 cleanup Dan Wendlandt 2011-06-21 add example to usage string for batch_config.py Dan Wendlandt 2011-06-21 Bug fixes and clean-up, including supporting libvirt
This commit is contained in:
commit
5d23ba2598
@ -240,6 +240,7 @@ def api_create_port(client, *args):
|
|||||||
|
|
||||||
def delete_port(manager, *args):
|
def delete_port(manager, *args):
|
||||||
tid, nid, pid = args
|
tid, nid, pid = args
|
||||||
|
manager.delete_port(tid, nid, pid)
|
||||||
LOG.info("Deleted Virtual Port:%s " \
|
LOG.info("Deleted Virtual Port:%s " \
|
||||||
"on Virtual Network:%s" % (pid, nid))
|
"on Virtual Network:%s" % (pid, nid))
|
||||||
|
|
||||||
@ -318,7 +319,8 @@ def api_unplug_iface(client, *args):
|
|||||||
output = res.read()
|
output = res.read()
|
||||||
LOG.debug(output)
|
LOG.debug(output)
|
||||||
if res.status != 202:
|
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
|
return
|
||||||
print "Unplugged interface from port:%s on network:%s" % (pid, nid)
|
print "Unplugged interface from port:%s on network:%s" % (pid, nid)
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ def network_create(tenant_id, name):
|
|||||||
net = None
|
net = None
|
||||||
try:
|
try:
|
||||||
net = session.query(models.Network).\
|
net = session.query(models.Network).\
|
||||||
filter_by(name=name).\
|
filter_by(tenant_id=tenant_id, name=name).\
|
||||||
one()
|
one()
|
||||||
raise Exception("Network with name \"%s\" already exists" % name)
|
raise Exception("Network with name \"%s\" already exists" % name)
|
||||||
except exc.NoResultFound:
|
except exc.NoResultFound:
|
||||||
@ -104,7 +104,7 @@ def network_rename(net_id, tenant_id, new_name):
|
|||||||
session = get_session()
|
session = get_session()
|
||||||
try:
|
try:
|
||||||
res = session.query(models.Network).\
|
res = session.query(models.Network).\
|
||||||
filter_by(name=new_name).\
|
filter_by(tenant_id=tenant_id, name=new_name).\
|
||||||
one()
|
one()
|
||||||
except exc.NoResultFound:
|
except exc.NoResultFound:
|
||||||
net = network_get(net_id)
|
net = network_get(net_id)
|
||||||
@ -156,13 +156,14 @@ def port_get(port_id):
|
|||||||
|
|
||||||
def port_set_attachment(port_id, new_interface_id):
|
def port_set_attachment(port_id, new_interface_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
ports = None
|
ports = []
|
||||||
try:
|
if new_interface_id != "":
|
||||||
ports = session.query(models.Port).\
|
try:
|
||||||
filter_by(interface_id=new_interface_id).\
|
ports = session.query(models.Port).\
|
||||||
all()
|
filter_by(interface_id=new_interface_id).\
|
||||||
except exc.NoResultFound:
|
all()
|
||||||
pass
|
except exc.NoResultFound:
|
||||||
|
pass
|
||||||
if len(ports) == 0:
|
if len(ports) == 0:
|
||||||
port = port_get(port_id)
|
port = port_get(port_id)
|
||||||
port.interface_id = new_interface_id
|
port.interface_id = new_interface_id
|
||||||
|
@ -62,20 +62,25 @@ mysql> FLUSH PRIVILEGES;
|
|||||||
distribution tarball (see below) and the agent will use the credentials here
|
distribution tarball (see below) and the agent will use the credentials here
|
||||||
to access the database.
|
to access the database.
|
||||||
|
|
||||||
# -- Agent configuration
|
# -- XenServer Agent configuration
|
||||||
|
|
||||||
- Create the agent distribution tarball
|
- Create the agent distribution tarball
|
||||||
|
|
||||||
$ make agent-dist
|
$ make agent-dist
|
||||||
- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova
|
- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova
|
||||||
compute node)
|
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
|
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.
|
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.
|
Make sure to specify this in your nova flagfile as --flat_network_bridge.
|
||||||
- Run the agent [on your hypervisor (dom0)]:
|
- Run the agent [on your hypervisor (dom0)]:
|
||||||
$ /etc/xapi.d/plugins/ovs_quantum_agent.py /etc/xapi.d/plugins/ovs_quantum_plugin.ini
|
$ /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
|
# -- Getting quantum up and running
|
||||||
|
|
||||||
- Start quantum [on the quantum service host]:
|
- Start quantum [on the quantum service host]:
|
||||||
|
@ -130,40 +130,40 @@ class OVSBridge:
|
|||||||
def get_port_stats(self, port_name):
|
def get_port_stats(self, port_name):
|
||||||
return self.db_get_map("Interface", port_name, "statistics")
|
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
|
# returns a VIF object for each VIF port
|
||||||
def get_vif_ports(self):
|
def get_vif_ports(self):
|
||||||
edge_ports = []
|
edge_ports = []
|
||||||
port_names = self.get_port_name_list()
|
port_names = self.get_port_name_list()
|
||||||
for name in port_names:
|
for name in port_names:
|
||||||
external_ids = self.db_get_map("Interface", name, "external_ids")
|
external_ids = self.db_get_map("Interface", name, "external_ids")
|
||||||
if "iface-id" in external_ids and "attached-mac" in external_ids:
|
if "xs-vm-uuid" in external_ids:
|
||||||
ofport = self.db_get_val("Interface", name, "ofport")
|
p = xapi_get_port(name)
|
||||||
p = VifPort(name, ofport, external_ids["iface-id"],
|
if p is not None:
|
||||||
external_ids["attached-mac"], self)
|
edge_ports.append(p)
|
||||||
edge_ports.append(p)
|
elif "iface-id" in external_ids and "attached-mac" in external_ids:
|
||||||
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)
|
|
||||||
ofport = self.db_get_val("Interface", name, "ofport")
|
ofport = self.db_get_val("Interface", name, "ofport")
|
||||||
p = VifPort(name, ofport, external_ids["iface-id"],
|
p = VifPort(name, ofport, external_ids["iface-id"],
|
||||||
external_ids["attached-mac"], self)
|
external_ids["attached-mac"], self)
|
||||||
@ -171,13 +171,15 @@ class OVSBridge:
|
|||||||
return edge_ports
|
return edge_ports
|
||||||
|
|
||||||
|
|
||||||
class OVSNaaSPlugin:
|
class OVSQuantumAgent:
|
||||||
|
|
||||||
def __init__(self, integ_br):
|
def __init__(self, integ_br):
|
||||||
self.setup_integration_br(integ_br)
|
self.setup_integration_br(integ_br)
|
||||||
|
|
||||||
def port_bound(self, port, vlan_id):
|
def port_bound(self, port, vlan_id):
|
||||||
self.int_br.set_db_attribute("Port", port.port_name, "tag",
|
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):
|
def port_unbound(self, port, still_exists):
|
||||||
if still_exists:
|
if still_exists:
|
||||||
@ -186,13 +188,8 @@ class OVSNaaSPlugin:
|
|||||||
def setup_integration_br(self, integ_br):
|
def setup_integration_br(self, integ_br):
|
||||||
self.int_br = OVSBridge(integ_br)
|
self.int_br = OVSBridge(integ_br)
|
||||||
self.int_br.remove_all_flows()
|
self.int_br.remove_all_flows()
|
||||||
# drop all traffic on the 'dead vlan'
|
# switch all traffic using L2 learning
|
||||||
self.int_br.add_flow(priority=2, match="dl_vlan=4095", actions="drop")
|
|
||||||
# switch all other traffic using L2 learning
|
|
||||||
self.int_br.add_flow(priority=1, actions="normal")
|
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):
|
def daemon_loop(self, conn):
|
||||||
self.local_vlan_map = {}
|
self.local_vlan_map = {}
|
||||||
@ -201,7 +198,7 @@ class OVSNaaSPlugin:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("SELECT * FROM network_bindings")
|
cursor.execute("SELECT * FROM ports")
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
all_bindings = {}
|
all_bindings = {}
|
||||||
@ -226,22 +223,26 @@ class OVSNaaSPlugin:
|
|||||||
else:
|
else:
|
||||||
# no binding, put him on the 'dead vlan'
|
# no binding, put him on the 'dead vlan'
|
||||||
self.int_br.set_db_attribute("Port", p.port_name, "tag",
|
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)
|
old_b = old_local_bindings.get(p.vif_id, None)
|
||||||
new_b = new_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 != new_b:
|
||||||
if old_b is not None:
|
if old_b is not None:
|
||||||
LOG.info("Removing binding to net-id = %s for %s"
|
LOG.info("Removing binding to net-id = %s for %s"
|
||||||
% (old_b, str(p)))
|
% (old_b, str(p)))
|
||||||
self.port_unbound(p, True)
|
self.port_unbound(p, True)
|
||||||
if new_b is not None:
|
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
|
# If we don't have a binding we have to stick it on
|
||||||
# the dead vlan
|
# the dead vlan
|
||||||
vlan_id = vlan_bindings.get(all_bindings[p.vif_id],
|
vlan_id = vlan_bindings.get(all_bindings[p.vif_id],
|
||||||
"4095")
|
"4095")
|
||||||
self.port_bound(p, vlan_id)
|
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():
|
for vif_id in old_vif_ports.keys():
|
||||||
if vif_id not in new_vif_ports:
|
if vif_id not in new_vif_ports:
|
||||||
LOG.info("Port Disappeared: %s" % vif_id)
|
LOG.info("Port Disappeared: %s" % vif_id)
|
||||||
@ -251,8 +252,6 @@ class OVSNaaSPlugin:
|
|||||||
|
|
||||||
old_vif_ports = new_vif_ports
|
old_vif_ports = new_vif_ports
|
||||||
old_local_bindings = new_local_bindings
|
old_local_bindings = new_local_bindings
|
||||||
self.int_br.run_cmd(["bash",
|
|
||||||
"/etc/xapi.d/plugins/set_external_ids.sh"])
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@ -291,7 +290,7 @@ if __name__ == "__main__":
|
|||||||
LOG.info("Connecting to database \"%s\" on %s" % (db_name, db_host))
|
LOG.info("Connecting to database \"%s\" on %s" % (db_name, db_host))
|
||||||
conn = MySQLdb.connect(host=db_host, user=db_user,
|
conn = MySQLdb.connect(host=db_host, user=db_user,
|
||||||
passwd=db_pass, db=db_name)
|
passwd=db_pass, db=db_name)
|
||||||
plugin = OVSNaaSPlugin(integ_br)
|
plugin = OVSQuantumAgent(integ_br)
|
||||||
plugin.daemon_loop(conn)
|
plugin.daemon_loop(conn)
|
||||||
finally:
|
finally:
|
||||||
if conn:
|
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:
|
except exc.NoResultFound:
|
||||||
pass
|
pass
|
||||||
session.flush()
|
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
|
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):
|
class VlanBinding(BASE):
|
||||||
"""Represents a binding of network_id, vlan_id"""
|
"""Represents a binding of network_id, vlan_id"""
|
||||||
__tablename__ = 'vlan_bindings'
|
__tablename__ = 'vlan_bindings'
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
[DATABASE]
|
[DATABASE]
|
||||||
name = ovs_naas
|
name = ovs_quantum
|
||||||
user = root
|
user = root
|
||||||
pass = foobar
|
pass = nova
|
||||||
host = 127.0.0.1
|
host = 127.0.0.1
|
||||||
port = 3306
|
port = 3306
|
||||||
|
|
||||||
[OVS]
|
[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):
|
def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):
|
||||||
db.port_set_attachment(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):
|
def unplug_interface(self, tenant_id, net_id, port_id):
|
||||||
db.port_set_attachment(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):
|
def get_interface_details(self, tenant_id, net_id, port_id):
|
||||||
res = db.port_get(port_id)
|
res = db.port_get(port_id)
|
||||||
|
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…
Reference in New Issue
Block a user