1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

oVirt connector SHOULD work fine right now (but needs more testing... :P).

Have the "volPath" problem (inside vsdm/clientIF.py) at this time, solved by patching my installation, but i have to find a definitive solution.

Will do also tests with "real" vms (not just small 1Gb with no os to test platform), but this should work fine. (we will see..)
This commit is contained in:
Adolfo Gómez 2012-11-23 11:47:58 +00:00
parent 0eea8a33b5
commit 830e1b2e6f
4 changed files with 163 additions and 70 deletions

View File

@ -38,7 +38,7 @@ import logging
logger = logging.getLogger(__name__)
opCreate, opStart, opStop, opSuspend, opRemove, opWait, opError, opFinish, opRetry = range(9)
opCreate, opStart, opStop, opSuspend, opRemove, opWait, opError, opFinish, opRetry, opChangeMac = range(10)
class OVirtLinkedDeployment(UserDeployment):
'''
@ -203,14 +203,18 @@ class OVirtLinkedDeployment(UserDeployment):
def __initQueueForDeploy(self, forLevel2 = False):
if forLevel2 is False:
self._queue = [opCreate, opStart, opFinish]
self._queue = [opCreate, opChangeMac, opStart, opFinish]
else:
self._queue = [opCreate, opStart, opWait, opSuspend, opFinish]
self._queue = [opCreate, opChangeMac, opStart, opWait, opSuspend, opFinish]
def __checkMachineState(self, chkState):
logger.debug('Checking that state of machine {0} is {1}'.format(self._vmid, chkState))
state = self.service().getMachineState(self._vmid)
# If we want to check an state and machine does not exists (except in case that we whant to check this)
if state == 'unknown' and chkState != 'unknown':
return self.__error('Machine not found')
if state != chkState:
return State.RUNNING
@ -249,7 +253,7 @@ class OVirtLinkedDeployment(UserDeployment):
return State.ERROR
def __executeQueue(self):
self.__debugQueue('executeQueue')
self.__debug('executeQueue')
op = self.__getCurrentOp()
if op == opError:
@ -259,12 +263,13 @@ class OVirtLinkedDeployment(UserDeployment):
return State.FINISHED
fncs = { opCreate: self.__create,
opRetry: self.__retry,
opRetry: self.__retry,
opStart: self.__startMachine,
opStop: self.__stopMachine,
opSuspend: self.__suspendMachine,
opWait: self.__wait,
opRemove: self.__remove
opRemove: self.__remove,
opChangeMac: self.__changeMac
}
try:
@ -273,9 +278,9 @@ class OVirtLinkedDeployment(UserDeployment):
if execFnc is None:
return self.__error('Unknown operation found at execution queue ({0})'.format(op))
state = execFnc()
execFnc()
return state
return State.RUNNING
except Exception as e:
return self.__error(e)
@ -285,6 +290,8 @@ class OVirtLinkedDeployment(UserDeployment):
Used to retry an operation
In fact, this will not be never invoked, unless we push it twice, because
checkState method will "pop" first item when a check operation returns State.FINISHED
At executeQueue this return value will be ignored, and it will only be used at checkState
'''
return State.FINISHED
@ -306,65 +313,76 @@ class OVirtLinkedDeployment(UserDeployment):
if self._vmid is None:
raise Exception('Can\'t create machine')
return State.RUNNING
def __remove(self):
'''
Removes a machine from system
'''
state = self.service().getMachineState(self._vmid)
if state == 'unknown':
raise Exception('Machine not found')
if state != 'down' and state != 'suspended':
self.__pushFrontOp(opStop)
return State.RUNNING
self.service().removeMachine(self._vmid)
return State.RUNNING
else:
self.service().removeMachine(self._vmid)
def __startMachine(self):
'''
Powers on the machine
'''
state = self.service().getMachineState(self._vmid)
if state == 'up':
return State.FINISHED
if state == 'unknown':
raise Exception('Machine not found')
if state == 'up': # Already started, return
return
if state != 'down':
self.__pushFrontOp(opRetry) # Remember here, the return State.FINISH will make this retry be "poped" right ar return
return State.FINISHED
self.service().startMachine(self._vmid)
return State.RUNNING
self.__pushFrontOp(opRetry) # Will call "check Retry", that will finish inmediatly and again call this one
else:
self.service().startMachine(self._vmid)
def __stopMachine(self):
'''
Powers off the machine
'''
state = self.service().getMachineState(self._vmid)
if state == 'down':
return State.FINISHED
if state == 'unknown':
raise Exception('Machine not found')
if state == 'down': # Already stoped, return
return
if state != 'up':
self.__pushBackOp(opRetry) # Remember here, the return State.FINISH will make this retry be "poped" right ar return
return State.FINISHED
self.service().stopMachine(self._vmid)
return State.RUNNING
self.__pushBackOp(opRetry) # Will call "check Retry", that will finish inmediatly and again call this one
else:
self.service().stopMachine(self._vmid)
def __suspendMachine(self):
'''
Suspends the machine
'''
state = self.service().getMachineState(self._vmid)
if state == 'suspended':
return State.FINISHED
if state == 'unknown':
raise Exception('Machine not found')
if state == 'suspended': # Already suspended, return
return
if state != 'up':
self.__pushBackOp(opRetry) # Remember here, the return State.FINISH will make this retry be "poped" right ar return
return State.FINISHED
else:
self.service().suspendMachine(self._vmid)
self.service().suspendMachine(self._vmid)
return State.RUNNING
def __changeMac(self):
'''
Changes the mac of the first nic
'''
self.service().updateMachineMac(self._vmid, self.getUniqueId())
# Check methods
def __checkCreate(self):
@ -397,11 +415,19 @@ class OVirtLinkedDeployment(UserDeployment):
'''
return self.__checkMachineState('unknown')
def __checkMac(self):
'''
Checks if change mac operation has finished.
Changing nic configuration es 1-step operation, so when we check it here, it is already done
'''
return State.FINISHED
def checkState(self):
'''
Check what operation is going on, and acts acordly to it
'''
self.__debugQueue('checkState')
self.__debug('checkState')
op = self.__getCurrentOp()
if op == opError:
@ -416,7 +442,8 @@ class OVirtLinkedDeployment(UserDeployment):
opStart: self.__checkStart,
opStop: self.__checkStop,
opSuspend: self.__checkSuspend,
opRemove: self.__checkRemoved
opRemove: self.__checkRemoved,
opChangeMac: self.__checkMac
}
try:
@ -438,8 +465,8 @@ class OVirtLinkedDeployment(UserDeployment):
'''
Invoked when the core notices that the deployment of a service has finished.
(No matter wether it is for cache or for an user)
'''
self.__debug('finish')
pass
def assignToUser(self, user):
@ -483,16 +510,19 @@ class OVirtLinkedDeployment(UserDeployment):
'''
Invoked for destroying a deployed service
'''
self.__debug('destroy')
# If executing something, wait until finished to remove it
# We simply replace the execution queue
op = self.__getCurrentOp()
if op == opFinish or op == opWait:
self._queue = [opStop, opRemove]
return self.__executeQueue()
if op == opError:
return self.__error('Machine is already in error state!')
self._queue = [op, opStop, opRemove]
if op == opFinish or op == opWait:
self._queue = [opStop, opRemove, opFinish]
return self.__executeQueue()
self._queue = [op, opStop, opRemove, opFinish]
# Do not execute anything.here, just continue normally
return State.RUNNING
@ -519,9 +549,14 @@ class OVirtLinkedDeployment(UserDeployment):
opWait: 'wait',
opError: 'error',
opFinish: 'finish',
opRetry: 'retry'
opRetry: 'retry',
opChangeMac: 'changing mac'
}.get(op, '????')
def __debugQueue(self, txt):
def __debug(self, txt):
logger.debug('_name {0}: {1}'.format(txt, self._name))
logger.debug('_ip {0}: {1}'.format(txt, self._ip))
logger.debug('_mac {0}: {1}'.format(txt, self._mac))
logger.debug('_vmid {0}: {1}'.format(txt, self._vmid))
logger.debug('Queue at {0}: {1}'.format(txt,[OVirtLinkedDeployment.__op2str(op) for op in self._queue ]))

View File

@ -112,6 +112,14 @@ class OVirtLinkedService(Service):
lenName = gui.NumericField(length = 1, label = translatable('Name Length'), defvalue = 5, order = 5,
tooltip = translatable('Length of numeric part for the names of this machines (betwen 3 and 6'), required = True)
display = gui.ChoiceField(label = translatable('Display'), rdonly = False, order = 6,
tooltip = translatable('Display type (only for administration pourposses)'),
values = [ gui.choiceItem('spice', 'Spice'),
gui.choiceItem('vnc', 'Vnc')
],
defvalue = '1' # Default value is the ID of the choicefield
)
ov = gui.HiddenField()
ev = gui.HiddenField() # We need to keep the env so we can instantiate the Provider
@ -169,7 +177,7 @@ class OVirtLinkedService(Service):
Raises an exception if operation fails.
'''
return self.parent().makeTemplate(name, comments, self.machine.value, self.cluster.value, self.datastore.value)
return self.parent().makeTemplate(name, comments, self.machine.value, self.cluster.value, self.datastore.value, self.display.value)
def getTemplateState(self, templateId):
'''
@ -196,7 +204,7 @@ class OVirtLinkedService(Service):
Returns:
Id of the machine being created form template
'''
return self.parent().deployFromTemplate(name, comments, templateId, self.cluster.value)
return self.parent().deployFromTemplate(name, comments, templateId, self.cluster.value, self.display.value)
def removeTemplate(self, templateId):
'''
@ -267,6 +275,12 @@ class OVirtLinkedService(Service):
Returns:
'''
return self.parent().removeMachine(machineId)
def updateMachineMac(self, machineId, macAddres):
'''
Changes the mac address of first nic of the machine to the one specified
'''
return self.parent().updateMachineMac(machineId, macAddres)
def getMacRange(self):
'''
@ -286,4 +300,9 @@ class OVirtLinkedService(Service):
'''
return int(self.lenName.value)
def getDisplay(self):
'''
Returns the selected display type (for created machines, for administration
'''
return self.display.value

View File

@ -233,21 +233,22 @@ class Provider(ServiceProvider):
'''
return self.__getApi().getStorageInfo(storageId, force)
def makeTemplate(self, name, comments, vmId, clusterId, storageId):
def makeTemplate(self, name, comments, machineId, clusterId, storageId, displayType):
'''
Publish the machine (makes a template from it so we can create COWs) and returns the template id of
the creating machine
Args:
name: Name of the machine (care, only ascii characters and no spaces!!!)
vmId: id of the machine to be published
machineId: id of the machine to be published
clusterId: id of the cluster that will hold the machine
storageId: id of the storage tuat will contain the publication AND linked clones
displayType: type of display (for oVirt admin interface only)
Returns
Raises an exception if operation could not be acomplished, or returns the id of the template being created.
'''
return self.__getApi().makeTemplate(name, comments, vmId, clusterId, storageId)
return self.__getApi().makeTemplate(name, comments, machineId, clusterId, storageId, displayType)
def getTemplateState(self, templateId):
'''
@ -290,7 +291,7 @@ class Provider(ServiceProvider):
'''
return self.__getApi().removeTemplate(templateId)
def deployFromTemplate(self, name, comments, templateId, clusterId):
def deployFromTemplate(self, name, comments, templateId, clusterId, displayType):
'''
Deploys a virtual machine on selected cluster from selected template
@ -303,7 +304,7 @@ class Provider(ServiceProvider):
Returns:
Id of the machine being created form template
'''
return self.__getApi().deployFromTemplate(name, comments, templateId, clusterId)
return self.__getApi().deployFromTemplate(name, comments, templateId, clusterId, displayType)
def startMachine(self, machineId):
'''
@ -351,6 +352,12 @@ class Provider(ServiceProvider):
'''
return self.__getApi().removeMachine(machineId)
def updateMachineMac(self, machineId, macAddres):
'''
Changes the mac address of first nic of the machine to the one specified
'''
return self.__getApi().updateMachineMac(machineId, macAddres)
def getMacRange(self):
return self.macsRange.value

View File

@ -10,6 +10,7 @@ from ovirtsdk.api import API
import threading
import logging
import ovirtsdk
from roman import OutOfRangeError
logger = logging.getLogger(__name__)
@ -63,7 +64,7 @@ class Client(object):
pass
cached_api_key = aKey
cached_api = API(url='https://'+self._host, username=self._username, password=self._password, timeout=self._timeout, insecure=True, debug=False)
cached_api = API(url='https://'+self._host, username=self._username, password=self._password, timeout=self._timeout, insecure=True, debug=True)
return cached_api
def __init__(self, host, username, password, timeout, cache):
@ -317,7 +318,7 @@ class Client(object):
lock.release()
def makeTemplate(self, name, comments, machineId, clusterId, storageId):
def makeTemplate(self, name, comments, machineId, clusterId, storageId, displayType):
'''
Publish the machine (makes a template from it so we can create COWs) and returns the template id of
the creating machine
@ -327,19 +328,18 @@ class Client(object):
machineId: id of the machine to be published
clusterId: id of the cluster that will hold the machine
storageId: id of the storage tuat will contain the publication AND linked clones
displayType: type of display (for oVirt admin interface only)
Returns
Raises an exception if operation could not be acomplished, or returns the id of the template being created.
'''
print "n: {0}, c: {1}, vm: {2}, cl: {3}, st: {3}".format(name, comments, machineId, clusterId, storageId)
logger.debug("n: {0}, c: {1}, vm: {2}, cl: {3}, st: {3}, dt: {4}".format(name, comments, machineId, clusterId, storageId, displayType))
try:
lock.acquire(True)
api = self.__getApi()
#storage = api.storagedomains.get(id=storageId)
storage_domain = params.StorageDomain(id=storageId)
cluster = api.clusters.get(id=clusterId)
vm = api.vms.get(id=machineId)
@ -350,14 +350,27 @@ class Client(object):
if cluster is None:
raise Exception('Cluster not found')
if vm.get_status().get_state() != 'down':
raise Exception('Machine must be in down state to publish it')
template = params.Template(name=name,storage_domain=storage_domain, vm=vm, cluster=cluster, description=comments)
# Create disks description to be created in specified storage domain, one for each disk
sd = params.StorageDomains(storage_domain=[params.StorageDomain(id=storageId)])
dsks = []
for dsk in vm.disks.list():
dsks.append(params.Disk(id=dsk.get_id(), storage_domains=sd))
disks = params.Disks(disk=dsks)
# Create display description
display = params.Display(type_=displayType)
template = params.Template(name=name, vm=params.VM(id=vm.get_id(), disks=disks),
cluster=params.Cluster(id=cluster.get_id()), description=comments,
display=display)
return api.templates.add(template).get_id()
#return api.templates.get(name=name).get_id()
finally:
lock.release()
@ -390,7 +403,7 @@ class Client(object):
finally:
lock.release()
def deployFromTemplate(self, name, comments, templateId, clusterId):
def deployFromTemplate(self, name, comments, templateId, clusterId, displayType):
'''
Deploys a virtual machine on selected cluster from selected template
@ -410,16 +423,9 @@ class Client(object):
cluster = params.Cluster(id=clusterId)
template = params.Template(id=templateId)
display = params.Display(type_=displayType)
if cluster is None:
raise Exception('Cluster not found')
if template is None:
raise Exception('Template not found')
par = params.VM(name=name, cluster=cluster, template=template, description=comments)
params.Display()
par = params.VM(name=name, cluster=cluster, template=template, description=comments, display=display)
return api.vms.add(par).get_id()
@ -550,7 +556,7 @@ class Client(object):
finally:
lock.release()
def removeMachine(self, machineId):
'''
Tries to delete a machine. No check is done, it is simply requested to oVirt
@ -574,4 +580,30 @@ class Client(object):
finally:
lock.release()
def updateMachineMac(self, machineId, macAddres):
'''
Changes the mac address of first nic of the machine to the one specified
'''
try:
lock.acquire(True)
api = self.__getApi()
vm = api.vms.get(id=machineId)
if vm is None:
raise Exception('Machine not found')
nic = vm.nics.list()[0] # If has no nic, will raise an exception (IndexError)
nic.get_mac().set_address(macAddres)
nic.update() # Updates the nic
except IndexError:
raise Exception('Machine do not have network interfaces!!')
finally:
lock.release()