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 <t...@apache.org> Authored: Wed Apr 24 22:10:48 2013 +0530 Committer: Prasanna Santhanam <t...@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)