]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Bug fixes and clean-up, including supporting libvirt
authorDan Wendlandt <dan@nicira.com>
Tue, 21 Jun 2011 07:14:14 +0000 (00:14 -0700)
committerDan Wendlandt <dan@nicira.com>
Tue, 21 Jun 2011 07:14:14 +0000 (00:14 -0700)
quantum/cli.py
quantum/db/api.py
quantum/plugins/openvswitch/README
quantum/plugins/openvswitch/agent/ovs_quantum_agent.py
quantum/plugins/openvswitch/agent/set_external_ids.sh [deleted file]
quantum/plugins/openvswitch/agent/xenserver_install.sh [moved from quantum/plugins/openvswitch/agent/install.sh with 100% similarity]
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
tools/batch_config.py [new file with mode: 0644]

index 4c0ba4eee5696650cc09f06de587a019035e596a..a0121b0341a5d2153152ebe3ec2c05318ad5af35 100644 (file)
@@ -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))
 
index 8a6ba305ccbd77f3382447ac10f3c30a4ecb04cc..1809af05768e198deea9a81a06d53e18ebd55e57 100644 (file)
@@ -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)
index 689624f1b98ffefb8c60449a124b260fa6e76eba..a6351ddf6848721e6221b5aca6e1850bacbd3a78 100644 (file)
@@ -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]:
index 34f28fbdd5c7dd36daeaa9306ae7cf4ff14cc49c..cb21d7a6b4110494fef7dc94c95e5fee92bcac1c 100755 (executable)
@@ -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 (executable)
index 2fae05f..0000000
+++ /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
-
index a2a72ec8ceb0644881be19b5ada823c5faefb712..a5785c7df15877dba593f65c8998213b89c8fec2 100644 (file)
@@ -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()
index 610902a7caa9ccda880c8360c546f6ddcfeed8ae..9ce83611df0b65395c6c75f0eb866afa615f9410 100644 (file)
@@ -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 "<NetworkBinding(%s,%s)>" % \
-          (self.network_id, self.vif_id)
-
 class VlanBinding(BASE):
     """Represents a binding of network_id, vlan_id"""
     __tablename__ = 'vlan_bindings'
index 0c75b3fc48a3f59a4a99ec966a021ab799d996a5..66095d85d1bc8ef8277a4fc28c587654c3607d39 100644 (file)
@@ -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
index 75619cae6276f74cd933dc3d830a8329102c5fba..375a4bd87aa79f82f4e6f56f7ceb97acb9ba17b1 100644 (file)
@@ -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 (file)
index 0000000..e6be088
--- /dev/null
@@ -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] <tenant-id> <config-string> [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)