#!/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)
-n|--namespace <Namespace>
    Namespace for application(s) (alphanumeric - max 16 chars) (required)
-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|ecdsa-sha2-nistp256-cert-v01@openssh.com|ecdsa-sha2-nistp384-cert-v01@openssh.com|ecdsa-sha2-nistp521-cert-v01@openssh.com|ssh-rsa-cert-v01@openssh.com|ssh-dss-cert-v01@openssh.com|ssh-rsa-cert-v00@openssh.com|ssh-dss-cert-v00@openssh.com|ecdsa-sha2-nistp256|ecdsa-sha2-nistp384|ecdsa-sha2-nistp521)
-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],
    ["--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],
    ["--help",             "-h", GetoptLong::NO_ARGUMENT]
)

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

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

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.with(consistency: :strong).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.with(consistency: :strong).reload
  domain.run_jobs
when "create"
  if ssh_key.nil? || namespace.nil? || login.nil?
    print "Please provide login, ssh key and namespace to create the user\n"
    exit 1
  end
  user = nil
  begin
    CloudUser.with(consistency: :eventual).find_by(login: login)
    puts "User #{login} already exists.  Please use the 'update' command to alter ssh keys or namespace."
    exit 1
  rescue Mongoid::Errors::DocumentNotFound
  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
  
  user = CloudUser.new(login: login)
  user.add_ssh_key(UserSshKey.new(name: ssh_name, content: ssh_key, type: ssh_type))
  user.save!
  Lock.create_lock(user)
  reply.resultIO << "Successfully created user.\n"

  domain = Domain.new(namespace: namespace, owner: user)
  domain.save!
  reply.resultIO << "Successfully created domain.\n"  
when "update"
  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
  
  if namespace
    if namespace.empty?
      puts "Namespace cannot be blank."
      exit 1
    else
      d = nil
      if user.domains.empty?
        d = Domain.new(namespace: namespace, owner: user)
        if not d.valid?
          puts "Namespace is not valid"
          exit 1
        end
        d.save!
        reply.resultIO << "Successfully added domain.\n"
      else
        d = user.domains.first
        unless d.canonical_namespace == namespace.downcase
          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

          # Validate the namespace being updated
          orig_namespace = d.namespace
          d.namespace = namespace
          if not d.valid?
            puts "Namespace is not valid"
            exit 1
          end

          # reset the original namespace back for updating
          d.namespace = orig_namespace
          begin
            d.update_namespace(namespace)
            d.save!
            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
      end
    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
    user.save!
    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."
    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"
  if user.domains.empty?
    reply.resultIO << "Namespace: No namespace registered\n"
  else
    reply.resultIO << "Namespace: #{user.domains.first.namespace}\n"
  end
  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 << "Applications:\n"
  user.domains.each do |dom|
    dom.applications.each do |app|
      reply.resultIO << app.as_json.to_yaml
    end
  end
end

print reply.resultIO.string
