Merge lp:~danwent/neutron/ovs-plugin-fixes into lp:neutron/diablo

Proposed by dan wendlandt
Status: Merged
Merge reported by: Somik Behera
Merged at revision: not available
Proposed branch: lp:~danwent/neutron/ovs-plugin-fixes
Merge into: lp:neutron/diablo
Diff against target: 547 lines (+239/-110)
10 files modified
quantum/cli.py (+3/-1)
quantum/db/api.py (+10/-9)
quantum/plugins/openvswitch/README (+7/-2)
quantum/plugins/openvswitch/agent/ovs_quantum_agent.py (+42/-43)
quantum/plugins/openvswitch/agent/set_external_ids.sh (+0/-15)
quantum/plugins/openvswitch/ovs_db.py (+0/-18)
quantum/plugins/openvswitch/ovs_models.py (+0/-17)
quantum/plugins/openvswitch/ovs_quantum_plugin.ini (+3/-3)
quantum/plugins/openvswitch/ovs_quantum_plugin.py (+0/-2)
tools/batch_config.py (+174/-0)
To merge this branch: bzr merge lp:~danwent/neutron/ovs-plugin-fixes
Reviewer Review Type Date Requested Status
Somik Behera netstack-core Approve
Brad Hall (community) Approve
Review via email: mp+66024@code.launchpad.net

Description of the change

This branch started out just aiming to tweak the OVS plugin so it could run on hypervisors other than XenServer. In the course, I fixed a couple of bugs in the OVS plugin and in the DB models created for the OVS plugin.

I also introduced a new tool called "batch_config.py" that simplifies testing by making it easy to create network topologies using a single CLI command, instead of copying and pasting UUIDs from individual calls.

Other than batch_config.py, there should be no new functionality, only fixes.

This code has been pretty heavily tested with libvirt, and Brad has tested it with XenServer.

To post a comment you must log in.
Revision history for this message
dan wendlandt (danwent) wrote :

One comment, you will notice a change that makes it permissible for multiple ports to have the empty string as an attachment. This was because the CLI actually performs an unplug using the empty string:

def api_unplug_iface(client, *args):
    tid, nid, pid = args
    data = {'port': {'attachment-id': ''}}

However, I actually think it would be cleaner if this happened by setting attachment-id to a null/none value. We should check with Salvatore on this.

Revision history for this message
Brad Hall (bgh) wrote :

Looks good to me.

review: Approve
Revision history for this message
Somik Behera (somikbehera) wrote :

1) There is 1 pep8 violation, trunk is pep8 clean, so we should make sure to get this merge cleaned up too.

./quantum/cli.py:322:80: E501 line too long (80 characters)

2) quantum/cli.py should raise an exception when it cant set attachement

except exc.NoResultFound:
         pass

But, this bug was pre-existing, I'll file something for this.

3) Otherwise, everything looks good! If you can just fix the pep8 change, we can get this bug fix merged in!

review: Needs Fixing (netstack-core)
lp:~danwent/neutron/ovs-plugin-fixes updated
23. By dan wendlandt

fix pep8 introduced by trunk merge

Revision history for this message
Somik Behera (somikbehera) wrote :

Thanks for fixing that pep8 change that had slipped in!

Got to keep the trunk pep8 clean.

review: Approve (netstack-core)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'quantum/cli.py'
--- quantum/cli.py 2011-06-24 18:20:03 +0000
+++ quantum/cli.py 2011-06-27 23:11:53 +0000
@@ -240,6 +240,7 @@
240240
241def delete_port(manager, *args):241def delete_port(manager, *args):
242 tid, nid, pid = args242 tid, nid, pid = args
243 manager.delete_port(tid, nid, pid)
243 LOG.info("Deleted Virtual Port:%s " \244 LOG.info("Deleted Virtual Port:%s " \
244 "on Virtual Network:%s" % (pid, nid))245 "on Virtual Network:%s" % (pid, nid))
245246
@@ -318,7 +319,8 @@
318 output = res.read()319 output = res.read()
319 LOG.debug(output)320 LOG.debug(output)
320 if res.status != 202:321 if res.status != 202:
321 LOG.error("Failed to unplug iface from port \"%s\": %s" % (pid, output))322 LOG.error("Failed to unplug iface from port \"%s\": %s" % \
323 (pid, output))
322 return324 return
323 print "Unplugged interface from port:%s on network:%s" % (pid, nid)325 print "Unplugged interface from port:%s on network:%s" % (pid, nid)
324326
325327
=== modified file 'quantum/db/api.py'
--- quantum/db/api.py 2011-06-08 10:21:47 +0000
+++ quantum/db/api.py 2011-06-27 23:11:53 +0000
@@ -72,7 +72,7 @@
72 net = None72 net = None
73 try:73 try:
74 net = session.query(models.Network).\74 net = session.query(models.Network).\
75 filter_by(name=name).\75 filter_by(tenant_id=tenant_id, name=name).\
76 one()76 one()
77 raise Exception("Network with name \"%s\" already exists" % name)77 raise Exception("Network with name \"%s\" already exists" % name)
78 except exc.NoResultFound:78 except exc.NoResultFound:
@@ -104,7 +104,7 @@
104 session = get_session()104 session = get_session()
105 try:105 try:
106 res = session.query(models.Network).\106 res = session.query(models.Network).\
107 filter_by(name=new_name).\107 filter_by(tenant_id=tenant_id, name=new_name).\
108 one()108 one()
109 except exc.NoResultFound:109 except exc.NoResultFound:
110 net = network_get(net_id)110 net = network_get(net_id)
@@ -156,13 +156,14 @@
156156
157def port_set_attachment(port_id, new_interface_id):157def port_set_attachment(port_id, new_interface_id):
158 session = get_session()158 session = get_session()
159 ports = None159 ports = []
160 try:160 if new_interface_id != "":
161 ports = session.query(models.Port).\161 try:
162 filter_by(interface_id=new_interface_id).\162 ports = session.query(models.Port).\
163 all()163 filter_by(interface_id=new_interface_id).\
164 except exc.NoResultFound:164 all()
165 pass165 except exc.NoResultFound:
166 pass
166 if len(ports) == 0:167 if len(ports) == 0:
167 port = port_get(port_id)168 port = port_get(port_id)
168 port.interface_id = new_interface_id169 port.interface_id = new_interface_id
169170
=== modified file 'quantum/plugins/openvswitch/README'
--- quantum/plugins/openvswitch/README 2011-06-09 14:42:19 +0000
+++ quantum/plugins/openvswitch/README 2011-06-27 23:11:53 +0000
@@ -62,20 +62,25 @@
62 distribution tarball (see below) and the agent will use the credentials here62 distribution tarball (see below) and the agent will use the credentials here
63 to access the database.63 to access the database.
6464
65# -- Agent configuration65# -- XenServer Agent configuration
6666
67- Create the agent distribution tarball67- Create the agent distribution tarball
6868
69$ make agent-dist69$ make agent-dist
70- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova70- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova
71 compute node)71 compute node)
72- Unpack the tarball and run install.sh. This will install all of the72- Unpack the tarball and run xenserver_install.sh. This will install all of the
73 necessary pieces into /etc/xapi.d/plugins. It will also spit out the name73 necessary pieces into /etc/xapi.d/plugins. It will also spit out the name
74 of the integration bridge that you'll need for your nova configuration.74 of the integration bridge that you'll need for your nova configuration.
75 Make sure to specify this in your nova flagfile as --flat_network_bridge.75 Make sure to specify this in your nova flagfile as --flat_network_bridge.
76- Run the agent [on your hypervisor (dom0)]:76- Run the agent [on your hypervisor (dom0)]:
77$ /etc/xapi.d/plugins/ovs_quantum_agent.py /etc/xapi.d/plugins/ovs_quantum_plugin.ini77$ /etc/xapi.d/plugins/ovs_quantum_agent.py /etc/xapi.d/plugins/ovs_quantum_plugin.ini
7878
79# -- KVM Agent configuration
80
81- Copy ovs_quantum_agent.py and ovs_quantum_plugin.ini to the Linux host and run:
82$ python ovs_quantum_agent.py ovs_quantum_plugin.ini
83
79# -- Getting quantum up and running84# -- Getting quantum up and running
8085
81- Start quantum [on the quantum service host]:86- Start quantum [on the quantum service host]:
8287
=== modified file 'quantum/plugins/openvswitch/agent/ovs_quantum_agent.py'
--- quantum/plugins/openvswitch/agent/ovs_quantum_agent.py 2011-06-08 10:21:47 +0000
+++ quantum/plugins/openvswitch/agent/ovs_quantum_agent.py 2011-06-27 23:11:53 +0000
@@ -130,40 +130,40 @@
130 def get_port_stats(self, port_name):130 def get_port_stats(self, port_name):
131 return self.db_get_map("Interface", port_name, "statistics")131 return self.db_get_map("Interface", port_name, "statistics")
132132
133 # this is a hack that should go away once nova properly reports bindings
134 # to quantum. We have this here for now as it lets us work with
135 # unmodified nova
136 def xapi_get_port(self, name):
137 external_ids = self.db_get_map("Interface", name, "external_ids")
138 if "attached-mac" not in external_ids:
139 return None
140 vm_uuid = external_ids.get("xs-vm-uuid", "")
141 if len(vm_uuid) == 0:
142 return None
143 LOG.debug("iface-id not set, got xs-vm-uuid: %s" % vm_uuid)
144 res = os.popen("xe vm-list uuid=%s params=name-label --minimal" \
145 % vm_uuid).readline().strip()
146 if len(res) == 0:
147 return None
148 external_ids["iface-id"] = res
149 LOG.info("Setting interface \"%s\" iface-id to \"%s\"" % (name, res))
150 self.set_db_attribute("Interface", name,
151 "external-ids:iface-id", res)
152 ofport = self.db_get_val("Interface", name, "ofport")
153 return VifPort(name, ofport, external_ids["iface-id"],
154 external_ids["attached-mac"], self)
155
133 # returns a VIF object for each VIF port156 # returns a VIF object for each VIF port
134 def get_vif_ports(self):157 def get_vif_ports(self):
135 edge_ports = []158 edge_ports = []
136 port_names = self.get_port_name_list()159 port_names = self.get_port_name_list()
137 for name in port_names:160 for name in port_names:
138 external_ids = self.db_get_map("Interface", name, "external_ids")161 external_ids = self.db_get_map("Interface", name, "external_ids")
139 if "iface-id" in external_ids and "attached-mac" in external_ids:162 if "xs-vm-uuid" in external_ids:
140 ofport = self.db_get_val("Interface", name, "ofport")163 p = xapi_get_port(name)
141 p = VifPort(name, ofport, external_ids["iface-id"],164 if p is not None:
142 external_ids["attached-mac"], self)165 edge_ports.append(p)
143 edge_ports.append(p)166 elif "iface-id" in external_ids and "attached-mac" in external_ids:
144 else:
145 # iface-id might not be set. See if we can figure it out and
146 # set it here.
147 external_ids = self.db_get_map("Interface", name,
148 "external_ids")
149 if "attached-mac" not in external_ids:
150 continue
151 vif_uuid = external_ids.get("xs-vif-uuid", "")
152 if len(vif_uuid) == 0:
153 continue
154 LOG.debug("iface-id not set, got vif-uuid: %s" % vif_uuid)
155 res = os.popen("xe vif-param-get param-name=other-config "
156 "uuid=%s | grep nicira-iface-id | "
157 "awk '{print $2}'"
158 % vif_uuid).readline()
159 res = res.strip()
160 if len(res) == 0:
161 continue
162 external_ids["iface-id"] = res
163 LOG.info("Setting interface \"%s\" iface-id to \"%s\""
164 % (name, res))
165 self.set_db_attribute("Interface", name,
166 "external-ids:iface-id", res)
167 ofport = self.db_get_val("Interface", name, "ofport")167 ofport = self.db_get_val("Interface", name, "ofport")
168 p = VifPort(name, ofport, external_ids["iface-id"],168 p = VifPort(name, ofport, external_ids["iface-id"],
169 external_ids["attached-mac"], self)169 external_ids["attached-mac"], self)
@@ -171,13 +171,15 @@
171 return edge_ports171 return edge_ports
172172
173173
174class OVSNaaSPlugin:174class OVSQuantumAgent:
175
175 def __init__(self, integ_br):176 def __init__(self, integ_br):
176 self.setup_integration_br(integ_br)177 self.setup_integration_br(integ_br)
177178
178 def port_bound(self, port, vlan_id):179 def port_bound(self, port, vlan_id):
179 self.int_br.set_db_attribute("Port", port.port_name, "tag",180 self.int_br.set_db_attribute("Port", port.port_name, "tag",
180 str(vlan_id))181 str(vlan_id))
182 self.int_br.delete_flows(match="in_port=%s" % port.ofport)
181183
182 def port_unbound(self, port, still_exists):184 def port_unbound(self, port, still_exists):
183 if still_exists:185 if still_exists:
@@ -186,13 +188,8 @@
186 def setup_integration_br(self, integ_br):188 def setup_integration_br(self, integ_br):
187 self.int_br = OVSBridge(integ_br)189 self.int_br = OVSBridge(integ_br)
188 self.int_br.remove_all_flows()190 self.int_br.remove_all_flows()
189 # drop all traffic on the 'dead vlan'191 # switch all traffic using L2 learning
190 self.int_br.add_flow(priority=2, match="dl_vlan=4095", actions="drop")
191 # switch all other traffic using L2 learning
192 self.int_br.add_flow(priority=1, actions="normal")192 self.int_br.add_flow(priority=1, actions="normal")
193 # FIXME send broadcast everywhere, regardless of tenant
194 #int_br.add_flow(priority=3, match="dl_dst=ff:ff:ff:ff:ff:ff",
195 # actions="normal")
196193
197 def daemon_loop(self, conn):194 def daemon_loop(self, conn):
198 self.local_vlan_map = {}195 self.local_vlan_map = {}
@@ -201,7 +198,7 @@
201198
202 while True:199 while True:
203 cursor = conn.cursor()200 cursor = conn.cursor()
204 cursor.execute("SELECT * FROM network_bindings")201 cursor.execute("SELECT * FROM ports")
205 rows = cursor.fetchall()202 rows = cursor.fetchall()
206 cursor.close()203 cursor.close()
207 all_bindings = {}204 all_bindings = {}
@@ -226,22 +223,26 @@
226 else:223 else:
227 # no binding, put him on the 'dead vlan'224 # no binding, put him on the 'dead vlan'
228 self.int_br.set_db_attribute("Port", p.port_name, "tag",225 self.int_br.set_db_attribute("Port", p.port_name, "tag",
229 "4095")226 "4095")
227 self.int_br.add_flow(priority=2,
228 match="in_port=%s" % p.ofport, actions="drop")
229
230 old_b = old_local_bindings.get(p.vif_id, None)230 old_b = old_local_bindings.get(p.vif_id, None)
231 new_b = new_local_bindings.get(p.vif_id, None)231 new_b = new_local_bindings.get(p.vif_id, None)
232
232 if old_b != new_b:233 if old_b != new_b:
233 if old_b is not None:234 if old_b is not None:
234 LOG.info("Removing binding to net-id = %s for %s"235 LOG.info("Removing binding to net-id = %s for %s"
235 % (old_b, str(p)))236 % (old_b, str(p)))
236 self.port_unbound(p, True)237 self.port_unbound(p, True)
237 if new_b is not None:238 if new_b is not None:
238 LOG.info("Adding binding to net-id = %s for %s" \
239 % (new_b, str(p)))
240 # If we don't have a binding we have to stick it on239 # If we don't have a binding we have to stick it on
241 # the dead vlan240 # the dead vlan
242 vlan_id = vlan_bindings.get(all_bindings[p.vif_id],241 vlan_id = vlan_bindings.get(all_bindings[p.vif_id],
243 "4095")242 "4095")
244 self.port_bound(p, vlan_id)243 self.port_bound(p, vlan_id)
244 LOG.info("Adding binding to net-id = %s " \
245 "for %s on vlan %s" % (new_b, str(p), vlan_id))
245 for vif_id in old_vif_ports.keys():246 for vif_id in old_vif_ports.keys():
246 if vif_id not in new_vif_ports:247 if vif_id not in new_vif_ports:
247 LOG.info("Port Disappeared: %s" % vif_id)248 LOG.info("Port Disappeared: %s" % vif_id)
@@ -251,8 +252,6 @@
251252
252 old_vif_ports = new_vif_ports253 old_vif_ports = new_vif_ports
253 old_local_bindings = new_local_bindings254 old_local_bindings = new_local_bindings
254 self.int_br.run_cmd(["bash",
255 "/etc/xapi.d/plugins/set_external_ids.sh"])
256 time.sleep(2)255 time.sleep(2)
257256
258if __name__ == "__main__":257if __name__ == "__main__":
@@ -291,7 +290,7 @@
291 LOG.info("Connecting to database \"%s\" on %s" % (db_name, db_host))290 LOG.info("Connecting to database \"%s\" on %s" % (db_name, db_host))
292 conn = MySQLdb.connect(host=db_host, user=db_user,291 conn = MySQLdb.connect(host=db_host, user=db_user,
293 passwd=db_pass, db=db_name)292 passwd=db_pass, db=db_name)
294 plugin = OVSNaaSPlugin(integ_br)293 plugin = OVSQuantumAgent(integ_br)
295 plugin.daemon_loop(conn)294 plugin.daemon_loop(conn)
296 finally:295 finally:
297 if conn:296 if conn:
298297
=== removed file 'quantum/plugins/openvswitch/agent/set_external_ids.sh'
--- quantum/plugins/openvswitch/agent/set_external_ids.sh 2011-06-04 03:59:49 +0000
+++ quantum/plugins/openvswitch/agent/set_external_ids.sh 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
1#!/bin/sh
2VIFLIST=`xe vif-list params=uuid --minimal | sed s/,/" "/g`
3for VIF_UUID in $VIFLIST; do
4DEVICE_NUM=`xe vif-list params=device uuid=$VIF_UUID --minimal`
5 VM_NAME=`xe vif-list params=vm-name-label uuid=$VIF_UUID --minimal`
6 NAME="$VM_NAME-eth$DEVICE_NUM"
7 echo "Vif: $VIF_UUID is '$NAME'"
8 xe vif-param-set uuid=$VIF_UUID other-config:nicira-iface-id="$NAME"
9done
10
11ps auxw | grep -v grep | grep ovs-xapi-sync > /dev/null 2>&1
12if [ $? -eq 0 ]; then
13 killall -HUP ovs-xapi-sync
14fi
15
160
=== renamed file 'quantum/plugins/openvswitch/agent/install.sh' => 'quantum/plugins/openvswitch/agent/xenserver_install.sh'
=== modified file 'quantum/plugins/openvswitch/ovs_db.py'
--- quantum/plugins/openvswitch/ovs_db.py 2011-06-08 10:21:47 +0000
+++ quantum/plugins/openvswitch/ovs_db.py 2011-06-27 23:11:53 +0000
@@ -56,21 +56,3 @@
56 except exc.NoResultFound:56 except exc.NoResultFound:
57 pass57 pass
58 session.flush()58 session.flush()
59
60
61def update_network_binding(netid, ifaceid):
62 session = db.get_session()
63 # Add to or delete from the bindings table
64 if ifaceid == None:
65 try:
66 binding = session.query(ovs_models.NetworkBinding).\
67 filter_by(network_id=netid).\
68 one()
69 session.delete(binding)
70 except exc.NoResultFound:
71 raise Exception("No binding found with network_id = %s" % netid)
72 else:
73 binding = ovs_models.NetworkBinding(netid, ifaceid)
74 session.add(binding)
75
76 session.flush()
7759
=== modified file 'quantum/plugins/openvswitch/ovs_models.py'
--- quantum/plugins/openvswitch/ovs_models.py 2011-06-08 10:21:47 +0000
+++ quantum/plugins/openvswitch/ovs_models.py 2011-06-27 23:11:53 +0000
@@ -26,23 +26,6 @@
26from quantum.db.models import BASE26from quantum.db.models import BASE
2727
2828
29class NetworkBinding(BASE):
30 """Represents a binding of network_id, vif_id"""
31 __tablename__ = 'network_bindings'
32
33 id = Column(Integer, primary_key=True, autoincrement=True)
34 network_id = Column(String(255))
35 vif_id = Column(String(255))
36
37 def __init__(self, network_id, vif_id):
38 self.network_id = network_id
39 self.vif_id = vif_id
40
41 def __repr__(self):
42 return "<NetworkBinding(%s,%s)>" % \
43 (self.network_id, self.vif_id)
44
45
46class VlanBinding(BASE):29class VlanBinding(BASE):
47 """Represents a binding of network_id, vlan_id"""30 """Represents a binding of network_id, vlan_id"""
48 __tablename__ = 'vlan_bindings'31 __tablename__ = 'vlan_bindings'
4932
=== modified file 'quantum/plugins/openvswitch/ovs_quantum_plugin.ini'
--- quantum/plugins/openvswitch/ovs_quantum_plugin.ini 2011-06-04 03:56:32 +0000
+++ quantum/plugins/openvswitch/ovs_quantum_plugin.ini 2011-06-27 23:11:53 +0000
@@ -1,9 +1,9 @@
1[DATABASE]1[DATABASE]
2name = ovs_naas2name = ovs_quantum
3user = root3user = root
4pass = foobar4pass = nova
5host = 127.0.0.15host = 127.0.0.1
6port = 33066port = 3306
77
8[OVS]8[OVS]
9integration-bridge = xapi19integration-bridge = br100
1010
=== modified file 'quantum/plugins/openvswitch/ovs_quantum_plugin.py'
--- quantum/plugins/openvswitch/ovs_quantum_plugin.py 2011-06-08 10:21:47 +0000
+++ quantum/plugins/openvswitch/ovs_quantum_plugin.py 2011-06-27 23:11:53 +0000
@@ -200,11 +200,9 @@
200200
201 def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):201 def plug_interface(self, tenant_id, net_id, port_id, remote_iface_id):
202 db.port_set_attachment(port_id, remote_iface_id)202 db.port_set_attachment(port_id, remote_iface_id)
203 ovs_db.update_network_binding(net_id, remote_iface_id)
204203
205 def unplug_interface(self, tenant_id, net_id, port_id):204 def unplug_interface(self, tenant_id, net_id, port_id):
206 db.port_set_attachment(port_id, "")205 db.port_set_attachment(port_id, "")
207 ovs_db.update_network_binding(net_id, None)
208206
209 def get_interface_details(self, tenant_id, net_id, port_id):207 def get_interface_details(self, tenant_id, net_id, port_id):
210 res = db.port_get(port_id)208 res = db.port_get(port_id)
211209
=== added file 'tools/batch_config.py'
--- tools/batch_config.py 1970-01-01 00:00:00 +0000
+++ tools/batch_config.py 2011-06-27 23:11:53 +0000
@@ -0,0 +1,174 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2011 Nicira Networks, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16# @author: Dan Wendlandt, Nicira Networks, Inc.
17
18import httplib
19import logging as LOG
20import json
21import socket
22import sys
23import urllib
24
25from quantum.manager import QuantumManager
26from optparse import OptionParser
27from quantum.common.wsgi import Serializer
28from quantum.cli import MiniClient
29
30FORMAT = "json"
31CONTENT_TYPE = "application/" + FORMAT
32
33
34def delete_all_nets(client, tenant_id):
35 res = client.do_request(tenant_id, 'GET', "/networks." + FORMAT)
36 resdict = json.loads(res.read())
37 LOG.debug(resdict)
38 for n in resdict["networks"]:
39 nid = n["id"]
40
41 res = client.do_request(tenant_id, 'GET',
42 "/networks/%s/ports.%s" % (nid, FORMAT))
43 output = res.read()
44 if res.status != 200:
45 LOG.error("Failed to list ports: %s" % output)
46 continue
47 rd = json.loads(output)
48 LOG.debug(rd)
49 for port in rd["ports"]:
50 pid = port["id"]
51
52 data = {'port': {'attachment-id': ''}}
53 body = Serializer().serialize(data, CONTENT_TYPE)
54 res = client.do_request(tenant_id, 'DELETE',
55 "/networks/%s/ports/%s/attachment.%s" % \
56 (nid, pid, FORMAT), body=body)
57 output = res.read()
58 LOG.debug(output)
59 if res.status != 202:
60 LOG.error("Failed to unplug iface from port \"%s\": %s" % (vid,
61 pid, output))
62 continue
63 LOG.info("Unplugged interface from port:%s on network:%s" % (pid,
64 nid))
65
66 res = client.do_request(tenant_id, 'DELETE',
67 "/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
68 output = res.read()
69 if res.status != 202:
70 LOG.error("Failed to delete port: %s" % output)
71 continue
72 print "Deleted Virtual Port:%s " \
73 "on Virtual Network:%s" % (pid, nid)
74
75 res = client.do_request(tenant_id, 'DELETE',
76 "/networks/" + nid + "." + FORMAT)
77 status = res.status
78 if status != 202:
79 Log.error("Failed to delete network: %s" % nid)
80 output = res.read()
81 print output
82 else:
83 print "Deleted Virtual Network with ID:%s" % nid
84
85
86def create_net_with_attachments(net_name, iface_ids):
87 data = {'network': {'network-name': '%s' % net_name}}
88 body = Serializer().serialize(data, CONTENT_TYPE)
89 res = client.do_request(tenant_id, 'POST',
90 "/networks." + FORMAT, body=body)
91 rd = json.loads(res.read())
92 LOG.debug(rd)
93 nid = rd["networks"]["network"]["id"]
94 print "Created a new Virtual Network %s with ID:%s" % (net_name, nid)
95
96 for iface_id in iface_ids:
97 res = client.do_request(tenant_id, 'POST',
98 "/networks/%s/ports.%s" % (nid, FORMAT))
99 output = res.read()
100 if res.status != 200:
101 LOG.error("Failed to create port: %s" % output)
102 continue
103 rd = json.loads(output)
104 new_port_id = rd["ports"]["port"]["id"]
105 print "Created Virtual Port:%s " \
106 "on Virtual Network:%s" % (new_port_id, nid)
107 data = {'port': {'attachment-id': '%s' % iface_id}}
108 body = Serializer().serialize(data, CONTENT_TYPE)
109 res = client.do_request(tenant_id, 'PUT',
110 "/networks/%s/ports/%s/attachment.%s" %\
111 (nid, new_port_id, FORMAT), body=body)
112 output = res.read()
113 LOG.debug(output)
114 if res.status != 202:
115 LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % \
116 (iface_id, new_port_id, output))
117 continue
118 print "Plugged interface \"%s\" to port:%s on network:%s" % \
119 (iface_id, new_port_id, nid)
120
121if __name__ == "__main__":
122 usagestr = "Usage: %prog [OPTIONS] <tenant-id> <config-string> [args]\n" \
123 "Example config-string: net1=instance-1,instance-2"\
124 ":net2=instance-3,instance-4\n" \
125 "This string would create two networks: \n" \
126 "'net1' would have two ports, with iface-ids "\
127 "instance-1 and instance-2 attached\n" \
128 "'net2' would have two ports, with iface-ids"\
129 " instance-3 and instance-4 attached\n"
130 parser = OptionParser(usage=usagestr)
131 parser.add_option("-H", "--host", dest="host",
132 type="string", default="127.0.0.1", help="ip address of api host")
133 parser.add_option("-p", "--port", dest="port",
134 type="int", default=9696, help="api poort")
135 parser.add_option("-s", "--ssl", dest="ssl",
136 action="store_true", default=False, help="use ssl")
137 parser.add_option("-v", "--verbose", dest="verbose",
138 action="store_true", default=False, help="turn on verbose logging")
139 parser.add_option("-d", "--delete", dest="delete",
140 action="store_true", default=False, \
141 help="delete existing tenants networks")
142
143 options, args = parser.parse_args()
144
145 if options.verbose:
146 LOG.basicConfig(level=LOG.DEBUG)
147 else:
148 LOG.basicConfig(level=LOG.WARN)
149
150 if len(args) < 1:
151 parser.print_help()
152 help()
153 sys.exit(1)
154
155 nets = {}
156 tenant_id = args[0]
157 if len(args) > 1:
158 config_str = args[1]
159 for net_str in config_str.split(":"):
160 arr = net_str.split("=")
161 net_name = arr[0]
162 nets[net_name] = arr[1].split(",")
163
164 print "nets: %s" % str(nets)
165
166 client = MiniClient(options.host, options.port, options.ssl)
167
168 if options.delete:
169 delete_all_nets(client, tenant_id)
170
171 for net_name, iface_ids in nets.items():
172 create_net_with_attachments(net_name, iface_ids)
173
174 sys.exit(0)

Subscribers

People subscribed via source and target branches