charm-glance/unit_tests/test_glance_contexts.py
James Page ed8bdede6f Add support for erasure coded ceph pools
Add standard configuration options for erasure coded pool
creation and profile configuration.

Update ceph relation joined handled to support erasure
coded pools - a replicated pool is created at 1% of the
total data weight alongside the erasure coding profile and
supporting erasure coded data pool.

Update ceph context to use the metadata pool name in the
glance configuration files when erasure-coded pool-type
is configured.

Resync charmhelpers to update Ceph Broker request support
for erasure coding.

Change-Id: If4a31a2adf8080af66885adb970fbb3cdd82f573
Depends-On: Iec4de19f7b39f0b08158d96c5cc1561b40aefa10
2020-08-07 10:41:40 +01:00

239 lines
9.4 KiB
Python

# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from mock import patch, MagicMock
import glance_contexts as contexts
from test_utils import (
CharmTestCase
)
TO_PATCH = [
"config",
'relation_ids',
'is_relation_made',
'service_name',
'determine_apache_port',
'determine_api_port',
'os_release',
]
class TestGlanceContexts(CharmTestCase):
def setUp(self):
super(TestGlanceContexts, self).setUp(contexts, TO_PATCH)
from charmhelpers.core.hookenv import cache
self.cache = cache
cache.clear()
def test_glance_context(self):
config = {
'disk-formats': 'dfmt1',
'container-formats': '',
'filesystem-store-datadir': "/var/lib/glance/images/",
'image-size-cap': ''}
self.config.side_effect = lambda x: config[x]
self.assertEqual(contexts.GlanceContext()(), {
'disk_formats': 'dfmt1',
'filesystem_store_datadir': "/var/lib/glance/images/"})
def test_glance_context_container_fmt(self):
config = {
'disk-formats': 'dfmt1',
'container-formats': 'cmft1',
'filesystem-store-datadir': "/var/lib/glance/images/",
'image-size-cap': ''}
self.config.side_effect = lambda x: config[x]
self.assertEqual(contexts.GlanceContext()(),
{'disk_formats': 'dfmt1',
'filesystem_store_datadir':
"/var/lib/glance/images/",
'container_formats': 'cmft1'})
def test_glance_context_image_size_cap(self):
config = {
'disk-formats': 'dfmt1',
'container-formats': 'cmft1',
'filesystem-store-datadir': "/var/lib/glance/images/",
'image-size-cap': '1TB'}
self.config.side_effect = lambda x: config[x]
self.assertEqual(contexts.GlanceContext()(),
{'disk_formats': 'dfmt1',
'container_formats': 'cmft1',
'filesystem_store_datadir':
"/var/lib/glance/images/",
'image_size_cap': 1099511627776})
def test_swift_not_related(self):
self.relation_ids.return_value = []
self.assertEqual(contexts.ObjectStoreContext()(), {})
def test_swift_related(self):
self.relation_ids.return_value = ['object-store:0']
self.assertEqual(contexts.ObjectStoreContext()(),
{'swift_store': True})
def test_cinder_not_related(self):
self.relation_ids.return_value = []
self.assertEqual(contexts.CinderStoreContext()(), {})
def test_cinder_related(self):
self.relation_ids.return_value = ['cinder-volume-service:0']
self.assertEqual(contexts.CinderStoreContext()(),
{'cinder_store': True})
def test_cinder_related_via_subordinate(self):
self.relation_ids.return_value = ['cinder-backend:0']
self.assertEqual(contexts.CinderStoreContext()(),
{'cinder_store': True})
def test_ceph_not_related(self):
self.is_relation_made.return_value = False
self.assertEqual(contexts.CephGlanceContext()(), {})
def test_ceph_related(self):
self.is_relation_made.return_value = True
service = 'glance'
self.service_name.return_value = service
conf_dict = {
'rbd-pool-name': None,
'expose-image-locations': True,
'pool-type': 'replicated',
}
self.config.side_effect = lambda x: conf_dict.get(x)
self.assertEqual(
contexts.CephGlanceContext()(),
{'rbd_pool': service,
'rbd_user': service,
'expose_image_locations': True})
self.config.assert_called_with('expose-image-locations')
# Check user supplied pool name:
conf_dict = {
'rbd-pool-name': 'mypoolname',
'expose-image-locations': True,
'pool-type': 'replicated',
}
self.assertEqual(
contexts.CephGlanceContext()(),
{'rbd_pool': 'mypoolname',
'rbd_user': service,
'expose_image_locations': True})
# Check erasure-coded pool type
conf_dict = {
'rbd-pool-name': None,
'expose-image-locations': True,
'pool-type': 'erasure-coded',
'ec-rbd-metadata-pool': None,
}
self.assertEqual(
contexts.CephGlanceContext()(),
{'rbd_pool': "{}-metadata".format(service),
'rbd_user': service,
'expose_image_locations': True})
# Ensure rbd-pool-name used for metadata pool name
conf_dict = {
'rbd-pool-name': 'foobar',
'expose-image-locations': True,
'pool-type': 'erasure-coded',
'ec-rbd-metadata-pool': None,
}
self.assertEqual(
contexts.CephGlanceContext()(),
{'rbd_pool': "foobar-metadata",
'rbd_user': service,
'expose_image_locations': True})
# Ensure ec-rbd-metadata-pool overrides everything
conf_dict = {
'rbd-pool-name': 'foobar',
'expose-image-locations': True,
'pool-type': 'erasure-coded',
'ec-rbd-metadata-pool': 'another-metadata',
}
self.assertEqual(
contexts.CephGlanceContext()(),
{'rbd_pool': "another-metadata",
'rbd_user': service,
'expose_image_locations': True})
def test_multistore_below_mitaka(self):
self.os_release.return_value = 'liberty'
self.relation_ids.return_value = ['random_rid']
self.assertEqual(contexts.MultiStoreContext()(),
{'known_stores': "glance.store.filesystem.Store,"
"glance.store.http.Store,"
"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.assertEqual(contexts.MultiStoreContext()(),
{'known_stores': "glance.store.cinder.Store,"
"glance.store.filesystem.Store,"
"glance.store.http.Store,"
"glance.store.rbd.Store,"
"glance.store.swift.Store"})
def test_multistore_defaults(self):
self.relation_ids.return_value = []
self.assertEqual(contexts.MultiStoreContext()(),
{'known_stores': "glance.store.filesystem.Store,"
"glance.store.http.Store"})
@patch('charmhelpers.contrib.openstack.context.relation_ids')
@patch('charmhelpers.contrib.hahelpers.cluster.config_get')
@patch('charmhelpers.contrib.openstack.context.https')
def test_apache_ssl_context_service_enabled(self, mock_https,
mock_config,
mock_relation_ids):
mock_relation_ids.return_value = []
mock_config.return_value = 'true'
mock_https.return_value = True
ctxt = contexts.ApacheSSLContext()
ctxt.enable_modules = MagicMock()
ctxt.configure_cert = MagicMock()
ctxt.configure_ca = MagicMock()
ctxt.canonical_names = MagicMock()
ctxt.get_network_addresses = MagicMock()
ctxt.get_network_addresses.return_value = [('1.2.3.4', '1.2.3.4')]
self.assertEqual(ctxt(), {'endpoints': [('1.2.3.4', '1.2.3.4',
9282, 9272)],
'ext_ports': [9282],
'namespace': 'glance'})
@patch('charmhelpers.contrib.openstack.context.config')
@patch("subprocess.check_output")
def test_glance_ipv6_context_service_enabled(self, mock_subprocess,
mock_config):
self.config.return_value = True
mock_config.return_value = True
mock_subprocess.return_value = 'true'
ctxt = contexts.GlanceIPv6Context()
self.assertEqual(ctxt(), {'bind_host': '::',
'registry_host': '[::]'})
@patch('charmhelpers.contrib.openstack.context.config')
@patch("subprocess.check_output")
def test_glance_ipv6_context_service_disabled(self, mock_subprocess,
mock_config):
self.config.return_value = False
mock_config.return_value = False
mock_subprocess.return_value = 'false'
ctxt = contexts.GlanceIPv6Context()
self.assertEqual(ctxt(), {'bind_host': '0.0.0.0',
'registry_host': '0.0.0.0'})