plugins/ceph: Add support for core Ceph charms
Also adds missing release combinations to package_codenames. Change-Id: I6fbde855ba8f83ef5e265bd5b5dfb0d01eae830b Related-Bug: #1879072
This commit is contained in:
parent
f0a486c59d
commit
e03f6a6a1c
|
@ -13,6 +13,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import collections
|
||||
import enum
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
|
@ -50,9 +51,27 @@ class BaseOpenStackCephCharm(object):
|
|||
# ceph service name is determined from `application_name` property.
|
||||
# If this does not fit your use case you can override.
|
||||
ceph_service_name_override = ''
|
||||
|
||||
# Unless you are writing a charm providing Ceph mon|osd|mgr|mds services
|
||||
# this should probably be left as-is.
|
||||
ceph_service_type = 'client'
|
||||
|
||||
class CephServiceType(enum.Enum):
|
||||
"""Ceph service type."""
|
||||
client = 'client'
|
||||
mds = 'mds'
|
||||
mgr = 'mgr'
|
||||
mon = 'mon'
|
||||
osd = 'osd'
|
||||
|
||||
def __str__(self):
|
||||
"""Return string representation of value.
|
||||
|
||||
:returns: string representation of value.
|
||||
:rtype: str
|
||||
"""
|
||||
return self.value
|
||||
|
||||
ceph_service_type = CephServiceType.client
|
||||
|
||||
# Path prefix to where the Ceph keyring should be stored.
|
||||
ceph_keyring_path_prefix = '/etc/ceph'
|
||||
|
@ -102,9 +121,13 @@ class BaseOpenStackCephCharm(object):
|
|||
:returns: Ceph key name
|
||||
:rtype: str
|
||||
"""
|
||||
base_key_name = '{}.{}'.format(
|
||||
self.ceph_service_type,
|
||||
self.ceph_service_name)
|
||||
if self.ceph_service_type == self.CephServiceType.client:
|
||||
base_key_name = '{}.{}'.format(
|
||||
self.ceph_service_type,
|
||||
self.ceph_service_name)
|
||||
else:
|
||||
base_key_name = self.ceph_service_name
|
||||
|
||||
if self.ceph_key_per_unit_name:
|
||||
return '{}.{}'.format(
|
||||
base_key_name,
|
||||
|
@ -131,9 +154,13 @@ class BaseOpenStackCephCharm(object):
|
|||
:returns: Absolute path to keyring file
|
||||
:rtype: str
|
||||
"""
|
||||
keyring_name = ('{}.{}.keyring'
|
||||
.format(cluster_name or self.ceph_cluster_name,
|
||||
self.ceph_key_name))
|
||||
if self.ceph_service_type == self.CephServiceType.client:
|
||||
keyring_name = ('{}.{}.keyring'
|
||||
.format(cluster_name or self.ceph_cluster_name,
|
||||
self.ceph_key_name))
|
||||
else:
|
||||
keyring_name = 'keyring'
|
||||
|
||||
keyring_absolute_path = os.path.join(self.ceph_keyring_path,
|
||||
keyring_name)
|
||||
return keyring_absolute_path
|
||||
|
@ -216,6 +243,8 @@ class CephCharm(charms_openstack.charm.OpenStackCharm,
|
|||
('10', 'mitaka'), # 10.2.x Jewel
|
||||
('12', 'pike'), # 12.2.x Luminous
|
||||
('13', 'rocky'), # 13.2.x Mimic
|
||||
('14', 'train'), # 14.2.x Nautilus
|
||||
('15', 'ussuri'), # 15.2.x Octopus
|
||||
]),
|
||||
}
|
||||
|
||||
|
@ -250,6 +279,11 @@ class CephCharm(charms_openstack.charm.OpenStackCharm,
|
|||
# Path prefix to where the Ceph keyring should be stored.
|
||||
ceph_keyring_path_prefix = '/var/lib/ceph'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Initialize class."""
|
||||
super().__init__(**kwargs)
|
||||
self.hostname = socket.gethostname()
|
||||
|
||||
@property
|
||||
def ceph_keyring_path(self):
|
||||
"""Provide a path to where the Ceph keyring should be stored.
|
||||
|
@ -257,14 +291,33 @@ class CephCharm(charms_openstack.charm.OpenStackCharm,
|
|||
:returns: Path to directory
|
||||
:rtype: str
|
||||
"""
|
||||
return os.path.join(self.snap_path_prefix,
|
||||
self.ceph_keyring_path_prefix,
|
||||
self.ceph_service_name)
|
||||
keyring_path_components = (
|
||||
self.snap_path_prefix,
|
||||
self.ceph_keyring_path_prefix,
|
||||
self.ceph_service_name)
|
||||
|
||||
if self.ceph_service_type != self.CephServiceType.client:
|
||||
keyring_path_components = (
|
||||
*keyring_path_components,
|
||||
'{}-{}'.format(self.ceph_cluster_name,
|
||||
self.hostname))
|
||||
|
||||
return os.path.join(*keyring_path_components)
|
||||
|
||||
def configure_ceph_keyring(self, key, cluster_name=None):
|
||||
"""Override parent function to add symlink in ``/etc/ceph``."""
|
||||
"""Override parent method for Ceph service providing charms.
|
||||
|
||||
:param cluster_name: (Optional) Name of Ceph cluster to operate on.
|
||||
Defaults to value of ``self.ceph_cluster_name``.
|
||||
:type cluster_name: str
|
||||
:raises: OSError
|
||||
"""
|
||||
keyring_absolute_path = super().configure_ceph_keyring(
|
||||
key, cluster_name=cluster_name)
|
||||
if self.ceph_service_type != self.CephServiceType.client:
|
||||
return
|
||||
# If the service is a client-type sevice (sych as RBD Mirror) add
|
||||
# symlink to key in ``/etc/ceph``.
|
||||
symlink_absolute_path = os.path.join(
|
||||
'/etc/ceph',
|
||||
os.path.basename(keyring_absolute_path))
|
||||
|
|
|
@ -14,9 +14,19 @@ TEST_CONFIG = {'config': True,
|
|||
class FakeOpenStackCephConsumingCharm(
|
||||
chm.OpenStackCharm,
|
||||
cpl.BaseOpenStackCephCharm):
|
||||
|
||||
abstract_class = True
|
||||
|
||||
|
||||
class FakeCephCharm(cpl.CephCharm):
|
||||
|
||||
abstract_class = True
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.hostname = 'somehost'
|
||||
|
||||
|
||||
class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -127,7 +137,7 @@ class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
|
|||
class TestCephCharm(BaseOpenStackCharmTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCephCharm, self).setUp(cpl.CephCharm, {'source': None})
|
||||
super(TestCephCharm, self).setUp(FakeCephCharm, {'source': None})
|
||||
|
||||
def test_ceph_keyring_path(self):
|
||||
self.patch_object(cpl.ch_core.hookenv, 'application_name',
|
||||
|
@ -140,6 +150,16 @@ class TestCephCharm(BaseOpenStackCharmTest):
|
|||
self.target.ceph_keyring_path,
|
||||
os.path.join(cpl.SNAP_PATH_PREFIX_FORMAT.format('gnocchi'),
|
||||
'/var/lib/ceph/charmname'))
|
||||
self.target.snaps = []
|
||||
self.target.ceph_service_type = self.target.CephServiceType.mds
|
||||
self.assertEqual(
|
||||
self.target.ceph_keyring_path,
|
||||
'/var/lib/ceph/charmname/ceph-somehost')
|
||||
self.target.snaps = ['somecephsnap']
|
||||
self.assertEqual(
|
||||
self.target.ceph_keyring_path,
|
||||
os.path.join(cpl.SNAP_PATH_PREFIX_FORMAT.format('gnocchi'),
|
||||
'/var/lib/ceph/charmname/ceph-somehost'))
|
||||
|
||||
def test_configure_ceph_keyring(self):
|
||||
self.patch_object(cpl.os.path, 'isdir', return_value=False)
|
||||
|
@ -154,6 +174,21 @@ class TestCephCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(cpl.os, 'readlink')
|
||||
self.patch_object(cpl.os, 'remove')
|
||||
self.readlink.side_effect = OSError
|
||||
self.target.ceph_service_type = self.target.CephServiceType.mds
|
||||
self.target.configure_ceph_keyring(key)
|
||||
self.isdir.assert_called_with('/var/lib/ceph/sarepta/ceph-somehost')
|
||||
self.mkdir.assert_called_with('/var/lib/ceph/sarepta/ceph-somehost',
|
||||
owner='root', group='root', perms=0o750)
|
||||
self.check_call.assert_called_with([
|
||||
'ceph-authtool',
|
||||
'/var/lib/ceph/sarepta/ceph-somehost/keyring',
|
||||
'--create-keyring', '--name=sarepta', '--add-key', 'KEY',
|
||||
'--mode', '0600',
|
||||
])
|
||||
self.exists.assert_not_called()
|
||||
self.readlink.assert_not_called()
|
||||
self.symlink.assert_not_called()
|
||||
self.target.ceph_service_type = self.target.CephServiceType.client
|
||||
self.target.configure_ceph_keyring(key)
|
||||
self.isdir.assert_called_with('/var/lib/ceph/sarepta')
|
||||
self.mkdir.assert_called_with('/var/lib/ceph/sarepta',
|
||||
|
@ -184,6 +219,11 @@ class TestCephCharm(BaseOpenStackCharmTest):
|
|||
self.target.delete_ceph_keyring()
|
||||
self.remove.assert_called_once_with(
|
||||
'/var/lib/ceph/sarepta/ceph.client.sarepta.keyring')
|
||||
self.remove.reset_mock()
|
||||
self.target.ceph_service_type = self.target.CephServiceType.mds
|
||||
self.target.delete_ceph_keyring()
|
||||
self.remove.assert_called_once_with(
|
||||
'/var/lib/ceph/sarepta/ceph-somehost/keyring')
|
||||
|
||||
def test_install(self):
|
||||
self.patch_object(cpl.subprocess, 'check_output', return_value=b'\n')
|
||||
|
|
Loading…
Reference in New Issue