From 645251dba4b6d920caed9d4f58f39431d85161d4 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 21 Jun 2011 00:14:14 -0700 Subject: [PATCH 1/5] Bug fixes and clean-up, including supporting libvirt --- quantum/cli.py | 1 + quantum/db/api.py | 4 +- quantum/plugins/openvswitch/README | 9 +- .../openvswitch/agent/ovs_quantum_agent.py | 77 +++++----- .../openvswitch/agent/set_external_ids.sh | 15 -- .../{install.sh => xenserver_install.sh} | 0 quantum/plugins/openvswitch/ovs_db.py | 16 -- quantum/plugins/openvswitch/ovs_models.py | 16 -- .../openvswitch/ovs_quantum_plugin.ini | 6 +- .../plugins/openvswitch/ovs_quantum_plugin.py | 2 - tools/batch_config.py | 137 ++++++++++++++++++ 11 files changed, 191 insertions(+), 92 deletions(-) delete mode 100755 quantum/plugins/openvswitch/agent/set_external_ids.sh rename quantum/plugins/openvswitch/agent/{install.sh => xenserver_install.sh} (100%) create mode 100644 tools/batch_config.py diff --git a/quantum/cli.py b/quantum/cli.py index 4c0ba4eee..a0121b034 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -220,6 +220,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)) diff --git a/quantum/db/api.py b/quantum/db/api.py index 8a6ba305c..1809af057 100644 --- a/quantum/db/api.py +++ b/quantum/db/api.py @@ -67,7 +67,7 @@ def network_create(tenant_id, name): net = None try: net = session.query(models.Network).\ - filter_by(name=name).\ + filter_by(tenant_id=tenant_id,name=name).\ one() raise Exception("Network with name \"%s\" already exists" % name) except exc.NoResultFound: @@ -96,7 +96,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) diff --git a/quantum/plugins/openvswitch/README b/quantum/plugins/openvswitch/README index 689624f1b..a6351ddf6 100644 --- a/quantum/plugins/openvswitch/README +++ b/quantum/plugins/openvswitch/README @@ -60,19 +60,24 @@ 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. - 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]: diff --git a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py index 34f28fbdd..cb21d7a6b 100755 --- a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py +++ b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py @@ -76,7 +76,7 @@ class OVSBridge: def remove_all_flows(self): self.run_ofctl("del-flows", []) - + def get_port_ofport(self, port_name): return self.db_get_val("Interface", port_name, "ofport") @@ -126,6 +126,29 @@ 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): @@ -133,42 +156,25 @@ class OVSBridge: 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) edge_ports.append(p) 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)) + self.int_br.delete_flows(match="in_port=%s" % port.ofport) def port_unbound(self, port, still_exists): if still_exists: @@ -177,12 +183,9 @@ 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 = {} @@ -191,7 +194,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 = {} @@ -215,8 +218,12 @@ class OVSNaaSPlugin: new_local_bindings[p.vif_id] = all_bindings[p.vif_id] else: # no binding, put him on the 'dead vlan' + LOG.info("No binding for %s, setting to dead vlan" \ + % p.vif_id) self.int_br.set_db_attribute("Port", p.port_name, "tag", "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: @@ -225,13 +232,13 @@ class OVSNaaSPlugin: % (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) @@ -241,8 +248,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__": @@ -281,7 +286,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: diff --git a/quantum/plugins/openvswitch/agent/set_external_ids.sh b/quantum/plugins/openvswitch/agent/set_external_ids.sh deleted file mode 100755 index 2fae05f0a..000000000 --- a/quantum/plugins/openvswitch/agent/set_external_ids.sh +++ /dev/null @@ -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 - diff --git a/quantum/plugins/openvswitch/agent/install.sh b/quantum/plugins/openvswitch/agent/xenserver_install.sh similarity index 100% rename from quantum/plugins/openvswitch/agent/install.sh rename to quantum/plugins/openvswitch/agent/xenserver_install.sh diff --git a/quantum/plugins/openvswitch/ovs_db.py b/quantum/plugins/openvswitch/ovs_db.py index a2a72ec8c..a5785c7df 100644 --- a/quantum/plugins/openvswitch/ovs_db.py +++ b/quantum/plugins/openvswitch/ovs_db.py @@ -54,19 +54,3 @@ def remove_vlan_binding(netid): 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() diff --git a/quantum/plugins/openvswitch/ovs_models.py b/quantum/plugins/openvswitch/ovs_models.py index 610902a7c..9ce83611d 100644 --- a/quantum/plugins/openvswitch/ovs_models.py +++ b/quantum/plugins/openvswitch/ovs_models.py @@ -26,22 +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 "" % \ - (self.network_id, self.vif_id) - class VlanBinding(BASE): """Represents a binding of network_id, vlan_id""" __tablename__ = 'vlan_bindings' diff --git a/quantum/plugins/openvswitch/ovs_quantum_plugin.ini b/quantum/plugins/openvswitch/ovs_quantum_plugin.ini index 0c75b3fc4..66095d85d 100644 --- a/quantum/plugins/openvswitch/ovs_quantum_plugin.ini +++ b/quantum/plugins/openvswitch/ovs_quantum_plugin.ini @@ -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 diff --git a/quantum/plugins/openvswitch/ovs_quantum_plugin.py b/quantum/plugins/openvswitch/ovs_quantum_plugin.py index 75619cae6..375a4bd87 100644 --- a/quantum/plugins/openvswitch/ovs_quantum_plugin.py +++ b/quantum/plugins/openvswitch/ovs_quantum_plugin.py @@ -189,11 +189,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) diff --git a/tools/batch_config.py b/tools/batch_config.py new file mode 100644 index 000000000..e6be088ed --- /dev/null +++ b/tools/batch_config.py @@ -0,0 +1,137 @@ +# 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 + + +if __name__ == "__main__": + usagestr = "Usage: %prog [OPTIONS] [args]" + 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") + + 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) + + 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"] + 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 + LOG.info("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: + print "Failed to delete network: %s" % nid + output = res.read() + print output + else: + print "Deleted Virtual Network with ID:%s" % nid + + for net_name, iface_ids in nets.items(): + 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\n" % (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) + + sys.exit(0) From 04062526c1031c40f6f2cde9a2d45bc499651efe Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 21 Jun 2011 10:13:07 -0700 Subject: [PATCH 2/5] add example to usage string for batch_config.py --- tools/batch_config.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/batch_config.py b/tools/batch_config.py index e6be088ed..cf70a8fb9 100644 --- a/tools/batch_config.py +++ b/tools/batch_config.py @@ -32,7 +32,11 @@ CONTENT_TYPE = "application/" + FORMAT if __name__ == "__main__": - usagestr = "Usage: %prog [OPTIONS] [args]" + usagestr = "Usage: %prog [OPTIONS] [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") From dad5dbb764d04cb30a22e5e1bbc62d1f2f5c1e2d Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Sat, 25 Jun 2011 02:04:55 -0700 Subject: [PATCH 3/5] refactor batch_config, allow multiple attaches with the empty string --- quantum/db/api.py | 15 +- .../openvswitch/agent/ovs_quantum_agent.py | 2 - tools/batch_config.py | 155 ++++++++++-------- 3 files changed, 96 insertions(+), 76 deletions(-) diff --git a/quantum/db/api.py b/quantum/db/api.py index 989f0d6c3..59459cadb 100644 --- a/quantum/db/api.py +++ b/quantum/db/api.py @@ -156,13 +156,14 @@ def port_get(port_id): 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 diff --git a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py index 60c864543..5d2a66ca3 100755 --- a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py +++ b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py @@ -222,8 +222,6 @@ class OVSQuantumAgent: new_local_bindings[p.vif_id] = all_bindings[p.vif_id] else: # no binding, put him on the 'dead vlan' - LOG.info("No binding for %s, setting to dead vlan" \ - % p.vif_id) self.int_br.set_db_attribute("Port", p.port_name, "tag", "4095") self.int_br.add_flow(priority=2, diff --git a/tools/batch_config.py b/tools/batch_config.py index 21b35684d..9a7efdda5 100644 --- a/tools/batch_config.py +++ b/tools/batch_config.py @@ -30,6 +30,89 @@ 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] [args]\n" \ @@ -49,6 +132,8 @@ if __name__ == "__main__": 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() @@ -75,74 +160,10 @@ if __name__ == "__main__": client = MiniClient(options.host, options.port, options.ssl) - 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"] - 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 - LOG.info("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: - print "Failed to delete network: %s" % nid - output = res.read() - print output - else: - print "Deleted Virtual Network with ID:%s" % nid + if options.delete: + delete_all_nets(client, tenant_id) for net_name, iface_ids in nets.items(): - 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\n" % (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) + create_net_with_attachments(net_name, iface_ids) sys.exit(0) From 7534f9dea7ef1899bf881753e568d91672bd36fd Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Mon, 27 Jun 2011 09:27:18 -0700 Subject: [PATCH 4/5] more pep8 goodness --- tools/batch_config.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/batch_config.py b/tools/batch_config.py index 9a7efdda5..63f4a5223 100644 --- a/tools/batch_config.py +++ b/tools/batch_config.py @@ -30,6 +30,7 @@ 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()) @@ -51,14 +52,16 @@ def delete_all_nets(client, tenant_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) + "/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)) + 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)) @@ -79,6 +82,7 @@ def delete_all_nets(client, tenant_id): 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) @@ -133,7 +137,8 @@ if __name__ == "__main__": 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") + action="store_true", default=False, \ + help="delete existing tenants networks") options, args = parser.parse_args() From a0692d9cc6c027e4ec8fe6deea9f10fc69748b75 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Mon, 27 Jun 2011 16:11:09 -0700 Subject: [PATCH 5/5] fix pep8 introduced by trunk merge --- quantum/cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/cli.py b/quantum/cli.py index 496055be1..bbbc9fbf9 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -319,7 +319,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)