diff --git a/tools/marvin/marvin/asyncJobMgr.py b/tools/marvin/marvin/asyncJobMgr.py index 40304fa4141..698462783bd 100644 --- a/tools/marvin/marvin/asyncJobMgr.py +++ b/tools/marvin/marvin/asyncJobMgr.py @@ -28,6 +28,8 @@ class job(object): def __init__(self): self.id = None self.cmd = None + + class jobStatus(object): def __init__(self): self.result = None @@ -37,8 +39,11 @@ class jobStatus(object): self.duration = None self.jobId = None self.responsecls = None + def __str__(self): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) + + class workThread(threading.Thread): def __init__(self, in_queue, outqueue, apiClient, db=None, lock=None): threading.Thread.__init__(self) @@ -47,11 +52,11 @@ class workThread(threading.Thread): self.connection = apiClient.connection.__copy__() self.db = None self.lock = lock - + def queryAsynJob(self, job): if job.jobId is None: return job - + try: self.lock.acquire() result = self.connection.poll(job.jobId, job.responsecls).jobresult @@ -59,10 +64,10 @@ class workThread(threading.Thread): result = str(e) finally: self.lock.release() - + job.result = result return job - + def executeCmd(self, job): cmd = job.cmd @@ -70,14 +75,15 @@ class workThread(threading.Thread): jobId = None try: self.lock.acquire() - + if cmd.isAsync == "false": jobstatus.startTime = datetime.datetime.now() - + result = self.connection.make_request(cmd) jobstatus.result = result jobstatus.endTime = datetime.datetime.now() - jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime(jobstatus.startTime.timetuple()) + jobstatus.duration = time.mktime(jobstatus.endTime.timetuple()) - time.mktime( + jobstatus.startTime.timetuple()) else: result = self.connection.make_request(cmd, None, True) if result is None: @@ -99,9 +105,9 @@ class workThread(threading.Thread): jobstatus.result = sys.exc_info() finally: self.lock.release() - + return jobstatus - + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -109,18 +115,20 @@ class workThread(threading.Thread): jobstatus = self.queryAsynJob(job) else: jobstatus = self.executeCmd(job) - + self.output.put(jobstatus) self.inqueue.task_done() - + '''release the resource''' self.connection.close() + class jobThread(threading.Thread): def __init__(self, inqueue, interval): threading.Thread.__init__(self) self.inqueue = inqueue self.interval = interval + def run(self): while self.inqueue.qsize() > 0: job = self.inqueue.get() @@ -130,23 +138,25 @@ class jobThread(threading.Thread): job.apiClient.connection.close() except: pass - + self.inqueue.task_done() time.sleep(self.interval) - + + class outputDict(object): def __init__(self): self.lock = threading.Condition() - self.dict = {} + self.dict = {} + class asyncJobMgr(object): def __init__(self, apiClient, db): self.inqueue = Queue.Queue() - self.output = outputDict() + self.output = outputDict() self.outqueue = Queue.Queue() self.apiClient = apiClient self.db = db - + def submitCmds(self, cmds): if not self.inqueue.empty(): return False @@ -160,11 +170,12 @@ class asyncJobMgr(object): id += 1 ids.append(id) return ids - + def updateTimeStamp(self, jobstatus): jobId = jobstatus.jobId if jobId is not None and self.db is not None: - result = self.db.execute("select job_status, created, last_updated from async_job where id=%s"%jobId) + result = self.db.execute( + "select job_status, created, last_updated from async_job where id='%s'" % str(jobId)) if result is not None and len(result) > 0: if result[0][0] == 1: jobstatus.status = True @@ -174,7 +185,7 @@ class asyncJobMgr(object): jobstatus.endTime = result[0][2] delta = jobstatus.endTime - jobstatus.startTime jobstatus.duration = delta.total_seconds() - + def waitForComplete(self, workers=10): self.inqueue.join() lock = threading.Lock() @@ -183,28 +194,30 @@ class asyncJobMgr(object): for i in range(workers): worker = workThread(self.outqueue, resultQueue, self.apiClient, self.db, lock) worker.start() - + self.outqueue.join() - + asyncJobResult = [] while resultQueue.qsize() > 0: jobstatus = resultQueue.get() self.updateTimeStamp(jobstatus) asyncJobResult.append(jobstatus) - + return asyncJobResult - + '''put commands into a queue at first, then start workers numbers threads to execute this commands''' + def submitCmdsAndWait(self, cmds, workers=10): self.submitCmds(cmds) lock = threading.Lock() for i in range(workers): worker = workThread(self.inqueue, self.outqueue, self.apiClient, self.db, lock) worker.start() - + return self.waitForComplete(workers) '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJobExecuteNtimes(self, job, ntimes=1, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() @@ -213,22 +226,23 @@ class asyncJobMgr(object): setattr(newjob, "apiClient", copy.copy(self.apiClient)) setattr(newjob, "lock", lock) inqueue1.put(newjob) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() inqueue1.join() - + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=1, interval=1): inqueue1 = Queue.Queue() lock = threading.Condition() - + for job in jobs: setattr(job, "apiClient", copy.copy(self.apiClient)) setattr(job, "lock", lock) inqueue1.put(job) - + for i in range(nums_threads): work = jobThread(inqueue1, interval) work.start() diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 5d30803d930..9a4c387a87a 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -33,13 +33,18 @@ from requests import RequestException 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 self.securityKey = securityKey self.mgtSvr = mgtSvr self.port = port + if user: + self.user = user + if passwd: + self.passwd = passwd self.logging = logging self.path = path self.retries = 5 @@ -55,9 +60,10 @@ class cloudConnection(object): % (self.protocol, self.mgtSvr, self.port, self.path) def __copy__(self): - return cloudConnection(self.mgtSvr, self.port, self.apiKey, - self.securityKey, self.asyncTimeout, - self.logging, self.protocol, self.path) + return cloudConnection(self.mgtSvr, self.port, self.user, self.passwd, + self.apiKey, self.securityKey, + self.asyncTimeout, self.logging, self.protocol, + self.path) def poll(self, jobid, response): """ @@ -200,7 +206,8 @@ class cloudConnection(object): @return: """ cmdname, isAsync, payload = self.sanitize_command(cmd) - self.logging.debug("sending %s request: %s %s" % (method, cmdname, str(payload))) + self.logging.debug("sending %s request: %s %s" % (method, cmdname, + str(payload))) response = self.request( cmdname, self.auth, payload=payload, method=method) self.logging.debug("Request: %s Response: %s" % diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 85552ed5523..d85a61c4872 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -18,24 +18,29 @@ import cloudstackConnection import asyncJobMgr import dbConnection -from cloudstackAPI import * +from cloudstackAPI import * import random import string import hashlib class cloudstackTestClient(object): - def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, + def __init__(self, mgtSvr=None, port=8096, user=None, passwd=None, + apiKey=None, securityKey=None, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): - self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey, asyncTimeout, logging) + self.connection = \ + cloudstackConnection.cloudConnection( + mgtSvr, port, user, + passwd, apiKey, securityKey, + asyncTimeout, logging) self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection) self.dbConnection = None self.asyncJobMgr = None self.ssh = None self.defaultWorkerThreads = defaultWorkerThreads - + def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) - + def isAdminContext(self): """ A user is a regular user if he fails to listDomains; @@ -53,7 +58,7 @@ class cloudstackTestClient(object): return 2 #domain-admin except: return 0 #user - + def random_gen(self, size=6, chars=string.ascii_uppercase + string.digits): """Generate Random Strings of variable length""" return ''.join(random.choice(chars) for x in range(size)) @@ -61,7 +66,7 @@ class cloudstackTestClient(object): def createUserApiClient(self, UserName, DomainName, acctType=0): if not self.isAdminContext(): return self.apiClient - + listDomain = listDomains.listDomainsCmd() listDomain.listall = True listDomain.name = DomainName @@ -73,11 +78,11 @@ class cloudstackTestClient(object): cdomain.name = DomainName domain = self.apiClient.createDomain(cdomain) domId = domain.id - + mdf = hashlib.md5() mdf.update("password") mdf_pass = mdf.hexdigest() - + cmd = listAccounts.listAccountsCmd() cmd.name = UserName cmd.domainid = domId @@ -95,46 +100,47 @@ class cloudstackTestClient(object): createAcctCmd.username = UserName acct = self.apiClient.createAccount(createAcctCmd) acctId = acct.id - - listuser = listUsers.listUsersCmd() + + listuser = listUsers.listUsersCmd() listuser.username = UserName - + listuserRes = self.apiClient.listUsers(listuser) userId = listuserRes[0].id apiKey = listuserRes[0].apikey securityKey = listuserRes[0].secretkey - + if apiKey is None: registerUser = registerUserKeys.registerUserKeysCmd() registerUser.id = userId registerUserRes = self.apiClient.registerUserKeys(registerUser) apiKey = registerUserRes.apikey securityKey = registerUserRes.secretkey - + newUserConnection = cloudstackConnection.cloudConnection(self.connection.mgtSvr, self.connection.port, + self.connection.user, self.connection.passwd, apiKey, securityKey, self.connection.asyncTimeout, self.connection.logging) self.userApiClient = cloudstackAPIClient.CloudStackAPIClient(newUserConnection) self.userApiClient.connection = newUserConnection return self.userApiClient - + def close(self): if self.connection is not None: self.connection.close() - + def getDbConnection(self): return self.dbConnection def executeSql(self, sql=None): if sql is None or self.dbConnection is None: return None - + return self.dbConnection.execute() - + def executeSqlFromFile(self, sqlFile=None): if sqlFile is None or self.dbConnection is None: return None return self.dbConnection.executeSqlFromFile(sqlFile) - + def getApiClient(self): return self.apiClient @@ -151,18 +157,21 @@ class cloudstackTestClient(object): '''FixME, httplib has issue if more than one thread submitted''' + def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) return self.asyncJobMgr.submitCmdsAndWait(cmds, workers) - + '''submit one job and execute the same job ntimes, with nums_threads of threads''' + def submitJob(self, job, ntimes=1, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) self.asyncJobMgr.submitJobExecuteNtimes(job, ntimes, nums_threads, interval) - - '''submit n jobs, execute them with nums_threads of threads''' + + '''submit n jobs, execute them with nums_threads of threads''' + def submitJobs(self, jobs, nums_threads=10, interval=1): if self.asyncJobMgr is None: self.asyncJobMgr = asyncJobMgr.asyncJobMgr(self.apiClient, self.dbConnection) diff --git a/tools/marvin/marvin/dbConnection.py b/tools/marvin/marvin/dbConnection.py index 8fa86438ab0..958299aff2a 100644 --- a/tools/marvin/marvin/dbConnection.py +++ b/tools/marvin/marvin/dbConnection.py @@ -37,7 +37,11 @@ class dbConnection(object): return None resultRow = [] - with contextlib.closing(mysql.connector.connect(host=self.host, port=self.port, user=self.user, password=self.passwd, db=self.database)) as conn: + with contextlib.closing(mysql.connector.connect(host=str(self.host), + port=int(self.port), + user=str(self.user), + password=str(self.passwd), + db=str(self.database))) as conn: conn.autocommit = True with contextlib.closing(conn.cursor(buffered=True)) as cursor: cursor.execute(sql, params) diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index d358789d8da..5ca1ebfb4f8 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -402,6 +402,7 @@ class deployDataCenters(): self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, mgt.port, \ + mgt.user, mgt.passwd, \ mgt.apiKey, \ mgt.securityKey, \ logging=self.testClientLogger) @@ -409,6 +410,7 @@ class deployDataCenters(): apiKey, securityKey = self.registerApiKey() self.testClient = \ cloudstackTestClient.cloudstackTestClient(mgt.mgtSvrIp, 8080, \ + mgt.user, mgt.passwd, \ apiKey, securityKey, \ logging=self.testClientLogger) @@ -419,6 +421,11 @@ class deployDataCenters(): dbSvr.passwd, dbSvr.db) self.apiClient = self.testClient.getApiClient() + """set hypervisor""" + if mgt.hypervisor: + self.apiClient.hypervisor = mgt.hypervisor + else: + self.apiClient.hypervisor = "XenServer" #Defaults to Xenserver def updateConfiguration(self, globalCfg): if globalCfg is None: diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 6c285233a82..1d86c6c1599 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -5,9 +5,9 @@ # 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 @@ -22,7 +22,7 @@ import marvin from utils import is_server_ssh_ready, random_gen from marvin.cloudstackAPI import * -#Import System modules +# Import System modules import time import hashlib import base64 @@ -54,8 +54,12 @@ class Domain: cmd.parentdomainid = parentdomainid elif "parentdomainid" in services: cmd.parentdomainid = services["parentdomainid"] - - return Domain(apiclient.createDomain(cmd).__dict__) + try: + domain = apiclient.createDomain(cmd) + if domain is not None: + return Domain(domain.__dict__) + except Exception as e: + raise e def delete(self, apiclient, cleanup=None): """Delete an domain""" @@ -83,7 +87,7 @@ class Account: """Creates an account""" cmd = createAccount.createAccountCmd() - #0 - User, 1 - Root Admin, 2 - Domain Admin + # 0 - User, 1 - Root Admin, 2 - Domain Admin cmd.accounttype = 2 if (admin and domainid) else int(admin) cmd.email = services["email"] @@ -213,14 +217,15 @@ class VirtualMachine: else: self.ssh_port = 22 self.ssh_client = None - #extract out the ipaddress + # extract out the ipaddress self.ipaddress = self.nic[0].ipaddress @classmethod def create(cls, apiclient, services, templateid=None, accountid=None, domainid=None, zoneid=None, networkids=None, serviceofferingid=None, securitygroupids=None, projectid=None, startvm=None, - diskofferingid=None, affinitygroupnames=None, hostid=None, mode='basic', method='GET'): + diskofferingid=None, affinitygroupnames=None, group=None, + hostid=None, keypair=None, mode='basic', method='GET'): """Create the instance""" cmd = deployVirtualMachine.deployVirtualMachineCmd() @@ -234,7 +239,13 @@ class VirtualMachine: cmd.zoneid = zoneid elif "zoneid" in services: cmd.zoneid = services["zoneid"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor + + if "displayname" in services: + cmd.displayname = services["displayname"] + + if "name" in services: + cmd.name = services["name"] if accountid: cmd.account = accountid @@ -256,9 +267,16 @@ class VirtualMachine: elif "template" in services: cmd.templateid = services["template"] - if "diskoffering" in services: + if diskofferingid: + cmd.diskofferingid = diskofferingid + elif "diskoffering" in services: cmd.diskofferingid = services["diskoffering"] + if keypair: + cmd.keypair = keypair + elif "keypair" in services: + cmd.keypair = services["keypair"] + if securitygroupids: cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids] @@ -282,6 +300,15 @@ class VirtualMachine: virtual_machine = apiclient.deployVirtualMachine(cmd, method=method) + if group: + cmd.group = group + virtual_machine = apiclient.deployVirtualMachine(cmd) + + if startvm == False: + virtual_machine.ssh_ip = virtual_machine.nic[0].ipaddress + virtual_machine.public_ip = virtual_machine.nic[0].ipaddress + return VirtualMachine(virtual_machine.__dict__, services) + # VM should be in Running state after deploy timeout = 10 while True: @@ -308,14 +335,14 @@ class VirtualMachine: virtual_machine.domainid, services ) - fw_rule = FireWallRule.create( + FireWallRule.create( apiclient, ipaddressid=public_ip.ipaddress.id, protocol='TCP', cidrlist=['0.0.0.0/0'], startport=22, endport=22 - ) + ) nat_rule = NATRule.create( apiclient, virtual_machine, @@ -348,7 +375,13 @@ class VirtualMachine: cmd.id = self.id apiclient.rebootVirtualMachine(cmd) - def get_ssh_client(self, ipaddress=None, reconnect=False, port=None): + def recover(self, apiclient): + """Recover the instance""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.id = self.id + apiclient.recoverVirtualMachine(cmd) + + def get_ssh_client(self, ipaddress=None, reconnect=False, port=None, keyPairFileLocation=None): """Get SSH object of VM""" # If NAT Rules are not created while VM deployment in Advanced mode @@ -358,27 +391,56 @@ class VirtualMachine: if port: self.ssh_port = port + if keyPairFileLocation is not None: + self.password = None + if reconnect: self.ssh_client = is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) self.ssh_client = self.ssh_client or is_server_ssh_ready( self.ssh_ip, self.ssh_port, self.username, - self.password + self.password, + keyPairFileLocation=keyPairFileLocation ) return self.ssh_client + def resetSshKey(self, apiclient, **kwargs): + """Resets SSH key""" + + cmd = resetSSHKeyForVirtualMachine.resetSSHKeyForVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.resetSSHKeyForVirtualMachine(cmd)) + + def update(self, apiclient, **kwargs): + """Updates the VM data""" + + cmd = updateVirtualMachine.updateVirtualMachineCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.updateVirtualMachine(cmd)) + def delete(self, apiclient): """Destroy an Instance""" cmd = destroyVirtualMachine.destroyVirtualMachineCmd() cmd.id = self.id apiclient.destroyVirtualMachine(cmd) + def migrate(self, apiclient, hostid=None): + """migrate an Instance""" + cmd = migrateVirtualMachine.migrateVirtualMachineCmd() + cmd.virtualmachineid = self.id + if hostid: + cmd.hostid = hostid + apiclient.migrateVirtualMachine(cmd) + def attach_volume(self, apiclient, volume): """Attach volume to instance""" cmd = attachVolume.attachVolumeCmd() @@ -394,7 +456,7 @@ class VirtualMachine: def add_nic(self, apiclient, networkId): """Add a NIC to a VM""" - cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd(); + cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd() cmd.virtualmachineid = self.id cmd.networkid = networkId return apiclient.addNicToVirtualMachine(cmd) @@ -413,6 +475,26 @@ class VirtualMachine: cmd.virtualmachineid = self.id return apiclient.updateDefaultNicForVirtualMachine(cmd) + def attach_iso(self, apiclient, iso): + """Attach ISO to instance""" + cmd = attachIso.attachIsoCmd() + cmd.id = iso.id + cmd.virtualmachineid = self.id + return apiclient.attachIso(cmd) + + def detach_iso(self, apiclient): + """Detach ISO to instance""" + cmd = detachIso.detachIsoCmd() + cmd.id = self.id + return apiclient.detachIso(cmd) + + def change_service_offering(self, apiclient, serviceOfferingId): + """Change service offering of the instance""" + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.id = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all VMs matching criteria""" @@ -428,16 +510,14 @@ class VirtualMachine: cmd.id = self.id try: response = apiclient.resetPasswordForVirtualMachine(cmd) - print response except Exception as e: raise Exception("Reset Password failed! - %s" % e) - print type(response) if isinstance(response, list): return response[0].password class Volume: - """Manage Volume Lifecycle + """Manage Volume Life cycle """ def __init__(self, items): self.__dict__.update(items) @@ -533,7 +613,7 @@ class Volume: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVolumes(cmd)) - def resize(cls, apiclient, **kwargs): + def resize(self, apiclient, **kwargs): """Resize a volume""" cmd = resizeVolume.resizeVolumeCmd() cmd.id = self.id @@ -541,6 +621,58 @@ class Volume: return(apiclient.resizeVolume(cmd)) @classmethod + def upload(cls, apiclient, services, zoneid=None, account=None, domainid=None, url=None): + """Uploads the volume to specified account""" + + cmd = uploadVolume.uploadVolumeCmd() + if zoneid: + cmd.zoneid = zoneid + if account: + cmd.account = account + if domainid: + cmd.domainid = domainid + cmd.format = services["format"] + cmd.name = services["diskname"] + if url: + cmd.url = url + else: + cmd.url = services["url"] + return Volume(apiclient.uploadVolume(cmd).__dict__) + + def wait_for_upload(self, apiclient, timeout=5, interval=60): + """Wait for upload""" + # Sleep to ensure template is in proper state before download + time.sleep(interval) + + while True: + volume_response = Volume.list( + apiclient, + id=self.id, + zoneid=self.zoneid, + ) + if isinstance(volume_response, list): + + volume = volume_response[0] + # If volume is ready, + # volume.state = Allocated + if volume.state == 'Uploaded': + break + + elif 'Uploading' in volume.state: + time.sleep(interval) + + elif 'Installing' not in volume.state: + raise Exception( + "Error in uploading volume: status - %s" % + volume.state) + elif timeout == 0: + break + + else: + time.sleep(interval) + timeout = timeout - 1 + return + def migrate(cls, apiclient, **kwargs): """Migrate a volume""" cmd = migrateVolume.migrateVolumeCmd() @@ -592,7 +724,7 @@ class Template: def create(cls, apiclient, services, volumeid=None, account=None, domainid=None, projectid=None): """Create template from Volume""" - #Create template from Virtual machine and Volume ID + # Create template from Virtual machine and Volume ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([services["name"], random_gen()]) @@ -617,7 +749,6 @@ class Template: 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 - cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False if volumeid: cmd.volumeid = volumeid @@ -637,12 +768,12 @@ class Template: account=None, domainid=None): """Create template from URL""" - #Create template from Virtual machine and Volume ID + # 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.hypervisor = apiclient.hypervisor if "ostypeid" in services: cmd.ostypeid = services["ostypeid"] @@ -689,7 +820,7 @@ class Template: def create_from_snapshot(cls, apiclient, snapshot, services, random_name=True): """Create Template from snapshot""" - #Create template from Virtual machine and Snapshot ID + # Create template from Virtual machine and Snapshot ID cmd = createTemplate.createTemplateCmd() cmd.displaytext = services["displaytext"] cmd.name = "-".join([ @@ -726,7 +857,7 @@ class Template: def download(self, apiclient, timeout=5, interval=60): """Download Template""" - #Sleep to ensure template is in proper state before download + # Sleep to ensure template is in proper state before download time.sleep(interval) while True: @@ -789,7 +920,7 @@ class Iso: def create(cls, apiclient, services, account=None, domainid=None, projectid=None): """Create an ISO""" - #Create ISO from URL + # Create ISO from URL cmd = registerIso.registerIsoCmd() cmd.displaytext = services["displaytext"] cmd.name = services["name"] @@ -841,7 +972,7 @@ class Iso: def download(self, apiclient, timeout=5, interval=60): """Download an ISO""" - #Ensuring ISO is successfully downloaded + # Ensuring ISO is successfully downloaded while True: time.sleep(interval) @@ -853,7 +984,6 @@ class Iso: response = iso_response[0] # Again initialize timeout to avoid listISO failure timeout = 5 - print response.status # Check whether download is in progress(for Ex:10% Downloaded) # or ISO is 'Successfully Installed' if response.status == 'Successfully Installed': @@ -940,7 +1070,7 @@ class NATRule: @classmethod def create(cls, apiclient, virtual_machine, services, ipaddressid=None, - projectid=None, networkid=None): + projectid=None, openfirewall=False, networkid=None, vpcid=None): """Create Port forwarding rule""" cmd = createPortForwardingRule.createPortForwardingRuleCmd() @@ -951,15 +1081,24 @@ class NATRule: cmd.privateport = services["privateport"] cmd.publicport = services["publicport"] + if "privateendport" in services: + cmd.privateendport = services["privateendport"] + if "publicendport" in services: + cmd.publicendport = services["publicendport"] cmd.protocol = services["protocol"] cmd.virtualmachineid = virtual_machine.id if projectid: cmd.projectid = projectid + if openfirewall: + cmd.openfirewall = True + if networkid: cmd.networkid = networkid + if vpcid: + cmd.vpcid = vpcid return NATRule(apiclient.createPortForwardingRule(cmd).__dict__) def delete(self, apiclient): @@ -985,10 +1124,10 @@ class StaticNATRule: self.__dict__.update(items) @classmethod - def create(cls, apiclient, services, ipaddressid=None, vpcid=None): + def create(cls, apiclient, services, ipaddressid=None, networkid=None, vpcid=None): """Creates static ip forwarding rule""" - cmd = createIpForwardingRule.createIpForwardingRuleCmd() + cmd = createFirewallRule.createFirewallRuleCmd() cmd.protocol = services["protocol"] cmd.startport = services["startport"] @@ -1003,10 +1142,12 @@ class StaticNATRule: elif "ipaddressid" in services: cmd.ipaddressid = services["ipaddressid"] + if networkid: + cmd.networkid = networkid + if vpcid: cmd.vpcid = vpcid - - return StaticNATRule(apiclient.createIpForwardingRule(cmd).__dict__) + return StaticNATRule(apiclient.createFirewallRule(cmd).__dict__) def delete(self, apiclient): """Delete IP forwarding rule""" @@ -1024,12 +1165,14 @@ class StaticNATRule: return(apiclient.listIpForwardingRules(cmd)) @classmethod - def enable(cls, apiclient, ipaddressid, virtualmachineid): + def enable(cls, apiclient, ipaddressid, virtualmachineid, networkid=None): """Enables Static NAT rule""" cmd = enableStaticNat.enableStaticNatCmd() cmd.ipaddressid = ipaddressid cmd.virtualmachineid = virtualmachineid + if networkid: + cmd.networkid = networkid apiclient.enableStaticNat(cmd) return @@ -1105,6 +1248,14 @@ class ServiceOffering: if "storagetype" in services: cmd.storagetype = services["storagetype"] + if "systemvmtype" in services: + cmd.systemvmtype = services['systemvmtype'] + + if "issystem" in services: + cmd.issystem = services['issystem'] + + if "tags" in services: + cmd.tags = services["tags"] # Service Offering private to that domain if domainid: cmd.domainid = domainid @@ -1183,20 +1334,25 @@ class NetworkOffering: cmd.displaytext = "-".join([services["displaytext"], random_gen()]) cmd.name = "-".join([services["name"], random_gen()]) cmd.guestiptype = services["guestiptype"] - cmd.supportedservices = services["supportedservices"] + cmd.supportedservices = '' + if "supportedservices" in services: + cmd.supportedservices = services["supportedservices"] cmd.traffictype = services["traffictype"] + if "useVpc" in services: + cmd.useVpc = services["useVpc"] cmd.serviceProviderList = [] - for service, provider in services["serviceProviderList"].items(): - cmd.serviceProviderList.append({ + if "serviceProviderList" in services: + for service, provider in services["serviceProviderList"].items(): + cmd.serviceProviderList.append({ 'service': service, 'provider': provider }) if "servicecapabilitylist" in services: - cmd.servicecapabilitylist = [] + cmd.serviceCapabilityList = [] for service, capability in services["servicecapabilitylist"].items(): for ctype, value in capability.items(): - cmd.servicecapabilitylist.append({ + cmd.serviceCapabilityList.append({ 'service': service, 'capabilitytype': ctype, 'capabilityvalue': value @@ -1205,6 +1361,7 @@ class NetworkOffering: cmd.specifyVlan = services["specifyVlan"] if "specifyIpRanges" in services: cmd.specifyIpRanges = services["specifyIpRanges"] + cmd.availability = 'Optional' [setattr(cmd, k, v) for k, v in kwargs.items()] @@ -1275,7 +1432,7 @@ class LoadBalancerRule: @classmethod def create(cls, apiclient, services, ipaddressid=None, accountid=None, - networkid=None, projectid=None, domainid=None): + networkid=None, vpcid=None, projectid=None, domainid=None): """Create Load balancing Rule""" cmd = createLoadBalancerRule.createLoadBalancerRuleCmd() @@ -1293,6 +1450,8 @@ class LoadBalancerRule: if domainid: cmd.domainid = domainid + if vpcid: + cmd.vpcid = vpcid cmd.name = services["name"] cmd.algorithm = services["alg"] cmd.privateport = services["privateport"] @@ -1359,19 +1518,19 @@ class LoadBalancerRule: for name, value in param.items(): cmd.param.append({'name': name, 'value': value}) return apiclient.createLBStickinessPolicy(cmd) - + def deleteSticky(self, apiclient, id): """Deletes stickyness policy""" - + cmd = deleteLBStickinessPolicy.deleteLBStickinessPolicyCmd() cmd.id = id return apiclient.deleteLBStickinessPolicy(cmd) - + @classmethod def listStickyPolicies(cls, apiclient, lbruleid, **kwargs): """Lists stickiness policies for load balancing rule""" - - cmd= listLBStickinessPolicies.listLBStickinessPoliciesCmd() + + cmd = listLBStickinessPolicies.listLBStickinessPoliciesCmd() cmd.lbruleid = lbruleid [setattr(cmd, k, v) for k, v in kwargs.items()] return apiclient.listLBStickinessPolicies(cmd) @@ -1396,7 +1555,7 @@ class Cluster: """Create Cluster""" cmd = addCluster.addClusterCmd() cmd.clustertype = services["clustertype"] - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor if zoneid: cmd.zoneid = zoneid @@ -1446,7 +1605,7 @@ class Host: """Create Host in cluster""" cmd = addHost.addHostCmd() - cmd.hypervisor = services["hypervisor"] + cmd.hypervisor = apiclient.hypervisor cmd.url = services["url"] cmd.clusterid = cluster.id @@ -1493,6 +1652,29 @@ class Host: cmd.id = self.id return apiclient.prepareHostForMaintenance(cmd) + @classmethod + def enableMaintenance(cls, apiclient, id): + """enables maintainance mode Host""" + + cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() + cmd.id = id + return apiclient.prepareHostForMaintenance(cmd) + + def cancelMaintenance(self, apiclient): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = self.id + return apiclient.cancelHostMaintenance(cmd) + + @classmethod + def cancelMaintenance(cls, apiclient, id): + """Cancels maintainance mode Host""" + + cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() + cmd.id = id + return apiclient.cancelHostMaintenance(cmd) + @classmethod def list(cls, apiclient, **kwargs): """List all Hosts matching criteria""" @@ -1586,7 +1768,8 @@ class Network: @classmethod def create(cls, apiclient, services, accountid=None, domainid=None, - networkofferingid=None, projectid=None, zoneid=None, + networkofferingid=None, projectid=None, + subdomainaccess=None, zoneid=None, gateway=None, netmask=None, vpcid=None, guestcidr=None): """Create Network for account""" cmd = createNetwork.createNetworkCmd() @@ -1603,6 +1786,9 @@ class Network: elif "zoneid" in services: cmd.zoneid = services["zoneid"] + if subdomainaccess is not None: + cmd.subdomainaccess = subdomainaccess + if gateway: cmd.gateway = gateway elif "gateway" in services: @@ -1717,7 +1903,7 @@ class Vpn: @classmethod def create(cls, apiclient, publicipid, account=None, domainid=None, - projectid=None, vpcid=None): + projectid=None, networkid=None, vpcid=None): """Create VPN for Public IP address""" cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd() cmd.publicipid = publicipid @@ -1727,6 +1913,8 @@ class Vpn: cmd.domainid = domainid if projectid: cmd.projectid = projectid + if networkid: + cmd.networkid = networkid if vpcid: cmd.vpcid = vpcid return Vpn(apiclient.createRemoteAccessVpn(cmd).__dict__) @@ -1755,10 +1943,11 @@ class VpnUser: @classmethod def create(cls, apiclient, username, password, account=None, domainid=None, - projectid=None): + projectid=None, rand_name=True): """Create VPN user""" cmd = addVpnUser.addVpnUserCmd() - cmd.username = username + cmd.username = "-".join([username, + random_gen()]) if rand_name else username cmd.password = password if account: @@ -1997,6 +2186,7 @@ class PhysicalNetwork: [setattr(cmd, k, v) for k, v in kwargs.items()] return map(lambda pn : PhysicalNetwork(pn.__dict__), apiclient.listPhysicalNetworks(cmd)) + class SecurityGroup: """Manage Security Groups""" @@ -2364,6 +2554,104 @@ class NetworkServiceProvider: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listNetworkServiceProviders(cmd)) + +class Router: + """Manage router life cycle""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def start(cls, apiclient, id): + """Starts the router""" + cmd = startRouter.startRouterCmd() + cmd.id = id + return apiclient.startRouter(cmd) + + @classmethod + def stop(cls, apiclient, id, forced=None): + """Stops the router""" + cmd = stopRouter.stopRouterCmd() + cmd.id = id + if forced: + cmd.forced = forced + return apiclient.stopRouter(cmd) + + @classmethod + def reboot(cls, apiclient, id): + """Reboots the router""" + cmd = rebootRouter.rebootRouterCmd() + cmd.id = id + return apiclient.rebootRouter(cmd) + + @classmethod + def destroy(cls, apiclient, id): + """Destroy the router""" + cmd = destroyRouter.destroyRouterCmd() + cmd.id = id + return apiclient.destroyRouter(cmd) + + @classmethod + def change_service_offering(cls, apiclient, id, serviceofferingid): + """Change service offering of the router""" + cmd = changeServiceForRouter.changeServiceForRouterCmd() + cmd.id = id + cmd.serviceofferingid = serviceofferingid + return apiclient.changeServiceForRouter(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List routers""" + + cmd = listRouters.listRoutersCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRouters(cmd)) + + +class Tag: + """Manage tags""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, resourceIds, resourceType, tags): + """Create tags""" + + cmd = createTags.createTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + return Tag(apiclient.createTags(cmd).__dict__) + + def delete(self, apiclient, resourceIds, resourceType, tags): + """Delete tags""" + + cmd = deleteTags.deleteTagsCmd() + cmd.resourceIds = resourceIds + cmd.resourcetype = resourceType + cmd.tags = [] + for key, value in tags.items(): + cmd.tags.append({ + 'key': key, + 'value': value + }) + apiclient.deleteTags(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all tags matching the criteria""" + + cmd = listTags.listTagsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listTags(cmd)) + + class VpcOffering: """Manage VPC offerings""" @@ -2417,7 +2705,7 @@ class VPC: @classmethod def create(cls, apiclient, services, vpcofferingid, - zoneid, networkDomain=None, account=None, domainid=None): + zoneid, networkDomain=None, account=None, domainid=None): """Creates the virtual private connection (VPC)""" cmd = createVPC.createVPCCmd() @@ -2467,6 +2755,40 @@ class VPC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) + +class PrivateGateway: + """Manage private gateway lifecycle""" + def create(cls, apiclient, gateway, ipaddress, netmask, vlan, vpcid, + physicalnetworkid=None): + """Create private gateway""" + + cmd = createPrivateGateway.createPrivateGatewayCmd() + cmd.gateway = gateway + cmd.ipaddress = ipaddress + cmd.netmask = netmask + cmd.vlan = vlan + cmd.vpcid = vpcid + if physicalnetworkid: + cmd.physicalnetworkid = physicalnetworkid + + return PrivateGateway(apiclient.createPrivateGateway(cmd).__dict__) + + def delete(self, apiclient): + """Delete private gateway""" + + cmd = deletePrivateGateway.deletePrivateGatewayCmd() + cmd.id = self.id + return apiclient.deletePrivateGateway(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List private gateways""" + + cmd = listPrivateGateways.listPrivateGatewaysCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listPrivateGateways(cmd)) + + class AffinityGroup: def __init__(self, items): self.__dict__.update(items) @@ -2495,9 +2817,35 @@ class AffinityGroup: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listVPCs(cmd)) +class StaticRoute: + """Manage static route lifecycle""" + @classmethod + def create(cls, apiclient, cidr, gatewayid): + """Create static route""" + + cmd = createStaticRoute.createStaticRouteCmd() + cmd.cidr = cidr + cmd.gatewayid = gatewayid + return StaticRoute(apiclient.createStaticRoute(cmd).__dict__) + + def delete(self, apiclient): + """Delete static route""" + + cmd = deleteStaticRoute.deleteStaticRouteCmd() + cmd.id = self.id + return apiclient.deleteStaticRoute(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List static route""" + + cmd = listStaticRoutes.listStaticRoutesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listStaticRoutes(cmd)) + + class VNMC: """Manage VNMC lifecycle""" - def __init__(self, items): self.__dict__.update(items) @@ -2526,13 +2874,153 @@ class VNMC: [setattr(cmd, k, v) for k, v in kwargs.items()] return(apiclient.listCiscoVnmcResources(cmd)) -class ASA1000V: - """Manage ASA 1000v lifecycle""" + +class SSHKeyPair: + """Manage SSH Key pairs""" + + def __init__(self, items, services): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, name=None, account=None, + domainid=None, projectid=None): + """Creates SSH keypair""" + cmd = createSSHKeyPair.createSSHKeyPairCmd() + cmd.name = name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + return (apiclient.createSSHKeyPair(cmd)) + + def delete(self, apiclient): + """Delete SSH key pair""" + cmd = deleteSSHKeyPair.deleteSSHKeyPairCmd() + cmd.name = self.name + apiclient.deleteSSHKeyPair(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all SSH key pairs""" + cmd = listSSHKeyPairs.listSSHKeyPairsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listSSHKeyPairs(cmd)) + + +class Capacities: + """Manage Capacities""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists capacities""" + + cmd = listCapacity.listCapacityCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listCapacity(cmd)) + + +class Alert: + """Manage alerts""" + + @classmethod + def list(cls, apiclient, **kwargs): + """Lists alerts""" + + cmd = listAlerts.listAlertsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listAlerts(cmd)) + + +class InstanceGroup: + """Manage VM instance groups""" def __init__(self, items): self.__dict__.update(items) @classmethod + def create(cls, apiclient, name=None, account=None, domainid=None, + projectid=None, networkid=None, rand_name=True): + """Creates instance groups""" + + cmd = createInstanceGroup.createInstanceGroupCmd() + cmd.name = "-".join([name, random_gen()]) if rand_name else name + if account is not None: + cmd.account = account + if domainid is not None: + cmd.domainid = domainid + if projectid is not None: + cmd.projectid = projectid + if networkid is not None: + cmd.networkid = networkid + return InstanceGroup(apiclient.createInstanceGroup(cmd).__dict__) + + def delete(self, apiclient): + """Delete instance group""" + cmd = deleteInstanceGroup.deleteInstanceGroupCmd() + cmd.id = self.id + apiclient.deleteInstanceGroup(cmd) + + def update(self, apiclient, **kwargs): + """Updates the instance groups""" + cmd = updateInstanceGroup.updateInstanceGroupCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.updateInstanceGroup(cmd)) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all instance groups""" + cmd = listInstanceGroups.listInstanceGroupsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return (apiclient.listInstanceGroups(cmd)) + + def startInstances(self, apiclient): + """Starts all instances in a VM tier""" + + cmd = startVirtualMachine.startVirtualMachineCmd() + cmd.group = self.id + return apiclient.startVirtualMachine(cmd) + + def stopInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = stopVirtualMachine.stopVirtualMachineCmd() + cmd.group = self.id + return apiclient.stopVirtualMachine(cmd) + + def rebootInstances(self, apiclient): + """Reboot all instances in a VM tier""" + + cmd = rebootVirtualMachine.rebootVirtualMachineCmd() + cmd.group = self.id + return apiclient.rebootVirtualMachine(cmd) + + def deleteInstances(self, apiclient): + """Stops all instances in a VM tier""" + + cmd = destroyVirtualMachine.destroyVirtualMachineCmd() + cmd.group = self.id + return apiclient.destroyVirtualMachine(cmd) + + def changeServiceOffering(self, apiclient, serviceOfferingId): + """Change service offering of the vm tier""" + + cmd = changeServiceForVirtualMachine.changeServiceForVirtualMachineCmd() + cmd.group = self.id + cmd.serviceofferingid = serviceOfferingId + return apiclient.changeServiceForVirtualMachine(cmd) + + def recoverInstances(self, apiclient): + """Recover the instances from vm tier""" + cmd = recoverVirtualMachine.recoverVirtualMachineCmd() + cmd.group = self.id + apiclient.recoverVirtualMachine(cmd) + + +class ASA1000V: + """Manage ASA 1000v lifecycle""" def create(cls, apiclient, hostname, insideportprofile, clusterid, physicalnetworkid): """Registers ASA 1000v appliance""" diff --git a/tools/marvin/marvin/integration/lib/utils.py b/tools/marvin/marvin/integration/lib/utils.py index cff24a1b2d5..6892c41d1ec 100644 --- a/tools/marvin/marvin/integration/lib/utils.py +++ b/tools/marvin/marvin/integration/lib/utils.py @@ -106,12 +106,17 @@ def cleanup_resources(api_client, resources): obj.delete(api_client) -def is_server_ssh_ready(ipaddress, port, username, password, retries=50): +def is_server_ssh_ready(ipaddress, port, username, password, retries=50, keyPairFileLocation=None): """Return ssh handle else wait till sshd is running""" loop_cnt = retries while True: try: - ssh = remoteSSHClient(ipaddress, port, username, password) + ssh = remoteSSHClient( + host=ipaddress, + port=port, + user=username, + passwd=password, + keyPairFileLocation=keyPairFileLocation) except Exception as e: if loop_cnt == 0: raise e @@ -149,12 +154,16 @@ def fetch_api_client(config_file='datacenterCfg'): ) -def get_process_status(hostip, port, username, password, linklocalip, process): +def get_process_status(hostip, port, username, password, linklocalip, process, hypervisor=None): """Double hop and returns a process status""" #SSH to the machine ssh = remoteSSHClient(hostip, port, username, password) - ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + if str(hypervisor).lower() == 'vmware': + ssh_command = "ssh -i /var/lib/cloud/management/.ssh/id_rsa -ostricthostkeychecking=no " + else: + ssh_command = "ssh -i ~/.ssh/id_rsa.cloud -ostricthostkeychecking=no " + ssh_command = ssh_command + \ "-oUserKnownHostsFile=/dev/null -p 3922 %s %s" % ( linklocalip, diff --git a/tools/marvin/marvin/remoteSSHClient.py b/tools/marvin/marvin/remoteSSHClient.py index 4fb2f0de8f0..04450fdf0e2 100644 --- a/tools/marvin/marvin/remoteSSHClient.py +++ b/tools/marvin/marvin/remoteSSHClient.py @@ -23,11 +23,12 @@ import logging from contextlib import closing class remoteSSHClient(object): - def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO): + def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO, keyPairFileLocation=None): self.host = host self.port = port self.user = user self.passwd = passwd + self.keyPairFile = keyPairFileLocation self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.logger = logging.getLogger('sshClient') @@ -38,8 +39,19 @@ class remoteSSHClient(object): retry_count = retries while True: try: - self.ssh.connect(str(host),int(port), user, passwd) - self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + if keyPairFileLocation == None: + self.ssh.connect(str(host),int(port), user, passwd) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) + else: + self.ssh.connect( + hostname=str(host), + port=int(port), + username=str(user), + key_filename=str(keyPairFileLocation), + look_for_keys=False + ) + self.logger.debug("connecting to server %s with user %s key %s"%(str(host), user, keyPairFileLocation)) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) except paramiko.SSHException, sshex: if retry_count == 0: raise cloudstackException.InvalidParameterException(repr(sshex))