-Removed reconfigure line
-Removed trailing spaces in input.json
-Renamed postinstall-new to postinstall for easier diff


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/64f49e3f
Tree: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/64f49e3f
Diff: 
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/64f49e3f

Branch: refs/heads/master
Commit: 64f49e3f747d6d5d40926a5f4fcec9902fa70140
Parents: ed58286
Author: peryder <pery...@cisco.com>
Authored: Mon Jan 9 09:24:43 2017 -0500
Committer: Dan Kirkwood <dang...@gmail.com>
Committed: Fri Jan 27 09:52:53 2017 -0700

----------------------------------------------------------------------
 traffic_ops/build/traffic_ops.spec      |    1 -
 traffic_ops/install/bin/input.json      |  142 +--
 traffic_ops/install/bin/postinstall     | 1385 ++++++++++++++------------
 traffic_ops/install/bin/postinstall-new |  781 ---------------
 4 files changed, 747 insertions(+), 1562 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/64f49e3f/traffic_ops/build/traffic_ops.spec
----------------------------------------------------------------------
diff --git a/traffic_ops/build/traffic_ops.spec 
b/traffic_ops/build/traffic_ops.spec
index 4483aa2..35cc608 100644
--- a/traffic_ops/build/traffic_ops.spec
+++ b/traffic_ops/build/traffic_ops.spec
@@ -109,7 +109,6 @@ Built: %(date) by %{getenv: USER}
     # install
     if [ "$1" = "1" ]; then
       # see postinstall, the .reconfigure file triggers init().
-      #/bin/touch %{PACKAGEDIR}/.reconfigure
        echo -e "\nRun /opt/traffic_ops/install/bin/postinstall from the root 
home directory to complete the install.\n"
     fi
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/64f49e3f/traffic_ops/install/bin/input.json
----------------------------------------------------------------------
diff --git a/traffic_ops/install/bin/input.json 
b/traffic_ops/install/bin/input.json
index 76720f6..b1adce2 100644
--- a/traffic_ops/install/bin/input.json
+++ b/traffic_ops/install/bin/input.json
@@ -1,169 +1,71 @@
-{  
-  "/opt/traffic_ops/app/conf/production/database.conf":[  
-    {  
+{
+  "/opt/traffic_ops/app/conf/production/database.conf":[
+    {
       "Database type":"mysql",
       "config_var":"type"
     },
-    {  
+    {
       "Database name":"traffic_ops_db",
       "config_var":"dbname"
     },
-    {  
+    {
       "Database server hostname IP or FQDN":"localhost",
       "config_var":"hostname"
     },
-    {  
+    {
       "Database port number":"3306",
       "config_var":"port"
     },
-    {  
+    {
       "Traffic Ops database user":"traffic_ops",
       "config_var":"user"
     },
-    {  
+    {
       "Traffic Ops database password":"default",
       "config_var":"password",
       "hidden":"1"
     }
   ],
-  "/opt/traffic_ops/app/db/dbconf.yml":[  
-    {  
+  "/opt/traffic_ops/app/db/dbconf.yml":[
+    {
       "Database server root (admin) username":"root",
       "config_var":"dbAdminUser"
     },
-    {  
+    {
       "Database server admin password":"default",
       "config_var":"dbAdminPw",
       "hidden":"1"
     }
   ],
-  "/opt/traffic_ops/app/conf/cdn.conf":[  
-    {  
+  "/opt/traffic_ops/app/conf/cdn.conf":[
+    {
       "Generate a new secret?":"yes",
       "config_var":"genSecret"
     },
-    {  
+    {
       "Number of secrets to keep?":"10",
       "config_var":"keepSecrets"
     }
   ],
-  "/opt/traffic_ops/app/conf/ldap.conf":[  
-    {  
+  "/opt/traffic_ops/app/conf/ldap.conf":[
+    {
       "Do you want to set up LDAP?":"no",
       "config_var":"setupLdap"
     },
-    {  
+    {
       "LDAP server hostname":"",
       "config_var":"hostname"
     },
-    {  
+    {
       "LDAP Admin DN":"",
       "config_var":"admin_dn"
     },
-    {  
+    {
       "LDAP Admin Password":"",
       "config_var":"password",
       "hidden":"1"
     },
-    {  
+    {
       "LDAP Search Base":"",
-      "config_var":"search_base"
-    }
-  ],
-  "/opt/traffic_ops/install/data/json/users.json":[  
-    {  
-      "Administration username for Traffic Ops":"root",
-      "config_var":"tmAdminUser"
-    },
-    {  
-      "Password for the admin user":"default",
-      "config_var":"tmAdminPw",
-      "hidden":"1"
-    }
-  ],
-  "/opt/traffic_ops/install/data/profiles/":[  
-
-  ],
-  "/opt/traffic_ops/install/data/json/openssl_configuration.json":[  
-    {  
-      "Do you want to generate a certificate?":"yes",
-      "config_var":"genCert"
-    },
-    {  
-      "Country Name (2 letter code)":"XX",
-      "config_var":"country"
-    },
-    {  
-      "State or Province Name (full name)":"Default State",
-      "config_var":"state"
-    },
-    {  
-      "Locality Name (eg, city)":"Default City",
-      "config_var":"locality"
-    },
-    {  
-      "Organization Name (eg, company)":"Default Company Ltd",
-      "config_var":"company"
-    },
-    {  
-      "Organizational Unit Name (eg, section)":"",
-      "config_var":"org_unit"
-    },
-    {  
-      "Common Name (eg, your name or your server's hostname)":"example.com",
-      "config_var":"common_name"
-    },
-    {  
-      "RSA Passphrase":"password",
-      "config_var":"rsaPassword",
-      "hidden":"1"
-    }
-  ],
-  "/opt/traffic_ops/install/data/json/profiles.json":[  
-    {  
-      "Traffic Ops url":"https://localhost";,
-      "config_var":"tm.url"
-    },
-    {  
-      "Human-readable CDN Name.  (No whitespace, please)":"kabletown_cdn",
-      "config_var":"cdn_name"
-    },
-    {  
-      "Health Polling Interval (milliseconds)":"8000",
-      "config_var":"health_polling_int"
-    },
-    {  
-      "DNS sub-domain for which your CDN is 
authoritative":"cdn1.kabletown.net",
-      "config_var":"dns_subdomain"
-    },
-    {  
-      "TLD SOA admin":"traffic_ops",
-      "config_var":"soa_admin"
-    },
-    {  
-      "TrafficServer Drive Prefix":"/dev/sd",
-      "config_var":"driver_prefix"
-    },
-    {  
-      "TrafficServer RAM Drive Prefix":"/dev/ram",
-      "config_var":"ram_drive_prefix"
-    },
-    {  
-      "TrafficServer RAM Drive Letters (comma separated)":"0,1,2,3,4,5,6,7",
-      "config_var":"ram_drive_letters"
-    },
-    {  
-      "Health Threshold Load Average":"25",
-      "config_var":"health_thresh_load_avg"
-    },
-    {  
-      "Health Threshold Available Bandwidth in Kbps":">1750000",
-      "config_var":"health_thresh_kbps"
-    },
-    {  
-      "Traffic Server Health Connection Timeout (milliseconds)":"2000",
-      "config_var":"health_connect_timeout"
-    }
-  ]
-}
-
+      "input.json"      169      L,
+      4044      C
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/64f49e3f/traffic_ops/install/bin/postinstall
----------------------------------------------------------------------
diff --git a/traffic_ops/install/bin/postinstall 
b/traffic_ops/install/bin/postinstall
index 6a747da..1092338 100755
--- a/traffic_ops/install/bin/postinstall
+++ b/traffic_ops/install/bin/postinstall
@@ -1,7 +1,6 @@
 #!/usr/bin/perl
 
 #
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
@@ -15,702 +14,768 @@
 # limitations under the License.
 #
 
-use strict;
-use warnings;
-
 use lib qw(/opt/traffic_ops/install/lib /opt/traffic_ops/install/lib/perl5 
/opt/traffic_ops/app/local/lib/perl5 /opt/traffic_ops/app/lib);
 $ENV{PATH}     = "/opt/traffic_ops/install/bin:$ENV{PATH}";
 $ENV{PERL5LIB} = 
"/opt/traffic_ops/install/lib:/opt/traffic_ops/install/lib/perl5:/opt/traffic_ops/app/local/lib/perl5:/opt/traffic_ops/app/lib";
 
-use DBI;
-use JSON;
+use strict;
+use warnings;
+
+use Safe;
+use POSIX;
+use File::Basename qw{dirname};
+use File::Path qw{make_path};
 use InstallUtils qw{ :all };
+use BuildPerlDeps qw{ :all };
+use GenerateCert qw{ :all };
+use ProfileCleanup qw { :all };
 use Digest::SHA1 qw(sha1_hex);
-use Data::Dumper;
-use File::Temp;
-use WWW::Curl::Easy;
-use LWP::UserAgent;
-use File::Copy;
-
-my $database_conf     = "/opt/traffic_ops/app/conf/production/database.conf";
-my $ldap_conf         = "/opt/traffic_ops/app/conf/ldap.conf";
-my $cdn_conf          = "/opt/traffic_ops/app/conf/cdn.conf";
-my $migrations_dbconf = "/opt/traffic_ops/app/db/dbconf.yml";
-my $post_install_cfg  = "/opt/traffic_ops/install/data/json/post_install.json";
-my $users_file        = "/opt/traffic_ops/install/data/json/users.json";
-my $profile_dir       = "/opt/traffic_ops/install/data/profiles/";
-my %dbdriver          = ( mysql => "mymysql", );
-
-my $reconfigure = "/opt/traffic_ops/.reconfigure";
-my $reconfigure_defaults = "/opt/traffic_ops/.reconfigure_defaults";
-my $tmAdminUser = "";
-my $tmAdminPw = "";
-my $parameters;
-
-my $installMsg = << 'EOF';
-
-This script will initialize the Traffic Ops database.
-Please enter the following information in order to completely 
-configure the Traffic Ops mysql database.
-
-EOF
-
-sub readJson {
-       my $file = shift;
-       open( my $fh, '<', $file ) or return;
-       local $/;    # slurp mode
-       my $text = <$fh>;
-       undef $fh;
-       return JSON->new->utf8->decode($text);
+use Data::Dumper qw(Dumper);
+use Scalar::Util qw(looks_like_number);
+use Getopt::Long;
+
+# paths of the output configuration files
+our $databaseConfFile = "/opt/traffic_ops/app/conf/production/database.conf";
+our $dbConfFile       = "/opt/traffic_ops/app/db/dbconf.yml";
+our $cdnConfFile      = "/opt/traffic_ops/app/conf/cdn.conf";
+our $ldapConfFile     = "/opt/traffic_ops/app/conf/ldap.conf";
+our $usersConfFile    = "/opt/traffic_ops/install/data/json/users.json";
+our $profilesConfFile = "/opt/traffic_ops/install/data/profiles/";
+our $opensslConfFile  = 
"/opt/traffic_ops/install/data/json/openssl_configuration.json";
+our $paramConfFile    = "/opt/traffic_ops/install/data/json/profiles.json";
+
+our $profile_dir       = "/opt/traffic_ops/install/data/profiles/";
+our $post_install_cfg = "/opt/traffic_ops/install/data/json/post_install.json";
+
+our $reconfigure_defaults = "/opt/traffic_ops/.reconfigure_defaults";
+
+our $parameters;
+
+# old way of reconfiguring postinstall - only here to check for file and let 
user know it is deprecated
+my $reconfigure_file = "/opt/traffic_ops/.reconfigure";
+
+# whether or not to reconfigure traffic ops
+my $reconfigure;
+
+# whether to create a config file with default values
+my $dumpDefaults;
+
+# log file for the installer
+our $logFile = "/var/log/traffic_ops/postinstall.log";
+
+# maximum size the uncompressed log file should be before rotating it - 
rotating it copies the current log
+#  file to the same name appended with .bkp replacing the old backup if any is 
there
+my $maxLogSize = 1000000;    #bytes
+
+# log file for cpan - this log becomes large and is rotated every install
+our $cpanLogFile = "/var/log/traffic_ops/cpan.log";
+
+# configuration file output with answers which can be used as input to 
postinstall
+our $outputConfigFile = "/var/log/traffic_ops/configuration_file.json";
+
+sub getDbDriver {
+    return "mymysql";
 }
 
-sub writeJson {
-       my $file = shift;
-       open( my $fh, '>', $file ) or die("open(): $!");
-       foreach my $data (@_) {
-               my $json_text = JSON->new->utf8->encode($data);
-               print $fh $json_text, "\n";
-       }
-       close $fh;
+sub getInstallPath {
+    my $relPath = shift;
+    return join( '/', "/tmp/traffic_ops", $relPath );
 }
 
-sub writeYamlToFH {
-       my $fh     = shift;
-       my $data   = shift;
-       my $level  = shift || 0;
-       my $prefix = shift || '';
-
-       my $type   = ref($data);
-       my $indent = ' ' x $level;
-       if ( $type eq '' ) {
-
-               # scalar
-               print $fh "$indent$prefix$data\n";
-       }
-       elsif ( $type eq 'HASH' ) {
-               foreach my $key ( keys %$data ) {
-                       my $value = $data->{$key};
-                       if ( ref($value) eq '' ) {
-                               print $fh "$indent$key: $value\n";
-                       }
-                       else {
-                               print $fh "$indent$key:\n";
-                               writeYamlToFH( $fh, $data->{$key}, $level + 1 );
-                       }
-               }
-       }
-       elsif ( $type eq 'ARRAY' ) {
-               foreach my $d (@$data) {
-                       writeYamlToFH( $fh, $d, $level + 1, '- ' );
-               }
-       }
+# given a var to the hash of config_var and question, will return the question
+sub getConfigQuestion {
+    my $var = shift;
+    foreach my $key ( keys $var ) {
+        if ( $key ne "hidden" && $key ne "config_var" ) {
+            return $key;
+        }
+    }
 }
 
-sub writeYaml {
-       my $file = shift;
-       my $data = shift;
-       open my $fh, '>', $file or die "open(): $!";
-       writeYamlToFH( $fh, $data );
+# question: The question given in the config file
+# config_answer: The answer given in the config file - if no config file given 
will be defaultInput
+# hidden: Whether or not the answer should be hidden from the terminal and 
logs, ex. passwords
+#
+# Determines if the script is being run in complete interactive mode and 
prompts user - otherwise
+#  returns answer to question in config or defaults
+
+sub getField {
+    my $question      = shift;
+    my $config_answer = shift;
+    my $hidden        = shift;
+
+    # if there is no config file and not in automatic mode prompt for all 
questions with default answers
+    if ( !$::inputFile && !$::automatic ) {
+
+        # if hidden then dont show password in terminal
+        if ($hidden) {
+            return promptPasswordVerify($question);
+        }
+        else {
+            return promptUser( $question, $config_answer );
+        }
+    }
+
+    return $config_answer;
 }
 
-# Init.
-sub init () {
-       my $c      = readJson($database_conf);
-       my %dbconf = %$c;
-       my $dbAdminUser;
-       my $dbAdminPw;
-
-       # loop exits on successful db connect
-       while (1) {
-               execCommand( "/usr/bin/tput", "clear" );
-
-               if ($DBI::errstr) {
-                       print "Error connecting to database using the supplied 
information: $DBI::errstr\n";
-               }
-
-               print "\n$installMsg\n";
-
-               $dbconf{type}     = promptUser( "Database type",                
       $dbconf{type}     || "mysql" );
-               $dbconf{dbname}   = promptUser( "Database name",                
       $dbconf{dbname}   || "traffic_ops_db" );
-               $dbconf{hostname} = promptUser( "Database server hostname IP or 
FQDN", $dbconf{hostname} || "localhost" );
-               $dbconf{port}     = promptUser( "Database port number",         
       $dbconf{port}     || "3306" );
-               $dbconf{user}     = promptUser( "Traffic Ops database user",    
       $dbconf{user}     || "traffic_ops" );
-               $dbconf{password} = promptPasswordVerify("Password for 
$dbconf{user}");
-               $dbconf{description} = "$dbconf{type} database on 
$dbconf{hostname}:$dbconf{port}";
-               print "\n";
-               $dbAdminUser = promptUser( "Database server root (admin) user 
name", "root" );
-               $dbAdminPw = promptPassword("Database server $dbAdminUser 
password");
-
-               print "Database Type: $dbconf{type}\n";
-               print "Database Name: $dbconf{dbname}\n";
-               print "Hostname: $dbconf{hostname}\n";
-               print "Port: $dbconf{port}\n";
-               print "Database User: $dbconf{user}\n";
-               my $ans = promptUser( "Is the above information correct (y/n)", 
"n" );
-
-               if ( $ans eq "y" ) {
-                       my $dsn = sprintf( "DBI:mysql:%s:%s:%s", "mysql", 
$dbconf{hostname}, $dbconf{port} );
-                       my $dbh = DBI->connect( $dsn, $dbAdminUser, $dbAdminPw 
);
-                       if ($dbh) {
-
-                               # Success!
-                               $dbh->disconnect();
-                               last;
-                       }
-               }
-       }
-
-       writeJson( $database_conf, \%dbconf );
-       print "\nThe database properties have been saved to $database_conf\n";
-
-       # migrations dbconf is in YAML
-       my $driver = $dbdriver{ $dbconf{type} };
-       my %migrations = ( production => { driver => $driver, open => 
"tcp:$dbconf{hostname}:$dbconf{port}*$dbconf{dbname}/$dbconf{user}/$dbconf{password}"
 } );
-       writeYaml( $migrations_dbconf, \%migrations );
-
-       my $msg = << 'EOF';
-
-  The database configuration has been saved.  Now we need to set some custom
-  fields that are necessary for the CDN to function correctly.
-
-EOF
-
-       print $msg, "\n";
-       while (1) {
-
-               my $tmurl = promptUser( "Traffic Ops url", 
$parameters->{"tm.url"} || "https://localhost"; );
-               $parameters->{"tm.url"}     = $tmurl;
-               $parameters->{"tm.infourl"} = "$tmurl/info";
-
-               $parameters->{cdnname}    = promptUser( "Human-readable CDN 
Name.  (No whitespace, please)",  $parameters->{cdnname}    || "kabletown_cdn" 
);
-               $parameters->{domainname} = promptUser( "DNS sub-domain for 
which your CDN is authoritative", $parameters->{domainname} || 
"cdn1.kabletown.net" );
-
-               my $geolocationUrl = "$tmurl/routing/GeoIP2-City.mmdb.gz";
-               $parameters->{"geolocation.polling.url"} = $geolocationUrl;
-
-               my $coverageZoneUrl = "$tmurl/routing/coverage-zone.json";
-               $parameters->{"coveragezone.polling.url"} = $coverageZoneUrl;
-
-               my $centosTarballFqn = '';
-               my $skip;
-               while (1) {
-                       $centosTarballFqn = promptUser( "Fully qualified name 
of your CentOS ISO kickstart tarball, or 'na' to skip and add files later",
-                               "/var/cache/centos72.tgz" );
-                       if ( $centosTarballFqn eq 'na' ) {
-                               $skip = 1;
-                               last;
-                       }
-                       if ( -f $centosTarballFqn ) {
-                               last;
-                       }
-                       print "\nNo file named $centosTarballFqn found.\n\n";
-               }
-
-               my $kickstartFilesFqn = promptUser( "Fully qualified location 
to store your ISO kickstart files", "/var/www/files" );
-               my $parametersJson = 
"/opt/traffic_ops/install/data/json/parameter.json";
-
-               ## Replace parameter with $kickstartFilesFqn
-               open( my $json_fh, "<:encoding(UTF-8)", $parametersJson )
-                       or die("Can't open \$filename\": $!\n");
-
-               my $json = JSON->new;
-               my @json_obj;
-               while ( my $json_text = <$json_fh> ) {
-                       my $data = $json->decode($json_text);
-
-                       if ( $data->{"name"} eq "kickstart.files.location" ) {
-                               $data->{"value"} = $kickstartFilesFqn;
-                       }
-                       push @json_obj, $data;
-               }
-               writeJson( $parametersJson, @json_obj );
-
-               execCommand( "/bin/cp", 
"/opt/traffic_ops/install/data/perl/osversions.cfg", $kickstartFilesFqn );
-
-               if ( !$skip ) {
-                       print "\nUncompressing CentOS ISO kickstart tarball.\n";
-                       print "\nFirst creating $kickstartFilesFqn.\n";
-                       execCommand( "/bin/mkdir", "-p", $kickstartFilesFqn );
-                       print "\nUncompressing $centosTarballFqn.\n";
-                       execCommand( "/bin/tar", "-xzf", $centosTarballFqn, 
"-C", $kickstartFilesFqn );
-               }
-
-               print "\nTraffic Ops URL: $parameters->{'tm.url'}\n";
-               print "Traffic Ops Info URL: $parameters->{'tm.infourl'}\n";
-               print "Domainname: $parameters->{domainname}\n";
-               print "CDN Name: $parameters->{cdnname}\n";
-               print "GeoLocation Polling URL: 
$parameters->{'geolocation.polling.url'}\n";
-               print "CoverageZone Polling URL: 
$parameters->{'coveragezone.polling.url'}\n\n";
-               my $ans = promptUser( "Is the above information correct (y/n)", 
"n" );
-               if ( $ans eq 'y' ) {
-                       last;
-               }
-       }
-       writeJson( $post_install_cfg, $parameters );
-       print "Install information has been saved to $post_install_cfg\n\n";
-
-       print "\nAdding an administration user to the Traffic Ops 
database.\n\n";
-       my %user = ();
-       $tmAdminUser = promptUser( "Administration username for Traffic Ops", 
'admin' );
-       $user{username} = $tmAdminUser;
-       $tmAdminPw = promptPasswordVerify("Password for the admin user 
$tmAdminUser");
-       $user{password} = sha1_hex($tmAdminPw);
-
-       writeJson( $users_file, \%user );
-
-       my $ans = promptUser( "Do you wish to create an ldap configuration for 
access to traffic ops [y/n] ?", "n" );
-       if ( $ans eq "y" ) {
-               my %ldapconf = readJson($ldap_conf);
-               while (1) {
-                       $ldapconf{host}     = promptUser( "LDAP server 
hostname", $ldapconf{host}     || "ldap.foobar.com" );
-                       $ldapconf{admin_dn} = promptUser( "LDAP Admin DN",      
  $ldapconf{admin_dn} || 'ad...@foobar.com' );
-                       $ldapconf{admin_pass} = promptPasswordVerify("LDAP 
Admin Password");
-                       $ldapconf{search_base} = promptUser( "LDAP Search 
Base", "dc=foobar,dc=com" );
-                       my $correct = promptUser( "Are the above values correct 
[y/n]?", "y" );
-                       if ( $correct eq 'y' ) {
-                               last;
-                       }
-               }
-               writeJson( $ldap_conf, \%ldapconf );
-               print "The ldap configuration has been saved.\n\n";
-       }
-
-       # Prompt for new secret
-       writeSecret($cdn_conf);
-
-       #
-       # Call mysql initialization script.
-       #
-       print "Creating database\n";
-       my $result = execCommand( "/opt/traffic_ops/install/bin/create_db", 
$dbAdminUser, $dbAdminPw );
-       if ( $result != 0 ) {
-               print "failed to create the database.\n";
-               exit 1;
-       }
-
-       print "Setting up database\n";
-       chdir("/opt/traffic_ops/app");
-       $result = execCommand( "/usr/bin/perl", "db/admin.pl", 
"--env=production", "setup" );
-
-       if ( $result != 0 ) {
-               print "Database initialization failed.\n";
-               exit 2;
-       }
-       else {
-               print "Database initialization succeeded.\n";
-       }
-
-       $result = execCommand( "/opt/traffic_ops/install/bin/dataload", 
$dbAdminUser, $dbAdminPw );
-       if ( $result != 0 ) {
-               print "failed to load seed data.\n";
-               exit 1;
-       }
-
-       print "Downloading MaxMind data.\n";
-       chdir("/opt/traffic_ops/app/public/routing");
-       $result = execCommand("/usr/bin/wget 
http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz";);
-       if ( $result != 0 ) {
-               print "failed to download MaxMind data.\n";
-
-               # exit 1;
-       }
-
-       print "Copying coverage zone file to public dir.\n";
-       $result = execCommand("/bin/mv 
/opt/traffic_ops/app/public/coverage-zone.json .");
-       if ( $result != 0 ) {
-               print "failed to copy coverage zone file.\n";
-
-               # exit 1;
-       }
-
-       if ( -x "/usr/bin/openssl" ) {
-               print "\nInstalling SSL Certificates.\n\n";
-               $result = 
execCommand("/opt/traffic_ops/install/bin/generateCert");
-
-               if ( $result != 0 ) {
-                       print "\nSSL Certificate Installation failed.\n";
-                       exit 3;
-               }
-               else {
-                       print "\nSSL Certificates have been installed.\n";
-               }
-       }
-       else {
-               print "Unable to install SSL certificates as openssl is not 
installed.\n";
-               print "Install openssl and then run 
/opt/traffic_ops/install/bin/generateCert to install SSL certificates.\n";
-               exit 4;
-       }
-}    # end of Init
-
-sub writeSecret {
-       print "\n\nTraffic Ops requires a secret key to generate authentication 
cookies.\n\n";
-
-       # read conf file -- see if secrets already there
-       my $cdnh = do $cdn_conf;
-       unless ( ref($cdnh) eq 'HASH' ) {
-               my $err = $@ || $! || ' -- not a HASH';
-               if ($err) {
-                       print "Could not load $cdn_conf $err";
-                       exit 4;
-               }
-       }
-
-       # newSecret
-       my $secrets = $cdnh->{secrets};
-       if ( ( ref $secrets eq 'ARRAY' ) && scalar @$secrets > 0 ) {
-               print "One or more secrets found in $cdn_conf.\n";
-               my $ans = promptUser( " Do want to add a new one (only 2 will 
be kept) [y/n] ?", "y" );
-               if ( $ans eq "n" ) {
-
-                       # nothing further to do...
-                       return;
-               }
-       }
-       my $new_secret = "";
-       while ( length $new_secret == 0 ) {
-               print "Adding a new secret.\n";
-               my $ans = promptUser( " Do you want one generated for you [y/n] 
?", "y" );
-               if ( $ans eq "n" ) {
-                       $new_secret = promptUser( "Secret key:", "" );
-               }
-               else {
-
-                       # create random word 12 chars long
-                       $new_secret = randomWord(12);
-               }
-       }
-
-       # keep 2 at most..
-       unshift( @$secrets, $new_secret );
-       if ( scalar @$secrets > 2 ) {
-               $#{$secrets} = 1;
-       }
-
-       # dump conf data in compact but readable form
-       my $dumper = Data::Dumper->new( [$cdnh] );
-       $dumper->Indent(1)->Terse(1)->Quotekeys(0);
-
-       # write whole config to temp file in pwd (keeps in same filesystem)
-       my $tmpfile = File::Temp->new(DIR => '.');
-       print $tmpfile $dumper->Dump();
-       close $tmpfile;
-
-       # rename current config file to something unique so it's not lost
-       my $backup_num = 0;
-       my $backup_name;
-       do {
-               $backup_num++;
-               $backup_name = "$cdn_conf.backup$backup_num";
-       } while ( -e $backup_name );
-       rename( $cdn_conf, $backup_name ) or die("rename(): $!");
-
-       # rename temp file to cdn.conf and set ownership/permissions same as 
backup
-       my @stats = stat($backup_name);
-       my ( $uid, $gid, $perm ) = @stats[ 4, 5, 2 ];
-       rename( $tmpfile, $cdn_conf ) or die("rename(): $!");
-
-       chown $uid, $gid, $cdn_conf;
-       chmod $perm, $cdn_conf;
+# userInput: The entire input config file which is either user input or the 
defaults
+# fileName: The name of the output config file given by the input config file
+#
+# Loops through an input config file and determines answers to each question 
using getField
+#  and returns the hash of answers
+
+sub getConfig {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my %config;
+
+    if ( !defined $userInput->{$fileName} ) {
+        logger( "No $fileName found in config", "error" );
+    }
+
+    logger( "===========$fileName===========", "info" );
+
+    foreach my $var ( @{ $userInput->{$fileName} } ) {
+        my $question = getConfigQuestion($var);
+        my $hidden   = $var->{"hidden"} if ( exists $var->{"hidden"} );
+        my $answer   = $config{ $var->{"config_var"} } = getField( $question, 
$var->{$question}, $hidden );
+
+        $config{ $var->{"config_var"} } = $answer;
+        if ( !$hidden ) {
+            logger( "$question:  $answer", "info" );
+        }
+    }
+    return %config;
 }
 
-chdir("/opt/traffic_ops/install/bin");
-
-$parameters = readJson($post_install_cfg);
-if ( -f $reconfigure ) {
-       my $rc = execCommand( 
"/opt/traffic_ops/install/bin/build_trafficops_perl_library", "-i" );
-       if ( $rc != 0 ) {
-               print "ERROR: failed to install perl dependencies, check the 
console output and rerun postinstall once you've resolved the error.\n";
-               exit 5;
-       }
-       $rc = execCommand( "./download_web_deps", "-i" );
-       if ( $rc != 0 ) {
-               print "ERROR: failed to install Traffic Ops Web dependencies, 
check the console output and rerun postinstall once you've resolved the 
error.\n";
-       }
-       init();
-       unlink($reconfigure);
+# userInput: The entire input config file which is either user input or the 
defaults
+# dbFileName: The filename of the output config file for the database
+# toDBFileName: The filename of the output config file for the Traffic Ops 
database
+#
+# Generates a config file for the database based on the questions and answers 
in the input config file
+
+sub generateDbConf {
+    my $userInput    = shift;
+    my $dbFileName   = shift;
+    my $toDBFileName = shift;
+
+    my %dbconf = getConfig( $userInput, $dbFileName );
+    $dbconf{"description"} = "$dbconf{type} database on 
$dbconf{hostname}:$dbconf{port}";
+    make_path( dirname($dbFileName), { mode => 0755 } );
+    writeJson( $dbFileName, \%dbconf );
+    logger( "Database configuration has been saved", "info" );
+
+    # broken out into separate file/config area
+    my %todbconf = getConfig( $userInput, $toDBFileName );
+
+    # No YAML library installed, but this is a simple file..
+    open( my $fh, '>', $toDBFileName ) or errorOut("Can't write to 
$toDBFileName!");
+    print $fh "production:\n";
+    print $fh "    driver: ", getDbDriver() . "\n";
+    print $fh "    open: 
tcp:$dbconf{hostname}:$dbconf{port}*$dbconf{dbname}/$dbconf{user}/$dbconf{password}\n";
+    close $fh;
+
+    return \%todbconf;
 }
-else {
-       my $rc = 
execCommand("/opt/traffic_ops/install/bin/build_trafficops_perl_library");
-       if ( $rc != 0 ) {
-               print "ERROR: failed to install perl dependencies, check the 
console output and rerun postinstall once you've resolved the error.\n";
-               exit 6;
-       }
-       $rc = execCommand( "./download_web_deps", "-i" );
-       if ( $rc != 0 ) {
-               print "ERROR: failed to install Traffic Ops Web dependencies, 
check the console output and rerun postinstall once you've resolved the 
error.\n";
-       }
+
+# userInput: The entire input config file which is either user input or the 
defaults
+# fileName: The filename of the output config file
+#
+# Generates a config file for the CDN
+
+sub generateCdnConf {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my %cdnConfiguration = getConfig( $userInput, $fileName );
+
+    # First,  read existing one -- already loaded with a bunch of stuff
+    my $cdnConf;
+    if ( -f $fileName ) {
+        $cdnConf = Safe->new->rdo($fileName) or errorOut("Error loading 
$fileName: $@");
+    }
+    if ( lc $cdnConfiguration{genSecret} =~ /^y(?:es)?/ ) {
+        my @secrets   = @{ $cdnConf->{secrets} };
+        my $newSecret = randomWord();
+        unshift @secrets, randomWord();
+        if ( $cdnConfiguration{keepSecrets} > 0 && $#secrets > 
$cdnConfiguration{keepSecrets} - 1 ) {
+
+            # Shorten the array to requested length
+            $#secrets = $cdnConfiguration{keepSecrets} - 1;
+        }
+    }
+    writePerl( $fileName, $cdnConf );
 }
 
-sub profile_replace {
-               my($profile) = @_;
-               my $profile_bak = $profile . ".bak";
-               rename($profile, $profile_bak) or die("rename(): $!");
-               open(my $fh, '<', $profile_bak) or die("open(): $!");
-               open(my $ofh, '>', $profile) or die("open(): $!");
-               while (<$fh>) {
-                               s/{{.TmUrl}}/$parameters->{'tm.url'}/g;
-                               s/{{.TmInfoUrl}}/$parameters->{"tminfo.url"}/g;
-                               
s/{{.TmInstanceName}}/$parameters->{"cdnname"}/g;
-                               
s/{{.GeolocationPollingUrl}}/$parameters->{"geolocation.polling.url"}/g;
-                               
s/{{.Geolocation6PollingUrl}}/$parameters->{"geolocation6.polling.url"}/g;
-                               s/{{.TmUrl}}/$parameters->{'tm.url'}/g;
-                               s/{{.TmToolName}}/Traffic Ops/g;
-                               
s/{{.HealthPollingInterval}}/$parameters->{"health.polling.interval"}/g;
-                               
s/{{.CoveragezonePollingUrl}}/$parameters->{"coveragezone.polling.url"}/g;
-                               s/{{.DomainName}}/$parameters->{"domainname"}/g;
-                               
s/{{.TldSoaAdmin}}/$parameters->{"tld.soa.admin"}/g;
-                               
s/{{.DrivePrefix}}/$parameters->{"Drive_Prefix"}/g;
-                               
s/{{.HealthThresholdLoadavg}}/$parameters->{"health.threshold.loadavg"}/g;
-                               
s/{{.HealthThresholdAvailableBandwidthInKbps}}/$parameters->{"health.threshold.availableBandwidthInKbps"}/g;
-                               
s/{{.RAMDrivePrefix}}/$parameters->{"RAM_Drive_Prefix"}/g;
-                               
s/{{.RAMDriveLetters}}/$parameters->{"RAM_Drive_Letters"}/g;
-                               
s/{{.HealthConnectionTimeout}}/$parameters->{"health.connection.timeout"}/g;
-                               s#{{.CronOrtSyncds}}#*/15 * * * * root 
/opt/ort/traffic_ops_ort.pl syncds warn $parameters->{'tm.url'} 
$tmAdminUser:$tmAdminPw > /tmp/ort/syncds.log 2>&1#g;
-                               print $ofh $_;
-               }
-               close $fh;
-               close $ofh;
-               unlink $profile_bak;
+# userInput: The entire input config file which is either user input or the 
defaults
+# fileName: The filename of the output config file
+#
+# Generates an LDAP config file
+
+sub generateLdapConf {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my $useLdap = $userInput->{$fileName}[0]->{"Do you want to set up LDAP?"};
+
+    if ( !lc $useLdap =~ /^y(?:es)?/ ) {
+        logger( "Not setting up ldap", "info" );
+        return;
+    }
+
+    my %ldapConf = getConfig( $userInput, $fileName );
+
+    make_path( dirname($fileName), { mode => 0755 } );
+    writeJson( $fileName, \%ldapConf );
 }
 
-sub replace_profile_templates() {
-         while (!defined $parameters->{'tm.url'} ||  $parameters->{'tm.url'} 
eq "") {
-                               $parameters->{'tm.url'} = 
InstallUtils::promptUser ("Traffic Ops url", "https://localhost";);
-         }
-         while (!defined $parameters->{"tminfo.url"} || 
$parameters->{"tminfo.url"} eq "") {
-                               $parameters->{"tminfo.url"} = 
"$parameters->{'tm.url'}/info"
-         }
-         while (!defined $parameters->{"cdnname"} || $parameters->{"cdnname"} 
eq "") {
-                               $parameters->{"cdnname"} = 
InstallUtils::promptUser ("Human-readable CDN Name.  (No whitespace, please)", 
"kabletown_cdn");
-         }
-         while (!defined $parameters->{"geolocation.polling.url"} || 
$parameters->{"geolocation.polling.url"} eq "") {
-                               $parameters->{"geolocation.polling.url"} = 
"$parameters->{'tm.url'}/routing/GeoIP2-City.mmdb.gz";
-         }
-         while (!defined $parameters->{"geolocation6.polling.url"} || 
$parameters->{"geolocation6.polling.url"} eq "") {
-                               $parameters->{"geolocation6.polling.url"} = 
"$parameters->{'tm.url'}/routing/GeoIP2-Cityv6.mmdb.gz";
-         }
-         while (!defined $parameters->{"health.polling.interval"} || 
$parameters->{"health.polling.interval"} eq "") {
-                               $parameters->{"health.polling.interval"} = 
InstallUtils::promptUser ("Health Polling Interval (milliseconds)", "8000");
-         }
-         while (!defined $parameters->{"coveragezone.polling.url"} || 
$parameters->{"coveragezone.polling.url"} eq "") {
-                               $parameters->{"coveragezone.polling.url"} = 
"$parameters->{'tm.url'}/routing/coverage-zone.json"
-         }
-         while (!defined $parameters->{"domainname"} || 
$parameters->{"domainname"} eq "") {
-                               $parameters->{"domainname"} = 
InstallUtils::promptUser ("DNS sub-domain for which your CDN is authoritative", 
"cdn1.kabletown.net");
-         }
-         while (!defined $parameters->{"tld.soa.admin"} || 
$parameters->{"tld.soa.admin"} eq "") {
-                               $parameters->{"tld.soa.admin"} = 
InstallUtils::promptUser ("TLD SOA admin", "traffic_ops");
-         }
-         while (!defined $parameters->{"Drive_Prefix"} || 
$parameters->{"Drive_Prefix"} eq "") {
-                               $parameters->{"Drive_Prefix"} = 
InstallUtils::promptUser ("TrafficServer Drive Prefix", "/dev/sd");
-         }
-         while (!defined $parameters->{"RAM_Drive_Prefix"} || 
$parameters->{"RAM_Drive_Prefix"} eq "") {
-                               $parameters->{"RAM_Drive_Prefix"} = 
InstallUtils::promptUser ("TrafficServer RAM Drive Prefix", "/dev/ram");
-         }
-         while (!defined $parameters->{"RAM_Drive_Letters"} || 
$parameters->{"RAM_Drive_Letters"} eq "") {
-                               $parameters->{"RAM_Drive_Letters"} = 
InstallUtils::promptUser ("TrafficServer RAM Drive Letters (comma separated)", 
"0,1,2,3,4,5,6,7");
-         }
-         while (!defined $parameters->{"health.threshold.loadavg"} || 
$parameters->{"health.threshold.loadavg"} eq "") {
-                               $parameters->{"health.threshold.loadavg"} = 
InstallUtils::promptUser ("Health Threshold Load Average", "25");
-         }
-         while (!defined 
$parameters->{"health.threshold.availableBandwidthInKbps"} || 
$parameters->{"health.threshold.availableBandwidthInKbps"} eq "" || 
$parameters->{"health.threshold.availableBandwidthInKbps"} eq ">") {
-                               
$parameters->{"health.threshold.availableBandwidthInKbps"} = ">" . 
InstallUtils::promptUser ("Health Threshold Available Bandwidth in Kbps", 
"1750000");
-         }
-         while (!defined $parameters->{"health.connection.timeout"} || 
$parameters->{"health.connection.timeout"} eq "") {
-                               $parameters->{"health.connection.timeout"} = 
InstallUtils::promptUser ("Traffic Server Health Connection Timeout 
(milliseconds)", "2000");
-         }
-
-         profile_replace($profile_dir . "profile.global.traffic_ops");
-         profile_replace($profile_dir . "profile.traffic_monitor.traffic_ops");
-         profile_replace($profile_dir . "profile.traffic_router.traffic_ops");
-         profile_replace($profile_dir . 
"profile.trafficserver_edge.traffic_ops");
-         profile_replace($profile_dir . 
"profile.trafficserver_mid.traffic_ops");
-         writeJson( $post_install_cfg, $parameters );
+sub generateUsersConf {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my %user = ();
+    my %config = getConfig( $userInput, $fileName );
+
+    $user{username} = $config{tmAdminUser};
+    $user{password} = sha1_hex( $config{tmAdminPw} );
+
+    writeJson( $fileName, \%user );
+    $user{password} = $config{tmAdminPw};
+    return \%user;
 }
 
-# Takes the Traffic Ops URI, user, and password.
-# Returns the cookie, or the empty string on error
-sub get_traffic_ops_cookie {
-               my($uri, $user, $pass) = @_;
-
-               my $loginUri = "/api/1.2/user/login";
-
-               my $curl = WWW::Curl::Easy->new;
-               my $response_body = "";
-               open(my $fileb, ">", \$response_body);
-               my $loginData = JSON::encode_json({ u => $user, p => $pass});
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_URL, $uri . $loginUri);
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_SSL_VERIFYPEER, 0);
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_HEADER, 1); # include 
header in response
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_NOBODY, 1); # disclude 
body in response
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_POST, 1);
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_POSTFIELDS, $loginData);
-               $curl->setopt(WWW::Curl::Easy::CURLOPT_WRITEDATA, $fileb);      
# put response in this var
-               $curl->perform();
-
-               my $cookie = $response_body;
-               if($cookie =~ /mojolicious=(.*); expires/)
-               {
-                               $cookie = $1;
-               }
-               else
-               {
-                               $cookie = ""
-               }
-               return $cookie;
+sub generateProfilesDir {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my $userIn = $userInput->{$fileName};
 }
 
-# Takes the filename of a Traffic Ops (TO) profile to import, the TO URI, and 
the TO login cookie
-sub profile_import_single {
-    my($profileFilename, $uri, $trafficOpsCookie) = @_;
-    print "Importing Profiles with: " . "curl -v -k -X POST -H \"Cookie: 
mojolicious=$trafficOpsCookie\" -F \"filename=$profileFilename\" -F 
\"profile_to_import=\@$profileFilename\" $uri/profile/doI\
-mport";
-    my $rc = execCommand("curl -v -k -X POST -H \"Cookie: 
mojolicious=$trafficOpsCookie\" -F \"filename=$profileFilename\" -F 
\"profile_to_import=\@$profileFilename\" $uri/profile/doImport");
-    if ( $rc != 0 ) {
-        print "ERROR: failed to import Traffic Ops profile, check the console 
output and rerun postinstall once you've resolved the error.\n";
+sub generateOpenSSLConf {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    if ( !defined $userInput->{$fileName} ) {
+        logger( "No OpenSSL Configuration - questions will be asked", "info" );
+
+        # write an empty config so openssl does not use an old file
+        writeJson( $fileName, my %emptyConfig );
+        return;
     }
+
+    my %config = getConfig( $userInput, $fileName );
+
+    writeJson( $fileName, \%config );
+    return \%config;
 }
 
-sub import_profiles() {
-               while (length $tmAdminUser == 0) {
-                               $tmAdminUser = InstallUtils::promptUser 
("Administration username for Traffic Ops");
-               }
-               while ($tmAdminPw eq "") {
-                               $tmAdminPw = InstallUtils::promptUser 
("Password for the admin user $tmAdminUser", "", 1);
-               }
-    while (!defined $parameters->{'tm.url'} || length $parameters->{'tm.url'} 
== 0) {
-                               $parameters->{'tm.url'} = 
InstallUtils::promptUser ("Traffic Ops url", "https://localhost";);
-         }
-
-               print "Importing profiles...\n";
-               # \todo take as params
-               my $toUri = $parameters->{'tm.url'};
-               my $toUser = $tmAdminUser;
-               my $toPass = $tmAdminPw;
-
-               my $toCookie = get_traffic_ops_cookie($toUri, $toUser, $toPass);
-
-               print "Got cookie: " . $toCookie;
-
-               # \todo use an array?
-               print "Importing Global profile...\n";
-               profile_import_single($profile_dir . 
"profile.global.traffic_ops", $toUri, $toCookie);
-               print "Importing Traffic Monitor profile...\n";
-               profile_import_single($profile_dir . 
"profile.traffic_monitor.traffic_ops", $toUri, $toCookie);
-               print "Importing Traffic Router profile...\n";
-               profile_import_single($profile_dir . 
"profile.traffic_router.traffic_ops", $toUri, $toCookie);
-               print "Importing TrafficServer Edge profile...\n";
-               profile_import_single($profile_dir . 
"profile.trafficserver_edge.traffic_ops", $toUri, $toCookie);
-               print "Importing TrafficServer Mid profile...\n";
-               profile_import_single($profile_dir . 
"profile.trafficserver_mid.traffic_ops", $toUri, $toCookie);
-               print "Finished Importing Profiles.\n";
+sub generateParamConf {
+    my $userInput = shift;
+    my $fileName  = shift;
+
+    my %config = getConfig( $userInput, $fileName );
+    writeJson( $fileName, \%config );
+    return \%config;
 }
 
-print "\nStarting Traffic Ops.\n\n";
-execCommand("/sbin/service traffic_ops start");
-
-print "\nWaiting for Traffic Ops to start.\n\n";
-sleep(5);
-
-sub profiles_exist {
-               if ( -f $reconfigure_defaults ) {
-                               print "Default profiles were previously 
created. Remove " . $reconfigure_defaults . " to create again.\n";
-                               return 1;
-               }
-
-               while ( length $tmAdminUser == 0 ) {
-                               $tmAdminUser =
-                                               
InstallUtils::promptUser("Administration username for Traffic Ops");
-               }
-               while ( $tmAdminPw eq "" ) {
-                               $tmAdminPw =
-                                               InstallUtils::promptUser( 
"Password for the admin user $tmAdminUser",
-                                                                               
                                                                        "", 1 );
-               }
-               while ( !defined $parameters->{'tm.url'}
-                                               || length 
$parameters->{'tm.url'} == 0 )
-               {
-                               $parameters->{'tm.url'} =
-                                               InstallUtils::promptUser( 
"Traffic Ops url", "https://localhost"; );
-               }
-
-               my $uri      = $parameters->{'tm.url'};
-               my $toCookie = get_traffic_ops_cookie( $parameters->{'tm.url'},
-                                                                               
                                                                                
         $tmAdminUser, $tmAdminPw );
-
-               my $profileEndpoint = "/api/1.2/profiles.json";
-
-               my $ua = LWP::UserAgent->new;
-               $ua->ssl_opts( verify_hostname => 0, SSL_verify_mode => 0x00 );
-               my $req = HTTP::Request->new( GET => $uri . $profileEndpoint );
-               $req->header( 'Cookie' => "mojolicious=" . $toCookie );
-               my $resp = $ua->request($req);
-
-               if ( !$resp->is_success ) {
-                               print "Error checking if profiles exist: " . 
$resp->status_line . "\n";
-                               return 1;    # return true, so we don't attempt 
to create profiles
-               }
-               my $message = $resp->decoded_content;
-
-               my $profiles = JSON->new->utf8->decode($message);
-               if (   ( !defined $profiles->{"response"} )
-                                        || ( ref $profiles->{"response"} ne 
'ARRAY' ) )
-               {
-                               print "Error checking if profiles exist: 
invalid JSON: $message\n";
-                               return 1;    # return true, so we don't attempt 
to create profiles
-               }
-
-               my $num_profiles = scalar( @{ $profiles->{"response"} } );
-               print "Existing Profile Count: $num_profiles\n";
-
-               my %initial_profiles = (
-                               "INFLUXDB"       => 1,
-                               "RIAK_ALL"       => 1,
-                               "TRAFFIC_STATS"  => 1,
-                               "TRAFFIC_PORTAL" => 1
-                               );
-
-               my $profiles_response = $profiles->{"response"};
-               foreach my $profile (@$profiles_response) {
-                               if ( !exists $initial_profiles{ 
$profile->{"name"} } ) {
-                                               print "Found existing profile 
(" . $profile->{"name"} . ")\n";
-                                               open( my 
$reconfigure_defaults_file, '>', $reconfigure_defaults ) or die("Failed to 
open() $reconfigure_defaults: $!");
-                                               close( 
$reconfigure_defaults_file );
-                                               return 1;
-                               }
-               }
-               return 0;
+# check default values for missing config_var parameter
+sub sanityCheckDefaults {
+    foreach my $file ( ( keys $::defaultInputs ) ) {
+        foreach my $defaultValue ( @{ $::defaultInputs->{$file} } ) {
+            my $question = getConfigQuestion($defaultValue);
+
+            if ( !defined $defaultValue->{"config_var"}
+                || $defaultValue->{"config_var"} eq "" )
+            {
+                errorOut("Question '$question' in file '$file' has no 
config_var");
+            }
+        }
+    }
 }
 
-if ( !profiles_exist() ) {
-               print "Creating default profiles...\n";
-               replace_profile_templates();
-               import_profiles();
-               profiles_exist(); # call again to create $reconfigure_defaults 
file if import was successful
+# userInput: The entire input config file which is either user input or the 
defaults
+#
+# Checks the input config file against the default inputs. If there is a 
question located in the default inputs which
+#  is not located in the input config file it will output a warning message.
+
+sub sanityCheckConfig {
+    my $userInput = shift;
+    my $diffs     = 0;
+
+    foreach my $file ( ( keys $::defaultInputs ) ) {
+        if ( !defined $userInput->{$file} ) {
+            logger( "File '$file' found in defaults but not config file", 
"warn" );
+            $userInput->{$file} = [];
+        }
+
+        foreach my $defaultValue ( @{ $::defaultInputs->{$file} } ) {
+
+            my $found = 0;
+            foreach my $configValue ( @{ $userInput->{$file} } ) {
+                if ( $defaultValue->{"config_var"} eq 
$configValue->{"config_var"} ) {
+                    $found = 1;
+                }
+            }
+
+            # if the question is not found in the config file add it from 
defaults
+            if ( !$found ) {
+                my $question = getConfigQuestion($defaultValue);
+                logger( "Question '$question' found in defaults but not in 
'$file'", "warn" );
+
+                my %temp;
+                my $answer;
+                my $hidden = exists $defaultValue->{"hidden"} && 
$defaultValue->{"hidden"} ? 1 : 0;
+
+                # in automatic mode add the missing question with default 
answer
+                if ($::automatic) {
+                    $answer = $defaultValue->{$question};
+                    logger( "Adding question '$question' with default answer " 
. ( $hidden ? "" : "'$answer'" ), "info" );
+                }
+
+                # in interactive mode prompt the user for answer to missing 
question
+                else {
+                    logger( "Prompting user for answer", "info" );
+                    if ($hidden) {
+                        $answer = promptPasswordVerify($question);
+                    }
+                    else {
+                        $answer = promptUser( $question, 
$defaultValue->{$question} );
+                    }
+                }
+
+                %temp = (
+                    "config_var" => $defaultValue->{"config_var"},
+                    $question    => $answer
+                );
+
+                if ($hidden) {
+                    $temp{"hidden"} .= "true";
+                }
+
+                push $userInput->{$file}, \%temp;
+
+                $diffs++;
+            }
+        }
+    }
+
+    logger( "File sanity check complete - found $diffs difference" . ( $diffs 
== 1 ? "" : "s" ), "info" );
 }
-else {
-               print "Not creating default profiles.\n";
+
+# A function which returns the default inputs data structure. These questions 
and answers will be used if there is no
+#  user input config file or if there are questions in the input config file 
which do not have answers
+
+sub getDefaults {
+    return {
+        $::databaseConfFile => [
+            {
+                "Database type" => "mysql",
+                "config_var"    => "type"
+            },
+            {
+                "Database name" => "traffic_ops",
+                "config_var"    => "dbname"
+            },
+            {
+                "Database server hostname IP or FQDN" => "localhost",
+                "config_var"                          => "hostname"
+            },
+            {
+                "Database port number" => "3306",
+                "config_var"           => "port"
+            },
+            {
+                "Traffic Ops database user" => "traffic_ops",
+                "config_var"                => "user"
+            },
+            {
+                "Password for Traffic Ops database user" => "",
+                "config_var"                             => "password",
+                "hidden"                                 => "true"
+            }
+        ],
+        $::dbConfFile => [
+            {
+                "Database server root (admin) user" => "root",
+                "config_var"                        => "dbAdminUser"
+            },
+            {
+                "Password for database server admin" => "",
+                "config_var"                         => "dbAdminPw",
+                "hidden"                             => "true"
+            }
+        ],
+        $::cdnConfFile => [
+            {
+                "Generate a new secret?" => "yes",
+                "config_var"             => "genSecret"
+            },
+            {
+                "Number of secrets to keep?" => "10",
+                "config_var"                 => "keepSecrets"
+            }
+        ],
+        $::ldapConfFile => [
+            {
+                "Do you want to set up LDAP?" => "no",
+                "config_var"                  => "setupLdap"
+            },
+            {
+                "LDAP server hostname" => "",
+                "config_var"           => "hostname"
+            },
+            {
+                "LDAP Admin DN" => "",
+                "config_var"    => "admin_dn"
+            },
+            {
+                "LDAP Admin Password" => "",
+                "config_var"          => "password",
+                "hidden"              => "true"
+            },
+            {
+                "LDAP Search Base" => "",
+                "config_var"       => "search_base"
+            }
+        ],
+        $::usersConfFile => [
+            {
+                "Administration username for Traffic Ops" => "admin",
+                "config_var"                              => "tmAdminUser"
+            },
+            {
+                "Password for the admin user" => "",
+                "config_var"                  => "tmAdminPw",
+                "hidden"                      => "true"
+            }
+        ],
+        $::profilesConfFile => [],
+        $::opensslConfFile  => [
+            {
+                "Do you want to generate a certificate?" => "yes",
+                "config_var"                             => "genCert"
+            },
+            {
+                "Country Name (2 letter code)" => "XX",
+                "config_var"                   => "country"
+            },
+            {
+                "State or Province Name (full name)" => "San Jose",
+                "config_var"                         => "state"
+            },
+            {
+                "Locality Name (eg, city)" => "Default City",
+                "config_var"               => "locality"
+            },
+            {
+                "Organization Name (eg, company)" => "Default Company Ltd",
+                "config_var"                      => "company"
+            },
+            {
+                "Organizational Unit Name (eg, section)" => "",
+                "config_var"                             => "org_unit"
+            },
+            {
+                "Common Name (eg, your name or your server's hostname)" => 
"example.com",
+                "config_var"                                            => 
"common_name"
+            },
+            {
+                "RSA Passphrase" => "",
+                "config_var"     => "rsaPassword",
+                "hidden"         => "true"
+            }
+        ],
+        $::paramConfFile => [
+            {
+                "Traffic Ops url" => "https://localhost";,
+                "config_var"      => "tm.url"
+            },
+            {
+                "Human-readable CDN Name.  (No whitespace, please)" => 
"kabletown_cdn",
+                "config_var"                                        => 
"cdn_name"
+            },
+            {
+                "Health Polling Interval (milliseconds)" => "8000",
+                "config_var"                             => 
"health_polling_int"
+            },
+            {
+                "DNS sub-domain for which your CDN is authoritative" => 
"cdn1.kabletown.net",
+                "config_var"                                         => 
"dns_subdomain"
+            },
+            {
+                "TLD SOA admin" => "traffic_ops",
+                "config_var"    => "soa_admin"
+            },
+            {
+                "TrafficServer Drive Prefix" => "/dev/sd",
+                "config_var"                 => "driver_prefix"
+            },
+            {
+                "TrafficServer RAM Drive Prefix" => "/dev/ram",
+                "config_var"                     => "ram_drive_prefix"
+            },
+            {
+                "TrafficServer RAM Drive Letters (comma separated)" => 
"0,1,2,3,4,5,6,7",
+                "config_var"                                        => 
"ram_drive_letters"
+            },
+            {
+                "Health Threshold Load Average" => "25",
+                "config_var"                    => "health_thresh_load_avg"
+            },
+            {
+                "Health Threshold Available Bandwidth in Kbps" => "1750000",
+                "config_var"                                   => 
"health_thresh_kbps"
+            },
+            {
+                "Traffic Server Health Connection Timeout (milliseconds)" => 
"2000",
+                "config_var"                                              => 
"health_connect_timeout"
+            }
+
+        ]
+    };
 }
 
-#print "\nRunning smoke tests.\n\n";
-#$rc = execCommand ("/opt/traffic_ops/install/bin/systemtest", "localhost", 
$user{username}, $tmAdminPw, "0");
-{
-               my $ans = promptUser( "\nInstall Cron entry to clean install 
.iso files older than 7 days? [y/n]", "n" );
-               if ($ans eq "y" || $ans eq "Y") {
-                               execCommand( "/bin/echo \"00 04 * * * root 
/bin/find /opt/traffic_ops/app/public/iso/*.iso -mtime +7 -exec /bin/rm {} \; > 
/dev/null 2>&1 \" > /etc/cron.d/trafops_clean_isos" );
-               }
+# carried over from old postinstall
+#
+# todbconf: The database configuration to be used
+# opensslconf: The openssl configuration if any
+
+sub setupDatabase {
+    my $todbconf    = shift;
+    my $opensslconf = shift;
+    my $genCert     = shift;
+
+    #
+    # Call mysql initialization script.
+    #
+    logger( "Creating database with user: $todbconf->{dbAdminUser}", "info" );
+    my $result = execCommand( "/opt/traffic_ops/install/bin/create_db", 
$todbconf->{dbAdminUser}, $todbconf->{dbAdminPw} );
+    if ( $result != 0 ) {
+        errorOut("Failed to create the database");
+    }
+
+    logger( "Setting up database", "info" );
+    chdir("/opt/traffic_ops/app");
+    $result = execCommand( "/usr/bin/perl", "db/admin.pl", "--env=production", 
"setup" );
+
+    if ( $result != 0 ) {
+        errorOut("Database initialization failed");
+    }
+    else {
+        logger( "Database initialization succeeded", "info" );
+    }
+
+    $result = execCommand( "/opt/traffic_ops/install/bin/dataload", 
$todbconf->{dbAdminUser}, $todbconf->{dbAdminPw} );
+    if ( $result != 0 ) {
+        logger( "Failed to load seed data", "error" );
+    }
+
+    logger( "Downloading MaxMind data", "info" );
+    chdir("/opt/traffic_ops/app/public/routing");
+    $result = execCommand("/usr/bin/wget 
http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.mmdb.gz";);
+    if ( $result != 0 ) {
+        logger( "Failed to download MaxMind data", "error" );
+    }
+
+    logger( "Copying coverage zone file to public dir", "info" );
+    $result = execCommand("/bin/mv 
/opt/traffic_ops/app/public/coverage-zone.json .");
+    if ( $result != 0 ) {
+        logger( "Failed to copy coverage zone file", "error" );
+    }
+
+    if ( lc $genCert =~ /^y(?:es)?/ ) {
+        if ( -x "/usr/bin/openssl" ) {
+            logger( "Installing SSL Certificates", "info" );
+            $result = GenerateCert::createCert($opensslconf);
+
+            if ( $result != 0 ) {
+                errorOut("SSL Certificate Installation failed");
+            }
+            else {
+                logger( "SSL Certificates have been installed", "info" );
+            }
+        }
+        else {
+            logger( "Unable to install SSL certificates as openssl is not 
installed",                                     "error" );
+            logger( "Install openssl and then run 
/opt/traffic_ops/install/bin/generateCert to install SSL certificates", "error" 
);
+            exit 4;
+        }
+    }
+    else {
+        logger("Not generating openssl certification", "info");
+    }
 }
 
-{
-               my $ans = promptUser( "\nShutdown Traffic Ops [y/n]", "n" );
-               if ( $ans eq "y" ) {
-                               print "\nShutting down Traffic Ops.\n\n";
-                               execCommand( "/sbin/service", "traffic_ops", 
"stop" );
-               }
+# -cfile     - Input File:       The input config file used to ask and answer 
questions
+# -a         - Automatic mode:   If there are questions in the config file 
which do not have answers, the script
+#                                will look to the defaults for the answer. If 
the answer is not in the defaults
+#                                the script will exit
+# -r         - Reconfigure:      Whether or not to reconfigure the database 
and check perl dependencies - This will rereate the database
+# -defaults  - Defaults:         Writes out a configuration file with defaults 
which can be used as input
+# -debug     - Debug Mode:       More output to the terminal
+# -h         - Help:             Basic command line help menu
+
+sub main {
+    our $inputFile = "";
+    our $automatic = 0;
+    our $debug     = 0;
+    my $help = 0;
+
+    my $usageString = "Usage: postinstall [-a] [-debug] [-defaults] [-r] 
-cfile=[config_file]\n";
+
+    GetOptions(
+        "cfile=s"     => \$inputFile,
+        "automatic"   => \$automatic,
+        "reconfigure" => \$reconfigure,
+        "defaults"    => \$dumpDefaults,
+        "debug"       => \$debug,
+        "help"        => \$help
+    ) or die($usageString);
+
+    # stores the default questions and answers
+    our $defaultInputs = getDefaults();
+
+    if ($help) {
+        print $usageString;
+        exit(0);
+    }
+
+    # check if the user running postinstall is root
+    if ( $ENV{USER} ne "root" ) {
+        errorOut("You must run this script as the root user");
+    }
+
+    if ( -f "$logFile.gz" ) {
+        execCommand( "/bin/gunzip", "$logFile.gz" );
+    }
+
+    logger( "Starting postinstall", "info" );
+
+    logger( "Debug is on", "info" );
+
+    if ($::automatic) {
+        logger( "Running in automatic mode", "info" );
+    }
+
+    # check if the reconfigure_file is present on the system - if it is let 
the user know its deprecated
+    #  and exit with an error
+    if ( -f $reconfigure_file ) {
+        logger( "$reconfigure_file file is reprecated - please remove and 
rerun postinstall", "error" );
+        return;
+    }
+
+    if ($dumpDefaults) {
+        logger( "Writing default configuration file to $outputConfigFile", 
"info" );
+        writeJson( $outputConfigFile, $::defaultInputs );
+        return;
+    }
+
+    logger( "Postinstall " . ( defined $reconfigure ? "in" : "not" ) . " in 
reconfigure mode", "info" );
+
+    rotateLog($cpanLogFile);
+
+    if ( -s $::logFile > $maxLogSize ) {
+        logger( "Postinstall log above max size of $maxLogSize bytes - 
rotating", "info" );
+        rotateLog($logFile);
+    }
+
+    # used to store the questions and answers provided by the user
+    my $userInput;
+
+    # if no input file provided use the defaults
+    if ( $::inputFile eq "" ) {
+        logger( "No input file given - using defaults", "info" );
+        $userInput = $::defaultInputs;
+    }
+    else {
+        logger( "Using input file $::inputFile", "info" );
+
+        # check if the input file exists
+        errorOut("File '$::inputFile' not found") if ( !-f $::inputFile );
+
+        # read and store the input file
+        $userInput = readJson($::inputFile);
+    }
+
+    # sanity check the defaults if running them automatically
+    sanityCheckDefaults();
+
+    # check the input config file against the defaults to check for missing 
questions
+    sanityCheckConfig($userInput) if ( $inputFile ne "" );
+
+    chdir("/opt/traffic_ops/install/bin");
+
+    # if the reconfigure file exists or reconfigure is set then rebuild the 
perl deps
+    if ( -f $reconfigure_file || $reconfigure ) {
+        my $rc = BuildPerlDeps::build(1);
+        if ( $rc != 0 ) {
+            errorOut("Failed to install perl dependencies, check the console 
output and rerun postinstall once you've resolved the error");
+        }
+        $rc = execCommand( "./download_web_deps", "-i" );
+        if ( $rc != 0 ) {
+            errorOut("Failed to install Traffic Ops Web dependencies, check 
the console output and rerun postinstall once you've resolved the error");
+        }
+    }
+    else {
+        my $rc = BuildPerlDeps::build();
+        if ( $rc != 0 ) {
+            errorOut("Failed to install perl dependencies, check the console 
output and rerun postinstall once you've resolved the error");
+        }
+        $rc = execCommand( "./download_web_deps", "-i" );
+        if ( $rc != 0 ) {
+            errorOut("Failed to install Traffic Ops Web dependencies, check 
the console output and rerun postinstall once you've resolved the error");
+        }
+    }
+
+    # The generator functions handle checking input/default/automatic mode
+
+    # todbconf will be used later when setting up the database
+    my $todbconf = generateDbConf( $userInput, $::databaseConfFile, 
$::dbConfFile );
+    generateCdnConf( $userInput, $::cdnConfFile );
+    generateLdapConf( $userInput, $::ldapConfFile );
+    my $adminconf = generateUsersConf( $userInput, $::usersConfFile );
+    generateProfilesDir( $userInput, $::profilesConfFile );
+    my $opensslconf = generateOpenSSLConf( $userInput, $::opensslConfFile );
+    my $paramconf = generateParamConf( $userInput, $::paramConfFile );
+
+    # if the reconfigure file exists or the reconfigure command line arg is 
set then setup the database
+    if ( -f $reconfigure_file || $reconfigure ) {
+        if ($::automatic) {
+            setupDatabase( $todbconf, $::opensslConfFile, 
$opensslconf->{genCert} );
+        }
+        else {
+            setupDatabase( $todbconf, 0, $opensslconf->{genCert} );
+        }
+    }
+
+    # remove the reconfigure file if it exists
+    if ( -f $reconfigure_file ) {
+        logger( "Removing reconfigure file", "info" );
+        unlink($reconfigure_file);
+    }
+
+    logger( "Starting Traffic Ops", "info" );
+    execCommand("/sbin/service traffic_ops start");
+
+    logger( "Waiting for Traffic Ops to start", "info" );
+
+    if ( !profiles_exist( $adminconf, $paramconf->{"tm.url"} ) ) {
+        logger( "Creating default profiles...", "info" );
+        replace_profile_templates($paramconf);
+        import_profiles($adminconf);
+        profiles_exist( $adminconf, $paramconf->{"tm.url"} );    # call again 
to create $reconfigure_defaults file if import was successful
+    }
+    else {
+        logger( "Not creating default profiles", "info" );
+    }
+
+    logger("Postinstall complete");
+
+    execCommand( "/bin/gzip", "$logFile" );
 }
 
-print "\nTo start Traffic Ops:  service traffic_ops start\n";
-print "To stop Traffic Ops:   service traffic_ops stop\n";
-print "\n";
+main;
 
-exit 0;
+# vi:syntax=perl

Reply via email to