From 0905362f0470279b1526c706f48904418f57edbe Mon Sep 17 00:00:00 2001 From: Chris MacNaughton Date: Thu, 29 Sep 2022 09:56:49 -0400 Subject: [PATCH] rewrite create-erasure-profile with ops famework Change-Id: I27b0e926865ecb39ad4f5ad25de8266e9db75695 --- actions/create-erasure-profile | 1 - src/charm.py | 3 + src/ops_actions/__init__.py | 1 + .../ops_actions}/create_erasure_profile.py | 70 ++++++------ unit_tests/test_ceph_actions.py | 101 ++++++++++++++++++ 5 files changed, 139 insertions(+), 37 deletions(-) delete mode 120000 actions/create-erasure-profile rename {actions => src/ops_actions}/create_erasure_profile.py (69%) diff --git a/actions/create-erasure-profile b/actions/create-erasure-profile deleted file mode 120000 index e7625474..00000000 --- a/actions/create-erasure-profile +++ /dev/null @@ -1 +0,0 @@ -create_erasure_profile.py \ No newline at end of file diff --git a/src/charm.py b/src/charm.py index 7ea17a3d..c16cffaa 100755 --- a/src/charm.py +++ b/src/charm.py @@ -153,6 +153,9 @@ class CephMonCharm(ops_openstack.core.OSBaseCharm): ops_actions.copy_pool.copy_pool) self._observe_action(self.on.create_crush_rule_action, ops_actions.create_crush_rule.create_crush_rule) + self._observe_action( + self.on.create_erasure_profile_action, + ops_actions.create_erasure_profile.create_erasure_profile_action) fw.observe(self.on.install, self.on_install) fw.observe(self.on.config_changed, self.on_config) diff --git a/src/ops_actions/__init__.py b/src/ops_actions/__init__.py index 571988ef..8711e196 100644 --- a/src/ops_actions/__init__.py +++ b/src/ops_actions/__init__.py @@ -16,4 +16,5 @@ from . import ( # noqa: F401 change_osd_weight, copy_pool, create_crush_rule, + create_erasure_profile, ) diff --git a/actions/create_erasure_profile.py b/src/ops_actions/create_erasure_profile.py similarity index 69% rename from actions/create_erasure_profile.py rename to src/ops_actions/create_erasure_profile.py index 40673d7e..d84285be 100755 --- a/actions/create_erasure_profile.py +++ b/src/ops_actions/create_erasure_profile.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright 2016 Canonical Ltd +# Copyright 2022 Canonical Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,16 +17,18 @@ from subprocess import CalledProcessError from charmhelpers.contrib.storage.linux.ceph import create_erasure_profile -from charmhelpers.core.hookenv import action_get, log, action_fail +import logging + +logger = logging.getLogger(__name__) -def make_erasure_profile(): - name = action_get("name") - plugin = action_get("plugin") - failure_domain = action_get("failure-domain") - device_class = action_get("device-class") - k = action_get("data-chunks") - m = action_get("coding-chunks") +def create_erasure_profile_action(event): + name = event.params.get("name") + plugin = event.params.get("plugin") + failure_domain = event.params.get("failure-domain") + device_class = event.params.get("device-class") + k = event.params.get("data-chunks") + m = event.params.get("coding-chunks") # jerasure requires k+m # isa requires k+m @@ -43,9 +45,9 @@ def make_erasure_profile(): failure_domain=failure_domain, device_class=device_class) except CalledProcessError as e: - log(e) - action_fail("Create erasure profile failed with " - "message: {}".format(str(e))) + logger.warning(e) + event.fail("Create erasure profile failed with " + "message: {}".format(str(e))) elif plugin == "isa": try: create_erasure_profile(service='admin', @@ -56,12 +58,12 @@ def make_erasure_profile(): failure_domain=failure_domain, device_class=device_class) except CalledProcessError as e: - log(e) - action_fail("Create erasure profile failed with " - "message: {}".format(str(e))) + logger.warning(e) + event.fail("Create erasure profile failed with " + "message: {}".format(str(e))) elif plugin == "lrc": - locality_chunks = action_get("locality-chunks") - crush_locality = action_get('crush-locality') + locality_chunks = event.params.get("locality-chunks") + crush_locality = event.params.get('crush-locality') try: create_erasure_profile(service='admin', erasure_plugin_name=plugin, @@ -73,11 +75,11 @@ def make_erasure_profile(): failure_domain=failure_domain, device_class=device_class) except CalledProcessError as e: - log(e) - action_fail("Create erasure profile failed with " - "message: {}".format(str(e))) + logger.warning(e) + event.fail("Create erasure profile failed with " + "message: {}".format(str(e))) elif plugin == "shec": - c = action_get("durability-estimator") + c = event.params.get("durability-estimator") try: create_erasure_profile(service='admin', erasure_plugin_name=plugin, @@ -88,12 +90,12 @@ def make_erasure_profile(): failure_domain=failure_domain, device_class=device_class) except CalledProcessError as e: - log(e) - action_fail("Create erasure profile failed with " - "message: {}".format(str(e))) + logger.warning(e) + event.fail("Create erasure profile failed with " + "message: {}".format(str(e))) elif plugin == "clay": - d = action_get("helper-chunks") - scalar_mds = action_get('scalar-mds') + d = event.params.get("helper-chunks") + scalar_mds = event.params.get('scalar-mds') try: create_erasure_profile(service='admin', erasure_plugin_name=plugin, @@ -105,15 +107,11 @@ def make_erasure_profile(): failure_domain=failure_domain, device_class=device_class) except CalledProcessError as e: - log(e) - action_fail("Create erasure profile failed with " - "message: {}".format(str(e))) + logger.warning(e) + event.fail("Create erasure profile failed with " + "message: {}".format(str(e))) else: # Unknown erasure plugin - action_fail("Unknown erasure-plugin type of {}. " - "Only jerasure, isa, lrc, shec or clay is " - "allowed".format(plugin)) - - -if __name__ == '__main__': - make_erasure_profile() + event.fail("Unknown erasure-plugin type of {}. " + "Only jerasure, isa, lrc, shec or clay is " + "allowed".format(plugin)) diff --git a/unit_tests/test_ceph_actions.py b/unit_tests/test_ceph_actions.py index 9b7d84fc..514b5dbb 100644 --- a/unit_tests/test_ceph_actions.py +++ b/unit_tests/test_ceph_actions.py @@ -129,3 +129,104 @@ class CreateCrushRuleTestCase(test_utils.CharmTestCase): mock_check_call.assert_called_once_with(expected) event.fail.assert_called_once_with( 'rule creation failed due to exception') + + +class CreateErasureProfileTestCase(test_utils.CharmTestCase): + """Run tests for action.""" + + def setUp(self): + self.harness = Harness(CephMonCharm) + self.addCleanup(self.harness.cleanup) + + @mock.patch('ops_actions.create_erasure_profile.create_erasure_profile') + def test_create_jerasure_profile(self, mock_create_erasure_profile): + self.harness.begin() + self.harness.charm.on_create_erasure_profile_action( + test_utils.MockActionEvent({ + 'name': 'erasure', + 'plugin': 'jerasure', + 'failure-domain': 'disk', + 'k': 6, + 'm': 3, + })) + mock_create_erasure_profile.assert_called_once_with( + service='admin', erasure_plugin_name='jerasure', + profile_name='erasure', data_chunks=None, + coding_chunks=None, failure_domain='disk', device_class=None + ) + + @mock.patch('ops_actions.create_erasure_profile.create_erasure_profile') + def test_create_isa_profile(self, mock_create_erasure_profile): + self.harness.begin() + self.harness.charm.on_create_erasure_profile_action( + test_utils.MockActionEvent({ + 'name': 'erasure', + 'plugin': 'isa', + 'failure-domain': 'disk', + 'k': 6, + 'm': 3, + })) + mock_create_erasure_profile.assert_called_once_with( + service='admin', erasure_plugin_name='isa', + profile_name='erasure', data_chunks=None, + coding_chunks=None, failure_domain='disk', device_class=None + ) + + @mock.patch('ops_actions.create_erasure_profile.create_erasure_profile') + def test_create_lrc_profile(self, mock_create_erasure_profile): + self.harness.begin() + self.harness.charm.on_create_erasure_profile_action( + test_utils.MockActionEvent({ + 'name': 'erasure', + 'plugin': 'lrc', + 'failure-domain': 'disk', + 'k': 6, + 'm': 3, + 'locality-chunks': 2, + 'crush-locality': 'host', + })) + mock_create_erasure_profile.assert_called_once_with( + service='admin', erasure_plugin_name='lrc', + profile_name='erasure', data_chunks=None, + coding_chunks=None, locality=2, crush_locality='host', + failure_domain='disk', device_class=None + ) + + @mock.patch('ops_actions.create_erasure_profile.create_erasure_profile') + def test_create_shec_profile(self, mock_create_erasure_profile): + self.harness.begin() + self.harness.charm.on_create_erasure_profile_action( + test_utils.MockActionEvent({ + 'name': 'erasure', + 'plugin': 'shec', + 'failure-domain': 'disk', + 'k': 6, + 'm': 3, + 'durability-estimator': 2 + })) + mock_create_erasure_profile.assert_called_once_with( + service='admin', erasure_plugin_name='shec', + profile_name='erasure', data_chunks=None, + coding_chunks=None, durability_estimator=2, + failure_domain='disk', device_class=None + ) + + @mock.patch('ops_actions.create_erasure_profile.create_erasure_profile') + def test_create_clay_profile(self, mock_create_erasure_profile): + self.harness.begin() + self.harness.charm.on_create_erasure_profile_action( + test_utils.MockActionEvent({ + 'name': 'erasure', + 'plugin': 'clay', + 'failure-domain': 'disk', + 'k': 6, + 'm': 3, + 'helper-chunks': 2, + 'scalar-mds': 'jerasure' + })) + mock_create_erasure_profile.assert_called_once_with( + service='admin', erasure_plugin_name='clay', + profile_name='erasure', data_chunks=None, + coding_chunks=None, helper_chunks=2, + scalar_mds='jerasure', failure_domain='disk', device_class=None + )