1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

Updated to start with identity api v3 instead of v2, and advanced a lot

This commit is contained in:
Adolfo Gómez García 2016-03-03 20:25:12 +01:00
parent bec74ddc99
commit cc6ba2ff41

View File

@ -48,6 +48,9 @@ __updated__ = '2016-03-03'
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
@ -57,13 +60,31 @@ logger = logging.getLogger(__name__)
# Helpers
def ensureResponseIsValid(response, errMsg=None):
if response.reason != 'OK':
if response.ok is False:
if errMsg is None:
errMsg = 'Error checking response'
logger.error('{}: {}'.format(errMsg, response.content))
print response.content
print response
raise Exception(errMsg)
# Decorators
def authRequired(func):
def ensurer(obj, *args, **kwargs):
obj.ensureAuthenticated()
return func(obj, *args, **kwargs)
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)
return ensurer
class UDSOpenStackClient(object):
cache = Cache('uds-openstack')
@ -71,16 +92,18 @@ class UDSOpenStackClient(object):
PRIVATE = 'private'
INTERNAL = 'url'
def __init__(self, host, port, username, password, useSSL=False, tenant=None, access=None):
def __init__(self, host, port, domain, username, password, useSSL=False, projectId=None, region=None, access=None):
self._authenticated = False
self._tokenId = None
self._serviceCatalog = None
self._catalog = None
self._access = UDSOpenStackClient.PUBLIC if access is None else access
self._host, self._port = host, int(port)
self._username, self._password = username, password
self._tenant = tenant
self._tenantId = None
self._domain, self._username, self._password = domain, username, password
self._userId = None
self._projectId = projectId
self._project = None
self._region = region
self._timeout = 10
self._authUrl = 'http{}://{}:{}/'.format('s' if useSSL else '', host, port)
@ -95,12 +118,12 @@ class UDSOpenStackClient(object):
# self._cacheKey = h.hexdigest()
def _getEndpointFor(self, type_, region=None): # If no region is indicatad, first endpoint is returned
for i in self._serviceCatalog:
def _getEndpointFor(self, type_): # If no region is indicatad, first endpoint is returned
for i in self._catalog:
if i['type'] == type_:
for j in i['endpoints']:
if region is None or j['region'] == region:
return j[self._access + 'URL']
if j['interface'] == self._access and (self._region is None or j['region'] == self._region):
return j['url']
def _requestHeaders(self):
headers = {'content-type': 'application/json'}
@ -109,22 +132,36 @@ class UDSOpenStackClient(object):
return headers
def authPassword(self):
data = {
'auth': {
'passwordCredentials': {
'username': self._username,
'identity': {
'methods': [
'password'
],
'password': {
'user': {
'name': self._username,
'domain': {
'name': 'Default' if self._domain is None else self._domain
},
'password': self._password
}
}
}
}
}
if self._tenant is not None:
data['auth']['tenantName'] = self._tenant
if self._projectId is None:
data['auth']['scope'] = 'unscoped'
else:
data['auth']['scope'] = {
'project': {
'id': self._projectId
}
}
r = requests.post(self._authUrl + 'v2.0/tokens',
r = requests.post(self._authUrl + 'v3/auth/tokens',
data=json.dumps(data),
headers={'content-type': 'application/json'},
verify=False,
@ -132,40 +169,118 @@ class UDSOpenStackClient(object):
ensureResponseIsValid(r, 'Invalid Credentials')
self._authtenticated = True
self._authenticated = True
self._tokenId = r.headers['X-Subject-Token']
# Extract the token id
r = json.loads(r.content)
token = r['access']['token']
self._tokenId = token['id']
validity = (dateutil.parser.parse(token['expires']).replace(tzinfo=None) - dateutil.parser.parse(token['issued_at']).replace(tzinfo=None)).seconds - 60
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))
# Now, if endpoints are present (only if tenant was specified), store & cache them
if self._tenant is not None:
self._serviceCatalog = r['access']['serviceCatalog']
print self._serviceCatalog
if self._projectId is not None:
self._catalog = token['catalog']
def ensureAuthenticated(self):
if self._authenticated is False:
self.authPassword()
def listTenants(self):
self.ensureAuthenticated()
r = requests.get(self._authUrl + 'v2.0/tenants/',
@authRequired
def listProjects(self):
r = requests.get(self._authUrl + 'v3/users/{user_id}/projects'.format(user_id=self._userId),
headers=self._requestHeaders())
ensureResponseIsValid(r, 'List Tenants')
return json.loads(r.content)['tenants']
for p in json.loads(r.content)['projects']:
yield p
@authRequired
def listRegions(self):
self.ensureAuthenticated()
r = requests.get(self._authUrl + 'v3/regions/',
headers=self._requestHeaders())
ensureResponseIsValid(r, 'List Regions')
return json.loads(r.content)['regions']
for r in json.loads(r.content)['regions']:
yield r
@authProjectRequired
def listVms(self):
url = self._getEndpointFor('compute') + '/servers'
while True:
r = requests.get(url, headers=self._requestHeaders())
ensureResponseIsValid(r, 'List Vms')
json = r.json()
for v in json['servers']:
yield { 'name': v['name'], 'id': v['id'] }
if 'next' not in json:
break
url = json['next']
@authProjectRequired
def listImages(self):
url = self._getEndpointFor('image') + '/v2/images?status=active'
while True:
r = requests.get(url, headers=self._requestHeaders())
ensureResponseIsValid(r, 'List Images')
json = r.json()
for i in json['images']:
yield { 'name': i['name'], 'size': i['size'], 'visibility': i['visibility'], 'format': i['disk_format'] }
if 'next' not in json:
break
url = json['next']
@authProjectRequired
def listVolumes(self):
url = self._getEndpointFor('volumev2') + '/volumes'
while True:
r = requests.get(url, headers=self._requestHeaders())
ensureResponseIsValid(r, 'List Volumes')
json = r.json()
for i in json['volumes']:
yield { 'id': i['id'], 'name': i['name'] }
if 'next' not in json:
break
url = json['next']
def testConection(self):
# First, ensure requested api is supported
# We need api version 3.2 or greater
r = requests.get(self._authUrl,
headers=self._requestHeaders())
for v in r.json()['versions']['values']:
if v['id'] >= 'v3.2':
# Tries to authenticate
try:
self.authPassword()
return True
except Exception:
return False
return False