[MediaWiki-commits] [Gerrit] operations...cumin[master]: Move configuration loader from cli to main module

2017-07-11 Thread jenkins-bot (Code Review)
jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/363746 )

Change subject: Move configuration loader from cli to main module
..


Move configuration loader from cli to main module

* add a cumin.Config class
* move the parse_config helper to cumin's main module from the cli one,
  to allow to easily load the configuration also when it's used as a
  library.

Bug: T169640
Change-Id: I924f0731268e15249be30e5b5482918f2d853265
---
M cumin/__init__.py
M cumin/cli.py
M cumin/tests/unit/test_cli.py
A cumin/tests/unit/test_init.py
4 files changed, 94 insertions(+), 52 deletions(-)

Approvals:
  Giuseppe Lavagetto: Looks good to me, but someone else must approve
  jenkins-bot: Verified
  Volans: Looks good to me, approved



diff --git a/cumin/__init__.py b/cumin/__init__.py
index 9e70e4c..941208c 100644
--- a/cumin/__init__.py
+++ b/cumin/__init__.py
@@ -1,6 +1,8 @@
 """Automation and orchestration framework written in Python."""
 from pkg_resources import DistributionNotFound, get_distribution
 
+import yaml
+
 
 try:
 __version__ = get_distribution(__name__).version
@@ -10,3 +12,43 @@
 
 class CuminError(Exception):
 """Base Exception class for all Cumin's custom Exceptions."""
+
+
+class Config(dict):
+"""Singleton-like dictionary class to load the configuration from a given 
path only once."""
+
+_instances = {}  # Keep track of different loaded configurations
+
+def __new__(cls, config='/etc/cumin/config.yaml'):
+"""Load the given configuration if not already loaded and return it.
+
+Called by Python's data model for each new instantiation of the class.
+
+Arguments:
+config -- path to the configuration file to load. [optional, default: 
/etc/cumin/config.yaml]
+"""
+if config not in cls._instances:
+cls._instances[config] = parse_config(config)
+
+return cls._instances[config]
+
+
+def parse_config(config_file):
+"""Parse the YAML configuration file.
+
+Arguments:
+config_file -- the path of the configuration file to load
+"""
+try:
+with open(config_file, 'r') as f:
+config = yaml.safe_load(f)
+except IOError as e:
+raise CuminError('Unable to read configuration file: 
{message}'.format(message=e))
+except yaml.parser.ParserError as e:
+raise CuminError("Unable to parse configuration file 
'{config}':\n{message}".format(
+config=config_file, message=e))
+
+if config is None:
+raise CuminError("Empty configuration found in 
'{config}'".format(config=config_file))
+
+return config
diff --git a/cumin/cli.py b/cumin/cli.py
index ae88a28..5bc038b 100644
--- a/cumin/cli.py
+++ b/cumin/cli.py
@@ -12,7 +12,6 @@
 from logging.handlers import RotatingFileHandler  # pylint: 
disable=ungrouped-imports
 
 import colorama
-import yaml
 
 from ClusterShell.NodeSet import NodeSet
 from tqdm import tqdm
@@ -171,27 +170,6 @@
 logger.setLevel(logging.DEBUG)
 else:
 logger.setLevel(logging.INFO)
-
-
-def parse_config(config_file):
-"""Parse the YAML configuration file.
-
-Arguments:
-config_file -- the path of the configuration file to load
-"""
-try:
-with open(config_file, 'r') as f:
-config = yaml.safe_load(f)
-except IOError as e:
-raise cumin.CuminError('Unable to read configuration file: 
{message}'.format(message=e))
-except yaml.parser.ParserError as e:
-raise cumin.CuminError("Unable to parse configuration file 
'{config}':\n{message}".format(
-config=config_file, message=e))
-
-if config is None:
-raise cumin.CuminError("Empty configuration found in 
'{config}'".format(config=config_file))
-
-return config
 
 
 def sigint_handler(*args):  # pylint: disable=unused-argument
@@ -375,7 +353,7 @@
 return 0
 
 user = get_running_user()
-config = parse_config(args.config)
+config = cumin.Config(args.config)
 setup_logging(config['log_file'], debug=args.debug)
 except cumin.CuminError as e:
 stderr(e)
diff --git a/cumin/tests/unit/test_cli.py b/cumin/tests/unit/test_cli.py
index cd9ace9..d7606fd 100644
--- a/cumin/tests/unit/test_cli.py
+++ b/cumin/tests/unit/test_cli.py
@@ -1,7 +1,4 @@
 """CLI tests."""
-import os
-import tempfile
-
 from logging import DEBUG, INFO
 
 import mock
@@ -78,32 +75,6 @@
 cli.setup_logging('filename', debug=True)
 logging.setLevel.assert_called_with(DEBUG)
 assert file_handler.called
-
-
-def test_parse_config_ok():
-"""The configuration file is properly parsed and accessible."""
-config = cli.parse_config('doc/examples/config.yaml')
-assert 'log_file' in config
-
-
-def test_parse_config_non_existent():
-"""A CuminError is raised if the configuration file is not available."""
-with pytest.raises(CuminError, 

[MediaWiki-commits] [Gerrit] operations...cumin[master]: Move configuration loader from cli to main module

2017-07-06 Thread Volans (Code Review)
Volans has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/363746 )

Change subject: Move configuration loader from cli to main module
..

Move configuration loader from cli to main module

* add a cumin.Config class
* move the parse_config helper to cumin's main module from the cli one,
  to allow to easily load the configuration also when it's used as a
  library.

Bug: T169640
Change-Id: I924f0731268e15249be30e5b5482918f2d853265
---
M cumin/__init__.py
M cumin/cli.py
M cumin/tests/unit/test_cli.py
A cumin/tests/unit/test_init.py
4 files changed, 94 insertions(+), 52 deletions(-)


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

diff --git a/cumin/__init__.py b/cumin/__init__.py
index 9e70e4c..941208c 100644
--- a/cumin/__init__.py
+++ b/cumin/__init__.py
@@ -1,6 +1,8 @@
 """Automation and orchestration framework written in Python."""
 from pkg_resources import DistributionNotFound, get_distribution
 
+import yaml
+
 
 try:
 __version__ = get_distribution(__name__).version
@@ -10,3 +12,43 @@
 
 class CuminError(Exception):
 """Base Exception class for all Cumin's custom Exceptions."""
+
+
+class Config(dict):
+"""Singleton-like dictionary class to load the configuration from a given 
path only once."""
+
+_instances = {}  # Keep track of different loaded configurations
+
+def __new__(cls, config='/etc/cumin/config.yaml'):
+"""Load the given configuration if not already loaded and return it.
+
+Called by Python's data model for each new instantiation of the class.
+
+Arguments:
+config -- path to the configuration file to load. [optional, default: 
/etc/cumin/config.yaml]
+"""
+if config not in cls._instances:
+cls._instances[config] = parse_config(config)
+
+return cls._instances[config]
+
+
+def parse_config(config_file):
+"""Parse the YAML configuration file.
+
+Arguments:
+config_file -- the path of the configuration file to load
+"""
+try:
+with open(config_file, 'r') as f:
+config = yaml.safe_load(f)
+except IOError as e:
+raise CuminError('Unable to read configuration file: 
{message}'.format(message=e))
+except yaml.parser.ParserError as e:
+raise CuminError("Unable to parse configuration file 
'{config}':\n{message}".format(
+config=config_file, message=e))
+
+if config is None:
+raise CuminError("Empty configuration found in 
'{config}'".format(config=config_file))
+
+return config
diff --git a/cumin/cli.py b/cumin/cli.py
index ae88a28..5bc038b 100644
--- a/cumin/cli.py
+++ b/cumin/cli.py
@@ -12,7 +12,6 @@
 from logging.handlers import RotatingFileHandler  # pylint: 
disable=ungrouped-imports
 
 import colorama
-import yaml
 
 from ClusterShell.NodeSet import NodeSet
 from tqdm import tqdm
@@ -171,27 +170,6 @@
 logger.setLevel(logging.DEBUG)
 else:
 logger.setLevel(logging.INFO)
-
-
-def parse_config(config_file):
-"""Parse the YAML configuration file.
-
-Arguments:
-config_file -- the path of the configuration file to load
-"""
-try:
-with open(config_file, 'r') as f:
-config = yaml.safe_load(f)
-except IOError as e:
-raise cumin.CuminError('Unable to read configuration file: 
{message}'.format(message=e))
-except yaml.parser.ParserError as e:
-raise cumin.CuminError("Unable to parse configuration file 
'{config}':\n{message}".format(
-config=config_file, message=e))
-
-if config is None:
-raise cumin.CuminError("Empty configuration found in 
'{config}'".format(config=config_file))
-
-return config
 
 
 def sigint_handler(*args):  # pylint: disable=unused-argument
@@ -375,7 +353,7 @@
 return 0
 
 user = get_running_user()
-config = parse_config(args.config)
+config = cumin.Config(args.config)
 setup_logging(config['log_file'], debug=args.debug)
 except cumin.CuminError as e:
 stderr(e)
diff --git a/cumin/tests/unit/test_cli.py b/cumin/tests/unit/test_cli.py
index cd9ace9..d7606fd 100644
--- a/cumin/tests/unit/test_cli.py
+++ b/cumin/tests/unit/test_cli.py
@@ -1,7 +1,4 @@
 """CLI tests."""
-import os
-import tempfile
-
 from logging import DEBUG, INFO
 
 import mock
@@ -78,32 +75,6 @@
 cli.setup_logging('filename', debug=True)
 logging.setLevel.assert_called_with(DEBUG)
 assert file_handler.called
-
-
-def test_parse_config_ok():
-"""The configuration file is properly parsed and accessible."""
-config = cli.parse_config('doc/examples/config.yaml')
-assert 'log_file' in config
-
-
-def test_parse_config_non_existent():
-"""A CuminError is raised if the configuration file is not available."""
-with pytest.raises(CuminError, match='Unable to read configuration file'):
-