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:
parent
bec74ddc99
commit
cc6ba2ff41
@ -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,63 +132,155 @@ class UDSOpenStackClient(object):
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
def authPassword(self):
|
||||
data = {
|
||||
'auth': {
|
||||
'passwordCredentials': {
|
||||
'username': self._username,
|
||||
'password': self._password
|
||||
|
||||
'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',
|
||||
data=json.dumps(data),
|
||||
headers={'content-type': 'application/json'},
|
||||
verify=False,
|
||||
timeout=self._timeout)
|
||||
r = requests.post(self._authUrl + 'v3/auth/tokens',
|
||||
data=json.dumps(data),
|
||||
headers={'content-type': 'application/json'},
|
||||
verify=False,
|
||||
timeout=self._timeout)
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user