You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ts...@apache.org on 2013/04/25 16:45:29 UTC

[03/51] [abbrv] git commit: updated refs/heads/marvin_refactor to dbcfc66

Merge branch 'master' into marvin_refactor

Conflicts:
	tools/marvin/marvin/cloudstackConnection.py
	tools/marvin/marvin/cloudstackTestClient.py
	tools/marvin/marvin/oldbase.py
	ui/scripts/zoneWizard.js


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

Branch: refs/heads/marvin_refactor
Commit: 5cea60128fed0467d098c5e307fdd6e90ddc6caa
Parents: 0b5fe9a a1ef9d7
Author: Prasanna Santhanam <ts...@apache.org>
Authored: Wed Apr 24 22:10:48 2013 +0530
Committer: Prasanna Santhanam <ts...@apache.org>
Committed: Wed Apr 24 22:10:48 2013 +0530

----------------------------------------------------------------------
 api/src/com/cloud/vm/UserVmService.java            |   27 +-
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 api/src/org/apache/cloudstack/api/BaseCmd.java     |   24 +
 .../command/admin/account/CreateAccountCmd.java    |   14 +-
 .../api/command/admin/vm/MigrateVMCmd.java         |    2 +-
 .../api/command/user/vm/DeployVMCmd.java           |   12 +-
 .../api/command/user/vm/UpdateVMCmd.java           |    2 +-
 .../cloudstack/api/response/ClusterResponse.java   |    9 +-
 .../api/response/DomainRouterResponse.java         |   11 +
 .../cloudstack/api/response/HostResponse.java      |    9 +-
 .../cloudstack/api/response/NetworkResponse.java   |    7 +
 .../cloudstack/api/response/PodResponse.java       |    9 +-
 .../cloudstack/api/response/SnapshotResponse.java  |   16 +
 .../api/response/StoragePoolResponse.java          |   15 +-
 .../cloudstack/api/response/SystemVmResponse.java  |   11 +
 .../cloudstack/api/response/TemplateResponse.java  |    7 +
 .../cloudstack/api/response/UserVmResponse.java    |    7 +
 .../cloudstack/api/response/VolumeResponse.java    |    8 +
 .../WEB-INF/classes/resources/messages.properties  | 1857 ++--
 .../classes/resources/messages_fr_FR.properties    |  216 +-
 core/src/com/cloud/vm/UserVmVO.java                |    6 +-
 debian/rules                                       |    5 +-
 docs/en-US/Common_Content/feedback.xml             |   24 +
 docs/en-US/Preface.xml                             |    2 +-
 docs/en-US/Release_Notes.xml                       |11164 ++++++++-------
 docs/en-US/changed-API-commands-4.2.xml            |  123 +
 docs/en-US/feedback.xml                            |   24 +
 docs/en-US/hypervisor-kvm-install-flow.xml         |    2 +-
 .../hypervisor-support-for-primarystorage.xml      |  148 +-
 docs/en-US/limit-accounts-domains.xml              |  371 +
 docs/en-US/vm-snapshots.xml                        |   10 +-
 docs/en-US/work-with-usage.xml                     |   26 +-
 .../cloudstack/storage/image/ImageServiceImpl.java |   85 +-
 .../storage/motion/AncientDataMotionStrategy.java  |    5 +-
 packaging/centos63/package.sh                      |    1 +
 server/src/com/cloud/api/ApiDispatcher.java        |    9 -
 server/src/com/cloud/api/ApiResponseHelper.java    |   12 +
 server/src/com/cloud/api/ApiServer.java            |  155 +-
 server/src/com/cloud/api/ApiServerService.java     |    1 +
 server/src/com/cloud/api/ApiServlet.java           |    6 +-
 .../api/query/dao/DomainRouterJoinDaoImpl.java     |    1 +
 .../com/cloud/api/query/dao/HostJoinDaoImpl.java   |    1 +
 .../api/query/dao/StoragePoolJoinDaoImpl.java      |    1 +
 .../com/cloud/api/query/dao/UserVmJoinDaoImpl.java |    1 +
 .../com/cloud/api/query/dao/VolumeJoinDaoImpl.java |    3 +-
 .../com/cloud/api/query/vo/DomainRouterJoinVO.java |   12 +
 server/src/com/cloud/api/query/vo/HostJoinVO.java  |   11 +
 .../com/cloud/api/query/vo/StoragePoolJoinVO.java  |   11 +
 .../src/com/cloud/api/query/vo/UserVmJoinVO.java   |   13 +
 .../src/com/cloud/api/query/vo/VolumeJoinVO.java   |   15 +
 server/src/com/cloud/configuration/Config.java     |   17 +-
 .../configuration/ConfigurationManagerImpl.java    |   13 +-
 server/src/com/cloud/dc/dao/DataCenterDao.java     |    2 +
 server/src/com/cloud/dc/dao/DataCenterDaoImpl.java |    8 +
 .../ExternalLoadBalancerDeviceManagerImpl.java     |    4 +-
 .../src/com/cloud/network/NetworkServiceImpl.java  |    7 +-
 .../src/com/cloud/network/vpc/VpcManagerImpl.java  |   31 +-
 .../com/cloud/template/TemplateManagerImpl.java    |   17 +-
 .../com/cloud/usage/UsageNetworkOfferingVO.java    |   14 +-
 .../usage/dao/UsageNetworkOfferingDaoImpl.java     |    9 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  100 +-
 server/src/com/cloud/vm/UserVmStateListener.java   |   21 +-
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   13 +-
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |   48 +-
 server/test/com/cloud/vm/UserVmManagerTest.java    |   45 +-
 .../test/com/cloud/vm/dao/UserVmDaoImplTest.java   |   43 +-
 .../cloud/vm/dao/UserVmDaoTestConfiguration.java   |   50 +
 server/test/resources/UserVMDaoTestContext.xml     |   44 +
 setup/db/db/schema-40to410.sql                     |    4 +-
 setup/db/db/schema-410to420.sql                    |  337 +-
 test/integration/smoke/test_affinity_groups.py     |   10 +-
 .../smoke/test_deploy_vm_with_userdata.py          |  144 +
 test/integration/smoke/test_global_settings.py     |   33 +-
 test/integration/smoke/test_non_contigiousvlan.py  |  139 +-
 test/integration/smoke/test_public_ip_range.py     |    6 +-
 test/integration/smoke/test_vm_life_cycle.py       |   28 +-
 tools/build/build_asf.sh                           |   79 +-
 tools/build/setnextversion.sh                      |   75 +
 tools/marvin/marvin/asyncJobMgr.py                 |   70 +-
 tools/marvin/marvin/cloudstackConnection.py        |   51 +-
 tools/marvin/marvin/cloudstackTestClient.py        |   55 +-
 tools/marvin/marvin/codegenerator.py               |    4 +-
 tools/marvin/marvin/cs_entity_generator.py         |  202 +
 tools/marvin/marvin/dbConnection.py                |    6 +-
 tools/marvin/marvin/deployDataCenter.py            |    7 +
 .../factory/test/test_encapsulated_factory.py      |   35 +
 tools/marvin/marvin/factory/test/test_factories.py |  187 +
 tools/marvin/marvin/oldbase.py                     |  597 +-
 tools/marvin/marvin/remoteSSHClient.py             |   18 +-
 tools/marvin/marvin/utils.py                       |   17 +-
 usage/src/com/cloud/usage/UsageManagerImpl.java    |   10 +-
 91 files changed, 10196 insertions(+), 6916 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/server/src/com/cloud/network/vpc/VpcManagerImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/tools/marvin/marvin/cloudstackConnection.py
----------------------------------------------------------------------
diff --cc tools/marvin/marvin/cloudstackConnection.py
index f6589bb,9a4c387..5266c75
--- a/tools/marvin/marvin/cloudstackConnection.py
+++ b/tools/marvin/marvin/cloudstackConnection.py
@@@ -30,10 -30,11 +30,11 @@@ from requests import Timeou
  from requests import RequestException
  
  
 -class cloudConnection(object):
 +class CloudConnection(object):
      """ Connections to make API calls to the cloudstack management server
      """
-     def __init__(self, mgtSvr, port=8096, apiKey=None, securityKey=None,
+     def __init__(self, mgtSvr, port=8096, user=None, passwd=None,
+                  apiKey=None, securityKey=None,
                   asyncTimeout=3600, logging=None, scheme='http',
                   path='client/api'):
          self.apiKey = apiKey

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/tools/marvin/marvin/cs_entity_generator.py
----------------------------------------------------------------------
diff --cc tools/marvin/marvin/cs_entity_generator.py
index 0000000,0000000..f6d94c0
new file mode 100644
--- /dev/null
+++ b/tools/marvin/marvin/cs_entity_generator.py
@@@ -1,0 -1,0 +1,202 @@@
++# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements.  See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership.  The ASF licenses this file
++# to you 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 marvin
++from marvin.cloudstackAPI import *
++import os
++
++# Add verbs in grammar - same as cloudmonkey
++grammar = ['create', 'list', 'delete', 'update',
++           'enable', 'activate', 'disable', 'add', 'remove',
++           'attach', 'detach', 'associate', 'generate', 'ldap',
++           'assign', 'authorize', 'change', 'register', 'configure',
++           'start', 'restart', 'reboot', 'stop', 'reconnect',
++           'cancel', 'destroy', 'revoke', 'mark', 'reset',
++           'copy', 'extract', 'migrate', 'restore', 'suspend',
++           'get', 'query', 'prepare', 'deploy', 'upload', 'lock',
++           'disassociate', 'scale']
++
++LICENSE = """# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements.  See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership.  The ASF licenses this file
++# to you 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.
++"""
++
++
++def get_api_cmds():
++    api_classes = __import__('marvin.cloudstackAPI')
++
++    cmdlist = map(
++                    lambda f: getattr(api_classes.cloudstackAPI, f),
++                    filter(
++                        lambda t: t.startswith('__') == False,
++                        dir(api_classes.cloudstackAPI)
++                    )
++    )
++
++    cmdlist = filter(
++                lambda g: g is not None,
++                cmdlist
++    )
++
++    clslist = map(
++                lambda g: getattr(g, g.__name__.split('.')[-1] + 'Cmd'),
++                filter(
++                    lambda h: h.__name__.split('.')[-1] not in ['baseCmd', 'baseResponse', 'cloudstackAPIClient'],
++                    cmdlist
++                )
++    )
++
++    cmdlets = map(lambda t: t(), clslist)
++    return cmdlets
++
++def get_entity_from_api(api):
++    matching_verbs = filter(lambda v: api.__class__.__name__.startswith(v), grammar)
++    if len(matching_verbs) > 0:
++        verb = matching_verbs[0]
++        entity = api.__class__.__name__.replace(verb, '').replace('Cmd', '')
++        return entity
++
++def get_actionable_entities():
++    cmdlets = sorted(get_api_cmds(), key=lambda k: get_entity_from_api(k))
++    entities = {}
++    for cmd in cmdlets:
++        requireds = getattr(cmd, 'required')
++        optionals = filter(lambda x: '__' not in x and 'required' not in x and 'isAsync' not in x, dir(cmd))
++        matching_verbs = filter(lambda v: cmd.__class__.__name__.startswith(v), grammar)
++        if len(matching_verbs)> 0:
++            verb = matching_verbs[0]
++            entity = cmd.__class__.__name__.replace(verb, '').replace('Cmd', '')
++            if entity[:-1] in entities:
++                # Accounts and Account are the same entity
++                entity = entity[:-1]
++            if entity[:-2] in entities:
++                # IpAddresses and IpAddress are the same entity
++                entity = entity[:-2]
++            if entity not in entities:
++                entities[entity] = { }
++            entities[entity][verb] = {}
++            entities[entity][verb]['args'] = requireds
++            entities[entity][verb]['apimodule'] = cmd.__class__.__module__.split('.')[-1]
++            entities[entity][verb]['apicmd'] = cmd.__class__.__name__
++    return entities
++
++def write_entity_classes(entities):
++    tabspace = '    '
++    entitydict = {}
++    #TODO: Add license header for ASLv2
++    for entity, actions in entities.iteritems():
++        body = []
++        imports = []
++        imports.append('from marvin.integration.lib.base import CloudStackEntity')
++        body.append('class %s(CloudStackEntity.CloudStackEntity):'%entity)
++        body.append('\n')
++        body.append(tabspace + 'def __init__(self, items):')
++        body.append(tabspace*2 + 'self.__dict__.update(items)')
++        body.append('\n')
++        for action, details in actions.iteritems():
++            imports.append('from marvin.cloudstackAPI import %s'%details['apimodule'])
++            if action in ['create', 'list', 'deploy']:
++                body.append(tabspace + '@classmethod')
++            if action in ['create', 'deploy']:
++                body.append(tabspace + 'def %s(cls, apiclient, %sFactory, **kwargs):'%(action, entity))
++                body.append(tabspace*2 + 'cmd = %(module)s.%(command)s()'%{"module": details["apimodule"], "command": details["apicmd"]})
++                body.append(tabspace*2 + '[setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in %sFactory.__dict__.iteritems()]'%entity)
++                body.append(tabspace*2 + '[setattr(cmd, key, value) for key,value in kwargs.iteritems()]')
++                body.append(tabspace*2 + '%s = apiclient.%s(cmd)'%(entity.lower(), details['apimodule']))
++                body.append(tabspace*2 + 'return %s(%s.__dict__)'%(entity, entity.lower()))
++            else:
++                if len(details['args']) > 0:
++                    body.append(tabspace + 'def %s(self, apiclient, %s, **kwargs):'%(action, ', '.join(list(set(details['args'])))))
++                else:
++                    body.append(tabspace + 'def %s(self, apiclient, **kwargs):'%(action))
++                body.append(tabspace*2 + 'cmd = %(module)s.%(command)s()'%{"module": details["apimodule"], "command": details["apicmd"]})
++                if action not in ['create', 'list', 'deploy']:
++                    body.append(tabspace*2 + 'cmd.id = self.id')
++                for arg in details['args']:
++                    body.append(tabspace*2 + 'cmd.%s = %s'%(arg, arg))
++                body.append(tabspace*2 + '[setattr(cmd, key, value) for key,value in kwargs.iteritems()]')
++                body.append(tabspace*2 + '%s = apiclient.%s(cmd)'%(entity.lower(), details['apimodule']))
++                if action in ['list']:
++                    body.append(tabspace*2 + 'return map(lambda e: %s(e.__dict__), %s)'%(entity, entity.lower()))
++                else:
++                    body.append(tabspace*2 + 'return %s'%(entity.lower()))
++            body.append('\n')
++
++        imports = '\n'.join(imports)
++        body = '\n'.join(body)
++        code = imports + '\n\n' + body
++
++        entitydict[entity] = code
++        #write_entity_factory(entity, actions)
++        with open("./base/%s.py"%entity, "w") as writer:
++            writer.write(LICENSE)
++            writer.write(code)
++
++
++def write_entity_factory(entity, actions):
++    tabspace = '    '
++    #TODO: Add license header for ASLv2
++    code = ''
++    factory_defaults = []
++    if 'create' in actions:
++        factory_defaults.extend(actions['create']['args'])
++    elif 'deploy' in actions:
++        factory_defaults.extend(actions['deploy']['args'])
++    elif 'associate' in actions:
++        factory_defaults.extend(actions['associate']['args'])
++    elif 'register' in actions:
++        factory_defaults.extend(actions['register']['args'])
++    else:
++        return
++
++    if os.path.exists("./factory/%sFactory.py"%entity):
++        for arg in factory_defaults:
++            code += tabspace + '%s = None\n'%arg
++        with open("./factory/%sFactory.py"%entity, "r") as reader:
++            rcode = reader.read()
++            if rcode.find(code) > 0:
++                return
++        with open("./factory/%sFactory.py"%entity, "a") as writer:
++            writer.write(code)
++    else:
++        code += 'import factory\n'
++        code += 'from marvin.integration.lib.base import %s\n'%entity
++        code += 'class %sFactory(factory.Factory):'%entity
++        code += '\n\n'
++        code += tabspace + 'FACTORY_FOR = %s.%s\n\n'%(entity,entity)
++        for arg in factory_defaults:
++            code += tabspace + '%s = None\n'%arg
++        with open("./factory/%sFactory.py"%entity, "w") as writer:
++            writer.write(LICENSE)
++            writer.write(code)
++
++if __name__=='__main__':
++    entities = get_actionable_entities()
++    write_entity_classes(entities)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/tools/marvin/marvin/deployDataCenter.py
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/tools/marvin/marvin/factory/test/test_encapsulated_factory.py
----------------------------------------------------------------------
diff --cc tools/marvin/marvin/factory/test/test_encapsulated_factory.py
index 0000000,0000000..36c2c21
new file mode 100644
--- /dev/null
+++ b/tools/marvin/marvin/factory/test/test_encapsulated_factory.py
@@@ -1,0 -1,0 +1,35 @@@
++# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements.  See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership.  The ASF licenses this file
++# to you 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 unittest
++import logging
++
++from marvin.cloudstackTestClient import cloudstackTestClient
++
++from marvin.base import Account
++
++class TestEncapsulatedFactory(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost',
++            logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def test_accountEncapsulatedFactory(self):
++        account = Account.factory()
++        self.assert_(account is not None)
++
++    def tearDown(self):
++        pass

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5cea6012/tools/marvin/marvin/factory/test/test_factories.py
----------------------------------------------------------------------
diff --cc tools/marvin/marvin/factory/test/test_factories.py
index 0000000,0000000..31cdb40
new file mode 100644
--- /dev/null
+++ b/tools/marvin/marvin/factory/test/test_factories.py
@@@ -1,0 -1,0 +1,187 @@@
++# Licensed to the Apache Software Foundation (ASF) under one
++# or more contributor license agreements.  See the NOTICE file
++# distributed with this work for additional information
++# regarding copyright ownership.  The ASF licenses this file
++# to you 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 unittest
++import logging
++
++from marvin.cloudstackTestClient import cloudstackTestClient
++
++from marvin.factory.AccountFactory import *
++from marvin.factory.ServiceOfferingFactory import *
++from marvin.factory.NetworkOfferingFactory import *
++from marvin.factory.TemplateFactory import *
++from marvin.factory.VirtualMachineFactory import *
++from marvin.factory.UserFactory import *
++
++from marvin.base.ServiceOffering import ServiceOffering
++from marvin.base.Zone import Zone
++from marvin.base.Account import Account
++from marvin.base.Template import Template
++from marvin.base.IpAddress import IpAddress
++from marvin.base.Network import Network
++
++class BuildVsCreateStrategyTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def tearDown(self):
++        pass
++
++    def test_buildUserAccountFactory(self):
++        af = UserAccountFactory()
++        self.assert_(af.name is not None, msg="Acount factory didn't initialize")
++
++    def test_createAccountFactory(self):
++        af = AccountFactory.create(apiclient=self.apiClient)
++        self.assert_(isinstance(af, Account))
++        self.assert_(af.account.id is not None, msg="Account creation failed")
++        self.assert_(af.account.domain is not None, msg="Account belongs to no domain")
++
++
++class AccountFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def test_adminAccountFactory(self):
++        accnt = AdminAccountFactory.create(apiclient=self.apiClient)
++        self.assert_(accnt is not None, msg="no account created by factory")
++        self.assert_(accnt.account.name is not None)
++
++    def test_userAccountFactoryCustomArgs(self):
++        accnt = UserAccountFactory.create(apiclient=self.apiClient, firstname='test', lastname='test')
++        a = accnt.list(apiclient=self.apiClient, account=accnt.account.username, domainid=accnt.account.domainid)
++        self.assert_(accnt is not None, msg="no account created by factory")
++        self.assert_(accnt.account.name is not None)
++
++    @unittest.skip("Account doesn't deserialize correctly")
++    def test_disableAccountPostFactoryGeneration(self):
++        domadmin = DomainAdminFactory.create(apiclient=self.apiClient)
++        self.assert_(domadmin is not None, msg="no account was created")
++        domadmin.disable(self.apiClient, lock=True)
++
++    def tearDown(self):
++        pass
++
++
++class ServiceOfferingFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def test_serviceOfferingFactory(self):
++        soffering = ServiceOfferingFactory.create(apiclient=self.apiClient)
++        self.assert_(soffering is not None, msg="no service offering was created")
++        self.assert_(soffering.name is not None, msg="error in service offering factory creation")
++
++
++    def tearDown(self):
++        pass
++
++
++class NetworkOfferingFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def test_defaultSourceNatOfferingFactory(self):
++        snatOffering = DefaultIsolatedNetworkOfferingWithSourceNatServiceFactory.create(apiclient=self.apiClient)
++        self.assert_(snatOffering is not None, msg = "no network offering was created")
++        self.assert_(snatOffering.name is not None, msg="error in network offering creation")
++
++    def test_defaultSGOfferingEnable(self):
++        sgOffering = DefaultSharedNetworkOfferingWithSGServiceFactory.create(apiclient=self.apiClient)
++        sgOffering.update(self.apiClient, state='Enabled')
++
++    def tearDown(self):
++        pass
++
++
++class VirtualMachineFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def tearDown(self):
++        pass
++
++    def test_virtualMachineDeploy(self):
++        accnt = AccountFactory.create(apiclient=self.apiClient)
++        service = SmallServiceOfferingFactory.create(apiclient=self.apiClient)
++        tf = DefaultBuiltInTemplateFactory.build() #FIXME: Using build() strategy is confusing
++        zones = Zone.list(apiclient=self.apiClient)
++        template = Template.list(apiclient=self.apiClient,
++                                 templatefilter="featured",
++                                 ostype = tf.ostype,
++                                 zoneid = zones[0].id)
++        vm = VirtualMachineFactory.create(apiclient=self.apiClient,
++                                          serviceofferingid = service.id,
++                                          templateid = template[0].id,
++                                          zoneid = zones[0].id,
++                                          account = accnt.account.name,
++                                          domainid = accnt.account.domainid)
++        vm.destroy(apiclient=self.apiClient)
++
++
++
++class UserFactorySubFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def tearDown(self):
++        pass
++
++    def test_userSubFactory(self):
++        uf = UserFactory.create(apiclient=self.apiClient)
++        user = User.list(apiclient=self.apiClient, username=uf.username)
++        self.assert_(uf.username == user[0].username, msg="Usernames don't match")
++
++
++class IpAddressFactoryTest(unittest.TestCase):
++    def setUp(self):
++        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
++
++    def tearDown(self):
++        pass
++
++    def test_associateIpAddress(self):
++        all_ips = IpAddress.list(apiclient=self.apiClient)
++        self.assert_(len(all_ips) > 0, msg="No free public IPs")
++        firstip = all_ips[0]
++        firstip.associate(apiclient=self.apiClient, zoneid=firstip.zoneid)
++
++    def test_vpcAssociateIpAddress(self):
++        #FIXME: To be written
++        self.assert_(1 == 1)
++
++    def test_associateIpAddressToNetwork(self):
++        accnt = AccountFactory.create(apiclient=self.apiClient)
++        self.assert_(accnt is not None)
++        self.assert_(isinstance(accnt, Account))
++        service = ServiceOffering.list(apiclient=self.apiClient, displaytext='Small')
++        self.assert_(len(service) > 0)
++        template = Template.list(apiclient=self.apiClient, templatefilter="featured")
++        self.assert_(len(template) > 0)
++        zones = Zone.list(apiclient=self.apiClient)
++        vm = VirtualMachineFactory.create(
++            apiclient=self.apiClient,
++            serviceofferingid = service[0].id,
++            templateid = template[0].id,
++            zoneid = zones[0].id,
++            account=accnt.account.name,
++            domainid=accnt.account.domainid)
++        all_ips = IpAddress.list(apiclient=self.apiClient)
++        firstip = all_ips[0]
++        networks = Network.list(apiclient=self.apiClient, account = accnt.account.name, domainid = accnt.account.domainid)
++        firstip.associate(apiclient=self.apiClient, networkid = networks[0].id)
++        vm.destroy(apiclient=self.apiClient)