# File lib/simp/cli/commands/bootstrap.rb, line 124
  def self.run(args = [])
    super
    return if @help_requested

    if File.exist?(Simp::Cli::BOOTSTRAP_START_LOCK_FILE)
      fail("Bootstrap cannot proceed until problem identified in\n" +
        "#{Simp::Cli::BOOTSTRAP_START_LOCK_FILE} is solved and that file is removed.")
    end

    bootstrap_start_time = Time.now

    # Set us up to use the SIMP environment, if this has not already been done.
    # (1) Be careful to preserve the existing primary, 'production' environment,
    #     if one exists.
    # (2) Create links to production in both the primary and secondary environment
    #     paths.
    environment_path = ::Utils.puppet_info[:simp_environment_path]

    fail("Could not find the simp environment path at #{environment_path}") unless File.directory?(environment_path)

    item = Simp::Cli::Config::Item::SetProductionToSimpAction.new
    item.start_time = bootstrap_start_time
    item.apply
    fail ("Could not set 'simp' to production environment") unless item.applied_status == :succeeded

    linecounts = Array.new

    # Open log file
    logfilepath = File.expand_path(BOOTSTRAP_LOG)
    FileUtils.mkpath(File.dirname(logfilepath)) unless File.exists?(logfilepath)
    @logfile = File.open(logfilepath, 'w')

    # Print intro
    system('clear')
    puts
    puts "*** Starting SIMP Bootstrap ***"
    puts "   If this runs quickly, something wrong happened. To debug the problem,"
    puts "   run 'puppet agent --test' by hand or read the log. The log can be found"
    puts "   at '#{@logfile.path}'."
    puts

    # Kill all puppet processes and stop specific services
    puts "Killing all Puppet processes, httpd and removing Puppet ssl certs.\n\n" if @verbose
    system("pkill -9 -f puppetmasterd >& /dev/null")
    system("pkill -9 -f puppet >& /dev/null")
    system('pkill -f pserver_tmp')
    system("puppet resource service puppetserver ensure=stopped >& /dev/null")
    system("puppet resource service httpd ensure=stopped >& /dev/null")
    FileUtils.rm_rf(Dir.glob(File.join(::Utils.puppet_info[:config]['ssldir'],'*')))
    FileUtils.rm_f(Dir.glob(File.join(::Utils.puppet_info[:config]['rundir'],'*')))
    FileUtils.touch('/.autorelabel')

    puts "*** Starting the Puppetmaster ***"
    puts

    FileUtils.mkdir_p("#{::Utils.puppet_info[:config]['vardir']}/pserver_tmp")
    FileUtils.chown('puppet','puppet',"#{::Utils.puppet_info[:config]['vardir']}/pserver_tmp")
    system(%{puppet resource simp_file_line puppetserver path='/etc/sysconfig/puppetserver' match='^JAVA_ARGS' line='JAVA_ARGS="-Xms2g -Xmx2g -XX:MaxPermSize=256m -Djava.io.tmpdir=#{::Utils.puppet_info[:config]['vardir']}/pserver_tmp"' 2>&1 > /dev/null})

    if File.directory?('/etc/puppetlabs/puppetserver/conf.d')
      puppetserver_dir = '/etc/puppetlabs/puppetserver/conf.d'
    else
      puppetserver_dir = '/etc/puppetserver/conf.d'
    end

    if File.directory?(puppetserver_dir)
      system(%{puppet resource simp_file_line puppetserver path='#{puppetserver_dir}/webserver.conf' match='^\\s*ssl-host' line='    ssl-host = 0.0.0.0' 2>&1 > /dev/null})
      system(%{puppet resource simp_file_line puppetserver path='#{puppetserver_dir}/webserver.conf' match='^\\s*ssl-port' line='    ssl-port = 8150' 2>&1 > /dev/null})
    end

    puts

    puppet_major_version = `puppet --version`.chomp.split('.').first
    # Define the puppet command call and the run command options
    pupcmd = 'puppet agent --onetime --no-daemonize --no-show_diff --verbose --no-splay --masterport=8150 --ca_port=8150'
    if puppet_major_version == '3'
      pupcmd += " --pluginsync"
    end

    # The final tagged run is pupmod, standalone.  It is isolated to mitigate b0rked
    # puppet runs caused by the inevitable restart of the puppetserver service during
    # its application to the system.
    pupruns = [
      'pki,stunnel,concat',
      'firstrun,concat',
      'rsync,concat,apache,iptables',
      'user',
      'group',
      'pupmod'
    ]

    # Begin tagged runs, against 8150.
    puts "Beginning Puppet agent runs ..."
    pupruns.each do |puprun|
      puts "... with tag#{puprun.include?(',') ? 's' : ''} '#{puprun}'"
      linecounts << track_output("#{pupcmd} --tags #{puprun} 2> /dev/null", '8150')
    end

    puts

    if Facter.value(:selinux) && !Facter.value(:selinux_current_mode).nil? && (Facter.value(:selinux_current_mode) != "disabled")
      puts 'Relabeling filesystem for selinux...'
      @logfile.puts('Relabeling filesystem for selinux.')
      system("fixfiles -f relabel >> #{@logfile.path} 2>&1")
    end

    # From this point on, run puppet without specifying the masterport since
    # puppetserver is configured.
    puts
    puts "*** Running Puppet Finalization ***"
    puts
    pupcmd = "puppet agent --onetime --no-daemonize --no-show_diff --verbose --no-splay"
    if puppet_major_version == '3'
      pupcmd += " --pluginsync"
    end

    # This is fugly, but until we devise an intelligent way to determine when your system
    # is 'bootstrapped', we're going to run puppet in a loop.
    (1..4).each do
      track_output("#{pupcmd}")
    end

    # Clean up the leftover puppetserver process (if any)
    begin
      pserver_proc = %x{netstat -tlpn}.split("\n").select{|x| x =~ /\d:8150/}
      unless pserver_proc.empty?
        pserver_pid = pserver_proc.first.split.last.split('/').first.to_i
        Process.kill('KILL',pserver_pid)
      end
    rescue Exception => e
      puts e
      puts "The Puppet Server process running on port 8150 could not be killed. Please check your configuration!"
    end

    # Print closing banner
    puts
    puts "*** SIMP Bootstrap Complete! ***"
    puts "Duration of complete bootstrap: #{Time.now - bootstrap_start_time} seconds" if @verbose

    if !system('ps -C httpd > /dev/null 2>&1') && (linecounts.include?(-1) || (linecounts.uniq.length < linecounts.length))
      puts "   \033[1mWarning\033[0m: Primitive checks indicate there may have been issues."
      puts "   Check '#{@logfile.path}' for details."
      puts "   Please run 'puppet agent -t' by hand to debug your configuration."
    else
      puts
      puts "You should \033[1mreboot\033[0m your system to ensure consistency at this point."
    end
    puts
  end