Create a base class for cinder plugins

The purpose of this new class is to ease development for existing
and upcoming cinder plugins, for instance, the cookiecutter and
solidfire ones. This class makes development much more in line with
the existing reactive libraries.

Change-Id: I55a849dd11e83e5b2b23efcece6ff8dfa511c96f
This commit is contained in:
Luciano Lo Giudice 2021-12-01 14:05:27 -03:00
parent 79c3414d77
commit 0cf56a3bb2
2 changed files with 119 additions and 0 deletions

View File

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import ops_openstack.core
# ch_context needed for bluestore validation
import charmhelpers.contrib.openstack.context as ch_context
@ -53,3 +55,73 @@ class BaseCephClientCharm(ops_openstack.core.OSBaseCharm):
bluestore_compression = None
if bluestore_compression:
return bluestore_compression.get_kwargs()
class CinderStoragePluginCharm(ops_openstack.core.OSBaseCharm):
def __init__(self, framework):
super().__init__(framework)
self.framework.observe(self.on.config_changed, self.on_config)
self.framework.observe(
self.on.storage_backend_relation_changed,
self.on_storage_backend)
def render_config(self, config, app_name):
return json.dumps({
"cinder": {
"/etc/cinder/cinder.confg": {
"sections": {app_name: self.cinder_configuration(config)}
}
}
})
def set_data(self, data, config, app_name):
"""Inform another charm of the backend name and configuration."""
data['backend_name'] = config['volume-backend-name'] or app_name
data['stateless'] = str(self.stateless)
data['active_active'] = str(self.active_active)
data['subordinate_configuration'] = self.render_config(
config, app_name)
def on_config(self, event):
config = dict(self.framework.model.config)
app_name = self.framework.model.app.name
for relation in self.framework.model.relations.get('storage-backend'):
self.set_data(relation.data[self.unit], config, app_name)
self.unit.status = ActiveStatus('Unit is ready')
def on_storage_backend(self, event):
self.set_data(
event.relation.data[self.unit],
self.framework.model.config,
self.framework.model.app.name)
def cinder_configuration(self, charm_config):
"""Entry point for cinder subordinates.
This method should return a list of 2-element tuples, where the
first element is the configuration key, and the second, its value."""
raise NotImplementedError()
@property
def stateless(self):
"""Indicate whether the charm is stateless.
For more information, see: https://cinderlib.readthedocs.io/en/v0.2.1/topics/serialization.html
:returns: A boolean value indicating statefulness.
:rtype: bool
""" # noqa
return False
@property
def active_active(self):
"""Indicate active-active support in the charm.
For more information, see: https://specs.openstack.org/openstack/cinder-specs/specs/mitaka/cinder-volume-active-active-support.html
:returns: A boolean indicating active-active support.
:rtype: bool
""" # noqa
return False

View File

@ -103,3 +103,50 @@ class TestBaseCephClientCharm(CharmTestCase):
self.assertIsInstance(
self.harness.charm.unit.status,
BlockedStatus)
class CinderCharm(ops_openstack.plugins.classes.CinderStoragePluginCharm):
def cinder_configuration(self, cinder_config):
return [('volume_driver', 'my-driver'),
('some-config', 'some-value')]
class TestBaseCinderCharm(unittest.TestCase):
def setUp(self):
self.harness = Harness(
CinderCharm,
meta='''
name: cinder-test
provides:
storage-backend:
interface: cinder-backend
scope: container
requires:
juju-info:
interface: juju-info
scope: container
''',
config='''
options:
volume-backend-name:
default: ""
type: string
'''
)
self.addCleanup(self.harness.cleanup)
self.harness.begin()
self.harness.set_leader(True)
backend = self.harness.add_relation('storage-backend', 'cinder')
self.harness.update_config({'volume-backend-name': 'test'})
self.harness.add_relation_unit(backend, 'cinder/0')
def test_cinder_base(self):
self.assertEqual(self.harness.framework.model.app.name, 'cinder-test')
self.harness.update_config({})
self.assertTrue(isinstance(self.harness.model.unit.status,
ActiveStatus))
config = self.harness.charm.cinder_configuration({})
self.assertTrue(config[0], ('volume_driver', 'my-driver'))
self.assertTrue(config[1], ('some-config', 'some-value'))