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:
parent
9f4ef20dc1
commit
608c1317d7
@ -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
|
||||
|
||||
|
@ -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'),
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user