mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-22 22:03:54 +03:00
Fixed macosx CoRD transports && backported OpenGnsys
This commit is contained in:
parent
201fb8ff9b
commit
34cd90f9a1
358
server/src/uds/services/OpenGnsys/OGDeployment.py
Normal file
358
server/src/uds/services/OpenGnsys/OGDeployment.py
Normal file
@ -0,0 +1,358 @@
|
||||
# -*- 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
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds.core.services import UserDeployment
|
||||
from uds.core.util.State import State
|
||||
from uds.core.util import log
|
||||
from uds.models.Util import getSqlDatetime
|
||||
|
||||
from . import og
|
||||
import six
|
||||
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
opCreate, opError, opFinish, opRemove, opRetry = range(5)
|
||||
|
||||
|
||||
class OGDeployment(UserDeployment):
|
||||
'''
|
||||
This class generates the user consumable elements of the service tree.
|
||||
|
||||
After creating at administration interface an Deployed Service, UDS will
|
||||
create consumable services for users using UserDeployment class as
|
||||
provider of this elements.
|
||||
|
||||
The logic for managing ovirt deployments (user machines in this case) is here.
|
||||
|
||||
'''
|
||||
|
||||
# : Recheck every six seconds by default (for task methods)
|
||||
suggestedTime = 20
|
||||
|
||||
def initialize(self):
|
||||
self._name = ''
|
||||
self._ip = ''
|
||||
self._mac = ''
|
||||
self._machineId = ''
|
||||
self._stamp = 0
|
||||
self._reason = ''
|
||||
self._queue = []
|
||||
|
||||
# Serializable needed methods
|
||||
def marshal(self):
|
||||
'''
|
||||
Does nothing right here, we will use envoronment storage in this sample
|
||||
'''
|
||||
return '\1'.join(['v1', self._name, self._ip, self._mac, self._machineId, self._reason, six.text_type(self._stamp), pickle.dumps(self._queue)])
|
||||
|
||||
def unmarshal(self, str_):
|
||||
'''
|
||||
Does nothing here also, all data are keeped at environment storage
|
||||
'''
|
||||
vals = str_.split('\1')
|
||||
if vals[0] == 'v1':
|
||||
self._name, self._ip, self._mac, self._machineId, self._reason, stamp, queue = vals[1:]
|
||||
self._stamp = int(stamp)
|
||||
self._queue = pickle.loads(queue)
|
||||
|
||||
def getName(self):
|
||||
return self._name
|
||||
|
||||
def getUniqueId(self):
|
||||
return self._mac.upper()
|
||||
|
||||
def getIp(self):
|
||||
return self._ip
|
||||
|
||||
def setReady(self):
|
||||
'''
|
||||
Right now, this does nothing on OG.
|
||||
The machine has been already been started.
|
||||
The problem is that currently there is no way that a machine is in FACT started.
|
||||
OpenGnsys will try it best by sending an WOL
|
||||
'''
|
||||
# if self.cache.get('ready') == '1':
|
||||
# return State.FINISHED
|
||||
|
||||
# status = self.service().status(self._machineId)
|
||||
# possible status are ("off", "oglive", "busy", "linux", "windows", "macos" o "unknown").
|
||||
# if status['status'] != 'off':
|
||||
# self.cache.put('ready', '1')
|
||||
# return State.FINISHED
|
||||
|
||||
# Return back machine to preparing?...
|
||||
return State.FINISHED
|
||||
|
||||
def deployForUser(self, user):
|
||||
'''
|
||||
Deploys an service instance for an user.
|
||||
'''
|
||||
logger.debug('Deploying for user')
|
||||
self.__initQueueForDeploy(False)
|
||||
return self.__executeQueue()
|
||||
|
||||
def deployForCache(self, cacheLevel):
|
||||
'''
|
||||
Deploys an service instance for cache
|
||||
'''
|
||||
self.__initQueueForDeploy() # No Level2 Cache possible
|
||||
return self.__executeQueue()
|
||||
|
||||
def __initQueueForDeploy(self):
|
||||
|
||||
self._queue = [opCreate, opFinish]
|
||||
|
||||
def __checkMachineReady(self):
|
||||
logger.debug('Checking that state of machine {} ({}) is ready'.format(self._machineId, self._name))
|
||||
|
||||
try:
|
||||
status = self.service().status(self._machineId)
|
||||
except Exception as e:
|
||||
logger.exception('Exception at checkMachineReady')
|
||||
return self.__error('Error checking machine: {}'.format(e))
|
||||
|
||||
# possible status are ("off", "oglive", "busy", "linux", "windows", "macos" o "unknown").
|
||||
if status['status'] in ("linux", "windows", "macos"):
|
||||
return State.FINISHED
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
def __getCurrentOp(self):
|
||||
if len(self._queue) == 0:
|
||||
return opFinish
|
||||
|
||||
return self._queue[0]
|
||||
|
||||
def __popCurrentOp(self):
|
||||
if len(self._queue) == 0:
|
||||
return opFinish
|
||||
|
||||
res = self._queue.pop(0)
|
||||
return res
|
||||
|
||||
def __pushFrontOp(self, op):
|
||||
self._queue.insert(0, op)
|
||||
|
||||
def __pushBackOp(self, op):
|
||||
self._queue.append(op)
|
||||
|
||||
def __error(self, reason):
|
||||
'''
|
||||
Internal method to set object as error state
|
||||
|
||||
Returns:
|
||||
State.ERROR, so we can do "return self.__error(reason)"
|
||||
'''
|
||||
logger.debug('Setting error state, reason: {0}'.format(reason))
|
||||
self.doLog(log.ERROR, reason)
|
||||
|
||||
# TODO: Unreserve machine?? Maybe it just better to keep it assigned so UDS don't get it again in a while...
|
||||
|
||||
self._queue = [opError]
|
||||
self._reason = str(reason)
|
||||
return State.ERROR
|
||||
|
||||
def __executeQueue(self):
|
||||
self.__debug('executeQueue')
|
||||
op = self.__getCurrentOp()
|
||||
|
||||
if op == opError:
|
||||
return State.ERROR
|
||||
|
||||
if op == opFinish:
|
||||
return State.FINISHED
|
||||
|
||||
fncs = {
|
||||
opCreate: self.__create,
|
||||
opRetry: self.__retry,
|
||||
opRemove: self.__remove,
|
||||
}
|
||||
|
||||
try:
|
||||
execFnc = fncs.get(op, None)
|
||||
|
||||
if execFnc is None:
|
||||
return self.__error('Unknown operation found at execution queue ({0})'.format(op))
|
||||
|
||||
execFnc()
|
||||
|
||||
return State.RUNNING
|
||||
except Exception as e:
|
||||
logger.exception('Got Exception')
|
||||
return self.__error(e)
|
||||
|
||||
# Queue execution methods
|
||||
def __retry(self):
|
||||
'''
|
||||
Used to retry an operation
|
||||
In fact, this will not be never invoked, unless we push it twice, because
|
||||
checkState method will "pop" first item when a check operation returns State.FINISHED
|
||||
|
||||
At executeQueue this return value will be ignored, and it will only be used at checkState
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def __create(self):
|
||||
'''
|
||||
Deploys a machine from template for user/cache
|
||||
'''
|
||||
try:
|
||||
r = self.service().reserve()
|
||||
except Exception as e:
|
||||
logger.exception('Creating machine')
|
||||
return self.__error('Error creating reservation: {}'.format(e))
|
||||
|
||||
self._machineId = r['id']
|
||||
self._name = r['name']
|
||||
self._mac = r['mac']
|
||||
self._ip = r['ip']
|
||||
self._stamp = getSqlDatetime(unix=True)
|
||||
# Store actor version
|
||||
self.dbservice().setProperty('actor_version', '1.0-OpenGnsys')
|
||||
|
||||
def __remove(self):
|
||||
'''
|
||||
Removes a machine from system
|
||||
'''
|
||||
self.service().unreserve(self._machineId)
|
||||
|
||||
# Check methods
|
||||
def __checkCreate(self):
|
||||
'''
|
||||
Checks the state of a deploy for an user or cache
|
||||
'''
|
||||
return self.__checkMachineReady()
|
||||
|
||||
def __checkRemoved(self):
|
||||
'''
|
||||
Checks if a machine has been removed
|
||||
'''
|
||||
return State.FINISHED # No check at all, always true
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Check what operation is going on, and acts acordly to it
|
||||
'''
|
||||
self.__debug('checkState')
|
||||
op = self.__getCurrentOp()
|
||||
|
||||
if op == opError:
|
||||
return State.ERROR
|
||||
|
||||
if op == opFinish:
|
||||
return State.FINISHED
|
||||
|
||||
fncs = {
|
||||
opCreate: self.__checkCreate,
|
||||
opRetry: self.__retry,
|
||||
opRemove: self.__checkRemoved,
|
||||
}
|
||||
|
||||
try:
|
||||
chkFnc = fncs.get(op, None)
|
||||
|
||||
if chkFnc is None:
|
||||
return self.__error('Unknown operation found at check queue ({0})'.format(op))
|
||||
|
||||
state = chkFnc()
|
||||
if state == State.FINISHED:
|
||||
self.__popCurrentOp() # Remove runing op
|
||||
return self.__executeQueue()
|
||||
|
||||
return state
|
||||
except Exception as e:
|
||||
return self.__error(e)
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when the core notices that the deployment of a service has finished.
|
||||
(No matter wether it is for cache or for an user)
|
||||
'''
|
||||
self.__debug('finish')
|
||||
pass
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
Returns the reason of the error.
|
||||
|
||||
Remember that the class is responsible of returning this whenever asked
|
||||
for it, and it will be asked everytime it's needed to be shown to the
|
||||
user (when the administation asks for it).
|
||||
'''
|
||||
return self._reason
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
Invoked for destroying a deployed service
|
||||
'''
|
||||
self.__debug('destroy')
|
||||
# If executing something, wait until finished to remove it
|
||||
# We simply replace the execution queue
|
||||
self._queue = [opRemove, opFinish]
|
||||
return self.__executeQueue()
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
invoked directly.
|
||||
'''
|
||||
return self.destroy()
|
||||
|
||||
@staticmethod
|
||||
def __op2str(op):
|
||||
return {
|
||||
opCreate: 'create',
|
||||
opRemove: 'remove',
|
||||
opError: 'error',
|
||||
opFinish: 'finish',
|
||||
opRetry: 'retry',
|
||||
}.get(op, '????')
|
||||
|
||||
def __debug(self, txt):
|
||||
logger.debug('_name {0}: {1}'.format(txt, self._name))
|
||||
logger.debug('_ip {0}: {1}'.format(txt, self._ip))
|
||||
logger.debug('_mac {0}: {1}'.format(txt, self._mac))
|
||||
logger.debug('_machineId {0}: {1}'.format(txt, self._machineId))
|
||||
logger.debug('Queue at {0}: {1}'.format(txt, [OGDeployment.__op2str(op) for op in self._queue]))
|
128
server/src/uds/services/OpenGnsys/OGPublication.py
Normal file
128
server/src/uds/services/OpenGnsys/OGPublication.py
Normal file
@ -0,0 +1,128 @@
|
||||
# -*- 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
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
from uds.core.services import Publication
|
||||
from uds.core.util.State import State
|
||||
from uds.models.Util import getSqlDatetime
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OGPublication(Publication):
|
||||
'''
|
||||
This class provides the publication of a oVirtLinkedService
|
||||
'''
|
||||
_name = ''
|
||||
|
||||
suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds
|
||||
|
||||
def initialize(self):
|
||||
'''
|
||||
This method will be invoked by default __init__ of base class, so it gives
|
||||
us the oportunity to initialize whataver we need here.
|
||||
|
||||
In our case, we setup a few attributes..
|
||||
'''
|
||||
|
||||
# We do not check anything at marshal method, so we ensure that
|
||||
# default values are correctly handled by marshal.
|
||||
self._name = ''
|
||||
|
||||
def marshal(self):
|
||||
'''
|
||||
returns data from an instance of Sample Publication serialized
|
||||
'''
|
||||
return '\t'.join(['v1', self._name])
|
||||
|
||||
def unmarshal(self, data):
|
||||
'''
|
||||
deserializes the data and loads it inside instance.
|
||||
'''
|
||||
logger.debug('Data: {0}'.format(data))
|
||||
vals = data.split('\t')
|
||||
if vals[0] == 'v1':
|
||||
self._name = vals[1]
|
||||
|
||||
def publish(self):
|
||||
'''
|
||||
Realizes the publication of the service
|
||||
'''
|
||||
self._name = 'Publication {}'.format(getSqlDatetime())
|
||||
return State.FINISHED
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Checks state of publication creation
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
In our case, finish does nothing
|
||||
'''
|
||||
pass
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
If a publication produces an error, here we must notify the reason why
|
||||
it happened. This will be called just after publish or checkState
|
||||
if they return State.ERROR
|
||||
|
||||
Returns an string, in our case, set at checkState
|
||||
'''
|
||||
return 'No error possible :)'
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is called once a publication is no more needed.
|
||||
|
||||
This method do whatever needed to clean up things, such as
|
||||
removing created "external" data (environment gets cleaned by core),
|
||||
etc..
|
||||
|
||||
The retunred value is the same as when publishing, State.RUNNING,
|
||||
State.FINISHED or State.ERROR.
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
Do same thing as destroy
|
||||
'''
|
||||
return self.destroy()
|
164
server/src/uds/services/OpenGnsys/OGService.py
Normal file
164
server/src/uds/services/OpenGnsys/OGService.py
Normal file
@ -0,0 +1,164 @@
|
||||
# -*- 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
|
||||
'''
|
||||
from django.utils.translation import ugettext_noop as _, ugettext
|
||||
from uds.core.transports import protocols
|
||||
from uds.core.services import Service, types as serviceTypes
|
||||
from .OGDeployment import OGDeployment
|
||||
from .OGPublication import OGPublication
|
||||
from . import helpers
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OGService(Service):
|
||||
'''
|
||||
OpenGnsys Service
|
||||
'''
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
# : sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
typeName = _('OpenGnsys Machines Service')
|
||||
# : Type used internally to identify this provider
|
||||
typeType = 'openGnsysMachine'
|
||||
# : Description shown at administration interface for this provider
|
||||
typeDescription = _('OpenGnsys physical machines')
|
||||
# : Icon file used as icon for this provider. This string will be translated
|
||||
# : BEFORE sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
iconFile = 'provider.png'
|
||||
|
||||
# Functional related data
|
||||
|
||||
# : If the service provides more than 1 "deployed user" (-1 = no limit,
|
||||
# : 0 = ???? (do not use it!!!), N = max number to deploy
|
||||
maxDeployed = -1
|
||||
# : If we need to generate "cache" for this service, so users can access the
|
||||
# : provided services faster. Is usesCache is True, you will need also
|
||||
# : set publicationType, do take care about that!
|
||||
usesCache = True
|
||||
# : Tooltip shown to user when this item is pointed at admin interface, none
|
||||
# : because we don't use it
|
||||
cacheTooltip = _('Number of desired machines to keep running waiting for an user')
|
||||
|
||||
# : If the service needs a s.o. manager (managers are related to agents
|
||||
# : provided by services itselfs, i.e. virtual machines with actors)
|
||||
needsManager = False
|
||||
# : If true, the system can't do an automatic assignation of a deployed user
|
||||
# : service from this service
|
||||
mustAssignManually = False
|
||||
|
||||
# : Types of publications (preparated data for deploys)
|
||||
# : In our case, we do no need a publication, so this is None
|
||||
publicationType = OGPublication
|
||||
# : Types of deploys (services in cache and/or assigned to users)
|
||||
deployedType = OGDeployment
|
||||
|
||||
allowedProtocols = protocols.GENERIC
|
||||
servicesTypeProvided = (serviceTypes.VDI,)
|
||||
|
||||
# Now the form part
|
||||
ou = gui.ChoiceField(
|
||||
label=_("OU"),
|
||||
order=100,
|
||||
fills={
|
||||
'callbackName' : 'osFillData',
|
||||
'function' : helpers.getResources,
|
||||
'parameters' : ['ov', 'ev', 'ou']
|
||||
},
|
||||
tooltip=_('Organizational Unit'),
|
||||
required=True
|
||||
)
|
||||
|
||||
# Lab is not required, but maybe used as filter
|
||||
lab = gui.ChoiceField(
|
||||
label=_("lab"),
|
||||
order=101,
|
||||
tooltip=_('Laboratory'),
|
||||
required=False
|
||||
)
|
||||
|
||||
# Required, this is the base image
|
||||
image = gui.ChoiceField(
|
||||
label=_("OS Image"),
|
||||
order=102,
|
||||
tooltip=_('OpenGnsys Operanting System Image'),
|
||||
required=True
|
||||
)
|
||||
|
||||
maxReservationTime = gui.NumericField(
|
||||
length=3,
|
||||
label=_("Max. reservation time"),
|
||||
order=110,
|
||||
tooltip=_('Security parameter for OpenGnsys to kepp reservations at most this hours'),
|
||||
defvalue='24',
|
||||
tab=_('Advanced'),
|
||||
required=False
|
||||
)
|
||||
|
||||
ov = gui.HiddenField(value=None)
|
||||
ev = gui.HiddenField(value=None) # We need to keep the env so we can instantiate the Provider
|
||||
|
||||
def initialize(self, values):
|
||||
'''
|
||||
We check here form values to see if they are valid.
|
||||
|
||||
Note that we check them throught FROM variables, that already has been
|
||||
initialized by __init__ method of base class, before invoking this.
|
||||
'''
|
||||
if values is not None:
|
||||
pass
|
||||
|
||||
def initGui(self):
|
||||
'''
|
||||
Loads required values inside
|
||||
'''
|
||||
ous = [gui.choiceItem(r['id'], r['name']) for r in self.parent().api.getOus()]
|
||||
self.ou.setValues(ous)
|
||||
|
||||
self.ov.setDefValue(self.parent().serialize())
|
||||
self.ev.setDefValue(self.parent().env.key)
|
||||
|
||||
def status(self, machineId):
|
||||
return self.parent().status(machineId)
|
||||
|
||||
def reserve(self):
|
||||
return self.parent().reserve(self.ou.value, self.image.value, self.lab.value, self.maxReservationTime.num())
|
||||
|
||||
def unreserve(self, machineId):
|
||||
return self.parent().unreserve(machineId)
|
181
server/src/uds/services/OpenGnsys/Provider.py
Normal file
181
server/src/uds/services/OpenGnsys/Provider.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 distributiog.
|
||||
# * 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 permissiog.
|
||||
#
|
||||
# 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.
|
||||
|
||||
'''
|
||||
Created on Jun 22, 2012
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.services import ServiceProvider
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import validators
|
||||
from defusedxml import minidom
|
||||
|
||||
from .OGService import OGService
|
||||
from . import og
|
||||
|
||||
|
||||
import logging
|
||||
import six
|
||||
|
||||
|
||||
__updated__ = '2017-05-23'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class OGProvider(ServiceProvider):
|
||||
'''
|
||||
This class represents the sample services provider
|
||||
|
||||
In this class we provide:
|
||||
* The Provider functionality
|
||||
* The basic configuration parameters for the provider
|
||||
* The form fields needed by administrators to configure this provider
|
||||
|
||||
:note: At class level, the translation must be simply marked as so
|
||||
using ugettext_noop. This is so cause we will translate the string when
|
||||
sent to the administration client.
|
||||
|
||||
For this class to get visible at administration client as a provider type,
|
||||
we MUST register it at package __init__.
|
||||
|
||||
'''
|
||||
# : What kind of services we offer, this are classes inherited from Service
|
||||
offers = [OGService]
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
# : sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
typeName = _('OpenGnsys Platform Provider')
|
||||
# : Type used internally to identify this provider
|
||||
typeType = 'openGnsysPlatform'
|
||||
# : Description shown at administration interface for this provider
|
||||
typeDescription = _('OpenGnsys platform service provider (experimental)')
|
||||
# : Icon file used as icon for this provider. This string will be translated
|
||||
# : BEFORE sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
iconFile = 'provider.png'
|
||||
|
||||
# now comes the form fields
|
||||
# There is always two fields that are requested to the admin, that are:
|
||||
# Service Name, that is a name that the admin uses to name this provider
|
||||
# Description, that is a short description that the admin gives to this provider
|
||||
# Now we are going to add a few fields that we need to use this provider
|
||||
# Remember that these are "dummy" fields, that in fact are not required
|
||||
# but used for sample purposes
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True)
|
||||
port = gui.NumericField(length=5, label=_('Port'), defvalue='443', order=2, tooltip=_('OpenGnsys Port (default is 443, and only ssl connection is allowed)'), required=True)
|
||||
checkCert = gui.CheckBoxField(label=_('Check Cert.'), order=3, tooltip=_('If checked, ssl certificate of OpenGnsys server must be valid, not self signed)'))
|
||||
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenGnsys'), required=True)
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenGnsys'), required=True)
|
||||
udsServerAccessUrl = gui.TextField(length=32, label=_('UDS Server URL'), order=6, tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'), required=False, tab=gui.PARAMETERS_TAB)
|
||||
|
||||
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
|
||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', order=90, tooltip=_('Timeout in seconds of connection to OpenGnsys'), required=True, tab=gui.ADVANCED_TAB)
|
||||
|
||||
# Own variables
|
||||
_api = None
|
||||
|
||||
def initialize(self, values=None):
|
||||
'''
|
||||
We will use the "autosave" feature for form fields
|
||||
'''
|
||||
|
||||
# Just reset _api connection variable
|
||||
self._api = None
|
||||
|
||||
if values is not None:
|
||||
self.timeout.value = validators.validateTimeout(self.timeout.value, returnAsInteger=False)
|
||||
logger.debug('Endpoint: {}'.format(self.endpoint))
|
||||
|
||||
@property
|
||||
def endpoint(self):
|
||||
return 'https://{}:{}/rest'.format(self.host.value, self.port.value)
|
||||
|
||||
@property
|
||||
def api(self):
|
||||
if self._api is None:
|
||||
self._api = og.OpenGnsysClient(self.username.value, self.password.value, self.endpoint, self.cache, self.checkCert.isTrue())
|
||||
|
||||
logger.debug('Api: {}'.format(self._api))
|
||||
return self._api
|
||||
|
||||
def resetApi(self):
|
||||
self._api = None
|
||||
|
||||
def testConnection(self):
|
||||
'''
|
||||
Test that conection to OpenGnsys server is fine
|
||||
|
||||
Returns
|
||||
|
||||
True if all went fine, false if id didn't
|
||||
'''
|
||||
try:
|
||||
if self.api.version[0:5] < '1.1.0':
|
||||
return [False, 'OpenGnsys version is not supported (required version 1.1.0 or newer and found {})'.format(self.api.version)]
|
||||
except Exception as e:
|
||||
logger.exception('Error')
|
||||
return [False, '{}'.format(e)]
|
||||
|
||||
return [True, _('OpenGnsys test connection passed')]
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
'''
|
||||
Test ovirt Connectivity
|
||||
|
||||
Args:
|
||||
env: environment passed for testing (temporal environment passed)
|
||||
|
||||
data: data passed for testing (data obtained from the form
|
||||
definition)
|
||||
|
||||
Returns:
|
||||
Array of two elements, first is True of False, depending on test
|
||||
(True is all right, false is error),
|
||||
second is an String with error, preferably internacionalizated..
|
||||
|
||||
'''
|
||||
return OGProvider(env, data).testConnection()
|
||||
|
||||
def reserve(self, ou, image, lab=0, maxtime=0):
|
||||
return self.api.reserve(ou, image, lab, maxtime)
|
||||
|
||||
def unreserve(self, machineId):
|
||||
return self.api.unreserve(machineId)
|
||||
|
||||
def status(self, machineId):
|
||||
return self.api.status(machineId)
|
32
server/src/uds/services/OpenGnsys/__init__.py
Normal file
32
server/src/uds/services/OpenGnsys/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# -*- 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.
|
||||
|
||||
|
||||
from .Provider import OGProvider
|
||||
|
39
server/src/uds/services/OpenGnsys/helpers.py
Normal file
39
server/src/uds/services/OpenGnsys/helpers.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
import logging
|
||||
from uds.core.ui import gui
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def getResources(parameters):
|
||||
'''
|
||||
This helper is designed as a callback for Project Selector
|
||||
'''
|
||||
from .Provider import OGProvider
|
||||
from uds.core.Environment import Environment
|
||||
logger.debug('Parameters received by getResources Helper: {0}'.format(parameters))
|
||||
env = Environment(parameters['ev'])
|
||||
provider = OGProvider(env)
|
||||
provider.unserialize(parameters['ov'])
|
||||
|
||||
api = provider.api
|
||||
|
||||
labs = [gui.choiceItem('0', _('All Labs'))] + [gui.choiceItem(l['id'], l['name']) for l in api.getLabs(ou=parameters['ou'])]
|
||||
images = [gui.choiceItem(z['id'], z['name']) for z in api.getImages(ou=parameters['ou'])]
|
||||
|
||||
data = [
|
||||
{'name': 'lab', 'values': labs },
|
||||
{'name': 'image', 'values': images },
|
||||
]
|
||||
logger.debug('Return data: {}'.format(data))
|
||||
return data
|
228
server/src/uds/services/OpenGnsys/og/__init__.py
Normal file
228
server/src/uds/services/OpenGnsys/og/__init__.py
Normal file
@ -0,0 +1,228 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 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
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from . import urls
|
||||
from . import fake
|
||||
|
||||
import sys
|
||||
import imp
|
||||
import re
|
||||
|
||||
import logging
|
||||
import six
|
||||
|
||||
import requests
|
||||
import json
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# URLS
|
||||
|
||||
# Fake part
|
||||
FAKE = True
|
||||
CACHE_VALIDITY = 180
|
||||
|
||||
|
||||
# Decorator
|
||||
def ensureConnected(fnc):
|
||||
def inner(*args, **kwargs):
|
||||
args[0].connect()
|
||||
return fnc(*args, **kwargs)
|
||||
return inner
|
||||
|
||||
# Result checker
|
||||
def ensureResponseIsValid(response, errMsg=None):
|
||||
if response.ok is False:
|
||||
if errMsg is None:
|
||||
errMsg = 'Invalid response'
|
||||
|
||||
# If response.code is not 200, the response is an error and should have a message
|
||||
# FIX THIS
|
||||
if response.code != 200:
|
||||
try:
|
||||
err = response.json()['message'] # Extract any key, in case of error is expected to have only one top key so this will work
|
||||
except Exception:
|
||||
err = response.content
|
||||
errMsg = '{}: {}, ({})'.format(errMsg, err, response.code)
|
||||
logger.error('{}: {}'.format(errMsg, response.content))
|
||||
raise Exception(errMsg)
|
||||
|
||||
return json.loads(response.content)
|
||||
|
||||
class OpenGnsysClient(object):
|
||||
def __init__(self, username, password, endpoint, cache, verifyCert=False):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.endpoint = endpoint
|
||||
self.auth = None
|
||||
self.cache = cache
|
||||
self.verifyCert = verifyCert
|
||||
self.cachedVersion = None
|
||||
|
||||
@property
|
||||
def headers(self):
|
||||
headers = {'content-type': 'application/json'}
|
||||
if self.auth is not None:
|
||||
headers['Authorization'] = self.auth
|
||||
|
||||
return headers
|
||||
|
||||
def _ogUrl(self, path):
|
||||
return self.endpoint + '/' + path
|
||||
|
||||
def _post(self, path, data, errMsg=None):
|
||||
if not FAKE:
|
||||
return ensureResponseIsValid(
|
||||
requests.post(self._ogUrl(path), data=json.dumps(data), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
)
|
||||
# FAKE Connection :)
|
||||
return fake.post(path, data, errMsg)
|
||||
|
||||
def _get(self, path, errMsg=None):
|
||||
if not FAKE:
|
||||
return ensureResponseIsValid(
|
||||
requests.get(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
)
|
||||
# FAKE Connection :)
|
||||
return fake.get(path, errMsg)
|
||||
|
||||
|
||||
def _delete(self, path, errMsg=None):
|
||||
if not FAKE:
|
||||
return ensureResponseIsValid(
|
||||
requests.delete(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
)
|
||||
return fake.delete(path, errMsg)
|
||||
|
||||
def connect(self):
|
||||
if self.auth is not None:
|
||||
return
|
||||
|
||||
cacheKey = 'auth{}{}'.format(self.endpoint, self.username)
|
||||
self.auth = self.cache.get(cacheKey)
|
||||
if self.auth is not None:
|
||||
return
|
||||
|
||||
auth = self._post(urls.LOGIN,
|
||||
data={
|
||||
'username': self.username,
|
||||
'password': self.password
|
||||
},
|
||||
errMsg='Loggin in'
|
||||
)
|
||||
|
||||
self.auth = auth['apikey']
|
||||
self.cache.put(cacheKey, self.auth, CACHE_VALIDITY)
|
||||
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
logger.debug('Getting version')
|
||||
if self.cachedVersion is None:
|
||||
# Retrieve Version & keep it
|
||||
info = self._get(urls.INFO, errMsg="Retrieving info")
|
||||
self.cachedVersion = info['version']
|
||||
|
||||
return self.cachedVersion
|
||||
|
||||
@ensureConnected
|
||||
def getOus(self):
|
||||
# Returns an array of elements with:
|
||||
# 'id': OpenGnsys Id
|
||||
# 'name': OU name
|
||||
# OpenGnsys already returns it in this format :)
|
||||
return self._get(urls.OUS, errMsg='Getting list of ous')
|
||||
|
||||
@ensureConnected
|
||||
def getLabs(self, ou):
|
||||
# Returns a list of available labs on an ou
|
||||
# /ous/{ouid}/labs
|
||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||
errMsg = 'Getting list of labs from ou {}'.format(ou)
|
||||
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.LABS.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True]
|
||||
|
||||
|
||||
@ensureConnected
|
||||
def getImages(self, ou):
|
||||
# Returns a list of available labs on an ou
|
||||
# /ous/{ouid}/images
|
||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||
errMsg = 'Getting list of images from ou {}'.format(ou)
|
||||
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.IMAGES.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True]
|
||||
|
||||
@ensureConnected
|
||||
def reserve(self, ou, image, lab=0, maxtime=24):
|
||||
# This method is inteded to "get" a machine from OpenGnsys
|
||||
# The method used is POST
|
||||
# invokes /ous/{ouid}}/images/{imageid}/reserve
|
||||
# also remember to store "labid"
|
||||
# Labid can be "0" that means "all laboratories"
|
||||
errMsg = 'Reserving image {} in ou {}'.format(ou, image)
|
||||
data = {
|
||||
'labid': lab,
|
||||
'maxtime': maxtime
|
||||
}
|
||||
res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg)
|
||||
return {
|
||||
'ou': ou,
|
||||
'image': image,
|
||||
'lab': lab,
|
||||
'client': res['id'],
|
||||
'id': '.'.join((six.text_type(ou), six.text_type(lab), six.text_type(res['id']))),
|
||||
'name': res['name'],
|
||||
'ip': res['ip'],
|
||||
'mac': ':'.join(re.findall('..', res['mac']))
|
||||
}
|
||||
|
||||
@ensureConnected
|
||||
def unreserve(self, id):
|
||||
# This method releases the previous reservation
|
||||
# Invoked every time we need to release a reservation (i mean, if a reservation is done, this will be called with the obtained id from that reservation)
|
||||
ou, lab, client = id.split('.')
|
||||
errMsg = 'Unreserving client {} in lab {} in ou {}'.format(client, lab, ou)
|
||||
return self._delete(urls.UNRESERVE.format(ou=ou, lab=lab, client=client), errMsg=errMsg)
|
||||
|
||||
@ensureConnected
|
||||
def status(self, id):
|
||||
# This method gets the status of the machine
|
||||
# /ous/{uoid}/labs/{labid}/clients/{clientid}/status
|
||||
# possible status are ("off", "oglive", "busy", "linux", "windows", "macos" o "unknown").
|
||||
# Look at api at informatica.us..
|
||||
ou, lab, client = id.split('.')
|
||||
return self._get(urls.STATUS.format(ou=ou, lab=lab, client=client))
|
225
server/src/uds/services/OpenGnsys/og/fake.py
Normal file
225
server/src/uds/services/OpenGnsys/og/fake.py
Normal file
@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 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
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
from . import urls
|
||||
import copy
|
||||
import random
|
||||
import six
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AUTH = {
|
||||
"userid": 1001,
|
||||
"apikey": "fakeAPIKeyJustForDeveloping"
|
||||
}
|
||||
|
||||
INFO = {
|
||||
"project": "OpenGnsys",
|
||||
"version": "1.1.0pre",
|
||||
"release": "r5299",
|
||||
"services": [
|
||||
"server",
|
||||
"repository",
|
||||
"tracker"
|
||||
],
|
||||
"oglive": [
|
||||
{
|
||||
"distribution": "xenial",
|
||||
"kernel": "4.8.0-39-generic",
|
||||
"architecture": "amd64",
|
||||
"revision": "r5225",
|
||||
"directory": "ogLive-xenial-4.8.0-amd64-r5225",
|
||||
"iso": "ogLive-xenial-4.8.0-39-generic-amd64-r5225.iso"
|
||||
},
|
||||
{
|
||||
"iso": "ogLive-precise-3.2.0-23-generic-r4820.iso",
|
||||
"directory": "ogLive-precise-3.2.0-i386-r4820",
|
||||
"revision": "r4820",
|
||||
"architecture": "i386",
|
||||
"kernel": "3.2.0-23-generic",
|
||||
"distribution": "precise"
|
||||
} ]
|
||||
}
|
||||
|
||||
OUS = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Unidad Organizativa (Default)"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Unidad Organizatva VACIA"
|
||||
},
|
||||
]
|
||||
|
||||
LABS = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Sala de control",
|
||||
"inremotepc": True,
|
||||
"group": {
|
||||
"id": "0"
|
||||
},
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Sala de computación cuántica",
|
||||
"inremotepc": True,
|
||||
"group": {
|
||||
"id": "0"
|
||||
},
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
IMAGES = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Basica1604",
|
||||
"inremotepc": True,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Ubuntu16",
|
||||
"inremotepc": True,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "Ubuntu64 Not in Remote",
|
||||
"inremotepc": False,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"name": "Ubuntu96 Not In Remote",
|
||||
"inremotepc": False,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
RESERVE = {
|
||||
"id": 4,
|
||||
"name": "pcpruebas",
|
||||
"mac": "4061860521FE",
|
||||
"ip": "10.1.14.31",
|
||||
"lab": {
|
||||
"id": 1
|
||||
},
|
||||
"ou": {
|
||||
"id": 1
|
||||
}
|
||||
}
|
||||
|
||||
UNRESERVE = ''
|
||||
|
||||
STATUS_OFF = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "off",
|
||||
"loggedin": False
|
||||
}
|
||||
|
||||
# A couple of status for testing
|
||||
STATUS_READY_LINUX = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "linux",
|
||||
"loggedin": False
|
||||
}
|
||||
|
||||
STATUS_READY_WINDOWS = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "windows",
|
||||
"loggedin": False
|
||||
}
|
||||
|
||||
# FAKE post
|
||||
def post(path, data, errMsg):
|
||||
logger.info('FAKE POST request to {} with {} data. ({})'.format(path, data, errMsg))
|
||||
if path == urls.LOGIN:
|
||||
return AUTH
|
||||
elif path == urls.RESERVE.format(ou=1, image=1) or path == urls.RESERVE.format(ou=1, image=2):
|
||||
res = copy.deepcopy(RESERVE)
|
||||
res['name'] += six.text_type(random.randint(5000, 100000))
|
||||
res['mac'] = ''.join(random.choice('0123456789ABCDEF') for __ in range(12))
|
||||
return res
|
||||
|
||||
raise Exception('Unknown FAKE URL on POST: {}'.format(path))
|
||||
|
||||
# FAKE get
|
||||
def get(path, errMsg):
|
||||
logger.info('FAKE GET request to {}. ({})'.format(path, errMsg))
|
||||
if path == urls.INFO:
|
||||
return INFO
|
||||
elif path == urls.OUS:
|
||||
return OUS
|
||||
elif path == urls.LABS.format(ou=1):
|
||||
return LABS
|
||||
elif path == urls.LABS.format(ou=2):
|
||||
return [] # Empty
|
||||
elif path == urls.IMAGES.format(ou=1):
|
||||
return IMAGES
|
||||
elif path == urls.IMAGES.format(ou=2):
|
||||
return []
|
||||
elif path[-6:] == 'status':
|
||||
rnd = random.randint(0, 100)
|
||||
if rnd < 25:
|
||||
return STATUS_READY_LINUX
|
||||
return STATUS_OFF
|
||||
|
||||
raise Exception('Unknown FAKE URL on GET: {}'.format(path))
|
||||
|
||||
def delete(path, errMsg):
|
||||
logger.info('FAKE DELETE request to {}. ({})'.format(path, errMsg))
|
||||
# Right now, only "unreserve" uses delete, so simply return
|
||||
return UNRESERVE
|
||||
# raise Exception('Unknown FAKE URL on DELETE: {}'.format(path))
|
45
server/src/uds/services/OpenGnsys/og/urls.py
Normal file
45
server/src/uds/services/OpenGnsys/og/urls.py
Normal file
@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 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
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# API URL 1: https://www.informatica.us.es/~ramon/opengnsys/?url=opengnsys-api.yml
|
||||
# API URL 2: http://opengnsys.es/wiki/ApiRest
|
||||
|
||||
LOGIN = '/login'
|
||||
INFO = '/info'
|
||||
OUS = '/ous'
|
||||
LABS = '/ous/{ou}/labs'
|
||||
IMAGES = '/ous/{ou}/images'
|
||||
RESERVE = '/ous/{ou}/images/{image}/reserve'
|
||||
UNRESERVE = '/ous/{ou}/labs/{lab}/clients/{client}/unreserve'
|
||||
STATUS = '/ous/{ou}/labs/{lab}/clients/{client}/status'
|
BIN
server/src/uds/services/OpenGnsys/provider.png
Normal file
BIN
server/src/uds/services/OpenGnsys/provider.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
@ -89,16 +89,16 @@ else: # CoRD
|
||||
url += '?screenDepth={m.r.bpp}'
|
||||
|
||||
if {m.r.fullScreen}: # @UndefinedVariable
|
||||
url += '&fullscreen=true'
|
||||
url += '&fullscreen###true'
|
||||
else:
|
||||
url += 'screenWidth={m.r.width}&screenHeight={m.r.height}'
|
||||
url += 'screenWidth###{m.r.width}&screenHeight###{m.r.height}'
|
||||
|
||||
url += '&forwardAudio=' + '01'[{m.r.redirectAudio}] # @UndefinedVariable
|
||||
url += '&forwardAudio###' + '01'[{m.r.redirectAudio}] # @UndefinedVariable
|
||||
|
||||
if {m.r.redirectDrives}: # @UndefinedVariable
|
||||
url += '&forwardDisks=true'
|
||||
url += '&forwardDisks###true'
|
||||
|
||||
if {m.r.redirectPrinters}: # @UndefinedVariable
|
||||
url += '&forwardPrinters=true'
|
||||
url += '&forwardPrinters###true'
|
||||
|
||||
tools.addTaskToWait(subprocess.Popen(['open', url]))
|
||||
|
@ -95,19 +95,19 @@ else:
|
||||
if domain != '':
|
||||
url += domain
|
||||
|
||||
url += '?screenDepth={m.r.bpp}'
|
||||
url += '?screenDepth###{m.r.bpp}'
|
||||
|
||||
if {m.r.fullScreen}: # @UndefinedVariable
|
||||
url += '&fullscreen=true'
|
||||
url += '&fullscreen###true'
|
||||
else:
|
||||
url += 'screenWidth={m.r.width}&screenHeight={m.r.height}'
|
||||
url += 'screenWidth###{m.r.width}&screenHeight###{m.r.height}'
|
||||
|
||||
url += '&forwardAudio=' + '01'[{m.r.redirectAudio}] # @UndefinedVariable
|
||||
# url += '&forwardAudio###' + '01'[{m.r.redirectAudio}] # @UndefinedVariable
|
||||
|
||||
if {m.r.redirectDrives}: # @UndefinedVariable
|
||||
url += '&forwardDisks=true'
|
||||
url += '&forwardDisks###true'
|
||||
|
||||
if {m.r.redirectPrinters}: # @UndefinedVariable
|
||||
url += '&forwardPrinters=true'
|
||||
url += '&forwardPrinters###true'
|
||||
|
||||
tools.addTaskToWait(subprocess.Popen(['open', url]))
|
||||
|
Loading…
x
Reference in New Issue
Block a user