1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-03-28 10:50:25 +03:00

Updated OpenStack client & added caching features

Added counters to Cache (maybe somtime will store them on db to keep track on performance
This commit is contained in:
Adolfo Gómez García 2016-03-08 12:36:42 +01:00
parent 9f4ef20dc1
commit 608c1317d7
4 changed files with 92 additions and 25 deletions

View File

@ -43,11 +43,15 @@ logger = logging.getLogger(__name__)
class Cache(object):
hits = 0
misses = 0
DEFAULT_VALIDITY = 60
CODEC = 'base64' # Can be zip, hez, bzip, base64, uuencoded
def __init__(self, owner):
self._owner = owner.encode('utf-8')
# Simple hits vs missses counters
def __getKey(self, key):
h = hashlib.md5()
@ -64,8 +68,10 @@ class Cache(object):
if expired:
return defValue
val = pickle.loads(c.value.decode(Cache.CODEC))
Cache.hits += 1
return val
except uds.models.Cache.DoesNotExist: # @UndefinedVariable
Cache.misses += 1
logger.debug('key not found: {}'.format(skey))
return defValue

View File

@ -42,7 +42,7 @@ from uds.core.ui import gui
import six
import logging
__updated__ = '2016-03-07'
__updated__ = '2016-03-08'
logger = logging.getLogger(__name__)
@ -96,22 +96,29 @@ class LiveService(Service):
servicesTypeProvided = (serviceTypes.VDI,)
# Now the form part
region = gui.ChoiceField(label=_("Region"), order=1, tooltip=_('Service region'), required=True)
project = gui.ChoiceField(label=_("Project"), order=2,
region = gui.ChoiceField(label=_('Region'), order=1, tooltip=_('Service region'), required=True, rdonly=True)
project = gui.ChoiceField(label=_('Project'), order=2,
fills={
'callbackName' : 'osFillResources',
'function' : helpers.getResources,
'parameters' : ['ov', 'ev', 'project', 'region']
},
tooltip=_('Project for this service'), required=True
tooltip=_('Project for this service'), required=True, rdonly=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)
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)
availabilityZone = gui.ChoiceField(label=_('Availability Zones'), order=3,
fills={
'callbackName' : 'osFillVolumees',
'function' : helpers.getVolumes,
'parameters' : ['ov', 'ev', 'project', 'region', 'availabilityZone']
},
tooltip=_('Service availability zones'), required=True, rdonly=True
)
volume = gui.ChoiceField(label=_('Volume'), order=4, tooltip=_('Base volume for service (restricted by availability zone)'), required=True)
# volumeType = gui.ChoiceField(label=_('Volume Type'), order=5, tooltip=_('Volume type for 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)
securityGroups = gui.MultiChoiceField(label=_('Security Groups'), order=8, tooltip=_('Service security groups'), required=True)
baseName = gui.TextField(
label=_('Machine Names'),

View File

@ -29,7 +29,6 @@ def getResources(parameters):
api = provider.api(parameters['project'], parameters['region'])
zones = [gui.choiceItem(z, z) for z in api.listAvailabilityZones()]
volumes = [gui.choiceItem(v['id'], v['name']) for v in api.listVolumes() if v['name'] != '']
networks = [gui.choiceItem(z['id'], z['name']) for z in api.listNetworks()]
flavors = [gui.choiceItem(z['id'], z['name']) for z in api.listFlavors()]
securityGroups = [gui.choiceItem(z['id'], z['name']) for z in api.listSecurityGroups()]
@ -37,17 +36,31 @@ def getResources(parameters):
data = [
{'name': 'availabilityZone', 'values': zones },
{'name': 'volume', 'values': volumes },
{'name': 'network', 'values': networks },
{'name': 'flavor', 'values': flavors },
{'name': 'securityGroups', 'values': securityGroups },
{'name': 'volumeType', 'values': volumeTypes },
]
logger.debug('Return data: {}'.format(data))
return data
def getVolumes(parameters):
'''
This helper is designed as a callback for Zone Selector
'''
from .Provider import Provider
from uds.core.Environment import Environment
logger.debug('Parameters received by getVolumes Helper: {0}'.format(parameters))
env = Environment(parameters['ev'])
provider = Provider(env)
provider.unserialize(parameters['ov'])
api = provider.api(parameters['project'], parameters['region'])
volumes = [gui.choiceItem(v['id'], v['name']) for v in api.listVolumes() if v['name'] != '' and v['availability_zone'] == parameters['availabilityZone']]
data = [
{'name': 'volume', 'values': volumes },
]
logger.debug('Return data: {}'.format(data))
return data

View File

@ -30,7 +30,7 @@
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=maybe-no-member
# pylint: disable=maybe-no-member,protected-access
from django.utils.translation import ugettext as _
from uds.core.util.Cache import Cache
@ -39,9 +39,11 @@ import logging
import requests
import json
import dateutil.parser
import hashlib
import six
__updated__ = '2016-03-07'
__updated__ = '2016-03-08'
logger = logging.getLogger(__name__)
@ -97,7 +99,12 @@ def getRecurringUrlJson(url, headers, key, params=None, errMsg=None, timeout=10)
def authRequired(func):
def ensurer(obj, *args, **kwargs):
obj.ensureAuthenticated()
return func(obj, *args, **kwargs)
try:
return func(obj, *args, **kwargs)
except Exception as e:
logger.error('Got error {} for openstack'.format(e))
obj._cleanCache() # On any request error, force next time auth
raise
return ensurer
def authProjectRequired(func):
@ -133,14 +140,16 @@ class Client(object):
self._authUrl = 'http{}://{}:{}/'.format('s' if useSSL else '', host, port)
# Generates a hash for auth + credentials
# h = hashlib.md5()
# h.update(six.binary_type(username))
# h.update(six.binary_type(password))
# h.update(six.binary_type(host))
# h.update(six.binary_type(port))
# h.update(six.binary_type(tenant))
# self._cacheKey = h.hexdigest()
h = hashlib.md5()
h.update(six.binary_type(host))
h.update(six.binary_type(port))
h.update(six.binary_type(domain))
h.update(six.binary_type(username))
h.update(six.binary_type(password))
h.update(six.binary_type(useSSL))
h.update(six.binary_type(projectId))
h.update(six.binary_type(region))
self._cacheKey = h.hexdigest()
def _getEndpointFor(self, type_): # If no region is indicatad, first endpoint is returned
for i in self._catalog:
@ -156,7 +165,38 @@ class Client(object):
return headers
def _getFromCache(self):
cached = self.cache.get(self._cacheKey)
if cached is not None:
self._authenticated = True
self._tokenId = cached['tokenId']
# Extract the token id
self._userId = cached['userId']
self._projectId = cached['projectId']
self._catalog = cached['catalog']
return True
return False
def _saveToCache(self, validity=600):
self.cache.put(self._cacheKey,
{
'tokenId': self._tokenId,
'userId': self._userId,
'projectId': self._projectId,
'catalog': self._catalog
},
validity - 60) # We substract some seconds to allow some time desynchronization
def _clearCache(self):
self.cache.remove(self._cacheKey)
def authPassword(self):
# If cached data exists, use it as auth
if self._getFromCache() is True:
return
data = {
'auth': {
'identity': {
@ -207,6 +247,7 @@ class Client(object):
if self._projectId is not None:
self._catalog = token['catalog']
self._saveToCache(validity)
def ensureAuthenticated(self):
if self._authenticated is False: