From 2e5b24738b90a79e0ea16cca42f761cc6f04965c Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Tue, 18 Dec 2012 14:46:41 -0500
Subject: [PATCH] Added interactive subsystem installation.

The pkispawn has been modified such that if there is no configuration
file specified it will enter an interactive mode.

Ticket #380
---
 base/deploy/etc/default.cfg                        |   6 +-
 base/deploy/src/pkidestroy                         |  18 +-
 base/deploy/src/pkispawn                           |  68 ++++++--
 .../deploy/src/scriptlets/infrastructure_layout.py |  10 +-
 base/deploy/src/scriptlets/pkiconfig.py            |   5 +-
 base/deploy/src/scriptlets/pkijython.py            |   4 +-
 base/deploy/src/scriptlets/pkiparser.py            | 192 ++++++++++++---------
 7 files changed, 177 insertions(+), 126 deletions(-)

diff --git a/base/deploy/etc/default.cfg b/base/deploy/etc/default.cfg
index 238912fcbefd6d367aa60c6ebae44ef993aff0c7..3292fe42991b03587b881b937d6857ef3ed0b69b 100644
--- a/base/deploy/etc/default.cfg
+++ b/base/deploy/etc/default.cfg
@@ -57,12 +57,12 @@ destroy_scriplets=
 # case someone wants to override them in their config file.
 #
 # Tomcat instances:
-# pki_instance_name=pki_tomcat 
+# pki_instance_name=pki-tomcat
 # pki_https_port=8443
 # pki_http_port=8080
 #
 # Apache instances:
-# pki_instance_name=pki_tomcat
+# pki_instance_name=pki-apache
 # pki_https_port=443
 # pki_http_port=80
 
@@ -125,7 +125,7 @@ pki_client_pkcs12_password_conf=%(pki_client_subsystem_dir)s/pkcs12_password.con
 pki_client_cert_database=%(pki_client_database_dir)s/cert8.db
 pki_client_key_database=%(pki_client_database_dir)s/key3.db
 pki_client_secmod_database=%(pki_client_database_dir)s/secmod.db
-pki_client_admin_cert=%(pki_subsystem_type)s_admin.cert
+pki_client_admin_cert=%(pki_client_dir)s/%(pki_subsystem_type)s_admin.cert
 pki_source_conf_path=/usr/share/pki/%(pki_subsystem_type)s/conf
 pki_source_setup_path=/usr/share/pki/setup
 pki_source_server_path=/usr/share/pki/server/conf
diff --git a/base/deploy/src/pkidestroy b/base/deploy/src/pkidestroy
index edb57e9ac3472ab34b650f7ec9cdf7662e946dc6..85e772491aa11e33d72343ee3606c176af0f9f95 100755
--- a/base/deploy/src/pkidestroy
+++ b/base/deploy/src/pkidestroy
@@ -1,4 +1,4 @@
-#!/usr/bin/python -t
+#!/usr/bin/python -tu
 # Authors:
 #     Matthew Harmsen <mharmsen@redhat.com>
 #
@@ -134,7 +134,7 @@ def main(argv):
         config.pki_subsystem.lower() + "/" +\
         config.USER_DEPLOYMENT_CONFIGURATION
 
-    parser.validate()
+    parser.initialize()
 
     # Enable 'pkidestroy' logging.
     config.pki_log_dir = config.pki_root_prefix +\
@@ -161,20 +161,6 @@ def main(argv):
                              extra=config.PKI_INDENTATION_LEVEL_0)
         sys.exit(1)
 
-    # NEVER print out 'sensitive' name/value pairs!!!
-    config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_default_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_web_server_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-
     # Combine the various sectional dictionaries into a PKI master dictionary
     parser.compose_pki_master_dictionary()
     config.pki_master_dict['pki_destroy_log'] = config.pki_log_dir + "/" +\
diff --git a/base/deploy/src/pkispawn b/base/deploy/src/pkispawn
index f64d79575000bf5c54ab5b9348cb243cce2d3b3b..f8e93c76bbb3826526d346b782f541f5aa4ed316 100755
--- a/base/deploy/src/pkispawn
+++ b/base/deploy/src/pkispawn
@@ -1,4 +1,4 @@
-#!/usr/bin/python -t
+#!/usr/bin/python -tu
 # Authors:
 #     Matthew Harmsen <mharmsen@redhat.com>
 #
@@ -52,6 +52,10 @@ error was:
 def main(argv):
     "main entry point"
 
+    print "PKI Subsystem Installation"
+    print "--------------------------"
+    print
+
     config.pki_deployment_executable = os.path.basename(argv[0])
 
     # Only run this program as "root".
@@ -96,7 +100,7 @@ def main(argv):
 
     parser.mandatory.add_argument('-f',
         dest='user_deployment_cfg', action='store',
-        nargs=1, required=True, metavar='<file>',
+        nargs=1, metavar='<file>',
         help='configuration filename '
             '(MUST specify complete path)')
 
@@ -109,12 +113,50 @@ def main(argv):
     config.default_deployment_cfg = config.PKI_DEPLOYMENT_DEFAULT_CONFIGURATION_FILE
 
     # -f <user deployment config>
-    config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']')
+    if not args.user_deployment_cfg is None:
+        config.user_deployment_cfg = str(args.user_deployment_cfg).strip('[\']')
 
     # -u
     config.pki_update_flag = args.pki_update_flag
 
-    parser.validate()
+    if config.user_deployment_cfg is None:
+        config.pki_subsystem = 'CA'
+        value = raw_input('Subsystem type [' + config.pki_subsystem + ']: ')
+        if len(value) > 0:
+            config.pki_subsystem = value
+
+    parser.initialize()
+
+    if config.user_deployment_cfg is None:
+        parser.read_text('DEFAULT', 'pki_instance_name', 'Instance name')
+        parser.read_text(config.pki_subsystem, 'pki_http_port', 'Tomcat HTTP Port')
+        parser.read_text(config.pki_subsystem, 'pki_https_port', 'Tomcat Secure HTTP port')
+        parser.read_text(config.pki_subsystem, 'pki_ajp_port', 'Tomcat AJP Port')
+        parser.read_text(config.pki_subsystem, 'pki_tomcat_server_port', 'Tomcat Server Port')
+        parser.read_text(config.pki_subsystem, 'pki_admin_uid', config.pki_subsystem + ' admin UID')
+
+        admin_password = parser.read_password(config.pki_subsystem, 'pki_admin_password', config.pki_subsystem + ' admin password')
+        parser.pki_config.set(config.pki_subsystem, 'pki_backup_password', admin_password)
+        parser.pki_config.set(config.pki_subsystem, 'pki_client_database_password', admin_password)
+        parser.pki_config.set(config.pki_subsystem, 'pki_client_pkcs12_password', admin_password)
+
+        parser.read_text(config.pki_subsystem, 'pki_client_admin_cert', config.pki_subsystem + ' admin certificate')
+
+        parser.read_text(config.pki_subsystem, 'pki_ds_hostname', 'Directory server hostname')
+        parser.read_text(config.pki_subsystem, 'pki_ds_ldap_port', 'Directory server port')
+        parser.read_text(config.pki_subsystem, 'pki_ds_base_dn', 'Directory server base DN')
+        parser.read_text(config.pki_subsystem, 'pki_ds_bind_dn', 'Directory server bind DN')
+        parser.read_password(config.pki_subsystem, 'pki_ds_password', 'Directory server password')
+
+        parser.read_text(config.pki_subsystem, 'pki_security_domain_name', 'Security domain name')
+        if config.pki_subsystem != "CA":
+            parser.read_text(config.pki_subsystem, 'pki_security_domain_hostname', 'Security domain hostname')
+            parser.read_text(config.pki_subsystem, 'pki_security_domain_https_port', 'Security domain secure HTTP port')
+            parser.read_text(config.pki_subsystem, 'pki_security_domain_user', 'Security domain user')
+            parser.read_password(config.pki_subsystem, 'pki_security_domain_password', 'Security domain password')
+            parser.read_text(config.pki_subsystem, 'pki_admin_cert_file', 'Security domain certificate')
+
+        print
 
     if not os.path.exists(config.PKI_DEPLOYMENT_SOURCE_ROOT +\
                           "/" + config.pki_subsystem.lower()):
@@ -161,20 +203,6 @@ def main(argv):
                              extra=config.PKI_INDENTATION_LEVEL_0)
         sys.exit(1)
 
-    # NEVER print out 'sensitive' name/value pairs!!!
-    config.pki_log.debug(log.PKI_DICTIONARY_DEFAULT,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_default_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_WEB_SERVER,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_web_server_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(log.PKI_DICTIONARY_SUBSYSTEM,
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-    config.pki_log.debug(pkilogging.format(config.pki_subsystem_dict),
-                         extra=config.PKI_INDENTATION_LEVEL_0)
-
     # Read in the PKI slots configuration file.
     parser.compose_pki_slots_dictionary()
     config.pki_log.debug(log.PKI_DICTIONARY_SLOTS,
@@ -184,6 +212,7 @@ def main(argv):
 
     # Combine the various sectional dictionaries into a PKI master dictionary
     parser.compose_pki_master_dictionary()
+
     if not config.pki_update_flag:
         config.pki_master_dict['pki_spawn_log'] = config.pki_log_dir + "/" +\
                                                   config.pki_log_name
@@ -214,6 +243,9 @@ def main(argv):
     config.pki_log.debug(pkilogging.format(config.pki_master_dict),
                          extra=config.PKI_INDENTATION_LEVEL_0)
 
+    print
+    print "Installation complete."
+
 
 # PKI Deployment Entry Point
 if __name__ == "__main__":
diff --git a/base/deploy/src/scriptlets/infrastructure_layout.py b/base/deploy/src/scriptlets/infrastructure_layout.py
index 947fbcdfef6cbf0217a644ce2e69c9f870bcc1c8..1a2751f63a7efde9e279598a955512df0343223a 100644
--- a/base/deploy/src/scriptlets/infrastructure_layout.py
+++ b/base/deploy/src/scriptlets/infrastructure_layout.py
@@ -58,8 +58,14 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
         util.directory.create(master['pki_subsystem_registry_path'])
         util.file.copy(master['pki_default_deployment_cfg'],
                        master['pki_default_deployment_cfg_replica'])
-        util.file.copy(master['pki_user_deployment_cfg'],
-                       master['pki_user_deployment_cfg_replica'])
+
+        if master['pki_user_deployment_cfg']:
+            util.file.copy(master['pki_user_deployment_cfg'],
+                           master['pki_user_deployment_cfg_replica'])
+        else:
+            with open(master['pki_user_deployment_cfg_replica'], 'w') as f:
+                config.user_config.write(f)
+
         # establish top-level infrastructure, instance, and subsystem
         # base directories and create the "registry" symbolic link that
         # the "pkidestroy" executable relies upon
diff --git a/base/deploy/src/scriptlets/pkiconfig.py b/base/deploy/src/scriptlets/pkiconfig.py
index 4a884617c7caab03159b68d4407b8897f151564c..cdd671c91d97c6cb5ff35d6c6576c766873a4303 100644
--- a/base/deploy/src/scriptlets/pkiconfig.py
+++ b/base/deploy/src/scriptlets/pkiconfig.py
@@ -180,10 +180,7 @@ pki_console_log_level = None
 
 
 # PKI Deployment Global Dictionaries
-pki_default_dict = None
-pki_web_server_dict = None
-pki_subsystem_dict = None
-pki_master_dict = None
+pki_master_dict = {}
 pki_slots_dict = None
 pki_master_jython_dict = None
 
diff --git a/base/deploy/src/scriptlets/pkijython.py b/base/deploy/src/scriptlets/pkijython.py
index fac352fdb6be71f747394be286d682902ce578d9..da9779c81f1010e04b34d4d70bf459dec5947680 100644
--- a/base/deploy/src/scriptlets/pkijython.py
+++ b/base/deploy/src/scriptlets/pkijython.py
@@ -560,9 +560,7 @@ class rest_client:
                 javasystem.out.println(log.PKI_JYTHON_RESPONSE_ADMIN_CERT +\
                                        " " + admin_cert)
                 # Store the Administration Certificate in a file
-                admin_cert_file = os.path.join(
-                    master['pki_client_dir'],
-                    master['pki_client_admin_cert'])
+                admin_cert_file = master['pki_client_admin_cert']
                 admin_cert_bin_file = admin_cert_file + ".der"
                 javasystem.out.println(log.PKI_JYTHON_ADMIN_CERT_SAVE +\
                                        " " + "'" + admin_cert_file + "'")
diff --git a/base/deploy/src/scriptlets/pkiparser.py b/base/deploy/src/scriptlets/pkiparser.py
index ba4f376daf4a26e8b4495b25f3c9dcccf66f8ed9..33c7e389a40d754f4b805a55f4232e1590838980 100644
--- a/base/deploy/src/scriptlets/pkiparser.py
+++ b/base/deploy/src/scriptlets/pkiparser.py
@@ -22,6 +22,7 @@
 # System Imports
 import ConfigParser
 import argparse
+import getpass
 import logging
 import os
 import random
@@ -57,7 +58,7 @@ class PKIConfigParser:
         self.mandatory.add_argument('-s',
                                dest='pki_subsystem', action='store',
                                nargs=1, choices=config.PKI_SUBSYSTEMS,
-                               required=True, metavar='<subsystem>',
+                               metavar='<subsystem>',
                                help='where <subsystem> is '
                                     'CA, KRA, OCSP, RA, TKS, or TPS')
         # Establish 'Optional' command-line options
@@ -122,7 +123,7 @@ class PKIConfigParser:
         return args
 
 
-    def validate(self):
+    def initialize(self):
 
         # Validate command-line options
         if len(config.pki_root_prefix) > 0:
@@ -145,16 +146,60 @@ class PKIConfigParser:
             self.arg_parser.print_help()
             self.arg_parser.exit(-1);
 
-        # verify user configuration file exists
-        if not os.path.exists(config.user_deployment_cfg) or\
-            not os.path.isfile(config.user_deployment_cfg):
-            print "ERROR:  " +\
-                  log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\
-                  config.user_deployment_cfg
-            print
-            self.arg_parser.print_help()
-            self.arg_parser.exit(-1);
+        if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+            default_instance_name = 'pki-tomcat'
+            default_http_port = '8080'
+            default_https_port = '8443'
+        else:
+            default_instance_name = 'pki-apache'
+            default_http_port = '80'
+            default_https_port = '443'
 
+        # RESTEasy
+        resteasy_lib = subprocess.check_output(\
+            'source /etc/pki/pki.conf && echo $RESTEASY_LIB',
+            shell=True).strip()
+
+        # arch dependent libpath
+        if config.pki_architecture == 64:
+            arch_java_lib = '/usr/lib64/java'
+        else:
+            arch_java_lib = '/usr/lib/java'
+
+        self.pki_config = ConfigParser.SafeConfigParser({
+            'pki_instance_name': default_instance_name,
+            'pki_http_port': default_http_port,
+            'pki_https_port': default_https_port,
+            'pki_dns_domainname': config.pki_dns_domainname,
+            'pki_subsystem' : config.pki_subsystem,
+            'pki_subsystem_type': config.pki_subsystem.lower(),
+            'pki_root_prefix' : config.pki_root_prefix,
+            'resteasy_lib': resteasy_lib,
+            'arch_java_lib': arch_java_lib,
+            'home_dir': os.path.expanduser("~"),
+            'pki_hostname': config.pki_hostname})
+
+        # Make keys case-sensitive!
+        self.pki_config.optionxform = str
+
+        with open(config.default_deployment_cfg) as f:
+                self.pki_config.readfp(f)
+
+        self.flatten_master_dict()
+
+        config.user_config = ConfigParser.SafeConfigParser()
+        config.user_config.optionxform = str
+
+        if config.user_deployment_cfg:
+            # verify user configuration file exists
+            if not os.path.exists(config.user_deployment_cfg) or\
+                not os.path.isfile(config.user_deployment_cfg):
+                print "ERROR:  " +\
+                      log.PKI_FILE_MISSING_OR_NOT_A_FILE_1 %\
+                      config.user_deployment_cfg
+                print
+                parser.arg_parser.print_help()
+                parser.arg_parser.exit(-1);
 
     # The following code is based heavily upon
     # "http://www.decalage.info/en/python/configparser"
@@ -179,84 +224,73 @@ class PKIConfigParser:
         f.close()
         return values
 
+    def read_text(self, section, property, message):
+        default = config.pki_master_dict[property]
+        if default:
+            message = message + ' [' + default + ']'
+        value = raw_input(message + ': ')
+        if len(value) == 0:
+            value = default
+
+        self.pki_config.set(section, property, value)
+        self.flatten_master_dict()
+
+        if section != "DEFAULT" and not config.user_config.has_section(section):
+            config.user_config.add_section(section)
+        config.user_config.set(section, property, value)
+
+        return value
+
+    def read_password(self, section, property, message):
+        value = ''
+        while len(value) == 0:
+            value = getpass.getpass(prompt=message + ': ')
+
+        self.pki_config.set(section, property, value)
+        self.flatten_master_dict()
+
+        if section != "DEFAULT" and not config.user_config.has_section(section):
+            config.user_config.add_section(section)
+        config.user_config.set(section, property, value)
+
+        return value
 
     def read_pki_configuration_file(self):
         "Read configuration file sections into dictionaries"
         rv = 0
         try:
-            if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
-                default_instance_name = 'pki-tomcat'
-                default_http_port = '8080'
-                default_https_port = '8443'
-            else:
-                default_instance_name = 'pki-apache'
-                default_http_port = '80'
-                default_https_port = '443'
+            if config.user_deployment_cfg:
+                print 'Reading configuration file ' + config.user_deployment_cfg + '.'
+                self.pki_config.read([config.user_deployment_cfg])
 
-            # RESTEasy
-            resteasy_lib = subprocess.check_output(\
-                'source /etc/pki/pki.conf && echo $RESTEASY_LIB',
-                shell=True).strip()
-
-            # arch dependent libpath
-            if config.pki_architecture == 64:
-                arch_java_lib = '/usr/lib64/java'
-            else:
-                arch_java_lib = '/usr/lib/java'
-
-            predefined_dict = {'pki_instance_name': default_instance_name,
-                               'pki_http_port': default_http_port,
-                               'pki_https_port': default_https_port,
-                               'pki_dns_domainname': config.pki_dns_domainname,
-                               'pki_subsystem' : config.pki_subsystem,
-                               'pki_subsystem_type': config.pki_subsystem.lower(),
-                               'pki_root_prefix' : config.pki_root_prefix,
-                               'resteasy_lib': resteasy_lib,
-                               'arch_java_lib': arch_java_lib,
-                               'home_dir': os.path.expanduser("~"),
-                               'pki_hostname': config.pki_hostname}
-
-            self.pki_config = ConfigParser.SafeConfigParser(predefined_dict)
-            # Make keys case-sensitive!
-            self.pki_config.optionxform = str
-            self.pki_config.read([
-                config.default_deployment_cfg,
-                config.user_deployment_cfg])
-            config.pki_default_dict = dict(self.pki_config.items('DEFAULT'))
-            pkilogging.sensitive_parameters = config.pki_default_dict['sensitive_parameters'].split()
-            if config.pki_subsystem == "CA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('CA'))
-            elif config.pki_subsystem == "KRA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('KRA'))
-            elif config.pki_subsystem == "OCSP":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('OCSP'))
-            elif config.pki_subsystem == "RA":
-                config.pki_web_server_dict = dict(self.pki_config.items('Apache'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('RA'))
-            elif config.pki_subsystem == "TKS":
-                config.pki_web_server_dict = dict(self.pki_config.items('Tomcat'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('TKS'))
-            elif config.pki_subsystem == "TPS":
-                config.pki_web_server_dict = dict(self.pki_config.items('Apache'))
-                config.pki_subsystem_dict = dict(self.pki_config.items('TPS'))
-            # Insert empty record into dictionaries for "pretty print" statements
-            #     NEVER print "sensitive" key value pairs!!!
-            config.pki_default_dict[0] = None
-            config.pki_web_server_dict[0] = None
-            config.pki_subsystem_dict[0] = None
         except ConfigParser.ParsingError, err:
             print err
             rv = err
         return rv
 
 
+    def flatten_master_dict(self):
+        config.pki_master_dict.update(__name__="PKI Master Dictionary")
+
+        default_dict = dict(self.pki_config.items('DEFAULT'))
+        default_dict[0] = None
+        config.pki_master_dict.update(default_dict)
+
+        if config.pki_subsystem in config.PKI_TOMCAT_SUBSYSTEMS:
+            web_server_dict = dict(self.pki_config.items('Tomcat'))
+        else:
+            web_server_dict = dict(self.pki_config.items('Apache'))
+        web_server_dict[0] = None
+        config.pki_master_dict.update(web_server_dict)
+
+        subsystem_dict = dict(self.pki_config.items(config.pki_subsystem))
+        subsystem_dict[0] = None
+        config.pki_master_dict.update(subsystem_dict)
+
+
     def compose_pki_master_dictionary(self):
         "Create a single master PKI dictionary from the sectional dictionaries"
         try:
-            config.pki_master_dict = dict()
             # 'pkispawn'/'pkirespawn'/'pkidestroy' name/value pairs
             config.pki_master_dict['pki_deployment_executable'] =\
                 config.pki_deployment_executable
@@ -280,12 +314,10 @@ class PKIConfigParser:
                 random.randint(pin_low, pin_high)
             config.pki_master_dict['pki_client_pin'] =\
                 random.randint(pin_low, pin_high)
-            # Configuration file name/value pairs
-            #     NEVER add "sensitive" key value pairs to the master dictionary!!!
-            config.pki_master_dict.update(config.pki_default_dict)
-            config.pki_master_dict.update(config.pki_web_server_dict)
-            config.pki_master_dict.update(config.pki_subsystem_dict)
-            config.pki_master_dict.update(__name__="PKI Master Dictionary")
+
+            self.flatten_master_dict()
+
+            pkilogging.sensitive_parameters = config.pki_master_dict['sensitive_parameters'].split()
 
             # PKI Target (slot substitution) name/value pairs
             config.pki_master_dict['pki_target_cs_cfg'] =\
-- 
1.7.12.1

