Repository: chaostoolkit/chaostoolkit-lib

Issue:
Bail cleanly when environment key was not found
It appears the toolkit doesn't tell you when a key couldn't be found in the environment. 

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54b1a3c..ff3263c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,20 @@
 
 ## [Unreleased][]
 
-[Unreleased]: https://github.com/chaostoolkit/chaostoolkit-lib/compare/0.15.0...HEAD
+[Unreleased]: https://github.com/chaostoolkit/chaostoolkit-lib/compare/0.15.1...HEAD
+
+## [0.15.1][] - 2018-03-09
+
+[0.15.1]: https://github.com/chaostoolkit/chaostoolkit-lib/compare/0.15.0...0.15.1
+
+### Changed
+
+-   Log a message wgen loding the configuration 
+-   Raise `InvalidExperiment` when a configuration or secret references a key
+    in the environment and that key does not exist (it may not be set however)
+    [#40][40]. This bails the experiment at validation time so before it runs.
+
+[40]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/40
 
 ## [0.15.0][] - 2018-02-20
 
diff --git a/chaoslib/__init__.py b/chaoslib/__init__.py
index ebb5445..e2065c9 100644
--- a/chaoslib/__init__.py
+++ b/chaoslib/__init__.py
@@ -6,7 +6,7 @@ from typing import Any, Dict, List, Mapping, Union
 from chaoslib.types import Configuration, Secrets
 
 __all__ = ["__version__", "substitute"]
-__version__ = '0.15.0'
+__version__ = '0.15.1'
 
 
 def substitute(data: Union[str, Dict[str, Any], List],
diff --git a/chaoslib/configuration.py b/chaoslib/configuration.py
index cb34bd4..4d97032 100644
--- a/chaoslib/configuration.py
+++ b/chaoslib/configuration.py
@@ -4,6 +4,7 @@ from typing import Dict
 
 from logzero import logger
 
+from chaoslib.exceptions import InvalidExperiment
 from chaoslib.types import Configuration
 
 __all__ = ["load_configuration"]
@@ -32,13 +33,19 @@ def load_configuration(config_info: Dict[str, str]) -> Configuration:
     configuration key is dynamically fetched from the `MY_TOKEN` environment
     variable.
     """
+    logger.debug("Loading configuration...")
     env = os.environ
     conf = {}
 
     for (key, value) in config_info.items():
         if isinstance(value, dict) and "type" in value:
             if value["type"] == "env":
-                conf[key] = env.get(value["key"])
+                env_key = value["key"]
+                if env_key not in env:
+                    raise InvalidExperiment(
+                        "Configuration makes reference to an environment key"
+                        " that does not exist: {}".format(env_key))
+                conf[key] = env.get(env_key)
         else:
             conf[key] = value
 
diff --git a/chaoslib/experiment.py b/chaoslib/experiment.py
index 4bcd6f6..b909733 100644
--- a/chaoslib/experiment.py
+++ b/chaoslib/experiment.py
@@ -73,6 +73,9 @@ def ensure_experiment_is_valid(experiment: Experiment):
             raise InvalidExperiment(
                 "experiment tags must be a non-empty string")
 
+    config = load_configuration(experiment.get("configuration", {}))
+    secrets = load_secrets(experiment.get("secrets", {}), config)
+
     ensure_hypothesis_is_valid(experiment)
 
     method = experiment.get("method")
diff --git a/chaoslib/secret.py b/chaoslib/secret.py
index dfe1dd2..a272151 100644
--- a/chaoslib/secret.py
+++ b/chaoslib/secret.py
@@ -10,6 +10,7 @@ try:
 except ImportError:
     HAS_HVAC = False
 
+from chaoslib.exceptions import InvalidExperiment
 from chaoslib.types import Configuration, Secrets
 
 __all__ = ["load_secrets"]
@@ -123,7 +124,12 @@ def load_secrets_from_env(secrets_info: Dict[str, Dict[str, str]],
 
         for (key, value) in keys.items():
             if isinstance(value, dict) and value.get("type") == "env":
-                secrets[target][key] = env.get(value["key"])
+                env_key = value["key"]
+                if env_key not in env:
+                    raise InvalidExperiment(
+                        "Secrets make reference to an environment key "
+                        "that does not exist: {}".format(env_key))
+                secrets[target][key] = env.get(env_key)
 
         if not secrets[target]:
             secrets.pop(target)


Test patch:
diff --git a/tests/fixtures/experiments.py b/tests/fixtures/experiments.py
index 627ce70..757f6f4 100644
--- a/tests/fixtures/experiments.py
+++ b/tests/fixtures/experiments.py
@@ -160,3 +160,11 @@ Experiment = {
         }
     ]
 }
+
+ExperimentWithConfigurationCallingMissingEnvKey = Experiment.copy()
+ExperimentWithConfigurationCallingMissingEnvKey["configuration"] = {
+    "mykey": {
+        "type": "env",
+        "key": "DOES_NOT_EXIST"
+    }
+}
\ No newline at end of file
diff --git a/tests/test_experiment.py b/tests/test_experiment.py
index 28046b4..444746f 100644
--- a/tests/test_experiment.py
+++ b/tests/test_experiment.py
@@ -152,3 +152,12 @@ def test_experiment_may_run_without_steady_state():
 
     journal = run_experiment(experiment)
     assert journal is not None
+
+
+def test_should_bail_experiment_when_env_was_not_found():
+    experiment = experiments.ExperimentWithConfigurationCallingMissingEnvKey
+
+    with pytest.raises(InvalidExperiment) as x:
+        run_experiment(experiment)
+    assert "Configuration makes reference to an environment key that does " \
+           "not exist" in str(x)
\ No newline at end of file