]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
add extension change to ying's branch
authorYing Liu <yinliu2@cisco.com>
Wed, 17 Aug 2011 19:26:32 +0000 (12:26 -0700)
committerYing Liu <yinliu2@cisco.com>
Wed, 17 Aug 2011 19:26:32 +0000 (12:26 -0700)
21 files changed:
cisco_demo/demo_client.py [new file with mode: 0755]
cisco_demo/demo_client.py.bk [new file with mode: 0755]
cisco_demo/test_client.py [new file with mode: 0644]
extensions/_credential_view.py [new file with mode: 0644]
extensions/_exceptions.py [new file with mode: 0644]
extensions/_faults.py [new file with mode: 0644]
extensions/_novatenant_view.py [new file with mode: 0644]
extensions/_pprofiles.py [new file with mode: 0644]
extensions/_qos_view.py [new file with mode: 0644]
extensions/credential.py [new file with mode: 0644]
extensions/novatenant.py [new file with mode: 0644]
extensions/portprofile.py [new file with mode: 0644]
extensions/qos.py [new file with mode: 0644]
quantum/plugins.ini
quantum/plugins/cisco/CiscoPlugin.py [new file with mode: 0644]
quantum/plugins/cisco/conf/db_conn.ini
quantum/plugins/cisco/conf/l2network_plugin.ini
quantum/plugins/cisco/conf/plugins.ini
test_scripts/__init__.py [new file with mode: 0644]
test_scripts/miniclient.py [new file with mode: 0644]
test_scripts/tests.py [new file with mode: 0644]

diff --git a/cisco_demo/demo_client.py b/cisco_demo/demo_client.py
new file mode 100755 (executable)
index 0000000..74b4a6a
--- /dev/null
@@ -0,0 +1,385 @@
+
+import os
+import sys
+
+import gettext
+
+#gettext.install('quantum', unicode=1)
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+                                   os.pardir,
+                                   os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'quantum', '__init__.py')):
+    sys.path.insert(0, possible_topdir)
+
+gettext.install('quantum', unicode=1)
+
+from test_scripts.miniclient import MiniClient
+from test_client import ExtClient
+from quantum.common.wsgi import Serializer
+
+HOST = '127.0.0.1'
+PORT = 9696
+USE_SSL = False
+TENANT_ID = 'ucs_user'
+
+
+test_network_data = \
+    {'network': {'net-name': 'cisco_test_network',
+                 'valn-id': 28}}
+test_portprofile_data = \
+    {'portprofile': {'portprofile_name': 'cisco_test_portprofile',
+                 'qos_name': 2,
+                 'qos_name': 'test-qos'}}
+test_cred_data = \
+    {'credential': {'credential_name': 'cred3',
+                    'user_name': 'newUser',
+                    'password': 'newPasswd'
+                    }}
+test_qos_data = \
+    {'qos': {'qos_name': 'plantimum',
+                    'qos_desc': {'PPS': 50, 'TTL': 5}}}
+
+
+#we put this assignment under portprofile resources
+#therefore we need to create such a test data
+test_port_assign_data = {'portprofile': {'network-id': '001',
+                                         'port-id': '1'}}
+test_attach_data = {'port': {'attachment-id': 'v01'}}
+
+test_act_data = {"get_available_host":123}
+
+test_instance_data={'novatenant':{'instance_id' : 1, 
+                    'instance_desc' : {'key1' : '1',
+                                       'key2' : '2'
+                                       }}}
+
+def test_get_host(format='json'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    body = Serializer().serialize(test_instance_data, content_type)
+    res = client.do_request(TENANT_ID, 
+                            'PUT', "/novatenants/001/get_host." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"    
+    
+def test_get_instance_port(format='json'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    body = Serializer().serialize(test_instance_data, content_type)
+    res = client.do_request(TENANT_ID, 
+                            'PUT', "/novatenants/001/get_instance_port." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_action_ext(format='json'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    action_name = 'get_available_host'
+    action_params = dict(name='test')
+    body = Serializer().serialize(test_act_data, content_type)
+  
+    res = client.do_request(TENANT_ID, 'POST', "/act_resources/1/action." + format, body=body)
+    content = print_response(res)
+
+def print_response(res):
+    content = res.read()
+    print "Status: %s" % res.status
+    print "Content: %s" % content
+    return content
+
+
+def create_cisco_network(format='xml'):
+    
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "CREATE NETWORK -- FORMAT:%s" % format 
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_network_data, content_type)
+    res = client.do_request(TENANT_ID, 
+                            'POST', "/networks." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+def create_cisco_portprofile(format='xml'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "List all Profile -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format)
+    content = print_response(res)
+    portprofile_data = Serializer().deserialize(content, content_type)
+    print portprofile_data
+  
+    print "List a specific Profile -- FORMAT:%s" % format
+    profile_id = portprofile_data['portprofiles'][0]['id']
+    #profile_id='001'
+    print "profile_id " + profile_id
+    res = client.do_request(TENANT_ID, 
+                            'GET', "/portprofiles/" 
+                            + profile_id + "." + format)
+    print_response(res)
+    
+    print "CREATE Profile -- FORMAT:%s" % format
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_portprofile_data, content_type)
+    print "***BODY is "
+    print body
+    res = client.do_request(TENANT_ID, 'POST', 
+                            "/portprofiles." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_credential (format='xml'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "----------------------------"
+    print "List all credentials -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/credentials." + format)
+    content = print_response(res)
+    credential_data = Serializer().deserialize(content, content_type)
+    print credential_data
+    
+    print "----------------------------"
+    print "CREATE Credential -- FORMAT:%s" % format
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_cred_data, content_type)
+    print "***BODY is "
+    print body
+    res = client.do_request(TENANT_ID, 'POST', 
+                            "/credentials." + format, body=body)
+    print "XML Response"
+    print_response(res)
+  
+    print "----------------------------"
+    print "List all credentials -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/credentials." + format)
+    content = print_response(res)
+    credential_data = Serializer().deserialize(content, content_type)
+    print credential_data
+    print "----------------------------"
+    print "List a specific cred -- FORMAT:%s" % format
+    print "----------------------------"
+    cred_id = credential_data['credentials'][0]['id']
+    #cred_id='001'
+    print "cred_id " + cred_id
+    res = client.do_request(TENANT_ID, 
+                            'GET', "/credentials/" 
+                            + cred_id + "." + format)
+    print_response(res)
+    
+    print "----------------------------"
+    print "TEST DELETE Credential -- FORMAT:%s" % format 
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'DELETE',
+                            "/credentials/" + cred_id + "." + format)
+    print_response(res)
+    
+    print "----------------------------"
+    print "List all credentials -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/credentials." + format)
+    content = print_response(res)
+    credential_data = Serializer().deserialize(content, content_type)
+    print credential_data
+    
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_qos (format='xml'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "----------------------------"
+    print "List all qoss -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/qoss." + format)
+    content = print_response(res)
+    qos_data = Serializer().deserialize(content, content_type)
+    print qos_data
+    
+    print "----------------------------"
+    print "CREATE qos -- FORMAT:%s" % format
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_qos_data, content_type)
+    print "***BODY is "
+    print body
+    res = client.do_request(TENANT_ID, 'POST', 
+                            "/qoss." + format, body=body)
+    print "XML Response"
+    print_response(res)
+  
+    print "----------------------------"
+    print "List all qoss -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/qoss." + format)
+    content = print_response(res)
+    qos_data = Serializer().deserialize(content, content_type)
+    print qos_data
+    print "----------------------------"
+    print "List a specific cred -- FORMAT:%s" % format
+    print "----------------------------"
+    qos_id = qos_data['qoss'][0]['id']
+    #cred_id='001'
+    print "qos_id " + qos_id
+    res = client.do_request(TENANT_ID, 
+                            'GET', "/qoss/" 
+                            + qos_id + "." + format)
+    print_response(res)
+    
+    print "----------------------------"
+    print "TEST DELETE qos -- FORMAT:%s" % format 
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'DELETE',
+                            "/qoss/" + qos_id + "." + format)
+    print_response(res)
+    
+    print "----------------------------"
+    print "List all qoss -- FORMat%s" % format
+    print "----------------------------"
+    res = client.do_request(TENANT_ID, 'GET', "/qoss." + format)
+    content = print_response(res)
+    qos_data = Serializer().deserialize(content, content_type)
+    print qos_data
+    
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_delete_network(format='xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "TEST DELETE NETWORK -- FORMAT:%s" % format 
+    print "----------------------------"
+    print "--> Step 1 - List All Networks"
+    res = client.do_request(TENANT_ID, 'GET', "/networks." + format)
+    content = print_response(res)
+    network_data = Serializer().deserialize(content, content_type)
+    print network_data
+    net_id = network_data['networks'][0]['id']
+    print "--> Step 2 - Delete network %s" % net_id    
+    res = client.do_request(TENANT_ID, 'DELETE',
+                            "/networks/" + net_id + "." + format)
+    print_response(res)
+    print "--> Step 3 - List All Networks (Again)"
+    res = client.do_request(TENANT_ID, 'GET', "/networks." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+def test_delete_portprofile(format='xml'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "TEST DELETE PROFILE -- FORMAT:%s" % format 
+    print "----------------------------"
+    print "--> Step 1 - List All Profiles"
+    res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format)
+    content = print_response(res)
+    portprofile_data = Serializer().deserialize(content, content_type)
+    print portprofile_data
+    profile_id = portprofile_data['portprofiles'][0]['id']
+    print "--> Step 2 - Delete portprofile %s" % profile_id    
+    res = client.do_request(TENANT_ID, 'DELETE',
+                            "/portprofiles/" + profile_id + "." + format)
+    print_response(res)
+    print "--> Step 3 - List All Profiles (Again)"
+    res = client.do_request(TENANT_ID, 'GET', "/portprofiles." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+    
+def test_create_port(format='xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "TEST CREATE PORT -- FORMAT:%s" % format 
+    print "----------------------------"
+    print "--> Step 1 - List Ports for network 001"
+    res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format)
+    print_response(res)
+    print "--> Step 2 - Create Port for network 001"
+    res = client.do_request(TENANT_ID, 'POST', "/networks/001/ports." + format)
+    print_response(res)
+    print "--> Step 3 - List Ports for network 001 (again)"
+    res = client.do_request(TENANT_ID, 'GET', "/networks/001/ports." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+#assuming network 001 and ports 1 are created in the plug-in    
+def test_attach_resource(format='xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "TEST attach resources to port"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_attach_data, content_type)
+    #attach virtual interface to the port
+    res = client.do_request(TENANT_ID, 'PUT', 
+                            "/networks/001/ports/1/attachment." 
+                            + format, body=body)
+    print_response(res)
+    #list existing interface of the port
+    res = client.do_request(TENANT_ID, 'GET', 
+                            "/networks/001/ports/1/attachment." + format)
+    print_response(res)
+    #de_attach virtual interface from the port
+    res = client.do_request(TENANT_ID, 'DELETE', 
+                            "/networks/001/ports/1/attachment." + format)
+    print_response(res)
+    #list existing interface of the port
+    res = client.do_request(TENANT_ID, 'GET', 
+                            "/networks/001/ports/1/attachment." + format)
+    print_response(res)
+
+
+#assuming network 001, ports 1 and portprofile 002 are created in the plug-in 
+def test_assign_portprofile(format='xml'):
+    client = ExtClient(HOST, PORT, USE_SSL)
+    print "TEST attach resources to port"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_port_assign_data, content_type)
+    print "body is " + body
+    res = client.do_request(TENANT_ID, 'PUT', 
+                            "/portprofiles/001/associate_portprofile." 
+                            + format, body=body)
+    print_response(res)
+    res = client.do_request(TENANT_ID, 'POST', 
+                            "/portprofiles/001/disassociate_portprofile." 
+                            + format, body=body)
+   
+    print_response(res)
+    
+    
+def main():
+    create_cisco_portprofile('json') 
+    test_attach_resource('json') 
+   
+    test_delete_portprofile('json') 
+    test_credential('json')
+    test_qos('json')
+    ##test_action_ext('json')
+    test_get_host('json')
+    test_get_instance_port('json')
+    
+    #create_cisco_network('json')
+    #test_create_port('json')
+    #create_cisco_portprofile('json')
+    #test_assign_portprofile('json')
+    pass
+    
+
+# Standard boilerplate to call the main() function.
+if __name__ == '__main__':
+    main()
diff --git a/cisco_demo/demo_client.py.bk b/cisco_demo/demo_client.py.bk
new file mode 100755 (executable)
index 0000000..3c7c928
--- /dev/null
@@ -0,0 +1,127 @@
+'''
+Created on Jun 08, 2011
+
+@author: ying
+'''
+
+import os
+import sys
+
+import gettext
+
+#gettext.install('quantum', unicode=1)
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+                                   os.pardir,
+                                   os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'quantum', '__init__.py')):
+    sys.path.insert(0, possible_topdir)
+
+gettext.install('quantum', unicode=1)
+
+from test_scripts.miniclient import MiniClient
+from quantum.common.wsgi import Serializer
+
+HOST = '127.0.0.1'
+PORT = 9696
+USE_SSL = False
+TENANT_ID = 'ucs_user'
+
+test_network_data = \
+    {'network': {'network-name': 'cisco_test_network',
+                 'valn-id': 28 }}
+    
+test_portprofile_data = \
+    {'portprofile': {'portprofile-name': 'cisco_test_portprofile',
+                 'vlan-id': 28,
+                 'vlan-name': 'test-vlan' }}
+
+def print_response(res):
+    content = res.read()
+    print "Status: %s" %res.status
+    print "Content: %s" %content
+    return content
+
+    
+def create_cisco_network(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "CREATE NETWORK -- FORMAT:%s" %format 
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_network_data, content_type)
+    res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def create_cisco_portprofile(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "CREATE Profile -- FORMAT:%s" %format
+    print "----------------------------"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_portprofile_data, content_type)
+    print "**********BODY is**********"
+    print body
+    print "***************************"
+    res = client.do_request(TENANT_ID,'POST', "/portprofiles." + format, body=body)
+    print "XML Response"
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_delete_network(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "TEST DELETE NETWORK -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - List All Networks"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    content = print_response(res)
+    network_data = Serializer().deserialize(content, content_type)
+    print network_data
+    net_id = network_data['networks'][0]['id']
+    print "--> Step 2 - Delete network %s" %net_id    
+    res = client.do_request(TENANT_ID,'DELETE',
+                            "/networks/" + net_id + "." + format)
+    print_response(res)
+    print "--> Step 3 - List All Networks (Again)"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+def test_delete_portprofile(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "TEST DELETE PROFILE -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - List All Profiles"
+    res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format)
+    content = print_response(res)
+    portprofile_data = Serializer().deserialize(content, content_type)
+    print portprofile_data
+    profile_id = portprofile_data['portprofiles'][0]['id']
+    print "--> Step 2 - Delete portprofile %s" %profile_id    
+    res = client.do_request(TENANT_ID,'DELETE',
+                            "/portprofiles/" + profile_id + "." + format)
+    print_response(res)
+    print "--> Step 3 - List All Profiles (Again)"
+    res = client.do_request(TENANT_ID,'GET', "/portprofiles." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def main():
+   
+    create_cisco_network('xml')
+  
+    create_cisco_portprofile('xml')    
+    #test_delete_network('json')
+    test_delete_portprofile('json') 
+    pass
+    
+
+# Standard boilerplate to call the main() function.
+if __name__ == '__main__':
+    main()
diff --git a/cisco_demo/test_client.py b/cisco_demo/test_client.py
new file mode 100644 (file)
index 0000000..4273e7d
--- /dev/null
@@ -0,0 +1,83 @@
+"""A base client class - derived from Quantum.MiniClient"""
+
+import httplib
+import socket
+import urllib
+
+
+class ExtClient(object):
+
+    action_prefix = '/v0.1/extensions/csco/tenants/{tenant_id}'
+    #action_prefix = '/v0.1/tenants/{tenant_id}'
+    def __init__(self, host, port, use_ssl):
+        """
+        Creates a new client to some service.
+
+        :param host: The host where service resides
+        :param port: The port where service resides
+        :param use_ssl: Should we use HTTPS?
+        """
+        self.host = host
+        self.port = port
+        self.use_ssl = use_ssl
+        self.connection = None
+
+    def get_connection_type(self):
+        """
+        Returns the proper connection type
+        """
+        if self.use_ssl:
+            return httplib.HTTPSConnection
+        else:
+            return httplib.HTTPConnection
+
+    def do_request(self, tenant, method, action, body=None,
+                   headers=None, params=None):
+        """
+        Connects to the server and issues a request.  
+        Returns the result data, or raises an appropriate exception if
+        HTTP status code is not 2xx
+
+        :param method: HTTP method ("GET", "POST", "PUT", etc...)
+        :param body: string of data to send, or None (default)
+        :param headers: mapping of key/value pairs to add as headers
+        :param params: dictionary of key/value pairs to add to append
+                             to action
+
+        """
+        action = ExtClient.action_prefix + action
+        action = action.replace('{tenant_id}', tenant)
+        if type(params) is dict:
+            action += '?' + urllib.urlencode(params)
+
+        try:
+            connection_type = self.get_connection_type()
+            headers = headers or {}
+            
+            # Open connection and send request
+            c = connection_type(self.host, self.port)
+            c.request(method, action, body, headers)
+            res = c.getresponse()
+            status_code = self.get_status_code(res)
+            if status_code in (httplib.OK,
+                               httplib.CREATED,
+                               httplib.ACCEPTED,
+                               httplib.NO_CONTENT):
+                return res
+            else:
+                raise Exception("Server returned error: %s" % res.read())
+
+        except (socket.error, IOError), e:
+            raise Exception("Unable to connect to "
+                            "server. Got error: %s" % e)
+
+    def get_status_code(self, response):
+        """
+        Returns the integer status code from the response, which
+        can be either a Webob.Response (used in testing) or httplib.Response
+        """
+        if hasattr(response, 'status_int'):
+            return response.status_int
+        else:
+            return response.status
+        
diff --git a/extensions/_credential_view.py b/extensions/_credential_view.py
new file mode 100644 (file)
index 0000000..e324d3f
--- /dev/null
@@ -0,0 +1,35 @@
+def get_view_builder(req):
+    base_url = req.application_url
+    return ViewBuilder(base_url)
+
+
+class ViewBuilder(object):
+    """
+    ViewBuilder for Credential, 
+    derived from quantum.views.networks
+    """
+    def __init__(self, base_url):
+        """
+        :param base_url: url of the root wsgi application
+        """
+        self.base_url = base_url
+
+    def build(self, credential_data, is_detail=False):
+        """Generic method used to generate a credential entity."""
+        print "credential-DATA:%s" % credential_data
+        if is_detail:
+            credential = self._build_detail(credential_data)
+        else:
+            credential = self._build_simple(credential_data)
+        return credential
+    
+    def _build_simple(self, credential_data):
+        """Return a simple model of a server."""
+        return dict(credential=dict(id=credential_data['credential_id']))
+    
+    def _build_detail(self, credential_data):
+        """Return a simple model of a server."""
+        
+        return dict(credential=dict(id=credential_data['credential_id'],
+                                name=credential_data['user_name'],
+                                password=credential_data['password']))
\ No newline at end of file
diff --git a/extensions/_exceptions.py b/extensions/_exceptions.py
new file mode 100644 (file)
index 0000000..5ae8850
--- /dev/null
@@ -0,0 +1,160 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2011 Cisco Systems, Inc.  All rights reserved.
+#
+#    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: Ying Liu, Cisco Systems, Inc.
+#
+import logging
+
+
+class ExtensionException(Exception):
+    """Quantum Cisco api Exception
+    
+    Taken from nova.exception.NovaException
+    To correctly use this class, inherit from it and define
+    a 'message' property. That message will get printf'd
+    with the keyword arguments provided to the constructor.
+
+    """
+    message = _("An unknown exception occurred.")
+
+    def __init__(self, **kwargs):
+        try:
+            self._error_string = self.message % kwargs
+
+        except Exception:
+            # at least get the core message out if something happened
+            self._error_string = self.message
+
+    def __str__(self):
+        return self._error_string
+
+
+class ProcessExecutionError(IOError):
+    def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
+                 description=None):
+        if description is None:
+            description = "Unexpected error while running command."
+        if exit_code is None:
+            exit_code = '-'
+        message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % (
+                  description, cmd, exit_code, stdout, stderr)
+        IOError.__init__(self, message)
+
+
+class Error(Exception):
+    def __init__(self, message=None):
+        super(Error, self).__init__(message)
+
+
+class ApiError(Error):
+    def __init__(self, message='Unknown', code='Unknown'):
+        self.message = message
+        self.code = code
+        super(ApiError, self).__init__('%s: %s' % (code, message))
+
+
+class NotFound(ExtensionException):
+    pass
+
+
+class ClassNotFound(NotFound):
+    message = _("Class %(class_name)s could not be found")
+
+
+class PortprofileNotFound(NotFound):
+    message = _("Portprofile %(_id)s could not be found")
+    
+    
+class NovatenantNotFound(NotFound):
+    message = _("Novatenant %(_id)s could not be found")
+
+
+class PortNotFound(NotFound):
+    message = _("Port %(port_id)s could not be found " \
+                "on Network %(net_id)s")
+    
+    
+class CredentialNotFound(NotFound):
+    message = _("Credential %(_id)s could not be found")
+    
+    
+class QosNotFound(NotFound):
+    message = _("QoS %(_id)s could not be found")
+    
+
+"""
+    
+
+class PortprofileInUse(ExtensionException):
+    message = _("Unable to complete operation on Portprofile %(net_id)s. " \
+                "There is one or more attachments plugged into its ports.")
+
+
+class PortInUse(ExtensionException):
+    message = _("Unable to complete operation on port %(port_id)s " \
+                "for Portprofile %(net_id)s. The attachment '%(att_id)s" \
+                "is plugged into the logical port.")
+
+class AlreadyAttached(ExtensionException):
+    message = _("Unable to plug the attachment %(att_id)s into port " \
+                "%(port_id)s for Portprofile %(net_id)s. The attachment is " \
+                "already plugged into port %(att_port_id)s")
+    
+"""
+
+
+class Duplicate(Error):
+    pass
+
+
+class NotAuthorized(Error):
+    pass
+
+
+class NotEmpty(Error):
+    pass
+
+
+class Invalid(Error):
+    pass
+
+
+class InvalidContentType(Invalid):
+    message = _("Invalid content type %(content_type)s.")
+
+
+class BadInputError(Exception):
+    """Error resulting from a client sending bad input to a server"""
+    pass
+
+
+class MissingArgumentError(Error):
+    pass
+
+
+def wrap_exception(f):
+    def _wrap(*args, **kw):
+        try:
+            return f(*args, **kw)
+        except Exception, e:
+            if not isinstance(e, Error):
+                #exc_type, exc_value, exc_traceback = sys.exc_info()
+                logging.exception('Uncaught exception')
+                #logging.error(traceback.extract_stack(exc_traceback))
+                raise Error(str(e))
+            raise
+    _wrap.func_name = f.func_name
+    return _wrap
diff --git a/extensions/_faults.py b/extensions/_faults.py
new file mode 100644 (file)
index 0000000..95ee9ae
--- /dev/null
@@ -0,0 +1,157 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2011 Cisco Systems, Inc.  All rights reserved.
+#
+#    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: Ying Liu, Cisco Systems, Inc.
+#
+import webob.dec
+import webob.exc
+
+from quantum.api import api_common as common
+from quantum.common import wsgi
+
+
+class Fault(webob.exc.HTTPException):
+    """Error codes for API faults"""
+
+    _fault_names = {
+            400: "malformedRequest",
+            401: "unauthorized",
+            420: "networkNotFound",
+            421: "PortprofileInUse",
+            430: "portNotFound",
+            431: "requestedStateInvalid",
+            432: "portInUse",
+            440: "alreadyAttached",
+            450: "PortprofileNotFound",
+            451: "CredentialNotFound",
+            452: "QoSNotFound",
+            453: "NovatenantNotFound",
+            470: "serviceUnavailable",
+            471: "pluginFault"}
+
+    def __init__(self, exception):
+        """Create a Fault for the given webob.exc.exception."""
+        self.wrapped_exc = exception
+
+    @webob.dec.wsgify(RequestClass=wsgi.Request)
+    def __call__(self, req):
+        """Generate a WSGI response based on the exception passed to ctor."""
+        #print ("*********TEST2")
+        # Replace the body with fault details.
+        code = self.wrapped_exc.status_int
+        fault_name = self._fault_names.get(code, "quantumServiceFault")
+        fault_data = {
+            fault_name: {
+                'code': code,
+                'message': self.wrapped_exc.explanation, 
+                'detail': self.wrapped_exc.detail}}
+        # 'code' is an attribute on the fault tag itself
+        metadata = {'application/xml': {'attributes': {fault_name: 'code'}}}
+        default_xmlns = common.XML_NS_V10
+        serializer = wsgi.Serializer(metadata, default_xmlns)
+        content_type = req.best_match_content_type()
+        self.wrapped_exc.body = serializer.serialize(fault_data, content_type)
+        self.wrapped_exc.content_type = content_type
+        return self.wrapped_exc
+
+
+class PortprofileNotFound(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server did not find the Portprofile specified
+    in the HTTP request
+
+    code: 450, title: Portprofile not Found
+    """
+    #print ("*********TEST1")
+    code = 450
+    title = 'Portprofile Not Found'
+    explanation = ('Unable to find a Portprofile with' 
+                   + ' the specified identifier.')
+
+
+class PortNotFound(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server did not find the port specified
+    in the HTTP request for a given network
+
+    code: 430, title: Port not Found
+    """
+    code = 430
+    title = 'Port not Found'
+    explanation = ('Unable to find a port with the specified identifier.')
+    
+    
+class CredentialNotFound(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server did not find the Credential specified
+    in the HTTP request
+
+    code: 460, title: Credential not Found
+    """
+    code = 451
+    title = 'Credential Not Found'
+    explanation = ('Unable to find a Credential with' 
+                   + ' the specified identifier.')
+  
+    
+class QosNotFound(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server did not find the QoS specified
+    in the HTTP request
+
+    code: 480, title: QoS not Found
+    """
+    code = 452
+    title = 'QoS Not Found'
+    explanation = ('Unable to find a QoS with' 
+                   + ' the specified identifier.')
+  
+    
+class NovatenantNotFound(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server did not find the Novatenant specified
+    in the HTTP request
+
+    code: 480, title: Nova tenant not Found
+    """
+    code = 453
+    title = 'Nova tenant Not Found'
+    explanation = ('Unable to find a Novatenant with' 
+                   + ' the specified identifier.')
+
+
+class RequestedStateInvalid(webob.exc.HTTPClientError):
+    """
+    subclass of :class:`~HTTPClientError`
+
+    This indicates that the server could not update the port state to
+    to the request value
+
+    code: 431, title: Requested State Invalid
+    """
+    code = 431
+    title = 'Requested State Invalid'
+    explanation = ('Unable to update port state with specified value.')
diff --git a/extensions/_novatenant_view.py b/extensions/_novatenant_view.py
new file mode 100644 (file)
index 0000000..3a1b3f8
--- /dev/null
@@ -0,0 +1,28 @@
+
+
+import os
+
+
+def get_view_builder(req):
+    base_url = req.application_url
+    return ViewBuilder(base_url)
+
+
+class ViewBuilder(object):
+    """
+    ViewBuilder for novatenant, 
+    derived from quantum.views.networks
+    """
+    def __init__(self, base_url):
+        """
+        :param base_url: url of the root wsgi application
+        """
+        self.base_url = base_url
+    
+    def build_host(self, host_data):
+        """Return host description."""
+        return dict(host_desc=host_data['host_desc'])
+    
+    def build_vif(self, vif_data):
+        """Return VIF description."""
+        return dict(vif_desc=vif_data['vif_desc'])   
diff --git a/extensions/_pprofiles.py b/extensions/_pprofiles.py
new file mode 100644 (file)
index 0000000..997cb26
--- /dev/null
@@ -0,0 +1,40 @@
+def get_view_builder(req):
+    base_url = req.application_url
+    return ViewBuilder(base_url)
+
+
+class ViewBuilder(object):
+    """
+    ViewBuilder for Portprofile, 
+    derived from quantum.views.networks
+    """
+    def __init__(self, base_url):
+        """
+        :param base_url: url of the root wsgi application
+        """
+        self.base_url = base_url
+
+    def build(self, portprofile_data, is_detail=False):
+        """Generic method used to generate a portprofile entity."""
+        print "portprofile_DATA:%s" % portprofile_data
+        if is_detail:
+            portprofile = self._build_detail(portprofile_data)
+        else:
+            portprofile = self._build_simple(portprofile_data)
+        return portprofile
+    
+    def _build_simple(self, portprofile_data):
+        """Return a simple model of a portprofile"""
+        return dict(portprofile=dict(id=portprofile_data['profile_id']))
+    
+    def _build_detail(self, portprofile_data):
+        """Return a detailed info of a portprofile."""
+        if (portprofile_data['assignment'] == None):
+            return dict(portprofile=dict(id=portprofile_data['profile_id'],
+                                name=portprofile_data['profile_name'],
+                                qos_name=portprofile_data['qos_name']))
+        else:
+            return dict(portprofile=dict(id=portprofile_data['profile_id'],
+                                name=portprofile_data['profile_name'],
+                                qos_name=portprofile_data['qos_name'],
+                                assignment=portprofile_data['assignment']))
diff --git a/extensions/_qos_view.py b/extensions/_qos_view.py
new file mode 100644 (file)
index 0000000..877d82d
--- /dev/null
@@ -0,0 +1,35 @@
+def get_view_builder(req):
+    base_url = req.application_url
+    return ViewBuilder(base_url)
+
+
+class ViewBuilder(object):
+    """
+    ViewBuilder for QoS, 
+    derived from quantum.views.networks
+    """
+    def __init__(self, base_url):
+        """
+        :param base_url: url of the root wsgi application
+        """
+        self.base_url = base_url
+
+    def build(self, qos_data, is_detail=False):
+        """Generic method used to generate a QoS entity."""
+        print "qos_DATA:%s" % qos_data
+        if is_detail:
+            qos = self._build_detail(qos_data)
+        else:
+            qos = self._build_simple(qos_data)
+        return qos
+    
+    def _build_simple(self, qos_data):
+        """Return a simple model of a server."""
+        return dict(qos=dict(id=qos_data['qos_id']))
+    
+    def _build_detail(self, qos_data):
+        """Return a simple model of a server."""
+        
+        return dict(qos=dict(id=qos_data['qos_id'],
+                                name=qos_data['qos_name'],
+                                description=qos_data['qos_desc']))
diff --git a/extensions/credential.py b/extensions/credential.py
new file mode 100644 (file)
index 0000000..46f25b6
--- /dev/null
@@ -0,0 +1,159 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2011 Cisco Systems, Inc.  All rights reserved.
+#
+#    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: Ying Liu, Cisco Systems, Inc.
+#
+
+import logging
+
+from webob import exc
+from extensions import _credential_view as credential_view
+from extensions import _exceptions as exception
+from extensions import _faults as faults
+
+from quantum.api import api_common as common
+from quantum.common import wsgi
+from quantum.common import extensions
+from quantum.manager import QuantumManager
+
+LOG = logging.getLogger('quantum.api.credentials')
+
+
+class Credential(object):
+
+    def __init__(self):
+        pass
+
+    def get_name(self):
+        return "Cisco Credential"
+
+    def get_alias(self):
+        return "Cisco Credential"
+
+    def get_description(self):
+        return "Credential include username and password"
+
+    def get_namespace(self):
+        return ""
+
+    def get_updated(self):
+        return "2011-07-25T13:25:27-06:00"
+
+    def get_resources(self):
+        parent_resource = dict(member_name="tenant",
+                               collection_name="extensions/csco/tenants")
+       
+        controller = CredentialController(QuantumManager.get_plugin())
+        return [extensions.ResourceExtension('credentials', controller,
+                                             parent=parent_resource)]
+
+
+class CredentialController(common.QuantumController):
+    """ credential API controller
+        based on QuantumController """
+
+    _credential_ops_param_list = [{
+        'param-name': 'credential_name',
+        'required': True}, {
+        'param-name': 'user_name',
+        'required': True}, {
+        'param-name': 'password',
+        'required': True}]
+   
+    _serialization_metadata = {
+        "application/xml": {
+            "attributes": {
+                "credential": ["id", "name"],
+            },
+        },
+    }
+
+    def __init__(self, plugin):
+        self._resource_name = 'credential'
+        super(CredentialController, self).__init__(plugin)
+             
+    def index(self, request, tenant_id):
+        """ Returns a list of credential ids """
+        #TODO: this should be for a given tenant!!!
+        return self._items(request, tenant_id, is_detail=False)
+
+    def _items(self, request, tenant_id, is_detail):
+        """ Returns a list of credentials. """
+        credentials = self._plugin.get_all_credentials(tenant_id)
+        builder = credential_view.get_view_builder(request)
+        result = [builder.build(credential, is_detail)['credential']
+                  for credential in credentials]
+        return dict(credentials=result)
+
+    def show(self, request, tenant_id, id):
+        """ Returns credential details for the given credential id """
+        try:
+            credential = self._plugin.get_credential_details(
+                            tenant_id, id)
+            builder = credential_view.get_view_builder(request)
+            #build response with details
+            result = builder.build(credential, True)
+            return dict(credentials=result)
+        except exception.CredentialNotFound as e:
+            return faults.Fault(faults.CredentialNotFound(e))
+                                
+            #return faults.Fault(e)
+
+    def create(self, request, tenant_id):
+        """ Creates a new credential for a given tenant """
+        #look for credential name in request
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._credential_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        credential = self._plugin.\
+                       create_credential(tenant_id,
+                                          req_params['credential_name'],
+                                          req_params['user_name'],
+                                          req_params['password'])
+        builder = credential_view.get_view_builder(request)
+        result = builder.build(credential)
+        return dict(credentials=result)
+
+    def update(self, request, tenant_id, id):
+        """ Updates the name for the credential with the given id """
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._credential_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        try:
+            credential = self._plugin.\
+            rename_credential(tenant_id,
+                        id, req_params['credential_name'])
+
+            builder = credential_view.get_view_builder(request)
+            result = builder.build(credential, True)
+            return dict(credentials=result)
+        except exception.CredentialNotFound as e:
+            return faults.Fault(faults.CredentialNotFound(e))
+
+    def delete(self, request, tenant_id, id):
+        """ Destroys the credential with the given id """
+        try:
+            self._plugin.delete_credential(tenant_id, id)
+            return exc.HTTPAccepted()
+        except exception.CredentialNotFound as e:
+            return faults.Fault(faults.CredentialNotFound(e))
+        
\ No newline at end of file
diff --git a/extensions/novatenant.py b/extensions/novatenant.py
new file mode 100644 (file)
index 0000000..91a48e8
--- /dev/null
@@ -0,0 +1,161 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+#    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.
+
+from webob import exc
+
+from extensions import _novatenant_view as novatenant_view
+from extensions import _exceptions as exception
+from extensions import _faults as faults
+
+from quantum.api import api_common as common
+from quantum.common import wsgi
+from quantum.common import extensions
+from quantum.manager import QuantumManager
+
+
+class Novatenant(object):
+
+    def __init__(self):
+        pass
+
+    def get_name(self):
+        return "Cisco Nova Tenant"
+
+    def get_alias(self):
+        return "Cisco Nova Tenant"
+
+    def get_description(self):
+        return "novatenant resource is used by nova side to invoke quantum api"
+
+    def get_namespace(self):
+        return ""
+
+    def get_updated(self):
+        return "2011-08-09T13:25:27-06:00"
+
+    def get_resources(self):
+        parent_resource = dict(member_name="tenant", 
+                               collection_name="extensions/csco/tenants")
+        member_actions = {'get_host': "PUT",
+                          'get_instance_port': "PUT"}
+        controller = NovatenantsController(QuantumManager.get_plugin())
+        return [extensions.ResourceExtension('novatenants', controller,
+                                             parent=parent_resource,
+                                             member_actions=member_actions)]
+
+
+class NovatenantsController(common.QuantumController):
+    """ Novatenant API controller
+        based on QuantumController """
+
+    _Novatenant_ops_param_list = [{
+        'param-name': 'novatenant_name',
+        'required': True}]
+    
+    _get_host_ops_param_list = [{
+        'param-name': 'instance_id',
+        'required': True}, {
+        'param-name': 'instance_desc',
+        'required': True}]
+    
+    _serialization_metadata = {
+        "application/xml": {
+            "attributes": {
+                "novatenant": ["id", "name"],
+            },
+        },
+    }
+
+    def __init__(self, plugin):
+        self._resource_name = 'novatenant'
+        super(NovatenantsController, self).__init__(plugin)
+             
+    def index(self, request, tenant_id):
+        """ Returns a list of novatenant ids """
+        return "novatenant is a dummy resource"
+
+    def _items(self, request, tenant_id, is_detail):
+        """ Returns a list of novatenants. """
+        return "novatenant is a dummy resource"
+
+    def show(self, request, tenant_id, id):
+        """ Returns novatenant details for the given novatenant id """
+        return "novatenant is a dummy resource"
+
+    def create(self, request, tenant_id):
+        """ Creates a new novatenant for a given tenant """
+        return "novatenant is a dummy resource"
+
+    def update(self, request, tenant_id, id):
+        """ Updates the name for the novatenant with the given id """
+        return "novatenant is a dummy resource"
+
+    def delete(self, request, tenant_id, id):
+        """ Destroys the Novatenant with the given id """
+        return "novatenant is a dummy resource"
+         
+    #added for cisco's extension
+    def get_host(self, request, tenant_id, id):
+        content_type = request.best_match_content_type()
+        print "Content type:%s" % content_type
+        
+        try:
+            req_params = \
+                self._parse_request_params(request,
+                                           self._get_host_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        instance_id = req_params['instance_id']
+        
+        instance_desc = req_params['instance_desc']
+        try:
+            host = self._plugin.get_host(tenant_id, instance_id, instance_desc)
+            builder = novatenant_view.get_view_builder(request)
+            result = builder.build_host(host)
+            return result
+            #return exc.HTTPAccepted()
+        except exception.NovatenantNotFound as e:
+            return faults.Fault(faults.NovatenantNotFound(e))
+        except exception.PortNotFound as e:
+            return faults.Fault(faults.PortNotFound(e))
+        
+     #added for Cisco extension
+    def get_instance_port(self, request, tenant_id, id):
+        content_type = request.best_match_content_type()
+        print "Content type:%s" % content_type
+        
+        try:
+            req_params = \
+                self._parse_request_params(request,
+                                           self._get_host_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        instance_id = req_params['instance_id']
+       
+        instance_desc = req_params['instance_desc']
+        try:
+            vif = self._plugin. \
+            get_instance_port(tenant_id, instance_id, instance_desc)
+            builder = novatenant_view.get_view_builder(request)
+            result = builder.build_vif(vif)
+            return result
+            
+            return exc.HTTPAccepted()
+        except exception.NovatenantNotFound as e:
+            return faults.Fault(faults.NovatenantNotFound(e))
+        except exception.PortNotFound as e:
+            return faults.Fault(faults.PortNotFound(e))
diff --git a/extensions/portprofile.py b/extensions/portprofile.py
new file mode 100644 (file)
index 0000000..7cd2b36
--- /dev/null
@@ -0,0 +1,207 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+#    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.
+
+from webob import exc
+
+from extensions import _pprofiles as pprofiles_view
+from extensions import _exceptions as exception
+from extensions import _faults as faults
+
+from quantum.api import api_common as common
+from quantum.common import wsgi
+from quantum.common import extensions
+from quantum.manager import QuantumManager
+
+
+class Portprofile(object):
+
+    def __init__(self):
+        pass
+
+    def get_name(self):
+        return "Cisco Port Profile"
+
+    def get_alias(self):
+        return "Cisco Port Profile"
+
+    def get_description(self):
+        return "Portprofile include QoS information"
+
+    def get_namespace(self):
+        return ""
+
+    def get_updated(self):
+        return "2011-07-23T13:25:27-06:00"
+
+    def get_resources(self):
+        parent_resource = dict(member_name="tenant", 
+                               collection_name="extensions/csco/tenants")
+        member_actions = {'associate_portprofile': "PUT",
+                          'disassociate_portprofile': "POST"}
+        controller = PortprofilesController(QuantumManager.get_plugin())
+        return [extensions.ResourceExtension('portprofiles', controller,
+                                             parent=parent_resource,
+                                             member_actions=member_actions)]
+    
+    
+class PortprofilesController(common.QuantumController):
+    """ portprofile API controller
+        based on QuantumController """
+
+    _portprofile_ops_param_list = [{
+        'param-name': 'portprofile_name',
+        'required': True}, {
+        'param-name': 'qos_name',
+        'required': True}, {
+        'param-name': 'assignment',
+        'required': False}]
+    
+    _assignprofile_ops_param_list = [{
+        'param-name': 'network-id',
+        'required': True}, {
+        'param-name': 'port-id',
+        'required': True}]
+    
+    _serialization_metadata = {
+        "application/xml": {
+            "attributes": {
+                "portprofile": ["id", "name"],
+            },
+        },
+    }
+
+    def __init__(self, plugin):
+        self._resource_name = 'portprofile'
+        super(PortprofilesController, self).__init__(plugin)
+             
+    def index(self, request, tenant_id):
+        """ Returns a list of portprofile ids """
+        #TODO: this should be for a given tenant!!!
+        return self._items(request, tenant_id, is_detail=False)
+
+    def _items(self, request, tenant_id, is_detail):
+        """ Returns a list of portprofiles. """
+        portprofiles = self._plugin.get_all_portprofiles(tenant_id)
+        builder = pprofiles_view.get_view_builder(request)
+        result = [builder.build(portprofile, is_detail)['portprofile']
+                  for portprofile in portprofiles]
+        return dict(portprofiles=result)
+    
+    def show(self, request, tenant_id, id):
+        """ Returns portprofile details for the given portprofile id """
+        try:
+            portprofile = self._plugin.get_portprofile_details(
+                            tenant_id, id)
+            builder = pprofiles_view.get_view_builder(request)
+            #build response with details
+            result = builder.build(portprofile, True)
+            return dict(portprofiles=result)
+        except exception.PortprofileNotFound as e:
+            return faults.Fault(faults.PortprofileNotFound(e))
+            #return faults.Fault(e)
+
+    def create(self, request, tenant_id):
+        """ Creates a new portprofile for a given tenant """
+        #look for portprofile name in request
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._portprofile_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        portprofile = self._plugin.\
+                       create_portprofile(tenant_id,
+                                          req_params['portprofile_name'],
+                                          req_params['qos_name'])
+        builder = pprofiles_view.get_view_builder(request)
+        result = builder.build(portprofile)
+        return dict(portprofiles=result)
+
+    def update(self, request, tenant_id, id):
+        """ Updates the name for the portprofile with the given id """
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._portprofile_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        try:
+            portprofile = self._plugin.\
+            rename_portprofile(tenant_id,
+                        id, req_params['portprofile_name'])
+
+            builder = pprofiles_view.get_view_builder(request)
+            result = builder.build(portprofile, True)
+            return dict(portprofiles=result)
+        except exception.PortprofileNotFound as e:
+            return faults.Fault(faults.PortprofileNotFound(e))
+
+    def delete(self, request, tenant_id, id):
+        """ Destroys the portprofile with the given id """
+        try:
+            self._plugin.delete_portprofile(tenant_id, id)
+            return exc.HTTPAccepted()
+        except exception.PortprofileNotFound as e:
+            return faults.Fault(faults.PortprofileNotFound(e))
+         
+    #added for cisco's extension
+    def associate_portprofile(self, request, tenant_id, id):
+        content_type = request.best_match_content_type()
+        print "Content type:%s" % content_type
+        
+        try:
+            req_params = \
+                self._parse_request_params(request,
+                                           self._assignprofile_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        net_id = req_params['network-id'].strip()
+        #print "*****net id "+net_id
+        port_id = req_params['port-id'].strip()
+        try:
+            self._plugin.associate_portprofile(tenant_id,
+                                                net_id, port_id,
+                                                id)
+            return exc.HTTPAccepted()
+        except exception.PortprofileNotFound as e:
+            return faults.Fault(faults.PortprofileNotFound(e))
+        except exception.PortNotFound as e:
+            return faults.Fault(faults.PortNotFound(e))
+        
+     #added for Cisco extension
+    def disassociate_portprofile(self, request, tenant_id, id):
+        content_type = request.best_match_content_type()
+        print "Content type:%s" % content_type
+        
+        try:
+            req_params = \
+                self._parse_request_params(request,
+                                           self._assignprofile_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        net_id = req_params['network-id'].strip()
+        #print "*****net id "+net_id
+        port_id = req_params['port-id'].strip()
+        try:
+            self._plugin. \
+            disassociate_portprofile(tenant_id,
+                                    net_id, port_id, id)
+            return exc.HTTPAccepted()
+        except exception.PortprofileNotFound as e:
+            return faults.Fault(faults.PortprofileNotFound(e))
+        except exception.PortNotFound as e:
+            return faults.Fault(faults.PortNotFound(e))
diff --git a/extensions/qos.py b/extensions/qos.py
new file mode 100644 (file)
index 0000000..5351cc0
--- /dev/null
@@ -0,0 +1,154 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2011 Cisco Systems, Inc.  All rights reserved.
+#
+#    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: Ying Liu, Cisco Systems, Inc.
+#
+
+import logging
+
+from webob import exc
+from extensions import _qos_view as qos_view
+from extensions import _exceptions as exception
+from extensions import _faults as faults
+
+from quantum.api import api_common as common
+from quantum.common import wsgi
+from quantum.common import extensions
+from quantum.manager import QuantumManager
+
+LOG = logging.getLogger('quantum.api.qoss')
+
+
+class Qos(object):
+
+    def __init__(self):
+        pass
+
+    def get_name(self):
+        return "Cisco qos"
+
+    def get_alias(self):
+        return "Cisco qos"
+
+    def get_description(self):
+        return "qos include username and password"
+
+    def get_namespace(self):
+        return ""
+
+    def get_updated(self):
+        return "2011-07-25T13:25:27-06:00"
+
+    def get_resources(self):
+        parent_resource = dict(member_name="tenant", 
+                               collection_name="extensions/csco/tenants")
+       
+        controller = QosController(QuantumManager.get_plugin())
+        return [extensions.ResourceExtension('qoss', controller,
+                                             parent=parent_resource)]
+
+
+class QosController(common.QuantumController):
+    """ qos API controller
+        based on QuantumController """
+
+    _qos_ops_param_list = [{
+        'param-name': 'qos_name',
+        'required': True}, {
+        'param-name': 'qos_desc',
+        'required': True}]
+    _serialization_metadata = {
+        "application/xml": {
+            "attributes": {
+                "qos": ["id", "name"],
+            },
+        },
+    }
+
+    def __init__(self, plugin):
+        self._resource_name = 'qos'
+        super(QosController, self).__init__(plugin)
+             
+    def index(self, request, tenant_id):
+        """ Returns a list of qos ids """
+        #TODO: this should be for a given tenant!!!
+        return self._items(request, tenant_id, is_detail=False)
+
+    def _items(self, request, tenant_id, is_detail):
+        """ Returns a list of qoss. """
+        qoss = self._plugin.get_all_qoss(tenant_id)
+        builder = qos_view.get_view_builder(request)
+        result = [builder.build(qos, is_detail)['qos']
+                  for qos in qoss]
+        return dict(qoss=result)
+
+    def show(self, request, tenant_id, id):
+        """ Returns qos details for the given qos id """
+        try:
+            qos = self._plugin.get_qos_details(
+                            tenant_id, id)
+            builder = qos_view.get_view_builder(request)
+            #build response with details
+            result = builder.build(qos, True)
+            return dict(qoss=result)
+        except exception.QosNotFound as e:
+            return faults.Fault(faults.QosNotFound(e))
+                                
+            #return faults.Fault(e)
+
+    def create(self, request, tenant_id):
+        """ Creates a new qos for a given tenant """
+        #look for qos name in request
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._qos_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        qos = self._plugin.\
+                       create_qos(tenant_id,
+                                          req_params['qos_name'],
+                                          req_params['qos_desc'])
+        builder = qos_view.get_view_builder(request)
+        result = builder.build(qos)
+        return dict(qoss=result)
+
+    def update(self, request, tenant_id, id):
+        """ Updates the name for the qos with the given id """
+        try:
+            req_params = \
+                self._parse_request_params(request, 
+                                           self._qos_ops_param_list)
+        except exc.HTTPError as e:
+            return faults.Fault(e)
+        try:
+            qos = self._plugin.\
+            rename_qos(tenant_id,
+                        id, req_params['qos_name'])
+
+            builder = qos_view.get_view_builder(request)
+            result = builder.build(qos, True)
+            return dict(qoss=result)
+        except exception.QosNotFound as e:
+            return faults.Fault(faults.QosNotFound(e))
+
+    def delete(self, request, tenant_id, id):
+        """ Destroys the qos with the given id """
+        try:
+            self._plugin.delete_qos(tenant_id, id)
+            return exc.HTTPAccepted()
+        except exception.QosNotFound as e:
+            return faults.Fault(faults.QosNotFound(e))
index 307d2b48d2c7b167a10112cf1990eb0441ff579f..58db5dbc14fca1d2c80793ddb1272a9aa933d203 100644 (file)
@@ -1,3 +1,4 @@
 [PLUGIN]
-# Quantum plugin provider module
-provider = quantum.plugins.SamplePlugin.FakePlugin
+provider = quantum.plugins.cisco.l2network_plugin.L2Network
+#provider = quantum.plugins.cisco.CiscoPlugin.CiscoPaloPlugin2
+#provider = quantum.plugins.SamplePlugin.FakePlugin
diff --git a/quantum/plugins/cisco/CiscoPlugin.py b/quantum/plugins/cisco/CiscoPlugin.py
new file mode 100644 (file)
index 0000000..bed81ab
--- /dev/null
@@ -0,0 +1,562 @@
+from quantum.common import exceptions as exc
+from extensions import _exceptions as extexc
+
+          
+class CiscoPaloPlugin2(object):
+    """
+    This plugin has internal data structure
+    derived from quantum fakeplugin
+    """
+
+    #static data for networks and ports
+    _port_dict_1 = {
+                   1: {'port-id': 1, 
+                        'port-state': 'DOWN',
+                        'attachment': None,
+                        'portprofile': None},
+                   2: {'port-id': 2, 
+                        'port-state': 'UP',
+                        'attachment': None,
+                        'portprofile': None}}
+    _port_dict_2 = {
+                   1: {'port-id': 1, 
+                        'port-state': 'UP',
+                        'attachment': 'SomeFormOfVIFID',
+                        'portprofile': '001'},
+                   2: {'port-id': 2, 
+                        'port-state': 'DOWN',
+                        'attachment': None,
+                        'portprofile': '001'}}        
+    _networks = {'001':
+                    {
+                    'net-id': '001',
+                    'net-name': 'pippotest',
+                    'net-ports': _port_dict_1},
+                    '002':
+                    {
+                    'net-id': '002',
+                    'net-name': 'cicciotest',
+                    'net-ports': _port_dict_2}}
+    _portprofiles = {'001':
+                    {
+                    'profile_id': '001',
+                    'profile_name': 'pprofiletest',
+                    'assignment': ['1', '2'],
+                    'qos_name': '001'},
+                    '002':
+                    {
+                    'profile_id': '002',
+                    'profile_name': 'cicciotest',
+                    'qos_name': '002',
+                    'assignment': None}}
+    
+    _credentials = {'001':
+                    {
+                    'credential_id': '001',
+                    'credential_name': 'cred1',
+                    'user_name': 'ying',
+                    'password': 'yingTest'},
+                    '002':
+                    {
+                    'credential_id': '002',
+                    'credential_name': 'cred2',
+                    'user_name': 'admin',
+                    'password': 'adminTest'}}
+    _qoss = {'001':
+                    {
+                    'qos_id': '001',
+                    'qos_name': 'silver',
+                    'qos_desc': {'pps':170, 'TTL':20}},
+                    '002':
+                    {
+                    'qos_id': '002',
+                    'qos_name': 'gold',
+                    'qos_desc': {'pps':340, 'TTL':10}}}
+    
+    _host = {'host_desc': {
+                           "host_key1": "host_value1",
+                           "host_key2": "host_value2"}}
+    _vif = {'vif_desc': {
+                           "vif_key1": "vif_value1",
+                           "vif_key2": "vif_value2"}
+            }
+                    
+    
+    supported_extension_aliases = ["Cisco Credential", "Cisco Port Profile", "Cisco qos", "Cisco Nova Tenant"]
+    
+    
+    """
+    def supports_extension(self, extension):
+        #return extension.get_alias() == "Cisco Port Profile"
+        return extension.get_alias() == "Cisco Credential"
+    """
+    def __init__(self):
+        CiscoPaloPlugin2._net_counter = \
+        len(CiscoPaloPlugin2._networks)
+        
+        CiscoPaloPlugin2._profile_counter = \
+        len(CiscoPaloPlugin2._portprofiles)
+        
+        CiscoPaloPlugin2._credential_counter = \
+        len(CiscoPaloPlugin2._credentials)
+        
+        CiscoPaloPlugin2._qos_counter = \
+        len(CiscoPaloPlugin2._qoss)
+    def _get_network(self, tenant_id, network_id):
+        
+        network = CiscoPaloPlugin2._networks.get(network_id)
+        if not network:
+            raise exc.NetworkNotFound(net_id=network_id)
+        return network
+    
+   
+    
+    def _get_credential(self, tenant_id, credential_id):
+        credential = CiscoPaloPlugin2._credentials.get(credential_id)
+        if not credential:
+            raise extexc.CredentialNotFound(credential_id=credential_id)
+        return credential  
+    
+    def _get_qos(self, tenant_id, qos_id):
+        qos = CiscoPaloPlugin2._qoss.get(qos_id)
+        if not qos:
+            raise extexc.QosNotFound(qos_id=qos_id)
+        return qos  
+    
+    def _get_port(self, tenant_id, network_id, port_id):
+        net = self._get_network(tenant_id, network_id)
+        port = net['net-ports'].get(int(port_id))
+        if not port:
+            raise exc.PortNotFound(net_id=network_id, port_id=port_id)
+        return port
+    
+    def _validate_port_state(self, port_state):
+        if port_state.upper() not in ('UP', 'DOWN'):
+            raise exc.StateInvalid(port_state=port_state)
+        return True
+    
+    def _validate_attachment(self, tenant_id, network_id, port_id,
+                             remote_interface_id):
+        network = self._get_network(tenant_id, network_id)
+        for port in network['net-ports'].values():
+            if port['attachment'] == remote_interface_id:
+                raise exc.AlreadyAttached(net_id=network_id,
+                                          port_id=port_id,
+                                          att_id=port['attachment'],
+                                          att_port_id=port['port-id'])
+        
+    def get_all_networks(self, tenant_id):
+        """
+        Returns a dictionary containing all
+        <network_uuid, network_name> for
+        the specified tenant. 
+        """
+        print("get_all_networks() called\n")
+        return CiscoPaloPlugin2._networks.values()
+
+    def get_network_details(self, tenant_id, net_id):
+        """
+        retrieved a list of all the remote vifs that
+        are attached to the network
+        """
+        print("get_network_details() called\n")
+        return self._get_network(tenant_id, net_id)
+
+    def create_network(self, tenant_id, net_name):
+        """
+        Creates a new Virtual Network, and assigns it
+        a symbolic name.
+        """
+        print("create_network() called\n")
+        CiscoPaloPlugin2._net_counter += 1
+        new_net_id = ("0" * (3 - len(str(CiscoPaloPlugin2._net_counter)))) + \
+                    str(CiscoPaloPlugin2._net_counter)
+        print new_net_id
+        new_net_dict = {'net-id': new_net_id,
+                      'net-name': net_name,
+                      'net-ports': {}}
+        CiscoPaloPlugin2._networks[new_net_id] = new_net_dict
+        # return network_id of the created network
+        return new_net_dict
+    
+    def delete_network(self, tenant_id, net_id):
+        """
+        Deletes the network with the specified network identifier
+        belonging to the specified tenant.
+        """
+        print("delete_network() called\n")
+        net = CiscoPaloPlugin2._networks.get(net_id)
+        # Verify that no attachments are plugged into the network
+        if net:
+            if net['net-ports']:
+                for port in net['net-ports'].values():
+                    if port['attachment']:
+                        raise exc.NetworkInUse(net_id=net_id)
+            CiscoPaloPlugin2._networks.pop(net_id)
+            return net
+        # Network not found
+        raise exc.NetworkNotFound(net_id=net_id)
+    
+    def rename_network(self, tenant_id, net_id, new_name):
+        """
+        Updates the symbolic name belonging to a particular
+        Virtual Network.
+        """
+        print("rename_network() called\n")
+        net = self._get_network(tenant_id, net_id)
+        net['net-name'] = new_name 
+        return net
+
+    def _get_portprofile(self, tenant_id, portprofile_id):
+        portprofile = CiscoPaloPlugin2._portprofiles.get(portprofile_id)
+        if not portprofile:
+            raise extexc.PortprofileNotFound(portprofile_id=portprofile_id)
+        return portprofile  
+    
+    def get_all_portprofiles(self, tenant_id):
+        """
+        Returns a dictionary containing all
+        <portprofile_uuid, portprofile_name> for
+        the specified tenant. 
+        """
+        print("get_all_portprofiles() called\n")
+        return CiscoPaloPlugin2._portprofiles.values()
+
+    def get_portprofile_details(self, tenant_id, profile_id):
+        """
+        retrieved a list of all the remote vifs that
+        are attached to the portprofile
+        """
+        print("get_portprofile_details() called\n")
+        return self._get_portprofile(tenant_id, profile_id)
+
+    def create_portprofile(self, tenant_id, profile_name, vlan_id):
+        """
+        Creates a new Virtual portprofile, and assigns it
+        a symbolic name.
+        """
+        print("create_portprofile() called\n")
+        CiscoPaloPlugin2._profile_counter += 1
+        new_profile_id = ("0" * \
+                          (3 - \
+                           len(str(CiscoPaloPlugin2._profile_counter)))) + \
+                    str(CiscoPaloPlugin2._profile_counter)
+        print new_profile_id
+        new_profile_dict = {'profile_id': new_profile_id,
+                      'profile_name': profile_name,
+                      'qos_name': vlan_id,
+                      'assignment': None}
+        CiscoPaloPlugin2._portprofiles[new_profile_id] = new_profile_dict
+        # return portprofile_id of the created portprofile
+        return new_profile_dict
+    
+    def delete_portprofile(self, tenant_id, profile_id):
+        """
+        Deletes the portprofile with the specified portprofile identifier
+        belonging to the specified tenant.
+        """
+        print("delete_portprofile() called\n")
+        profile = CiscoPaloPlugin2._portprofiles.get(profile_id)
+        # Verify that no attachments are plugged into the portprofile
+        if profile:
+            CiscoPaloPlugin2._portprofiles.pop(profile_id)
+            return profile
+        # portprofile not found
+        raise extexc.PortprofileNotFound(profile_id=profile_id)
+    
+    def rename_portprofile(self, tenant_id, profile_id, new_name):
+        """
+        Updates the symbolic name belonging to a particular
+        Virtual portprofile.
+        """
+        print("rename_portprofile() called\n")
+        profile = self._get_portprofile(tenant_id, profile_id)
+        profile['profile_name'] = new_name 
+        return profile
+    
+    
+
+    def associate_portprofile(self, tenant_id, net_id, port_id, pprofile_id):
+        """
+        Assign portprofile to the specified port on the
+        specified Virtual Network.
+        """
+        print("assign_portprofile() called\n")
+        print("net_id " + net_id)
+        # Validate attachment
+        #self._validate_attachment(tenant_id, net_id, port_id,
+                               #  remote_interface_id)
+        #TODO: modify the exception
+        port = self._get_port(tenant_id, net_id, port_id)
+        if (not port['portprofile'] == None):
+            raise exc.PortInUse(net_id=net_id, port_id=port_id,
+                                att_id=port['portprofile'])
+        port['portprofile'] = pprofile_id
+    
+    def disassociate_portprofile(self, tenant_id, net_id, port_id, portprofile_id):
+        """
+        De-assign a portprofile from the specified port on the
+        specified Virtual Network.
+        """
+        print("deassign_portprofile() called\n")
+        #print("*******net_id is "+net_id)
+        port = self._get_port(tenant_id, net_id, port_id)
+      
+        port['portprofile'] = None
+        #TODO:
+        #modify assignment[portprofile_id] to remove this port
+    
+    #TODO: add new data structure to 
+    #hold all the assignment for a specific portprofile    
+    def get_portprofile_assignment(self, tenant_id, net_id, port_id):
+        print("get portprofile assignment called\n") 
+        port = self._get_port(tenant_id, net_id, port_id)
+        ppid = port['portprofile'] 
+        if (ppid == None):
+            print("***no portprofile attached")
+            return "no portprofile attached"
+        else:
+            print("***attached portprofile id is " + ppid)
+            return ("attached portprofile " + ppid)
+        
+    
+    def get_all_credentials(self, tenant_id):
+        """
+        Returns a dictionary containing all
+        <credential_id, credential_name> for
+        the specified tenant. 
+        """
+        print("get_all_credentials() called\n")
+        return CiscoPaloPlugin2._credentials.values()
+
+    def get_credential_details(self, tenant_id, credential_id):
+        """
+        retrieved a list of all the remote vifs that
+        are attached to the credential
+        """
+        print("get_credential_details() called\n")
+        return self._get_credential(tenant_id, credential_id)
+
+    def create_credential(self, tenant_id, credential_name, user_name, password):
+        """
+        Creates a new Virtual credential, and assigns it
+        a symbolic name.
+        """
+        print("create_credential() called\n")
+        CiscoPaloPlugin2._credential_counter += 1
+        new_credential_id = ("0" * \
+                          (3 - \
+                           len(str(CiscoPaloPlugin2._credential_counter)))) + \
+                    str(CiscoPaloPlugin2._credential_counter)
+        print new_credential_id
+        new_credential_dict = {'credential_id': new_credential_id,
+                      'credential_name': credential_name,
+                      'user_name': user_name,
+                      'password': password}
+        CiscoPaloPlugin2._credentials[new_credential_id] = new_credential_dict
+        # return credential_id of the created credential
+        return new_credential_dict
+    
+    def delete_credential(self, tenant_id, credential_id):
+        """
+        Deletes the credential with the specified credential identifier
+        belonging to the specified tenant.
+        """
+        print("delete_credential() called\n")
+        credential = CiscoPaloPlugin2._credentials.get(credential_id)
+        
+        if credential:
+            CiscoPaloPlugin2._credentials.pop(credential_id)
+            return credential
+        # credential not found
+        raise extexc.CredentialNotFound(credential_id=credential_id)
+    
+    def rename_credential(self, tenant_id, credential_id, new_name):
+        """
+        Updates the symbolic name belonging to a particular
+        Virtual credential.
+        """
+        print("rename_credential() called\n")
+        credential = self._get_credential(tenant_id, credential_id)
+        credential['credential_name'] = new_name 
+        return credential
+    
+    
+    def get_all_qoss(self, tenant_id):
+        """
+        Returns a dictionary containing all
+        <qos_id, qos_name> for
+        the specified tenant. 
+        """
+        print("get_all_qoss() called\n")
+        return CiscoPaloPlugin2._qoss.values()
+
+    def get_qos_details(self, tenant_id, qos_id):
+        """
+        retrieved a list of all the remote vifs that
+        are attached to the qos
+        """
+        print("get_qos_details() called\n")
+        return self._get_qos(tenant_id, qos_id)
+
+    def create_qos(self, tenant_id, qos_name, qos_desc):
+        """
+        Creates a new Virtual qos, and assigns it
+        a symbolic name.
+        """
+        print("create_qos() called\n")
+        CiscoPaloPlugin2._qos_counter += 1
+        new_qos_id = ("0" * \
+                          (3 - \
+                           len(str(CiscoPaloPlugin2._qos_counter)))) + \
+                    str(CiscoPaloPlugin2._qos_counter)
+        print new_qos_id
+        new_qos_dict = {'qos_id': new_qos_id,
+                      'qos_name': qos_name,
+                      'qos_desc': qos_desc}
+        
+        print("************************")
+        print("test dictionary data")
+        print(qos_desc['TTL'])
+        print("************************")
+
+        CiscoPaloPlugin2._qoss[new_qos_id] = new_qos_dict
+        # return qos_id of the created qos
+        return new_qos_dict
+    
+    def delete_qos(self, tenant_id, qos_id):
+        """
+        Deletes the qos with the specified qos identifier
+        belonging to the specified tenant.
+        """
+        print("delete_qos() called\n")
+        qos = CiscoPaloPlugin2._qoss.get(qos_id)
+        # Verify that no attachments are plugged into the qos
+        if qos:
+            CiscoPaloPlugin2._qoss.pop(qos_id)
+            return qos
+        # qos not found
+        raise extexc.QosNotFound(qos_id=qos_id)
+    
+    def rename_qos(self, tenant_id, qos_id, new_name):
+        """
+        Updates the symbolic name belonging to a particular
+        Virtual qos.
+        """
+        print("rename_qos() called\n")
+        qos = self._get_qos(tenant_id, qos_id)
+        qos['qos_name'] = new_name 
+        return qos
+    
+    
+        
+
+    def get_all_ports(self, tenant_id, net_id):
+        """
+        Retrieves all port identifiers belonging to the
+        specified Virtual Network.
+        """
+        print("get_all_ports() called\n")
+        network = self._get_network(tenant_id, net_id)
+        ports_on_net = network['net-ports'].values()
+        return ports_on_net
+
+    def get_port_details(self, tenant_id, net_id, port_id):
+        """
+        This method allows the user to retrieve a remote interface
+        that is attached to this particular port.
+        """
+        print("get_port_details() called\n")
+        return self._get_port(tenant_id, net_id, port_id)
+        
+    def create_port(self, tenant_id, net_id, port_state=None):
+        """
+        Creates a port on the specified Virtual Network.
+        """
+        print("create_port() called\n")
+        net = self._get_network(tenant_id, net_id)
+        # check port state
+        # TODO(salvatore-orlando): Validate port state in API?            
+        self._validate_port_state(port_state)
+        ports = net['net-ports']
+        new_port_id = max(ports.keys()) + 1
+        new_port_dict = {'port-id': new_port_id,
+                         'port-state': port_state,
+                         'attachment': None,
+                         'portprofile': None}
+        ports[new_port_id] = new_port_dict
+        return new_port_dict 
+
+    def update_port(self, tenant_id, net_id, port_id, port_state):
+        """
+        Updates the state of a port on the specified Virtual Network.
+        """
+        print("create_port() called\n")
+        port = self._get_port(tenant_id, net_id, port_id)
+        self._validate_port_state(port_state)
+        port['port-state'] = port_state
+        return port 
+        
+    def delete_port(self, tenant_id, net_id, port_id):
+        """
+        Deletes a port on a specified Virtual Network,
+        if the port contains a remote interface attachment,
+        the remote interface is first un-plugged and then the port
+        is deleted.
+        """
+        print("delete_port() called\n")
+        net = self._get_network(tenant_id, net_id)
+        port = self._get_port(tenant_id, net_id, port_id)
+        if port['attachment']:
+            raise exc.PortInUse(net_id=net_id, port_id=port_id,
+                                att_id=port['attachment'])
+        try:
+            net['net-ports'].pop(int(port_id))
+        except KeyError:  
+            raise exc.PortNotFound(net_id=net_id, port_id=port_id)
+
+    def get_interface_details(self, tenant_id, net_id, port_id):
+        print("get interface detail called\n") 
+        port = self._get_port(tenant_id, net_id, port_id)
+        vid = port['attachment'] 
+        if (vid == None):
+            print("***no interface is attached")
+            return "no interface attached"
+        else:
+            print("***interface id is " + vid)
+            return ("attached interface " + vid)
+        
+    def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
+        """
+        Attaches a remote interface to the specified port on the
+        specified Virtual Network.
+        """
+        print("plug_interface() called\n")
+        # Validate attachment
+        self._validate_attachment(tenant_id, net_id, port_id,
+                                  remote_interface_id)
+        port = self._get_port(tenant_id, net_id, port_id)
+        if port['attachment']:
+            raise exc.PortInUse(net_id=net_id, port_id=port_id,
+                                att_id=port['attachment'])
+        port['attachment'] = remote_interface_id
+    
+    def unplug_interface(self, tenant_id, net_id, port_id):
+        """
+        Detaches a remote interface from the specified port on the
+        specified Virtual Network.
+        """
+        print("unplug_interface() called\n")
+        port = self._get_port(tenant_id, net_id, port_id)
+        # TODO(salvatore-orlando):
+        # Should unplug on port without attachment raise an Error?
+        port['attachment'] = None
+        
+    def get_host(self, tenant_id, instance_id, instance_desc):
+        print("associate an instance to a port....")
+        print("get key2: " + instance_desc['key2'])
+        return CiscoPaloPlugin2._host
+    def get_instance_port(self, tenant_id, instance_id, instance_desc):
+        print("get instance associated port....")
+        print("get key1: " + instance_desc['key1'])
+        return CiscoPaloPlugin2._vif
\ No newline at end of file
index 4a5d7e3713821ac7440f0190d288223cc0bf26ce..fdc7ace15e795a7a57663743736392c443e4e2a1 100644 (file)
@@ -1,5 +1,5 @@
 [DATABASE]
 name = quantum_l2network
-user = <put_db_user_name_here>
-pass = <put_db_password_here>
-host = <put_quantum_mysql_host_here>
+user =root 
+pass =nova 
+host =localhost 
index 3a740a9713c2e098ea895b711229866521d175a8..f51c1ae33162f7b1fd8ccba98efe3b8994d052c0 100644 (file)
@@ -1,6 +1,6 @@
 [VLANS]
-vlan_start=<put_vlan_id_range_start_here>
-vlan_end=<put_vlan_id_range_end_here>
+vlan_start=100
+vlan_end=300
 vlan_name_prefix=q-
 
 [PORTS]
index 8b4b476a0ad03e6e60e3071bdc37a86f4adbc4b3..a4b62c89032e12938aa30973ce58ce023c736bf8 100644 (file)
@@ -1,3 +1,3 @@
 [PLUGINS]
-ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin
+#ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin
 #nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin
diff --git a/test_scripts/__init__.py b/test_scripts/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test_scripts/miniclient.py b/test_scripts/miniclient.py
new file mode 100644 (file)
index 0000000..fb1ebc8
--- /dev/null
@@ -0,0 +1,98 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Citrix Systems
+# All Rights Reserved.
+#
+#    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.
+
+import httplib
+import socket
+import urllib
+
+class MiniClient(object):
+
+    """A base client class - derived from Glance.BaseClient"""
+
+    action_prefix = '/v0.1/tenants/{tenant_id}'
+
+    def __init__(self, host, port, use_ssl):
+        """
+        Creates a new client to some service.
+
+        :param host: The host where service resides
+        :param port: The port where service resides
+        :param use_ssl: Should we use HTTPS?
+        """
+        self.host = host
+        self.port = port
+        self.use_ssl = use_ssl
+        self.connection = None
+
+    def get_connection_type(self):
+        """
+        Returns the proper connection type
+        """
+        if self.use_ssl:
+            return httplib.HTTPSConnection
+        else:
+            return httplib.HTTPConnection
+
+    def do_request(self, tenant, method, action, body=None,
+                   headers=None, params=None):
+        """
+        Connects to the server and issues a request.  
+        Returns the result data, or raises an appropriate exception if
+        HTTP status code is not 2xx
+
+        :param method: HTTP method ("GET", "POST", "PUT", etc...)
+        :param body: string of data to send, or None (default)
+        :param headers: mapping of key/value pairs to add as headers
+        :param params: dictionary of key/value pairs to add to append
+                             to action
+
+        """
+        action = MiniClient.action_prefix + action
+        action = action.replace('{tenant_id}',tenant)
+        if type(params) is dict:
+            action += '?' + urllib.urlencode(params)
+
+        try:
+            connection_type = self.get_connection_type()
+            headers = headers or {}
+            
+            # Open connection and send request
+            c = connection_type(self.host, self.port)
+            c.request(method, action, body, headers)
+            res = c.getresponse()
+            status_code = self.get_status_code(res)
+            if status_code in (httplib.OK,
+                               httplib.CREATED,
+                               httplib.ACCEPTED,
+                               httplib.NO_CONTENT):
+                return res
+            else:
+                raise Exception("Server returned error: %s" % res.read())
+
+        except (socket.error, IOError), e:
+            raise Exception("Unable to connect to "
+                            "server. Got error: %s" % e)
+
+    def get_status_code(self, response):
+        """
+        Returns the integer status code from the response, which
+        can be either a Webob.Response (used in testing) or httplib.Response
+        """
+        if hasattr(response, 'status_int'):
+            return response.status_int
+        else:
+            return response.status
\ No newline at end of file
diff --git a/test_scripts/tests.py b/test_scripts/tests.py
new file mode 100644 (file)
index 0000000..589d9da
--- /dev/null
@@ -0,0 +1,150 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Citrix Systems
+# All Rights Reserved.
+#
+#    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.
+
+import gettext
+
+gettext.install('quantum', unicode=1)
+
+from miniclient import MiniClient
+from quantum.common.wsgi import Serializer
+
+HOST = '127.0.0.1'
+PORT = 9696
+USE_SSL = False
+TENANT_ID = 'totore'
+
+test_network_data = \
+    {'network': {'network-name': 'test' }}
+
+def print_response(res):
+    content = res.read()
+    print "Status: %s" %res.status
+    print "Content: %s" %content
+    return content
+
+def test_list_networks_and_ports(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "TEST LIST NETWORKS AND PORTS -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - List All Networks"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    print_response(res)
+    print "--> Step 2 - Details for Network 001"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001." + format)
+    print_response(res)
+    print "--> Step 3 - Ports for Network 001"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format)
+    print_response(res)
+    print "--> Step 4 - Details for Port 1"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001/ports/1." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+    
+def test_create_network(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "TEST CREATE NETWORK -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - Create Network"
+    content_type = "application/" + format
+    body = Serializer().serialize(test_network_data, content_type)
+    res = client.do_request(TENANT_ID,'POST', "/networks." + format, body=body)
+    print_response(res)
+    print "--> Step 2 - List All Networks"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+def test_rename_network(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format    
+    print "TEST RENAME NETWORK -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - Retrieve network"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001." + format)
+    print_response(res)
+    print "--> Step 2 - Rename network to 'test_renamed'"
+    test_network_data['network']['network-name'] = 'test_renamed'
+    body = Serializer().serialize(test_network_data, content_type)
+    res = client.do_request(TENANT_ID,'PUT', "/networks/001." + format, body=body)
+    print_response(res)
+    print "--> Step 2 - Retrieve network (again)"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+    
+def test_delete_network(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    content_type = "application/" + format
+    print "TEST DELETE NETWORK -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - List All Networks"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    content = print_response(res)
+    network_data = Serializer().deserialize(content, content_type)
+    print network_data
+    net_id = network_data['networks'][0]['id']
+    print "--> Step 2 - Delete network %s" %net_id    
+    res = client.do_request(TENANT_ID,'DELETE',
+                            "/networks/" + net_id + "." + format)
+    print_response(res)
+    print "--> Step 3 - List All Networks (Again)"
+    res = client.do_request(TENANT_ID,'GET', "/networks." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+def test_create_port(format = 'xml'):
+    client = MiniClient(HOST, PORT, USE_SSL)
+    print "TEST CREATE PORT -- FORMAT:%s" %format 
+    print "----------------------------"
+    print "--> Step 1 - List Ports for network 001"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format)
+    print_response(res)
+    print "--> Step 2 - Create Port for network 001"
+    res = client.do_request(TENANT_ID,'POST', "/networks/001/ports." + format)
+    print_response(res)
+    print "--> Step 3 - List Ports for network 001 (again)"
+    res = client.do_request(TENANT_ID,'GET', "/networks/001/ports." + format)
+    print_response(res)
+    print "COMPLETED"
+    print "----------------------------"
+
+
+def main():
+    test_list_networks_and_ports('xml')
+    test_list_networks_and_ports('json')
+    test_create_network('xml')
+    test_create_network('json')
+    test_rename_network('xml')
+    test_rename_network('json')
+    # NOTE: XML deserializer does not work properly 
+    # disabling XML test - this is NOT a server-side issue
+    #test_delete_network('xml')
+    test_delete_network('json')
+    test_create_port('xml')
+    test_create_port('json')
+    
+    pass
+    
+
+# Standard boilerplate to call the main() function.
+if __name__ == '__main__':
+    main()
\ No newline at end of file