Merge "Add keystone endpoint resource methods"

This commit is contained in:
Jenkins 2015-06-04 01:46:24 +00:00 committed by Gerrit Code Review
commit c4c196132b
5 changed files with 422 additions and 0 deletions

View File

@ -2840,3 +2840,115 @@ class OperatorCloud(OpenStackCloud):
"Failed to delete service {id}".format(id=service['id']),
exc_info=True)
raise OpenStackCloudException(str(e))
def create_endpoint(self, service_name_or_id, public_url,
internal_url=None, admin_url=None, region=None):
"""Create a Keystone endpoint.
:param service_name_or_id: Service name or id for this endpoint.
:param public_url: Endpoint public URL.
:param internal_url: Endpoint internal URL.
:param admin_url: Endpoint admin URL.
:param region: Endpoint region.
:returns: a dict containing the endpoint description.
:raise OpenStackCloudException: if the service cannot be found or if
something goes wrong during the openstack API call.
"""
# ToDo: support v3 api (dguerri)
service = self.get_service(name_or_id=service_name_or_id)
if service is None:
raise OpenStackCloudException("service {service} not found".format(
service=service_name_or_id))
try:
endpoint = self.manager.submitTask(_tasks.EndpointCreate(
service_id=service['id'],
region=region,
publicurl=public_url,
internalurl=internal_url,
adminurl=admin_url
))
except Exception as e:
self.log.debug(
"Failed to create endpoint for service {service}".format(
service=service['name'], exc_info=True))
raise OpenStackCloudException(str(e))
return meta.obj_to_dict(endpoint)
def list_endpoints(self):
"""List Keystone endpoints.
:returns: a list of dict containing the endpoint description.
:raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call.
"""
# ToDo: support v3 api (dguerri)
try:
endpoints = self.manager.submitTask(_tasks.EndpointList())
except Exception as e:
self.log.debug("Failed to list endpoints", exc_info=True)
raise OpenStackCloudException(str(e))
return meta.obj_list_to_dict(endpoints)
def search_endpoints(self, id=None, filters=None):
"""List Keystone endpoints.
:param id: endpoint id.
:param filters: a dict containing additional filters to use. e.g.
{'region': 'region-a.geo-1'}
:returns: a list of dict containing the endpoint description. Each dict
contains the following attributes::
- id: <endpoint id>
- region: <endpoint region>
- public_url: <endpoint public url>
- internal_url: <endpoint internal url> (optional)
- admin_url: <endpoint admin url> (optional)
:raises: ``OpenStackCloudException``: if something goes wrong during
the openstack API call.
"""
endpoints = self.list_endpoints()
return _utils._filter_list(endpoints, id, filters)
def get_endpoint(self, id, filters=None):
"""Get exactly one Keystone endpoint.
:param id: endpoint id.
:param filters: a dict containing additional filters to use. e.g.
{'region': 'region-a.geo-1'}
:returns: a dict containing the endpoint description. i.e. a dict
containing the following attributes::
- id: <endpoint id>
- region: <endpoint region>
- public_url: <endpoint public url>
- internal_url: <endpoint internal url> (optional)
- admin_url: <endpoint admin url> (optional)
"""
return _utils._get_entity(self.search_endpoints, id, filters)
def delete_endpoint(self, id):
"""Delete a Keystone endpoint.
:param id: Id of the endpoint to delete.
:returns: None
:raises: ``OpenStackCloudException`` if something goes wrong during
the openstack API call.
"""
# ToDo: support v3 api (dguerri)
endpoint = self.get_endpoint(id=id)
if endpoint is None:
return
try:
self.manager.submitTask(_tasks.EndpointDelete(id=id))
except Exception as e:
self.log.debug(
"Failed to delete endpoint {id}".format(id=id),
exc_info=True)
raise OpenStackCloudException(str(e))

View File

@ -341,3 +341,18 @@ class ServiceList(task_manager.Task):
class ServiceDelete(task_manager.Task):
def main(self, client):
return client.keystone_client.services.delete(**self.args)
class EndpointCreate(task_manager.Task):
def main(self, client):
return client.keystone_client.endpoints.create(**self.args)
class EndpointList(task_manager.Task):
def main(self, client):
return client.keystone_client.endpoints.list()
class EndpointDelete(task_manager.Task):
def main(self, client):
return client.keystone_client.endpoints.delete(**self.args)

View File

@ -20,6 +20,17 @@ Fakes used for testing
"""
class FakeEndpoint(object):
def __init__(self, id, service_id, region, publicurl, internalurl=None,
adminurl=None):
self.id = id
self.service_id = service_id
self.region = region
self.publicurl = publicurl
self.internalurl = internalurl
self.adminurl = adminurl
class FakeFlavor(object):
def __init__(self, id, name):
self.id = id

View File

@ -0,0 +1,152 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
#
# See the License for the specific language governing permissions and
# limitations under the License.
"""
test_endpoint
----------------------------------
Functional tests for `shade` endpoint resource.
"""
import string
import random
from shade import operator_cloud
from shade.exc import OpenStackCloudException
from shade.tests import base
class TestEndpoints(base.TestCase):
endpoint_attributes = ['id', 'region', 'publicurl', 'internalurl',
'service_id', 'adminurl']
def setUp(self):
super(TestEndpoints, self).setUp()
# Shell should have OS-* envvars from openrc, typically loaded by job
self.operator_cloud = operator_cloud()
# Generate a random name for services and regions in this test
self.new_item_name = 'test_' + ''.join(
random.choice(string.ascii_lowercase) for _ in range(5))
self.addCleanup(self._cleanup_services)
self.addCleanup(self._cleanup_endpoints)
def _cleanup_endpoints(self):
exception_list = list()
for e in self.operator_cloud.list_endpoints():
if e.get('region') is not None and \
e['region'].startswith(self.new_item_name):
try:
self.operator_cloud.delete_endpoint(id=e['id'])
except Exception as e:
# We were unable to delete a service, let's try with next
exception_list.append(e)
continue
if exception_list:
# Raise an error: we must make users aware that something went
# wrong
raise OpenStackCloudException('\n'.join(exception_list))
def _cleanup_services(self):
exception_list = list()
for s in self.operator_cloud.list_services():
if s['name'].startswith(self.new_item_name):
try:
self.operator_cloud.delete_service(name_or_id=s['id'])
except Exception as e:
# We were unable to delete a service, let's try with next
exception_list.append(e)
continue
if exception_list:
# Raise an error: we must make users aware that something went
# wrong
raise OpenStackCloudException('\n'.join(exception_list))
def test_create_endpoint(self):
service_name = self.new_item_name + '_create'
service = self.operator_cloud.create_service(
name=service_name, service_type='test_type',
description='this is a test description')
endpoint = self.operator_cloud.create_endpoint(
service_name_or_id=service['id'],
public_url='http://public.test/',
internal_url='http://internal.test/',
admin_url='http://admin.url/',
region=service_name)
self.assertIsNotNone(endpoint.get('id'))
# Test None parameters
endpoint = self.operator_cloud.create_endpoint(
service_name_or_id=service['id'],
public_url='http://public.test/',
region=service_name)
self.assertIsNotNone(endpoint.get('id'))
def test_list_endpoints(self):
service_name = self.new_item_name + '_list'
service = self.operator_cloud.create_service(
name=service_name, service_type='test_type',
description='this is a test description')
endpoint = self.operator_cloud.create_endpoint(
service_name_or_id=service['id'],
public_url='http://public.test/',
internal_url='http://internal.test/',
region=service_name)
observed_endpoints = self.operator_cloud.list_endpoints()
found = False
for e in observed_endpoints:
# Test all attributes are returned
if e['id'] == endpoint['id']:
found = True
self.assertEqual(service['id'], e['service_id'])
self.assertEqual('http://public.test/', e['publicurl'])
self.assertEqual('http://internal.test/', e['internalurl'])
self.assertEqual(service_name, e['region'])
self.assertTrue(found, msg='new endpoint not found in endpoints list!')
def test_delete_endpoint(self):
service_name = self.new_item_name + '_delete'
service = self.operator_cloud.create_service(
name=service_name, service_type='test_type',
description='this is a test description')
endpoint = self.operator_cloud.create_endpoint(
service_name_or_id=service['id'],
public_url='http://public.test/',
internal_url='http://internal.test/',
region=service_name)
self.operator_cloud.delete_endpoint(endpoint['id'])
observed_endpoints = self.operator_cloud.list_endpoints()
found = False
for e in observed_endpoints:
if e['id'] == endpoint['id']:
found = True
break
self.failUnlessEqual(
False, found, message='new endpoint was not deleted!')

View File

@ -0,0 +1,132 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
test_cloud_endpoints
----------------------------------
Tests Keystone endpoints commands.
"""
from mock import patch
from shade import OperatorCloud
from shade.tests.fakes import FakeEndpoint
from shade.tests.unit import base
# ToDo: support v3 api (dguerri)
class TestCloudEndpoints(base.TestCase):
mock_endpoints = [
{'id': 'id1', 'service_id': 'sid1', 'region': 'region1',
'publicurl': 'purl1', 'internalurl': None, 'adminurl': None},
{'id': 'id2', 'service_id': 'sid2', 'region': 'region1',
'publicurl': 'purl2', 'internalurl': None, 'adminurl': None},
{'id': 'id3', 'service_id': 'sid3', 'region': 'region2',
'publicurl': 'purl3', 'internalurl': 'iurl3', 'adminurl': 'aurl3'}
]
def setUp(self):
super(TestCloudEndpoints, self).setUp()
self.client = OperatorCloud("op_cloud", {})
self.mock_ks_endpoints = \
[FakeEndpoint(**kwa) for kwa in self.mock_endpoints]
@patch.object(OperatorCloud, 'list_services')
@patch.object(OperatorCloud, 'keystone_client')
def test_create_endpoint(self, mock_keystone_client, mock_list_services):
mock_list_services.return_value = [
{
'id': 'service_id1',
'name': 'service1',
'type': 'type1',
'description': 'desc1'
}
]
mock_keystone_client.endpoints.create.return_value = \
self.mock_ks_endpoints[0]
endpoint = self.client.create_endpoint(
service_name_or_id='service1',
region='mock_region',
public_url='mock_public_url',
internal_url='mock_internal_url',
admin_url='mock_admin_url'
)
mock_keystone_client.endpoints.create.assert_called_with(
service_id='service_id1',
region='mock_region',
publicurl='mock_public_url',
internalurl='mock_internal_url',
adminurl='mock_admin_url'
)
# test keys and values are correct
for k, v in self.mock_endpoints[0].items():
self.assertEquals(v, endpoint.get(k))
@patch.object(OperatorCloud, 'keystone_client')
def test_list_endpoints(self, mock_keystone_client):
mock_keystone_client.endpoints.list.return_value = \
self.mock_ks_endpoints
endpoints = self.client.list_endpoints()
mock_keystone_client.endpoints.list.assert_called_with()
# test we are getting exactly len(self.mock_endpoints) elements
self.assertEqual(len(self.mock_endpoints), len(endpoints))
# test keys and values are correct
for mock_endpoint in self.mock_endpoints:
found = False
for e in endpoints:
if e['id'] == mock_endpoint['id']:
found = True
for k, v in mock_endpoint.items():
self.assertEquals(v, e.get(k))
break
self.assertTrue(
found, msg="endpoint {id} not found!".format(
id=mock_endpoint['id']))
@patch.object(OperatorCloud, 'keystone_client')
def test_search_endpoints(self, mock_keystone_client):
mock_keystone_client.endpoints.list.return_value = \
self.mock_ks_endpoints
# Search by id
endpoints = self.client.search_endpoints(id='id3')
# # test we are getting exactly 1 element
self.assertEqual(1, len(endpoints))
for k, v in self.mock_endpoints[2].items():
self.assertEquals(v, endpoints[0].get(k))
# Not found
endpoints = self.client.search_endpoints(id='blah!')
self.assertEqual(0, len(endpoints))
# Multiple matches
endpoints = self.client.search_endpoints(
filters={'region': 'region1'})
# # test we are getting exactly 2 elements
self.assertEqual(2, len(endpoints))
@patch.object(OperatorCloud, 'keystone_client')
def test_delete_endpoint(self, mock_keystone_client):
mock_keystone_client.endpoints.list.return_value = \
self.mock_ks_endpoints
# Delete by id
self.client.delete_endpoint(id='id2')
mock_keystone_client.endpoints.delete.assert_called_with(id='id2')