Add support for storage of images in Cinder

Glance charm allows to store images in file, ceph, swift.

This changeset adds support for storage of images in Cinder
for OpenStack Mitaka or later.

Required dependencies are installed on relation to Cinder
(inline with Ceph integration).

This feature is dependent on resolution of some packaging
issues in the glance-store package (see Related-Bug).

Related-Bug: 1609733

Change-Id: Ib9d9f28e040b7b2eebb3f5d0ee9ff0773292bdcc
This commit is contained in:
Andrey Pavlov 2016-08-22 15:37:38 +03:00 committed by James Page
parent ad8888b09b
commit fa1c1dda1c
9 changed files with 82 additions and 13 deletions

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

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

@ -30,6 +30,10 @@ from charmhelpers.contrib.hahelpers.cluster import (
determine_api_port,
)
from charmhelpers.contrib.openstack.utils import (
os_release
)
class CephGlanceContext(OSContextGenerator):
interfaces = ['ceph-glance']
@ -65,6 +69,21 @@ class ObjectStoreContext(OSContextGenerator):
}
class CinderStoreContext(OSContextGenerator):
interfaces = ['cinder-volume-service']
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.
"""
if not relation_ids('cinder-volume-service'):
return {}
return {
'cinder_store': True,
}
class MultiStoreContext(OSContextGenerator):
def __call__(self):
@ -76,6 +95,9 @@ 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
os_release('glance-common') >= 'mitaka'):
stores.append('glance.store.cinder.Store')
return {
'known_stores': ','.join(stores)
}

@ -88,6 +88,7 @@ from charmhelpers.contrib.openstack.utils import (
sync_db_with_multi_ipv6_addresses,
pausable_restart_on_change as restart_on_change,
is_unit_paused_set,
os_requires_version,
)
from charmhelpers.contrib.storage.linux.ceph import (
send_request_if_needed,
@ -526,7 +527,8 @@ def ha_relation_changed():
@hooks.hook('identity-service-relation-broken',
'object-store-relation-broken',
'shared-db-relation-broken',
'pgsql-db-relation-broken')
'pgsql-db-relation-broken',
'cinder-volume-service-relation-broken')
def relation_broken():
CONFIGS.write_all()
@ -590,6 +592,17 @@ 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):
optional_packages = ["python-cinderclient",
"python-os-brick",
"python-oslo.rootwrap"]
apt_install(filter_installed_packages(optional_packages), fatal=True)
CONFIGS.write_all()
if __name__ == '__main__':
try:
hooks.execute(sys.argv)

@ -142,8 +142,6 @@ HTTPS_APACHE_CONF = "/etc/apache2/sites-available/openstack_https_frontend"
HTTPS_APACHE_24_CONF = "/etc/apache2/sites-available/" \
"openstack_https_frontend.conf"
CONF_DIR = "/etc/glance"
TEMPLATES = 'templates/'
# The interface is said to be satisfied if anyone of the interfaces in the
@ -182,6 +180,7 @@ CONFIG_FILES = OrderedDict([
service_user='glance'),
glance_contexts.CephGlanceContext(),
glance_contexts.ObjectStoreContext(),
glance_contexts.CinderStoreContext(),
glance_contexts.HAProxyContext(),
context.SyslogContext(),
glance_contexts.LoggingConfigContext(),
@ -396,7 +395,7 @@ def git_post_install(projects_yaml):
src_etc = os.path.join(git_src_dir(projects_yaml, 'glance'), 'etc')
configs = {
'src': src_etc,
'dest': '/etc/glance',
'dest': GLANCE_CONF_DIR,
}
if os.path.exists(configs['dest']):
@ -418,7 +417,7 @@ def git_post_install(projects_yaml):
bin_dir = os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
# Use systemd init units/scripts from ubuntu wily onward
if lsb_release()['DISTRIB_RELEASE'] >= '15.10':
templates_dir = os.path.join(charm_dir(), 'templates/git')
templates_dir = os.path.join(charm_dir(), TEMPLATES, 'git')
daemons = ['glance-api', 'glance-glare', 'glance-registry']
for daemon in daemons:
glance_context = {
@ -437,7 +436,7 @@ def git_post_install(projects_yaml):
'start_dir': '/var/lib/glance',
'process_name': 'glance-api',
'executable_name': os.path.join(bin_dir, 'glance-api'),
'config_files': ['/etc/glance/glance-api.conf'],
'config_files': [GLANCE_API_CONF],
'log_file': '/var/log/glance/api.log',
}
@ -448,7 +447,7 @@ def git_post_install(projects_yaml):
'start_dir': '/var/lib/glance',
'process_name': 'glance-registry',
'executable_name': os.path.join(bin_dir, 'glance-registry'),
'config_files': ['/etc/glance/glance-registry.conf'],
'config_files': [GLANCE_REGISTRY_CONF],
'log_file': '/var/log/glance/registry.log',
}
@ -477,8 +476,10 @@ def get_optional_interfaces():
if relation_ids('ha'):
optional_interfaces['ha'] = ['cluster']
if relation_ids('ceph') or relation_ids('object-store'):
optional_interfaces['storage-backend'] = ['ceph', 'object-store']
if (relation_ids('ceph') or relation_ids('object-store') or
relation_ids('cinder-volume-service')):
optional_interfaces['storage-backend'] = ['ceph', 'object-store',
'cinder']
if relation_ids('amqp'):
optional_interfaces['messaging'] = ['amqp']

@ -37,6 +37,8 @@ requires:
ha:
interface: hacluster
scope: container
cinder-volume-service:
interface: cinder
peers:
cluster:
interface: glance-ha

@ -51,6 +51,8 @@ stores = {{ known_stores }}
default_store = rbd
{% elif swift_store -%}
default_store = swift
{% elif cinder_store -%}
default_store = cinder
{% else -%}
default_store = file
{% endif -%}

@ -26,6 +26,7 @@ TO_PATCH = [
'service_name',
'determine_apache_port',
'determine_api_port',
'os_release',
]
@ -62,7 +63,8 @@ class TestGlanceContexts(CharmTestCase):
'expose_image_locations': True})
self.config.assert_called_with('expose-image-locations')
def test_multistore(self):
def test_multistore_below_mitaka(self):
self.os_release.return_value = 'liberty'
self.relation_ids.return_value = ['random_rid']
self.assertEquals(contexts.MultiStoreContext()(),
{'known_stores': "glance.store.filesystem.Store,"
@ -70,6 +72,16 @@ class TestGlanceContexts(CharmTestCase):
"glance.store.rbd.Store,"
"glance.store.swift.Store"})
def test_multistore_for_mitaka_and_upper(self):
self.os_release.return_value = 'mitaka'
self.relation_ids.return_value = ['random_rid']
self.assertEquals(contexts.MultiStoreContext()(),
{'known_stores': "glance.store.filesystem.Store,"
"glance.store.http.Store,"
"glance.store.rbd.Store,"
"glance.store.swift.Store,"
"glance.store.cinder.Store"})
def test_multistore_defaults(self):
self.relation_ids.return_value = []
self.assertEquals(contexts.MultiStoreContext()(),

@ -35,9 +35,13 @@ utils.register_configs = MagicMock()
utils.restart_map = MagicMock()
with patch('hooks.charmhelpers.contrib.hardening.harden.harden') as mock_dec:
mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
lambda *args, **kwargs: f(*args, **kwargs))
import hooks.glance_relations as relations
with patch('hooks.charmhelpers.contrib.openstack.'
'utils.os_requires_version') as mock_os:
mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
lambda *args, **kwargs: f(*args, **kwargs))
mock_os.side_effect = (lambda *dargs, **dkwargs: lambda f:
lambda *args, **kwargs: f(*args, **kwargs))
import hooks.glance_relations as relations
relations.hooks._config_save = False
@ -933,3 +937,14 @@ class GlanceRelationTests(CharmTestCase):
def test_relation_broken(self, configs):
relations.relation_broken()
self.assertTrue(configs.write_all.called)
@patch.object(relations, 'CONFIGS')
def test_cinder_volume_joined(self, configs):
self.filter_installed_packages.side_effect = lambda pkgs: pkgs
relations.cinder_volume_service_relation_joined()
self.assertTrue(configs.write_all.called)
self.apt_install.assert_called_with(
["python-cinderclient",
"python-os-brick",
"python-oslo.rootwrap"], fatal=True
)