forked from shaba/openuds
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
16f05920b5 | ||
|
98befc7cee |
@ -38,18 +38,16 @@ from uds.core.util.Cache import Cache
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
import dateutil.parser
|
||||
# import dateutil.parser
|
||||
import hashlib
|
||||
import six
|
||||
|
||||
|
||||
__updated__ = '2017-03-21'
|
||||
__updated__ = '2018-03-01'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Required: Authentication v3
|
||||
|
||||
|
||||
# This is a vary basic implementation for what we need from openstack
|
||||
# This does not includes (nor it is intention) full API implementation, just the parts we need
|
||||
# Theese are related to auth, compute & network basically
|
||||
@ -60,9 +58,17 @@ logger = logging.getLogger(__name__)
|
||||
# Do not verify SSL conections right now
|
||||
VERIFY_SSL = False
|
||||
|
||||
|
||||
class AuthenticationRequiredException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# Helpers
|
||||
def ensureResponseIsValid(response, errMsg=None):
|
||||
if response.ok is False:
|
||||
if response.status_code == 401:
|
||||
raise AuthenticationRequiredException('Authentication required')
|
||||
|
||||
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)
|
||||
@ -70,7 +76,7 @@ def ensureResponseIsValid(response, errMsg=None):
|
||||
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))
|
||||
logger.error('{}: {} ({})'.format(errMsg, response.content, response.status_code))
|
||||
raise Exception(errMsg)
|
||||
|
||||
|
||||
@ -96,22 +102,42 @@ def getRecurringUrlJson(url, headers, key, params=None, errMsg=None, timeout=10)
|
||||
|
||||
# Decorators
|
||||
def authRequired(func):
|
||||
|
||||
def ensurer(obj, *args, **kwargs):
|
||||
obj.ensureAuthenticated()
|
||||
try:
|
||||
return func(obj, *args, **kwargs)
|
||||
except AuthenticationRequiredException:
|
||||
# Retry funcion with a re-auth
|
||||
obj._cleanCache()
|
||||
obj.authPassword()
|
||||
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):
|
||||
|
||||
def ensurer(obj, *args, **kwargs):
|
||||
if obj._projectId is None:
|
||||
raise Exception('Need a project for method {}'.format(func))
|
||||
obj.ensureAuthenticated()
|
||||
return func(obj, *args, **kwargs)
|
||||
try:
|
||||
return func(obj, *args, **kwargs)
|
||||
except AuthenticationRequiredException:
|
||||
# Retry funcion with a re-auth
|
||||
obj._cleanCache()
|
||||
obj.authPassword()
|
||||
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
|
||||
|
||||
|
||||
@ -237,22 +263,20 @@ class Client(object):
|
||||
# Extract the token id
|
||||
token = r.json()['token']
|
||||
self._userId = token['user']['id']
|
||||
validity = (dateutil.parser.parse(token['expires_at']).replace(tzinfo=None) - dateutil.parser.parse(token['issued_at']).replace(tzinfo=None)).seconds - 60
|
||||
|
||||
|
||||
logger.debug('The token {} will be valid for {}'.format(self._tokenId, validity))
|
||||
# validity = (dateutil.parser.parse(token['expires_at']).replace(tzinfo=None) - dateutil.parser.parse(token['issued_at']).replace(tzinfo=None)).seconds - 60
|
||||
# logger.debug('The token {} will be valid for {}'.format(self._tokenId, validity))
|
||||
|
||||
# Now, if endpoints are present (only if tenant was specified), store & cache them
|
||||
if self._projectId is not None:
|
||||
self._catalog = token['catalog']
|
||||
|
||||
self._saveToCache(validity)
|
||||
self._saveToCache(300) # Store credentials 300 seconds
|
||||
|
||||
def ensureAuthenticated(self):
|
||||
if self._authenticated is False:
|
||||
self.authPassword()
|
||||
|
||||
|
||||
@authRequired
|
||||
def listProjects(self):
|
||||
return getRecurringUrlJson(self._authUrl + 'v3/users/{user_id}/projects'.format(user_id=self._userId),
|
||||
@ -261,7 +285,6 @@ class Client(object):
|
||||
errMsg='List Projects',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authRequired
|
||||
def listRegions(self):
|
||||
return getRecurringUrlJson(self._authUrl + 'v3/regions/',
|
||||
@ -270,7 +293,6 @@ class Client(object):
|
||||
errMsg='List Regions',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listServers(self, detail=False, params=None):
|
||||
path = '/servers/' + 'detail' if detail is True else ''
|
||||
@ -281,7 +303,6 @@ class Client(object):
|
||||
errMsg='List Vms',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listImages(self):
|
||||
return getRecurringUrlJson(self._getEndpointFor('image') + '/v2/images?status=active',
|
||||
@ -290,7 +311,6 @@ class Client(object):
|
||||
errMsg='List Images',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeTypes(self):
|
||||
return getRecurringUrlJson(self._getEndpointFor('volumev2') + '/types',
|
||||
@ -299,7 +319,6 @@ class Client(object):
|
||||
errMsg='List Volume Types',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumes(self):
|
||||
# self._getEndpointFor('volumev2') + '/volumes'
|
||||
@ -309,7 +328,6 @@ class Client(object):
|
||||
errMsg='List Volumes',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeSnapshots(self, volumeId=None):
|
||||
for s in getRecurringUrlJson(self._getEndpointFor('volumev2') + '/snapshots',
|
||||
@ -320,7 +338,6 @@ class Client(object):
|
||||
if volumeId is None or s['volume_id'] == volumeId:
|
||||
yield s
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listAvailabilityZones(self):
|
||||
for az in getRecurringUrlJson(self._getEndpointFor('compute') + '/os-availability-zone',
|
||||
@ -331,7 +348,6 @@ class Client(object):
|
||||
if az['zoneState']['available'] is True:
|
||||
yield az['zoneName']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listFlavors(self):
|
||||
return getRecurringUrlJson(self._getEndpointFor('compute') + '/flavors',
|
||||
@ -340,7 +356,6 @@ class Client(object):
|
||||
errMsg='List Flavors',
|
||||
timeout=self._timeout)
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listNetworks(self):
|
||||
return getRecurringUrlJson(self._getEndpointFor('network') + '/v2.0/networks',
|
||||
@ -372,7 +387,6 @@ class Client(object):
|
||||
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),
|
||||
@ -396,7 +410,6 @@ class Client(object):
|
||||
|
||||
return v
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def getSnapshot(self, snapshotId):
|
||||
'''
|
||||
@ -414,7 +427,6 @@ class Client(object):
|
||||
|
||||
return v
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def updateSnapshot(self, snapshotId, name=None, description=None):
|
||||
data = { 'snapshot': {} }
|
||||
@ -436,7 +448,6 @@ class Client(object):
|
||||
|
||||
return v
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeSnapshot(self, volumeId, name, description=None):
|
||||
description = 'UDS Snapshot' if description is None else description
|
||||
@ -461,7 +472,6 @@ class Client(object):
|
||||
|
||||
return r.json()['snapshot']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeFromSnapshot(self, snapshotId, name, description=None):
|
||||
description = 'UDS Volume' if description is None else description
|
||||
@ -520,7 +530,6 @@ class Client(object):
|
||||
|
||||
return r.json()['server']
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def deleteServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
@ -533,7 +542,6 @@ class Client(object):
|
||||
|
||||
# This does not returns anything
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def deleteSnapshot(self, snapshotId):
|
||||
r = requests.delete(self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
@ -545,7 +553,6 @@ class Client(object):
|
||||
|
||||
# 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),
|
||||
@ -558,7 +565,6 @@ class Client(object):
|
||||
|
||||
# This does not returns anything
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def stopServer(self, serverId):
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
@ -589,7 +595,6 @@ class Client(object):
|
||||
|
||||
ensureResponseIsValid(r, 'Resuming server')
|
||||
|
||||
|
||||
def testConnection(self):
|
||||
# First, ensure requested api is supported
|
||||
# We need api version 3.2 or greater
|
||||
|
Loading…
Reference in New Issue
Block a user