Merge "Fix up amulet for queens"

This commit is contained in:
Zuul 2018-03-02 15:21:05 +00:00 committed by Gerrit Code Review
commit b12ccd189a
6 changed files with 440 additions and 138 deletions

View File

@ -367,13 +367,36 @@ class OpenStackAmuletUtils(AmuletUtils):
project_domain_name=None, project_name=None):
"""Authenticate with Keystone"""
self.log.debug('Authenticating with keystone...')
port = 5000
if admin_port:
port = 35357
base_ep = "http://{}:{}".format(keystone_ip.strip().decode('utf-8'),
port)
if not api_version or api_version == 2:
ep = base_ep + "/v2.0"
if not api_version:
api_version = 2
sess, auth = self.get_keystone_session(
keystone_ip=keystone_ip,
username=username,
password=password,
api_version=api_version,
admin_port=admin_port,
user_domain_name=user_domain_name,
domain_name=domain_name,
project_domain_name=project_domain_name,
project_name=project_name
)
if api_version == 2:
client = keystone_client.Client(session=sess)
else:
client = keystone_client_v3.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
def get_keystone_session(self, keystone_ip, username, password,
api_version=False, admin_port=False,
user_domain_name=None, domain_name=None,
project_domain_name=None, project_name=None):
"""Return a keystone session object"""
ep = self.get_keystone_endpoint(keystone_ip,
api_version=api_version,
admin_port=admin_port)
if api_version == 2:
auth = v2.Password(
username=username,
password=password,
@ -381,12 +404,7 @@ class OpenStackAmuletUtils(AmuletUtils):
auth_url=ep
)
sess = keystone_session.Session(auth=auth)
client = keystone_client.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
else:
ep = base_ep + "/v3"
auth = v3.Password(
user_domain_name=user_domain_name,
username=username,
@ -397,10 +415,57 @@ class OpenStackAmuletUtils(AmuletUtils):
auth_url=ep
)
sess = keystone_session.Session(auth=auth)
client = keystone_client_v3.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
return (sess, auth)
def get_keystone_endpoint(self, keystone_ip, api_version=None,
admin_port=False):
"""Return keystone endpoint"""
port = 5000
if admin_port:
port = 35357
base_ep = "http://{}:{}".format(keystone_ip.strip().decode('utf-8'),
port)
if api_version == 2:
ep = base_ep + "/v2.0"
else:
ep = base_ep + "/v3"
return ep
def get_default_keystone_session(self, keystone_sentry,
openstack_release=None):
"""Return a keystone session object and client object assuming standard
default settings
Example call in amulet tests:
self.keystone_session, self.keystone = u.get_default_keystone_session(
self.keystone_sentry,
openstack_release=self._get_openstack_release())
The session can then be used to auth other clients:
neutronclient.Client(session=session)
aodh_client.Client(session=session)
eyc
"""
self.log.debug('Authenticating keystone admin...')
api_version = 2
client_class = keystone_client.Client
# 11 => xenial_queens
if openstack_release and openstack_release >= 11:
api_version = 3
client_class = keystone_client_v3.Client
keystone_ip = keystone_sentry.info['public-address']
session, auth = self.get_keystone_session(
keystone_ip,
api_version=api_version,
username='admin',
password='openstack',
project_name='admin',
user_domain_name='admin_domain',
project_domain_name='admin_domain')
client = client_class(session=session)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(session)
return session, client
def authenticate_keystone_admin(self, keystone_sentry, user, password,
tenant=None, api_version=None,

View File

@ -182,7 +182,7 @@ SWIFT_CODENAMES = OrderedDict([
('pike',
['2.13.0', '2.15.0']),
('queens',
['2.16.0']),
['2.16.0', '2.17.0']),
])
# >= Liberty version->codename mapping

View File

@ -32,6 +32,9 @@ u = OpenStackAmuletUtils(DEBUG)
class CeilometerBasicDeployment(OpenStackAmuletDeployment):
"""Amulet tests on a basic ceilometer deployment."""
no_origin = ['memcached', 'percona-cluster', 'rabbitmq-server',
'ceph-mon', 'ceph-osd']
def __init__(self, series, openstack=None, source=None, stable=False):
"""Deploy the entire test environment."""
super(CeilometerBasicDeployment, self).__init__(series, openstack,
@ -42,7 +45,7 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
self._deploy()
u.log.info('Waiting on extended status checks...')
exclude_services = ['mongodb']
exclude_services = ['mongodb', 'memcached']
self._auto_wait_for_status(exclude_services=exclude_services)
self.d.sentry.wait()
@ -62,21 +65,29 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
{'name': 'percona-cluster', 'constraints': {'mem': '3072M'}},
{'name': 'rabbitmq-server'},
{'name': 'keystone'},
{'name': 'mongodb',
'location': 'cs:~thedac/{}/mongodb'.format(self.series)},
{'name': 'glance'}, # to satisfy workload status
{'name': 'ceilometer-agent'},
{'name': 'nova-compute'}
]
super(CeilometerBasicDeployment, self)._add_services(this_service,
other_services)
if self._get_openstack_release() >= self.xenial_queens:
other_services.extend([
{'name': 'gnocchi'},
{'name': 'memcached', 'location': 'cs:memcached'},
{'name': 'ceph-mon', 'units': 3},
{'name': 'ceph-osd', 'units': 3}])
else:
other_services.append({
'name': 'mongodb',
'location': 'cs:~thedac/{}/mongodb'.format(self.series)})
super(CeilometerBasicDeployment, self)._add_services(
this_service,
other_services,
no_origin=self.no_origin)
def _add_relations(self):
"""Add all of the relations for the services."""
relations = {
'ceilometer:shared-db': 'mongodb:database',
'ceilometer:amqp': 'rabbitmq-server:amqp',
'ceilometer:identity-service': 'keystone:identity-service',
'ceilometer:identity-notifications': 'keystone:'
'identity-notifications',
'keystone:shared-db': 'percona-cluster:shared-db',
@ -90,6 +101,25 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'glance:amqp': 'rabbitmq-server:amqp',
'nova-compute:image-service': 'glance:image-service'
}
if self._get_openstack_release() >= self.xenial_queens:
additional_relations = {
'ceilometer:identity-credentials': 'keystone:'
'identity-credentials',
'ceilometer:identity-notifications': 'keystone:'
'identity-notifications',
'ceilometer:metric-service': 'gnocchi:metric-service',
'ceph-mon:osd': 'ceph-osd:mon',
'gnocchi:identity-service': 'keystone:identity-service',
'gnocchi:shared-db': 'percona-cluster:shared-db',
'gnocchi:storage-ceph': 'ceph-mon:client',
'gnocchi:coordinator-memcached': 'memcached:cache',
}
else:
additional_relations = {
'ceilometer:shared-db': 'mongodb:database',
'ceilometer:identity-service': 'keystone:identity-service'}
relations.update(additional_relations)
print(relations)
super(CeilometerBasicDeployment, self)._add_relations(relations)
def _configure_services(self):
@ -106,6 +136,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'keystone': keystone_config,
'percona-cluster': pxc_config,
}
if self._get_openstack_release() >= self.xenial_queens:
configs['ceph-osd'] = {'osd-devices': '/dev/vdb',
'osd-reformat': 'yes',
'ephemeral-unmount': '/mnt'}
super(CeilometerBasicDeployment, self)._configure_services(configs)
def _get_token(self):
@ -119,42 +153,50 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
self.pxc_sentry = self.d.sentry['percona-cluster'][0]
self.keystone_sentry = self.d.sentry['keystone'][0]
self.rabbitmq_sentry = self.d.sentry['rabbitmq-server'][0]
self.mongodb_sentry = self.d.sentry['mongodb'][0]
self.nova_sentry = self.d.sentry['nova-compute'][0]
if self._get_openstack_release() >= self.xenial_queens:
self.gnocchi_sentry = self.d.sentry['gnocchi'][0]
else:
self.mongodb_sentry = self.d.sentry['mongodb'][0]
u.log.debug('openstack release val: {}'.format(
self._get_openstack_release()))
u.log.debug('openstack release str: {}'.format(
self._get_openstack_release_string()))
# Authenticate admin with keystone endpoint
self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,
user='admin',
password='openstack',
tenant='admin')
self.keystone_session, self.keystone = u.get_default_keystone_session(
self.keystone_sentry,
openstack_release=self._get_openstack_release())
# Authenticate admin with ceilometer endpoint
ep = self.keystone.service_catalog.url_for(service_type='metering',
interface='publicURL')
os_token = self.keystone.auth_token
self.log.debug('Instantiating ceilometer client...')
self.ceil = ceilo_client.Client(endpoint=ep, token=os_token)
if self._get_openstack_release() >= self.xenial_queens:
self.ceil = ceilo_client.Client(session=self.keystone_session,)
else:
# Authenticate admin with ceilometer endpoint
ep = self.keystone.service_catalog.url_for(service_type='metering',
interface='publicURL')
os_token = self.keystone.auth_token
self.ceil = ceilo_client.Client(endpoint=ep, token=os_token)
def test_100_services(self):
"""Verify the expected services are running on the corresponding
service units."""
u.log.debug('Checking system services on units...')
release = self._get_openstack_release()
ceilometer_svcs = [
'ceilometer-agent-central',
'ceilometer-collector',
'ceilometer-agent-notification',
]
if self._get_openstack_release() >= self.xenial_ocata:
if release < self.xenial_queens:
ceilometer_svcs.append('ceilometer-collector')
if (release >= self.xenial_ocata and release < self.xenial_queens):
ceilometer_svcs.append('apache2')
else:
if release < self.xenial_ocata:
ceilometer_svcs.append('ceilometer-api')
if self._get_openstack_release() < self.trusty_mitaka:
if release < self.trusty_mitaka:
ceilometer_svcs.append('ceilometer-alarm-evaluator')
ceilometer_svcs.append('ceilometer-alarm-notifier')
@ -169,6 +211,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
u.log.debug('OK')
def test_105_memcache(self):
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping memcache test as memcache server is external'
' to ceilometer')
return
u.validate_memcache(self.ceil_sentry,
'/etc/ceilometer/ceilometer.conf',
self._get_openstack_release(),
@ -176,6 +222,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_110_service_catalog(self):
"""Verify that the service catalog endpoint data is valid."""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping catalogue checks as ceilometer no longer '
'registers endpoints')
return
u.log.debug('Checking keystone service catalog data...')
endpoint_check = {
'adminURL': u.valid_url,
@ -190,7 +240,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
}
actual = self.keystone.service_catalog.get_endpoints()
ret = u.validate_svc_catalog_endpoint_data(expected, actual)
ret = u.validate_svc_catalog_endpoint_data(
expected,
actual,
openstack_release=self._get_openstack_release())
if ret:
amulet.raise_status(amulet.FAIL, msg=ret)
@ -198,6 +251,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_112_keystone_api_endpoint(self):
"""Verify the ceilometer api endpoint data."""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping catalogue checks as ceilometer no longer '
'registers endpoints')
return
u.log.debug('Checking keystone api endpoint data...')
endpoints = self.keystone.endpoints.list()
u.log.debug(endpoints)
@ -210,8 +267,13 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'publicurl': u.valid_url,
'service_id': u.not_null}
ret = u.validate_endpoint_data(endpoints, admin_port, internal_port,
public_port, expected)
ret = u.validate_endpoint_data(
endpoints,
admin_port,
internal_port,
public_port,
expected,
openstack_release=self._get_openstack_release())
if ret:
message = 'Keystone endpoint: {}'.format(ret)
amulet.raise_status(amulet.FAIL, msg=message)
@ -220,6 +282,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_114_ceilometer_api_endpoint(self):
"""Verify the ceilometer api endpoint data."""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping catalogue checks as ceilometer no longer '
'registers endpoints')
return
u.log.debug('Checking ceilometer api endpoint data...')
endpoints = self.keystone.endpoints.list()
u.log.debug(endpoints)
@ -241,6 +307,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_200_ceilometer_identity_relation(self):
"""Verify the ceilometer to keystone identity-service relation data"""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping identity-service checks as ceilometer no '
'longer has this rerlation')
return
u.log.debug('Checking ceilometer to keystone identity-service '
'relation data...')
unit = self.ceil_sentry
@ -268,6 +338,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_201_keystone_ceilometer_identity_relation(self):
"""Verify the keystone to ceilometer identity-service relation data"""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping identity-service checks as ceilometer no '
'longer has this rerlation')
return
u.log.debug('Checking keystone:ceilometer identity relation data...')
unit = self.keystone_sentry
relation = ['identity-service', 'ceilometer:identity-service']
@ -304,7 +378,7 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
# May be glance- or keystone- or another endpoint-changed value, so
# check that at least one ???-endpoint-changed value exists.
unit = self.keystone_sentry
relation_data = unit.relation('identity-service',
relation_data = unit.relation('identity-notifications',
'ceilometer:identity-notifications')
expected = '-endpoint-changed'
@ -358,42 +432,6 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
u.log.debug('OK')
def test_205_ceilometer_to_mongodb_relation(self):
"""Verify the ceilometer to mongodb relation data"""
u.log.debug('Checking ceilometer:mongodb relation data...')
unit = self.ceil_sentry
relation = ['shared-db', 'mongodb:database']
expected = {
'ceilometer_database': 'ceilometer',
'private-address': u.valid_ip,
}
ret = u.validate_relation_data(unit, relation, expected)
if ret:
message = u.relation_error('ceilometer shared-db', ret)
amulet.raise_status(amulet.FAIL, msg=message)
u.log.debug('OK')
def test_206_mongodb_to_ceilometer_relation(self):
"""Verify the mongodb to ceilometer relation data"""
u.log.debug('Checking mongodb:ceilometer relation data...')
unit = self.mongodb_sentry
relation = ['database', 'ceilometer:shared-db']
expected = {
'hostname': u.valid_ip,
'port': '27017',
'private-address': u.valid_ip,
'type': 'database',
}
ret = u.validate_relation_data(unit, relation, expected)
if ret:
message = u.relation_error('mongodb database', ret)
amulet.raise_status(amulet.FAIL, msg=message)
u.log.debug('OK')
def test_207_ceilometer_ceilometer_agent_relation(self):
"""Verify the ceilometer to ceilometer-agent relation data"""
u.log.debug('Checking ceilometer:ceilometer-agent relation data...')
@ -404,18 +442,22 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'rabbitmq_user': 'ceilometer',
'verbose': 'False',
'rabbitmq_host': u.valid_ip,
'service_ports': "{'ceilometer_api': [8777, 8767]}",
'use_syslog': 'False',
'metering_secret': u.not_null,
'rabbitmq_virtual_host': 'openstack',
'db_port': '27017',
'private-address': u.valid_ip,
'db_name': 'ceilometer',
'db_host': u.valid_ip,
'debug': 'False',
'rabbitmq_password': u.not_null,
'port': '8767'
}
if self._get_openstack_release() >= self.xenial_queens:
expected['gnocchi_url'] = u.valid_url
expected['port'] = '8777'
else:
expected['db_port'] = '27017'
expected['db_name'] = 'ceilometer'
expected['db_host'] = u.valid_ip
expected['service_ports'] = "{'ceilometer_api': [8777, 8767]}"
ret = u.validate_relation_data(unit, relation, expected)
if ret:
@ -442,12 +484,6 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
"""Verify the data in the ceilometer config file."""
u.log.debug('Checking ceilometer config file data...')
unit = self.ceil_sentry
ks_rel = self.keystone_sentry.relation('identity-service',
'ceilometer:identity-service')
db_relation = self.mongodb_sentry.relation('database',
'ceilometer:shared-db')
db_conn = 'mongodb://%s:%s/ceilometer' % (db_relation['hostname'],
db_relation['port'])
conf = '/etc/ceilometer/ceilometer.conf'
expected = {
'DEFAULT': {
@ -458,10 +494,26 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'api': {
'port': '8767',
},
'database': {
'connection': db_conn,
},
}
if self._get_openstack_release() >= self.xenial_queens:
relation = self.gnocchi_sentry.relation(
'metric-service',
'ceilometer:metric-service')
expected['dispatcher_gnocchi'] = {'url': relation['gnocchi_url']}
ks_rel = self.keystone_sentry.relation(
'identity-credentials',
'ceilometer:identity-credentials')
ks_key_prefix = 'credentials'
else:
db_relation = self.mongodb_sentry.relation('database',
'ceilometer:shared-db')
db_conn = 'mongodb://%s:%s/ceilometer' % (db_relation['hostname'],
db_relation['port'])
expected['database'] = {'connection': db_conn}
ks_rel = self.keystone_sentry.relation(
'identity-service',
'ceilometer:identity-service')
ks_key_prefix = 'service'
if self._get_openstack_release() < self.trusty_mitaka:
auth_uri = '%s://%s:%s/v2.0' % (ks_rel['service_protocol'],
@ -473,9 +525,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
'os_password':
ks_rel['service_password']}
else:
auth_uri = '%s://%s:%s' % (ks_rel['service_protocol'],
ks_rel['service_host'],
ks_rel['service_port'])
auth_uri = '%s://%s:%s' % (
ks_rel['{}_protocol'.format(ks_key_prefix)],
ks_rel['{}_host'.format(ks_key_prefix)],
ks_rel['{}_port'.format(ks_key_prefix)])
# NOTE(dosaboy): os_ prefix is deprecated and no longer used as
# of Mitaka.
project_domain_name = 'default'
@ -483,25 +536,21 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
if 'api_version' in ks_rel and float(ks_rel['api_version']) > 2:
project_domain_name = 'service_domain'
user_domain_name = 'service_domain'
expected['service_credentials'] = {'auth_url': auth_uri,
'project_name': 'services',
'project_domain_name':
project_domain_name,
'user_domain_name':
user_domain_name,
'username': 'ceilometer',
'password':
ks_rel['service_password']}
expected['keystone_authtoken'] = {'auth_uri': auth_uri,
'auth_type': 'password',
'project_domain_name':
project_domain_name,
'user_domain_name':
user_domain_name,
'project_name': 'services',
'username': 'ceilometer',
'password':
ks_rel['service_password']}
expected['service_credentials'] = {
'auth_url': auth_uri,
'project_name': 'services',
'project_domain_name': project_domain_name,
'user_domain_name': user_domain_name,
'username': 'ceilometer',
'password': ks_rel['{}_password'.format(ks_key_prefix)]}
expected['keystone_authtoken'] = {
'auth_uri': auth_uri,
'auth_type': 'password',
'project_domain_name': project_domain_name,
'user_domain_name': user_domain_name,
'project_name': 'services',
'username': 'ceilometer',
'password': ks_rel['{}_password'.format(ks_key_prefix)]}
if self._get_openstack_release() >= self.xenial_ocata:
del expected['api']
@ -516,6 +565,10 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
def test_400_api_connection(self):
"""Simple api calls to check service is up and responding"""
if self._get_openstack_release() >= self.xenial_queens:
u.log.debug('Skipping API checks as ceilometer api has been '
'removed')
return
u.log.debug('Checking api functionality...')
assert(self.ceil.samples.list() == [])
assert(self.ceil.meters.list() == [])
@ -537,7 +590,13 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
# Services which are expected to restart upon config change,
# and corresponding config files affected by the change
conf_file = '/etc/ceilometer/ceilometer.conf'
if self._get_openstack_release() >= self.xenial_ocata:
if self._get_openstack_release() >= self.xenial_queens:
services = {
'ceilometer-polling: AgentManager worker(0)': conf_file,
'ceilometer-agent-notification: NotificationService worker(0)':
conf_file,
}
elif self._get_openstack_release() >= self.xenial_ocata:
services = {
'ceilometer-collector: CollectorService worker(0)': conf_file,
'ceilometer-polling: AgentManager worker(0)': conf_file,

View File

@ -21,6 +21,9 @@ from collections import OrderedDict
from charmhelpers.contrib.amulet.deployment import (
AmuletDeployment
)
from charmhelpers.contrib.openstack.amulet.utils import (
OPENSTACK_RELEASES_PAIRS
)
DEBUG = logging.DEBUG
ERROR = logging.ERROR
@ -271,11 +274,8 @@ class OpenStackAmuletDeployment(AmuletDeployment):
release.
"""
# Must be ordered by OpenStack release (not by Ubuntu release):
(self.trusty_icehouse, self.trusty_kilo, self.trusty_liberty,
self.trusty_mitaka, self.xenial_mitaka, self.xenial_newton,
self.yakkety_newton, self.xenial_ocata, self.zesty_ocata,
self.xenial_pike, self.artful_pike, self.xenial_queens,
self.bionic_queens,) = range(13)
for i, os_pair in enumerate(OPENSTACK_RELEASES_PAIRS):
setattr(self, os_pair, i)
releases = {
('trusty', None): self.trusty_icehouse,

View File

@ -50,6 +50,13 @@ ERROR = logging.ERROR
NOVA_CLIENT_VERSION = "2"
OPENSTACK_RELEASES_PAIRS = [
'trusty_icehouse', 'trusty_kilo', 'trusty_liberty',
'trusty_mitaka', 'xenial_mitaka', 'xenial_newton',
'yakkety_newton', 'xenial_ocata', 'zesty_ocata',
'xenial_pike', 'artful_pike', 'xenial_queens',
'bionic_queens']
class OpenStackAmuletUtils(AmuletUtils):
"""OpenStack amulet utilities.
@ -63,7 +70,34 @@ class OpenStackAmuletUtils(AmuletUtils):
super(OpenStackAmuletUtils, self).__init__(log_level)
def validate_endpoint_data(self, endpoints, admin_port, internal_port,
public_port, expected):
public_port, expected, openstack_release=None):
"""Validate endpoint data. Pick the correct validator based on
OpenStack release. Expected data should be in the v2 format:
{
'id': id,
'region': region,
'adminurl': adminurl,
'internalurl': internalurl,
'publicurl': publicurl,
'service_id': service_id}
"""
validation_function = self.validate_v2_endpoint_data
xenial_queens = OPENSTACK_RELEASES_PAIRS.index('xenial_queens')
if openstack_release and openstack_release >= xenial_queens:
validation_function = self.validate_v3_endpoint_data
expected = {
'id': expected['id'],
'region': expected['region'],
'region_id': 'RegionOne',
'url': self.valid_url,
'interface': self.not_null,
'service_id': expected['service_id']}
return validation_function(endpoints, admin_port, internal_port,
public_port, expected)
def validate_v2_endpoint_data(self, endpoints, admin_port, internal_port,
public_port, expected):
"""Validate endpoint data.
Validate actual endpoint data vs expected endpoint data. The ports
@ -141,7 +175,86 @@ class OpenStackAmuletUtils(AmuletUtils):
if len(found) != expected_num_eps:
return 'Unexpected number of endpoints found'
def validate_svc_catalog_endpoint_data(self, expected, actual):
def convert_svc_catalog_endpoint_data_to_v3(self, ep_data):
"""Convert v2 endpoint data into v3.
{
'service_name1': [
{
'adminURL': adminURL,
'id': id,
'region': region.
'publicURL': publicURL,
'internalURL': internalURL
}],
'service_name2': [
{
'adminURL': adminURL,
'id': id,
'region': region.
'publicURL': publicURL,
'internalURL': internalURL
}],
}
"""
self.log.warn("Endpoint ID and Region ID validation is limited to not "
"null checks after v2 to v3 conversion")
for svc in ep_data.keys():
assert len(ep_data[svc]) == 1, "Unknown data format"
svc_ep_data = ep_data[svc][0]
ep_data[svc] = [
{
'url': svc_ep_data['adminURL'],
'interface': 'admin',
'region': svc_ep_data['region'],
'region_id': self.not_null,
'id': self.not_null},
{
'url': svc_ep_data['publicURL'],
'interface': 'public',
'region': svc_ep_data['region'],
'region_id': self.not_null,
'id': self.not_null},
{
'url': svc_ep_data['internalURL'],
'interface': 'internal',
'region': svc_ep_data['region'],
'region_id': self.not_null,
'id': self.not_null}]
return ep_data
def validate_svc_catalog_endpoint_data(self, expected, actual,
openstack_release=None):
"""Validate service catalog endpoint data. Pick the correct validator
for the OpenStack version. Expected data should be in the v2 format:
{
'service_name1': [
{
'adminURL': adminURL,
'id': id,
'region': region.
'publicURL': publicURL,
'internalURL': internalURL
}],
'service_name2': [
{
'adminURL': adminURL,
'id': id,
'region': region.
'publicURL': publicURL,
'internalURL': internalURL
}],
}
"""
validation_function = self.validate_v2_svc_catalog_endpoint_data
xenial_queens = OPENSTACK_RELEASES_PAIRS.index('xenial_queens')
if openstack_release and openstack_release >= xenial_queens:
validation_function = self.validate_v3_svc_catalog_endpoint_data
expected = self.convert_svc_catalog_endpoint_data_to_v3(expected)
return validation_function(expected, actual)
def validate_v2_svc_catalog_endpoint_data(self, expected, actual):
"""Validate service catalog endpoint data.
Validate a list of actual service catalog endpoints vs a list of
@ -367,13 +480,36 @@ class OpenStackAmuletUtils(AmuletUtils):
project_domain_name=None, project_name=None):
"""Authenticate with Keystone"""
self.log.debug('Authenticating with keystone...')
port = 5000
if admin_port:
port = 35357
base_ep = "http://{}:{}".format(keystone_ip.strip().decode('utf-8'),
port)
if not api_version or api_version == 2:
ep = base_ep + "/v2.0"
if not api_version:
api_version = 2
sess, auth = self.get_keystone_session(
keystone_ip=keystone_ip,
username=username,
password=password,
api_version=api_version,
admin_port=admin_port,
user_domain_name=user_domain_name,
domain_name=domain_name,
project_domain_name=project_domain_name,
project_name=project_name
)
if api_version == 2:
client = keystone_client.Client(session=sess)
else:
client = keystone_client_v3.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
def get_keystone_session(self, keystone_ip, username, password,
api_version=False, admin_port=False,
user_domain_name=None, domain_name=None,
project_domain_name=None, project_name=None):
"""Return a keystone session object"""
ep = self.get_keystone_endpoint(keystone_ip,
api_version=api_version,
admin_port=admin_port)
if api_version == 2:
auth = v2.Password(
username=username,
password=password,
@ -381,12 +517,7 @@ class OpenStackAmuletUtils(AmuletUtils):
auth_url=ep
)
sess = keystone_session.Session(auth=auth)
client = keystone_client.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
else:
ep = base_ep + "/v3"
auth = v3.Password(
user_domain_name=user_domain_name,
username=username,
@ -397,10 +528,57 @@ class OpenStackAmuletUtils(AmuletUtils):
auth_url=ep
)
sess = keystone_session.Session(auth=auth)
client = keystone_client_v3.Client(session=sess)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(sess)
return client
return (sess, auth)
def get_keystone_endpoint(self, keystone_ip, api_version=None,
admin_port=False):
"""Return keystone endpoint"""
port = 5000
if admin_port:
port = 35357
base_ep = "http://{}:{}".format(keystone_ip.strip().decode('utf-8'),
port)
if api_version == 2:
ep = base_ep + "/v2.0"
else:
ep = base_ep + "/v3"
return ep
def get_default_keystone_session(self, keystone_sentry,
openstack_release=None):
"""Return a keystone session object and client object assuming standard
default settings
Example call in amulet tests:
self.keystone_session, self.keystone = u.get_default_keystone_session(
self.keystone_sentry,
openstack_release=self._get_openstack_release())
The session can then be used to auth other clients:
neutronclient.Client(session=session)
aodh_client.Client(session=session)
eyc
"""
self.log.debug('Authenticating keystone admin...')
api_version = 2
client_class = keystone_client.Client
# 11 => xenial_queens
if openstack_release and openstack_release >= 11:
api_version = 3
client_class = keystone_client_v3.Client
keystone_ip = keystone_sentry.info['public-address']
session, auth = self.get_keystone_session(
keystone_ip,
api_version=api_version,
username='admin',
password='openstack',
project_name='admin',
user_domain_name='admin_domain',
project_domain_name='admin_domain')
client = client_class(session=session)
# This populates the client.service_catalog
client.auth_ref = auth.get_access(session)
return session, client
def authenticate_keystone_admin(self, keystone_sentry, user, password,
tenant=None, api_version=None,