Volans has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/363747 )

Change subject: Configuration: automatically load backend's aliases
......................................................................

Configuration: automatically load backend's aliases

* when loading the configuration, automatically load also any backend's
  aliases file present in the same directory of the configuration file.
  Support for aliases into the backends will be added next.
* improved tests fixture usage and removed usage of the example
  configuration present in the documentation from the tests.

Bug: T169640
Change-Id: Ief4c374408741af0e29d9bf07d8976b8f753d78d
---
M cumin/__init__.py
M cumin/tests/__init__.py
A cumin/tests/fixtures/config/empty/config.yaml
A cumin/tests/fixtures/config/invalid/config.yaml
A cumin/tests/fixtures/config/valid/config.yaml
A cumin/tests/fixtures/config/valid_with_aliases/config.yaml
A cumin/tests/fixtures/config/valid_with_aliases/direct_aliases.yaml
A cumin/tests/fixtures/config/valid_with_aliases/puppetdb_aliases.yaml
A cumin/tests/fixtures/config/valid_with_empty_aliases/config.yaml
A cumin/tests/fixtures/config/valid_with_empty_aliases/direct_aliases.yaml
A cumin/tests/fixtures/config/valid_with_empty_aliases/puppetdb_aliases.yaml
A cumin/tests/fixtures/config/valid_with_invalid_aliases/config.yaml
A cumin/tests/fixtures/config/valid_with_invalid_aliases/puppetdb_aliases.yaml
R cumin/tests/fixtures/grammar/invalid_grammars.txt
R cumin/tests/fixtures/grammar/valid_grammars.txt
M cumin/tests/unit/test_grammar.py
M cumin/tests/unit/test_init.py
17 files changed, 156 insertions(+), 24 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/software/cumin 
refs/changes/47/363747/1

diff --git a/cumin/__init__.py b/cumin/__init__.py
index 941208c..7d450dd 100644
--- a/cumin/__init__.py
+++ b/cumin/__init__.py
@@ -1,4 +1,7 @@
 """Automation and orchestration framework written in Python."""
+import os
+import pkgutil
+
 from pkg_resources import DistributionNotFound, get_distribution
 
 import yaml
@@ -29,6 +32,7 @@
         """
         if config not in cls._instances:
             cls._instances[config] = parse_config(config)
+            load_backend_aliases(cls._instances[config], 
os.path.dirname(config))
 
         return cls._instances[config]
 
@@ -52,3 +56,26 @@
         raise CuminError("Empty configuration found in 
'{config}'".format(config=config_file))
 
     return config
+
+
+def load_backend_aliases(config, base_path):
+    """Given a configuration, automatically add backend aliases from 
configuration files in the base_path directory.
+
+    It will look for files named {backend}_aliases.yaml in the base_path 
directory and will load it's content into the
+    main configuration under the 'aliases' key under the backend specific 
configuration, so that it will be accessible
+    by config[backend]['aliases'].
+
+    Arguments:
+    config    -- the configuration object to add the aliases to.
+    base_path -- the base path where to look for the aliases files.
+    """
+    abs_path = os.path.dirname(os.path.abspath(__file__))
+    backends = [name for _, name, _ in 
pkgutil.iter_modules([os.path.join(abs_path, 'backends')])]
+
+    for backend in backends:
+        alias_file = os.path.join(base_path, 
'{backend}_aliases.yaml'.format(backend=backend))
+        if os.path.isfile(alias_file):  # Do not fail if the alias file 
doesn't exists
+            if config.get(backend) is None:
+                config[backend] = {}
+
+            config[backend]['aliases'] = parse_config(alias_file)
diff --git a/cumin/tests/__init__.py b/cumin/tests/__init__.py
index 742e027..de0b2a3 100644
--- a/cumin/tests/__init__.py
+++ b/cumin/tests/__init__.py
@@ -7,17 +7,26 @@
 _TESTS_BASE_PATH = os.path.realpath(os.path.dirname(__file__))
 
 
-def get_fixture(filename, as_string=False):
+def get_fixture(path, as_string=False):
     """Return the content of a fixture file.
 
     Arguments:
-    filename  -- the file to be opened in the test's fixture directory
+    path      -- the relative path to the test's fixture directory to be 
opened.
     as_string -- return the content as a multiline string instead of a list of 
lines [optional, default: False]
     """
-    with open(os.path.join(_TESTS_BASE_PATH, 'fixtures', filename)) as f:
+    with open(get_fixture_path(path)) as f:
         if as_string:
             content = f.read()
         else:
             content = f.readlines()
 
     return content
+
+
+def get_fixture_path(path):
+    """Return the absolute path of the given fixture.
+
+    Arguments:
+    path      -- the relative path to the test's fixture directory.
+    """
+    return os.path.join(_TESTS_BASE_PATH, 'fixtures', path)
diff --git a/cumin/tests/fixtures/config/empty/config.yaml 
b/cumin/tests/fixtures/config/empty/config.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cumin/tests/fixtures/config/empty/config.yaml
diff --git a/cumin/tests/fixtures/config/invalid/config.yaml 
b/cumin/tests/fixtures/config/invalid/config.yaml
new file mode 100644
index 0000000..64c7e22
--- /dev/null
+++ b/cumin/tests/fixtures/config/invalid/config.yaml
@@ -0,0 +1,3 @@
+key:
+  other_key: value
+  - invalid_item
diff --git a/cumin/tests/fixtures/config/valid/config.yaml 
b/cumin/tests/fixtures/config/valid/config.yaml
new file mode 100644
index 0000000..b3591c0
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid/config.yaml
@@ -0,0 +1,17 @@
+backend: puppetdb
+transport: clustershell
+log_file: logs/cumin.log
+
+environment:
+    ENV_VARIABLE: env_value
+
+puppetdb:
+    host: puppetdb.local
+    port: 443
+    urllib3_disable_warnings:
+        - SubjectAltNameWarning
+
+clustershell:
+    ssh_options:
+        - 'some_option'
+    fanout: 16
diff --git a/cumin/tests/fixtures/config/valid_with_aliases/config.yaml 
b/cumin/tests/fixtures/config/valid_with_aliases/config.yaml
new file mode 120000
index 0000000..579f660
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_aliases/config.yaml
@@ -0,0 +1 @@
+../valid/config.yaml
\ No newline at end of file
diff --git a/cumin/tests/fixtures/config/valid_with_aliases/direct_aliases.yaml 
b/cumin/tests/fixtures/config/valid_with_aliases/direct_aliases.yaml
new file mode 100644
index 0000000..10aef29
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_aliases/direct_aliases.yaml
@@ -0,0 +1,3 @@
+group1: host10[10-22].example.org
+group2: host20[10-22].example.org
+group_all: A:group1 OR A:group2
diff --git 
a/cumin/tests/fixtures/config/valid_with_aliases/puppetdb_aliases.yaml 
b/cumin/tests/fixtures/config/valid_with_aliases/puppetdb_aliases.yaml
new file mode 100644
index 0000000..a98bad3
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_aliases/puppetdb_aliases.yaml
@@ -0,0 +1,3 @@
+role1: R:Class = Role::Role1
+dc1: '*.dc1.example.org'
+group_all: A:role1 AND A:dc1
diff --git a/cumin/tests/fixtures/config/valid_with_empty_aliases/config.yaml 
b/cumin/tests/fixtures/config/valid_with_empty_aliases/config.yaml
new file mode 120000
index 0000000..579f660
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_empty_aliases/config.yaml
@@ -0,0 +1 @@
+../valid/config.yaml
\ No newline at end of file
diff --git 
a/cumin/tests/fixtures/config/valid_with_empty_aliases/direct_aliases.yaml 
b/cumin/tests/fixtures/config/valid_with_empty_aliases/direct_aliases.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_empty_aliases/direct_aliases.yaml
diff --git 
a/cumin/tests/fixtures/config/valid_with_empty_aliases/puppetdb_aliases.yaml 
b/cumin/tests/fixtures/config/valid_with_empty_aliases/puppetdb_aliases.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_empty_aliases/puppetdb_aliases.yaml
diff --git a/cumin/tests/fixtures/config/valid_with_invalid_aliases/config.yaml 
b/cumin/tests/fixtures/config/valid_with_invalid_aliases/config.yaml
new file mode 120000
index 0000000..579f660
--- /dev/null
+++ b/cumin/tests/fixtures/config/valid_with_invalid_aliases/config.yaml
@@ -0,0 +1 @@
+../valid/config.yaml
\ No newline at end of file
diff --git 
a/cumin/tests/fixtures/config/valid_with_invalid_aliases/puppetdb_aliases.yaml 
b/cumin/tests/fixtures/config/valid_with_invalid_aliases/puppetdb_aliases.yaml
new file mode 100644
index 0000000..0bc3a7c
--- /dev/null
+++ 
b/cumin/tests/fixtures/config/valid_with_invalid_aliases/puppetdb_aliases.yaml
@@ -0,0 +1,2 @@
+name: query
+- invalid_name
diff --git a/cumin/tests/fixtures/invalid_grammars.txt 
b/cumin/tests/fixtures/grammar/invalid_grammars.txt
similarity index 100%
rename from cumin/tests/fixtures/invalid_grammars.txt
rename to cumin/tests/fixtures/grammar/invalid_grammars.txt
diff --git a/cumin/tests/fixtures/valid_grammars.txt 
b/cumin/tests/fixtures/grammar/valid_grammars.txt
similarity index 100%
rename from cumin/tests/fixtures/valid_grammars.txt
rename to cumin/tests/fixtures/grammar/valid_grammars.txt
diff --git a/cumin/tests/unit/test_grammar.py b/cumin/tests/unit/test_grammar.py
index 2c78319..b006fd3 100644
--- a/cumin/tests/unit/test_grammar.py
+++ b/cumin/tests/unit/test_grammar.py
@@ -1,5 +1,7 @@
 """Grammar tests."""
 
+import os
+
 from cumin.grammar import grammar
 from cumin.tests import get_fixture
 
@@ -13,13 +15,14 @@
 
 def test_valid_strings():
     """Run quick pyparsing test over valid grammar strings."""
-    results = grammar.runTests(get_fixture('valid_grammars.txt', 
as_string=True))
+    results = grammar.runTests(get_fixture(os.path.join('grammar', 
'valid_grammars.txt'), as_string=True))
     assert results[0]
 
 
 def test_invalid_strings():
     """Run quick pyparsing test over invalid grammar strings."""
-    results = grammar.runTests(get_fixture('invalid_grammars.txt', 
as_string=True), failureTests=True)
+    results = grammar.runTests(
+        get_fixture(os.path.join('grammar', 'invalid_grammars.txt'), 
as_string=True), failureTests=True)
     assert results[0]
 
 
diff --git a/cumin/tests/unit/test_init.py b/cumin/tests/unit/test_init.py
index 12a9608..c2b9e3f 100644
--- a/cumin/tests/unit/test_init.py
+++ b/cumin/tests/unit/test_init.py
@@ -1,23 +1,62 @@
 """Cumin package tests."""
+# pylint: disable=invalid-name
 import os
-import tempfile
 
 import pytest
 
 import cumin
 
+from cumin.tests import get_fixture_path
 
-def test_config_class_instantiation():
+
+def test_config_class_valid():
     """Should return the config. Multiple Config with the same path should 
return the same object."""
-    config1 = cumin.Config('doc/examples/config.yaml')
+    config_file = get_fixture_path(os.path.join('config', 'valid', 
'config.yaml'))
+    config1 = cumin.Config(config=config_file)
     assert 'log_file' in config1
-    config2 = cumin.Config('doc/examples/config.yaml')
+    config2 = cumin.Config(config=config_file)
     assert config1 is config2
+
+
+def test_config_class_empty():
+    """A CuminError is raised if the configuration is empty."""
+    with pytest.raises(cumin.CuminError, match='Empty configuration found in'):
+        cumin.Config(config=get_fixture_path(os.path.join('config', 'empty', 
'config.yaml')))
+
+
+def test_config_class_invalid():
+    """A CuminError is raised if the configuration cannot be parsed."""
+    with pytest.raises(cumin.CuminError, match='Unable to parse configuration 
file'):
+        cumin.Config(config=get_fixture_path(os.path.join('config', 'invalid', 
'config.yaml')))
+
+
+def test_config_class_valid_with_aliases():
+    """Should return the config including the backend aliases."""
+    config = cumin.Config(config=get_fixture_path(os.path.join('config', 
'valid_with_aliases', 'config.yaml')))
+    assert 'log_file' in config
+    assert 'aliases' in config['puppetdb']
+    assert 'role1' in config['puppetdb']['aliases']
+    assert config['puppetdb']['aliases']['role1'] == 'R:Class = Role::Role1'
+    assert 'aliases' in config['direct']
+    assert 'group1' in config['direct']['aliases']
+    assert config['direct']['aliases']['group1'] == 'host10[10-22].example.org'
+
+
+def test_config_class_empty_aliases():
+    """A CuminError is raised if one of the backend aliases is empty."""
+    with pytest.raises(cumin.CuminError, match='Empty configuration found in'):
+        cumin.Config(config=get_fixture_path(os.path.join('config', 
'valid_with_empty_aliases', 'config.yaml')))
+
+
+def test_config_class_invalid_aliases():
+    """A CuminError is raised if one of the backend aliases is invalid."""
+    with pytest.raises(cumin.CuminError, match='Unable to parse configuration 
file'):
+        cumin.Config(config=get_fixture_path(os.path.join('config', 
'valid_with_invalid_aliases', 'config.yaml')))
 
 
 def test_parse_config_ok():
     """The configuration file is properly parsed and accessible."""
-    config = cumin.parse_config('doc/examples/config.yaml')
+    config = cumin.parse_config(get_fixture_path(os.path.join('config', 
'valid', 'config.yaml')))
     assert 'log_file' in config
 
 
@@ -29,23 +68,46 @@
 
 def test_parse_config_invalid():
     """A CuminError is raised if the configuration cannot be parsed."""
-    invalid_yaml = '\n'.join((
-        'foo:',
-        '  bar: baz',
-        '  - foobar',
-    ))
-    tmpfile, tmpfilepath = tempfile.mkstemp(suffix='config.yaml', 
prefix='cumin', text=True)
-    os.write(tmpfile, invalid_yaml)
-
     with pytest.raises(cumin.CuminError, match='Unable to parse configuration 
file'):
-        cumin.parse_config(tmpfilepath)
+        cumin.parse_config(get_fixture_path(os.path.join('config', 'invalid', 
'config.yaml')))
 
 
 def test_parse_config_empty():
     """A CuminError is raised if the configuration is empty."""
-    empty_yaml = ''
-    tmpfile, tmpfilepath = tempfile.mkstemp(suffix='config.yaml', 
prefix='cumin', text=True)
-    os.write(tmpfile, empty_yaml)
-
     with pytest.raises(cumin.CuminError, match='Empty configuration found in'):
-        cumin.parse_config(tmpfilepath)
+        cumin.parse_config(get_fixture_path(os.path.join('config', 'empty', 
'config.yaml')))
+
+
+def test_load_backend_aliases_missing():
+    """If no aliases file is present, load_backend_aliases() should not raise 
any error."""
+    base_path = get_fixture_path(os.path.join('config', 'valid'))
+    config = {}
+    cumin.load_backend_aliases(config, base_path)
+    assert config == {}
+
+
+def test_load_backend_aliases_valid():
+    """If valid aliases files are present, load_backend_aliases() should load 
them into the configuration."""
+    base_path = get_fixture_path(os.path.join('config', 'valid_with_aliases'))
+    config = {'direct': {}}
+    cumin.load_backend_aliases(config, base_path)
+    assert 'aliases' in config['puppetdb']
+    assert 'role1' in config['puppetdb']['aliases']
+    assert config['puppetdb']['aliases']['role1'] == 'R:Class = Role::Role1'
+    assert 'aliases' in config['direct']
+    assert 'group1' in config['direct']['aliases']
+    assert config['direct']['aliases']['group1'] == 'host10[10-22].example.org'
+
+
+def test_load_backend_aliases_empty():
+    """If empty aliases files are present, load_backend_aliases() should raise 
CuminError."""
+    base_path = get_fixture_path(os.path.join('config', 
'valid_with_empty_aliases'))
+    with pytest.raises(cumin.CuminError, match='Empty configuration found in'):
+        cumin.load_backend_aliases({}, base_path)
+
+
+def test_load_backend_aliases_invalid():
+    """If invalid aliases files are present, load_backend_aliases() should 
raise CuminError."""
+    base_path = get_fixture_path(os.path.join('config', 
'valid_with_invalid_aliases'))
+    with pytest.raises(cumin.CuminError, match='Unable to parse configuration 
file'):
+        cumin.load_backend_aliases({}, base_path)

-- 
To view, visit https://gerrit.wikimedia.org/r/363747
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ief4c374408741af0e29d9bf07d8976b8f753d78d
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/cumin
Gerrit-Branch: master
Gerrit-Owner: Volans <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to