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.
|
# limitations under the License.
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import enum
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
|
@ -50,9 +51,27 @@ class BaseOpenStackCephCharm(object):
|
||||||
# ceph service name is determined from `application_name` property.
|
# ceph service name is determined from `application_name` property.
|
||||||
# If this does not fit your use case you can override.
|
# If this does not fit your use case you can override.
|
||||||
ceph_service_name_override = ''
|
ceph_service_name_override = ''
|
||||||
|
|
||||||
# Unless you are writing a charm providing Ceph mon|osd|mgr|mds services
|
# Unless you are writing a charm providing Ceph mon|osd|mgr|mds services
|
||||||
# this should probably be left as-is.
|
# 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.
|
# Path prefix to where the Ceph keyring should be stored.
|
||||||
ceph_keyring_path_prefix = '/etc/ceph'
|
ceph_keyring_path_prefix = '/etc/ceph'
|
||||||
|
@ -102,9 +121,13 @@ class BaseOpenStackCephCharm(object):
|
||||||
:returns: Ceph key name
|
:returns: Ceph key name
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
base_key_name = '{}.{}'.format(
|
if self.ceph_service_type == self.CephServiceType.client:
|
||||||
self.ceph_service_type,
|
base_key_name = '{}.{}'.format(
|
||||||
self.ceph_service_name)
|
self.ceph_service_type,
|
||||||
|
self.ceph_service_name)
|
||||||
|
else:
|
||||||
|
base_key_name = self.ceph_service_name
|
||||||
|
|
||||||
if self.ceph_key_per_unit_name:
|
if self.ceph_key_per_unit_name:
|
||||||
return '{}.{}'.format(
|
return '{}.{}'.format(
|
||||||
base_key_name,
|
base_key_name,
|
||||||
|
@ -131,9 +154,13 @@ class BaseOpenStackCephCharm(object):
|
||||||
:returns: Absolute path to keyring file
|
:returns: Absolute path to keyring file
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
keyring_name = ('{}.{}.keyring'
|
if self.ceph_service_type == self.CephServiceType.client:
|
||||||
.format(cluster_name or self.ceph_cluster_name,
|
keyring_name = ('{}.{}.keyring'
|
||||||
self.ceph_key_name))
|
.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_absolute_path = os.path.join(self.ceph_keyring_path,
|
||||||
keyring_name)
|
keyring_name)
|
||||||
return keyring_absolute_path
|
return keyring_absolute_path
|
||||||
|
@ -216,6 +243,8 @@ class CephCharm(charms_openstack.charm.OpenStackCharm,
|
||||||
('10', 'mitaka'), # 10.2.x Jewel
|
('10', 'mitaka'), # 10.2.x Jewel
|
||||||
('12', 'pike'), # 12.2.x Luminous
|
('12', 'pike'), # 12.2.x Luminous
|
||||||
('13', 'rocky'), # 13.2.x Mimic
|
('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.
|
# Path prefix to where the Ceph keyring should be stored.
|
||||||
ceph_keyring_path_prefix = '/var/lib/ceph'
|
ceph_keyring_path_prefix = '/var/lib/ceph'
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
"""Initialize class."""
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.hostname = socket.gethostname()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ceph_keyring_path(self):
|
def ceph_keyring_path(self):
|
||||||
"""Provide a path to where the Ceph keyring should be stored.
|
"""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
|
:returns: Path to directory
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
return os.path.join(self.snap_path_prefix,
|
keyring_path_components = (
|
||||||
self.ceph_keyring_path_prefix,
|
self.snap_path_prefix,
|
||||||
self.ceph_service_name)
|
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):
|
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(
|
keyring_absolute_path = super().configure_ceph_keyring(
|
||||||
key, cluster_name=cluster_name)
|
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(
|
symlink_absolute_path = os.path.join(
|
||||||
'/etc/ceph',
|
'/etc/ceph',
|
||||||
os.path.basename(keyring_absolute_path))
|
os.path.basename(keyring_absolute_path))
|
||||||
|
|
|
@ -14,9 +14,19 @@ TEST_CONFIG = {'config': True,
|
||||||
class FakeOpenStackCephConsumingCharm(
|
class FakeOpenStackCephConsumingCharm(
|
||||||
chm.OpenStackCharm,
|
chm.OpenStackCharm,
|
||||||
cpl.BaseOpenStackCephCharm):
|
cpl.BaseOpenStackCephCharm):
|
||||||
|
|
||||||
abstract_class = True
|
abstract_class = True
|
||||||
|
|
||||||
|
|
||||||
|
class FakeCephCharm(cpl.CephCharm):
|
||||||
|
|
||||||
|
abstract_class = True
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.hostname = 'somehost'
|
||||||
|
|
||||||
|
|
||||||
class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
|
class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -127,7 +137,7 @@ class TestOpenStackCephConsumingCharm(BaseOpenStackCharmTest):
|
||||||
class TestCephCharm(BaseOpenStackCharmTest):
|
class TestCephCharm(BaseOpenStackCharmTest):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCephCharm, self).setUp(cpl.CephCharm, {'source': None})
|
super(TestCephCharm, self).setUp(FakeCephCharm, {'source': None})
|
||||||
|
|
||||||
def test_ceph_keyring_path(self):
|
def test_ceph_keyring_path(self):
|
||||||
self.patch_object(cpl.ch_core.hookenv, 'application_name',
|
self.patch_object(cpl.ch_core.hookenv, 'application_name',
|
||||||
|
@ -140,6 +150,16 @@ class TestCephCharm(BaseOpenStackCharmTest):
|
||||||
self.target.ceph_keyring_path,
|
self.target.ceph_keyring_path,
|
||||||
os.path.join(cpl.SNAP_PATH_PREFIX_FORMAT.format('gnocchi'),
|
os.path.join(cpl.SNAP_PATH_PREFIX_FORMAT.format('gnocchi'),
|
||||||
'/var/lib/ceph/charmname'))
|
'/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):
|
def test_configure_ceph_keyring(self):
|
||||||
self.patch_object(cpl.os.path, 'isdir', return_value=False)
|
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, 'readlink')
|
||||||
self.patch_object(cpl.os, 'remove')
|
self.patch_object(cpl.os, 'remove')
|
||||||
self.readlink.side_effect = OSError
|
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.target.configure_ceph_keyring(key)
|
||||||
self.isdir.assert_called_with('/var/lib/ceph/sarepta')
|
self.isdir.assert_called_with('/var/lib/ceph/sarepta')
|
||||||
self.mkdir.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.target.delete_ceph_keyring()
|
||||||
self.remove.assert_called_once_with(
|
self.remove.assert_called_once_with(
|
||||||
'/var/lib/ceph/sarepta/ceph.client.sarepta.keyring')
|
'/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):
|
def test_install(self):
|
||||||
self.patch_object(cpl.subprocess, 'check_output', return_value=b'\n')
|
self.patch_object(cpl.subprocess, 'check_output', return_value=b'\n')
|
||||||
|
|
Loading…
Reference in New Issue