Remove Keystone V2 API support
removing keystone v2.0 api because is no longer supported Closes-Bug: #1614892 Change-Id: Iaeabc663990168e2d6959d8fb629234ca02128d1
This commit is contained in:
parent
2c26125421
commit
95c0d43f19
@ -22,7 +22,6 @@ import threading
|
||||
import requests
|
||||
import six
|
||||
|
||||
from collectd_ceilometer.common.keystone_light import ClientV2
|
||||
from collectd_ceilometer.common.keystone_light import ClientV3
|
||||
from collectd_ceilometer.common.keystone_light import KeystoneException
|
||||
from collectd_ceilometer.common.settings import Config
|
||||
@ -78,20 +77,12 @@ class Sender(object):
|
||||
# create a keystone client if it doesn't exist
|
||||
if self._keystone is None:
|
||||
cfg = Config.instance()
|
||||
if cfg.OS_IDENTITY_API_VERSION == "2.0":
|
||||
self._keystone = ClientV2(
|
||||
auth_url=cfg.OS_AUTH_URL,
|
||||
username=cfg.OS_USERNAME,
|
||||
password=cfg.OS_PASSWORD,
|
||||
tenant_name=cfg.OS_TENANT_NAME
|
||||
)
|
||||
else:
|
||||
self._keystone = ClientV3(
|
||||
auth_url=cfg.OS_AUTH_URL,
|
||||
username=cfg.OS_USERNAME,
|
||||
password=cfg.OS_PASSWORD,
|
||||
tenant_name=cfg.OS_TENANT_NAME
|
||||
)
|
||||
self._keystone = ClientV3(
|
||||
auth_url=cfg.OS_AUTH_URL,
|
||||
username=cfg.OS_USERNAME,
|
||||
password=cfg.OS_PASSWORD,
|
||||
tenant_name=cfg.OS_TENANT_NAME
|
||||
)
|
||||
# store the authentication token
|
||||
self._auth_token = self._keystone.auth_token
|
||||
|
||||
|
@ -145,114 +145,6 @@ class ClientV3(object):
|
||||
e, self._services)
|
||||
|
||||
|
||||
class ClientV2(object):
|
||||
"""Light weight client for the OpenStack Identity API V2.
|
||||
|
||||
:param string username: Username for authentication. (optional)
|
||||
:param string password: Password for authentication.
|
||||
:param string tenant_name: Tenant name. (optional)
|
||||
:param string auth_url: Keystone service endpoint for authorization.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, auth_url, username, password, tenant_name):
|
||||
"""Initialize a new client"""
|
||||
|
||||
self.auth_url = auth_url
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.tenant_name = tenant_name
|
||||
self._auth_token = None
|
||||
self._services = None
|
||||
|
||||
@property
|
||||
def auth_token(self):
|
||||
"""Return token string usable for X-Auth-Token """
|
||||
# actualize token
|
||||
self.refresh()
|
||||
return self._auth_token
|
||||
|
||||
@property
|
||||
def services(self):
|
||||
"""Return list of services retrieved from identity server """
|
||||
return self._services
|
||||
|
||||
def _get_auth_data(self, headers=None):
|
||||
"""Prepare auth data for request """
|
||||
|
||||
auth = {'password': self.password}
|
||||
|
||||
if self.username:
|
||||
auth['username'] = self.username
|
||||
|
||||
return {'passwordCredentials': auth}
|
||||
|
||||
def _request_identity_data(self):
|
||||
"""Will send (POST) and retrieve data from identity server """
|
||||
|
||||
headers = {'Accept': 'application/json'}
|
||||
url = self.auth_url.rstrip('/') + '/tokens'
|
||||
params = {'auth': self._get_auth_data(headers)}
|
||||
|
||||
if self.tenant_name:
|
||||
params['auth']['tenantName'] = self.tenant_name
|
||||
|
||||
resp = requests.post(url, json=params, headers=headers)
|
||||
try:
|
||||
resp.raise_for_status()
|
||||
resp_data = resp.json()['access']
|
||||
except (KeyError, ValueError, requests.exceptions.HTTPError) as e:
|
||||
raise InvalidResponse(e, resp)
|
||||
|
||||
return resp_data
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh token and services list (getting it from identity server) """
|
||||
resp_data = self._request_identity_data()
|
||||
|
||||
try:
|
||||
self._services = resp_data['serviceCatalog']
|
||||
token = resp_data['token']
|
||||
|
||||
self._auth_token = token['id']
|
||||
except (TypeError, KeyError, ValueError) as e:
|
||||
raise InvalidResponse(e, resp_data)
|
||||
|
||||
return resp_data
|
||||
|
||||
def get_service_endpoint(self, name, urlkey="internalURL", region=None):
|
||||
"""Return url endpoint of service
|
||||
|
||||
possible values of urlkey = 'adminURL' | 'publicURL' | 'internalURL'
|
||||
provide region if more endpoints are available
|
||||
"""
|
||||
endpoints = None
|
||||
|
||||
try:
|
||||
for service in self._services:
|
||||
if service['name'] == name:
|
||||
endpoints = service['endpoints']
|
||||
break
|
||||
|
||||
if not endpoints:
|
||||
raise MissingServices("Missing name '%s' in received services"
|
||||
% name,
|
||||
None, self._services)
|
||||
|
||||
# preselect default
|
||||
endpoint = endpoints[0]
|
||||
|
||||
if region:
|
||||
for ep in endpoints:
|
||||
if ep['region'] == region:
|
||||
endpoint = ep
|
||||
break
|
||||
|
||||
return endpoint[urlkey].rstrip('/')
|
||||
except (KeyError, ValueError) as e:
|
||||
raise MissingServices("Missing data in received services",
|
||||
e, self._services)
|
||||
|
||||
"""
|
||||
Example of response (part only)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collectd_ceilometer import keystone_light
|
||||
from collectd_ceilometer.keystone_light import ClientV2
|
||||
from collectd_ceilometer.keystone_light import ClientV3
|
||||
from collectd_ceilometer.keystone_light import MissingServices
|
||||
import mock
|
||||
@ -350,200 +349,3 @@ class KeystoneLightTestV3(unittest.TestCase):
|
||||
|
||||
with self.assertRaises(keystone_light.InvalidResponse):
|
||||
client.refresh()
|
||||
|
||||
|
||||
class KeystoneLightTestV2(unittest.TestCase):
|
||||
"""Test the keystone light client with 2.0 keystone api"""
|
||||
|
||||
def setUp(self):
|
||||
super(KeystoneLightTestV2, self).setUp()
|
||||
|
||||
self.test_authtoken = "c5bbb1c9a27e470fb482de2a718e08c2"
|
||||
self.test_public_endpoint = "http://public_endpoint"
|
||||
self.test_internal_endpoint = "http://iternal_endpoint"
|
||||
self.test_region = "RegionOne"
|
||||
|
||||
response = {'access': {
|
||||
"token": {
|
||||
"issued_at": "2015-09-04T08:59:09.991646",
|
||||
"expires": "2015-09-04T09:59:09Z",
|
||||
"id": self.test_authtoken,
|
||||
"tenant": {
|
||||
"enabled": True,
|
||||
"description": None,
|
||||
"name": "service",
|
||||
"id": "fdeec62f6c794c8dbfda448a83de9ce2"
|
||||
},
|
||||
"audit_ids": [
|
||||
"Pig7hVfGQjSuUnt1Hc5mCg"
|
||||
]
|
||||
},
|
||||
"serviceCatalog": [{
|
||||
"endpoints_links": [],
|
||||
"endpoints": [{
|
||||
"adminURL": "http://10.237.214.74:8777/",
|
||||
"region": self.test_region,
|
||||
"publicURL": self.test_public_endpoint + '/',
|
||||
"internalURL": self.test_internal_endpoint,
|
||||
"id": "ac95b1a24a854ec7a4b63b08ed4cbd83"
|
||||
}],
|
||||
"type": "metering",
|
||||
"name": "ceilometer"
|
||||
}, ],
|
||||
}}
|
||||
|
||||
self.mock_response = mock.Mock()
|
||||
self.mock_response.json.return_value = response
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_refresh(self, mock_post):
|
||||
"""Test refresh"""
|
||||
|
||||
mock_post.return_value = self.mock_response
|
||||
|
||||
client = ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
client.refresh()
|
||||
|
||||
self.assertEqual(mock_post.call_count, 1)
|
||||
self.assertEqual(client.auth_token, self.test_authtoken)
|
||||
|
||||
expected_args = {
|
||||
'headers': {'Accept': 'application/json'},
|
||||
'json': {
|
||||
'auth': {
|
||||
'tenantName': u'test_tenant',
|
||||
'passwordCredentials': {
|
||||
'username': u'test_username',
|
||||
'password': u'test_password'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(mock_post.call_args[0], (u'test_auth_url/tokens',))
|
||||
self.assertEqual(mock_post.call_args[1], expected_args)
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_getservice_endpoint(self, mock_post):
|
||||
"""Test getservice endpoint"""
|
||||
|
||||
mock_post.return_value = self.mock_response
|
||||
|
||||
client = ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
client.refresh()
|
||||
|
||||
endpoint = client.get_service_endpoint('ceilometer')
|
||||
self.assertEqual(endpoint, self.test_internal_endpoint)
|
||||
|
||||
endpoint = client.get_service_endpoint('ceilometer', 'publicURL')
|
||||
self.assertEqual(endpoint, self.test_public_endpoint)
|
||||
|
||||
endpoint = client.get_service_endpoint('ceilometer', 'publicURL',
|
||||
self.test_region)
|
||||
self.assertEqual(endpoint, self.test_public_endpoint)
|
||||
|
||||
with self.assertRaises(MissingServices):
|
||||
client.get_service_endpoint('badname')
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_getservice_endpoint_error(self, mock_post):
|
||||
"""Test getservice endpoint error"""
|
||||
|
||||
response = {'access': {
|
||||
"token": {
|
||||
"id": "authtoken",
|
||||
},
|
||||
"serviceCatalog": [{
|
||||
"endpoints_links": [],
|
||||
"endpoints": [],
|
||||
"type": "metering",
|
||||
"missingname": "ceilometer"
|
||||
},
|
||||
],
|
||||
}}
|
||||
|
||||
self.mock_response = mock.Mock()
|
||||
self.mock_response.json.return_value = response
|
||||
|
||||
mock_post.return_value = self.mock_response
|
||||
|
||||
client = ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
client.refresh()
|
||||
|
||||
with self.assertRaises(MissingServices):
|
||||
client.get_service_endpoint('ceilometer')
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_invalidresponse_missing_access(self, mock_post):
|
||||
"""Test invalid response: missing access"""
|
||||
|
||||
response = {'badresponse': None}
|
||||
|
||||
mock_response = mock.Mock()
|
||||
mock_response.json.return_value = response
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
client = keystone_light.ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
|
||||
with self.assertRaises(keystone_light.InvalidResponse):
|
||||
client.refresh()
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_invalidresponse_missing_servicecatalog(self, mock_post):
|
||||
"""Test invalid response: missing servicecatalog"""
|
||||
|
||||
response = {'access': {
|
||||
'token': None
|
||||
}
|
||||
}
|
||||
|
||||
mock_response = mock.Mock()
|
||||
mock_response.json.return_value = response
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
client = keystone_light.ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
|
||||
with self.assertRaises(keystone_light.InvalidResponse):
|
||||
client.refresh()
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_invalidresponse_missing_token(self, mock_post):
|
||||
"""Test invalid response: missing token"""
|
||||
|
||||
response = {'access': {
|
||||
"serviceCatalog": []
|
||||
}}
|
||||
|
||||
mock_response = mock.Mock()
|
||||
mock_response.json.return_value = response
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
client = keystone_light.ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
|
||||
with self.assertRaises(keystone_light.InvalidResponse):
|
||||
client.refresh()
|
||||
|
||||
@mock.patch('collectd_ceilometer.common.keystone_light.requests.post')
|
||||
def test_invalidresponse_missing_id(self, mock_post):
|
||||
"""Test invalid response: missing id"""
|
||||
|
||||
response = {'access': {
|
||||
"serviceCatalog": [],
|
||||
"token": None
|
||||
}, }
|
||||
|
||||
mock_response = mock.Mock()
|
||||
mock_response.json.return_value = response
|
||||
mock_post.return_value = mock_response
|
||||
|
||||
client = keystone_light.ClientV2("test_auth_url", "test_username",
|
||||
"test_password", "test_tenant")
|
||||
|
||||
with self.assertRaises(keystone_light.InvalidResponse):
|
||||
client.refresh()
|
||||
|
@ -59,3 +59,26 @@ COLLECTD_LOG_LEVEL
|
||||
(debug|info|notice|warning|err) All log messages with lower log level than
|
||||
this are going to be filtered out from the log file.
|
||||
Default: info
|
||||
|
||||
Authenticating using Identity Server API v3
|
||||
===========================================
|
||||
|
||||
following environment variables are used in this plugin for authentication
|
||||
to Keystone API v3
|
||||
|
||||
OS_IDENTITY_API_VERSION
|
||||
specifies version of keystone API used, should be set to 3 as 2.0 is
|
||||
deprecated.
|
||||
Default: 3
|
||||
|
||||
OS_AUTH_URL
|
||||
url where keystone is listening
|
||||
Default: based on $KEYSTONE_AUTH_URI/v$IDENTITY_API_VERSION
|
||||
|
||||
OS_PASSWORD
|
||||
password for service tenant used for keystone authentication
|
||||
Default: based on $SERVICE_PASSWORD
|
||||
|
||||
OS_TENANT_NAME
|
||||
name of service tenant used for keystone authentication
|
||||
Default: based on $SERVICE_TENANT_NAME
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Added support for Keystone V3 API.
|
||||
upgrade:
|
||||
- Removed Keystone V2 support.
|
Loading…
x
Reference in New Issue
Block a user