URL: https://github.com/freeipa/freeipa/pull/3036
Author: t-woerner
 Title: #3036: New logger.info_cmd used as a replacement of print calls
Action: opened

PR body:
"""
The use of print calls in the installer parts are resulting in the need to
redirect stdout using redirect_stdout in ansible-freeipa. resirect_stdout
is creating a new scope.

The logger has been extended with the info_cmd method. This method is a
wrapper for the info method and is additionally setting { "cmd_output":
True } for the extra argument. This will be filtered with the a
InfoCommandFilter for the log file handler created in
standard_logging_setup.

The log format used for info_cmd is defined with LOGGING_FORMAT_INFO_CMD
and is applied with the extended Formatter class for the log level INFO
only.

These files have been adapted to use logger.info_cmd and logging.getLogger
has been added where it was missing:

   ipaclient/install/client.py
   ipalib/cli.py
   ipalib/messages.py
   ipaserver/dnssec/ldapkeydb.py
   ipaserver/dnssec/localhsm.py
   ipaserver/install/adtrust.py
   ipaserver/install/adtrustinstance.py
   ipaserver/install/bindinstance.py
   ipaserver/install/ca.py
   ipaserver/install/cainstance.py
   ipaserver/install/custodiainstance.py
   ipaserver/install/dns.py
   ipaserver/install/dnskeysyncinstance.py
   ipaserver/install/dsinstance.py
   ipaserver/install/installutils.py
   ipaserver/install/ipa_crlgen_manage.py
   ipaserver/install/replication.py
   ipaserver/install/server/__init__.py
   ipaserver/install/server/install.py
   ipaserver/install/server/replicainstall.py
   ipaserver/install/server/upgrade.py
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/3036/head:pr3036
git checkout pr3036
From f26a4cd0fe7fcdc1341367ab53b46a0d7fae068e Mon Sep 17 00:00:00 2001
From: Thomas Woerner <[email protected]>
Date: Fri, 12 Apr 2019 16:45:50 +0200
Subject: [PATCH] New logger.info_cmd used as a replacement of print calls

The use of print calls in the installer parts are resulting in the need to
redirect stdout using redirect_stdout in ansible-freeipa. resirect_stdout
is creating a new scope.

The logger has been extended with the info_cmd method. This method is a
wrapper for the info method and is additionally setting { "cmd_output":
True } for the extra argument. This will be filtered with the a
InfoCommandFilter for the log file handler created in
standard_logging_setup.

The log format used for info_cmd is defined with LOGGING_FORMAT_INFO_CMD
and is applied with the extended Formatter class for the log level INFO
only.

These files have been adapted to use logger.info_cmd and logging.getLogger
has been added where it was missing:

   ipaclient/install/client.py
   ipalib/cli.py
   ipalib/messages.py
   ipaserver/dnssec/ldapkeydb.py
   ipaserver/dnssec/localhsm.py
   ipaserver/install/adtrust.py
   ipaserver/install/adtrustinstance.py
   ipaserver/install/bindinstance.py
   ipaserver/install/ca.py
   ipaserver/install/cainstance.py
   ipaserver/install/custodiainstance.py
   ipaserver/install/dns.py
   ipaserver/install/dnskeysyncinstance.py
   ipaserver/install/dsinstance.py
   ipaserver/install/installutils.py
   ipaserver/install/ipa_crlgen_manage.py
   ipaserver/install/replication.py
   ipaserver/install/server/__init__.py
   ipaserver/install/server/install.py
   ipaserver/install/server/replicainstall.py
   ipaserver/install/server/upgrade.py
---
 ipaclient/install/client.py                |  21 +-
 ipalib/cli.py                              |  22 +-
 ipalib/messages.py                         |   7 +-
 ipapython/ipa_log_manager.py               |  59 +++++
 ipaserver/dnssec/ldapkeydb.py              |  32 +--
 ipaserver/dnssec/localhsm.py               |  54 ++--
 ipaserver/install/adtrust.py               | 144 ++++++-----
 ipaserver/install/adtrustinstance.py       |  15 +-
 ipaserver/install/bindinstance.py          |  38 +--
 ipaserver/install/ca.py                    |  16 +-
 ipaserver/install/cainstance.py            |  10 +-
 ipaserver/install/custodiainstance.py      |   4 +-
 ipaserver/install/dns.py                   | 110 ++++----
 ipaserver/install/dnskeysyncinstance.py    |   6 +-
 ipaserver/install/dsinstance.py            |   4 +-
 ipaserver/install/installutils.py          |  44 ++--
 ipaserver/install/ipa_crlgen_manage.py     |  13 +-
 ipaserver/install/replication.py           |  61 +++--
 ipaserver/install/server/__init__.py       |   4 +-
 ipaserver/install/server/install.py        | 282 +++++++++++----------
 ipaserver/install/server/replicainstall.py |  22 +-
 ipaserver/install/server/upgrade.py        |   4 +-
 22 files changed, 555 insertions(+), 417 deletions(-)

diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
index 6a723356ca..2d69b8b075 100644
--- a/ipaclient/install/client.py
+++ b/ipaclient/install/client.py
@@ -2055,9 +2055,9 @@ def install_check(options):
     global client_domain
     global cli_basedn
 
-    print("This program will set up FreeIPA client.")
-    print("Version {}".format(version.VERSION))
-    print("")
+    logger.info_cmd("This program will set up FreeIPA client.")
+    logger.info_cmd("Version {}".format(version.VERSION))
+    logger.info_cmd("")
 
     cli_domain_source = 'Unknown source'
     cli_server_source = 'Unknown source'
@@ -2084,10 +2084,11 @@ def install_check(options):
         try:
             timeconf.check_timedate_services()
         except timeconf.NTPConflictingService as e:
-            print("WARNING: conflicting time&date synchronization service '{}'"
-                  " will be disabled".format(e.conflicting_service))
-            print("in favor of chronyd")
-            print("")
+            logger.info_cmd(
+                "WARNING: conflicting time&date synchronization service '{}'"
+                " will be disabled".format(e.conflicting_service))
+            logger.info_cmd("in favor of chronyd")
+            logger.info_cmd("")
         except timeconf.NTPConfigurationError:
             pass
 
@@ -2406,14 +2407,14 @@ def install_check(options):
                 is_ipaddr = False
 
         if is_ipaddr:
-            print()
+            logger.info_cmd("")
             logger.warning(
                 "It seems that you are using an IP address "
                 "instead of FQDN as an argument to --server. The "
                 "installation may fail.")
             break
 
-    print()
+    logger.info_cmd("")
     if not options.unattended and not user_input(
             "Continue to configure the system with these values?", False):
         raise ScriptError(rval=CLIENT_INSTALL_ERROR)
@@ -2488,7 +2489,7 @@ def sync_time(options, fstore, statestore):
                        "or pool address was provided.")
 
     if not configured:
-        print("Using default chrony configuration.")
+        logger.info_cmd("Using default chrony configuration.")
 
     return timeconf.sync_chrony()
 
diff --git a/ipalib/cli.py b/ipalib/cli.py
index ecd9ef2b3b..12df80a023 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -200,7 +200,7 @@ def print_plain(self, string):
         """
         Print exactly like ``print`` statement would.
         """
-        print(unicode(string))
+        logger.info_cmd(unicode(string))
 
     def print_line(self, text, width=None):
         """
@@ -222,7 +222,7 @@ def print_line(self, text, width=None):
             width = self.get_tty_width()
         if width is not None and width < len(text):
             text = text[:width - 3] + '...'
-        print(unicode(text))
+        logger.info_cmd(unicode(text))
 
     def print_paragraph(self, text, width=None):
         """
@@ -251,7 +251,7 @@ def print_paragraph(self, text, width=None):
         if width is None:
             width = self.get_tty_width()
         for line in textwrap.wrap(text.strip(), width):
-            print(line)
+            logger.info_cmd(line)
 
     def print_indented(self, text, indent=1):
         """
@@ -267,7 +267,7 @@ def print_indented(self, text, indent=1):
         >>> ui.print_indented('No indentation.', indent=0)
         No indentation.
         """
-        print((CLI_TAB * indent + text))
+        logger.info_cmd((CLI_TAB * indent + text))
 
     def print_keyval(self, rows, indent=1):
         """
@@ -380,7 +380,7 @@ def print_entries(self, entries, order=None, labels=None, flags=None, print_all=
         first = True
         for entry in entries:
             if not first:
-                print('')
+                logger.info_cmd('')
             first = False
             self.print_entry(entry, order, labels, flags, print_all, format, indent)
 
@@ -550,7 +550,7 @@ def print_count(self, count, singular, plural=None):
         )
 
     def print_error(self, text):
-        print('  ** %s **' % unicode(text))
+        logger.info_cmd('  ** %s **' % unicode(text))
 
     def prompt_helper(self, prompt, label, prompt_func=input):
         """Prompt user for input
@@ -561,7 +561,7 @@ def prompt_helper(self, prompt, label, prompt_func=input):
         try:
             return self.decode(prompt_func(self.encode(prompt)))
         except (KeyboardInterrupt, EOFError):
-            print()
+            logger.info_cmd("")
             raise PromptFailed(name=label)
 
     def print_prompt_attribute_error(self, attribute, error):
@@ -946,7 +946,7 @@ def run(self, command_name, **options):
             out.append((param.cli_name, param.param_spec))
             mcl = max(mcl,len(param.cli_name))
         for item in out:
-            print(to_cli(item[0]).ljust(mcl)+' : '+item[1])
+            logger.info_cmd(to_cli(item[0]).ljust(mcl) + ' : ' + item[1])
 
 
 class console(frontend.Command):
@@ -1041,10 +1041,10 @@ def run(self, namespaces=None):
         first = True
         for line in lines:
             if line[0] == 0 and not first:
-                print('')
+                logger.info_cmd('')
             if first:
                 first = False
-            print('%s%s %r' % (
+            logger.info_cmd('%s%s %r' % (
                 ' ' * line[0],
                 line[1].ljust(ml),
                 line[2],
@@ -1465,7 +1465,7 @@ def run(api):
             raise NotConfiguredError()
         sys.exit(api.Backend.cli.run(argv))
     except KeyboardInterrupt:
-        print('')
+        logger.info_cmd('')
         logger.info('operation aborted')
     except PublicError as e:
         error = e
diff --git a/ipalib/messages.py b/ipalib/messages.py
index 8567134ac9..955f9af005 100644
--- a/ipalib/messages.py
+++ b/ipalib/messages.py
@@ -31,6 +31,7 @@
 """
 from __future__ import print_function
 
+import logging
 from inspect import isclass
 
 import six
@@ -43,6 +44,8 @@
 if six.PY3:
     unicode = str
 
+logger = logging.getLogger(__name__)
+
 def add_message(version, result, message):
     if client_has_capability(version, 'messages'):
         result.setdefault('messages', []).append(message.to_dict())
@@ -502,8 +505,8 @@ def iter_messages(variables, base):
 
 def print_report(label, classes):
     for cls in classes:
-        print('%d\t%s' % (cls.errno, cls.__name__))
-    print('(%d %s)' % (len(classes), label))
+        logger.info_cmd('%d\t%s' % (cls.errno, cls.__name__))
+    logger.info_cmd('(%d %s)' % (len(classes), label))
 
 if __name__ == '__main__':
     print_report('public messages', public_messages)
diff --git a/ipapython/ipa_log_manager.py b/ipapython/ipa_log_manager.py
index 902f7a4d6a..849059c96f 100644
--- a/ipapython/ipa_log_manager.py
+++ b/ipapython/ipa_log_manager.py
@@ -54,6 +54,20 @@
 # Used by standard_logging_setup() for file message
 LOGGING_FORMAT_STANDARD_FILE = '%(asctime)s %(levelname)s %(message)s'
 
+# Used by standard_logging_setup() for command line output
+LOGGING_FORMAT_INFO_CMD = '%(message)s'
+
+
+# Additional info_log level methods
+def log_info_cmd(obj, msg, *args, **kwargs):
+    kwargs.setdefault("extra", {})["cmd_output"] = True
+    obj._log(logging.INFO, msg, args, **kwargs)
+
+
+def log_info_cmd_root(msg, *args, **kwargs):
+    extra = {"cmd_output": True}
+    logging.log(logging.INFO, msg, args, dict({"extra": extra}, **kwargs))
+
 
 class _DeprecatedLogger:
     def __init__(self, logger, name):
@@ -73,6 +87,10 @@ def info(self, *args, **kwargs):
         self._warn()
         self._logger.info(*args, **kwargs)
 
+    def info_cmd(self, *args, **kwargs):
+        self._warn()
+        self._logger.info_cmd(*args, **kwargs)
+
     def warning(self, *args, **kwargs):
         self._warn()
         self._logger.warning(*args, **kwargs)
@@ -119,6 +137,7 @@ def get_logger(who, bind_logger_names=False):
 
         for method in ('debug',
                        'info',
+                       'info_cmd',
                        'warning',
                        'error',
                        'exception',
@@ -141,12 +160,45 @@ def filter(self, record):
                 record.levelno >= self.level)
 
 
+class InfoCommandFilter(logging.Filter):
+    """
+    The InfoCommandFilter filters out info_cmd log messages for the log file.
+    info_cmd log messages should only be visble on the command line.
+    """
+
+    def filter(self, record):
+        if hasattr(record, "cmd_output") and record.__dict__["cmd_output"]:
+            return False
+        return True
+
+
 class Formatter(logging.Formatter):
     def __init__(
             self, fmt=LOGGING_FORMAT_STDOUT, datefmt=ISO8601_UTC_DATETIME_FMT):
         super(Formatter, self).__init__(fmt, datefmt)
         self.converter = time.gmtime
 
+    def format(self, record):
+        """
+        Format the specified record as text.
+
+        Uses LOGGING_FORMAT_INFO_CMD for info_cmd, otherwise normal logging
+        format. For info_cmd record.__dict__["cmd_output"] is set to True.
+        """
+        if record.levelno == logging.INFO and \
+           hasattr(record, "cmd_output") and record.__dict__["cmd_output"]:
+            # Save original logging format
+            orig_fmt = self._fmt
+            # Temporarily use LOGGING_FORMAT_INFO_CMD
+            self._fmt = LOGGING_FORMAT_INFO_CMD
+            # Create result
+            result = logging.Formatter.format(self, record)
+            # Restore original logging format
+            self._fmt = orig_fmt
+            return result
+
+        # Return normal format
+        return logging.Formatter.format(self, record)
 
 def standard_logging_setup(filename=None, verbose=False, debug=False,
                            filemode='w', console_format=None):
@@ -164,6 +216,7 @@ def standard_logging_setup(filename=None, verbose=False, debug=False,
         finally:
             os.umask(umask)
         file_handler.setLevel(logging.DEBUG)
+        file_handler.addFilter(InfoCommandFilter())
         file_handler.setFormatter(Formatter(LOGGING_FORMAT_STANDARD_FILE))
         root_logger.addHandler(file_handler)
 
@@ -197,6 +250,12 @@ def convert_log_level(value):
     return level
 
 
+# Add info_cmd to logger and root logger
+if not hasattr(logging.getLoggerClass(), "info_cmd"):
+    logging.getLoggerClass().info_cmd = log_info_cmd
+if not hasattr(logging, "info_cmd"):
+    logging.info_cmd = log_info_cmd_root
+
 # Single shared instance of log manager
 log_mgr = sys.modules[__name__]
 
diff --git a/ipaserver/dnssec/ldapkeydb.py b/ipaserver/dnssec/ldapkeydb.py
index d47b03732f..b58e2266db 100644
--- a/ipaserver/dnssec/ldapkeydb.py
+++ b/ipaserver/dnssec/ldapkeydb.py
@@ -2,11 +2,11 @@
 # Copyright (C) 2014  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 from binascii import hexlify
 import logging
-from pprint import pprint
+from pprint import pformat
 
 import six
 
@@ -478,22 +478,22 @@ def zone_keypairs(self):
                                    ipalib.api.env.container_dns,
                                    ipalib.api.env.basedn))
 
-    print('replica public keys: CKA_WRAP = TRUE')
-    print('====================================')
+    logger.info_cmd('replica public keys: CKA_WRAP = TRUE')
+    logger.info_cmd('====================================')
     for pubkey_id, pubkey in ldapkeydb.replica_pubkeys_wrap.items():
-        print(str_hexlify(pubkey_id))
-        pprint(pubkey)
+        logger.info_cmd(str_hexlify(pubkey_id))
+        logger.info_cmd(pformat(pubkey))
 
-    print('')
-    print('master keys')
-    print('===========')
+    logger.info_cmd('')
+    logger.info_cmd('master keys')
+    logger.info_cmd('===========')
     for mkey_id, mkey in ldapkeydb.master_keys.items():
-        print(str_hexlify(mkey_id))
-        pprint(mkey)
+        logger.info_cmd(str_hexlify(mkey_id))
+        logger.info_cmd(pformat(mkey))
 
-    print('')
-    print('zone key pairs')
-    print('==============')
+    logger.info_cmd('')
+    logger.info_cmd('zone key pairs')
+    logger.info_cmd('==============')
     for key_id, key in ldapkeydb.zone_keypairs.items():
-        print(str_hexlify(key_id))
-        pprint(key)
+        logger.info_cmd(str_hexlify(key_id))
+        logger.info_cmd(pformat(key))
diff --git a/ipaserver/dnssec/localhsm.py b/ipaserver/dnssec/localhsm.py
index d02fdbe142..c6e1649ec0 100644
--- a/ipaserver/dnssec/localhsm.py
+++ b/ipaserver/dnssec/localhsm.py
@@ -2,10 +2,11 @@
 # Copyright (C) 2014  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import os
-from pprint import pprint
+import logging
+from pprint import pformat
 
 import six
 
@@ -24,6 +25,7 @@
     from collections import MutableMapping
 # pylint: enable=no-name-in-module, import-error
 
+logger = logging.getLogger(__name__)
 
 private_key_api_params = set(["label", "id", "data", "unwrapping_key",
     "wrapping_mech", "key_type", "cka_always_authenticate", "cka_copyable",
@@ -201,36 +203,36 @@ def import_private_key(self, source, data, unwrapping_key):
     localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, SOFTHSM_DNSSEC_TOKEN_LABEL,
             open(paths.DNSSEC_SOFTHSM_PIN).read())
 
-    print('replica public keys: CKA_WRAP = TRUE')
-    print('====================================')
+    logger.info_cmd('replica public keys: CKA_WRAP = TRUE')
+    logger.info_cmd('====================================')
     for pubkey_id, pubkey in localhsm.replica_pubkeys_wrap.items():
-        print(str_hexlify(pubkey_id))
-        pprint(pubkey)
+        logger.info_cmd(str_hexlify(pubkey_id))
+        logger.info_cmd(pformat(pubkey))
 
-    print('')
-    print('replica public keys: all')
-    print('========================')
+    logger.info_cmd('')
+    logger.info_cmd('replica public keys: all')
+    logger.info_cmd('========================')
     for pubkey_id, pubkey in localhsm.replica_pubkeys.items():
-        print(str_hexlify(pubkey_id))
-        pprint(pubkey)
+        logger.info_cmd(str_hexlify(pubkey_id))
+        logger.info_cmd(pformat(pubkey))
 
-    print('')
-    print('master keys')
-    print('===========')
+    logger.info_cmd('')
+    logger.info_cmd('master keys')
+    logger.info_cmd('===========')
     for mkey_id, mkey in localhsm.master_keys.items():
-        print(str_hexlify(mkey_id))
-        pprint(mkey)
+        logger.info_cmd(str_hexlify(mkey_id))
+        logger.info_cmd(pformat(mkey))
 
-    print('')
-    print('zone public keys')
-    print('================')
+    logger.info_cmd('')
+    logger.info_cmd('zone public keys')
+    logger.info_cmd('================')
     for key_id, zkey in localhsm.zone_pubkeys.items():
-        print(str_hexlify(key_id))
-        pprint(zkey)
+        logger.info_cmd(str_hexlify(key_id))
+        logger.info_cmd(pformat(zkey))
 
-    print('')
-    print('zone private keys')
-    print('=================')
+    logger.info_cmd('')
+    logger.info_cmd('zone private keys')
+    logger.info_cmd('=================')
     for key_id, zkey in localhsm.zone_privkeys.items():
-        print(str_hexlify(key_id))
-        pprint(zkey)
+        logger.info_cmd(str_hexlify(key_id))
+        logger.info_cmd(pformat(zkey))
diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index 75194eed8f..3583818ad6 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -6,7 +6,7 @@
 AD trust installer module
 """
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import logging
 import os
@@ -45,18 +45,18 @@ def netbios_name_error(name):
 def read_netbios_name(netbios_default):
     netbios_name = ""
 
-    print("Enter the NetBIOS name for the IPA domain.")
-    print("Only up to 15 uppercase ASCII letters, digits "
-          "and dashes are allowed.")
-    print("Example: EXAMPLE.")
-    print("")
-    print("")
+    logger.info_cmd("Enter the NetBIOS name for the IPA domain.")
+    logger.info_cmd("Only up to 15 uppercase ASCII letters, digits "
+                    "and dashes are allowed.")
+    logger.info_cmd("Example: EXAMPLE.")
+    logger.info_cmd("")
+    logger.info_cmd("")
     if not netbios_default:
         netbios_default = "EXAMPLE"
     while True:
         netbios_name = ipautil.user_input(
             "NetBIOS domain name", netbios_default, allow_empty=False)
-        print("")
+        logger.info_cmd("")
         if adtrustinstance.check_netbios_name(netbios_name):
             break
 
@@ -108,17 +108,17 @@ def set_and_check_netbios_name(netbios_name, unattended, api):
         reset_netbios_name = False
     elif cur_netbios_name and cur_netbios_name != netbios_name:
         # change the NetBIOS name
-        print("Current NetBIOS domain name is %s, new name is %s.\n"
-              % (cur_netbios_name, netbios_name))
-        print("Please note that changing the NetBIOS name might "
-              "break existing trust relationships.")
+        logger.info_cmd("Current NetBIOS domain name is %s, new name is %s.\n"
+                        % (cur_netbios_name, netbios_name))
+        logger.info_cmd("Please note that changing the NetBIOS name might "
+                        "break existing trust relationships.")
         if unattended:
             reset_netbios_name = True
-            print("NetBIOS domain name will be changed to %s.\n"
-                  % netbios_name)
+            logger.info_cmd("NetBIOS domain name will be changed to %s.\n"
+                            % netbios_name)
         else:
-            print("Say 'yes' if the NetBIOS shall be changed and "
-                  "'no' if the old one shall be kept.")
+            logger.info_cmd("Say 'yes' if the NetBIOS shall be changed and "
+                            "'no' if the old one shall be kept.")
             reset_netbios_name = ipautil.user_input(
                             'Do you want to reset the NetBIOS domain name?',
                             default=False, allow_empty=False)
@@ -134,8 +134,9 @@ def set_and_check_netbios_name(netbios_name, unattended, api):
 
         if gen_netbios_name is not None:
             # Fix existing trust configuration
-            print("Trust is configured but no NetBIOS domain name found, "
-                  "setting it now.")
+            logger.info_cmd(
+                "Trust is configured but no NetBIOS domain name found, "
+                "setting it now.")
             reset_netbios_name = True
         else:
             # initial trust configuration
@@ -163,16 +164,18 @@ def set_and_check_netbios_name(netbios_name, unattended, api):
 
 
 def enable_compat_tree():
-    print("Do you want to enable support for trusted domains in Schema "
-          "Compatibility plugin?")
-    print("This will allow clients older than SSSD 1.9 and non-Linux "
-          "clients to work with trusted users.")
-    print("")
+    logger.info_cmd(
+        "Do you want to enable support for trusted domains in Schema "
+        "Compatibility plugin?")
+    logger.info_cmd(
+        "This will allow clients older than SSSD 1.9 and non-Linux "
+        "clients to work with trusted users.")
+    logger.info_cmd("")
     enable_compat = ipautil.user_input(
         "Enable trusted domains support in slapi-nis?",
         default=False,
         allow_empty=False)
-    print("")
+    logger.info_cmd("")
     return enable_compat
 
 
@@ -221,22 +224,22 @@ def retrieve_and_ask_about_sids(api, options):
 
     object_count = len(entries)
     if object_count > 0:
-        print("")
-        print("WARNING: %d existing users or groups do not have "
-              "a SID identifier assigned." % len(entries))
-        print("Installer can run a task to have ipa-sidgen "
-              "Directory Server plugin generate")
-        print("the SID identifier for all these users. Please note, "
-              "in case of a high")
-        print("number of users and groups, the operation might "
-              "lead to high replication")
-        print("traffic and performance degradation. Refer to "
-              "ipa-adtrust-install(1) man page")
-        print("for details.")
-        print("")
+        logger.info_cmd("")
+        logger.info_cmd("WARNING: %d existing users or groups do not have "
+                        "a SID identifier assigned." % len(entries))
+        logger.info_cmd("Installer can run a task to have ipa-sidgen "
+                        "Directory Server plugin generate")
+        logger.info_cmd("the SID identifier for all these users. Please note, "
+                        "in case of a high")
+        logger.info_cmd("number of users and groups, the operation might "
+                        "lead to high replication")
+        logger.info_cmd("traffic and performance degradation. Refer to "
+                        "ipa-adtrust-install(1) man page")
+        logger.info_cmd("for details.")
+        logger.info_cmd("")
         if options.unattended:
-            print("Unattended mode was selected, installer will "
-                  "NOT run ipa-sidgen task!")
+            logger.info_cmd("Unattended mode was selected, installer will "
+                            "NOT run ipa-sidgen task!")
         else:
             if ipautil.user_input(
                     "Do you want to run the ipa-sidgen task?",
@@ -312,20 +315,21 @@ def add_new_adtrust_agents(api, options):
     potential_agents_cns = retrieve_potential_adtrust_agents(api)
 
     if potential_agents_cns:
-        print("")
-        print("WARNING: %d IPA masters are not yet able to serve "
-              "information about users from trusted forests."
-              % len(potential_agents_cns))
-        print("Installer can add them to the list of IPA masters "
-              "allowed to access information about trusts.")
-        print("If you choose to do so, you also need to restart "
-              "LDAP service on those masters.")
-        print("Refer to ipa-adtrust-install(1) man page for details.")
-        print("")
+        logger.info_cmd("")
+        logger.info_cmd("WARNING: %d IPA masters are not yet able to serve "
+                        "information about users from trusted forests."
+                        % len(potential_agents_cns))
+        logger.info_cmd("Installer can add them to the list of IPA masters "
+                        "allowed to access information about trusts.")
+        logger.info_cmd("If you choose to do so, you also need to restart "
+                        "LDAP service on those masters.")
+        logger.info_cmd("Refer to ipa-adtrust-install(1) man page for "
+                        "details.")
+        logger.info_cmd("")
         if options.unattended:
-            print("Unattended mode was selected, installer will NOT "
-                  "add other IPA masters to the list of allowed to")
-            print("access information about trusted forests!")
+            logger.info_cmd("Unattended mode was selected, installer will NOT "
+                            "add other IPA masters to the list of allowed to")
+            logger.info_cmd("access information about trusted forests!")
             return
 
     new_agents = []
@@ -340,12 +344,12 @@ def add_new_adtrust_agents(api, options):
     if new_agents:
         add_hosts_to_adtrust_agents(api, new_agents)
 
-        print("""
+        logger.info_cmd("""
 WARNING: you MUST restart (e.g. ipactl restart) the following IPA masters in
 order to activate them to serve information about users from trusted forests:
 """)
         for x in new_agents:
-            print(x)
+            logger.info_cmd(x)
 
 
 def install_check(standalone, options, api):
@@ -358,10 +362,11 @@ def install_check(standalone, options, api):
     realm_not_matching_domain = (api.env.domain.upper() != api.env.realm)
 
     if realm_not_matching_domain:
-        print("WARNING: Realm name does not match the domain name.\n"
-              "You will not be able to establish trusts with Active "
-              "Directory unless\nthe realm name of the IPA server matches its "
-              "domain name.\n\n")
+        logger.info_cmd(
+            "WARNING: Realm name does not match the domain name.\n"
+            "You will not be able to establish trusts with Active "
+            "Directory unless\nthe realm name of the IPA server matches its "
+            "domain name.\n\n")
         if not options.unattended:
             if not ipautil.user_input("Do you wish to continue?",
                                       default=False,
@@ -373,25 +378,25 @@ def install_check(standalone, options, api):
 
     if adtrustinstance.ipa_smb_conf_exists():
         if not options.unattended:
-            print("IPA generated smb.conf detected.")
+            logger.info_cmd("IPA generated smb.conf detected.")
             if not ipautil.user_input("Overwrite smb.conf?",
                                       default=False,
                                       allow_empty=False):
                 raise ScriptError("Aborting installation.")
 
     elif os.path.exists(paths.SMB_CONF):
-        print("WARNING: The smb.conf already exists. Running "
-              "ipa-adtrust-install will break your existing samba "
-              "configuration.\n\n")
+        logger.info_cmd("WARNING: The smb.conf already exists. Running "
+                        "ipa-adtrust-install will break your existing samba "
+                        "configuration.\n\n")
         if not options.unattended:
             if not ipautil.user_input("Do you wish to continue?",
                                       default=False,
                                       allow_empty=False):
                 raise ScriptError("Aborting installation.")
     elif os.path.exists(paths.SMB_CONF):
-        print("WARNING: The smb.conf already exists. Running "
-              "ipa-adtrust-install will break your existing samba "
-              "configuration.\n\n")
+        logger.info_cmd("WARNING: The smb.conf already exists. Running "
+                        "ipa-adtrust-install will break your existing samba "
+                        "configuration.\n\n")
         if not options.unattended:
             if not ipautil.user_input("Do you wish to continue?",
                                       default=False,
@@ -410,10 +415,11 @@ def install_check(standalone, options, api):
 
 def install(standalone, options, fstore, api):
     if not options.unattended and standalone:
-        print("")
-        print("The following operations may take some minutes to complete.")
-        print("Please wait until the prompt is returned.")
-        print("")
+        logger.info_cmd("")
+        logger.info_cmd(
+            "The following operations may take some minutes to complete.")
+        logger.info_cmd("Please wait until the prompt is returned.")
+        logger.info_cmd("")
 
     smb = adtrustinstance.ADTRUSTInstance(fstore)
     smb.realm = api.env.realm
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index d117e18d58..19bd524138 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -17,7 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import logging
 import os
@@ -68,18 +68,19 @@
 def check_inst():
     for smbfile in [paths.SMBD, paths.NET]:
         if not os.path.exists(smbfile):
-            print("%s was not found on this system" % smbfile)
-            print("Please install the 'samba' packages and " \
-                  "start the installation again")
+            logger.info_cmd("%s was not found on this system" % smbfile)
+            logger.info_cmd("Please install the 'samba' packages and "
+                            "start the installation again")
             return False
 
     # Check that ipa-server-trust-ad package is installed,
     # by looking for the file /usr/share/ipa/smb.conf.empty
     if not os.path.exists(os.path.join(paths.USR_SHARE_IPA_DIR,
                                        "smb.conf.empty")):
-        print("AD Trust requires the '%s' package" %
-              constants.IPA_ADTRUST_PACKAGE_NAME)
-        print("Please install the package and start the installation again")
+        logger.info_cmd("AD Trust requires the '%s' package" %
+                        constants.IPA_ADTRUST_PACKAGE_NAME)
+        logger.info_cmd(
+            "Please install the package and start the installation again")
         return False
 
     #TODO: Add check for needed samba4 libraries
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 63f552dcd2..3d25170575 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -18,7 +18,6 @@
 #
 
 from __future__ import absolute_import
-from __future__ import print_function
 
 import logging
 import tempfile
@@ -530,7 +529,7 @@ def check_reverse_zones(ip_addresses, reverse_zones, options, unattended,
 
 
 def check_forwarders(dns_forwarders):
-    print("Checking DNS forwarders, please wait ...")
+    logger.info_cmd("Checking DNS forwarders, please wait ...")
     forwarders_dnssec_valid = True
     for forwarder in dns_forwarders:
         logger.debug("Checking DNS server: %s", forwarder)
@@ -544,17 +543,20 @@ def check_forwarders(dns_forwarders):
                            "DNSSEC support.\n"
                            "(For BIND 9 add directive \"dnssec-enable yes;\" "
                            "to \"options {}\")")
-            print("DNS server %s: %s" % (forwarder, e))
-            print("Please fix forwarder configuration to enable DNSSEC support.")
-            print("(For BIND 9 add directive \"dnssec-enable yes;\" to \"options {}\")")
+            logger.info_cmd("DNS server %s: %s" % (forwarder, e))
+            logger.info_cmd(
+                "Please fix forwarder configuration to enable DNSSEC support.")
+            logger.info_cmd(
+                "(For BIND 9 add directive \"dnssec-enable yes;\" to "
+                "\"options {}\")")
         except EDNS0UnsupportedError as e:
             forwarders_dnssec_valid = False
             logger.warning("DNS server %s does not support ENDS0 "
                            "(RFC 6891): %s", forwarder, e)
             logger.warning("Please fix forwarder configuration. "
                            "DNSSEC support cannot be enabled without EDNS0")
-            print(("WARNING: DNS server %s does not support EDNS0 "
-                   "(RFC 6891): %s" % (forwarder, e)))
+            logger.info_cmd("WARNING: DNS server %s does not support EDNS0 "
+                            "(RFC 6891): %s" % (forwarder, e))
         except UnresolvableRecordError as e:
             logger.error("DNS server %s: %s", forwarder, e)
             raise RuntimeError("DNS server %s: %s" % (forwarder, e))
@@ -708,8 +710,9 @@ def create_file_with_system_records(self):
                 suffix=".db", delete=False
         ) as f:
             f.write(text)
-            print("Please add records in this file to your DNS system:",
-                  f.name)
+            logger.info_cmd(
+                "Please add records in this file to your DNS system: %s" %
+                f.name)
 
     def create_instance(self):
 
@@ -763,7 +766,7 @@ def __start(self):
             self.restart()
         except Exception as e:
             logger.error("Named service failed to start (%s)", e)
-            print("named service failed to start")
+            logger.info_cmd("named service failed to start")
 
     def __enable(self):
         if self.get_state("enabled") is None:
@@ -1182,14 +1185,17 @@ def check_global_configuration(self):
         )
 
         if not global_conf_set:
-            print("Global DNS configuration in LDAP server is empty")
-            print("You can use 'dnsconfig-mod' command to set global DNS options that")
-            print("would override settings in local named.conf files")
+            logger.info_cmd("Global DNS configuration in LDAP server is empty")
+            logger.info_cmd("You can use 'dnsconfig-mod' command to set "
+                            "global DNS options that")
+            logger.info_cmd(
+                "would override settings in local named.conf files")
             return
 
-        print("Global DNS configuration in LDAP server is not empty")
-        print("The following configuration options override local settings in named.conf:")
-        print("")
+        logger.info_cmd("Global DNS configuration in LDAP server is not empty")
+        logger.info_cmd("The following configuration options override local "
+                        "settings in named.conf:")
+        logger.info_cmd("")
         textui = ipalib.cli.textui(self.api)
         self.api.Command.dnsconfig_show.output_for_cli(textui, result, None,
                                                        reverse=False)
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 47730616ed..b1a3ec8280 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -6,7 +6,7 @@
 CA installer module
 """
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import enum
 import logging
@@ -103,16 +103,16 @@ def print_ca_configuration(options):
     Does not print trailing empty line.
 
     """
-    print("The CA will be configured with:")
-    print("Subject DN:   {}".format(options.ca_subject))
-    print("Subject base: {}".format(options.subject_base))
+    logger.info_cmd("The CA will be configured with:")
+    logger.info_cmd("Subject DN:   {}".format(options.ca_subject))
+    logger.info_cmd("Subject base: {}".format(options.subject_base))
     if options.external_ca:
         chaining = "externally signed (two-step installation)"
     elif options.external_cert_files:
         chaining = "externally signed"
     else:
         chaining = "self-signed"
-    print("Chaining:     {}".format(chaining))
+    logger.info_cmd("Chaining:     {}".format(chaining))
 
 
 def uninstall_check(options):
@@ -137,8 +137,8 @@ def uninstall_check(options):
         crlgen_enabled = True
 
     if crlgen_enabled:
-        print("Deleting this server will leave your installation "
-              "without a CRL generation master.")
+        logger.info_cmd("Deleting this server will leave your installation "
+                        "without a CRL generation master.")
         if (options.unattended and not options.ignore_last_of_role) or \
            not (options.unattended or ipautil.user_input(
                 "Are you sure you want to continue with the uninstall "
@@ -233,7 +233,7 @@ def install_check(standalone, replica_config, options):
 
     if not options.external_cert_files:
         if not cainstance.check_ports():
-            print(
+            logger.info_cmd(
                 "IPA requires ports 8080 and 8443 for PKI, but one or more "
                 "are currently in use."
             )
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index b128e44ffe..6fda725785 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -19,7 +19,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import base64
 import binascii
@@ -673,8 +673,12 @@ def __spawn_instance(self):
             os.remove(cfg_file)
 
         if self.external == 1:
-            print("The next step is to get %s signed by your CA and re-run %s as:" % (self.csr_file, sys.argv[0]))
-            print("%s --external-cert-file=/path/to/signed_certificate --external-cert-file=/path/to/external_ca_certificate" % sys.argv[0])
+            logger.info_cmd("The next step is to get %s signed by your CA and "
+                            "re-run %s as:" % (self.csr_file, sys.argv[0]))
+            logger.info_cmd(
+                "%s --external-cert-file=/path/to/signed_certificate "
+                "--external-cert-file=/path/to/external_ca_certificate" %
+                sys.argv[0])
             sys.exit(0)
         else:
             shutil.move(paths.CA_BACKUP_KEYS_P12,
diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
index 00b2c4c446..14c065152b 100644
--- a/ipaserver/install/custodiainstance.py
+++ b/ipaserver/install/custodiainstance.py
@@ -1,6 +1,6 @@
 # Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license.
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import enum
 import logging
@@ -227,7 +227,7 @@ def _wait_keys(self):
                 if saved_e is None:
                     # FIXME: Change once there's better way to show this
                     # message in installer output,
-                    print(
+                    logger.info_cmd(
                         "  Waiting for keys to appear on host: {}, please "
                         "wait until this has completed.".format(
                             self.ldap_uri)
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 40688dc274..3592763a73 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -7,7 +7,6 @@
 """
 
 from __future__ import absolute_import
-from __future__ import print_function
 
 import enum
 import logging
@@ -148,35 +147,43 @@ def install_check(standalone, api, replica, options, hostname):
                 raise e
 
     if standalone:
-        print("==============================================================================")
-        print("This program will setup DNS for the FreeIPA Server.")
-        print("")
-        print("This includes:")
-        print("  * Configure DNS (bind)")
-        print("  * Configure SoftHSM (required by DNSSEC)")
-        print("  * Configure ipa-dnskeysyncd (required by DNSSEC)")
+        logger.info_cmd("===================================================="
+                        "==========================")
+        logger.info_cmd("This program will setup DNS for the FreeIPA Server.")
+        logger.info_cmd("")
+        logger.info_cmd("This includes:")
+        logger.info_cmd("  * Configure DNS (bind)")
+        logger.info_cmd("  * Configure SoftHSM (required by DNSSEC)")
+        logger.info_cmd("  * Configure ipa-dnskeysyncd (required by DNSSEC)")
         if options.dnssec_master:
-            print("  * Configure ipa-ods-exporter (required by DNSSEC key master)")
-            print("  * Configure OpenDNSSEC (required by DNSSEC key master)")
-            print("  * Generate DNSSEC master key (required by DNSSEC key master)")
+            logger.info_cmd("  * Configure ipa-ods-exporter (required by "
+                            "DNSSEC key master)")
+            logger.info_cmd("  * Configure OpenDNSSEC (required by DNSSEC "
+                            "key master)")
+            logger.info_cmd("  * Generate DNSSEC master key (required by "
+                            "DNSSEC key master)")
         elif options.disable_dnssec_master:
-            print("  * Unconfigure ipa-ods-exporter")
-            print("  * Unconfigure OpenDNSSEC")
-            print("")
-            print("No new zones will be signed without DNSSEC key master IPA server.")
-            print("")
-            print(("Please copy file from %s after uninstallation. This file is needed "
-                   "on new DNSSEC key " % paths.IPA_KASP_DB_BACKUP))
-            print("master server")
-        print("")
-        print("NOTE: DNSSEC zone signing is not enabled by default")
-        print("")
+            logger.info_cmd("  * Unconfigure ipa-ods-exporter")
+            logger.info_cmd("  * Unconfigure OpenDNSSEC")
+            logger.info_cmd("")
+            logger.info_cmd("No new zones will be signed without DNSSEC key "
+                            "master IPA server.")
+            logger.info_cmd("")
+            logger.info_cmd("Please copy file from %s after uninstallation. "
+                            "This file is needed on new DNSSEC key " %
+                            paths.IPA_KASP_DB_BACKUP)
+            logger.info_cmd("master server")
+        logger.info_cmd("")
+        logger.info_cmd("NOTE: DNSSEC zone signing is not enabled by default")
+        logger.info_cmd("")
         if options.dnssec_master:
-            print("Plan carefully, replacing DNSSEC key master is not recommended")
-            print("")
-        print("")
-        print("To accept the default shown in brackets, press the Enter key.")
-        print("")
+            logger.info_cmd("Plan carefully, replacing DNSSEC key master is "
+                            "not recommended")
+            logger.info_cmd("")
+        logger.info_cmd("")
+        logger.info_cmd("To accept the default shown in brackets, press the "
+                        "Enter key.")
+        logger.info_cmd("")
 
     if (options.dnssec_master and not options.unattended and not
         ipautil.user_input(
@@ -216,7 +223,7 @@ def install_check(standalone, api, replica, options, hostname):
         dnssec_masters = ods.get_masters()
         # we can reinstall current server if it is dnssec master
         if dnssec_masters and api.env.host not in dnssec_masters:
-            print("DNSSEC key master(s):", u','.join(dnssec_masters))
+            logger.info_cmd("DNSSEC key master(s):", u','.join(dnssec_masters))
             raise ScriptError(
                 "Only one DNSSEC key master is supported in current version.")
 
@@ -295,7 +302,7 @@ def install_check(standalone, api, replica, options, hostname):
         if not options.no_dnssec_validation \
                 and not bindinstance.check_forwarders(options.forwarders):
             options.no_dnssec_validation = True
-            print("WARNING: DNSSEC validation will be disabled")
+            logger.info_cmd("WARNING: DNSSEC validation will be disabled")
 
     logger.debug("will use DNS forwarders: %s\n", options.forwarders)
 
@@ -315,7 +322,7 @@ def install_check(standalone, api, replica, options, hostname):
     )
 
     if reverse_zones:
-        print("Using reverse zone(s) %s" % ', '.join(reverse_zones))
+        logger.info_cmd("Using reverse zone(s) %s" % ', '.join(reverse_zones))
 
 
 def install(standalone, replica, options, api=api):
@@ -332,13 +339,14 @@ def install(standalone, replica, options, api=api):
                no_dnssec_validation=options.no_dnssec_validation)
 
     if standalone and not options.unattended:
-        print("")
-        print("The following operations may take some minutes to complete.")
-        print("Please wait until the prompt is returned.")
-        print("")
+        logger.info_cmd("")
+        logger.info_cmd("The following operations may take some minutes to "
+                        "complete.")
+        logger.info_cmd("Please wait until the prompt is returned.")
+        logger.info_cmd("")
 
     bind.create_instance()
-    print("Restarting the web server to pick up resolv.conf changes")
+    logger.info_cmd("Restarting the web server to pick up resolv.conf changes")
     services.knownservices.httpd.restart(capture_output=True)
 
     # on dnssec master this must be installed last
@@ -365,33 +373,35 @@ def install(standalone, replica, options, api=api):
     bind.update_system_records()
 
     if standalone:
-        print("==============================================================================")
-        print("Setup complete")
-        print("")
+        logger.info_cmd("==================================================="
+                        "===========================")
+        logger.info_cmd("Setup complete")
+        logger.info_cmd("")
         bind.check_global_configuration()
-        print("")
-        print("")
-        print("\tYou must make sure these network ports are open:")
-        print("\t\tTCP Ports:")
-        print("\t\t  * 53: bind")
-        print("\t\tUDP Ports:")
-        print("\t\t  * 53: bind")
+        logger.info_cmd("")
+        logger.info_cmd("")
+        logger.info_cmd("\tYou must make sure these network ports are open:")
+        logger.info_cmd("\t\tTCP Ports:")
+        logger.info_cmd("\t\t  * 53: bind")
+        logger.info_cmd("\t\tUDP Ports:")
+        logger.info_cmd("\t\t  * 53: bind")
     elif not standalone and replica:
-        print("")
+        logger.info_cmd("")
         bind.check_global_configuration()
-        print("")
+        logger.info_cmd("")
 
 
 def uninstall_check(options):
     # test if server is DNSSEC key master
     masters = opendnssecinstance.get_dnssec_key_masters(api.Backend.ldap2)
     if api.env.host in masters:
-        print("This server is active DNSSEC key master. Uninstall could break your DNS system.")
+        logger.info_cmd("This server is active DNSSEC key master. Uninstall "
+                        "could break your DNS system.")
         if not (options.unattended or user_input(
                 "Are you sure you want to continue with the uninstall "
                 "procedure?", False)):
-            print("")
-            print("Aborting uninstall operation.")
+            logger.info_cmd("")
+            logger.info_cmd("Aborting uninstall operation.")
             sys.exit(1)
 
 
diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py
index a1651b2398..fb27abaa97 100644
--- a/ipaserver/install/dnskeysyncinstance.py
+++ b/ipaserver/install/dnskeysyncinstance.py
@@ -2,7 +2,7 @@
 # Copyright (C) 2014  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import logging
 import errno
@@ -97,7 +97,7 @@ def remove_replica_public_keys(self, replica_fqdn):
             ldap.delete_entry(entry)
 
     def start_dnskeysyncd(self):
-        print("Restarting ipa-dnskeysyncd")
+        logger.info_cmd("Restarting ipa-dnskeysyncd")
         self.__start()
 
     def create_instance(self, fqdn, realm_name):
@@ -439,7 +439,7 @@ def __start(self):
         try:
             self.restart()
         except Exception as e:
-            print("Failed to start ipa-dnskeysyncd")
+            logger.info_cmd("Failed to start ipa-dnskeysyncd")
             logger.debug("Failed to start ipa-dnskeysyncd: %s", e)
 
 
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 8240e3043d..b3b5d4ed1e 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -18,7 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import logging
 import shutil
@@ -1052,7 +1052,7 @@ def change_admin_password(self, password):
                 ipautil.run(args, env=env)
                 logger.debug("ldappasswd done")
             except ipautil.CalledProcessError as e:
-                print("Unable to set admin password", e)
+                logger.info_cmd("Unable to set admin password %s" % e)
                 logger.debug("Unable to set admin password %s", e)
 
     def uninstall(self):
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 39564c418c..588bb841bd 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -175,7 +175,8 @@ def verify_fqdn(host_name, no_host_dns=False, local_hostname=True):
                 e.errno, e.strerror)  # pylint: disable=no-member
 
     if no_host_dns:
-        print("Warning: skipping DNS resolution of host", host_name)
+        logger.info_cmd("Warning: skipping DNS resolution of host %s" %
+                        host_name)
         return
 
     try:
@@ -254,7 +255,8 @@ def record_in_hosts(ip, host_name=None, conf_file=paths.HOSTS):
                     return None
             return (hosts_ip, names)
         except IndexError:
-            print("Warning: Erroneous line '%s' in %s" % (line, conf_file))
+            logger.info_cmd(
+                "Warning: Erroneous line '%s' in %s" % (line, conf_file))
             continue
 
     return None
@@ -278,7 +280,7 @@ def read_ip_addresses():
         try:
             ip_parsed = ipautil.CheckedIPAddress(ip)
         except Exception as e:
-            print("Error: Invalid IP Address %s: %s" % (ip, e))
+            logger.info_cmd("Error: Invalid IP Address %s: %s" % (ip, e))
             continue
         ips.append(ip_parsed)
 
@@ -288,13 +290,15 @@ def read_ip_addresses():
 def read_dns_forwarders():
     addrs = []
     if ipautil.user_input("Do you want to configure DNS forwarders?", True):
-        print("Following DNS servers are configured in /etc/resolv.conf: %s" %
-                ", ".join(resolver.get_default_resolver().nameservers))
+        logger.info_cmd(
+            "Following DNS servers are configured in /etc/resolv.conf: %s" %
+            ", ".join(resolver.get_default_resolver().nameservers))
         if ipautil.user_input("Do you want to configure these servers as DNS "
                 "forwarders?", True):
             addrs = resolver.default_resolver.nameservers[:]
-            print("All DNS servers from /etc/resolv.conf were added. You can "
-                  "enter additional addresses now:")
+            logger.info_cmd(
+                "All DNS servers from /etc/resolv.conf were added. You can "
+                "enter additional addresses now:")
         while True:
             ip = ipautil.user_input("Enter an IP address for a DNS forwarder, "
                                     "or press Enter to skip", allow_empty=True)
@@ -303,15 +307,16 @@ def read_dns_forwarders():
             try:
                 ip_parsed = ipautil.CheckedIPAddress(ip, parse_netmask=False)
             except Exception as e:
-                print("Error: Invalid IP Address %s: %s" % (ip, e))
-                print("DNS forwarder %s not added." % ip)
+                logger.info_cmd("Error: Invalid IP Address %s: %s" % (ip, e))
+                logger.info_cmd("DNS forwarder %s not added." % ip)
                 continue
 
-            print("DNS forwarder %s added. You may add another." % ip)
+            logger.info_cmd("DNS forwarder %s added. You may add another." %
+                            ip)
             addrs.append(str(ip_parsed))
 
     if not addrs:
-        print("No DNS forwarders configured")
+        logger.info_cmd("No DNS forwarders configured")
 
     return addrs
 
@@ -360,7 +365,7 @@ def read_password(user, confirm=True, validate=True, retry=True, validator=_read
                 try:
                     validator(pwd)
                 except ValueError as e:
-                    print(str(e))
+                    logger.info_cmd(str(e))
                     pwd = None
                     continue
             if not confirm:
@@ -368,15 +373,15 @@ def read_password(user, confirm=True, validate=True, retry=True, validator=_read
                 continue
             pwd_confirm = get_password("Password (confirm): ")
             if pwd != pwd_confirm:
-                print("Password mismatch!")
-                print("")
+                logger.info_cmd("Password mismatch!")
+                logger.info_cmd("")
                 pwd = None
             else:
                 correct = True
     except EOFError:
         return None
     finally:
-        print("")
+        logger.info_cmd("")
     return pwd
 
 def update_file(filename, orig, subst):
@@ -393,7 +398,7 @@ def update_file(filename, orig, subst):
         os.chown(filename, st.st_uid, st.st_gid) # reset perms
         return 0
     else:
-        print("File %s doesn't exist." % filename)
+        logger.info_cmd("File %s doesn't exist." % filename)
         return 1
 
 
@@ -544,8 +549,9 @@ def update_hosts_file(ip_addresses, host_name, fstore):
     for ip_address in ip_addresses:
         if record_in_hosts(str(ip_address)):
             continue
-        print("Adding [{address!s} {name}] to your /etc/hosts file".format(
-            address=ip_address, name=host_name))
+        logger.info_cmd(
+            "Adding [{address!s} {name}] to your /etc/hosts file".format(
+                address=ip_address, name=host_name))
         add_record_to_hosts(str(ip_address), host_name)
 
 
@@ -759,7 +765,7 @@ def run_script(main_function, operation_name, log_file_name=None,
                 logger.debug('The %s command failed, exception: %s: %s',
                              operation_name, type(e).__name__, e)
                 if fail_message and not isinstance(e, SystemExit):
-                    print(fail_message)
+                    logger.info_cmd(fail_message)
                 raise
         else:
             if return_value:
diff --git a/ipaserver/install/ipa_crlgen_manage.py b/ipaserver/install/ipa_crlgen_manage.py
index b5d9a81efb..738385358c 100644
--- a/ipaserver/install/ipa_crlgen_manage.py
+++ b/ipaserver/install/ipa_crlgen_manage.py
@@ -2,7 +2,7 @@
 # Copyright (C) 2019  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import os
 import logging
@@ -96,23 +96,24 @@ def disable(self, ca):
     def status(self, ca):
         # When the local node is not a CA, return "disabled"
         if not self.check_local_ca_instance():
-            print("CRL generation: disabled")
+            logger.info_cmd("CRL generation: disabled")
             return
 
         # Local node is a CA, check its configuration
         if ca.is_crlgen_enabled():
-            print("CRL generation: enabled")
+            logger.info_cmd("CRL generation: enabled")
             try:
                 crl_filename = os.path.join(paths.PKI_CA_PUBLISH_DIR,
                                             'MasterCRL.bin')
                 with open(crl_filename, 'rb') as f:
                     crl = x509.load_der_x509_crl(f.read(), default_backend())
-                    print("Last CRL update: {}".format(crl.last_update))
+                    logger.info_cmd("Last CRL update: {}".format(
+                        crl.last_update))
                     for ext in crl.extensions:
                         if ext.oid == x509.oid.ExtensionOID.CRL_NUMBER:
-                            print("Last CRL Number: {}".format(
+                            logger.info_cmd("Last CRL Number: {}".format(
                                 ext.value.crl_number))
             except IOError:
                 logger.error("Unable to find last CRL")
         else:
-            print("CRL generation: disabled")
+            logger.info_cmd("CRL generation: disabled")
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index 44592bc89c..ebd2f92c40 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -17,7 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import logging
 import itertools
@@ -100,7 +100,7 @@ def replica_conn_check(master_host, host_name, realm, check_ca,
 
     Does not return a value, will raise ScriptError on failure.
     """
-    print("Run connection check to master")
+    logger.info_cmd("Run connection check to master")
     args = [paths.IPA_REPLICA_CONNCHECK, "--master", master_host,
             "--auto-master-check", "--realm", realm,
             "--hostname", host_name]
@@ -128,7 +128,7 @@ def replica_conn_check(master_host, host_name, realm, check_ca,
             "\nSee /var/log/ipareplica-conncheck.log for more information."
             "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.")
     else:
-        print("Connection check OK")
+        logger.info_cmd("Connection check OK")
 
 
 def enable_replication_version_checking(realm, dirman_passwd):
@@ -666,7 +666,7 @@ def setup_chaining_backend(self, conn):
             except errors.DuplicateEntry:
                 benum += 1
             except errors.ExecutionError as e:
-                print("Could not add backend entry " + dn, e)
+                logger.info_cmd("Could not add backend entry %s %s" % (dn, e))
                 raise
 
         return cn
@@ -720,13 +720,15 @@ def setup_chain_on_update(self, other_conn):
 
     def add_passsync_user(self, conn, password):
         pass_dn = DN(('uid', 'passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'), self.suffix)
-        print("The user for the Windows PassSync service is %s" % pass_dn)
+        logger.info_cmd(
+            "The user for the Windows PassSync service is %s" % pass_dn)
         try:
             conn.get_entry(pass_dn)
-            print("Windows PassSync system account exists, not resetting password")
+            logger.info_cmd("Windows PassSync system account exists, not "
+                            "resetting password")
         except errors.NotFound:
             # The user doesn't exist, add it
-            print("Adding Windows PassSync system account")
+            logger.info_cmd("Adding Windows PassSync system account")
             entry = conn.make_entry(
                 pass_dn,
                 objectclass=["account", "simplesecurityobject", "inetUser"],
@@ -1022,7 +1024,7 @@ def check_repl_init(self, conn, agmtdn, start):
                     'nsds5ReplicaLastInitEnd']
         entry = conn.get_entry(agmtdn, attrlist)
         if not entry:
-            print("Error reading status from agreement", agmtdn)
+            logger.info_cmd("Error reading status from agreement %s" % agmtdn)
             hasError = 1
         else:
             refresh = entry.single_value.get('nsds5BeginReplicaRefresh')
@@ -1030,20 +1032,22 @@ def check_repl_init(self, conn, agmtdn, start):
             status = entry.single_value.get('nsds5ReplicaLastInitStatus')
             if not refresh: # done - check status
                 if not status:
-                    print("No status yet")
+                    logger.info_cmd("No status yet")
                 elif status.find("replica busy") > -1:
-                    print("[%s] reports: Replica Busy! Status: [%s]"
-                          % (conn.ldap_uri, status))
+                    logger.info_cmd(
+                        "[%s] reports: Replica Busy! Status: [%s]" %
+                        (conn.ldap_uri, status))
                     done = True
                     hasError = 2
                 elif status.find("Total update succeeded") > -1:
-                    print("\nUpdate succeeded")
+                    logger.info_cmd("\nUpdate succeeded")
                     done = True
                 elif inprogress.lower() == 'true':
-                    print("\nUpdate in progress yet not in progress")
+                    logger.info_cmd("\nUpdate in progress yet not in progress")
                 else:
-                    print("\n[%s] reports: Update failed! Status: [%s]"
-                          % (conn.ldap_uri, status))
+                    logger.info_cmd(
+                        "\n[%s] reports: Update failed! Status: [%s]" %
+                        (conn.ldap_uri, status))
                     hasError = 1
                     done = True
             else:
@@ -1064,7 +1068,7 @@ def check_repl_update(self, conn, agmtdn):
                     'nsds5ReplicaLastUpdateEnd']
         entry = conn.get_entry(agmtdn, attrlist)
         if not entry:
-            print("Error reading status from agreement", agmtdn)
+            logger.info_cmd("Error reading status from agreement %s" % agmtdn)
             hasError = 1
         else:
             inprogress = entry.single_value.get('nsds5replicaUpdateInProgress')
@@ -1106,7 +1110,7 @@ def wait_for_repl_init(self, conn, agmtdn):
         while not done and not haserror:
             time.sleep(1)  # give it a few seconds to get going
             done, haserror = self.check_repl_init(conn, agmtdn, start)
-        print("")
+        logger.info_cmd("")
         return haserror
 
     def wait_for_repl_update(self, conn, agmtdn, maxtries=600):
@@ -1118,12 +1122,15 @@ def wait_for_repl_update(self, conn, agmtdn, maxtries=600):
             done, haserror, error_message = self.check_repl_update(conn, agmtdn)
             maxtries -= 1
         if maxtries == 0: # too many tries
-            print("Error: timeout: could not determine agreement status: please check your directory server logs for possible errors")
+            logger.info_cmd("Error: timeout: could not determine agreement "
+                            "status: please check your directory server logs "
+                            "for possible errors")
             haserror = 1
         return haserror, error_message
 
     def start_replication(self, conn, hostname=None, master=None):
-        print("Starting replication, please wait until this has completed.")
+        logger.info_cmd(
+            "Starting replication, please wait until this has completed.")
         if hostname is None:
             hostname = self.hostname
         _cn, dn = self.agreement_dn(hostname, master)
@@ -1516,11 +1523,14 @@ def cleanallruv(self, replicaId):
         try:
             self.conn.add_entry(e)
         except errors.DuplicateEntry:
-            print("CLEANALLRUV task for replica id %d already exists." % replicaId)
+            logger.info_cmd(
+                "CLEANALLRUV task for replica id %d already exists." %
+                replicaId)
         else:
-            print("Background task created to clean replication data. This may take a while.")
+            logger.info_cmd("Background task created to clean replication "
+                            "data. This may take a while.")
 
-        print("This may be safely interrupted with Ctrl+C")
+        logger.info_cmd("This may be safely interrupted with Ctrl+C")
 
         wait_for_task(self.conn, dn)
 
@@ -1545,11 +1555,12 @@ def abortcleanallruv(self, replicaId, force=False):
         try:
             self.conn.add_entry(e)
         except errors.DuplicateEntry:
-            print("An abort CLEANALLRUV task for replica id %d already exists." % replicaId)
+            logger.info_cmd("An abort CLEANALLRUV task for replica id %d "
+                            "already exists." % replicaId)
         else:
-            print("Background task created. This may take a while.")
+            logger.info_cmd("Background task created. This may take a while.")
 
-        print("This may be safely interrupted with Ctrl+C")
+        logger.info_cmd("This may be safely interrupted with Ctrl+C")
 
         wait_for_task(self.conn, dn)
 
diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
index ac56ddcf76..466fd3819f 100644
--- a/ipaserver/install/server/__init__.py
+++ b/ipaserver/install/server/__init__.py
@@ -8,6 +8,7 @@
 
 from __future__ import print_function
 
+import logging
 import collections
 import os.path
 import random
@@ -40,6 +41,7 @@
 
 from .. import adtrust, ca, conncheck, dns, kra
 
+logger = logging.getLogger(__name__)
 
 @group
 class ServerUninstallInterface(service.ServiceInstallInterface):
@@ -522,7 +524,7 @@ class ServerMasterInstall(ServerMasterInstallInterface):
     def domain_name(self, value):
         if (self.setup_dns and
                 not self.allow_zone_overlap):
-            print("Checking DNS domain %s, please wait ..." % value)
+            logger.info_cmd("Checking DNS domain %s, please wait ..." % value)
             check_zone_overlap(value, False)
 
     dm_password = extend_knob(
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index b56bbe6859..b20e84fd84 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -2,7 +2,7 @@
 # Copyright (C) 2015  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import errno
 import logging
@@ -161,35 +161,39 @@ def write_cache(options):
 
 
 def read_host_name(host_default, no_host_dns=False):
-    print("Enter the fully qualified domain name of the computer")
-    print("on which you're setting up server software. Using the form")
-    print("<hostname>.<domainname>")
-    print("Example: master.example.com.")
-    print("")
-    print("")
+    logger.info_cmd("Enter the fully qualified domain name of the computer")
+    logger.info_cmd(
+        "on which you're setting up server software. Using the form")
+    logger.info_cmd("<hostname>.<domainname>")
+    logger.info_cmd("Example: master.example.com.")
+    logger.info_cmd("")
+    logger.info_cmd("")
     if host_default == "":
         host_default = "master.example.com"
     host_name = user_input("Server host name", host_default, allow_empty=False)
-    print("")
+    logger.info_cmd("")
     verify_fqdn(host_name, no_host_dns)
 
     return host_name
 
 
 def read_domain_name(domain_name, unattended):
-    print("The domain name has been determined based on the host name.")
-    print("")
+    logger.info_cmd(
+        "The domain name has been determined based on the host name.")
+    logger.info_cmd("")
     if not unattended:
         domain_name = str(user_input("Please confirm the domain name",
                                      domain_name))
-        print("")
+        logger.info_cmd("")
     return domain_name
 
 
 def read_realm_name(domain_name, unattended):
-    print("The kerberos protocol requires a Realm name to be defined.")
-    print("This is typically the domain name converted to uppercase.")
-    print("")
+    logger.info_cmd(
+        "The kerberos protocol requires a Realm name to be defined.")
+    logger.info_cmd(
+        "This is typically the domain name converted to uppercase.")
+    logger.info_cmd("")
 
     if unattended:
         return domain_name.upper()
@@ -197,26 +201,29 @@ def read_realm_name(domain_name, unattended):
                                 domain_name.upper()))
     upper_dom = realm_name.upper()
     if upper_dom != realm_name:
-        print("An upper-case realm name is required.")
+        logger.info_cmd("An upper-case realm name is required.")
         if not user_input("Do you want to use " + upper_dom +
                           " as realm name?", True):
             raise ScriptError(
                 "An upper-case realm name is required. Unable to continue.")
         else:
             realm_name = upper_dom
-        print("")
+        logger.info_cmd("")
     return realm_name
 
 
 def read_dm_password():
-    print("Certain directory server operations require an administrative user.")
-    print("This user is referred to as the Directory Manager and has full "
-          "access")
-    print("to the Directory for system management tasks and will be added to "
-          "the")
-    print("instance of directory server created for IPA.")
-    print("The password must be at least 8 characters long.")
-    print("")
+    logger.info_cmd(
+        "Certain directory server operations require an administrative user.")
+    logger.info_cmd(
+        "This user is referred to as the Directory Manager and has full "
+        "access")
+    logger.info_cmd(
+        "to the Directory for system management tasks and will be added to "
+        "the")
+    logger.info_cmd("instance of directory server created for IPA.")
+    logger.info_cmd("The password must be at least 8 characters long.")
+    logger.info_cmd("")
     # TODO: provide the option of generating a random password
     dm_password = read_password("Directory Manager",
                                 validator=validate_dm_password)
@@ -224,10 +231,12 @@ def read_dm_password():
 
 
 def read_admin_password():
-    print("The IPA server requires an administrative user, named 'admin'.")
-    print("This user is a regular system account used for IPA server "
-          "administration.")
-    print("")
+    logger.info_cmd(
+        "The IPA server requires an administrative user, named 'admin'.")
+    logger.info_cmd(
+        "This user is a regular system account used for IPA server "
+        "administration.")
+    logger.info_cmd("")
     # TODO: provide the option of generating a random password
     admin_password = read_password("IPA admin",
                                    validator=validate_admin_password)
@@ -255,9 +264,10 @@ def decorated(installer):
             success = True
         except KeyboardInterrupt:
             ds = installer._ds
-            print("\nCleaning up...")
+            logger.info_cmd("\nCleaning up...")
             if ds:
-                print("Removing configuration for %s instance" % ds.serverid)
+                logger.info_cmd(
+                    "Removing configuration for %s instance" % ds.serverid)
                 ds.stop()
                 if ds.serverid:
                     try:
@@ -318,7 +328,7 @@ def install_check(installer):
 
     mask_str = validate_mask()
     if mask_str:
-        print("Unexpected system mask: %s, expected 0022" % mask_str)
+        logger.info_cmd("Unexpected system mask: %s, expected 0022" % mask_str)
         if installer.interactive:
             if not user_input("Do you want to continue anyway?", True):
                 raise ScriptError(
@@ -331,12 +341,12 @@ def install_check(installer):
                "KDC master password of sufficient strength is autogenerated "
                "during IPA server installation and should not be set "
                "manually.")
-        print(textwrap.fill(msg, width=79, replace_whitespace=False))
+        logger.info_cmd(textwrap.fill(msg, width=79, replace_whitespace=False))
 
     installer._installation_cleanup = True
 
-    print("\nThe log file for this installation can be found in "
-          "/var/log/ipaserver-install.log")
+    logger.info_cmd("\nThe log file for this installation can be found in "
+                    "/var/log/ipaserver-install.log")
     if (not options.external_ca and not options.external_cert_files and
             is_ipa_configured()):
         installer._installation_cleanup = False
@@ -390,36 +400,39 @@ def install_check(installer):
         raise ScriptError(
             "--setup-kra cannot be used with CA-less installation")
 
-    print("======================================="
-          "=======================================")
-    print("This program will set up the FreeIPA Server.")
-    print("Version {}".format(version.VERSION))
-    print("")
-    print("This includes:")
+    logger.info_cmd("======================================="
+                    "=======================================")
+    logger.info_cmd("This program will set up the FreeIPA Server.")
+    logger.info_cmd("Version {}".format(version.VERSION))
+    logger.info_cmd("")
+    logger.info_cmd("This includes:")
     if setup_ca:
-        print("  * Configure a stand-alone CA (dogtag) for certificate "
-              "management")
+        logger.info_cmd("  * Configure a stand-alone CA (dogtag) for "
+                        "certificate management")
     if not options.no_ntp:
-        print("  * Configure the NTP client (chronyd)")
-    print("  * Create and configure an instance of Directory Server")
-    print("  * Create and configure a Kerberos Key Distribution Center (KDC)")
-    print("  * Configure Apache (httpd)")
+        logger.info_cmd("  * Configure the NTP client (chronyd)")
+    logger.info_cmd("  * Create and configure an instance of Directory Server")
+    logger.info_cmd("  * Create and configure a Kerberos Key Distribution "
+                    "Center (KDC)")
+    logger.info_cmd("  * Configure Apache (httpd)")
     if options.setup_kra:
-        print("  * Configure KRA (dogtag) for secret management")
+        logger.info_cmd("  * Configure KRA (dogtag) for secret management")
     if options.setup_dns:
-        print("  * Configure DNS (bind)")
+        logger.info_cmd("  * Configure DNS (bind)")
     if options.setup_adtrust:
-        print("  * Configure Samba (smb) and winbind for managing AD trusts")
+        logger.info_cmd("  * Configure Samba (smb) and winbind for managing "
+                        "AD trusts")
     if not options.no_pkinit:
-        print("  * Configure the KDC to enable PKINIT")
+        logger.info_cmd("  * Configure the KDC to enable PKINIT")
     if options.no_ntp:
-        print("")
-        print("Excluded by options:")
-        print("  * Configure the NTP client (chronyd)")
+        logger.info_cmd("")
+        logger.info_cmd("Excluded by options:")
+        logger.info_cmd("  * Configure the NTP client (chronyd)")
     if installer.interactive:
-        print("")
-        print("To accept the default shown in brackets, press the Enter key.")
-    print("")
+        logger.info_cmd("")
+        logger.info_cmd("To accept the default shown in brackets, press the "
+                        "Enter key.")
+    logger.info_cmd("")
 
     if not options.external_cert_files:
         # Make sure the 389-ds ports are available
@@ -429,10 +442,11 @@ def install_check(installer):
         try:
             ipaclient.install.timeconf.check_timedate_services()
         except ipaclient.install.timeconf.NTPConflictingService as e:
-            print("WARNING: conflicting time&date synchronization service '{}'"
-                  " will be disabled".format(e.conflicting_service))
-            print("in favor of chronyd")
-            print("")
+            logger.info_cmd(
+                "WARNING: conflicting time&date synchronization service '{}'"
+                " will be disabled".format(e.conflicting_service))
+            logger.info_cmd("in favor of chronyd")
+            logger.info_cmd("")
         except ipaclient.install.timeconf.NTPConfigurationError:
             pass
 
@@ -440,7 +454,7 @@ def install_check(installer):
         if ipautil.user_input("Do you want to configure integrated DNS "
                               "(BIND)?", False):
             options.setup_dns = True
-        print("")
+        logger.info_cmd("")
 
     # check bind packages are installed
     if options.setup_dns:
@@ -672,30 +686,32 @@ def install_check(installer):
     if options.ip_addresses or options.setup_dns:
         installer._update_hosts_file = True
 
-    print()
-    print("The IPA Master Server will be configured with:")
-    print("Hostname:       %s" % host_name)
-    print("IP address(es): %s" % ", ".join(str(ip) for ip in ip_addresses))
-    print("Domain name:    %s" % domain_name)
-    print("Realm name:     %s" % realm_name)
-    print()
+    logger.info_cmd("")
+    logger.info_cmd("The IPA Master Server will be configured with:")
+    logger.info_cmd("Hostname:       %s" % host_name)
+    logger.info_cmd("IP address(es): %s" % ", ".join(str(ip) for ip in
+                                                     ip_addresses))
+    logger.info_cmd("Domain name:    %s" % domain_name)
+    logger.info_cmd("Realm name:     %s" % realm_name)
+    logger.info_cmd("")
 
     if setup_ca:
         ca.print_ca_configuration(options)
-        print()
+        logger.info_cmd("")
 
     if options.setup_dns:
-        print("BIND DNS server will be configured to serve IPA domain with:")
-        print("Forwarders:       %s" % (
+        logger.info_cmd("BIND DNS server will be configured to serve IPA "
+                        "domain with:")
+        logger.info_cmd("Forwarders:       %s" % (
             "No forwarders" if not options.forwarders
             else ", ".join([str(ip) for ip in options.forwarders])
         ))
-        print('Forward policy:   %s' % options.forward_policy)
-        print("Reverse zone(s):  %s" % (
+        logger.info_cmd('Forward policy:   %s' % options.forward_policy)
+        logger.info_cmd("Reverse zone(s):  %s" % (
             "No reverse zone" if options.no_reverse or not dns.reverse_zones
             else ", ".join(str(rz) for rz in dns.reverse_zones)
         ))
-        print()
+        logger.info_cmd("")
 
     if not options.setup_adtrust:
         # If domain name and realm does not match, IPA server will not be able
@@ -704,10 +720,11 @@ def install_check(installer):
         realm_not_matching_domain = (domain_name.upper() != realm_name)
 
         if realm_not_matching_domain:
-            print("WARNING: Realm name does not match the domain name.\n"
-                  "You will not be able to establish trusts with Active "
-                  "Directory unless\nthe realm name of the IPA server matches "
-                  "its domain name.\n\n")
+            logger.info_cmd(
+                "WARNING: Realm name does not match the domain name.\n"
+                "You will not be able to establish trusts with Active "
+                "Directory unless\nthe realm name of the IPA server matches "
+                "its domain name.\n\n")
 
     if installer.interactive and not user_input(
             "Continue to configure the system with these values?", False):
@@ -759,10 +776,11 @@ def install(installer):
     installer._installation_cleanup = False
 
     if installer.interactive:
-        print("")
-        print("The following operations may take some minutes to complete.")
-        print("Please wait until the prompt is returned.")
-        print("")
+        logger.info_cmd("")
+        logger.info_cmd("The following operations may take some minutes to "
+                        "complete.")
+        logger.info_cmd("Please wait until the prompt is returned.")
+        logger.info_cmd("")
 
     # set hostname (transient and static) if user instructed us to do so
     if options._host_name_overridden:
@@ -780,9 +798,10 @@ def install(installer):
         # the ipa-server-install --uninstall
         if not options.no_ntp:
             if not ipaclient.install.client.sync_time(options, fstore, sstore):
-                print("Warning: IPA was unable to sync time with chrony!")
-                print("         Time synchronization is required for IPA "
-                      "to work correctly")
+                logger.info_cmd("Warning: IPA was unable to sync time with "
+                                "chrony!")
+                logger.info_cmd("         Time synchronization is required "
+                                "for IPA to work correctly")
 
         if options.dirsrv_cert_files:
             ds = dsinstance.DsInstance(fstore=fstore,
@@ -937,7 +956,7 @@ def install(installer):
         dur = time.time() - start
         logger.debug("Client install duration: %0.3f", dur,
                      extra={'timing': ('clientinstall', None, None, dur)})
-        print()
+        logger.info_cmd("")
     except Exception:
         raise ScriptError("Configuration of client side components failed!")
 
@@ -954,43 +973,45 @@ def install(installer):
     # Everything installed properly, activate ipa service.
     services.knownservices.ipa.enable()
 
-    print("======================================="
-          "=======================================")
-    print("Setup complete")
-    print("")
-    print("Next steps:")
-    print("\t1. You must make sure these network ports are open:")
-    print("\t\tTCP Ports:")
-    print("\t\t  * 80, 443: HTTP/HTTPS")
-    print("\t\t  * 389, 636: LDAP/LDAPS")
-    print("\t\t  * 88, 464: kerberos")
+    logger.info_cmd("======================================="
+                    "=======================================")
+    logger.info_cmd("Setup complete")
+    logger.info_cmd("")
+    logger.info_cmd("Next steps:")
+    logger.info_cmd("\t1. You must make sure these network ports are open:")
+    logger.info_cmd("\t\tTCP Ports:")
+    logger.info_cmd("\t\t  * 80, 443: HTTP/HTTPS")
+    logger.info_cmd("\t\t  * 389, 636: LDAP/LDAPS")
+    logger.info_cmd("\t\t  * 88, 464: kerberos")
     if options.setup_dns:
-        print("\t\t  * 53: bind")
-    print("\t\tUDP Ports:")
-    print("\t\t  * 88, 464: kerberos")
+        logger.info_cmd("\t\t  * 53: bind")
+    logger.info_cmd("\t\tUDP Ports:")
+    logger.info_cmd("\t\t  * 88, 464: kerberos")
     if options.setup_dns:
-        print("\t\t  * 53: bind")
+        logger.info_cmd("\t\t  * 53: bind")
     if not options.no_ntp:
-        print("\t\t  * 123: ntp")
-    print("")
-    print("\t2. You can now obtain a kerberos ticket using the command: "
-          "'kinit admin'")
-    print("\t   This ticket will allow you to use the IPA tools (e.g., ipa "
-          "user-add)")
-    print("\t   and the web user interface.")
+        logger.info_cmd("\t\t  * 123: ntp")
+    logger.info_cmd("")
+    logger.info_cmd("\t2. You can now obtain a kerberos ticket using the "
+                    "command: 'kinit admin'")
+    logger.info_cmd(
+        "\t   This ticket will allow you to use the IPA tools (e.g., ipa "
+        "user-add)")
+    logger.info_cmd("\t   and the web user interface.")
 
     if not services.knownservices.chronyd.is_running():
-        print("\t3. Kerberos requires time synchronization between clients")
-        print("\t   and servers for correct operation. You should consider "
-              "enabling chronyd.")
+        logger.info_cmd("\t3. Kerberos requires time synchronization between "
+                        "clients")
+        logger.info_cmd("\t   and servers for correct operation. You should "
+                        "consider enabling chronyd.")
 
-    print("")
+    logger.info_cmd("")
     if setup_ca:
-        print(("Be sure to back up the CA certificates stored in " +
-              paths.CACERT_P12))
-        print("These files are required to create replicas. The password for "
-              "these")
-        print("files is the Directory Manager password")
+        logger.info_cmd("Be sure to back up the CA certificates stored in " +
+                        paths.CACERT_P12)
+        logger.info_cmd("These files are required to create replicas. The "
+                        "password for these")
+        logger.info_cmd("files is the Directory Manager password")
 
     if os.path.isfile(paths.ROOT_IPA_CACHE):
         os.remove(paths.ROOT_IPA_CACHE)
@@ -1005,9 +1026,10 @@ def uninstall_check(installer):
     installer._installation_cleanup = False
 
     if not is_ipa_configured():
-        print("WARNING:\nIPA server is not configured on this system. "
-              "If you want to install the\nIPA server, please install "
-              "it using 'ipa-server-install'.")
+        logger.info_cmd(
+            "WARNING:\nIPA server is not configured on this system. "
+            "If you want to install the\nIPA server, please install "
+            "it using 'ipa-server-install'.")
 
     fstore = sysrestore.FileStore(SYSRESTORE_DIR_PATH)
     sstore = sysrestore.StateFile(SYSRESTORE_DIR_PATH)
@@ -1026,10 +1048,11 @@ def uninstall_check(installer):
     api.finalize()
 
     if installer.interactive:
-        print("\nThis is a NON REVERSIBLE operation and will delete all data "
-              "and configuration!\nIt is highly recommended to take a backup of "
-              "existing data and configuration using ipa-backup utility "
-              "before proceeding.\n")
+        logger.info_cmd(
+            "\nThis is a NON REVERSIBLE operation and will delete all data "
+            "and configuration!\nIt is highly recommended to take a backup of "
+            "existing data and configuration using ipa-backup utility "
+            "before proceeding.\n")
         if not user_input("Are you sure you want to continue with the "
                           "uninstall procedure?", False):
             raise ScriptError("Aborting uninstall operation.")
@@ -1046,7 +1069,7 @@ def uninstall_check(installer):
                "If this server is the last instance of CA, KRA, or DNSSEC "
                "master, uninstallation may result in data loss.\n\n"
         )
-        print(textwrap.fill(msg, width=80, replace_whitespace=False))
+        logger.info_cmd(textwrap.fill(msg, width=80, replace_whitespace=False))
 
         if (installer.interactive and not user_input(
                 "Are you sure you want to continue with the uninstall "
@@ -1077,8 +1100,9 @@ def uninstall_check(installer):
                         other_masters)
                 )
                 cmd = "$ ipa-replica-manage del %s\n" % api.env.host
-                print(textwrap.fill(msg, width=80, replace_whitespace=False))
-                print(cmd)
+                logger.info_cmd(
+                    textwrap.fill(msg, width=80, replace_whitespace=False))
+                logger.info_cmd(cmd)
                 if (installer.interactive and
                         not user_input("Are you sure you want to continue with"
                                        " the uninstall procedure?", False)):
@@ -1099,7 +1123,7 @@ def uninstall(installer):
 
     rv = 0
 
-    print("Shutting down all IPA services")
+    logger.info_cmd("Shutting down all IPA services")
     try:
         services.knownservices.ipa.stop()
     except Exception:
@@ -1199,7 +1223,7 @@ def uninstall(installer):
             logger.warning("Failed to remove file %s: %s",
                            paths.IPA_RENEWAL_LOCK, e)
 
-    print("Removing IPA client configuration")
+    logger.info_cmd("Removing IPA client configuration")
     try:
         result = run([paths.IPA_CLIENT_INSTALL, "--on-master",
                       "--unattended", "--uninstall"],
@@ -1208,7 +1232,7 @@ def uninstall(installer):
             raise RuntimeError("Failed to configure the client")
     except Exception:
         rv = 1
-        print("Uninstall of client side components failed!")
+        logger.info_cmd("Uninstall of client side components failed!")
 
     sys.exit(rv)
 
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 3cb19ace5d..373d21c4bd 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -404,7 +404,7 @@ def decorated(installer):
         except KeyboardInterrupt:
             raise ScriptError()
         except Exception:
-            print(
+            logger.info_cmd(
                 "Your system may be partly configured.\n"
                 "Run /usr/sbin/ipa-server-install --uninstall to clean up.\n")
             raise
@@ -435,10 +435,10 @@ def uninstall_client():
     An unsuccessful attempt to uninstall is ignored (no exception raised).
     """
 
-    print("Removing client side components")
+    logger.info_cmd("Removing client side components")
     ipautil.run([paths.IPA_CLIENT_INSTALL, "--unattended", "--uninstall"],
                 raiseonerr=False, redirect_output=True)
-    print()
+    logger.info_cmd("")
 
 
 def promote_sssd(host_name):
@@ -587,9 +587,10 @@ def common_check(no_ntp):
         try:
             ipaclient.install.timeconf.check_timedate_services()
         except ipaclient.install.timeconf.NTPConflictingService as e:
-            print("WARNING: conflicting time&date synchronization service "
-                  "'{svc}' will\nbe disabled in favor of chronyd\n"
-                  .format(svc=e.conflicting_service))
+            logger.info_cmd(
+                "WARNING: conflicting time&date synchronization service "
+                "'{svc}' will\nbe disabled in favor of chronyd\n"
+                .format(svc=e.conflicting_service))
         except ipaclient.install.timeconf.NTPConfigurationError:
             pass
 
@@ -733,7 +734,7 @@ def ensure_enrolled(installer):
         service.print_msg("Configuring client side components")
         installer._enrollment_performed = True
         ipautil.run(args, stdin=stdin, nolog=nolog, redirect_output=True)
-        print()
+        logger.info_cmd("")
     except ipautil.CalledProcessError:
         raise ScriptError("Configuration of client side components failed!")
 
@@ -784,9 +785,10 @@ def promote_check(installer):
     else:
         if (options.domain_name or options.server or options.realm_name or
                 options.host_name or options.password or options.keytab):
-            print("IPA client is already configured on this system, ignoring "
-                  "the --domain, --server, --realm, --hostname, --password "
-                  "and --keytab options.")
+            logger.info_cmd(
+                "IPA client is already configured on this system, ignoring "
+                "the --domain, --server, --realm, --hostname, --password "
+                "and --keytab options.")
 
         # The NTP configuration can not be touched on pre-installed client:
         if options.no_ntp or options.ntp_servers or options.ntp_pool:
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 09a0aca5d9..aa3fd02020 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -2,7 +2,7 @@
 # Copyright (C) 2015  FreeIPA Contributors see COPYING for license
 #
 
-from __future__ import print_function, absolute_import
+from __future__ import absolute_import
 
 import errno
 import logging
@@ -2197,7 +2197,7 @@ def upgrade():
         else:
             logger.info('Update complete, no data were modified')
 
-    print('Upgrading IPA services')
+    logger.info_cmd('Upgrading IPA services')
     logger.info('Upgrading the configuration of the IPA services')
     with empty_ccache():
         upgrade_configuration()
_______________________________________________
FreeIPA-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/[email protected]

Reply via email to