#!/usr/bin/env oo-ruby

require 'rubygems'
require 'getoptlong'

def usage
  puts <<USAGE
== Synopsis

oo-admin-ctl-domain: Manage user domains

== Usage

oo-admin-ctl-domain OPTIONS

Options:
-l|--login <login_name>
    Login with OpenShift access (required)
-p|--provider <provider_name>
    Source of the login (optional)
-n|--namespace <Namespace>
    Namespace for application(s) (alphanumeric - max 16 chars) (required)
   --new_namespace <Namespace>
    New namespace for application(s) (alphanumeric - max 16 chars) (required
      for --comand update)
-c|--command (create|update|delete|info|env_add|env_del)
-s|--ssh_key <ssh key>
    User\'s SSH key
-t|--key_type <ssh key type>
    User's SSH key type (ssh-rsa|ssh-dss|ssh-rsa-cert-v01@openssh.com|ssh-dss-cert-v01@openssh.com|ssh-rsa-cert-v00@openssh.com|ssh-dss-cert-v00@openssh.com|krb5-principal)
-k|--key_name <ssh key name>
    User's SSH key name
-e|--env_name <env var name>
-v|--env_value <env var value>
-h|--help:
    Show Usage info
USAGE
  exit 255
end

opts = GetoptLong.new(
    ["--login",            "-l", GetoptLong::REQUIRED_ARGUMENT],
    ["--provider",         "-p", GetoptLong::REQUIRED_ARGUMENT],
    ["--namespace",        "-n", GetoptLong::REQUIRED_ARGUMENT],
    ["--command",          "-c", GetoptLong::REQUIRED_ARGUMENT],
    ["--ssh_key",          "-s", GetoptLong::REQUIRED_ARGUMENT],
    ["--key_type",         "-t", GetoptLong::REQUIRED_ARGUMENT],
    ["--key_name",         "-k", GetoptLong::REQUIRED_ARGUMENT],
    ["--env_name",         "-e", GetoptLong::REQUIRED_ARGUMENT],
    ["--env_value",        "-v", GetoptLong::REQUIRED_ARGUMENT],
    ["--new_namespace"         , GetoptLong::REQUIRED_ARGUMENT],
    ["--allowed_gear_sizes"    , GetoptLong::REQUIRED_ARGUMENT],
    ["--help",             "-h", GetoptLong::NO_ARGUMENT]
)

args = {}
begin
  opts.each{ |k,v| args[k]=v }
rescue GetoptLong::Error => e
  usage
end

login = args["--login"]
provider = args["--provider"]
ssh_key = args["--ssh_key"]
ssh_type = args["--key_type"]
ssh_name = args["--key_name"]
namespace = args["--namespace"]
new_namespace = args["--new_namespace"]
env_name = args["--env_name"]
env_value = args["--env_value"]
allowed_gear_sizes = args["--allowed_gear_sizes"]

if login.nil? or args["--help"]
  usage
end

require "/var/www/openshift/broker/config/environment"
# Disable analytics for admin scripts
Rails.configuration.analytics[:enabled] = false

reply = ResultIO.new
case args["--command"]
when "env_add"
  if env_name.nil? || env_value.nil?
    print "Please provide environment variable name and value\n"
    exit 1
  end
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
    puts "User with login: #{login} not found"
    exit 1
  end
  begin
    domain = Domain.with(consistency: :eventual).find_by(owner: user, canonical_namespace: namespace.downcase)
  rescue Mongoid::Errors::DocumentNotFound
    puts "Domain with namespace: #{namespace} not found for user #{user.login}"
    exit 1
  end

  env = domain.env_vars.select{ |e| e["key"] == env_name }.first
  unless env.nil?
    puts "Environment variable with name #{env_name} already exists in the domain. Please remove it first"
    exit 1
  end

  domain.add_env_variables([{"key" => env_name, "value" => env_value}])
  domain.reload
  domain.run_jobs
when "env_del"
  if env_name.nil?
    print "Please provide environment variable name\n"
    exit 1
  end
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
    puts "User with login: #{login} not found"
    exit 1
  end
  begin
    domain = Domain.with(consistency: :eventual).find_by(owner: user, canonical_namespace: namespace.downcase)
  rescue Mongoid::Errors::DocumentNotFound
    puts "Domain with namespace: #{namespace} not found for user #{user.login}"
    exit 1
  end

  env = domain.env_vars.select{ |e| e["key"] == env_name }.first
  if env.nil?
    puts "Environment variable #{env_name} not found withing domain #{namespace}"
    exit 1
  end

  domain.remove_env_variables([{"key" => env["key"], "value" => env["value"]}])
  domain.reload
  domain.run_jobs
when "create"
  if namespace.blank? || login.blank?
    print "Please provide login and namespace to create the domain\n"
    exit 1
  end
  user = nil
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
    puts "User #{login} does not exist."
    exit 1
  end

  unless user.domains.count < user.max_domains
    puts "The user #{login} cannot have more than #{user.max_domains} #{"domain".pluralize(user.max_domains)}.  Please use the 'update' command instead."
    exit 1
  end
  
  begin
    Domain.with(consistency: :eventual).find_by(canonical_namespace: namespace.downcase)
    puts "Domain #{namespace.downcase} already exists.  Please choose another."
    exit 1
  rescue Mongoid::Errors::DocumentNotFound
  end
  
  # Add the ssh key if it is provided
  if ssh_key
    user.add_ssh_key(UserSshKey.new(name: ssh_name, content: ssh_key, type: ssh_type))
    unless user.save
      puts "An error occurred during ssh key addition. Errors: #{user.errors.messages}"
      exit 2
    end
  end
  
  domain = Domain.new(namespace: namespace, owner: user)
  unless domain.save
    puts "An error occurred during domain creation. Errors: #{domain.errors.messages}"
    exit 3
  end
  reply.resultIO << "Successfully created domain.\n"

when "update"
  if namespace.blank? || login.blank? || (allowed_gear_sizes.nil? && new_namespace.blank?)
    print "Please provide login, namespace, and either a new namespace (rename), or a set of allowed gear sizes, to update the domain\n"
    exit 1
  end
  user = nil
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
  end
  unless user
    puts "User with login: #{login} not found"
    exit 1
  end

  d = nil
  if user.domains.empty?
    puts "No domain exists for the user #{login}.  Please use the 'create' command instead."
    exit 1
  else
    begin
      d = user.domains.find_by(canonical_namespace: namespace)
      if new_namespace
        d.namespace = new_namespace
      end
      if allowed_gear_sizes
        d.allowed_gear_sizes = allowed_gear_sizes.split(',').map(&:strip)
      end
      d.save_with_duplicate_check!
      reply.resultIO << "Successfully updated domain.\n"
    rescue OpenShift::UserException => e
      puts "#{e.message}"
      exit e.code
    rescue Exception => e
      puts "#{e.message}"
      exit 1
    end
  end
  
  unless ssh_key.nil?
    has_key = false
    user.ssh_keys.each do |key|
      if key.name == ssh_name
        has_key = true
        break
      end
    end
    if has_key 
      user.update_ssh_key(UserSshKey.new(name: ssh_name, content: ssh_key, type: ssh_type))
    else
      user.add_ssh_key(UserSshKey.new(name: ssh_name, content: ssh_key, type: ssh_type))
    end
    unless user.save
      puts "An error occurred during ssh key add/update. Errors: #{user.errors.messages}"
      exit 2
    end
    reply.resultIO << "Successfully updated user.\n"
  end
  
when "delete"
  user = nil
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
    puts "User with login '#{login}' not found"
    exit 1
  end
  if namespace
    domain = nil
    user.domains.each do |d|
      if namespace.downcase == d.canonical_namespace
        domain = d
        break
      end
    end
    unless domain
      puts "Domain not found: #{namespace.downcase}"
      exit 1
    end
    unless domain.applications.empty?
      puts "User still has applications. Delete them first."
      exit 1
    end
    domain.delete
    reply.resultIO << "Successfully deleted domain.\n"
  else
    unless user.domains.empty?
      puts "User still has domains. Delete them first."
      exit 1
    end
    user.delete
    reply.resultIO << "Successfully deleted user.\n"
  end
else
  user = nil
  begin
    user = CloudUser.with(consistency: :eventual).find_by(login: login)
  rescue Mongoid::Errors::DocumentNotFound
  end
  unless user
    puts "User with login: #{login} not found"
    exit 1
  end
  reply.resultIO << "RHLogin: #{user.login}\n"
  domains = user.domains.select{ |d| namespace.nil? || d.namespace.downcase == namespace.downcase }
  domains.each do |domain|
    reply.resultIO << "Namespace: #{domain.namespace}\n"
    reply.resultIO << "SSH keys:\n"
    user.ssh_keys.each do |key|
      reply.resultIO << "\t#{key.name}:\n#{key.content}\n\n"
    end unless user.ssh_keys.nil?
    reply.resultIO << "Allowed gear sizes: #{domain.allowed_gear_sizes.join(', ')}\n"
    reply.resultIO << "Applications:\n"
    domain.applications.each do |app|
      reply.resultIO << app.as_json.to_yaml
    end
  end
  if domains.empty?
    if namespace
      reply.resultIO << "No domains for #{login} match #{namespace}\n"
    else
      reply.resultIO << "No domains for #{login}\n"
    end
  end
end

print reply.resultIO.string
