Allow to provide configuration for specific cinder backend

This changeset allows to change default store to cinder
and define additional key/values for glance-api.conf file.
Some cinder backends could require additional changes
in service and additional changes in the OS.
Same functionality implemented in cinder charm via storage-backend interface.

Change-Id: Ia9c78df7e9a1ccb0d9ca2121dd01e5832186bf19
This commit is contained in:
Andrey Pavlov 2016-08-24 16:25:04 +03:00
parent fa1c1dda1c
commit 2b3eea98eb
10 changed files with 92 additions and 16 deletions

View File

@ -15,6 +15,8 @@
from charmhelpers.core.hookenv import (
is_relation_made,
relation_ids,
relation_get,
related_units,
service_name,
config
)
@ -70,18 +72,22 @@ class ObjectStoreContext(OSContextGenerator):
class CinderStoreContext(OSContextGenerator):
interfaces = ['cinder-volume-service']
interfaces = ['cinder-volume-service', 'storage-backend']
def __call__(self):
"""Cinder store config.
Used to generate template context to be added to glance-api.conf in
the presence of a 'cinder-volume-service' relation.
the presence of a 'cinder-volume-service' relation or in the
presence of a flag 'cinder-backend' in the 'storage-backend' relation.
"""
if not relation_ids('cinder-volume-service'):
return {}
return {
'cinder_store': True,
}
if relation_ids('cinder-volume-service'):
return {'cinder_store': True}
for rid in relation_ids('storage-backend'):
for unit in related_units(rid):
value = relation_get('cinder-backend', rid=rid, unit=unit)
# value is a boolean flag
return {'cinder_store': value}
return {}
class MultiStoreContext(OSContextGenerator):
@ -95,8 +101,12 @@ class MultiStoreContext(OSContextGenerator):
for store_relation, store_type in store_mapping.iteritems():
if relation_ids(store_relation):
stores.append(store_type)
if (relation_ids('cinder-volume-service') and
if ((relation_ids('cinder-volume-service') or
relation_ids('storage-backend')) and
os_release('glance-common') >= 'mitaka'):
# even if storage-backend is present with cinder-backend=False it
# means that glance should not store images in cinder by default
# but can read images from cinder.
stores.append('glance.store.cinder.Store')
return {
'known_stores': ','.join(stores)

View File

@ -528,7 +528,8 @@ def ha_relation_changed():
'object-store-relation-broken',
'shared-db-relation-broken',
'pgsql-db-relation-broken',
'cinder-volume-service-relation-broken')
'cinder-volume-service-relation-broken',
'storage-backend-relation-broken')
def relation_broken():
CONFIGS.write_all()
@ -592,17 +593,32 @@ def update_status():
juju_log('Updating status.')
@hooks.hook('cinder-volume-service-relation-joined')
@os_requires_version('mitaka', 'glance-common')
@restart_on_change(restart_map(), stopstart=True)
def cinder_volume_service_relation_joined(relid=None):
def install_packages_for_cinder_store():
optional_packages = ["python-cinderclient",
"python-os-brick",
"python-oslo.rootwrap"]
apt_install(filter_installed_packages(optional_packages), fatal=True)
@hooks.hook('cinder-volume-service-relation-joined')
@os_requires_version('mitaka', 'glance-common')
@restart_on_change(restart_map(), stopstart=True)
def cinder_volume_service_relation_joined(relid=None):
install_packages_for_cinder_store()
CONFIGS.write_all()
@hooks.hook('storage-backend-relation-changed')
@os_requires_version('mitaka', 'glance-common')
@restart_on_change(restart_map(), stopstart=True)
def storage_backend_hook():
if 'storage-backend' not in CONFIGS.complete_contexts():
juju_log('storage-backend relation incomplete. Peer not ready?')
return
install_packages_for_cinder_store()
CONFIGS.write(GLANCE_API_CONF)
if __name__ == '__main__':
try:
hooks.execute(sys.argv)

View File

@ -190,7 +190,11 @@ CONFIG_FILES = OrderedDict([
context.OSConfigFlagContext(
charm_flag='api-config-flags',
template_flag='api_config_flags'),
context.InternalEndpointContext()],
context.InternalEndpointContext(),
context.SubordinateConfigContext(
interface=['storage-backend'],
service=['glance-api'],
config_file=GLANCE_API_CONF)],
'services': ['glance-api']
}),
(ceph_config_file(), {
@ -477,9 +481,11 @@ def get_optional_interfaces():
optional_interfaces['ha'] = ['cluster']
if (relation_ids('ceph') or relation_ids('object-store') or
relation_ids('cinder-volume-service')):
relation_ids('cinder-volume-service') or
relation_ids('storage-backend')):
optional_interfaces['storage-backend'] = ['ceph', 'object-store',
'cinder']
'cinder-volume-service',
'storage-backend']
if relation_ids('amqp'):
optional_interfaces['messaging'] = ['amqp']

View File

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

View File

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

View File

@ -39,6 +39,9 @@ requires:
scope: container
cinder-volume-service:
interface: cinder
storage-backend:
interface: glance-backend
scope: container
peers:
cluster:
interface: glance-ha

View File

@ -89,3 +89,5 @@ flavor = keystone
{% include "parts/section-database" %}
{% include "section-rabbitmq-oslo" %}
{% include "parts/section-storage" %}

View File

@ -0,0 +1,8 @@
{% for section in sections -%}
{% if section != 'DEFAULT' -%}
[{{ section }}]
{% for key, value in sections[section] -%}
{{ key }} = {{ value }}
{% endfor %}
{% endif %}
{%- endfor %}

View File

@ -47,6 +47,20 @@ class TestGlanceContexts(CharmTestCase):
self.assertEquals(contexts.ObjectStoreContext()(),
{'swift_store': True})
def test_cinder_not_related(self):
self.relation_ids.return_value = []
self.assertEquals(contexts.CinderStoreContext()(), {})
def test_cinder_related(self):
self.relation_ids.return_value = ['cinder-volume-service:0']
self.assertEquals(contexts.CinderStoreContext()(),
{'cinder_store': True})
def test_cinder_related_via_subordinate(self):
self.relation_ids.return_value = ['cinder-backend:0']
self.assertEquals(contexts.CinderStoreContext()(),
{'cinder_store': True})
def test_ceph_not_related(self):
self.is_relation_made.return_value = False
self.assertEquals(contexts.CephGlanceContext()(), {})

View File

@ -948,3 +948,18 @@ class GlanceRelationTests(CharmTestCase):
"python-os-brick",
"python-oslo.rootwrap"], fatal=True
)
@patch.object(relations, 'CONFIGS')
def test_storage_backend_changed(self, configs):
self.filter_installed_packages.side_effect = lambda pkgs: pkgs
configs.complete_contexts = MagicMock()
configs.complete_contexts.return_value = ['storage-backend']
configs.write = MagicMock()
relations.storage_backend_hook()
self.assertEquals([call('/etc/glance/glance-api.conf')],
configs.write.call_args_list)
self.apt_install.assert_called_with(
["python-cinderclient",
"python-os-brick",
"python-oslo.rootwrap"], fatal=True
)