Add support for OpenStack Queens.

Update charm to support Ceilometer@Queens; specifically:

 - Removal of Ceilometer API service
 - Removal of ceilometer-collector service

Most of this change is related to dropping of these
services; In addition its now possible to complete a
ceilometer-upgrade without mongodb being configured.

As this charm no longer provides any endpoints to
keystone, for Queens the identity-credentials relation
is required instead of the identity-service relation.

Change-Id: I3cefc24ffc9a0e60f446fbbdff603dfad37f7baa
This commit is contained in:
James Page 2017-12-15 10:57:24 +00:00
parent a34db0aa8e
commit 4c450fed8c
15 changed files with 348 additions and 56 deletions

View File

@ -17,18 +17,31 @@ default install Ceilometer and its dependencies from the Cloud Archive.
Usage
-----
In order to deploy Ceilometer service, the MongoDB service is required:
In order to deploy Ceilometer service (prior to Queens), the MongoDB
service is required:
juju deploy mongodb
juju deploy ceilometer
juju add-relation ceilometer mongodb
For OpenStack Queens or later, Gnocchi should be used instead of MongoDB
for resource, metrics and measure storage:
juju add-relation ceilometer gnocchi
then Keystone and Rabbit relationships need to be established:
juju add-relation ceilometer rabbitmq
juju add-relation ceilometer keystone:identity-service
juju add-relation ceilometer keystone:identity-notifications
For OpenStack Queens, the identity-service relation must be replaced
with the identity-credentials relation:
juju add-relation ceilometer keystone:identity-credentials
Ceilometer@Queens does not provide an API service.
In order to capture the calculations, a Ceilometer compute agent needs to be
installed in each nova node, and be related with Ceilometer service:

View File

@ -334,10 +334,7 @@ class IdentityServiceContext(OSContextGenerator):
self.rel_name = rel_name
self.interfaces = [self.rel_name]
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
def _setup_pki_cache(self):
if self.service and self.service_user:
# This is required for pki token signing if we don't want /tmp to
# be used.
@ -347,6 +344,15 @@ class IdentityServiceContext(OSContextGenerator):
mkdir(path=cachedir, owner=self.service_user,
group=self.service_user, perms=0o700)
return cachedir
return None
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
cachedir = self._setup_pki_cache()
if cachedir:
ctxt['signing_dir'] = cachedir
for rid in relation_ids(self.rel_name):
@ -385,6 +391,62 @@ class IdentityServiceContext(OSContextGenerator):
return {}
class IdentityCredentialsContext(IdentityServiceContext):
'''Context for identity-credentials interface type'''
def __init__(self,
service=None,
service_user=None,
rel_name='identity-credentials'):
super(IdentityCredentialsContext, self).__init__(service,
service_user,
rel_name)
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
cachedir = self._setup_pki_cache()
if cachedir:
ctxt['signing_dir'] = cachedir
for rid in relation_ids(self.rel_name):
self.related = True
for unit in related_units(rid):
rdata = relation_get(rid=rid, unit=unit)
credentials_host = rdata.get('credentials_host')
credentials_host = (
format_ipv6_addr(credentials_host) or credentials_host
)
auth_host = rdata.get('auth_host')
auth_host = format_ipv6_addr(auth_host) or auth_host
svc_protocol = rdata.get('credentials_protocol') or 'http'
auth_protocol = rdata.get('auth_protocol') or 'http'
api_version = rdata.get('api_version') or '2.0'
ctxt.update({
'service_port': rdata.get('credentials_port'),
'service_host': credentials_host,
'auth_host': auth_host,
'auth_port': rdata.get('auth_port'),
'admin_tenant_name': rdata.get('credentials_project'),
'admin_tenant_id': rdata.get('credentials_project_id'),
'admin_user': rdata.get('credentials_username'),
'admin_password': rdata.get('credentials_password'),
'service_protocol': svc_protocol,
'auth_protocol': auth_protocol,
'api_version': api_version
})
if float(api_version) > 2:
ctxt.update({'admin_domain_name':
rdata.get('domain')})
if self.context_complete(ctxt):
return ctxt
return {}
class AMQPContext(OSContextGenerator):
def __init__(self, ssl_dir=None, rel_name='amqp', relation_prefix=None):

View File

@ -2045,14 +2045,25 @@ def token_cache_pkgs(source=None, release=None):
def update_json_file(filename, items):
"""Updates the json `filename` with a given dict.
:param filename: json filename (i.e.: /etc/glance/policy.json)
:param filename: path to json file (e.g. /etc/glance/policy.json)
:param items: dict of items to update
"""
if not items:
return
with open(filename) as fd:
policy = json.load(fd)
# Compare before and after and if nothing has changed don't write the file
# since that could cause unnecessary service restarts.
before = json.dumps(policy, indent=4, sort_keys=True)
policy.update(items)
after = json.dumps(policy, indent=4, sort_keys=True)
if before == after:
return
with open(filename, "w") as fd:
fd.write(json.dumps(policy, indent=4))
fd.write(after)
@cached

View File

@ -621,16 +621,24 @@ def create_erasure_profile(service, profile_name, erasure_plugin_name='jerasure'
:param durability_estimator: int
:return: None. Can raise CalledProcessError
"""
version = ceph_version()
# Ensure this failure_domain is allowed by Ceph
validator(failure_domain, six.string_types,
['chassis', 'datacenter', 'host', 'osd', 'pdu', 'pod', 'rack', 'region', 'room', 'root', 'row'])
cmd = ['ceph', '--id', service, 'osd', 'erasure-code-profile', 'set', profile_name,
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks),
'ruleset_failure_domain=' + failure_domain]
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks)
]
if locality is not None and durability_estimator is not None:
raise ValueError("create_erasure_profile should be called with k, m and one of l or c but not both.")
# failure_domain changed in luminous
if version and version >= '12.0.0':
cmd.append('crush-failure-domain=' + failure_domain)
else:
cmd.append('ruleset-failure-domain=' + failure_domain)
# Add plugin specific information
if locality is not None:
# For local erasure codes
@ -1064,14 +1072,24 @@ class CephBrokerRq(object):
self.ops = []
def add_op_request_access_to_group(self, name, namespace=None,
permission=None, key_name=None):
permission=None, key_name=None,
object_prefix_permissions=None):
"""
Adds the requested permissions to the current service's Ceph key,
allowing the key to access only the specified pools
allowing the key to access only the specified pools or
object prefixes. object_prefix_permissions should be a dictionary
keyed on the permission with the corresponding value being a list
of prefixes to apply that permission to.
{
'rwx': ['prefix1', 'prefix2'],
'class-read': ['prefix3']}
"""
self.ops.append({'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace, 'name': key_name or service_name(),
'group-permission': permission})
self.ops.append({
'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace,
'name': key_name or service_name(),
'group-permission': permission,
'object-prefix-permissions': object_prefix_permissions})
def add_op_create_pool(self, name, replica_count=3, pg_num=None,
weight=None, group=None, namespace=None):
@ -1107,7 +1125,10 @@ class CephBrokerRq(object):
def _ops_equal(self, other):
if len(self.ops) == len(other.ops):
for req_no in range(0, len(self.ops)):
for key in ['replicas', 'name', 'op', 'pg_num', 'weight']:
for key in [
'replicas', 'name', 'op', 'pg_num', 'weight',
'group', 'group-namespace', 'group-permission',
'object-prefix-permissions']:
if self.ops[req_no].get(key) != other.ops[req_no].get(key):
return False
else:

View File

@ -26,6 +26,7 @@ from charmhelpers.fetch import (
)
from charmhelpers.core.hookenv import (
open_port,
close_port,
relation_get,
relation_set,
relation_ids,
@ -48,6 +49,8 @@ from charmhelpers.contrib.openstack.utils import (
openstack_upgrade_available,
pausable_restart_on_change as restart_on_change,
is_unit_paused_set,
get_os_codename_install_source,
CompareOpenStackReleases,
)
from charmhelpers.contrib.openstack.ha.utils import (
update_dns_ha_resource_params,
@ -112,7 +115,6 @@ def install():
status_set('maintenance', 'Installing packages')
apt_update(fatal=True)
apt_install(packages, fatal=True)
open_port(CEILOMETER_PORT)
if init_is_systemd():
# NOTE(jamespage): ensure systemd override folder exists prior to
# attempting to write override.conf
@ -146,6 +148,8 @@ def metric_service_joined():
"shared-db-relation-departed",
"identity-service-relation-changed",
"identity-service-relation-departed",
"identity-credentials-relation-changed",
"identity-credentials-relation-departed",
"metric-service-relation-changed",
"metric-service-relation-departed")
@restart_on_change(restart_map())
@ -159,8 +163,13 @@ def any_changed():
# and mongodb to be configured to successfully
# upgrade the underlying data stores.
if ('metric-service' in CONFIGS.complete_contexts() and
'identity-service' in CONFIGS.complete_contexts() and
'mongodb' in CONFIGS.complete_contexts()):
'identity-service' in CONFIGS.complete_contexts()):
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
# NOTE(jamespage): however at queens, this limitation has gone!
if (cmp_codename < 'queens' and
'mongodb' not in CONFIGS.complete_contexts()):
return
ceilometer_upgrade()
@ -168,6 +177,10 @@ def configure_https():
"""Enables SSL API Apache config if appropriate."""
# need to write all to ensure changes to the entire request pipeline
# propagate (c-api, haprxy, apache)
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'queens':
return
CONFIGS.write_all()
if 'https' in CONFIGS.complete_contexts():
cmd = ['a2ensite', 'openstack_https_frontend']
@ -200,9 +213,23 @@ def config_changed():
# reload ensures port override is set correctly
reload_systemd()
ceilometer_joined()
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename < 'queens':
open_port(CEILOMETER_PORT)
else:
close_port(CEILOMETER_PORT)
configure_https()
# NOTE(jamespage): Iterate identity-{service,credentials} relations
# to pickup any required databag changes on these
# relations.
for rid in relation_ids('identity-service'):
keystone_joined(relid=rid)
for rid in relation_ids('identity-credentials'):
keystone_credentials_joined(relid=rid)
# Define the new ocf resource and use the key delete_resources to delete
# legacy resource for >= Liberty since the ceilometer-agent-central moved
@ -350,8 +377,21 @@ def ha_changed():
keystone_joined(relid=rid)
@hooks.hook("identity-credentials-relation-joined")
def keystone_credentials_joined(relid=None):
relation_set(relation_id=relid,
username=CEILOMETER_SERVICE,
requested_roles=CEILOMETER_ROLE)
@hooks.hook("identity-service-relation-joined")
def keystone_joined(relid=None):
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'queens':
log('Skipping endpoint registration for >= Queens', level=DEBUG)
return
if config('vip') and not is_clustered():
log('Defering registration until clustered', level=DEBUG)
return

View File

@ -0,0 +1 @@
ceilometer_hooks.py

View File

@ -0,0 +1 @@
ceilometer_hooks.py

View File

@ -0,0 +1 @@
ceilometer_hooks.py

View File

@ -0,0 +1 @@
ceilometer_hooks.py

View File

@ -16,7 +16,7 @@ from charmhelpers.core.hookenv import (
relation_ids,
relation_get,
related_units,
config
config,
)
from charmhelpers.contrib.openstack.utils import (

View File

@ -69,6 +69,11 @@ CEILOMETER_BASE_SERVICES = [
'ceilometer-api',
]
QUEENS_SERVICES = [
'ceilometer-agent-central',
'ceilometer-agent-notification'
]
ICEHOUSE_SERVICES = [
'ceilometer-alarm-notifier',
'ceilometer-alarm-evaluator',
@ -101,6 +106,11 @@ MITAKA_PACKAGES = [
'ceilometer-agent-notification'
]
QUEENS_PACKAGES = [
'ceilometer-agent-central',
'ceilometer-agent-notification'
]
REQUIRED_INTERFACES = {
'database': ['mongodb'],
'messaging': ['amqp'],
@ -112,6 +122,23 @@ SVC = 'ceilometer'
WSGI_CEILOMETER_API_CONF = '/etc/apache2/sites-enabled/wsgi-openstack-api.conf'
PACKAGE_CEILOMETER_API_CONF = '/etc/apache2/sites-enabled/ceilometer-api.conf'
QUEENS_CONFIG_FILES = OrderedDict([
(CEILOMETER_CONF, {
'hook_contexts': [
context.IdentityCredentialsContext(service=SVC,
service_user=SVC),
context.AMQPContext(ssl_dir=CEILOMETER_CONF_DIR),
LoggingConfigContext(),
MongoDBContext(),
CeilometerContext(),
context.SyslogContext(),
context.MemcacheContext(),
MetricServiceContext(),
context.WorkerConfigContext()],
'services': QUEENS_SERVICES
}),
])
CONFIG_FILES = OrderedDict([
(CEILOMETER_CONF, {
'hook_contexts': [context.IdentityServiceContext(service=SVC,
@ -124,7 +151,8 @@ CONFIG_FILES = OrderedDict([
context.SyslogContext(),
HAProxyContext(),
context.MemcacheContext(),
MetricServiceContext()],
MetricServiceContext(),
context.WorkerConfigContext()],
'services': CEILOMETER_BASE_SERVICES
}),
(CEILOMETER_API_SYSTEMD_CONF, {
@ -165,36 +193,46 @@ def register_configs():
# if called without anything installed (eg during install hook)
# just default to earliest supported release. configs dont get touched
# till post-install, anyway.
release = (get_os_codename_package('ceilometer-common', fatal=False) or
'grizzly')
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
openstack_release=release)
for conf in (CEILOMETER_CONF, HAPROXY_CONF):
configs.register(conf, CONFIG_FILES[conf]['hook_contexts'])
if init_is_systemd():
configs.register(
CEILOMETER_API_SYSTEMD_CONF,
CONFIG_FILES[CEILOMETER_API_SYSTEMD_CONF]['hook_contexts']
)
if os.path.exists('/etc/apache2/conf-available'):
configs.register(HTTPS_APACHE_24_CONF,
CONFIG_FILES[HTTPS_APACHE_24_CONF]['hook_contexts'])
if CompareOpenStackReleases(release) >= 'queens':
for conf in QUEENS_CONFIG_FILES:
configs.register(conf, QUEENS_CONFIG_FILES[conf]['hook_contexts'])
else:
configs.register(HTTPS_APACHE_CONF,
CONFIG_FILES[HTTPS_APACHE_CONF]['hook_contexts'])
if enable_memcache(release=release):
configs.register(MEMCACHED_CONF, [context.MemcacheContext()])
for conf in (CEILOMETER_CONF, HAPROXY_CONF):
configs.register(conf, CONFIG_FILES[conf]['hook_contexts'])
if run_in_apache():
wsgi_script = "/usr/share/ceilometer/app.wsgi"
configs.register(WSGI_CEILOMETER_API_CONF,
[context.WSGIWorkerConfigContext(name="ceilometer",
script=wsgi_script),
CeilometerContext(),
HAProxyContext()])
if init_is_systemd():
configs.register(
CEILOMETER_API_SYSTEMD_CONF,
CONFIG_FILES[CEILOMETER_API_SYSTEMD_CONF]['hook_contexts']
)
if os.path.exists('/etc/apache2/conf-available'):
configs.register(
HTTPS_APACHE_24_CONF,
CONFIG_FILES[HTTPS_APACHE_24_CONF]['hook_contexts']
)
else:
configs.register(
HTTPS_APACHE_CONF,
CONFIG_FILES[HTTPS_APACHE_CONF]['hook_contexts']
)
if enable_memcache(release=release):
configs.register(MEMCACHED_CONF, [context.MemcacheContext()])
if run_in_apache():
wsgi_script = "/usr/share/ceilometer/app.wsgi"
configs.register(
WSGI_CEILOMETER_API_CONF,
[context.WSGIWorkerConfigContext(name="ceilometer",
script=wsgi_script),
CeilometerContext(),
HAProxyContext()]
)
return configs
@ -206,8 +244,14 @@ def restart_map():
:returns: dict: A dictionary mapping config file to lists of services
that should be restarted when file changes.
"""
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'queens':
_config_files = QUEENS_CONFIG_FILES
else:
_config_files = CONFIG_FILES
_map = {}
for f, ctxt in CONFIG_FILES.iteritems():
for f, ctxt in _config_files.items():
svcs = []
for svc in ctxt['services']:
svcs.append(svc)
@ -217,10 +261,11 @@ def restart_map():
if svcs:
_map[f] = svcs
if enable_memcache(source=config('openstack-origin')):
if (cmp_codename < 'queens' and
enable_memcache(source=config('openstack-origin'))):
_map[MEMCACHED_CONF] = ['memcached']
if run_in_apache():
if cmp_codename < 'queens' and run_in_apache():
for cfile in _map:
svcs = _map[cfile]
if 'ceilometer-api' in svcs:
@ -254,14 +299,24 @@ def determine_ports():
"""
# TODO(ajkavanagh) - determine what other ports the service listens on
# apart from the main CEILOMETER port
ports = [CEILOMETER_PORT]
return ports
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'queens':
# NOTE(jamespage): No API service for queens or later
return []
return [CEILOMETER_PORT]
def get_ceilometer_context():
""" Retrieve a map of all current relation data for agent configuration """
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'queens':
_config_files = QUEENS_CONFIG_FILES
else:
_config_files = CONFIG_FILES
ctxt = {}
for hcontext in CONFIG_FILES[CEILOMETER_CONF]['hook_contexts']:
for hcontext in _config_files[CEILOMETER_CONF]['hook_contexts']:
ctxt.update(hcontext())
return ctxt
@ -301,9 +356,9 @@ def do_openstack_upgrade(configs):
def ceilometer_release_services():
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'mitaka':
if cmp_codename >= 'mitaka' and cmp_codename < 'queens':
return MITAKA_SERVICES
elif cmp_codename >= 'icehouse':
elif cmp_codename >= 'icehouse' and cmp_codename < 'mitaka':
return ICEHOUSE_SERVICES
else:
return []
@ -312,7 +367,7 @@ def ceilometer_release_services():
def ceilometer_release_packages():
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
if cmp_codename >= 'mitaka':
if cmp_codename >= 'mitaka' and cmp_codename < 'queens':
return MITAKA_PACKAGES
elif cmp_codename >= 'icehouse':
return ICEHOUSE_PACKAGES
@ -321,6 +376,14 @@ def ceilometer_release_packages():
def get_packages():
cmp_codename = CompareOpenStackReleases(
get_os_codename_install_source(config('openstack-origin')))
# NOTE(jamespage): @queens ceilometer has no API service, so
# no requirement for token caching.
if cmp_codename >= 'queens':
return deepcopy(QUEENS_PACKAGES)
packages = (deepcopy(CEILOMETER_BASE_PACKAGES) +
ceilometer_release_packages())
packages.extend(token_cache_pkgs(source=config('openstack-origin')))
@ -378,6 +441,9 @@ def resolve_required_interfaces():
required_ints = deepcopy(REQUIRED_INTERFACES)
if CompareOpenStackReleases(os_release('ceilometer-common')) >= 'mitaka':
required_ints['database'].append('metric-service')
if CompareOpenStackReleases(os_release('ceilometer-common')) >= 'queens':
required_ints['database'].remove('mongodb')
required_ints['identity'] = ['identity-credentials']
return required_ints
@ -446,7 +512,8 @@ def run_in_apache():
"""Return true if ceilometer API is run under apache2 with mod_wsgi in
this release.
"""
return CompareOpenStackReleases(os_release('ceilometer-common')) >= 'ocata'
os_cmp = CompareOpenStackReleases(os_release('ceilometer-common'))
return (os_cmp >= 'ocata' and os_cmp < 'queens')
def disable_package_apache_site():

View File

@ -36,6 +36,8 @@ requires:
interface: keystone
identity-notifications:
interface: keystone-notifications
identity-credentials:
interface: keystone-credentials
ha:
interface: hacluster
scope: container

View File

@ -17,10 +17,17 @@ event_dispatchers = gnocchi
meter_dispatchers = database
{%- endif %}
{% if transport_url -%}
transport_url = {{ transport_url }}
{%- endif %}
[api]
port = {{ port }}
workers = {{ api_workers }}
[notification]
workers = {{ workers }}
{% if service_host -%}
[service_credentials]
auth_url = {{ service_protocol }}://{{ service_host }}:{{ service_port }}

View File

@ -48,6 +48,7 @@ TO_PATCH = [
'apt_install',
'apt_update',
'open_port',
'close_port',
'config',
'log',
'relation_ids',
@ -69,6 +70,7 @@ TO_PATCH = [
'init_is_systemd',
'get_relation_ip',
'is_clustered',
'get_os_codename_install_source',
]
@ -82,6 +84,7 @@ class CeilometerHooksTest(CharmTestCase):
self.filter_installed_packages.return_value = \
ceilometer_utils.CEILOMETER_BASE_PACKAGES
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
self.get_os_codename_install_source.return_value = 'mitaka'
@patch('charmhelpers.payload.execd.default_execd_dir',
return_value=os.path.join(os.getcwd(), 'exec.d'))
@ -99,7 +102,6 @@ class CeilometerHooksTest(CharmTestCase):
hooks.hooks.execute(['hooks/install.real'])
self.configure_installation_source.\
assert_called_with('cloud:precise-grizzly')
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
self.apt_update.assert_called_with(fatal=True)
self.apt_install.assert_called_with(
ceilometer_utils.CEILOMETER_BASE_PACKAGES,
@ -114,7 +116,6 @@ class CeilometerHooksTest(CharmTestCase):
hooks.hooks.execute(['hooks/install.real'])
self.configure_installation_source.\
assert_called_with('distro')
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
self.apt_update.assert_called_with(fatal=True)
self.apt_install.assert_called_with(
ceilometer_utils.CEILOMETER_BASE_PACKAGES,
@ -201,6 +202,25 @@ class CeilometerHooksTest(CharmTestCase):
self.assertTrue(self.CONFIGS.write_all.called)
self.assertTrue(joined.called)
self.assertTrue(self.reload_systemd.called)
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
@patch.object(hooks, 'install_event_pipeline_setting')
@patch('charmhelpers.core.hookenv.config')
@patch.object(hooks, 'ceilometer_joined')
def test_config_changed_queens(self,
joined, mock_config, event_pipe):
self.openstack_upgrade_available.return_value = False
self.get_os_codename_install_source.return_value = 'queens'
hooks.hooks.execute(['hooks/config-changed'])
self.openstack_upgrade_available.\
assert_called_with('ceilometer-common')
self.assertFalse(self.do_openstack_upgrade.called)
self.assertTrue(event_pipe.called)
self.assertTrue(self.CONFIGS.write_all.called)
self.assertTrue(joined.called)
self.assertTrue(self.reload_systemd.called)
self.close_port.assert_called_with(hooks.CEILOMETER_PORT)
self.open_port.assert_not_called()
@patch.object(hooks, 'install_event_pipeline_setting')
@patch('charmhelpers.core.hookenv.config')
@ -216,6 +236,7 @@ class CeilometerHooksTest(CharmTestCase):
self.assertTrue(self.CONFIGS.write_all.called)
self.assertTrue(joined.called)
self.assertTrue(self.reload_systemd.called)
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
@patch.object(hooks, 'install_event_pipeline_setting')
def test_config_changed_with_openstack_upgrade_action(self,
@ -227,6 +248,14 @@ class CeilometerHooksTest(CharmTestCase):
self.assertFalse(self.do_openstack_upgrade.called)
self.assertTrue(event_pipe.called)
self.open_port.assert_called_with(hooks.CEILOMETER_PORT)
def test_keystone_credentials_joined(self):
hooks.hooks.execute(['hooks/identity-credentials-relation-joined'])
self.relation_set.assert_called_with(
username=hooks.CEILOMETER_SERVICE,
requested_roles=hooks.CEILOMETER_ROLE,
relation_id=None)
@patch.object(hooks, 'canonical_url')
@patch('charmhelpers.core.hookenv.config')

View File

@ -47,6 +47,7 @@ class CeilometerUtilsTest(CharmTestCase):
def setUp(self):
super(CeilometerUtilsTest, self).setUp(utils, TO_PATCH)
self.config.side_effect = self.test_config.get
self.get_os_codename_install_source.return_value = 'icehouse'
def tearDown(self):
super(CeilometerUtilsTest, self).tearDown()
@ -55,6 +56,7 @@ class CeilometerUtilsTest(CharmTestCase):
self.os.path.exists.return_value = True
self.init_is_systemd.return_value = False
self.os_release.return_value = 'havana'
self.get_os_codename_package.return_value = 'havana'
configs = utils.register_configs()
calls = []
for conf in (utils.CEILOMETER_CONF, utils.HAPROXY_CONF,
@ -67,6 +69,7 @@ class CeilometerUtilsTest(CharmTestCase):
self.os.path.exists.return_value = False
self.init_is_systemd.return_value = False
self.os_release.return_value = 'havana'
self.get_os_codename_package.return_value = 'havana'
configs = utils.register_configs()
calls = []
for conf in (utils.CEILOMETER_CONF, utils.HAPROXY_CONF,
@ -79,6 +82,7 @@ class CeilometerUtilsTest(CharmTestCase):
self.os.path.exists.return_value = True
self.init_is_systemd.return_value = True
self.os_release.return_value = 'havana'
self.get_os_codename_package.return_value = 'havana'
configs = utils.register_configs()
calls = []
for conf in (utils.CEILOMETER_CONF, utils.HAPROXY_CONF,
@ -101,6 +105,12 @@ class CeilometerUtilsTest(CharmTestCase):
self.assertEqual(['ceilometer-agent-notification'],
utils.ceilometer_release_services())
def test_ceilometer_release_services_queens(self):
"""Ensure that queens specific services are identified"""
self.get_os_codename_install_source.return_value = 'queens'
self.assertEqual([],
utils.ceilometer_release_services())
def test_restart_map(self):
"""Ensure that alarming services are present for < OpenStack Mitaka"""
self.get_os_codename_install_source.return_value = 'icehouse'
@ -150,6 +160,20 @@ class CeilometerUtilsTest(CharmTestCase):
}
)
def test_restart_map_queens(self):
"""Ensure that alarming services are missing for OpenStack Queens"""
self.get_os_codename_install_source.return_value = 'queens'
self.os_release.return_value = 'queens'
self.maxDiff = None
restart_map = utils.restart_map()
self.assertEqual(
restart_map,
{'/etc/ceilometer/ceilometer.conf': [
'ceilometer-agent-central',
'ceilometer-agent-notification'],
}
)
def test_get_ceilometer_conf(self):
class TestContext():
@ -272,6 +296,18 @@ class CeilometerUtilsTest(CharmTestCase):
}
)
def test_resolve_required_interfaces_queens(self):
self.os_release.side_effect = None
self.os_release.return_value = 'queens'
self.assertEqual(
utils.resolve_required_interfaces(),
{
'database': ['metric-service'],
'messaging': ['amqp'],
'identity': ['identity-credentials'],
}
)
@patch.object(utils, 'subprocess')
def test_ceilometer_upgrade(self, mock_subprocess):
self.is_leader.return_value = True