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

View File

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

View File

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

View File

@ -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)
}

View File

@ -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)

View File

@ -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']

View File

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

View File

@ -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 -%}

View File

@ -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()(),

View File

@ -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
)