forked from shaba/openuds
OpenStack working (initially)
This commit is contained in:
parent
c45833c252
commit
9f4ef20dc1
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=1.9.0
|
||||
VERSION=`cat ../../VERSION`
|
||||
RELEASE=1
|
||||
|
||||
top=`pwd`
|
||||
|
@ -1,3 +1,15 @@
|
||||
udsactor (2.0.0) stable; urgency=medium
|
||||
|
||||
* Upgrade for 2.0.0
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:39:21 +0100
|
||||
|
||||
udsactor (1.9.1) stable; urgency=medium
|
||||
|
||||
* Upgrade for 1.9.1
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:19:21 +0100
|
||||
|
||||
udsactor (1.9.0) stable; urgency=medium
|
||||
|
||||
* Upgrade for 1.9.0 (fixed package version)
|
||||
|
@ -1,3 +1,3 @@
|
||||
udsactor_1.9.0_all.deb admin optional
|
||||
udsactor-xrdp_1.9.0_all.deb x11 optional
|
||||
udsactor-nx_1.9.0_all.deb x11 optional
|
||||
udsactor-nx_2.0.0_all.deb x11 optional
|
||||
udsactor-xrdp_2.0.0_all.deb x11 optional
|
||||
udsactor_2.0.0_all.deb admin optional
|
||||
|
@ -2,7 +2,13 @@ udsclient (2.0.0) stable; urgency=medium
|
||||
|
||||
* Release upgrade
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 19 Feb 2015 09:33:18 +0200
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 09:33:18 +0100
|
||||
|
||||
udsclient (1.9.1) stable; urgency=medium
|
||||
|
||||
* Minor fixes & making version match UDS version
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:02:37 +0100
|
||||
|
||||
udsclient (1.9.0) stable; urgency=medium
|
||||
|
||||
|
@ -44,7 +44,7 @@ import threading
|
||||
import time
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-01'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -116,8 +116,7 @@ class DelayedTaskRunner(object):
|
||||
|
||||
if taskInstance is not None:
|
||||
logger.debug('Executing delayedTask:>{0}<'.format(task))
|
||||
env = Environment.getEnvForType(taskInstance.__class__)
|
||||
taskInstance.setEnv(env)
|
||||
taskInstance.env = Environment.getEnvForType(taskInstance.__class__)
|
||||
DelayedTaskThread(taskInstance).start()
|
||||
|
||||
def __insert(self, instance, delay, tag):
|
||||
|
@ -33,8 +33,11 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from . import action
|
||||
from . import common
|
||||
from . import group
|
||||
from . import process
|
||||
from . import publication
|
||||
from . import userService
|
||||
from . import servicePool
|
||||
from . import task
|
||||
from . import group
|
||||
from . import userService
|
@ -85,7 +85,7 @@ class ServiceCacheUpdater(Job):
|
||||
sp.userServices.update() # Cleans cached queries
|
||||
# If this deployedService don't have a publication active and needs it, ignore it
|
||||
if sp.activePublication() is None and sp.service.getInstance().publicationType is not None:
|
||||
logger.debug('Needs publication but do not have one, cache test ignored')
|
||||
logger.debug('{} Needs publication but do not have one, cache test ignored'.format(sp))
|
||||
continue
|
||||
# If it has any running publication, do not generate cache anymore
|
||||
if sp.publications.filter(state=State.PREPARING).count() > 0:
|
||||
|
@ -30,13 +30,13 @@
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=protected-access
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand # , CommandError
|
||||
from optparse import make_option
|
||||
from django.conf import settings
|
||||
|
||||
from django.utils.daemonize import become_daemon
|
||||
from uds.core.managers.TaskManager import TaskManager
|
||||
from uds.core.util.Config import GlobalConfig
|
||||
import logging
|
||||
@ -54,6 +54,41 @@ PID_FILE = 'taskmanager.pid'
|
||||
def getPidFile():
|
||||
return settings.BASE_DIR + '/' + PID_FILE
|
||||
|
||||
# become_daemon seems te be removed on django 1.9
|
||||
# This is a copy of posix version from django 1.8
|
||||
buffering = int(six.PY3)
|
||||
def become_daemon(our_home_dir='.', out_log='/dev/null',
|
||||
err_log='/dev/null', umask=0o022):
|
||||
"Robustly turn into a UNIX daemon, running in our_home_dir."
|
||||
# First fork
|
||||
try:
|
||||
if os.fork() > 0:
|
||||
sys.exit(0) # kill off parent
|
||||
except OSError as e:
|
||||
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
|
||||
sys.exit(1)
|
||||
os.setsid()
|
||||
os.chdir(our_home_dir)
|
||||
os.umask(umask)
|
||||
|
||||
# Second fork
|
||||
try:
|
||||
if os.fork() > 0:
|
||||
os._exit(0)
|
||||
except OSError as e:
|
||||
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
|
||||
os._exit(1)
|
||||
|
||||
si = open('/dev/null', 'r')
|
||||
so = open(out_log, 'a+', buffering)
|
||||
se = open(err_log, 'a+', buffering)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
# Set custom file descriptors so that they get proper buffering.
|
||||
sys.stdout, sys.stderr = so, se
|
||||
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = "None"
|
||||
@ -82,7 +117,7 @@ class Command(BaseCommand):
|
||||
|
||||
pid = None
|
||||
try:
|
||||
pid = int(file(getPidFile(), 'r').readline())
|
||||
pid = int(open(getPidFile(), 'r').readline())
|
||||
except Exception:
|
||||
pid = None
|
||||
|
||||
|
@ -40,7 +40,7 @@ from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-03-04'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -161,7 +161,7 @@ class LiveService(Service):
|
||||
name: Name (sanitized) of the machine
|
||||
comments: Comments for machine
|
||||
templateId: Id of the template to deploy from
|
||||
displayType: 'vnc' or 'spice'. Display to use ad oVirt admin interface
|
||||
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
|
||||
|
||||
@ -198,7 +198,7 @@ class LiveService(Service):
|
||||
|
||||
def startMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt.
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula.
|
||||
|
||||
This start also "resume" suspended/paused machines
|
||||
|
||||
@ -211,7 +211,7 @@ class LiveService(Service):
|
||||
|
||||
def stopMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
@ -222,7 +222,7 @@ class LiveService(Service):
|
||||
|
||||
def suspendMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
@ -233,7 +233,7 @@ class LiveService(Service):
|
||||
|
||||
def removeMachine(self, machineId):
|
||||
'''
|
||||
Tries to delete a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to delete a machine. No check is done, it is simply requested to OpenNebula
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
@ -39,7 +39,7 @@ from . import openStack
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-02-26'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -58,8 +58,13 @@ class LiveDeployment(UserDeployment):
|
||||
provider of this elements.
|
||||
|
||||
The logic for managing ovirt deployments (user machines in this case) is here.
|
||||
|
||||
'''
|
||||
_name = ''
|
||||
_ip = ''
|
||||
_mac = ''
|
||||
_vmid = ''
|
||||
_reason = ''
|
||||
_queue = None
|
||||
|
||||
# : Recheck every six seconds by default (for task methods)
|
||||
suggestedTime = 6
|
||||
@ -171,12 +176,17 @@ class LiveDeployment(UserDeployment):
|
||||
if self.cache.get('ready') == '1':
|
||||
return State.FINISHED
|
||||
|
||||
state = self.service().getMachineState(self._vmid)
|
||||
status = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == openStack.VmState.UNKNOWN:
|
||||
if openStack.statusIsLost(status):
|
||||
return self.__error('Machine is not available anymore')
|
||||
|
||||
self.service().startMachine()
|
||||
if status == openStack.PAUSED:
|
||||
self.service().resumeMachine(self._vmid)
|
||||
elif status == openStack.STOPPED:
|
||||
self.service().startMachine(self._vmId)
|
||||
|
||||
# Right now, we suppose the machine is ready
|
||||
|
||||
self.cache.put('ready', '1')
|
||||
return State.FINISHED
|
||||
@ -215,25 +225,25 @@ class LiveDeployment(UserDeployment):
|
||||
def __initQueueForDeploy(self, forLevel2=False):
|
||||
|
||||
if forLevel2 is False:
|
||||
self._queue = [opCreate, opStart, opFinish]
|
||||
self._queue = [opCreate, opFinish]
|
||||
else:
|
||||
self._queue = [opCreate, opStart, opWait, opSuspend, opFinish]
|
||||
self._queue = [opCreate, 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)
|
||||
status = 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 == openStack.VmState.UNKNOWN:
|
||||
return self.__error('Machine not found')
|
||||
if openStack.statusIsLost(status):
|
||||
return self.__error('Machine not available')
|
||||
|
||||
ret = State.RUNNING
|
||||
|
||||
if type(chkState) is list:
|
||||
if state in chkState:
|
||||
if status in chkState:
|
||||
ret = State.FINISHED
|
||||
else:
|
||||
if state == chkState:
|
||||
if status == chkState:
|
||||
ret = State.FINISHED
|
||||
|
||||
return ret
|
||||
@ -340,16 +350,13 @@ class LiveDeployment(UserDeployment):
|
||||
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)
|
||||
status = self.service().getMachineState(self._vmid)
|
||||
|
||||
if state == openStack.VmState.UNKNOWN:
|
||||
if openStack.statusIsLost(status):
|
||||
raise Exception('Machine not found')
|
||||
|
||||
self.service().removeMachine(self._vmid)
|
||||
@ -371,19 +378,25 @@ class LiveDeployment(UserDeployment):
|
||||
'''
|
||||
Checks the state of a deploy for an user or cache
|
||||
'''
|
||||
return self.__checkMachineState(openStack.VmState.ACTIVE)
|
||||
ret = self.__checkMachineState(openStack.ACTIVE)
|
||||
if ret == State.FINISHED:
|
||||
# Get IP & MAC (early stage)
|
||||
self._mac, self._ip = self.service().getNetInfo(self._vmid)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def __checkStart(self):
|
||||
'''
|
||||
Checks if machine has started
|
||||
'''
|
||||
return self.__checkMachineState(openStack.VmState.ACTIVE)
|
||||
return self.__checkMachineState(openStack.ACTIVE)
|
||||
|
||||
def __checkSuspend(self):
|
||||
'''
|
||||
Check if the machine has suspended
|
||||
'''
|
||||
return self.__checkMachineState(openStack.VmState.SUSPENDED)
|
||||
return self.__checkMachineState(openStack.SUSPENDED)
|
||||
|
||||
def __checkRemoved(self):
|
||||
'''
|
||||
|
@ -35,10 +35,13 @@ from django.utils.translation import ugettext as _
|
||||
from uds.core.services import Publication
|
||||
from uds.core.util.State import State
|
||||
from datetime import datetime
|
||||
|
||||
import six
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
__updated__ = '2016-02-08'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -48,6 +51,11 @@ class LivePublication(Publication):
|
||||
'''
|
||||
This class provides the publication of a oVirtLinkedService
|
||||
'''
|
||||
_name = ''
|
||||
_reason = ''
|
||||
_templateId = ''
|
||||
_state = 'r'
|
||||
_destroyAfter = 'n'
|
||||
|
||||
suggestedTime = 2 # : Suggested recheck time if publication is unfinished in seconds
|
||||
|
||||
@ -65,12 +73,13 @@ class LivePublication(Publication):
|
||||
self._reason = ''
|
||||
self._templateId = ''
|
||||
self._state = 'r'
|
||||
self._destroyAfter = 'n'
|
||||
|
||||
def marshal(self):
|
||||
'''
|
||||
returns data from an instance of Sample Publication serialized
|
||||
'''
|
||||
return '\t'.join(['v1', self._name, self._reason, self._templateId, self._state])
|
||||
return '\t'.join(['v1', self._name, self._reason, self._templateId, self._state, self._destroyAfter])
|
||||
|
||||
def unmarshal(self, data):
|
||||
'''
|
||||
@ -79,7 +88,7 @@ class LivePublication(Publication):
|
||||
logger.debug('Data: {0}'.format(data))
|
||||
vals = data.split('\t')
|
||||
if vals[0] == 'v1':
|
||||
self._name, self._reason, self._templateId, self._state = vals[1:]
|
||||
self._name, self._reason, self._templateId, self._state, self._destroyAfter = vals[1:]
|
||||
|
||||
def publish(self):
|
||||
'''
|
||||
@ -87,13 +96,16 @@ class LivePublication(Publication):
|
||||
'''
|
||||
self._name = self.service().sanitizeVmName('UDSP ' + self.dsName() + "-" + str(self.revision()))
|
||||
self._reason = '' # No error, no reason for it
|
||||
self._state = 'ok'
|
||||
self._destroyAfter = 'n'
|
||||
|
||||
try:
|
||||
self._templateId = self.service().makeTemplate(self._name)
|
||||
res = self.service().makeTemplate(self._name)
|
||||
logger.debug('Result: {}'.format(res))
|
||||
self._templateId = res['id']
|
||||
self._state = res['status']
|
||||
except Exception as e:
|
||||
self._state = 'error'
|
||||
self._reason = str(e)
|
||||
self._reason = 'Got error {}'.format(e)
|
||||
return State.ERROR
|
||||
|
||||
return State.RUNNING
|
||||
@ -105,11 +117,15 @@ class LivePublication(Publication):
|
||||
if self._state == 'error':
|
||||
return State.ERROR
|
||||
|
||||
if self._state == 'ok':
|
||||
if self._state == 'available':
|
||||
return State.FINISHED
|
||||
|
||||
self._state = 'ok'
|
||||
return State.FINISHED
|
||||
self._state = self.service().getTemplate(self._templateId)['status'] # For next check
|
||||
|
||||
if self._destroyAfter == 'y' and self._state == 'available':
|
||||
return self.destroy()
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
@ -139,11 +155,18 @@ class LivePublication(Publication):
|
||||
State.FINISHED or State.ERROR.
|
||||
'''
|
||||
# We do not do anything else to destroy this instance of publication
|
||||
if self._state == 'error':
|
||||
return # Nothing to cancel
|
||||
|
||||
if self._state == 'creating':
|
||||
self._destroyAfter = 'y'
|
||||
return State.RUNNING
|
||||
|
||||
try:
|
||||
self.service().removeTemplate(self._templateId)
|
||||
except Exception as e:
|
||||
self._state = 'error'
|
||||
self._reason = str(e)
|
||||
self._reason = six.text_type(e)
|
||||
return State.ERROR
|
||||
|
||||
return State.FINISHED
|
||||
|
@ -39,10 +39,10 @@ from . import helpers
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
|
||||
import six
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-03-04'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -105,10 +105,10 @@ class LiveService(Service):
|
||||
},
|
||||
tooltip=_('Project for this service'), required=True
|
||||
)
|
||||
availabilityZone = gui.ChoiceField(label=_("Availability Zones"), order=3, tooltip=_('Service availability zones'), required=True)
|
||||
availabilityZone = gui.ChoiceField(label=_("Availability Zones"), order=3, tooltip=_('Service availability zones'), required=True, rdonly=True)
|
||||
volume = gui.ChoiceField(label=_("Volume"), order=4, tooltip=_('Base volume for service'), required=True)
|
||||
# volumeType = gui.ChoiceField(label=_("Volume Type"), order=5, tooltip=_('Volume type for service'), required=True)
|
||||
networks = gui.MultiChoiceField(label=_("Networks"), order=6, tooltip=_('Networks to attach to this service'), required=True)
|
||||
network = gui.ChoiceField(label=_("Network"), order=6, tooltip=_('Network to attach to this service'), required=True)
|
||||
flavor = gui.ChoiceField(label=_("Flavor"), order=7, tooltip=_('Flavor for service'), required=True)
|
||||
|
||||
securityGroups = gui.MultiChoiceField(label=_("Security Groups"), order=8, tooltip=_('Service security groups'), required=True)
|
||||
@ -137,7 +137,7 @@ class LiveService(Service):
|
||||
'''
|
||||
We check here form values to see if they are valid.
|
||||
|
||||
Note that we check them throught FROM variables, that already has been
|
||||
Note that we check them through FROM variables, that already has been
|
||||
initialized by __init__ method of base class, before invoking this.
|
||||
'''
|
||||
if values is not None:
|
||||
@ -158,7 +158,7 @@ class LiveService(Service):
|
||||
Loads required values inside
|
||||
'''
|
||||
api = self.parent().api()
|
||||
regions = [gui.choiceItem(r, r) for r in api.listRegions()]
|
||||
regions = [gui.choiceItem(r['id'], r['id']) for r in api.listRegions()]
|
||||
self.region.setValues(regions)
|
||||
|
||||
tenants = [gui.choiceItem(t['id'], t['name']) for t in api.listProjects()]
|
||||
@ -187,6 +187,12 @@ class LiveService(Service):
|
||||
description = 'UDS Template snapshot' if description is None else description
|
||||
return self.api.createVolumeSnapshot(self.volume.value, templateName, description)
|
||||
|
||||
def getTemplate(self, snapshotId):
|
||||
'''
|
||||
Checks current state of a template (an snapshot)
|
||||
'''
|
||||
return self.api.getSnapshot(snapshotId)
|
||||
|
||||
def deployFromTemplate(self, name, snapshotId):
|
||||
'''
|
||||
Deploys a virtual machine on selected cluster from selected template
|
||||
@ -194,45 +200,58 @@ class LiveService(Service):
|
||||
Args:
|
||||
name: Name (sanitized) of the machine
|
||||
comments: Comments for machine
|
||||
templateId: Id of the template to deploy from
|
||||
displayType: 'vnc' or 'spice'. Display to use ad oVirt admin interface
|
||||
memoryMB: Memory requested for machine, in MB
|
||||
guaranteedMB: Minimum memory guaranteed for this machine
|
||||
snapshotId: Id of the snapshot to deploy from
|
||||
|
||||
Returns:
|
||||
Id of the machine being created form template
|
||||
'''
|
||||
logger.debug('Deploying from template {0} machine {1}'.format(snapshotId, name))
|
||||
# self.datastoreHasSpace()
|
||||
# self.api.
|
||||
return self.api.createServerFromSnapshot(snapshotId=snapshotId,
|
||||
name=name,
|
||||
availabilityZone=self.availabilityZone.value,
|
||||
flavorId=self.flavor.value,
|
||||
networkId=self.network.value,
|
||||
securityGroupsIdsList=self.securityGroups.value)['id']
|
||||
|
||||
def removeTemplate(self, templateId):
|
||||
'''
|
||||
invokes removeTemplate from parent provider
|
||||
'''
|
||||
return self.parent().removeTemplate(templateId)
|
||||
self.api.deleteSnapshot(templateId)
|
||||
|
||||
def getMachineState(self, machineId):
|
||||
'''
|
||||
Invokes getMachineState from parent provider
|
||||
(returns if machine is "active" or "inactive"
|
||||
Invokes getServer from openstack client
|
||||
|
||||
Args:
|
||||
machineId: If 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
|
||||
ACTIVE. The server is active.
|
||||
BUILDING. The server has not finished the original build process.
|
||||
DELETED. The server is permanently deleted.
|
||||
ERROR. The server is in error.
|
||||
HARD_REBOOT. The server is hard rebooting. This is equivalent to pulling the power plug on a physical server, plugging it back in, and rebooting it.
|
||||
MIGRATING. The server is being migrated to a new host.
|
||||
PASSWORD. The password is being reset on the server.
|
||||
PAUSED. In a paused state, the state of the server is stored in RAM. A paused server continues to run in frozen state.
|
||||
REBOOT. The server is in a soft reboot state. A reboot command was passed to the operating system.
|
||||
REBUILD. The server is currently being rebuilt from an image.
|
||||
RESCUED. The server is in rescue mode. A rescue image is running with the original server image attached.
|
||||
RESIZED. Server is performing the differential copy of data that changed during its initial copy. Server is down for this stage.
|
||||
REVERT_RESIZE. The resize or migration of a server failed for some reason. The destination server is being cleaned up and the original source server is restarting.
|
||||
SOFT_DELETED. The server is marked as deleted but the disk images are still available to restore.
|
||||
STOPPED. The server is powered off and the disk image still persists.
|
||||
SUSPENDED. The server is suspended, either by request or necessity. This status appears for only the XenServer/XCP, KVM, and ESXi hypervisors. Administrative users can suspend an instance if it is infrequently used or to perform system maintenance. When you suspend an instance, its VM state is stored on disk, all memory is written to disk, and the virtual machine is stopped. Suspending an instance is similar to placing a device in hibernation; memory and vCPUs become available to create other instances.
|
||||
VERIFY_RESIZE. System is awaiting confirmation that the server is operational after a move or resize.
|
||||
'''
|
||||
return self.parent().getMachineState(machineId)
|
||||
return self.api.getServer(machineId)['status']
|
||||
|
||||
def startMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt.
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenStack.
|
||||
|
||||
This start also "resume" suspended/paused machines
|
||||
|
||||
@ -241,46 +260,60 @@ class LiveService(Service):
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.parent().startMachine(machineId)
|
||||
return self.api.startServer(machineId)
|
||||
|
||||
def stopMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to stop a machine. No check is done, it is simply requested to OpenStack
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.parent().stopMachine(machineId)
|
||||
return self.api.stopServer(machineId)
|
||||
|
||||
def suspendMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to suspend a machine. No check is done, it is simply requested to OpenStack
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.parent().suspendMachine(machineId)
|
||||
return self.api.suspendServer(machineId)
|
||||
|
||||
def resumeMachine(self, machineId):
|
||||
'''
|
||||
Tries to start a machine. No check is done, it is simply requested to OpenStack
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.api.suspendServer(machineId)
|
||||
|
||||
|
||||
def removeMachine(self, machineId):
|
||||
'''
|
||||
Tries to delete a machine. No check is done, it is simply requested to oVirt
|
||||
Tries to delete a machine. No check is done, it is simply requested to OpenStack
|
||||
|
||||
Args:
|
||||
machineId: Id of the machine
|
||||
|
||||
Returns:
|
||||
'''
|
||||
return self.parent().removeMachine(machineId)
|
||||
return self.api.deleteServer(machineId)
|
||||
|
||||
def getNetInfo(self, machineId, networkId=None):
|
||||
def getNetInfo(self, machineId):
|
||||
'''
|
||||
Changes the mac address of first nic of the machine to the one specified
|
||||
Gets the mac address of first nic of the machine
|
||||
'''
|
||||
return self.parent().getNetInfo(machineId, networkId=None)
|
||||
net = self.api.getServer(machineId)['addresses']
|
||||
vals = six.next(six.itervalues(net))[0] # Returns "any" mac address of any interface. We just need only one interface info
|
||||
return (vals['OS-EXT-IPS-MAC:mac_addr'], vals['addr'])
|
||||
|
||||
def getBaseName(self):
|
||||
'''
|
||||
@ -293,9 +326,3 @@ class LiveService(Service):
|
||||
Returns the length of numbers part
|
||||
'''
|
||||
return int(self.lenName.value)
|
||||
|
||||
def getDisplay(self):
|
||||
'''
|
||||
Returns the selected display type (for created machines, for administration
|
||||
'''
|
||||
return self.display.value
|
||||
|
@ -38,7 +38,7 @@ def getResources(parameters):
|
||||
data = [
|
||||
{'name': 'availabilityZone', 'values': zones },
|
||||
{'name': 'volume', 'values': volumes },
|
||||
{'name': 'networks', 'values': networks },
|
||||
{'name': 'network', 'values': networks },
|
||||
{'name': 'flavor', 'values': flavors },
|
||||
{'name': 'securityGroups', 'values': securityGroups },
|
||||
{'name': 'volumeType', 'values': volumeTypes },
|
||||
|
@ -31,20 +31,17 @@
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=maybe-no-member
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from uds.core.util.Cache import Cache
|
||||
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
import six
|
||||
import hashlib
|
||||
import dateutil.parser
|
||||
|
||||
|
||||
# Python bindings for OpenNebula
|
||||
from .common import sanitizeName
|
||||
|
||||
__updated__ = '2016-03-04'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -64,32 +61,36 @@ VERIFY_SSL = False
|
||||
# Helpers
|
||||
def ensureResponseIsValid(response, errMsg=None):
|
||||
if response.ok is False:
|
||||
print "False"
|
||||
try:
|
||||
_x, err = response.json().popitem() # Extract any key, in case of error is expected to have only one top key so this will work
|
||||
errMsg = errMsg + ': {message}'.format(**err)
|
||||
except Exception:
|
||||
pass # If error geting error message, simply ignore it (will be loged on service log anyway)
|
||||
if errMsg is None:
|
||||
errMsg = 'Error checking response'
|
||||
logger.error('{}: {}'.format(errMsg, response.content))
|
||||
print response.content
|
||||
print response
|
||||
raise Exception(errMsg)
|
||||
|
||||
|
||||
def getRecurringUrlJson(url, headers, key, errMsg=None):
|
||||
def getRecurringUrlJson(url, headers, key, params=None, errMsg=None, timeout=10):
|
||||
counter = 0
|
||||
while True:
|
||||
counter += 1
|
||||
logger.debug('Requesting url #{}: {}'.format(counter, url))
|
||||
r = requests.get(url, headers=headers, verify=VERIFY_SSL)
|
||||
logger.debug('Requesting url #{}: {} / {}'.format(counter, url, params))
|
||||
r = requests.get(url, params=params, headers=headers, verify=VERIFY_SSL, timeout=timeout)
|
||||
|
||||
ensureResponseIsValid(r, errMsg)
|
||||
|
||||
json = r.json()
|
||||
j = r.json()
|
||||
|
||||
for v in json[key]:
|
||||
for v in j[key]:
|
||||
yield v
|
||||
|
||||
if 'next' not in json:
|
||||
if 'next' not in j:
|
||||
break
|
||||
|
||||
url = json['next']
|
||||
url = j['next']
|
||||
|
||||
|
||||
# Decorators
|
||||
@ -214,68 +215,70 @@ class Client(object):
|
||||
|
||||
@authRequired
|
||||
def listProjects(self):
|
||||
for p in getRecurringUrlJson(self._authUrl + 'v3/users/{user_id}/projects'.format(user_id=self._userId),
|
||||
return getRecurringUrlJson(self._authUrl + 'v3/users/{user_id}/projects'.format(user_id=self._userId),
|
||||
headers=self._requestHeaders(),
|
||||
key='projects',
|
||||
errMsg='List Projects'):
|
||||
|
||||
yield p
|
||||
errMsg='List Projects',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authRequired
|
||||
def listRegions(self):
|
||||
for r in getRecurringUrlJson(self._authUrl + 'v3/regions/',
|
||||
return getRecurringUrlJson(self._authUrl + 'v3/regions/',
|
||||
headers=self._requestHeaders(),
|
||||
key='regions',
|
||||
errMsg='List Regions'):
|
||||
yield r['id']
|
||||
errMsg='List Regions',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVms(self):
|
||||
for v in getRecurringUrlJson(self._getEndpointFor('compute') + '/servers',
|
||||
def listServers(self, detail=False, params=None):
|
||||
path = '/servers/' + 'detail' if detail is True else ''
|
||||
return getRecurringUrlJson(self._getEndpointFor('compute') + path,
|
||||
headers=self._requestHeaders(),
|
||||
key='servers',
|
||||
errMsg='List Vms'):
|
||||
yield { 'name': v['name'], 'id': v['id'] }
|
||||
params=params,
|
||||
errMsg='List Vms',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listImages(self):
|
||||
for i in getRecurringUrlJson(self._getEndpointFor('image') + '/v2/images?status=active',
|
||||
return getRecurringUrlJson(self._getEndpointFor('image') + '/v2/images?status=active',
|
||||
headers=self._requestHeaders(),
|
||||
key='images',
|
||||
errMsg='List Images'):
|
||||
yield { 'name': i['name'], 'size': i['size'], 'visibility': i['visibility'], 'format': i['disk_format'] }
|
||||
errMsg='List Images',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeTypes(self):
|
||||
for t in getRecurringUrlJson(self._getEndpointFor('volumev2') + '/types',
|
||||
return getRecurringUrlJson(self._getEndpointFor('volumev2') + '/types',
|
||||
headers=self._requestHeaders(),
|
||||
key='volume_types',
|
||||
errMsg='List Volume Types'):
|
||||
yield { 'id': t['id'], 'name': t['name'] }
|
||||
errMsg='List Volume Types',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumes(self):
|
||||
# self._getEndpointFor('volumev2') + '/volumes'
|
||||
for v in getRecurringUrlJson(self._getEndpointFor('volumev2') + '/volumes/detail',
|
||||
return getRecurringUrlJson(self._getEndpointFor('volumev2') + '/volumes/detail',
|
||||
headers=self._requestHeaders(),
|
||||
key='volumes',
|
||||
errMsg='List Volumes'):
|
||||
yield { 'id': v['id'], 'name': v['name'], 'size': v['size'], 'status': v['status'] }
|
||||
errMsg='List Volumes',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeSnapshots(self, volumeId):
|
||||
def listVolumeSnapshots(self, volumeId=None):
|
||||
for s in getRecurringUrlJson(self._getEndpointFor('volumev2') + '/snapshots',
|
||||
headers=self._requestHeaders(),
|
||||
key='snapshots',
|
||||
errMsg='List snapshots'):
|
||||
if s['volume_id'] == volumeId:
|
||||
yield { 'id': s['id'], 'name': s['name'], 'description': s['description'], 'status': s['status'] }
|
||||
errMsg='List snapshots',
|
||||
timeout=self._timeout):
|
||||
if volumeId is None or s['volume_id'] == volumeId:
|
||||
yield s
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
@ -283,43 +286,69 @@ class Client(object):
|
||||
for az in getRecurringUrlJson(self._getEndpointFor('compute') + '/os-availability-zone',
|
||||
headers=self._requestHeaders(),
|
||||
key='availabilityZoneInfo',
|
||||
errMsg='List Availability Zones'):
|
||||
errMsg='List Availability Zones',
|
||||
timeout=self._timeout):
|
||||
if az['zoneState']['available'] is True:
|
||||
yield az['zoneName']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listFlavors(self):
|
||||
for f in getRecurringUrlJson(self._getEndpointFor('compute') + '/flavors',
|
||||
return getRecurringUrlJson(self._getEndpointFor('compute') + '/flavors',
|
||||
headers=self._requestHeaders(),
|
||||
key='flavors',
|
||||
errMsg='List Flavors'):
|
||||
yield { 'id': f['id'], 'name': f['name'] }
|
||||
errMsg='List Flavors',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listNetworks(self):
|
||||
for n in getRecurringUrlJson(self._getEndpointFor('compute') + '/os-tenant-networks',
|
||||
return getRecurringUrlJson(self._getEndpointFor('network') + '/v2.0/networks',
|
||||
headers=self._requestHeaders(),
|
||||
key='networks',
|
||||
errMsg='List Networks'):
|
||||
yield { 'id': n['id'], 'name': n['label'] }
|
||||
errMsg='List Networks',
|
||||
timeout=self._timeout)
|
||||
|
||||
@authProjectRequired
|
||||
def listPorts(self, networkId=None, ownerId=None):
|
||||
params = {}
|
||||
if networkId is not None:
|
||||
params['network_id'] = networkId
|
||||
if ownerId is not None:
|
||||
params['device_owner'] = ownerId
|
||||
|
||||
return getRecurringUrlJson(self._getEndpointFor('network') + '/v2.0/ports',
|
||||
headers=self._requestHeaders(),
|
||||
key='ports',
|
||||
params=params,
|
||||
errMsg='List ports',
|
||||
timeout=self._timeout)
|
||||
|
||||
@authProjectRequired
|
||||
def listSecurityGroups(self):
|
||||
for s in getRecurringUrlJson(self._getEndpointFor('compute') + '/os-security-groups',
|
||||
return getRecurringUrlJson(self._getEndpointFor('compute') + '/os-security-groups',
|
||||
headers=self._requestHeaders(),
|
||||
key='security_groups',
|
||||
errMsg='List security groups'):
|
||||
yield { 'id': s['id'], 'name': s['name'] }
|
||||
errMsg='List security groups',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def getServer(self, serverId):
|
||||
r = requests.get(self._getEndpointFor('compute') + '/servers/{server_id}'.format(server_id=serverId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Get Server information')
|
||||
return r.json()['server']
|
||||
|
||||
@authProjectRequired
|
||||
def getVolume(self, volumeId):
|
||||
r = requests.get(self._getEndpointFor('volumev2') + '/volumes/{volume_id}'.format(volume_id=volumeId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL)
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Get Volume information')
|
||||
|
||||
@ -330,17 +359,43 @@ class Client(object):
|
||||
|
||||
@authProjectRequired
|
||||
def getSnapshot(self, snapshotId):
|
||||
'''
|
||||
States are:
|
||||
creating, available, deleting, error, error_deleting
|
||||
'''
|
||||
r = requests.get(self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL)
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Get Snaphost information')
|
||||
|
||||
v = r.json()['snapshot']
|
||||
|
||||
return { 'id': v['id'], 'name': v['name'], 'status': v['status'], 'volume_id': v['volume_id'] }
|
||||
return v
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def updateSnapshot(self, snapshotId, name=None, description=None):
|
||||
data = { 'snapshot': {} }
|
||||
if name is not None:
|
||||
data['snapshot']['name'] = name
|
||||
|
||||
if description is not None:
|
||||
data['snapshot']['description'] = description
|
||||
|
||||
r = requests.put(self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Update Snaphost information')
|
||||
|
||||
v = r.json()['snapshot']
|
||||
|
||||
return v
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeSnapshot(self, volumeId, name, description=None):
|
||||
@ -364,7 +419,8 @@ class Client(object):
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot create snapshot. Ensure volume is in state "available"')
|
||||
|
||||
return r.json()
|
||||
return r.json()['snapshot']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeFromSnapshot(self, snapshotId, name, description=None):
|
||||
@ -373,7 +429,7 @@ class Client(object):
|
||||
'volume': {
|
||||
'name': name,
|
||||
'description': description,
|
||||
# 'volume_type': volType, # This is the volume type, not the id
|
||||
# 'volume_type': volType, # This seems to be the volume type name, not the id
|
||||
'snapshot_id': snapshotId
|
||||
}
|
||||
}
|
||||
@ -388,6 +444,111 @@ class Client(object):
|
||||
|
||||
return r.json()
|
||||
|
||||
@authProjectRequired
|
||||
def createServerFromSnapshot(self, snapshotId, name, availabilityZone, flavorId, networkId, securityGroupsIdsList, count=1):
|
||||
data = {
|
||||
'server': {
|
||||
'name': name,
|
||||
'imageRef': '',
|
||||
'os-availability-zone': availabilityZone,
|
||||
'availability_zone': availabilityZone,
|
||||
'block_device_mapping_v2': [{
|
||||
'boot_index': '0',
|
||||
'uuid': snapshotId,
|
||||
# 'volume_size': 1,
|
||||
# 'device_name': 'vda',
|
||||
'source_type': 'snapshot',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': True
|
||||
}],
|
||||
'flavorRef': flavorId,
|
||||
# 'OS-DCF:diskConfig': 'AUTO',
|
||||
'max_count': count,
|
||||
'min_count': count,
|
||||
'networks': [ { 'uuid': networkId } ],
|
||||
'security_groups': [{'name': sg} for sg in securityGroupsIdsList]
|
||||
}
|
||||
}
|
||||
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers',
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot create instance from snapshot.')
|
||||
|
||||
return r.json()['server']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def deleteServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"forceDelete": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot start server (probably server does not exists).')
|
||||
|
||||
# This does not returns anything
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def deleteSnapshot(self, snapshotId):
|
||||
r = requests.delete(self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot remove snapshot.')
|
||||
|
||||
# Does not returns a message body
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def startServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"os-start": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Starting server')
|
||||
|
||||
# This does not returns anything
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def stopServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"os-stop": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Stoping server')
|
||||
|
||||
@authProjectRequired
|
||||
def suspendServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"suspend": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Suspending server')
|
||||
|
||||
@authProjectRequired
|
||||
def resumeServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"resume": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
|
||||
ensureResponseIsValid(r, 'Resuming server')
|
||||
|
||||
|
||||
def testConnection(self):
|
||||
# First, ensure requested api is supported
|
||||
@ -405,6 +566,6 @@ class Client(object):
|
||||
self.authPassword()
|
||||
return True
|
||||
except Exception:
|
||||
raise Exception('Authentication error')
|
||||
raise Exception(_('Authentication error'))
|
||||
|
||||
raise Exception(_('Openstack does not support identity API 3.2 or newer. This OpenStack server is not compatible with UDS.'))
|
||||
|
@ -41,7 +41,7 @@ import six
|
||||
from defusedxml import minidom
|
||||
|
||||
|
||||
__updated__ = '2016-03-04'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -50,7 +50,3 @@ from .common import *
|
||||
|
||||
from .UDSOpenStackClient import Client
|
||||
|
||||
from . import template
|
||||
from . import vm
|
||||
from . import storage
|
||||
|
||||
|
@ -33,15 +33,26 @@
|
||||
|
||||
import re
|
||||
|
||||
from libcloud.compute.types import Provider
|
||||
from libcloud.compute.providers import get_driver
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2016-03-04'
|
||||
__updated__ = '2016-03-07'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
(ACTIVE, BUILDING, DELETED, ERROR,
|
||||
HARD_REBOOT, MIGRATING, PASSWORD,
|
||||
PAUSED, REBOOT, REBUILD, RESCUED,
|
||||
RESIZED, REVERT_RESIZE, SOFT_DELETED,
|
||||
STOPPED, SUSPENDED, UNKNOWN, VERIFY_RESIZE) = ('ACTIVE', 'BUILDING', 'DELETED', 'ERROR',
|
||||
'HARD_REBOOT', 'MIGRATING', 'PASSWORD',
|
||||
'PAUSED', 'REBOOT', 'REBUILD', 'RESCUED',
|
||||
'RESIZED', 'REVERT_RESIZE', 'SOFT_DELETED',
|
||||
'STOPPED', 'SUSPENDED', 'UNKNOWN', 'VERIFY_RESIZE')
|
||||
|
||||
# Helpers to check statuses
|
||||
def statusIsLost(status):
|
||||
return status in [DELETED, ERROR, UNKNOWN, SOFT_DELETED]
|
||||
|
||||
def sanitizeName(name):
|
||||
'''
|
||||
machine names with [a-zA-Z0-9_-]
|
||||
|
@ -1,42 +0,0 @@
|
||||
# -*- 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-25'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -1,46 +0,0 @@
|
||||
# -*- 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-25'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
# -*- 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
|
||||
|
||||
__updated__ = '2016-02-25'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user