You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2017/01/27 16:53:25 UTC

[04/36] incubator-trafficcontrol git commit: -Removed reconfigure line -Removed trailing spaces in input.json -Renamed postinstall-new to postinstall for easier diff

-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 <pe...@cisco.com>
Authored: Mon Jan 9 09:24:43 2017 -0500
Committer: Dan Kirkwood <da...@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} || 'admin@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