[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#930776: marked as done (unblock: ionit/0.3.2-1)



Your message dated Fri, 21 Jun 2019 21:06:19 +0200
with message-id <0afd01d4-17bd-f43c-5877-a0919e6ed3ed@debian.org>
and subject line Re: Bug#930776: unblock: ionit/0.3.2-1
has caused the Debian Bug report #930776,
regarding unblock: ionit/0.3.2-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
930776: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=930776
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package ionit

ionit runs too late for /etc/network/interfaces (RC bug #919690). This
is fixed in 0.3.2-1. The debdiff is attached.

ionit is a quite new and very small tool (popcon count: 4), which is
developed and used by us. It has 100% test coverage (run at build time
and as autopkgtest).

unblock ionit/0.3.2-1

-- 
Benjamin Drung
System Developer
Debian & Ubuntu Developer

1&1 IONOS Cloud GmbH | Greifswalder Str. 207 | 10405 Berlin | Germany
E-mail: benjamin.drung@cloud.ionos.com | Web: www.ionos.de

Head Office: Berlin, Germany
District Court Berlin Charlottenburg, Registration number: HRB 125506 B
Executive Management: Christoph Steffens, Matthias Steinberg, Achim
Weiss

Member of United Internet
diff -Nru ionit-0.2.1/debian/changelog ionit-0.3.2/debian/changelog
--- ionit-0.2.1/debian/changelog	2019-01-07 14:22:30.000000000 +0100
+++ ionit-0.3.2/debian/changelog	2019-06-20 12:21:44.000000000 +0200
@@ -1,3 +1,13 @@
+ionit (0.3.2-1) unstable; urgency=medium
+
+  * New upstream release.
+    - Support specifying a configuration file
+    - Support specifying --config multiple times
+    - Run ionit.service before systemd-modules-load.service
+    - Run ionit.service before systemd-udev-trigger.service (Closes: #919690)
+
+ -- Benjamin Drung <benjamin.drung@cloud.ionos.com>  Thu, 20 Jun 2019 12:21:44 +0200
+
 ionit (0.2.1-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru ionit-0.2.1/ionit ionit-0.3.2/ionit
--- ionit-0.2.1/ionit	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/ionit	2019-06-20 12:17:42.000000000 +0200
@@ -28,6 +28,7 @@
 
 import ionit_plugin
 
+DEFAULT_CONFIG = "/etc/ionit"
 LOG_FORMAT = '%(asctime)s %(name)s %(levelname)s: %(message)s'
 SCRIPT_NAME = "ionit"
 
@@ -86,23 +87,34 @@
     return context
 
 
-def collect_context(directory):
+def get_config_files(paths):
+    """Return files for the given paths (could either be files or directories)."""
+    logger = logging.getLogger(SCRIPT_NAME)
+    files = []
+    for path in paths:
+        logger.debug("Searching for configuration files in '%s'...", path)
+        try:
+            if os.path.isfile(path):
+                files.append(path)
+            else:
+                files += sorted([os.path.join(path, f) for f in os.listdir(path)])
+        except OSError as error:
+            logger.warning("Failed to read configuration directory: %s", error)
+    logger.debug("Configuration files: %s", files)
+    return files
+
+
+def collect_context(paths):
     """Collect context that will be used when rendering the templates"""
     logger = logging.getLogger(SCRIPT_NAME)
-    logger.debug("Collecting context from '%s'...", directory)
-    try:
-        files = sorted(os.listdir(directory))
-    except OSError as error:
-        logger.warning("Failed to read configuration directory: %s", error)
-        files = []
+    logger.debug("Collecting context...")
 
     failures = 0
     context = {}
 
-    for filename in files:
+    for file in get_config_files(paths):
         file_context = None
-        file = os.path.join(directory, filename)
-        extension = os.path.splitext(filename)[1]
+        extension = os.path.splitext(file)[1]
         try:
             if extension == ".json":
                 logger.info("Reading configuration file '%s'...", file)
@@ -184,9 +196,9 @@
 def main(argv):
     """Main function with argument parsing"""
     parser = argparse.ArgumentParser()
-    parser.add_argument("-c", "--config", default="/etc/ionit",
-                        help="Configuration directory containing context for rendering (default: "
-                             "%(default)s)")
+    parser.add_argument("-c", "--config", action="append",
+                        help="Configuration directory/file containing context for rendering "
+                             "(default: %s)" % (DEFAULT_CONFIG,))
     parser.add_argument("-t", "--templates", default="/etc",
                         help="Directory to search for Jinja templates (default: %(default)s)")
     parser.add_argument("-e", "--template-extension", default="jinja",
@@ -197,6 +209,8 @@
                         help="Decrease output verbosity to warnings and errors",
                         action="store_const", const=logging.WARNING)
     args = parser.parse_args(argv)
+    if args.config is None:
+        args.config = [DEFAULT_CONFIG]
     logging.basicConfig(level=args.log_level, format=LOG_FORMAT)
     logger = logging.getLogger(SCRIPT_NAME)
 
diff -Nru ionit-0.2.1/ionit.py ionit-0.3.2/ionit.py
--- ionit-0.2.1/ionit.py	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/ionit.py	2019-06-20 12:17:42.000000000 +0200
@@ -28,6 +28,7 @@
 
 import ionit_plugin
 
+DEFAULT_CONFIG = "/etc/ionit"
 LOG_FORMAT = '%(asctime)s %(name)s %(levelname)s: %(message)s'
 SCRIPT_NAME = "ionit"
 
@@ -86,23 +87,34 @@
     return context
 
 
-def collect_context(directory):
+def get_config_files(paths):
+    """Return files for the given paths (could either be files or directories)."""
+    logger = logging.getLogger(SCRIPT_NAME)
+    files = []
+    for path in paths:
+        logger.debug("Searching for configuration files in '%s'...", path)
+        try:
+            if os.path.isfile(path):
+                files.append(path)
+            else:
+                files += sorted([os.path.join(path, f) for f in os.listdir(path)])
+        except OSError as error:
+            logger.warning("Failed to read configuration directory: %s", error)
+    logger.debug("Configuration files: %s", files)
+    return files
+
+
+def collect_context(paths):
     """Collect context that will be used when rendering the templates"""
     logger = logging.getLogger(SCRIPT_NAME)
-    logger.debug("Collecting context from '%s'...", directory)
-    try:
-        files = sorted(os.listdir(directory))
-    except OSError as error:
-        logger.warning("Failed to read configuration directory: %s", error)
-        files = []
+    logger.debug("Collecting context...")
 
     failures = 0
     context = {}
 
-    for filename in files:
+    for file in get_config_files(paths):
         file_context = None
-        file = os.path.join(directory, filename)
-        extension = os.path.splitext(filename)[1]
+        extension = os.path.splitext(file)[1]
         try:
             if extension == ".json":
                 logger.info("Reading configuration file '%s'...", file)
@@ -184,9 +196,9 @@
 def main(argv):
     """Main function with argument parsing"""
     parser = argparse.ArgumentParser()
-    parser.add_argument("-c", "--config", default="/etc/ionit",
-                        help="Configuration directory containing context for rendering (default: "
-                             "%(default)s)")
+    parser.add_argument("-c", "--config", action="append",
+                        help="Configuration directory/file containing context for rendering "
+                             "(default: %s)" % (DEFAULT_CONFIG,))
     parser.add_argument("-t", "--templates", default="/etc",
                         help="Directory to search for Jinja templates (default: %(default)s)")
     parser.add_argument("-e", "--template-extension", default="jinja",
@@ -197,6 +209,8 @@
                         help="Decrease output verbosity to warnings and errors",
                         action="store_const", const=logging.WARNING)
     args = parser.parse_args(argv)
+    if args.config is None:
+        args.config = [DEFAULT_CONFIG]
     logging.basicConfig(level=args.log_level, format=LOG_FORMAT)
     logger = logging.getLogger(SCRIPT_NAME)
 
diff -Nru ionit-0.2.1/ionit.service ionit-0.3.2/ionit.service
--- ionit-0.2.1/ionit.service	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/ionit.service	2019-06-20 12:17:42.000000000 +0200
@@ -3,7 +3,7 @@
 Documentation=man:ionit(1)
 DefaultDependencies=no
 After=local-fs.target
-Before=ferm.service network-pre.target openibd.service shutdown.target sysinit.target
+Before=ferm.service network-pre.target openibd.service shutdown.target sysinit.target systemd-modules-load.service systemd-udev-trigger.service
 Wants=network-pre.target
 RequiresMountsFor=/usr
 
diff -Nru ionit-0.2.1/NEWS ionit-0.3.2/NEWS
--- ionit-0.2.1/NEWS	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/NEWS	2019-06-20 12:17:42.000000000 +0200
@@ -1,3 +1,17 @@
+ionit 0.3.2 (2019-06-20)
+
+* Run ionit.service before systemd-udev-trigger.service
+  (fixes Debian bug #919690)
+
+ionit 0.3.1 (2019-04-11)
+
+* Run ionit.service before systemd-modules-load.service
+
+ionit 0.3.0 (2019-02-20)
+
+* Support specifying a configuration file (instead of a directory)
+* Support specifying --config multiple times
+
 ionit 0.2.1 (2019-01-07)
 
 * Remove unnecessary pass statement to make pylint 2.2.2 happy
diff -Nru ionit-0.2.1/setup.py ionit-0.3.2/setup.py
--- ionit-0.2.1/setup.py	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/setup.py	2019-06-20 12:17:42.000000000 +0200
@@ -34,7 +34,7 @@
 if __name__ == "__main__":
     setup(
         name="ionit",
-        version="0.2.1",
+        version="0.3.2",
         description="Render configuration files from Jinja templates",
         long_description=(
             "ionit is a simple and small configuration templating tool. It collects a context and "
diff -Nru ionit-0.2.1/tests/test_ionit.py ionit-0.3.2/tests/test_ionit.py
--- ionit-0.2.1/tests/test_ionit.py	2019-01-07 14:01:10.000000000 +0100
+++ ionit-0.3.2/tests/test_ionit.py	2019-06-20 12:17:42.000000000 +0200
@@ -33,30 +33,35 @@
     """
 
     def test_collect_function(self):
-        """Test: Run collect_context("tests/config/function")"""
-        failures, context = collect_context(os.path.join(CONFIG_DIR, "function"))
+        """Test: Run collect_context(["tests/config/function"])"""
+        failures, context = collect_context([os.path.join(CONFIG_DIR, "function")])
         self.assertEqual(failures, 0)
         self.assertEqual(set(context.keys()), set(["answer_to_all_questions"]))
         self.assertEqual(context["answer_to_all_questions"](), 42)
 
     def test_collect_static_context(self):
-        """Test: Run collect_context("tests/config/static")"""
-        self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "static")), (0, {
+        """Test: Run collect_context(["tests/config/static"])"""
+        self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "static")]), (0, {
             "first": 1,
             "second": 2,
         }))
 
+    def test_configuration_file(self):
+        """Test: Run collect_context(["tests/config/static/second.yaml"])"""
+        self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "static", "second.yaml")]),
+                         (0, {"second": 2}))
+
     def test_context_stacking(self):
-        """Test: Run collect_context("tests/config/stacking")"""
-        self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "stacking")), (0, {
+        """Test: Run collect_context(["tests/config/stacking"])"""
+        self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "stacking")]), (0, {
             "big_number": 1071,
             "small_number": 7,
         }))
 
     def test_empty_python_file(self):
-        """Test: Run collect_context("tests/config/empty")"""
+        """Test: Run collect_context(["tests/config/empty"])"""
         with self.assertLogs("ionit", level="WARNING") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "empty")), (0, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "empty")]), (0, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], (
                 "WARNING:ionit:Python module '[^']+config/empty/empty.py' does "
@@ -64,10 +69,10 @@
                 r"\(using the ionit_plugin.function decorator\)."))
 
     def test_empty_context(self):
-        """Test: Run collect_context("tests/config/empty-context")"""
+        """Test: Run collect_context(["tests/config/empty-context"])"""
         try:
             with self.assertLogs("ionit", level="WARNING") as context_manager:
-                failures, context = collect_context(os.path.join(CONFIG_DIR, "empty-context"))
+                failures, context = collect_context([os.path.join(CONFIG_DIR, "empty-context")])
         except AssertionError:
             pass
         self.assertEqual(failures, 0)
@@ -75,9 +80,9 @@
         self.assertEqual(context_manager.output, [])
 
     def test_ignoring_additional_files(self):
-        """Test: Run collect_context("tests/config/additional-file")"""
+        """Test: Run collect_context(["tests/config/additional-file"])"""
         with self.assertLogs("ionit", level="INFO") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "additional-file")),
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "additional-file")]),
                              (0, {"key": "value"}))
             self.assertEqual(len(context_manager.output), 2)
             self.assertRegex(context_manager.output[0], (
@@ -85,18 +90,19 @@
                 "because it does not end with .*"))
 
     def test_invalid_json(self):
-        """Test: Run collect_context("tests/config/invalid-json")"""
+        """Test: Run collect_context(["tests/config/invalid-json"])"""
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "invalid-json")), (1, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "invalid-json")]), (1, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], (
                 "ERROR:ionit:Failed to read JSON from '[^']*config/invalid-json/invalid.json': "
                 r"Expecting property name enclosed in double quotes: line 3 column 1 \(char 22\)"))
 
     def test_invalid_python(self):
-        """Test: Run collect_context("tests/config/invalid-python")"""
+        """Test: Run collect_context(["tests/config/invalid-python"])"""
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "invalid-python")), (1, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "invalid-python")]),
+                             (1, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], re.compile(
                 "ERROR:ionit:Importing Python module '[^']*config/invalid-python/invalid.py' "
@@ -104,9 +110,9 @@
                 flags=re.DOTALL))
 
     def test_invalid_yaml(self):
-        """Test: Run collect_context("tests/config/invalid-yaml")"""
+        """Test: Run collect_context(["tests/config/invalid-yaml"])"""
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "invalid-yaml")), (1, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "invalid-yaml")]), (1, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], (
                 "ERROR:ionit:Failed to read YAML from '[^']*config/invalid-yaml/invalid.yaml': "
@@ -116,7 +122,7 @@
     def test_missing_directory(self):
         """Test: Non-existing context directory"""
         with self.assertLogs("ionit", level="WARNING") as context_manager:
-            self.assertEqual(collect_context(os.path.join(TESTS_DIR, "non-existing-directory")),
+            self.assertEqual(collect_context([os.path.join(TESTS_DIR, "non-existing-directory")]),
                              (0, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], (
@@ -124,9 +130,9 @@
                 r"No such file or directory: '\S*non-existing-directory'"))
 
     def test_non_dict_context(self):
-        """Test failure for collect_context("tests/config/non-dict")"""
+        """Test failure for collect_context(["tests/config/non-dict"])"""
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "non-dict")), (1, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "non-dict")]), (1, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], (
                 "ERROR:ionit:Failed to update context with content from "
@@ -134,16 +140,16 @@
                 "element #0 has length 1; 2 is required"))
 
     def test_python_module(self):
-        """Test: Run collect_context("tests/config/python")"""
-        self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "python")), (0, {
+        """Test: Run collect_context(["tests/config/python"])"""
+        self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "python")]), (0, {
             "small": 42,
             "big": 8000,
         }))
 
     def test_raise_exception(self):
-        """Test failure for collect_context("tests/config/exception")"""
+        """Test failure for collect_context(["tests/config/exception"])"""
         with self.assertLogs("ionit", level="ERROR") as context_manager:
-            self.assertEqual(collect_context(os.path.join(CONFIG_DIR, "exception")), (1, {}))
+            self.assertEqual(collect_context([os.path.join(CONFIG_DIR, "exception")]), (1, {}))
             self.assertEqual(len(context_manager.output), 1)
             self.assertRegex(context_manager.output[0], re.compile(
                 r"ERROR:ionit:Calling collect_context\(\) from '\S*config/exception/exception.py' "
@@ -230,6 +236,19 @@
 
 class TestMain(unittest.TestCase):
     """Test main function"""
+    @unittest.mock.patch("ionit.DEFAULT_CONFIG", os.path.join(CONFIG_DIR, "function"))
+    def test_main_default_config(self):
+        """Test main() with default config"""
+        template_dir = os.path.join(TEMPLATE_DIR, "function")
+        try:
+            self.assertEqual(main(["-t", template_dir]), 0)
+            with open(os.path.join(template_dir, "Document")) as document_file:
+                self.assertEqual(document_file.read(), (
+                    "The answer to the Ultimate Question of Life, The Universe, "
+                    "and Everything is 42.\n"))
+        finally:
+            os.remove(os.path.join(template_dir, "Document"))
+
     def test_main_static(self):
         """Test main() with static context"""
         template_dir = os.path.join(TEMPLATE_DIR, "static")

--- End Message ---
--- Begin Message ---
Hi Benjamin,

On 20-06-2019 16:13, Benjamin Drung wrote:
> Okay. Uploaded that debdiff as 0.3.2+really0.2.1-1.

Unblocked, thanks.

Paul

Attachment: signature.asc
Description: OpenPGP digital signature


--- End Message ---

Reply to: