From 051ba3cd707699d8ea4c74d134894daea0deeeed Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 17 May 2012 18:10:55 +0530 Subject: [PATCH] Files from the demo are now available in the sandbox --- tools/marvin/marvin/sandbox/demo/README | 4 - tools/marvin/marvin/sandbox/demo/live/README | 8 + .../demo/{ => live}/testSshDeployVM.py | 143 +- .../marvin/sandbox/demo/simulator/README | 12 + .../sandbox/demo/{ => simulator}/__init__.py | 0 .../sandbox/demo/simulator/simulator_setup.py | 117 ++ .../demo/simulator/simulatordemo.properties | 39 + .../demo/simulator/testcase/__init__.py | 0 .../demo/simulator/testcase/libs/__init__.py | 0 .../demo/simulator/testcase/libs/base.py | 1423 +++++++++++++++++ .../demo/simulator/testcase/libs/common.py | 447 ++++++ .../demo/simulator/testcase/libs/utils.py | 102 ++ .../simulator/testcase/test_vm_life_cycle.py | 519 ++++++ .../marvin/sandbox/demo/testDeployVM.py | 98 -- 14 files changed, 2729 insertions(+), 183 deletions(-) delete mode 100644 tools/marvin/marvin/sandbox/demo/README create mode 100644 tools/marvin/marvin/sandbox/demo/live/README rename tools/marvin/marvin/sandbox/demo/{ => live}/testSshDeployVM.py (60%) create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/README rename tools/marvin/marvin/sandbox/demo/{ => simulator}/__init__.py (100%) create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/simulatordemo.properties create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/__init__.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/__init__.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/base.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/common.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py create mode 100644 tools/marvin/marvin/sandbox/demo/simulator/testcase/test_vm_life_cycle.py delete mode 100644 tools/marvin/marvin/sandbox/demo/testDeployVM.py diff --git a/tools/marvin/marvin/sandbox/demo/README b/tools/marvin/marvin/sandbox/demo/README deleted file mode 100644 index 650ea05df1c..00000000000 --- a/tools/marvin/marvin/sandbox/demo/README +++ /dev/null @@ -1,4 +0,0 @@ -Demo files for use with the tutorial on "Testing with Python". - -testDeployVM.py - to be run against a 2.2.y installation of management server -testSshDeployVM.py - to be run against a 3.0.x installation of management server diff --git a/tools/marvin/marvin/sandbox/demo/live/README b/tools/marvin/marvin/sandbox/demo/live/README new file mode 100644 index 00000000000..8ca0f4cf763 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/live/README @@ -0,0 +1,8 @@ + +Download Marvin source from hudson + +Install Marvin: +pip install Marvin-0.1.0.tar.gz + +To Run the test: +python -m marvin.deployAndRun -c demo.cfg -t /tmp/t.log -r /tmp/r.log -f testSshDeployVM.py -l diff --git a/tools/marvin/marvin/sandbox/demo/testSshDeployVM.py b/tools/marvin/marvin/sandbox/demo/live/testSshDeployVM.py similarity index 60% rename from tools/marvin/marvin/sandbox/demo/testSshDeployVM.py rename to tools/marvin/marvin/sandbox/demo/live/testSshDeployVM.py index 106f693fda1..63728eff1d3 100644 --- a/tools/marvin/marvin/sandbox/demo/testSshDeployVM.py +++ b/tools/marvin/marvin/sandbox/demo/live/testSshDeployVM.py @@ -14,77 +14,30 @@ -from cloudstackTestCase import * -from remoteSSHClient import remoteSSHClient +import marvin +from marvin.cloudstackTestCase import * +from marvin.remoteSSHClient import remoteSSHClient -import unittest -import hashlib -import random -import string -class TestDeployVm(cloudstackTestCase): +@UserName('demo', 'ROOT', '0') +class TestSshDeployVm(cloudstackTestCase): """ This test deploys a virtual machine into a user account using the small service offering and builtin template """ - @classmethod - def setUpClass(cls): - """ - CloudStack internally saves its passwords in md5 form and that is how we - specify it in the API. Python's hashlib library helps us to quickly hash - strings as follows - """ - mdf = hashlib.md5() - mdf.update('password') - mdf_pass = mdf.hexdigest() - acctName = 'bugs-'+''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) #randomly generated account + def setUp(self): + self.apiClient = self.testClient.getApiClient() - cls.apiClient = super(TestDeployVm, cls).getClsTestClient().getApiClient() - cls.acct = createAccount.createAccountCmd() #The createAccount command - cls.acct.accounttype = 0 #We need a regular user. admins have accounttype=1 - cls.acct.firstname = 'bugs' - cls.acct.lastname = 'bunny' #What's up doc? - cls.acct.password = mdf_pass #The md5 hashed password string - cls.acct.username = acctName - cls.acct.email = 'bugs@rabbithole.com' - cls.acct.account = acctName - cls.acct.domainid = 1 #The default ROOT domain - cls.acctResponse = cls.apiClient.createAccount(cls.acct) - - def setUpNAT(self, virtualmachineid): - listSourceNat = listPublicIpAddresses.listPublicIpAddressesCmd() - listSourceNat.account = self.acct.account - listSourceNat.domainid = self.acct.domainid - listSourceNat.issourcenat = True - - listsnatresponse = self.apiClient.listPublicIpAddresses(listSourceNat) - self.assertNotEqual(len(listsnatresponse), 0, "Found a source NAT for the acct %s"%self.acct.account) - - snatid = listsnatresponse[0].id - snatip = listsnatresponse[0].ipaddress - - try: - createFwRule = createFirewallRule.createFirewallRuleCmd() - createFwRule.cidrlist = "0.0.0.0/0" - createFwRule.startport = 22 - createFwRule.endport = 22 - createFwRule.ipaddressid = snatid - createFwRule.protocol = "tcp" - createfwresponse = self.apiClient.createFirewallRule(createFwRule) - - createPfRule = createPortForwardingRule.createPortForwardingRuleCmd() - createPfRule.privateport = 22 - createPfRule.publicport = 22 - createPfRule.virtualmachineid = virtualmachineid - createPfRule.ipaddressid = snatid - createPfRule.protocol = "tcp" - - createpfresponse = self.apiClient.createPortForwardingRule(createPfRule) - except e: - self.debug("Failed to create PF rule in account %s due to %s"%(self.acct.account, e)) - raise e - finally: - return snatip + self.zone = listZones.listZonesCmd() + self.zone.uuid = self.apiClient.listZones(self.zone)[0].id + + self.service_offering = listServiceOfferings.listServiceOfferingsCmd() + self.service_offering.uuid = self.apiClient.listServiceOfferings(self.service_offering)[0].id + + self.template = listTemplates.listTemplatesCmd() + self.template.templatefilter = 'featured' + self.template.name = 'CentOS' + self.template.uuid = self.apiClient.listTemplates(self.template)[0].id def test_DeployVm(self): """ @@ -95,11 +48,9 @@ class TestDeployVm(cloudstackTestCase): The hardcoded values are used only for brevity. """ deployVmCmd = deployVirtualMachine.deployVirtualMachineCmd() - deployVmCmd.zoneid = 1 - deployVmCmd.account = self.acct.account - deployVmCmd.domainid = self.acct.domainid - deployVmCmd.templateid = 5 #CentOS 5.6 builtin - deployVmCmd.serviceofferingid = 1 + deployVmCmd.zoneid = self.zone.uuid + deployVmCmd.templateid = self.template.uuid #CentOS 5.6 builtin + deployVmCmd.serviceofferingid = self.service_offering.uuid deployVmResponse = self.apiClient.deployVirtualMachine(deployVmCmd) self.debug("VM %s was deployed in the job %s"%(deployVmResponse.id, deployVmResponse.jobid)) @@ -115,6 +66,8 @@ class TestDeployVm(cloudstackTestCase): returns a non-empty response") vm = listVmResponse[0] + self.assertEqual(vm.state, "Running", "Check if VM has reached Running state in CS") + hostname = vm.name nattedip = self.setUpNAT(vm.id) @@ -126,18 +79,46 @@ class TestDeployVm(cloudstackTestCase): a state of running") # SSH login and compare hostname - ssh_client = remoteSSHClient(nattedip, 22, "root", "password") + self.debug("Attempting to SSH into %s over %s of %s"%(nattedip, "22", vm.name)) + ssh_client = remoteSSHClient(nattedip, "22", "root", "password") stdout = ssh_client.execute("hostname") - - self.assertEqual(hostname, stdout[0], "cloudstack VM name and hostname match") + self.assertEqual(hostname, stdout[0], "cloudstack VM name and hostname \ + do not match") - @classmethod - def tearDownClass(cls): - """ - And finally let us cleanup the resources we created by deleting the - account. All good unittests are atomic and rerunnable this way - """ - deleteAcct = deleteAccount.deleteAccountCmd() - deleteAcct.id = cls.acctResponse.account.id - cls.apiClient.deleteAccount(deleteAcct) + def setUpNAT(self, virtualmachineid): + listSourceNat = listPublicIpAddresses.listPublicIpAddressesCmd() + listSourceNat.issourcenat = True + + listsnatresponse = self.apiClient.listPublicIpAddresses(listSourceNat) + self.assertNotEqual(len(listsnatresponse), 0, "Found a source NAT for the account user") + + snatid = listsnatresponse[0].id + snatip = listsnatresponse[0].ipaddress + + try: + createFwRule = createFirewallRule.createFirewallRuleCmd() + createFwRule.cidrlist = "0.0.0.0/0" + createFwRule.startport = 22 + createFwRule.endport = 22 + createFwRule.ipaddressid = snatid + createFwRule.protocol = "tcp" + createfwresponse = self.apiClient.createFirewallRule(createFwRule) + + createPfRule = createPortForwardingRule.createPortForwardingRuleCmd() + createPfRule.publicport = 22 + createPfRule.privateport = 22 + createPfRule.virtualmachineid = virtualmachineid + createPfRule.ipaddressid = snatid + createPfRule.protocol = "tcp" + + createpfresponse = self.apiClient.createPortForwardingRule(createPfRule) + except e: + self.debug("Failed to create PF rule in the account due to %s"%e) + raise e + finally: + self.debug("Successfully programmed PF rule for :%s"%snatip) + return snatip + + def tearDown(self): + self.testClient.close() diff --git a/tools/marvin/marvin/sandbox/demo/simulator/README b/tools/marvin/marvin/sandbox/demo/simulator/README new file mode 100644 index 00000000000..d34ca9f80ec --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/README @@ -0,0 +1,12 @@ +To generate the config +Alter the .properties file to point to your simulator installed environment + +python simulator_setup.py -i simulatordemo.properties -o simulatordemo.cfg + + +To deploy the environment and run the tests + +python -m marvin.deployAndRun -c simulatordemo.cfg -t /tmp/t.log -r /tmp/r.log -d testcase + + + diff --git a/tools/marvin/marvin/sandbox/demo/__init__.py b/tools/marvin/marvin/sandbox/demo/simulator/__init__.py similarity index 100% rename from tools/marvin/marvin/sandbox/demo/__init__.py rename to tools/marvin/marvin/sandbox/demo/simulator/__init__.py diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py new file mode 100644 index 00000000000..ee800761df9 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python + +from ConfigParser import SafeConfigParser +from optparse import OptionParser +from configGenerator import * +import random + + +def getGlobalSettings(config): + for k, v in dict(config.items('globals')).iteritems(): + cfg = configuration() + cfg.name = k + cfg.value = v + yield cfg + + +def describeResources(config): + zs = cloudstackConfiguration() + + z = zone() + z.dns1 = config.get('environment', 'dns') + z.internaldns1 = config.get('environment', 'dns') + z.name = 'Sandbox-%s'%(config.get('environment', 'hypervisor')) + z.networktype = 'Advanced' + z.guestcidraddress = '10.1.1.0/24' + z.vlan = config.get('cloudstack', 'zone.vlan') + + p = pod() + p.name = 'POD0' + p.gateway = config.get('cloudstack', 'private.gateway') + p.startip = config.get('cloudstack', 'private.pod.startip') + p.endip = config.get('cloudstack', 'private.pod.endip') + p.netmask = '255.255.255.0' + + v = iprange() + v.gateway = config.get('cloudstack', 'public.gateway') + v.startip = config.get('cloudstack', 'public.vlan.startip') + v.endip = config.get('cloudstack', 'public.vlan.endip') + v.netmask = '255.255.255.0' + v.vlan = config.get('cloudstack', 'public.vlan') + z.ipranges.append(v) + + c = cluster() + c.clustername = 'C0' + c.hypervisor = config.get('environment', 'hypervisor') + c.clustertype = 'CloudManaged' + + h = host() + h.username = 'root' + h.password = 'password' + h.url = 'http://%s'%(config.get('cloudstack', 'host')) + c.hosts.append(h) + + h = host() + h.username = 'root' + h.password = 'password' + h.url = 'http://%s'%(config.get('cloudstack', 'host2')) + c.hosts.append(h) + + ps = primaryStorage() + ps.name = 'PS0' + ps.url = config.get('cloudstack', 'pool') + c.primaryStorages.append(ps) + + p.clusters.append(c) + z.pods.append(p) + + secondary = secondaryStorage() + secondary.url = config.get('cloudstack', 'secondary') + z.secondaryStorages.append(secondary) + + '''Add zone''' + zs.zones.append(z) + + '''Add mgt server''' + mgt = managementServer() + mgt.mgtSvrIp = config.get('environment', 'mshost') + zs.mgtSvr.append(mgt) + + '''Add a database''' + db = dbServer() + db.dbSvr = config.get('environment', 'dbhost') + db.passwd = config.get('environment', 'dbpasswd') + zs.dbSvr = db + + '''Add some configuration''' + [zs.globalConfig.append(cfg) for cfg in getGlobalSettings(config)] + + ''''add loggers''' + testClientLogger = logger() + testClientLogger.name = 'TestClient' + testClientLogger.file = '/var/log/testclient.log' + + testCaseLogger = logger() + testCaseLogger.name = 'TestCase' + testCaseLogger.file = '/var/log/testcase.log' + + zs.logger.append(testClientLogger) + zs.logger.append(testCaseLogger) + return zs + + +if __name__ == '__main__': + parser = OptionParser() + parser.add_option('-i', '--input', action='store', default='setup.properties', \ + dest='input', help='file containing environment setup information') + parser.add_option('-o', '--output', action='store', default='./sandbox.cfg', \ + dest='output', help='path where environment json will be generated') + + + (opts, args) = parser.parse_args() + + cfg_parser = SafeConfigParser() + cfg_parser.read(opts.input) + + cfg = describeResources(cfg_parser) + generate_setup_config(cfg, opts.output) diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulatordemo.properties b/tools/marvin/marvin/sandbox/demo/simulator/simulatordemo.properties new file mode 100644 index 00000000000..ef01fb8e628 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulatordemo.properties @@ -0,0 +1,39 @@ +[globals] +expunge.delay=60 +expunge.interval=60 +storage.cleanup.interval=300 +account.cleanup.interval=600 +expunge.workers=3 +workers=10 +use.user.concentrated.pod.allocation=false +vm.allocation.algorithm=random +vm.op.wait.interval=5 +guest.domain.suffix=sandbox.simulator +instance.name=QA +direct.agent.load.size=1000 +default.page.size=10000 +check.pod.cidrs=true +secstorage.allowed.internal.sites=10.147.28.0/24 +[environment] +dns=4.2.2.2 +mshost=10.223.132.171 +dbhost=10.223.132.171 +dbpasswd= +hypervisor=simulator +[cloudstack] +zone.vlan=100-200 +#pod configuration +private.gateway=172.16.15.1 +private.pod.startip=172.16.15.2 +private.pod.endip=172.16.15.200 +#public vlan range +public.gateway=192.168.2.1 +public.vlan=50 +public.vlan.startip=192.168.2.2 +public.vlan.endip=192.168.2.200 +#hosts +host=simulator.host.vmops.com +host2=simulator-2.host.vmops.com +#pools +pool=nfs://172.16.15.30/export/share/primary +secondary=nfs://172.16.15.30/export/share/secondary diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/__init__.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/__init__.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/base.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/base.py new file mode 100644 index 00000000000..e2fd5d74c81 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/base.py @@ -0,0 +1,1423 @@ +# -*- encoding: utf-8 -*- +# +# Copyright (c) 2012 Citrix. All rights reserved. +# + +""" Base class for all Cloudstack resources + -Virtual machine, Volume, Snapshot etc +""" + +from utils import is_server_ssh_ready, random_gen +from marvin.cloudstackAPI import * +#Import System modules +import time +import hashlib +import base64 +import types + + +class Domain: + """ Domain Life Cycle """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, name=None, networkdomain=None, + parentdomainid=None): + """Creates an domain""" + + cmd = createDomain.createDomainCmd() + + if name: + cmd.name = "-".join([name, random_gen()]) + elif "name" in services: + cmd.name = "-".join([services["name"], random_gen()]) + + if networkdomain: + cmd.networkdomain = networkdomain + elif "networkdomain" in services: + cmd.networkdomain = services["networkdomain"] + + if parentdomainid: + cmd.parentdomainid = parentdomainid + elif "parentdomainid" in services: + cmd.parentdomainid = services["parentdomainid"] + + return Domain(apiclient.createDomain(cmd).__dict__) + + def delete(self, apiclient, cleanup=None): + """Delete an domain""" + cmd = deleteDomain.deleteDomainCmd() + cmd.id = self.id + if cleanup: + cmd.cleanup = cleanup + apiclient.deleteDomain(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists domains""" + cmd = listDomains.listDomainsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDomains(cmd)) + + +class Account: + """ Account Life Cycle """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, admin=False, domainid=None): + """Creates an account""" + cmd = createAccount.createAccountCmd() + + #0 - User, 1 - Root Admin, 2 - Domain Admin + cmd.accounttype = 2 if (admin and domainid) else int(admin) + + cmd.email = services["email"] + cmd.firstname = services["firstname"] + cmd.lastname = services["lastname"] + + # Password Encoding + mdf = hashlib.md5() + mdf.update(services["password"]) + cmd.password = mdf.hexdigest() + cmd.username = "-".join([services["username"], random_gen()]) + + if domainid: + cmd.domainid = domainid + account = apiclient.createAccount(cmd) + + return Account(account.__dict__) + + def delete(self, apiclient): + """Delete an account""" + cmd = deleteAccount.deleteAccountCmd() + cmd.id = self.account.id + apiclient.deleteAccount(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists accounts and provides detailed account information for + listed accounts""" + + cmd = listAccounts.listAccountsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAccounts(cmd)) + + +class User: + """ User Life Cycle """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, account, domainid): + cmd = createUser.createUserCmd() + """Creates an user""" + + cmd.account = account + cmd.domainid = domainid + cmd.email = services["email"] + cmd.firstname = services["firstname"] + cmd.lastname = services["lastname"] + + # Password Encoding + mdf = hashlib.md5() + mdf.update(services["password"]) + cmd.password = mdf.hexdigest() + cmd.username = "-".join([services["username"], random_gen()]) + user = apiclient.createUser(cmd) + + return User(user.__dict__) + + def delete(self, apiclient): + """Delete an account""" + cmd = deleteUser.deleteUserCmd() + cmd.id = self.id + apiclient.deleteUser(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists users and provides detailed account information for + listed users""" + + cmd = listUsers.listUsersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listUsers(cmd)) + + +class VirtualMachine: + """Manage virtual machine lifecycle""" + + def __init__(self, items, services): + self.__dict__.update(items) + self.username = services["username"] + self.password = services["password"] + self.ssh_port = services["ssh_port"] + self.ssh_client = None + #extract out the ipaddress + self.ipaddress = self.nic[0].ipaddress + + @classmethod + def create(cls, apiclient, services, templateid=None, accountid=None, + domainid=None, networkids=None, serviceofferingid=None, + securitygroupids=None, mode='basic'): + """Create the instance""" + + cmd = deployVirtualMachine.deployVirtualMachineCmd() + + if serviceofferingid: + cmd.serviceofferingid = serviceofferingid + elif "serviceoffering" in services: + cmd.serviceofferingid = services["serviceoffering"] + + cmd.zoneid = services["zoneid"] + cmd.hypervisor = services["hypervisor"] + + if accountid: + cmd.account = accountid + elif "account" in services: + cmd.account = services["account"] + + if domainid: + cmd.domainid = domainid + elif "domainid" in services: + cmd.domainid = services["domainid"] + + if networkids: + cmd.networkids = networkids + elif "networkids" in services: + cmd.networkids = services["networkids"] + + if templateid: + cmd.templateid = templateid + elif "template" in services: + cmd.templateid = services["template"] + + if "diskoffering" in services: + cmd.diskofferingid = services["diskoffering"] + + if securitygroupids: + cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids] + + if "userdata" in services: + cmd.userdata = base64.b64encode(services["userdata"]) + + virtual_machine = apiclient.deployVirtualMachine(cmd) + + # VM should be in Running state after deploy + timeout = 10 + while True: + vm_status = VirtualMachine.list( + apiclient, + id=virtual_machine.id + ) + if isinstance(vm_status, list): + if vm_status[0].state == 'Running': + break + elif timeout == 0: + raise Exception( + "TimeOutException: Failed to start VM (ID: %s)" % + virtual_machine.id) + + time.sleep(10) + timeout = timeout -1 + + return VirtualMachine(virtual_machine.__dict__, services) + + def start(self, apiclient): + """Start the instance""" + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.id = self.id + apiclient.startVirtualMachine(cmd) + + def stop(self, apiclient): + """Stop the instance""" + cmd = stopVirtualMachine.stopVirtualMachineCmd() + cmd.id = self.id + apiclient.stopVirtualMachine(cmd) + + def reboot(self, apiclient): + """Reboot the instance""" + cmd = rebootVirtualMachine.rebootVirtualMachineCmd() + cmd.id = self.id + apiclient.rebootVirtualMachine(cmd) + + + def delete(self, apiclient): + """Destroy an Instance""" + cmd = destroyVirtualMachine.destroyVirtualMachineCmd() + cmd.id = self.id + apiclient.destroyVirtualMachine(cmd) + + def attach_volume(self, apiclient, volume): + """Attach volume to instance""" + cmd = attachVolume.attachVolumeCmd() + cmd.id = volume.id + cmd.virtualmachineid = self.id + return apiclient.attachVolume(cmd) + + def detach_volume(self, apiclient, volume): + """Detach volume to instance""" + cmd = detachVolume.detachVolumeCmd() + cmd.id = volume.id + return apiclient.detachVolume(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all VMs matching criteria""" + + cmd = listVirtualMachines.listVirtualMachinesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVirtualMachines(cmd)) + + +class Volume: + """Manage Volume Lifecycle + """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, zoneid=None, account=None, domainid=None, + diskofferingid=None): + """Create Volume""" + cmd = createVolume.createVolumeCmd() + cmd.name = services["diskname"] + + if diskofferingid: + cmd.diskofferingid = diskofferingid + elif "diskofferingid" in services: + cmd.diskofferingid = services["diskofferingid"] + + if zoneid: + cmd.zoneid = zoneid + elif "zoneid" in services: + cmd.zoneid = services["zoneid"] + + if account: + cmd.account = account + elif "account" in services: + cmd.account = services["account"] + + if domainid: + cmd.domainid = domainid + elif "domainid" in services: + cmd.domainid = services["domainid"] + + return Volume(apiclient.createVolume(cmd).__dict__) + + @classmethod + def create_custom_disk(cls, apiclient, services, account=None, domainid=None): + """Create Volume from Custom disk offering""" + cmd = createVolume.createVolumeCmd() + cmd.name = services["diskname"] + cmd.diskofferingid = services["customdiskofferingid"] + cmd.size = services["customdisksize"] + cmd.zoneid = services["zoneid"] + + if account: + cmd.account = account + else: + cmd.account = services["account"] + + if domainid: + cmd.domainid = domainid + else: + cmd.domainid = services["domainid"] + + return Volume(apiclient.createVolume(cmd).__dict__) + + @classmethod + def create_from_snapshot(cls, apiclient, snapshot_id, services, + account=None, domainid=None): + """Create Volume from snapshot""" + cmd = createVolume.createVolumeCmd() + cmd.name = "-".join([services["diskname"], random_gen()]) + cmd.snapshotid = snapshot_id + cmd.zoneid = services["zoneid"] + cmd.size = services["size"] + if account: + cmd.account = account + else: + cmd.account = services["account"] + if domainid: + cmd.domainid = domainid + else: + cmd.domainid = services["domainid"] + return Volume(apiclient.createVolume(cmd).__dict__) + + def delete(self, apiclient): + """Delete Volume""" + cmd = deleteVolume.deleteVolumeCmd() + cmd.id = self.id + apiclient.deleteVolume(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all volumes matching criteria""" + + cmd = listVolumes.listVolumesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVolumes(cmd)) + + +class Snapshot: + """Manage Snapshot Lifecycle + """ + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, volume_id, account=None, domainid=None): + """Create Snapshot""" + cmd = createSnapshot.createSnapshotCmd() + cmd.volumeid = volume_id + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + return Snapshot(apiclient.createSnapshot(cmd).__dict__) + + def delete(self, apiclient): + """Delete Snapshot""" + cmd = deleteSnapshot.deleteSnapshotCmd() + cmd.id = self.id + apiclient.deleteSnapshot(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all snapshots matching criteria""" + + cmd = listSnapshots.listSnapshotsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshots(cmd)) + + +class Template: + """Manage template life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, volumeid=None, + account=None, domainid=None): + """Create template from Volume""" + #Create template from Virtual machine and Volume ID + cmd = createTemplate.createTemplateCmd() + cmd.displaytext = services["displaytext"] + cmd.name = "-".join([services["name"], random_gen()]) + cmd.ostypeid = services["ostypeid"] + + cmd.isfeatured = services["isfeatured"] if "isfeatured" in services else False + cmd.ispublic = services["ispublic"] if "ispublic" in services else False + cmd.isextractable = services["isextractable"] if "isextractable" in services else False + cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False + + if volumeid: + cmd.volumeid = volumeid + + if account: + cmd.account = account + + if domainid: + cmd.domainid = domainid + + return Template(apiclient.createTemplate(cmd).__dict__) + + @classmethod + def register(cls, apiclient, services, zoneid=None, account=None, domainid=None): + """Create template from URL""" + + #Create template from Virtual machine and Volume ID + cmd = registerTemplate.registerTemplateCmd() + cmd.displaytext = services["displaytext"] + cmd.name = "-".join([services["name"], random_gen()]) + cmd.format = services["format"] + cmd.hypervisor = services["hypervisor"] + cmd.ostypeid = services["ostypeid"] + cmd.url = services["url"] + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + cmd.isfeatured = services["isfeatured"] if "isfeatured" in services else False + cmd.ispublic = services["ispublic"] if "ispublic" in services else False + cmd.isextractable = services["isextractable"] if "isextractable" in services else False + + if account: + cmd.account = account + + if domainid: + cmd.domainid = domainid + + # Register Template + template = apiclient.registerTemplate(cmd) + + if isinstance(template, list): + return Template(template[0].__dict__) + + @classmethod + def create_from_snapshot(cls, apiclient, snapshot, services, random_name=True): + """Create Template from snapshot""" + #Create template from Virtual machine and Snapshot ID + cmd = createTemplate.createTemplateCmd() + cmd.displaytext = services["displaytext"] + cmd.name = "-".join([ + services["name"], + random_gen() + ]) if random_name else services["name"] + cmd.ostypeid = services["ostypeid"] + cmd.snapshotid = snapshot.id + return Template(apiclient.createTemplate(cmd).__dict__) + + def delete(self, apiclient): + """Delete Template""" + + cmd = deleteTemplate.deleteTemplateCmd() + cmd.id = self.id + apiclient.deleteTemplate(cmd) + + def download(self, apiclient, timeout=5, interval=60): + """Download Template""" + #Sleep to ensure template is in proper state before download + time.sleep(interval) + + while True: + template_response = Template.list( + apiclient, + id=self.id, + zoneid=self.zoneid, + templatefilter='self' + ) + if isinstance(template_response, list): + + template = template_response[0] + # If template is ready, + # template.status = Download Complete + # Downloading - x% Downloaded + # Error - Any other string + if template.status == 'Download Complete': + break + + elif 'Downloaded' in template.status: + time.sleep(interval) + + elif 'Installing' not in template.status: + raise Exception("ErrorInDownload") + + elif timeout == 0: + break + + else: + time.sleep(interval) + timeout = timeout - 1 + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all templates matching criteria""" + + cmd = listTemplates.listTemplatesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTemplates(cmd)) + + +class Iso: + """Manage ISO life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, account=None, domainid=None): + """Create an ISO""" + #Create ISO from URL + cmd = registerIso.registerIsoCmd() + cmd.displaytext = services["displaytext"] + cmd.name = services["name"] + cmd.ostypeid = services["ostypeid"] + cmd.url = services["url"] + cmd.zoneid = services["zoneid"] + + if "isextractable" in services: + cmd.isextractable = services["isextractable"] + if "isfeatured" in services: + cmd.isfeatured = services["isfeatured"] + if "ispublic" in services: + cmd.ispublic = services["ispublic"] + + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + # Register ISO + iso = apiclient.registerIso(cmd) + + if iso: + return Iso(iso[0].__dict__) + + def delete(self, apiclient): + """Delete an ISO""" + cmd = deleteIso.deleteIsoCmd() + cmd.id = self.id + apiclient.deleteIso(cmd) + return + + def download(self, apiclient, timeout=5, interval=60): + """Download an ISO""" + #Ensuring ISO is successfully downloaded + while True: + time.sleep(interval) + + cmd = listIsos.listIsosCmd() + cmd.id = self.id + iso_response = apiclient.listIsos(cmd) + + if isinstance(iso_response, list): + response = iso_response[0] + # Again initialize timeout to avoid listISO failure + timeout = 5 + + # Check whether download is in progress(for Ex:10% Downloaded) + # or ISO is 'Successfully Installed' + if response.status == 'Successfully Installed': + return + + elif 'Downloaded' in response.status: + time.sleep(interval) + + elif 'Installing' not in response.status: + raise Exception("ErrorInDownload") + + elif timeout == 0: + raise Exception("TimeoutException") + else: + timeout = timeout - 1 + return + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all available ISO files.""" + + cmd = listIsos.listIsosCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listIsos(cmd)) + + +class PublicIPAddress: + """Manage Public IP Addresses""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, accountid, zoneid=None, domainid=None, + services=None, networkid=None): + """Associate Public IP address""" + cmd = associateIpAddress.associateIpAddressCmd() + cmd.account = accountid + cmd.zoneid = zoneid or services["zoneid"] + cmd.domainid = domainid or services["domainid"] + + if networkid: + cmd.networkid = networkid + + return PublicIPAddress(apiclient.associateIpAddress(cmd).__dict__) + + def delete(self, apiclient): + """Dissociate Public IP address""" + cmd = disassociateIpAddress.disassociateIpAddressCmd() + cmd.id = self.ipaddress.id + apiclient.disassociateIpAddress(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Public IPs matching criteria""" + + cmd = listPublicIpAddresses.listPublicIpAddressesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPublicIpAddresses(cmd)) + +class NATRule: + """Manage port forwarding rule""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, virtual_machine, services, ipaddressid=None): + """Create Port forwarding rule""" + cmd = createPortForwardingRule.createPortForwardingRuleCmd() + + if ipaddressid: + cmd.ipaddressid = ipaddressid + elif "ipaddressid" in services: + cmd.ipaddressid = services["ipaddressid"] + + cmd.privateport = services["privateport"] + cmd.publicport = services["publicport"] + cmd.protocol = services["protocol"] + cmd.virtualmachineid = virtual_machine.id + + return NATRule(apiclient.createPortForwardingRule(cmd).__dict__) + + def delete(self, apiclient): + """Delete port forwarding""" + cmd = deletePortForwardingRule.deletePortForwardingRuleCmd() + cmd.id = self.id + apiclient.deletePortForwardingRule(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all NAT rules matching criteria""" + + cmd = listPortForwardingRules.listPortForwardingRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPortForwardingRules(cmd)) + + +class StaticNATRule: + """Manage Static NAT rule""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, ipaddressid=None): + """Creates static ip forwarding rule""" + + cmd = createIpForwardingRule.createIpForwardingRuleCmd() + cmd.protocol = services["protocol"] + cmd.startport = services["startport"] + + if "endport" in services: + cmd.endport = services["endport"] + + if "cidrlist" in services: + cmd.cidrlist = services["cidrlist"] + + if ipaddressid: + cmd.ipaddressid = ipaddressid + elif "ipaddressid" in services: + cmd.ipaddressid = services["ipaddressid"] + + return StaticNATRule(apiclient.createIpForwardingRule(cmd).__dict__) + + def delete(self, apiclient): + """Delete IP forwarding rule""" + cmd = deleteIpForwardingRule.deleteIpForwardingRuleCmd() + cmd.id = self.id + apiclient.deleteIpForwardingRule(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all IP forwarding rules matching criteria""" + + cmd = listIpForwardingRules.listIpForwardingRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listIpForwardingRules(cmd)) + + @classmethod + def enable(cls, apiclient, ipaddressid, virtualmachineid): + """Enables Static NAT rule""" + + cmd = enableStaticNat.enableStaticNatCmd() + cmd.ipaddressid = ipaddressid + cmd.virtualmachineid = virtualmachineid + apiclient.enableStaticNat(cmd) + return + + @classmethod + def disable(cls, apiclient, ipaddressid, virtualmachineid): + """Disables Static NAT rule""" + + cmd = disableStaticNat.disableStaticNatCmd() + cmd.ipaddressid = ipaddressid + apiclient.disableStaticNat(cmd) + return + + +class FireWallRule: + """Manage Firewall rule""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, ipaddressid, protocol, cidrlist=None, + startport=None, endport=None): + """Create Firewall Rule""" + cmd = createFirewallRule.createFirewallRuleCmd() + cmd.ipaddressid = ipaddressid + cmd.protocol = protocol + if cidrlist: + cmd.cidrlist = cidrlist + if startport: + cmd.startport = startport + if endport: + cmd.endport = endport + + return FireWallRule(apiclient.createFirewallRule(cmd).__dict__) + + def delete(self, apiclient): + """Delete Firewall rule""" + cmd = deleteFirewallRule.deleteFirewallRuleCmd() + cmd.id = self.id + apiclient.deleteFirewallRule(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Firewall Rules matching criteria""" + + cmd = listFirewallRules.listFirewallRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listFirewallRules(cmd)) + + +class ServiceOffering: + """Manage service offerings cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create Service offering""" + cmd = createServiceOffering.createServiceOfferingCmd() + cmd.cpunumber = services["cpunumber"] + cmd.cpuspeed = services["cpuspeed"] + cmd.displaytext = services["displaytext"] + cmd.memory = services["memory"] + cmd.name = services["name"] + + # Service Offering private to that domain + if domainid: + cmd.domainid = domainid + + return ServiceOffering(apiclient.createServiceOffering(cmd).__dict__) + + def delete(self, apiclient): + """Delete Service offering""" + cmd = deleteServiceOffering.deleteServiceOfferingCmd() + cmd.id = self.id + apiclient.deleteServiceOffering(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all available service offerings.""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listServiceOfferings(cmd)) + +class DiskOffering: + """Manage disk offerings cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, custom=False): + """Create Disk offering""" + cmd = createDiskOffering.createDiskOfferingCmd() + cmd.displaytext = services["displaytext"] + cmd.name = services["name"] + if custom: + cmd.customized = True + else: + cmd.disksize = services["disksize"] + return DiskOffering(apiclient.createDiskOffering(cmd).__dict__) + + def delete(self, apiclient): + """Delete Disk offering""" + cmd = deleteDiskOffering.deleteDiskOfferingCmd() + cmd.id = self.id + apiclient.deleteDiskOffering(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all available disk offerings.""" + + cmd = listDiskOfferings.listDiskOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDiskOfferings(cmd)) + + +class SnapshotPolicy: + """Manage snapshot policies""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, volumeid, services): + """Create Snapshot policy""" + cmd = createSnapshotPolicy.createSnapshotPolicyCmd() + cmd.intervaltype = services["intervaltype"] + cmd.maxsnaps = services["maxsnaps"] + cmd.schedule = services["schedule"] + cmd.timezone = services["timezone"] + cmd.volumeid = volumeid + return SnapshotPolicy(apiclient.createSnapshotPolicy(cmd).__dict__) + + def delete(self, apiclient): + """Delete Snapshot policy""" + cmd = deleteSnapshotPolicies.deleteSnapshotPoliciesCmd() + cmd.id = self.id + apiclient.deleteSnapshotPolicies(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists snapshot policies.""" + + cmd = listSnapshotPolicies.listSnapshotPoliciesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshotPolicies(cmd)) + + +class LoadBalancerRule: + """Manage Load Balancer rule""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, ipaddressid, accountid=None): + """Create Load balancing Rule""" + + cmd = createLoadBalancerRule.createLoadBalancerRuleCmd() + cmd.publicipid = ipaddressid or services["ipaddressid"] + cmd.account = accountid or services["account"] + cmd.name = services["name"] + cmd.algorithm = services["alg"] + cmd.privateport = services["privateport"] + cmd.publicport = services["publicport"] + return LoadBalancerRule(apiclient.createLoadBalancerRule(cmd).__dict__) + + def delete(self, apiclient): + """Delete load balancing rule""" + cmd = deleteLoadBalancerRule.deleteLoadBalancerRuleCmd() + cmd.id = self.id + apiclient.deleteLoadBalancerRule(cmd) + return + + def assign(self, apiclient, vms): + """Assign virtual machines to load balancing rule""" + cmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd() + cmd.id = self.id + cmd.virtualmachineids = [str(vm.id) for vm in vms] + apiclient.assignToLoadBalancerRule(cmd) + return + + def remove(self, apiclient, vms): + """Remove virtual machines from load balancing rule""" + cmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd() + cmd.id = self.id + cmd.virtualmachineids = [str(vm.id) for vm in vms] + apiclient.removeFromLoadBalancerRule(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Load balancing rules matching criteria""" + + cmd = listLoadBalancerRules.listLoadBalancerRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listLoadBalancerRules(cmd)) + + +class Cluster: + """Manage Cluster life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, zoneid=None, podid=None): + """Create Cluster""" + cmd = addCluster.addClusterCmd() + cmd.clustertype = services["clustertype"] + cmd.hypervisor = services["hypervisor"] + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + if podid: + cmd.podid = podid + else: + cmd.podid = services["podid"] + + if "username" in services: + cmd.username = services["username"] + if "password" in services: + cmd.password = services["password"] + if "url" in services: + cmd.url = services["url"] + if "clustername" in services: + cmd.clustername = services["clustername"] + + return Cluster(apiclient.addCluster(cmd)[0].__dict__) + + def delete(self, apiclient): + """Delete Cluster""" + cmd = deleteCluster.deleteClusterCmd() + cmd.id = self.id + apiclient.deleteCluster(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Clusters matching criteria""" + + cmd = listClusters.listClustersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listClusters(cmd)) + + +class Host: + """Manage Host life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, cluster, services, zoneid=None, podid=None): + """Create Host in cluster""" + + cmd = addHost.addHostCmd() + cmd.hypervisor = services["hypervisor"] + cmd.url = services["url"] + cmd.clusterid = cluster.id + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + if podid: + cmd.podid = podid + else: + cmd.podid = services["podid"] + + if "clustertype" in services: + cmd.clustertype = services["clustertype"] + if "username" in services: + cmd.username = services["username"] + if "password" in services: + cmd.password = services["password"] + + # Add host + host = apiclient.addHost(cmd) + + if isinstance(host, list): + return Host(host[0].__dict__) + + def delete(self, apiclient): + """Delete Host""" + # Host must be in maintenance mode before deletion + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = self.id + apiclient.prepareHostForMaintenance(cmd) + time.sleep(30) + + cmd = deleteHost.deleteHostCmd() + cmd.id = self.id + apiclient.deleteHost(cmd) + return + + def enableMaintenance(self, apiclient): + """enables maintainance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = self.id + return apiclient.prepareHostForMaintenance(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Hosts matching criteria""" + + cmd = listHosts.listHostsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listHosts(cmd)) + + +class StoragePool: + """Manage Storage pools (Primary Storage)""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, clusterid=None, zoneid=None, podid=None): + """Create Storage pool (Primary Storage)""" + + cmd = createStoragePool.createStoragePoolCmd() + cmd.name = services["name"] + + if podid: + cmd.podid = podid + else: + cmd.podid = services["podid"] + + cmd.url = services["url"] + if clusterid: + cmd.clusterid = clusterid + elif "clusterid" in services: + cmd.clusterid = services["clusterid"] + + if zoneid: + cmd.zoneid = zoneid + else: + cmd.zoneid = services["zoneid"] + + return StoragePool(apiclient.createStoragePool(cmd).__dict__) + + def delete(self, apiclient): + """Delete Storage pool (Primary Storage)""" + + # Storage pool must be in maintenance mode before deletion + cmd = enableStorageMaintenance.enableStorageMaintenanceCmd() + cmd.id = self.id + apiclient.enableStorageMaintenance(cmd) + time.sleep(30) + cmd = deleteStoragePool.deleteStoragePoolCmd() + cmd.id = self.id + apiclient.deleteStoragePool(cmd) + return + + def enableMaintenance(self, apiclient): + """enables maintainance mode Storage pool""" + + cmd = enableStorageMaintenance.enableStorageMaintenanceCmd() + cmd.id = self.id + return apiclient.enableStorageMaintenance(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all storage pools matching criteria""" + + cmd = listStoragePools.listStoragePoolsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStoragePools(cmd)) + + +class Network: + """Manage Network pools""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, accountid=None, domainid=None): + """Create Network for account""" + cmd = createNetwork.createNetworkCmd() + cmd.name = services["name"] + cmd.displaytext = services["displaytext"] + cmd.networkofferingid = services["networkoffering"] + cmd.zoneid = services["zoneid"] + if accountid: + cmd.account = accountid + if domainid: + cmd.domainid = domainid + + return Network(apiclient.createNetwork(cmd).__dict__) + + def delete(self, apiclient): + """Delete Account""" + + cmd = deleteNetwork.deleteNetworkCmd() + cmd.id = self.id + apiclient.deleteNetwork(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Networks matching criteria""" + + cmd = listNetworks.listNetworksCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworks(cmd)) + + +class Vpn: + """Manage VPN life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, publicipid, account=None, domainid=None): + """Create VPN for Public IP address""" + cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd() + cmd.publicipid = publicipid + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + + return Vpn(apiclient.createRemoteAccessVpn(cmd).__dict__) + + def delete(self, apiclient): + """Delete remote VPN access""" + + cmd = deleteRemoteAccessVpn.deleteRemoteAccessVpnCmd() + cmd.publicipid = self.publicipid + apiclient.deleteRemoteAccessVpn(cmd) + + +class VpnUser: + """Manage VPN user""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, username, password, account=None, domainid=None): + """Create VPN user""" + cmd = addVpnUser.addVpnUserCmd() + cmd.username = username + cmd.password = password + + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + + return VpnUser(apiclient.addVpnUser(cmd).__dict__) + + def delete(self, apiclient): + """Remove VPN user""" + + cmd = removeVpnUser.removeVpnUserCmd() + cmd.username = self.username + cmd.account = self.account + cmd.domainid = self.domainid + apiclient.removeVpnUser(cmd) + + +class Zone: + """Manage Zone""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create zone""" + cmd = createZone.createZoneCmd() + cmd.dns1 = services["dns1"] + cmd.internaldns1 = services["internaldns1"] + cmd.name = services["name"] + cmd.networktype = services["networktype"] + + if "dns2" in services: + cmd.dns2 = services["dns2"] + if "internaldns2" in services: + cmd.internaldns2 = services["internaldns2"] + if domainid: + cmd.domainid = domainid + + return Zone(apiclient.createZone(cmd).__dict__) + + def delete(self, apiclient): + """Delete Zone""" + + cmd = deleteZone.deleteZoneCmd() + cmd.id = self.id + apiclient.deleteZone(cmd) + + def update(self, apiclient, **kwargs): + """Update the zone""" + + cmd = updateZone.updateZoneCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateZone(cmd) + + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Zones matching criteria""" + + cmd = listZones.listZonesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listZones(cmd)) + + +class Pod: + """Manage Pod""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services): + """Create Pod""" + cmd = createPod.createPodCmd() + cmd.gateway = services["gateway"] + cmd.netmask = services["netmask"] + cmd.name = services["name"] + cmd.startip = services["startip"] + cmd.endip = services["endip"] + cmd.zoneid = services["zoneid"] + + return Pod(apiclient.createPod(cmd).__dict__) + + def delete(self, apiclient): + """Delete Pod""" + + cmd = deletePod.deletePodCmd() + cmd.id = self.id + apiclient.deletePod(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + "Returns a default pod for specified zone" + + cmd = listPods.listPodsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.listPods(cmd) + + +class PublicIpRange: + """Manage VlanIpRange""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services): + """Create VlanIpRange""" + + cmd = createVlanIpRange.createVlanIpRangeCmd() + cmd.gateway = services["gateway"] + cmd.netmask = services["netmask"] + cmd.forvirtualnetwork = services["forvirtualnetwork"] + cmd.startip = services["startip"] + cmd.endip = services["endip"] + cmd.zoneid = services["zoneid"] + cmd.podid = services["podid"] + cmd.vlan = services["vlan"] + + return PublicIpRange(apiclient.createVlanIpRange(cmd).__dict__) + + def delete(self, apiclient): + """Delete VlanIpRange""" + + cmd = deleteVlanIpRange.deleteVlanIpRangeCmd() + cmd.id = self.id + apiclient.deleteVlanIpRange(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all VLAN IP ranges.""" + + cmd = listVlanIpRanges.listVlanIpRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVlanIpRanges(cmd)) + + +class SecondaryStorage: + """Manage Secondary storage""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services): + """Create Secondary Storage""" + cmd = addSecondaryStorage.addSecondaryStorageCmd() + + cmd.url = services["url"] + if "zoneid" in services: + cmd.zoneid = services["zoneid"] + return SecondaryStorage(apiclient.addSecondaryStorage(cmd).__dict__) + + def delete(self, apiclient): + """Delete Secondary Storage""" + + cmd = deleteHost.deleteHostCmd() + cmd.id = self.id + apiclient.deleteHost(cmd) + + +class SecurityGroup: + """Manage Security Groups""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, account=None, domainid=None, + description=None): + """Create security group""" + cmd = createSecurityGroup.createSecurityGroupCmd() + + cmd.name = services["name"] + if account: + cmd.account = account + if domainid: + cmd.domainid=domainid + if description: + cmd.description=description + + return SecurityGroup(apiclient.createSecurityGroup(cmd).__dict__) + + def delete(self, apiclient): + """Delete Security Group""" + + cmd = deleteSecurityGroup.deleteSecurityGroupCmd() + cmd.id = self.id + apiclient.deleteSecurityGroup(cmd) + + def authorize(self, apiclient, services, + account=None, domainid=None): + """Authorize Ingress Rule""" + + cmd=authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + + if domainid: + cmd.domainid = domainid + if account: + cmd.account = account + + cmd.securitygroupid=self.id + cmd.protocol=services["protocol"] + + if services["protocol"] == 'ICMP': + cmd.icmptype = -1 + cmd.icmpcode = -1 + else: + cmd.startport = services["startport"] + cmd.endport = services["endport"] + + cmd.cidrlist = services["cidrlist"] + return (apiclient.authorizeSecurityGroupIngress(cmd).__dict__) + + def revoke(self, apiclient, id): + """Revoke ingress rule""" + + cmd=revokeSecurityGroupIngress.revokeSecurityGroupIngressCmd() + cmd.id=id + return apiclient.revokeSecurityGroupIngress(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists all security groups.""" + + cmd = listSecurityGroups.listSecurityGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSecurityGroups(cmd)) diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/common.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/common.py new file mode 100644 index 00000000000..5b2b096743e --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/common.py @@ -0,0 +1,447 @@ +# -*- encoding: utf-8 -*- +# +# Copyright (c) 2012 Citrix. All rights reserved. +# + +"""Common functions +""" + +#Import Local Modules +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +import marvin.remoteSSHClient +from utils import * +from base import * + +#Import System modules +import time + +def get_domain(apiclient, services=None): + "Returns a default domain" + + cmd = listDomains.listDomainsCmd() + if services: + if "domainid" in services: + cmd.id = services["domainid"] + + domains = apiclient.listDomains(cmd) + + if isinstance(domains, list): + return domains[0] + else: + raise Exception("Failed to find specified domain.") + +def get_zone(apiclient, services=None): + "Returns a default zone" + + cmd = listZones.listZonesCmd() + if services: + if "zoneid" in services: + cmd.id = services["zoneid"] + + zones = apiclient.listZones(cmd) + + if isinstance(zones, list): + return zones[0] + else: + raise Exception("Failed to find specified zone.") + +def get_pod(apiclient, zoneid, services=None): + "Returns a default pod for specified zone" + + cmd = listPods.listPodsCmd() + cmd.zoneid = zoneid + + if services: + if "podid" in services: + cmd.id = services["podid"] + + pods = apiclient.listPods(cmd) + + if isinstance(pods, list): + return pods[0] + else: + raise Exception("Exception: Failed to find specified pod.") + +def get_template(apiclient, zoneid, ostypeid=12, services=None): + "Returns a template" + + cmd = listTemplates.listTemplatesCmd() + cmd.templatefilter = 'featured' + cmd.zoneid = zoneid + + if services: + if "template" in services: + cmd.id = services["template"] + + list_templates = apiclient.listTemplates(cmd) + + for template in list_templates: + if template.ostypeid == ostypeid: + return template + + raise Exception("Exception: Failed to find template with OSTypeID: %s" % + ostypeid) + return + +def download_systemplates_sec_storage(server, services): + """Download System templates on sec storage""" + + try: + # Login to management server + ssh = marvin.remoteSSHClient.remoteSSHClient( + server["ipaddress"], + server["port"], + server["username"], + server["password"] + ) + except Exception as e: + raise Exception("SSH access failted for server with IP address: %s" % + server["ipaddess"]) + # Mount Secondary Storage on Management Server + cmds = [ + "mkdir -p %s" % services["mnt_dir"], + "mount -t nfs %s:/%s %s" % ( + services["sec_storage"], + services["path"], + services["mnt_dir"] + ), + "%s -m %s -u %s -h %s -F" % ( + services["command"], + services["mnt_dir"], + services["download_url"], + services["hypervisor"] + ) + ] + for c in cmds: + result = ssh.execute(c) + + res = str(result) + + # Unmount the Secondary storage + ssh.execute("umount %s" % (services["mnt_dir"])) + + if res.count("Successfully installed system VM template") == 1: + return + else: + raise Exception("Failed to download System Templates on Sec Storage") + return + +def wait_for_ssvms(apiclient, zoneid, podid, interval=60): + """After setup wait for SSVMs to come Up""" + + time.sleep(interval) + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='secondarystoragevm', + zoneid=zoneid, + podid=podid + ) + ssvm = list_ssvm_response[0] + if ssvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(30) + timeout = timeout - 1 + elif ssvm.state == 'Running': + break + elif timeout == 0: + raise Exception("SSVM failed to come up") + break + + timeout = 40 + while True: + list_ssvm_response = list_ssvms( + apiclient, + systemvmtype='consoleproxy', + zoneid=zoneid, + podid=podid + ) + cpvm = list_ssvm_response[0] + if cpvm.state != 'Running': + # Sleep to ensure SSVMs are Up and Running + time.sleep(interval) + timeout = timeout - 1 + elif cpvm.state == 'Running': + break + elif timeout == 0: + raise Exception("CPVM failed to come up") + break + return + +def download_builtin_templates(apiclient, zoneid, hypervisor, host, linklocalip, interval=60): + """After setup wait till builtin templates are downloaded""" + + # Change IPTABLES Rules + result = get_process_status( + host["ipaddress"], + host["port"], + host["username"], + host["password"], + linklocalip, + "iptables -P INPUT ACCEPT" + ) + time.sleep(interval) + # Find the BUILTIN Templates for given Zone, Hypervisor + list_template_response = list_templates( + apiclient, + hypervisor=hypervisor, + zoneid=zoneid, + templatefilter='self' + ) + + if not isinstance(list_template_response, list): + raise Exception("Failed to download BUILTIN templates") + + # Ensure all BUILTIN templates are downloaded + templateid = None + for template in list_template_response: + if template.templatetype == "BUILTIN": + templateid = template.id + + # Sleep to ensure that template is in downloading state after adding + # Sec storage + time.sleep(interval) + while True: + template_response = list_templates( + apiclient, + id=templateid, + zoneid=zoneid, + templatefilter='self' + ) + template = template_response[0] + # If template is ready, + # template.status = Download Complete + # Downloading - x% Downloaded + # Error - Any other string + if template.status == 'Download Complete': + break + + elif 'Downloaded' in template.status: + time.sleep(interval) + + elif 'Installing' not in template.status: + raise Exception("ErrorInDownload") + + return + +def update_resource_limit(apiclient, resourcetype, account=None, domainid=None, + max=None): + """Updates the resource limit to 'max' for given account""" + + cmd = updateResourceLimit.updateResourceLimitCmd() + cmd.resourcetype = resourcetype + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + if max: + cmd.max = max + apiclient.updateResourceLimit(cmd) + return + +def list_routers(apiclient, **kwargs): + """List all Routers matching criteria""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRouters(cmd)) + +def list_zones(apiclient, **kwargs): + """List all Zones matching criteria""" + + cmd = listZones.listZonesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listZones(cmd)) + +def list_networks(apiclient, **kwargs): + """List all Networks matching criteria""" + + cmd = listNetworks.listNetworksCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworks(cmd)) + +def list_clusters(apiclient, **kwargs): + """List all Clusters matching criteria""" + + cmd = listClusters.listClustersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listClusters(cmd)) + +def list_ssvms(apiclient, **kwargs): + """List all SSVMs matching criteria""" + + cmd = listSystemVms.listSystemVmsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSystemVms(cmd)) + +def list_storage_pools(apiclient, **kwargs): + """List all storage pools matching criteria""" + + cmd = listStoragePools.listStoragePoolsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStoragePools(cmd)) + +def list_virtual_machines(apiclient, **kwargs): + """List all VMs matching criteria""" + + cmd = listVirtualMachines.listVirtualMachinesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVirtualMachines(cmd)) + +def list_hosts(apiclient, **kwargs): + """List all Hosts matching criteria""" + + cmd = listHosts.listHostsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listHosts(cmd)) + +def list_configurations(apiclient, **kwargs): + """List configuration with specified name""" + + cmd = listConfigurations.listConfigurationsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listConfigurations(cmd)) + +def list_publicIP(apiclient, **kwargs): + """List all Public IPs matching criteria""" + + cmd = listPublicIpAddresses.listPublicIpAddressesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPublicIpAddresses(cmd)) + +def list_nat_rules(apiclient, **kwargs): + """List all NAT rules matching criteria""" + + cmd = listPortForwardingRules.listPortForwardingRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPortForwardingRules(cmd)) + +def list_lb_rules(apiclient, **kwargs): + """List all Load balancing rules matching criteria""" + + cmd = listLoadBalancerRules.listLoadBalancerRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listLoadBalancerRules(cmd)) + +def list_lb_instances(apiclient, **kwargs): + """List all Load balancing instances matching criteria""" + + cmd = listLoadBalancerRuleInstances.listLoadBalancerRuleInstancesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listLoadBalancerRuleInstances(cmd)) + +def list_firewall_rules(apiclient, **kwargs): + """List all Firewall Rules matching criteria""" + + cmd = listFirewallRules.listFirewallRulesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listFirewallRules(cmd)) + +def list_volumes(apiclient, **kwargs): + """List all volumes matching criteria""" + + cmd = listVolumes.listVolumesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVolumes(cmd)) + +def list_isos(apiclient, **kwargs): + """Lists all available ISO files.""" + + cmd = listIsos.listIsosCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listIsos(cmd)) + +def list_snapshots(apiclient, **kwargs): + """List all snapshots matching criteria""" + + cmd = listSnapshots.listSnapshotsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshots(cmd)) + +def list_templates(apiclient, **kwargs): + """List all templates matching criteria""" + + cmd = listTemplates.listTemplatesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTemplates(cmd)) + +def list_domains(apiclient, **kwargs): + """Lists domains""" + + cmd = listDomains.listDomainsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDomains(cmd)) + +def list_accounts(apiclient, **kwargs): + """Lists accounts and provides detailed account information for + listed accounts""" + + cmd = listAccounts.listAccountsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAccounts(cmd)) + +def list_users(apiclient, **kwargs): + """Lists users and provides detailed account information for + listed users""" + + cmd = listUsers.listUsersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listUsers(cmd)) + +def list_snapshot_policy(apiclient, **kwargs): + """Lists snapshot policies.""" + + cmd = listSnapshotPolicies.listSnapshotPoliciesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSnapshotPolicies(cmd)) + +def list_events(apiclient, **kwargs): + """Lists events""" + + cmd = listEvents.listEventsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listEvents(cmd)) + +def list_disk_offering(apiclient, **kwargs): + """Lists all available disk offerings.""" + + cmd = listDiskOfferings.listDiskOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listDiskOfferings(cmd)) + +def list_service_offering(apiclient, **kwargs): + """Lists all available service offerings.""" + + cmd = listServiceOfferings.listServiceOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listServiceOfferings(cmd)) + +def list_vlan_ipranges(apiclient, **kwargs): + """Lists all VLAN IP ranges.""" + + cmd = listVlanIpRanges.listVlanIpRangesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listVlanIpRanges(cmd)) + +def list_usage_records(apiclient, **kwargs): + """Lists usage records for accounts""" + + cmd = listUsageRecords.listUsageRecordsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listUsageRecords(cmd)) + +def list_network_offerings(apiclient, **kwargs): + """Lists network offerings""" + + cmd = listNetworkOfferings.listNetworkOfferingsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNetworkOfferings(cmd)) + +def list_resource_limits(apiclient, **kwargs): + """Lists resource limits""" + + cmd = listResourceLimits.listResourceLimitsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listResourceLimits(cmd)) \ No newline at end of file diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py new file mode 100644 index 00000000000..69d524deea0 --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/testcase/libs/utils.py @@ -0,0 +1,102 @@ +# -*- encoding: utf-8 -*- +# +# Copyright (c) 2012 Citrix. All rights reserved. +# + +"""Utilities functions +""" + +import time +import marvin.remoteSSHClient +from marvin.cloudstackAPI import * +import marvin.cloudstackConnection +from marvin.remoteSSHClient import remoteSSHClient +#from marvin.cloudstackConnection import cloudConnection +import marvin.configGenerator +import logging +import string +import random + +def random_gen(size=6, chars=string.ascii_uppercase + string.digits): + """Generate Random Strings of variable length""" + return ''.join(random.choice(chars) for x in range(size)) + +def cleanup_resources(api_client, resources): + """Delete resources""" + for obj in resources: + obj.delete(api_client) + +def is_server_ssh_ready(ipaddress, port, username, password, retries=50): + """Return ssh handle else wait till sshd is running""" + loop_cnt = retries + while True: + try: + ssh = marvin.remoteSSHClient.remoteSSHClient( + ipaddress, + port, + username, + password + ) + except Exception as e: + if loop_cnt == 0: + raise e + loop_cnt = loop_cnt - 1 + time.sleep(30) + else: + return ssh + + +def format_volume_to_ext3(ssh_client, device="/dev/sda"): + """Format attached storage to ext3 fs""" + cmds = [ + "echo -e 'n\np\n1\n\n\nw' | fdisk %s" % device, + "mkfs.ext3 %s1" % device, + ] + for c in cmds: + ssh_client.execute(c) + +def fetch_api_client(config_file='datacenterCfg'): + """Fetch the Cloudstack API Client""" + config = configGenerator.get_setup_config(config_file) + mgt = config.mgtSvr[0] + testClientLogger = logging.getLogger("testClient") + asyncTimeout = 3600 + return cloudstackAPIClient.CloudStackAPIClient( + cloudstackConnection.cloudConnection( + mgt.mgtSvrIp, + mgt.port, + mgt.apiKey, + mgt.securityKey, + asyncTimeout, + testClientLogger + ) + ) + +def get_process_status(hostip, port, username, password, linklocalip, process): + """Double hop and returns a process status""" + + #SSH to the machine + ssh = marvin.remoteSSHClient.remoteSSHClient( + hostip, + port, + username, + password + ) + ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + ssh_command = ssh_command + "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" \ + % (linklocalip, process) + + # Double hop into router + timeout = 5 + # Ensure the SSH login is successful + while True: + res = ssh.execute(ssh_command) + + if res[0] != "Host key verification failed.": + break + elif timeout == 0: + break + + time.sleep(5) + timeout = timeout - 1 + return res diff --git a/tools/marvin/marvin/sandbox/demo/simulator/testcase/test_vm_life_cycle.py b/tools/marvin/marvin/sandbox/demo/simulator/testcase/test_vm_life_cycle.py new file mode 100644 index 00000000000..176f4ae870f --- /dev/null +++ b/tools/marvin/marvin/sandbox/demo/simulator/testcase/test_vm_life_cycle.py @@ -0,0 +1,519 @@ +# -*- encoding: utf-8 -*- +# Copyright 2012 Citrix Systems, Inc. Licensed under the +# Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. Citrix Systems, Inc. +# reserves all rights not expressly granted by 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. +# +# Automatically generated by addcopyright.py at 04/03/2012 +""" BVT tests for Virtual Machine Life Cycle +""" +#Import Local Modules +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient + +from testcase.libs.utils import * +from testcase.libs.base import * +from testcase.libs.common import * + +#Import System modules +import time + +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + "disk_offering":{ + "displaytext": "Small", + "name": "Small", + "disksize": 1 + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "small": + # Create a small virtual machine instance with disk offering + { + "displayname": "testserver", + "username": "root", # VM creds for SSH + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "medium": # Create a medium virtual machine instance + { + "displayname": "testserver", + "username": "root", + "password": "password", + "ssh_port": 22, + "hypervisor": 'XenServer', + "privateport": 22, + "publicport": 22, + "protocol": 'TCP', + }, + "service_offerings": + { + "tiny": + { + "name": "Tiny Instance", + "displaytext": "Tiny Instance", + "cpunumber": 1, + "cpuspeed": 100, # in MHz + "memory": 64, # In MBs + }, + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "Small Instance", + "displaytext": "Small Instance", + "cpunumber": 1, + "cpuspeed": 500, + "memory": 256 + }, + "medium": + { + # Medium service offering ID to for + # change VM service offering from small to medium + "name": "Medium Instance", + "displaytext": "Medium Instance", + "cpunumber": 1, + "cpuspeed": 1000, + "memory": 1024 + } + }, + "sleep": 60, + "timeout": 10, + #Migrate VM to hostid + "ostypeid": 'ccde7156-9b8b-4fb9-bf08-530dedf4dc61', + # CentOS 5.3 (64-bit) + "mode":'advanced', + } + + +class TestDeployVM(cloudstackTestCase): + + def setUp(self): + + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.services = Services().services + # Get Zone, Domain and templates + domain = get_domain(self.apiclient, self.services) + zone = get_zone(self.apiclient, self.services) + + template = get_template( + self.apiclient, + zone.id, + self.services["ostypeid"] + ) + # Set Zones and disk offerings + self.services["small"]["zoneid"] = zone.id + self.services["small"]["template"] = template.id + + self.services["medium"]["zoneid"] = zone.id + self.services["medium"]["template"] = template.id + + # Create Account, VMs, NAT Rules etc + self.account = Account.create( + self.apiclient, + self.services["account"], + domainid=domain.id + ) + + self.service_offering = ServiceOffering.create( + self.apiclient, + self.services["service_offerings"]["tiny"] + ) + # Cleanup + self.cleanup = [ + self.service_offering, + self.account + ] + + def test_deploy_vm(self): + """Test Deploy Virtual Machine + """ + + # Validate the following: + # 1. Virtual Machine is accessible via SSH + # 2. listVirtualMachines returns accurate information + # 3. The Cloud Database contains the valid information + + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.services["small"], + accountid=self.account.account.name, + domainid=self.account.account.domainid, + serviceofferingid=self.service_offering.id + ) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.virtual_machine.id + ) + + self.debug( + "Verify listVirtualMachines response for virtual machine: %s" \ + % self.virtual_machine.id + ) + + self.assertEqual( + isinstance(list_vm_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_vm_response), + 0, + "Check VM available in List Virtual Machines" + ) + vm_response = list_vm_response[0] + + self.assertEqual( + + vm_response.id, + self.virtual_machine.id, + "Check virtual machine id in listVirtualMachines" + ) + + self.assertEqual( + vm_response.displayname, + self.virtual_machine.displayname, + "Check virtual machine displayname in listVirtualMachines" + ) + return + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + self.debug("Warning! Exception in tearDown: %s" % e) + + +class TestVMLifeCycle(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super(TestVMLifeCycle, cls).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + zone.id, + cls.services["ostypeid"] + ) + # Set Zones and disk offerings + cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["template"] = template.id + + cls.services["medium"]["zoneid"] = zone.id + cls.services["medium"]["template"] = template.id + + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + cls.small_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offerings"]["small"] + ) + + cls.medium_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offerings"]["medium"] + ) + #create small and large virtual machines + cls.small_virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + cls.medium_virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["medium"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.medium_offering.id, + mode=cls.services["mode"] + ) + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + cls._cleanup = [ + cls.small_offering, + cls.medium_offering, + cls.account + ] + + @classmethod + def tearDownClass(cls): + cls.api_client = super(TestVMLifeCycle, cls).getClsTestClient().getApiClient() + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created ISOs + cleanup_resources(self.apiclient, self.cleanup) + return + + def test_01_stop_vm(self): + """Test Stop Virtual Machine + """ + + # Validate the following + # 1. Should Not be able to login to the VM. + # 2. listVM command should return + # this VM.State of this VM should be ""Stopped"". + + self.debug("Stopping VM - ID: %s" % self.virtual_machine.id) + self.small_virtual_machine.stop(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.small_virtual_machine.id + ) + + self.assertEqual( + isinstance(list_vm_response, list), + True, + "Check list response returns a valid list" + ) + self.assertNotEqual( + len(list_vm_response), + 0, + "Check VM available in List Virtual Machines" + ) + + self.assertEqual( + list_vm_response[0].state, + "Stopped", + "Check virtual machine is in stopped state" + ) + return + + def test_02_start_vm(self): + """Test Start Virtual Machine + """ + # Validate the following + # 1. listVM command should return this VM.State + # of this VM should be Running". + + self.debug("Starting VM - ID: %s" % self.virtual_machine.id) + self.small_virtual_machine.start(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.small_virtual_machine.id + ) + self.assertEqual( + isinstance(list_vm_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_vm_response), + 0, + "Check VM avaliable in List Virtual Machines" + ) + + self.debug( + "Verify listVirtualMachines response for virtual machine: %s" \ + % self.small_virtual_machine.id + ) + self.assertEqual( + list_vm_response[0].state, + "Running", + "Check virtual machine is in running state" + ) + return + + def test_04_change_offering_small(self): + """Change Offering to a small capacity + """ + + # Validate the following + # 1. Log in to the Vm .We should see that the CPU and memory Info of + # this Vm matches the one specified for "Small" service offering. + # 2. Using listVM command verify that this Vm + # has Small service offering Id. + + self.debug("Stopping VM - ID: %s" % self.medium_virtual_machine.id) + + self.medium_virtual_machine.stop(self.apiclient) + + # Poll listVM to ensure VM is stopped properly + timeout = self.services["timeout"] + + while True: + time.sleep(self.services["sleep"]) + + # Ensure that VM is in stopped state + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.medium_virtual_machine.id + ) + + if isinstance(list_vm_response, list): + + vm = list_vm_response[0] + if vm.state == 'Stopped': + self.debug("VM state: %s" % vm.state) + break + + if timeout == 0: + raise Exception( + "Failed to stop VM (ID: %s) in change service offering" % vm.id) + + timeout = timeout - 1 + + self.debug("Change Service offering VM - ID: %s" % + self.medium_virtual_machine.id) + + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.id = self.medium_virtual_machine.id + cmd.serviceofferingid = self.small_offering.id + self.apiclient.changeServiceForVirtualMachine(cmd) + + self.debug("Starting VM - ID: %s" % self.medium_virtual_machine.id) + self.medium_virtual_machine.start(self.apiclient) + + # Poll listVM to ensure VM is started properly + timeout = self.services["timeout"] + + while True: + time.sleep(self.services["sleep"]) + + # Ensure that VM is in running state + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.medium_virtual_machine.id + ) + + if isinstance(list_vm_response, list): + + vm = list_vm_response[0] + if vm.state == 'Running': + self.debug("VM state: %s" % vm.state) + break + + if timeout == 0: + raise Exception( + "Failed to start VM (ID: %s) after changing service offering" % vm.id) + + timeout = timeout - 1 + + return + + def test_06_destroy_vm(self): + """Test destroy Virtual Machine + """ + + # Validate the following + # 1. Should not be able to login to the VM. + # 2. listVM command should return this VM.State + # of this VM should be "Destroyed". + + self.debug("Destroy VM - ID: %s" % self.small_virtual_machine.id) + self.small_virtual_machine.delete(self.apiclient) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.small_virtual_machine.id + ) + self.assertEqual( + isinstance(list_vm_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_vm_response), + 0, + "Check VM avaliable in List Virtual Machines" + ) + + self.assertEqual( + list_vm_response[0].state, + "Destroyed", + "Check virtual machine is in destroyed state" + ) + return + + def test_07_restore_vm(self): + """Test recover Virtual Machine + """ + + # Validate the following + # 1. listVM command should return this VM. + # State of this VM should be "Stopped". + # 2. We should be able to Start this VM successfully. + + self.debug("Recovering VM - ID: %s" % self.small_virtual_machine.id) + + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.id = self.small_virtual_machine.id + self.apiclient.recoverVirtualMachine(cmd) + + list_vm_response = list_virtual_machines( + self.apiclient, + id=self.small_virtual_machine.id + ) + self.assertEqual( + isinstance(list_vm_response, list), + True, + "Check list response returns a valid list" + ) + + self.assertNotEqual( + len(list_vm_response), + 0, + "Check VM avaliable in List Virtual Machines" + ) + + self.assertEqual( + list_vm_response[0].state, + "Stopped", + "Check virtual machine is in Stopped state" + ) + + return diff --git a/tools/marvin/marvin/sandbox/demo/testDeployVM.py b/tools/marvin/marvin/sandbox/demo/testDeployVM.py deleted file mode 100644 index 4afaee346ad..00000000000 --- a/tools/marvin/marvin/sandbox/demo/testDeployVM.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# Copyright 2012 Citrix Systems, Inc. Licensed under the -# Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. Citrix Systems, Inc. -# reserves all rights not expressly granted by 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. -# -# Automatically generated by addcopyright.py at 04/03/2012 - -from cloudstackTestCase import * - -import unittest -import hashlib -import random - -class TestDeployVm(cloudstackTestCase): - """ - This test deploys a virtual machine into a user account - using the small service offering and builtin template - """ - def setUp(self): - """ - CloudStack internally saves its passwords in md5 form and that is how we - specify it in the API. Python's hashlib library helps us to quickly hash - strings as follows - """ - mdf = hashlib.md5() - mdf.update('password') - mdf_pass = mdf.hexdigest() - - self.apiClient = self.testClient.getApiClient() #Get ourselves an API client - - self.acct = createAccount.createAccountCmd() #The createAccount command - self.acct.accounttype = 0 #We need a regular user. admins have accounttype=1 - self.acct.firstname = 'bugs' - self.acct.lastname = 'bunny' #What's up doc? - self.acct.password = mdf_pass #The md5 hashed password string - self.acct.username = 'bugs' - self.acct.email = 'bugs@rabbithole.com' - self.acct.account = 'bugs' - self.acct.domainid = 1 #The default ROOT domain - self.acctResponse = self.apiClient.createAccount(self.acct) - #And upon successful creation we'll log a helpful message in our logs - self.debug("successfully created account: %s, user: %s, id: \ - %s"%(self.acctResponse.account.account, \ - self.acctResponse.account.username, \ - self.acctResponse.account.id)) - - def test_DeployVm(self): - """ - Let's start by defining the attributes of our VM that we will be - deploying on CloudStack. We will be assuming a single zone is available - and is configured and all templates are Ready - - The hardcoded values are used only for brevity. - """ - deployVmCmd = deployVirtualMachine.deployVirtualMachineCmd() - deployVmCmd.zoneid = 1 - deployVmCmd.account = self.acct.account - deployVmCmd.domainid = self.acct.domainid - deployVmCmd.templateid = 2 - deployVmCmd.serviceofferingid = 1 - - deployVmResponse = self.apiClient.deployVirtualMachine(deployVmCmd) - self.debug("VM %s was deployed in the job %s"%(deployVmResponse.id, deployVmResponse.jobid)) - - # At this point our VM is expected to be Running. Let's find out what - # listVirtualMachines tells us about VMs in this account - - listVmCmd = listVirtualMachines.listVirtualMachinesCmd() - listVmCmd.id = deployVmResponse.id - listVmResponse = self.apiClient.listVirtualMachines(listVmCmd) - - self.assertNotEqual(len(listVmResponse), 0, "Check if the list API \ - returns a non-empty response") - - vm = listVmResponse[0] - - self.assertEqual(vm.id, deployVmResponse.id, "Check if the VM returned \ - is the same as the one we deployed") - - - self.assertEqual(vm.state, "Running", "Check if VM has reached \ - a state of running") - - def tearDown(self): - """ - And finally let us cleanup the resources we created by deleting the - account. All good unittests are atomic and rerunnable this way - """ - deleteAcct = deleteAccount.deleteAccountCmd() - deleteAcct.id = self.acctResponse.account.id - self.apiClient.deleteAccount(deleteAcct)