Handle missing/invalid mandatory options

Change-Id: I54d8989bfb374a1fa07dfc145428e546d3839264
diff --git a/src/charm.py b/src/charm.py
index d40d3b3..7c260c7 100755
--- a/src/charm.py
+++ b/src/charm.py
@@ -14,10 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import logging
 
 from ops_openstack.plugins.classes import CinderStoragePluginCharm
 from ops_openstack.core import charm_class, get_charm_class
 from ops.main import main
+from ops.model import BlockedStatus
+
+logger = logging.getLogger(__name__)
 
 
 class CinderCharmBase(CinderStoragePluginCharm):
@@ -31,10 +35,44 @@
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
+    def _check_for_config_errors(self, config):
+        missing = []
+        for mandatory in self.MANDATORY_CONFIG:
+            if mandatory not in config:
+                missing.append(mandatory)
+
+        if missing:
+            return f"Mandatory options are missing: {', '.join(missing)}"
+
+        if config["protocol"] not in ["block", "iscsi"]:
+            return (
+                f"""Invalid 'protocol' option provided: '{config["protocol"]}';"""
+                "valid are 'block' and 'iscsi'"
+            )
+
+        if config["protocol"] == "block":
+            return "'protocol' value 'block' not yet supported"
+
+    def on_config(self, event):
+        config = dict(self.framework.model.config)
+        conf_error = self._check_for_config_errors(config)
+        if conf_error is not None:
+            logger.error(conf_error)
+            self.unit.status = BlockedStatus(conf_error)
+            return
+
+        super().on_config(event)
+
     def cinder_configuration(self, config):
+        conf_error = self._check_for_config_errors(config)
+        if conf_error is not None:
+            logger.error(conf_error)
+            return []
+
         # Return the configuration to be set by the principal.
         backend_name = config.get("volume-backend-name", self.framework.model.app.name)
         volume_driver = "cinder.volume.drivers.storpool.StorPoolDriver"
+
         options = [
             ("volume_driver", volume_driver),
             ("volume_backend_name", backend_name),
diff --git a/unit_tests/test_cinder_storpool_charm.py b/unit_tests/test_cinder_storpool_charm.py
index 2399857..78111d8 100644
--- a/unit_tests/test_cinder_storpool_charm.py
+++ b/unit_tests/test_cinder_storpool_charm.py
@@ -14,7 +14,7 @@
 
 import unittest
 from src.charm import CinderCharmBase
-from ops.model import ActiveStatus
+from ops.model import ActiveStatus, BlockedStatus
 from ops.testing import Harness
 
 
@@ -41,6 +41,19 @@
         self.assertTrue(conf.get("use_multipath_for_image_xfer"))
         self.assertTrue(conf.get("enforce_multipath_for_image_xfer"))
 
-    def test_cinder_configuration(self):
-        # Add check here that configuration is as expected.
-        pass
+    def test_invalid_cinder_configurations(self):
+        self.harness.update_config({"protocol": "block"})
+        self.assertTrue(isinstance(self.harness.model.unit.status, BlockedStatus))
+
+        self.harness.update_config({"protocol": "iscsi"})
+        self.assertTrue(isinstance(self.harness.model.unit.status, ActiveStatus))
+
+        self.harness.update_config({"protocol": "something_invalid"})
+        self.assertTrue(isinstance(self.harness.model.unit.status, BlockedStatus))
+
+        self.harness.update_config({"protocol": "iscsi"})
+        self.assertTrue(isinstance(self.harness.model.unit.status, ActiveStatus))
+
+        # Cannot test for missing options with default values as it seems the
+        # defaults are applied after update_config() below:
+        # self.harness.update_config(unset=["protocol"])