cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t..@apache.org
Subject git commit: refs/heads/bvt - WIP: work in progress marvin-apidiscovery autosync
Date Tue, 26 Mar 2013 12:59:56 GMT
Updated Branches:
  refs/heads/bvt 3307dbaec -> 4c5c71cdf


WIP: work in progress marvin-apidiscovery autosync

Signed-off-by: Prasanna Santhanam <tsp@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/4c5c71cd
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/4c5c71cd
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/4c5c71cd

Branch: refs/heads/bvt
Commit: 4c5c71cdfa235d8d45155a6c4c56f41d158474d1
Parents: 3307dba
Author: Prasanna Santhanam <tsp@apache.org>
Authored: Tue Mar 26 18:29:23 2013 +0530
Committer: Prasanna Santhanam <tsp@apache.org>
Committed: Tue Mar 26 18:29:23 2013 +0530

----------------------------------------------------------------------
 test/integration/smoke/test_vm_life_cycle.py |   17 ++++-
 tools/marvin/marvin/cloudstackTestClient.py  |   15 +++-
 tools/marvin/marvin/codegenerator.py         |   96 +++++++++++++++++++--
 tools/marvin/marvin/marvinPlugin.py          |   14 +++
 4 files changed, 129 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c5c71cd/test/integration/smoke/test_vm_life_cycle.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py
index 9d6c249..cf9fd75 100644
--- a/test/integration/smoke/test_vm_life_cycle.py
+++ b/test/integration/smoke/test_vm_life_cycle.py
@@ -262,11 +262,26 @@ class TestDeployVM(cloudstackTestCase):
         self.assertIsNotNone(router.publicip, msg="Router has no public ip")
         self.assertIsNotNone(router.guestipaddress, msg="Router has no guest ip")
 
+    @attr(hypervisor = ["simulator"])
+    @attr(mode = ["basic"])
+    def test_basicZoneVirtualRouter(self):
+        """
+        Tests for basic zone virtual router
+        1. Is Running
+        2. is in the account the VM was deployed in
+        @return:
+        """
+        routers = list_routers(self.apiclient, account=self.account.account.name)
+        self.assertTrue(len(routers) > 0, msg = "No virtual router found")
+        router = routers[0]
+
+        self.assertEqual(router.state, 'Running', msg="Router is not in running state")
+        self.assertEqual(router.account, self.account.account.name, msg="Router does not
belong to the account")
+
     def tearDown(self):
         pass
 
 
-
 class TestVMLifeCycle(cloudstackTestCase):
 
     @classmethod

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c5c71cd/tools/marvin/marvin/cloudstackTestClient.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py
index cb63179..4bfb90b 100644
--- a/tools/marvin/marvin/cloudstackTestClient.py
+++ b/tools/marvin/marvin/cloudstackTestClient.py
@@ -24,7 +24,8 @@ import string
 import hashlib
 
 class cloudstackTestClient(object):
-    def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600,
defaultWorkerThreads=10, logging=None):
+    def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600,
+                 defaultWorkerThreads=10, logging=None):
         self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey,
asyncTimeout, logging)
         self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection)
         self.dbConnection = None
@@ -32,7 +33,6 @@ class cloudstackTestClient(object):
         self.ssh = None
         self.defaultWorkerThreads = defaultWorkerThreads
         
-        
     def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'):
         self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db)
     
@@ -147,7 +147,16 @@ class cloudstackTestClient(object):
         if hasattr(self, "userApiClient"):
             return self.userApiClient
         return None
-    
+
+    def synchronize(self):
+        """
+        synchronize the api from an endpoint
+        """
+        apiclient = self.getApiClient()
+        cmd = listApis.listApisCmd()
+        response = apiclient.listApis(cmd)
+
+
     '''FixME, httplib has issue if more than one thread submitted'''
     def submitCmdsAndWait(self, cmds, workers=1):
         if self.asyncJobMgr is None:

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c5c71cd/tools/marvin/marvin/codegenerator.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py
index ed9248c..5d9a2df 100644
--- a/tools/marvin/marvin/codegenerator.py
+++ b/tools/marvin/marvin/codegenerator.py
@@ -16,10 +16,12 @@
 # under the License.
 
 import xml.dom.minidom
+import json
 from optparse import OptionParser
 from textwrap import dedent
 import os
 import sys
+
 class cmdParameterProperty(object):
     def __init__(self):
         self.name = None
@@ -97,6 +99,7 @@ class codeGenerator:
                 subclass += self.space + self.space + 'self.%s = None\n'%pro.name
         
         self.subclass.append(subclass)
+
     def generate(self, cmd):
        
         self.cmd = cmd
@@ -159,8 +162,7 @@ class codeGenerator:
         fp.close()
         self.code = ""
         self.subclass = []
-       
-        
+
     def finalize(self):
         '''generate an api call'''
         
@@ -215,8 +217,7 @@ class codeGenerator:
         fp.write(basecmd)
         fp.close()
         
-    
-    def constructResponse(self, response):
+    def constructResponseFromXML(self, response):
         paramProperty = cmdParameterProperty()
         paramProperty.name = getText(response.getElementsByTagName('name'))
         paramProperty.desc = getText(response.getElementsByTagName('description'))
@@ -224,7 +225,23 @@ class codeGenerator:
             '''This is a list'''
             paramProperty.name = paramProperty.name.split('(*)')[0]
             for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'):
-                subProperty = self.constructResponse(subresponse)
+                subProperty = self.constructResponseFromXML(subresponse)
+                paramProperty.subProperties.append(subProperty)
+        return paramProperty
+
+    def constructResponseFromJSON(self, response):
+        paramProperty = cmdParameterProperty()
+        if response.has_key('name'):
+            paramProperty.name = response['name']
+        assert paramProperty.name
+
+        if response.has_key('description'):
+            paramProperty.desc = response['description']
+        if response.has_key('type') and response['type'] == 'list':
+            #Here list becomes a subproperty
+            paramProperty.name = paramProperty.name.split('(*)')[0]
+            for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'):
+                subProperty = self.constructResponseFromXML(subresponse)
                 paramProperty.subProperties.append(subProperty)
         return paramProperty
 
@@ -269,18 +286,79 @@ class codeGenerator:
                 if response.parentNode != responseEle:
                     continue
             
-                paramProperty = self.constructResponse(response)
+                paramProperty = self.constructResponseFromXML(response)
                 csCmd.response.append(paramProperty)
             
             cmds.append(csCmd)
         return cmds
-    
-    def generateCode(self):
+
+    def loadCmdFromJSON(self, apiStream):
+        if apiStream is None:
+            raise Exception("No APIs found through discovery")
+
+        apiDict = json.loads(apiStream)
+        if not apiDict.has_key('listapisresponse'):
+            raise Exception("API discovery plugin response failed")
+        if not apiDict['listapisresponse'].has_key('count'):
+            raise Exception("Malformed api response")
+
+        apilist = apiDict['listapisresponse']['api']
+        cmds = []
+        for cmd in apilist:
+            csCmd = cloudStackCmd()
+            if cmd.has_key('name'):
+                csCmd.name = cmd['name']
+            assert csCmd.name
+
+            if cmd.has_key('description'):
+                csCmd.desc = cmd['description']
+
+            if cmd.has_key('async'):
+                csCmd.async = cmd['isasync']
+
+            for param in cmd['params']:
+                paramProperty = cmdParameterProperty()
+
+                if param.has_key('name'):
+                    paramProperty.name = param['name']
+                assert paramProperty.name
+
+                if param.has_key('required'):
+                    paramProperty.required = param.getElementsByTagName('required')
+
+                if param.has_key('description'):
+                    paramProperty.desc = param['description']
+
+                if param.has_key('type'):
+                    paramProperty.type = param['type']
+
+                csCmd.request.append(paramProperty)
+
+            for response in cmd['response']:
+                paramProperty = self.constructResponseFromJSON(response)
+                csCmd.response.append(paramProperty)
+
+            cmds.append(csCmd)
+        return cmds
+
+
+    def generateCodeFromXML(self):
         cmds = self.loadCmdFromXML()
         for cmd in cmds:
             self.generate(cmd)
         self.finalize()
 
+    def generateCodeFromJSON(self, apiJson):
+        """
+        Api Discovery plugin returns the supported APIs of a CloudStack endpoint.
+        @return: The classes in cloudstackAPI/ formed from api discovery json
+        """
+        with open(apiJson, 'r') as apiStream:
+            cmds = self.loadCmdFromJSON(apiStream)
+            for cmd in cmds:
+                self.generate(cmd)
+            self.finalize()
+
 def getText(elements):
     return elements[0].childNodes[0].nodeValue.strip()
 
@@ -315,5 +393,5 @@ if __name__ == "__main__":
             exit(2)
     
     cg = codeGenerator(folder, apiSpecFile)
-    cg.generateCode()
+    cg.generateCodeFromXML()
     

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4c5c71cd/tools/marvin/marvin/marvinPlugin.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py
index c52596e..518f27f 100644
--- a/tools/marvin/marvin/marvinPlugin.py
+++ b/tools/marvin/marvin/marvinPlugin.py
@@ -21,6 +21,7 @@ import logging
 import nose.core
 from marvin.cloudstackTestCase import cloudstackTestCase
 from marvin import deployDataCenter
+from marvin import apiSynchronizer
 from nose.plugins.base import Plugin
 from functools import partial
 
@@ -39,6 +40,10 @@ class MarvinPlugin(Plugin):
         self.enableOpt = "--with-marvin"
         self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s")
 
+        if options.sync:
+            self.do_sync(options.config)
+            return
+
         if options.debug_log:
             self.logger = logging.getLogger("NoseTestExecuteEngine")
             self.debug_stream = logging.FileHandler(options.debug_log) 
@@ -65,6 +70,13 @@ class MarvinPlugin(Plugin):
         cfg.debugLog = self.debug_stream
         
         self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, descriptions=True,
verbosity=2, config=config)
+
+    def do_sync(self, config):
+        """
+        Use the ApiDiscovery plugin exposed by the CloudStack mgmt server to rebuild the
cloudStack API
+        """
+        apiSynchronizer.sync(config)
+
     
     def options(self, parser, env):
         """
@@ -84,6 +96,8 @@ class MarvinPlugin(Plugin):
                           help="The path to the testcase debug logs [DEBUG_LOG]")
         parser.add_option("--load", action="store_true", default=False, dest="load",
                           help="Only load the deployment configuration given")
+        parser.add_option("--sync", action="store_true", default=False, dest="sync",
+                          help="Sync the APIs from the CloudStack endpoint in marvin-config")
         
         Plugin.options(self, parser, env)
  


Mime
View raw message