mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-24 02:04:09 +03:00
Another big step forward for OpenNebula provider
This commit is contained in:
parent
de4aef3a5c
commit
fd6b0c9458
@ -34,15 +34,17 @@ from uds.core.services import UserDeployment
|
||||
from uds.core.util.State import State
|
||||
from uds.core.util import log
|
||||
|
||||
from . import on
|
||||
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-01-28'
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
opCreate, opStart, opStop, opSuspend, opRemove, opWait, opError, opFinish, opRetry, opChangeMac = range(10)
|
||||
opCreate, opStart, opSuspend, opRemove, opWait, opError, opFinish, opRetry = range(8)
|
||||
|
||||
NO_MORE_NAMES = 'NO-NAME-ERROR'
|
||||
|
||||
@ -139,8 +141,6 @@ class LiveDeployment(UserDeployment):
|
||||
The get method of a mac generator takes one param, that is the mac range
|
||||
to use to get an unused mac.
|
||||
'''
|
||||
if self._mac == '':
|
||||
self._mac = self.macGenerator().get(self.service().getMacRange())
|
||||
return self._mac
|
||||
|
||||
def getIp(self):
|
||||
@ -173,12 +173,10 @@ class LiveDeployment(UserDeployment):
|
||||
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == 'unknown':
|
||||
if state == on.VmState.UNKNOWN:
|
||||
return self.__error('Machine is not available anymore')
|
||||
|
||||
if state not in ('up', 'powering_up', 'restoring_state'):
|
||||
self._queue = [opStart, opFinish]
|
||||
return self.__executeQueue()
|
||||
self.service().startMachine()
|
||||
|
||||
self.cache().put('ready', '1')
|
||||
return State.FINISHED
|
||||
@ -217,24 +215,23 @@ class LiveDeployment(UserDeployment):
|
||||
def __initQueueForDeploy(self, forLevel2=False):
|
||||
|
||||
if forLevel2 is False:
|
||||
self._queue = [opCreate, opChangeMac, opStart, opFinish]
|
||||
self._queue = [opCreate, opStart, opFinish]
|
||||
else:
|
||||
self._queue = [opCreate, opChangeMac, opStart, opWait, opSuspend, opFinish]
|
||||
self._queue = [opCreate, opStart, opWait, opSuspend, opFinish]
|
||||
|
||||
def __checkMachineState(self, chkState):
|
||||
logger.debug('Checking that state of machine {} ({}) is {}'.format(self._vmid, self._name, 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':
|
||||
if state == on.VmState.UNKNOWN:
|
||||
return self.__error('Machine not found')
|
||||
|
||||
ret = State.RUNNING
|
||||
|
||||
if type(chkState) is list:
|
||||
for cks in chkState:
|
||||
if state == cks:
|
||||
ret = State.FINISHED
|
||||
break
|
||||
if state in chkState:
|
||||
ret = State.FINISHED
|
||||
else:
|
||||
if state == chkState:
|
||||
ret = State.FINISHED
|
||||
@ -270,11 +267,9 @@ class LiveDeployment(UserDeployment):
|
||||
logger.debug('Setting error state, reason: {0}'.format(reason))
|
||||
self.doLog(log.ERROR, reason)
|
||||
|
||||
if self._vmid != '': # Powers off
|
||||
if self._vmid != '': # Powers off & delete it
|
||||
try:
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
if state in ('up', 'suspended'):
|
||||
self.service().stopMachine(self._vmid)
|
||||
self.service().removeMachine(self._vmid)
|
||||
except:
|
||||
logger.debug('Can\t set machine state to stopped')
|
||||
|
||||
@ -296,11 +291,9 @@ class LiveDeployment(UserDeployment):
|
||||
opCreate: self.__create,
|
||||
opRetry: self.__retry,
|
||||
opStart: self.__startMachine,
|
||||
opStop: self.__stopMachine,
|
||||
opSuspend: self.__suspendMachine,
|
||||
opWait: self.__wait,
|
||||
opRemove: self.__remove,
|
||||
opChangeMac: self.__changeMac
|
||||
}
|
||||
|
||||
try:
|
||||
@ -341,123 +334,62 @@ class LiveDeployment(UserDeployment):
|
||||
if name == NO_MORE_NAMES:
|
||||
raise Exception('No more names available for this service. (Increase digits for this service to fix)')
|
||||
|
||||
name = self.service().sanitizeVmName(name) # oVirt don't let us to create machines with more than 15 chars!!!
|
||||
comments = 'UDS Linked clone'
|
||||
name = self.service().sanitizeVmName(name) # OpenNebula don't let us to create machines with more than 15 chars!!!
|
||||
|
||||
self._vmid = self.service().deployFromTemplate(name, comments, templateId)
|
||||
self._vmid = self.service().deployFromTemplate(name, templateId)
|
||||
if self._vmid is None:
|
||||
raise Exception('Can\'t create machine')
|
||||
|
||||
# Get IP & MAC (early stage)
|
||||
self._mac, self._ip = self.service().getNetInfo(self._vmid)
|
||||
|
||||
def __remove(self):
|
||||
'''
|
||||
Removes a machine from system
|
||||
'''
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == 'unknown':
|
||||
if state == on.VmState.UNKNOWN:
|
||||
raise Exception('Machine not found')
|
||||
|
||||
if state != 'down':
|
||||
self.__pushFrontOp(opStop)
|
||||
self.__executeQueue()
|
||||
else:
|
||||
self.service().removeMachine(self._vmid)
|
||||
self.service().removeMachine(self._vmid)
|
||||
|
||||
def __startMachine(self):
|
||||
'''
|
||||
Powers on the machine
|
||||
'''
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == 'unknown':
|
||||
raise Exception('Machine not found')
|
||||
|
||||
if state == 'up': # Already started, return
|
||||
return
|
||||
|
||||
if state != 'down' and state != 'suspended':
|
||||
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 == 'unknown':
|
||||
raise Exception('Machine not found')
|
||||
|
||||
if state == 'down': # Already stoped, return
|
||||
return
|
||||
|
||||
if state != 'up' and state != 'suspended':
|
||||
self.__pushFrontOp(opRetry) # Will call "check Retry", that will finish inmediatly and again call this one
|
||||
else:
|
||||
self.service().stopMachine(self._vmid)
|
||||
self.service().startMachine(self._vmid)
|
||||
|
||||
def __suspendMachine(self):
|
||||
'''
|
||||
Suspends the machine
|
||||
'''
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == 'unknown':
|
||||
raise Exception('Machine not found')
|
||||
|
||||
if state == 'suspended': # Already suspended, return
|
||||
return
|
||||
|
||||
if state != 'up':
|
||||
self.__pushFrontOp(opRetry) # Remember here, the return State.FINISH will make this retry be "poped" right ar return
|
||||
else:
|
||||
self.service().suspendMachine(self._vmid)
|
||||
|
||||
def __changeMac(self):
|
||||
'''
|
||||
Changes the mac of the first nic
|
||||
'''
|
||||
self.service().updateMachineMac(self._vmid, self.getUniqueId())
|
||||
self.service().suspendMachine(self._vmid)
|
||||
|
||||
# Check methods
|
||||
def __checkCreate(self):
|
||||
'''
|
||||
Checks the state of a deploy for an user or cache
|
||||
'''
|
||||
return self.__checkMachineState('down')
|
||||
return self.__checkMachineState(on.VmState.ACTIVE)
|
||||
|
||||
def __checkStart(self):
|
||||
'''
|
||||
Checks if machine has started
|
||||
'''
|
||||
return self.__checkMachineState('up')
|
||||
|
||||
def __checkStop(self):
|
||||
'''
|
||||
Checks if machine has stoped
|
||||
'''
|
||||
return self.__checkMachineState('down')
|
||||
return self.__checkMachineState(on.VmState.ACTIVE)
|
||||
|
||||
def __checkSuspend(self):
|
||||
'''
|
||||
Check if the machine has suspended
|
||||
'''
|
||||
return self.__checkMachineState('suspended')
|
||||
return self.__checkMachineState(on.VmState.SUSPENDED)
|
||||
|
||||
def __checkRemoved(self):
|
||||
'''
|
||||
Checks if a machine has been removed
|
||||
'''
|
||||
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
|
||||
return State.FINISHED # No check at all, always true
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
@ -477,10 +409,8 @@ class LiveDeployment(UserDeployment):
|
||||
opRetry: self.__retry,
|
||||
opWait: self.__wait,
|
||||
opStart: self.__checkStart,
|
||||
opStop: self.__checkStop,
|
||||
opSuspend: self.__checkSuspend,
|
||||
opRemove: self.__checkRemoved,
|
||||
opChangeMac: self.__checkMac
|
||||
}
|
||||
|
||||
try:
|
||||
@ -570,10 +500,10 @@ class LiveDeployment(UserDeployment):
|
||||
return self.__error('Machine is already in error state!')
|
||||
|
||||
if op == opFinish or op == opWait:
|
||||
self._queue = [opStop, opRemove, opFinish]
|
||||
self._queue = [opRemove, opFinish]
|
||||
return self.__executeQueue()
|
||||
|
||||
self._queue = [op, opStop, opRemove, opFinish]
|
||||
self._queue = [op, opRemove, opFinish]
|
||||
# Do not execute anything.here, just continue normally
|
||||
return State.RUNNING
|
||||
|
||||
@ -594,14 +524,12 @@ class LiveDeployment(UserDeployment):
|
||||
return {
|
||||
opCreate: 'create',
|
||||
opStart: 'start',
|
||||
opStop: 'stop',
|
||||
opSuspend: 'suspend',
|
||||
opRemove: 'remove',
|
||||
opWait: 'wait',
|
||||
opError: 'error',
|
||||
opFinish: 'finish',
|
||||
opRetry: 'retry',
|
||||
opChangeMac: 'changing mac'
|
||||
}.get(op, '????')
|
||||
|
||||
def __debug(self, txt):
|
||||
|
@ -35,13 +35,12 @@ from uds.core.transports import protocols
|
||||
from uds.core.services import Service, types as serviceTypes
|
||||
from .LivePublication import LivePublication
|
||||
from .LiveDeployment import LiveDeployment
|
||||
from . import Helpers
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-08'
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -135,7 +134,7 @@ class LiveService(Service):
|
||||
templates = self.parent().getTemplates()
|
||||
vals = []
|
||||
for t in templates:
|
||||
vals.append(gui.choiceItem(t.id, t.name))
|
||||
vals.append(gui.choiceItem(t[0], t[1]))
|
||||
|
||||
# This is not the same case, values is not the "value" of the field, but
|
||||
# the list of values shown because this is a "ChoiceField"
|
||||
@ -144,7 +143,7 @@ class LiveService(Service):
|
||||
datastores = self.parent().getDatastores()
|
||||
vals = []
|
||||
for d in datastores:
|
||||
vals.append(gui.choiceItem(d.id, d.name))
|
||||
vals.append(gui.choiceItem(d[0], d[1]))
|
||||
|
||||
self.datastore.setValues(vals)
|
||||
|
||||
@ -154,20 +153,7 @@ class LiveService(Service):
|
||||
def makeTemplate(self, templateName):
|
||||
return self.parent().makeTemplate(self.template.value, templateName, self.datastore.value)
|
||||
|
||||
def getTemplateState(self, templateId):
|
||||
'''
|
||||
Invokes getTemplateState from parent provider
|
||||
|
||||
Args:
|
||||
templateId: templateId to remove
|
||||
|
||||
Returns nothing
|
||||
|
||||
Raises an exception if operation fails.
|
||||
'''
|
||||
return self.parent().getTemplateState(templateId)
|
||||
|
||||
def deployFromTemplate(self, name, comments, templateId):
|
||||
def deployFromTemplate(self, name, templateId):
|
||||
'''
|
||||
Deploys a virtual machine on selected cluster from selected template
|
||||
|
||||
@ -183,9 +169,8 @@ class LiveService(Service):
|
||||
Id of the machine being created form template
|
||||
'''
|
||||
logger.debug('Deploying from template {0} machine {1}'.format(templateId, name))
|
||||
self.datastoreHasSpace()
|
||||
return self.parent().deployFromTemplate(name, comments, templateId, self.cluster.value,
|
||||
self.display.value, int(self.memory.value), int(self.memoryGuaranteed.value))
|
||||
# self.datastoreHasSpace()
|
||||
return self.parent().deployFromTemplate(name, templateId)
|
||||
|
||||
def removeTemplate(self, templateId):
|
||||
'''
|
||||
@ -257,17 +242,11 @@ class LiveService(Service):
|
||||
'''
|
||||
return self.parent().removeMachine(machineId)
|
||||
|
||||
def updateMachineMac(self, machineId, macAddres):
|
||||
def getNetInfo(self, machineId, networkId=None):
|
||||
'''
|
||||
Changes the mac address of first nic of the machine to the one specified
|
||||
'''
|
||||
return self.parent().updateMachineMac(machineId, macAddres)
|
||||
|
||||
def getMacRange(self):
|
||||
'''
|
||||
Returns de selected mac range
|
||||
'''
|
||||
return self.parent().getMacRange()
|
||||
return self.parent().getNetInfo(machineId, networkId=None)
|
||||
|
||||
def getBaseName(self):
|
||||
'''
|
||||
@ -286,9 +265,3 @@ class LiveService(Service):
|
||||
Returns the selected display type (for created machines, for administration
|
||||
'''
|
||||
return self.display.value
|
||||
|
||||
def getConsoleConnection(self, machineId):
|
||||
return self.parent().getConsoleConnection(machineId)
|
||||
|
||||
def desktopLogin(self, machineId, username, password, domain):
|
||||
return self.parent().desktopLogin(machineId, username, password, domain)
|
||||
|
@ -41,6 +41,7 @@ from uds.core.util import validators
|
||||
from defusedxml import minidom
|
||||
|
||||
from .LiveService import LiveService
|
||||
from . import on
|
||||
|
||||
|
||||
import logging
|
||||
@ -49,7 +50,7 @@ import six
|
||||
# Python bindings for OpenNebula
|
||||
import oca
|
||||
|
||||
__updated__ = '2016-02-08'
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -100,8 +101,6 @@ class Provider(ServiceProvider):
|
||||
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenNebula'), required=True, defvalue='oneadmin')
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenNebula'), required=True)
|
||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', order=6, tooltip=_('Timeout in seconds of connection to OpenNebula'), required=True)
|
||||
macsRange = gui.TextField(length=36, label=_('Macs range'), defvalue='52:54:00:00:00:00-52:54:00:FF:FF:FF', order=7, rdonly=True,
|
||||
tooltip=_('Range of valid macs for UDS managed machines'), required=True)
|
||||
|
||||
# Own variables
|
||||
_api = None
|
||||
@ -115,9 +114,8 @@ class Provider(ServiceProvider):
|
||||
self._api = None
|
||||
|
||||
if values is not None:
|
||||
self.macsRange.value = validators.validateMacRange(self.macsRange.value)
|
||||
self.timeout.value = validators.validateTimeout(self.timeout.value, returnAsInteger=False)
|
||||
logger.debug('Endpoint: {}'.format(self.endPoint))
|
||||
logger.debug('Endpoint: {}'.format(self.endpoint))
|
||||
|
||||
@property
|
||||
def endpoint(self):
|
||||
@ -135,11 +133,7 @@ class Provider(ServiceProvider):
|
||||
self._api = None
|
||||
|
||||
def sanitizeVmName(self, name):
|
||||
'''
|
||||
Ovirt only allows machine names with [a-zA-Z0-9_-]
|
||||
'''
|
||||
import re
|
||||
return re.sub("[^a-zA-Z0-9_-]", "_", name)
|
||||
return on.sanitizeName(name)
|
||||
|
||||
def testConnection(self):
|
||||
'''
|
||||
@ -180,128 +174,19 @@ class Provider(ServiceProvider):
|
||||
return vmpool
|
||||
|
||||
def getDatastores(self, datastoreType=0):
|
||||
'''
|
||||
0 seems to be images datastore
|
||||
'''
|
||||
datastores = oca.DatastorePool(self.api)
|
||||
datastores.info()
|
||||
|
||||
for ds in datastores:
|
||||
if ds.type == datastoreType:
|
||||
yield ds
|
||||
return on.storage.enumerateDatastores(self.api, datastoreType)
|
||||
|
||||
def getTemplates(self, force=False):
|
||||
logger.debug('Api: {}'.format(self.api))
|
||||
templatesPool = oca.VmTemplatePool(self.api)
|
||||
templatesPool.info()
|
||||
|
||||
for t in templatesPool:
|
||||
if t.name[:4] != 'UDSP':
|
||||
yield t
|
||||
return on.template.getTemplates(self.api, force)
|
||||
|
||||
def makeTemplate(self, fromTemplateId, name, toDataStore):
|
||||
'''
|
||||
Publish the machine (makes a template from it so we can create COWs) and returns the template id of
|
||||
the creating machine
|
||||
|
||||
Args:
|
||||
fromTemplateId: id of the base template
|
||||
name: Name of the machine (care, only ascii characters and no spaces!!!)
|
||||
|
||||
Returns
|
||||
Raises an exception if operation could not be acomplished, or returns the id of the template being created.
|
||||
|
||||
Note:
|
||||
Maybe we need to also clone the hard disk?
|
||||
'''
|
||||
try:
|
||||
# First, we clone the themplate itself
|
||||
templateId = self.api.call('template.clone', int(fromTemplateId), name)
|
||||
|
||||
# Now copy cloned images if possible
|
||||
try:
|
||||
imgs = oca.ImagePool(self.api)
|
||||
imgs.info()
|
||||
imgs = dict(((i.name, i.id) for i in imgs))
|
||||
|
||||
info = self.api.call('template.info', templateId)
|
||||
template = minidom.parseString(info).getElementsByTagName('TEMPLATE')[0]
|
||||
logger.debug('XML: {}'.format(template.toxml()))
|
||||
|
||||
counter = 0
|
||||
for dsk in template.getElementsByTagName('DISK'):
|
||||
counter += 1
|
||||
imgIds = dsk.getElementsByTagName('IMAGE_ID')
|
||||
if len(imgIds) == 0:
|
||||
fromId = False
|
||||
node = dsk.getElementsByTagName('IMAGE')[0].childNodes[0]
|
||||
imgName = node.data
|
||||
# Locate
|
||||
imgId = imgs[imgName]
|
||||
else:
|
||||
fromId = True
|
||||
node = imgIds[0].childNodes[0]
|
||||
imgId = node.data
|
||||
|
||||
logger.debug('Found {} for cloning'.format(imgId))
|
||||
|
||||
# Now clone the image
|
||||
imgName = self.sanitizeVmName(name + ' DSK ' + six.text_type(counter))
|
||||
newId = self.api.call('image.clone', int(imgId), imgName, int(toDataStore))
|
||||
if fromId is True:
|
||||
node.data = six.text_type(newId)
|
||||
else:
|
||||
node.data = imgName
|
||||
|
||||
# Now update the clone
|
||||
self.api.call('template.update', templateId, template.toxml())
|
||||
except:
|
||||
logger.exception('Exception cloning image')
|
||||
|
||||
return six.text_type(templateId)
|
||||
except Exception as e:
|
||||
logger.error('Creating template on OpenNebula: {}'.format(e))
|
||||
raise
|
||||
return on.template.create(self.api, fromTemplateId, name, toDataStore)
|
||||
|
||||
def removeTemplate(self, templateId):
|
||||
'''
|
||||
Removes a template from ovirt server
|
||||
return on.template.remove(self.api, templateId)
|
||||
|
||||
Returns nothing, and raises an Exception if it fails
|
||||
'''
|
||||
try:
|
||||
# First, remove Images (wont be possible if there is any images already in use, but will try)
|
||||
# Now copy cloned images if possible
|
||||
try:
|
||||
imgs = oca.ImagePool(self.api)
|
||||
imgs.info()
|
||||
imgs = dict(((i.name, i.id) for i in imgs))
|
||||
|
||||
info = self.api.call('template.info', int(templateId))
|
||||
template = minidom.parseString(info).getElementsByTagName('TEMPLATE')[0]
|
||||
logger.debug('XML: {}'.format(template.toxml()))
|
||||
|
||||
counter = 0
|
||||
for dsk in template.getElementsByTagName('DISK'):
|
||||
imgIds = dsk.getElementsByTagName('IMAGE_ID')
|
||||
if len(imgIds) == 0:
|
||||
node = dsk.getElementsByTagName('IMAGE')[0].childNodes[0]
|
||||
imgId = imgs[node.data]
|
||||
else:
|
||||
node = imgIds[0].childNodes[0]
|
||||
imgId = node.data
|
||||
|
||||
logger.debug('Found {} for cloning'.format(imgId))
|
||||
|
||||
# Now delete the image
|
||||
self.api.call('image.delete', int(imgId))
|
||||
|
||||
except:
|
||||
logger.exception('Exception cloning image')
|
||||
|
||||
self.api.call('template.delete', int(templateId))
|
||||
except Exception as e:
|
||||
logger.error('Creating template on OpenNebula: {}'.format(e))
|
||||
def deployFromTemplate(self, name, templateId):
|
||||
return on.template.deployFrom(self.api, templateId, name)
|
||||
|
||||
def getMachineState(self, machineId):
|
||||
'''
|
||||
@ -312,32 +197,15 @@ class Provider(ServiceProvider):
|
||||
machineId: Id of the machine to get state
|
||||
|
||||
Returns:
|
||||
one of this values:
|
||||
unassigned, down, up, powering_up, powered_down,
|
||||
paused, migrating_from, migrating_to, unknown, not_responding,
|
||||
wait_for_launch, reboot_in_progress, saving_state, restoring_state,
|
||||
suspended, image_illegal, image_locked or powering_down
|
||||
Also can return'unknown' if Machine is not known
|
||||
one of the on.VmState Values
|
||||
'''
|
||||
return self.__getApi().getMachineState(machineId)
|
||||
try:
|
||||
vm = oca.VirtualMachine.new_with_id(self.api, int(machineId))
|
||||
vm.info()
|
||||
return vm.state
|
||||
except Exception as e:
|
||||
logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e))
|
||||
|
||||
def deployFromTemplate(self, name, comments, templateId, clusterId, displayType, memoryMB, guaranteedMB):
|
||||
'''
|
||||
Deploys a virtual machine on selected cluster from selected template
|
||||
|
||||
Args:
|
||||
name: Name (sanitized) of the machine
|
||||
comments: Comments for machine
|
||||
templateId: Id of the template to deploy from
|
||||
clusterId: Id of the cluster to deploy to
|
||||
displayType: 'vnc' or 'spice'. Display to use ad OpenNebula admin interface
|
||||
memoryMB: Memory requested for machine, in MB
|
||||
guaranteedMB: Minimum memory guaranteed for this machine
|
||||
|
||||
Returns:
|
||||
Id of the machine being created form template
|
||||
'''
|
||||
return self.__getApi().deployFromTemplate(name, comments, templateId, clusterId, displayType, memoryMB, guaranteedMB)
|
||||
|
||||
def startMachine(self, machineId):
|
||||
'''
|
||||
@ -350,7 +218,7 @@ class Provider(ServiceProvider):
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.__getApi().startMachine(machineId)
|
||||
on.vm.startMachine(self.api, machineId)
|
||||
|
||||
def stopMachine(self, machineId):
|
||||
'''
|
||||
@ -361,7 +229,7 @@ class Provider(ServiceProvider):
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.__getApi().stopMachine(machineId)
|
||||
on.vm.stopMachine(self.api, machineId)
|
||||
|
||||
def suspendMachine(self, machineId):
|
||||
'''
|
||||
@ -372,7 +240,7 @@ class Provider(ServiceProvider):
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.__getApi().suspendMachine(machineId)
|
||||
on.vm.suspendMachine(self.api, machineId)
|
||||
|
||||
def removeMachine(self, machineId):
|
||||
'''
|
||||
@ -383,24 +251,13 @@ class Provider(ServiceProvider):
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.__getApi().removeMachine(machineId)
|
||||
on.vm.removeMachine(self.api, machineId)
|
||||
|
||||
def updateMachineMac(self, machineId, macAddres):
|
||||
def getNetInfo(self, machineId, networkId=None):
|
||||
'''
|
||||
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
|
||||
|
||||
def getConsoleConnection(self, machineId):
|
||||
return self.__getApi().getConsoleConnection(machineId)
|
||||
|
||||
def desktopLogin(self, machineId, username, password, domain):
|
||||
'''
|
||||
'''
|
||||
return self.__getApi().desktopLogin(machineId, username, password, domain)
|
||||
return on.vm.getNetInfo(self.api, machineId, networkId)
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
|
63
server/src/uds/services/OpenNebula/on/__init__.py
Normal file
63
server/src/uds/services/OpenNebula/on/__init__.py
Normal file
@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import sys
|
||||
import imp
|
||||
import re
|
||||
|
||||
import logging
|
||||
import six
|
||||
|
||||
from defusedxml import minidom
|
||||
|
||||
# Python bindings for OpenNebula
|
||||
import oca
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
module = sys.modules[__name__]
|
||||
VmState = imp.new_module('VmState')
|
||||
|
||||
for i in enumerate(['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED', 'DONE', 'FAILED', 'POWEROFF', 'UNDEPLOYED']):
|
||||
setattr(VmState, i[1], i[0])
|
||||
|
||||
|
||||
# Import submodules
|
||||
from common import *
|
||||
import template
|
||||
import vm
|
||||
import storage
|
||||
|
55
server/src/uds/services/OpenNebula/on/common.py
Normal file
55
server/src/uds/services/OpenNebula/on/common.py
Normal file
@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import sys
|
||||
import imp
|
||||
import re
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
module = sys.modules[__name__]
|
||||
VmState = imp.new_module('VmState')
|
||||
|
||||
for i in enumerate(['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED', 'DONE', 'FAILED', 'POWEROFF', 'UNDEPLOYED', 'UNKNOWN']):
|
||||
setattr(VmState, i[1], i[0])
|
||||
|
||||
|
||||
def sanitizeName(name):
|
||||
'''
|
||||
machine names with [a-zA-Z0-9_-]
|
||||
'''
|
||||
return re.sub("[^a-zA-Z0-9._-]", "_", name)
|
52
server/src/uds/services/OpenNebula/on/storage.py
Normal file
52
server/src/uds/services/OpenNebula/on/storage.py
Normal file
@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import logging
|
||||
import six
|
||||
import oca
|
||||
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def enumerateDatastores(api, datastoreType=0):
|
||||
'''
|
||||
0 seems to be images datastore
|
||||
'''
|
||||
datastores = oca.DatastorePool(api)
|
||||
datastores.info()
|
||||
|
||||
for ds in datastores:
|
||||
if ds.type == datastoreType:
|
||||
yield (ds.id, ds.name)
|
177
server/src/uds/services/OpenNebula/on/template.py
Normal file
177
server/src/uds/services/OpenNebula/on/template.py
Normal file
@ -0,0 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import logging
|
||||
import six
|
||||
import oca
|
||||
|
||||
from defusedxml import minidom
|
||||
# Python bindings for OpenNebula
|
||||
from .common import sanitizeName
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def getTemplates(api, force=False):
|
||||
logger.debug('Api: {}'.format(api))
|
||||
templatesPool = oca.VmTemplatePool(api)
|
||||
templatesPool.info()
|
||||
|
||||
for t in templatesPool:
|
||||
if t.name[:4] != 'UDSP':
|
||||
yield (t.id, t.name)
|
||||
|
||||
|
||||
def create(api, fromTemplateId, name, toDataStore):
|
||||
'''
|
||||
Publish the machine (makes a template from it so we can create COWs) and returns the template id of
|
||||
the creating machine
|
||||
|
||||
Args:
|
||||
fromTemplateId: id of the base template
|
||||
name: Name of the machine (care, only ascii characters and no spaces!!!)
|
||||
|
||||
Returns
|
||||
Raises an exception if operation could not be acomplished, or returns the id of the template being created.
|
||||
|
||||
Note:
|
||||
Maybe we need to also clone the hard disk?
|
||||
'''
|
||||
try:
|
||||
# First, we clone the themplate itself
|
||||
templateId = api.call('template.clone', int(fromTemplateId), name)
|
||||
|
||||
# Now copy cloned images if possible
|
||||
try:
|
||||
imgs = oca.ImagePool(api)
|
||||
imgs.info()
|
||||
imgs = dict(((i.name, i.id) for i in imgs))
|
||||
|
||||
info = api.call('template.info', templateId)
|
||||
template = minidom.parseString(info).getElementsByTagName('TEMPLATE')[0]
|
||||
logger.debug('XML: {}'.format(template.toxml()))
|
||||
|
||||
counter = 0
|
||||
for dsk in template.getElementsByTagName('DISK'):
|
||||
counter += 1
|
||||
imgIds = dsk.getElementsByTagName('IMAGE_ID')
|
||||
if len(imgIds) == 0:
|
||||
fromId = False
|
||||
node = dsk.getElementsByTagName('IMAGE')[0].childNodes[0]
|
||||
imgName = node.data
|
||||
# Locate
|
||||
imgId = imgs[imgName]
|
||||
else:
|
||||
fromId = True
|
||||
node = imgIds[0].childNodes[0]
|
||||
imgId = node.data
|
||||
|
||||
logger.debug('Found {} for cloning'.format(imgId))
|
||||
|
||||
# Now clone the image
|
||||
imgName = sanitizeName(name + ' DSK ' + six.text_type(counter))
|
||||
newId = api.call('image.clone', int(imgId), imgName, int(toDataStore))
|
||||
if fromId is True:
|
||||
node.data = six.text_type(newId)
|
||||
else:
|
||||
node.data = imgName
|
||||
|
||||
# Now update the clone
|
||||
api.call('template.update', templateId, template.toxml())
|
||||
except Exception:
|
||||
logger.exception('Exception cloning image')
|
||||
|
||||
return six.text_type(templateId)
|
||||
except Exception as e:
|
||||
logger.error('Creating template on OpenNebula: {}'.format(e))
|
||||
raise
|
||||
|
||||
def remove(api, templateId):
|
||||
'''
|
||||
Removes a template from ovirt server
|
||||
|
||||
Returns nothing, and raises an Exception if it fails
|
||||
'''
|
||||
try:
|
||||
# First, remove Images (wont be possible if there is any images already in use, but will try)
|
||||
# Now copy cloned images if possible
|
||||
try:
|
||||
imgs = oca.ImagePool(api)
|
||||
imgs.info()
|
||||
imgs = dict(((i.name, i.id) for i in imgs))
|
||||
|
||||
info = api.call('template.info', int(templateId))
|
||||
template = minidom.parseString(info).getElementsByTagName('TEMPLATE')[0]
|
||||
logger.debug('XML: {}'.format(template.toxml()))
|
||||
|
||||
for dsk in template.getElementsByTagName('DISK'):
|
||||
imgIds = dsk.getElementsByTagName('IMAGE_ID')
|
||||
if len(imgIds) == 0:
|
||||
node = dsk.getElementsByTagName('IMAGE')[0].childNodes[0]
|
||||
imgId = imgs[node.data]
|
||||
else:
|
||||
node = imgIds[0].childNodes[0]
|
||||
imgId = node.data
|
||||
|
||||
logger.debug('Found {} for cloning'.format(imgId))
|
||||
|
||||
# Now delete the image
|
||||
api.call('image.delete', int(imgId))
|
||||
|
||||
except:
|
||||
logger.exception('Exception cloning image')
|
||||
|
||||
api.call('template.delete', int(templateId))
|
||||
except Exception as e:
|
||||
logger.error('Creating template on OpenNebula: {}'.format(e))
|
||||
|
||||
def deployFrom(api, templateId, name):
|
||||
'''
|
||||
Deploys a virtual machine on selected cluster from selected template
|
||||
|
||||
Args:
|
||||
name: Name (sanitized) of the machine
|
||||
comments: Comments for machine
|
||||
templateId: Id of the template to deploy from
|
||||
clusterId: Id of the cluster to deploy to
|
||||
displayType: 'vnc' or 'spice'. Display to use ad OpenNebula admin interface
|
||||
memoryMB: Memory requested for machine, in MB
|
||||
guaranteedMB: Minimum memory guaranteed for this machine
|
||||
|
||||
Returns:
|
||||
Id of the machine being created form template
|
||||
'''
|
||||
vmId = api.call('template.instantiate', int(templateId), name, False, '')
|
||||
return six.text_type(vmId)
|
181
server/src/uds/services/OpenNebula/on/vm.py
Normal file
181
server/src/uds/services/OpenNebula/on/vm.py
Normal file
@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
import logging
|
||||
import six
|
||||
import oca
|
||||
|
||||
from defusedxml import minidom
|
||||
# Python bindings for OpenNebula
|
||||
from .common import VmState
|
||||
|
||||
__updated__ = '2016-02-09'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def getMachineState(api, machineId):
|
||||
'''
|
||||
Returns the state of the machine
|
||||
This method do not uses cache at all (it always tries to get machine state from OpenNebula server)
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine to get state
|
||||
|
||||
Returns:
|
||||
one of the on.VmState Values
|
||||
'''
|
||||
try:
|
||||
vm = oca.VirtualMachine.new_with_id(api, int(machineId))
|
||||
vm.info()
|
||||
return vm.state
|
||||
except Exception as e:
|
||||
logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e))
|
||||
|
||||
return VmState.UNKNOWN
|
||||
|
||||
|
||||
def startMachine(api, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula.
|
||||
|
||||
This start also "resume" suspended/paused machines
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
try:
|
||||
vm = oca.VirtualMachine.new_with_id(api, int(machineId))
|
||||
vm.resume()
|
||||
except Exception as e:
|
||||
logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e))
|
||||
|
||||
def stopMachine(api, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
try:
|
||||
vm = oca.VirtualMachine.new_with_id(api, int(machineId))
|
||||
vm.poweroff_hard()
|
||||
except Exception as e:
|
||||
logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e))
|
||||
|
||||
|
||||
def suspendMachine(api, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
startMachine(api, machineId)
|
||||
|
||||
def removeMachine(api, machineId):
|
||||
'''
|
||||
Tries to delete a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
try:
|
||||
vm = oca.VirtualMachine.new_with_id(api, int(machineId))
|
||||
vm.delete()
|
||||
except Exception as e:
|
||||
logger.error('Error obtaining machine state for {} on opennebula: {}'.format(machineId, e))
|
||||
|
||||
|
||||
def enumerateMachines(self):
|
||||
'''
|
||||
Obtains the list of machines inside OpenNebula.
|
||||
Machines starting with UDS are filtered out
|
||||
|
||||
Args:
|
||||
force: If true, force to update the cache, if false, tries to first
|
||||
get data from cache and, if valid, return this.
|
||||
|
||||
Returns
|
||||
An array of dictionaries, containing:
|
||||
'name'
|
||||
'id'
|
||||
'cluster_id'
|
||||
'''
|
||||
vmpool = oca.VirtualMachinePool(self.api)
|
||||
vmpool.info()
|
||||
|
||||
for vm in vmpool:
|
||||
yield (vm.id, vm.name)
|
||||
|
||||
|
||||
def getNetInfo(api, machineId, networkId=None):
|
||||
'''
|
||||
Changes the mac address of first nic of the machine to the one specified
|
||||
'''
|
||||
md = minidom.parseString(api.call('vm.info', int(machineId)))
|
||||
node = md
|
||||
|
||||
for nic in md.getElementsByTagName('NIC'):
|
||||
netId = nic.getElementsByTagName('NETWORK_ID')[0].childNodes[0].data
|
||||
if networkId is None or int(netId) == int(networkId):
|
||||
node = nic
|
||||
break
|
||||
|
||||
# Default, returns first MAC found (or raise an exception if there is no MAC)
|
||||
return (node.getElementsByTagName('MAC')[0].childNodes[0].data, node.getElementsByTagName('IP')[0].childNodes[0].data)
|
||||
|
||||
# Sample NIC Content (there will be as much as nics)
|
||||
# <NIC>
|
||||
# <BRIDGE><![CDATA[br0]]></BRIDGE>
|
||||
# <CLUSTER_ID><![CDATA[100]]></CLUSTER_ID>
|
||||
# <IP><![CDATA[172.27.0.49]]></IP>
|
||||
# <IP6_LINK><![CDATA[fe80::400:acff:fe1b:31]]></IP6_LINK>
|
||||
# <MAC><![CDATA[02:00:ac:1b:00:31]]></MAC>
|
||||
# <NETWORK><![CDATA[private]]></NETWORK>
|
||||
# <NETWORK_ID><![CDATA[1]]></NETWORK_ID>
|
||||
# <NETWORK_UNAME><![CDATA[oneadmin]]></NETWORK_UNAME>
|
||||
# <NIC_ID><![CDATA[2]]></NIC_ID>
|
||||
# <VLAN><![CDATA[NO]]></VLAN>
|
||||
# </NIC>
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user