Initial attempt to implement
https://fedorahosted.org/freeipa/ticket/4517

Some points to discuss:

1.) name of the config entries: currently the option names are derived from CLI options but have underscores in them instead of dashes. Maybe keeping the CLI option names also for config entries will make it easier for the user to transfer their CLI options from scripts to config files.

2.) Config sections: there is currently only one valid section named '[global]' in accordance with the format of 'default.conf'. Should we have separate sections equivalent to option groups in CLI (e.g. [basic], [certificate system], [dns])?

3.) Handling of unattended mode when specifying a config file:
Currently there is no connection between --config-file and unattended mode. So when you run ipa-server-install using config file, you still get asked for missing stuff. Should '--config-file' automatically imply '--unattended'?

There are probably other issues to discuss. Feel free to write email/ping me on IRC.

--
Martin^3 Babinsky
From 57685dfca56e5300d6c996ba6362c407b7b1a63b Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Wed, 22 Jul 2015 13:55:26 +0200
Subject: [PATCH] IPA server and replica installers can accept options from
 config file

New option '--config-file' enables ipa-server-install and ipa-replica-install
to obtain parameters from supplied configuration file in INI format.

The file syntax is as follows:
    * all options are listed in a single [global] section
    * the option name can be derived from long CLI option name by replacing
      dashes with underscores
    * boolean options are specified as a keyword without value: e.g. to enable
      installation of DNS component specify only 'setup_dns' in the config
      file.
      The absence of the boolean implies that the option is False
    * to specify multivalued parameter, assign a list of entries on multiple
      lines to a single option like this:
           multi_valued_option = value1
               value2
               value3

Parameters specified explicitly through CLI options take precedence over the
values contained in config file.

In the case of unknown options present in the config file, the installer will
raise an error listing them.

https://fedorahosted.org/freeipa/ticket/4517
---
 ipapython/install/cli.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/ipapython/install/cli.py b/ipapython/install/cli.py
index 1ba9a815c4c499dff0e7974f399f2de31eb932cd..614c0562c28362e79690783757d2a8995907bf6e 100644
--- a/ipapython/install/cli.py
+++ b/ipapython/install/cli.py
@@ -9,6 +9,7 @@ Command line support.
 import collections
 import optparse
 import signal
+from ConfigParser import ConfigParser
 
 from ipapython import admintool, ipa_log_manager
 from ipapython.ipautil import CheckedIPAddress, private_ccache
@@ -148,6 +149,17 @@ class ConfigureTool(admintool.AdminTool):
         for group, opt_group in groups.iteritems():
             parser.add_option_group(opt_group)
 
+        alt_source_group = optparse.OptionGroup(
+            parser, "alternative configuration sources")
+        alt_source_group.add_option(
+            "--config-file",
+            dest='config_filename',
+            default=None,
+            metavar='FILE',
+            help="get installer specific options from config file"
+        )
+        parser.add_option_group(alt_source_group)
+
         super(ConfigureTool, cls).add_options(parser,
                                               debug_option=cls.debug_option)
 
@@ -274,6 +286,11 @@ class ConfigureTool(admintool.AdminTool):
     def run(self):
         kwargs = {}
 
+        if self.options.config_filename is not None:
+            values_from_config = self.parse_config_file(
+                self.options.config_filename)
+            kwargs.update(values_from_config)
+
         transformed_cls = self._transform(self.configurable_class)
         for owner_cls, name in transformed_cls.knobs():
             value = getattr(self.options, name, None)
@@ -311,6 +328,65 @@ class ConfigureTool(admintool.AdminTool):
     def __signal_handler(signum, frame):
         raise KeyboardInterrupt
 
+    def parse_config_file(self, filename):
+        config_parser = ConfigParser(allow_no_value=True)
+
+        with open(filename, 'r') as f:
+            config_parser.readfp(f)
+
+        # use single section name for now
+        section_name = 'global'
+        config_entries = {x[0]: x[1] for x
+                          in config_parser.items(section_name)}
+
+        result = {}
+
+        transformed_cls = self._transform(self.configurable_class)
+        for owner_cls, name in transformed_cls.knobs():
+            knob_cls = getattr(owner_cls, name)
+
+            entry_name = (knob_cls.cli_name.replace('-', '_')
+                          if knob_cls.cli_name is not None else name)
+            try:
+                config_entry = config_entries.pop(entry_name)
+            except KeyError:
+                continue
+
+            try:
+                result[name] = self._value_from_config_entry(knob_cls, name,
+                                                             config_entry)
+            except ValueError as e:
+                raise RuntimeError(
+                    "In config file '{0}': {1}".format(
+                        filename, e)
+                )
+
+        # check for unrecognized entries left and raise an error
+        if config_entries:
+            raise RuntimeError(
+                "In config file '{0}':\n\tUnrecognized entries: {1}".format(
+                    filename, ', '.join([x for x in config_entries])
+                )
+            )
+
+        return result
+
+    def _value_from_config_entry(self, knob_cls, knob_name, config_entry):
+        # since ConfigParser does not by default support
+        # multi-valued entries, we will split multi-line entries
+        # into list of values when multi-valued Knob is detected
+        if isinstance(knob_cls.type, tuple) and knob_cls.type[0] == list:
+            config_value = config_entry.split('\n')
+            new_value = []
+            for v in config_value:
+                new_value = self._parse_knob(
+                    knob_cls, new_value, v)
+        else:
+            new_value = self._parse_knob(knob_cls, None,
+                                         config_entry)
+
+        return new_value
+
 
 class InstallTool(ConfigureTool):
     uninstall_kwargs = None
-- 
2.4.3

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to