#!/usr/bin/env ruby
#
# After installation, this script is used to configure the system.
#
# This is really a basic script intended to get the ball rolling in the early
# stages of the project.
#
# Run this script with elevated privileges.
#

#=============================================================================
# Configuration
#=============================================================================
# Do not change these values without also editing the "helix_web_services"
# script in the bin/ directory.

INSTALL_DIR = ENV['install_dir']
raise 'install_dir not defined' if INSTALL_DIR.nil?

HWS_USER = 'helixwebservices'

DATA_DIR = '/var/lib/perforce/helix_web_services'

LOG_DIR = '/var/log/perforce/helix_web_services'

UPSTART_FILE = '/etc/init/helix_web_services.conf'

P4PORT = '1666'

P4ROOT = '/var/lib/perforce/p4d'

P4SUPER = 'super'

P4SUPERPASS = 'superuser1A!'

#=============================================================================
# Helper Methods
#=============================================================================

require 'ohai'

def node
  @node ||= init_system
end

def init_system
  puts 'collecting system data'
  s = Ohai::System.new
  s.all_plugins
  s
end

def centos?
  node['platform'] == 'centos'
end

def ubuntu?
  node['platform'] == 'ubuntu'
end

def centos_major_version
  node['platform_version'][/\d+/]
end

def user_exists?(username)
  system("getent passwd #{username} > /dev/null")
end

def create_user(username)
  puts "creating user #{username}"

  home_dir = File.join(INSTALL_DIR, 'home', username)

  if centos?
    system(%W(
           useradd -r
               --shell /bin/bash
               --home #{home_dir}
               #{username}
      ).join(' '))
  else
    system(%W(adduser --system
             --group
             --home #{home_dir}
               --shell /bin/bash
             #{username}).join(' '))
  end
end

def ensure_dir_exists(dir, user)
  unless Dir.exist?(dir)
    FileUtils.mkpath(dir)
    FileUtils.chown(user, user, dir)
  end
end

# Make sure that the Upstart configuration file has been linked
def ensure_startup_config_exists
  unless File.exist?(UPSTART_FILE)
    FileUtils.ln_sf("#{INSTALL_DIR}#{UPSTART_FILE}", UPSTART_FILE)
    system('sudo initctl reload-configuration')
  end
end

def package_installed?(package)
  if centos?
    system("yum list installed #{package} > /dev/null 2>&1")
  else
    `sudo dpkg -l | awk '{print $2}'`.include?(package)
  end
end

def add_packaging_key
  if centos?
    system('sudo rpm --import http://package.perforce.com/perforce.pubkey')
  else
    system('wget -q http://package.perforce.com/perforce.pubkey -O - | sudo apt-key add -')
  end
end

def configure_repo
  if centos?
    IO.write('/etc/yum.repos.d/perforce.repo',
      <<-END.gsub(/^[ ]{6}/, '')
      [perforce]
      name=Perforce
      baseurl=http://package.perforce.com/yum/rhel/#{centos_major_version}/#{node["kernel"]["machine"]}
      enabled=1
      gpgcheck=1
      END
    )
  else
    IO.write('/etc/apt/sources.list.d/perforce.sources.list',
             'deb http://package.perforce.com/apt/ubuntu precise release')
  end
end

def configure_package_repo
  add_packaging_key
  configure_repo
  if ubuntu?
    system('sudo apt-get update')
  end
end

def create_projects_stream(p4)
  depot = p4.fetch_depot('projects')
  depot._depot = 'projects'
  depot._type = 'stream'
  p4.save_depot(depot)
end

def create_projects_meta_depot(p4)
  depot = p4.fetch_depot('.projects')
  depot._depot = '.projects'
  p4.save_depot(depot)
end

# When setting up the default p4d instance, this will create the //projects
# stream depot and //.projects standard depot for Helix Sync.
def configure_project_depots
  require 'P4'

  p4 = P4.new
  p4.exception_level = P4::RAISE_ERRORS
  p4.port = ':1666'
  p4.charset = 'auto'
  p4.user = P4SUPER
  p4.password = P4SUPERPASS
  p4.connect
  p4.run_login

  create_projects_stream(p4)
  create_projects_meta_depot(p4)

  p4.run_logout
  p4.disconnect
end

# Install and configure a p4d instance with a default superuser and password.
# This will generate a couple of depots for Helix Sync usage.
def install_default_p4d
  puts 'Installing default perforce-server'
  configure_package_repo

  if centos?
    system('sudo yum -y install perforce-server')
  else
    system('sudo apt-get install -y perforce-server')
  end

  system('/opt/perforce/sbin/configure-perforce-server.sh helix-evaluation ' +
             "-n -p #{P4PORT} -r #{P4ROOT} " +
             "-u #{P4SUPER} " +
             "-P #{P4SUPERPASS} " +
             '--unicode')

  configure_project_depots
end

def install_nginx
  if centos?
    system('sudo yum -y install epel-release')
    system('sudo yum -y install nginx')
    # CentOS doesn't have the 'snakeoil' cert by default
    system('mkdir -p /etc/ssl/private')
    system("#{INSTALL_DIR}/bin/make-dummy-cert")
  else
    system('sudo apt-get update')
    system('sudo apt-get install -y nginx ssl-cert')
  end
end

def configure_default_nginx
  IO.write('/etc/nginx/nginx.conf', <<-END.gsub(/^[ ]{4}/, '')
    error_log /var/log/nginx/error.log info;
    worker_processes 10;
    events {
      worker_connections  1024;
    }
    http {
      log_format   main '$remote_addr - $remote_user [$time_local]  $status '
          '"$request" $body_bytes_sent "$http_referer" '
          '"$http_user_agent" "$http_x_forwarded_for"';
      access_log /var/log/nginx/access.log;
      map $http_upgrade $connection_upgrade {
        default Upgrade;
        ''      close;
      }
      upstream unicorn_server {
        server 127.0.0.1:9000;
      }
      server {
        listen 443;
        ssl on;
        ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
        ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
        location /hws/ {
          rewrite /hws/(.*) /$1 break;
          proxy_pass http://unicorn_server;
        }
      }
    }
    END
  )
end

#=============================================================================
# Execution
#=============================================================================

unless user_exists?(HWS_USER)
  create_user(HWS_USER)
end

require 'fileutils'

ensure_dir_exists(DATA_DIR, HWS_USER)
ensure_dir_exists(LOG_DIR, HWS_USER)

ensure_startup_config_exists

unless package_installed?('nginx')
  install_nginx
  configure_default_nginx
end

unless package_installed?('perforce-server')
  # This seems to trigger a script exit
  install_default_p4d
end

puts 'helix_web_services ready to be started'