#!/usr/bin/env ruby
# Copyright 2011 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

require 'rhc-common'

#
# print help
#
def p_usage

    puts <<USAGE

Usage: #{$0}
Bind a registered rhcloud user to a domain in rhcloud.

  NOTE: to change ssh key, alter your openshift <id_rsa> and
        <id_rsa>.pub keys, then re-run with --alter

  -n|--namespace   namespace   Namespace for your application(s) (alphanumeric - max #{RHC::DEFAULT_MAX_LENGTH} chars) (required)
  -l|--rhlogin     rhlogin     Red Hat login (RHN or OpenShift login with OpenShift Express access) (required)
  -p|--password    password    RHLogin password (optional, will prompt)
  -a|--alter                   Alter namespace (will change urls) and/or ssh key
  -d|--debug                   Print Debug info
  -h|--help                    Show Usage info
  --config  path               Path of alternate config file
  --timeout #                  Timeout, in seconds, for connection

USAGE
exit 255
end

begin
    opts = GetoptLong.new(
        ["--debug", "-d", GetoptLong::NO_ARGUMENT],
        ["--help",  "-h", GetoptLong::NO_ARGUMENT],
        ["--rhlogin",  "-l", GetoptLong::REQUIRED_ARGUMENT],
        ["--password",  "-p", GetoptLong::REQUIRED_ARGUMENT],
        ["--namespace", "-n", GetoptLong::REQUIRED_ARGUMENT],
        ["--config", GetoptLong::REQUIRED_ARGUMENT],
        ["--alter", "-a", GetoptLong::NO_ARGUMENT],
        ["--timeout", GetoptLong::REQUIRED_ARGUMENT]
    )
    
    opt = {}
    opts.each do |o, a|
        opt[o[2..-1]] = a.to_s
    end
rescue Exception => e
  #puts e.message
  p_usage
end

# If provided a config path, check it
check_cpath(opt)

# Pull in configs from files
libra_server = get_var('libra_server')
debug = get_var('debug') == 'false' ? nil : get_var('debug')


ssh_key_file_path = get_kfile(false)
ssh_pub_key_file_path = get_kpfile(ssh_key_file_path, opt['alter'])

ssh_config = "#{ENV['HOME']}/.ssh/config"
ssh_config_d = "#{ENV['HOME']}/.ssh/"

if opt["help"]
    p_usage
end

if opt["debug"]
    debug = true
end
RHC::debug(debug)

RHC::timeout(opt["timeout"] ? opt["timeout"] : get_var('timeout'))

if !RHC::check_namespace(opt['namespace'])
    p_usage
end

if !RHC::check_rhlogin(opt['rhlogin'])
    p_usage
end


if !opt["rhlogin"] || !opt["namespace"]
    p_usage
end

password = opt['password']
if !password
  password = RHC::get_password
end

#
# Add a new namespace to configs
#
def add_rhlogin_config(rhlogin, uuid)
    f = open(File.expand_path(config_path), 'a')
    unless config.get_value('default_rhlogin')
        f.puts("# Default rhlogin to use if none is specified")
        f.puts("default_rhlogin=#{rhlogin}")
        f.puts("")
    end
    f.close
end

#
# Check / add new host to ~/.ssh/config
#
def add_ssh_config_host(rhc_domain, ssh_key_file_path, ssh_config, ssh_config_d)
  
  puts "Checking ~/.ssh/config"
  ssh_key_file_name = File.basename(ssh_key_file_path)
  if ssh_key_file_path =~ /^#{ENV['HOME']}/
    ssh_key_file_path = ssh_key_file_path[ENV['HOME'].length..-1]
    if ssh_key_file_path =~ /^\// || ssh_key_file_path =~ /^\\/
      ssh_key_file_path = '~' + ssh_key_file_path
    else
      ssh_key_file_path = '~/' + ssh_key_file_path
    end
  end
  if (ssh_key_file_name != 'id_rsa')
    found = false

    begin
        File.open(ssh_config, "r") do |sline|
            while(line = sline.gets)
                if line.to_s.index("Host *.#{rhc_domain}") == 0
                    found = true
                    break
                end
            end
        end
    rescue Errno::EACCES
        puts "Could not read from #{ssh_config}"
        puts "Reason: " + $!
        puts
        puts "Please correct this first.  Then run rerun."
        puts
        exit 213
    rescue Errno::ENOENT
        puts "Could not find #{ssh_config}.  This is ok, continuing"
    end
    if found
        puts "Found #{rhc_domain} in ~/.ssh/config... No need to adjust"
    else
        puts "    Adding #{rhc_domain} to ~/.ssh/config"
        begin
            f = File.open(ssh_config, "a")
            f.puts <<SSH

# Added by rhc-create-domain on #{`date`}
Host *.#{rhc_domain}
    IdentityFile #{ssh_key_file_path}
    VerifyHostKeyDNS yes
    StrictHostKeyChecking no
    UserKnownHostsFile ~/.ssh/libra_known_hosts

SSH
            f.close
        rescue Errno::EACCES
            puts "Could not write to #{ssh_config}"
            puts "Reason: " + $!
            puts
            puts "Please correct this first.  Then run rerun."
            puts
            exit 214
        rescue Errno::ENOENT
            # Make directory and config if they do not exist
            puts "Could not find directory: " + $!
            puts "creating"
            FileUtils.mkdir_p ssh_config_d
            file = File.open(ssh_config, 'w')
            file.close
            retry
        end
    end

    File.chmod(0700, ssh_config_d)
    File.chmod(0600, ssh_config)
  end
end


#
# Check to see if a ssh_key_file_path exists, if not create it.
#

if File.readable?(ssh_key_file_path)
    puts "OpenShift Express key found at #{ssh_key_file_path}.  Reusing..."
else
    puts "Generating OpenShift Express ssh key to #{ssh_key_file_path}"
    # Use system for interaction
    system("ssh-keygen -t rsa -f '#{ssh_key_file_path}'")
end

ssh_keyfile_contents = File.open(ssh_pub_key_file_path).gets.chomp.split(' ')
ssh_key = ssh_keyfile_contents[1]
ssh_key_type = ssh_keyfile_contents[0]

data = {'namespace' => opt['namespace'],
        'rhlogin' => opt['rhlogin'],
        'ssh' => ssh_key,
        'key_type' => ssh_key_type}

if (opt['alter'])
  data[:alter] = true
  not_found_message = "A user with rhlogin '#{opt['rhlogin']}' does not have a registered domain.  Be sure to run rhc-create-domain without -a|--alter first."
  user_info = RHC::get_user_info(libra_server, opt['rhlogin'], password, @http, true, not_found_message)
end
if debug
  data[:debug] = true
end
RHC::print_post_data(data)
json_data = RHC::generate_json(data)

url = URI.parse("https://#{libra_server}/broker/domain")
response = RHC::http_post(@http, url, json_data, password)

if response.code == '200'
    begin
        json_resp = JSON.parse(response.body)
        RHC::print_response_success(json_resp)
        json_rhlogininfo = JSON.parse(json_resp['data'])
        add_rhlogin_config(json_rhlogininfo['rhlogin'], json_rhlogininfo['uuid'])
        add_ssh_config_host(json_rhlogininfo['rhc_domain'], ssh_key_file_path, ssh_config, ssh_config_d)
    
        if opt['alter'] != ''
            puts <<EOF
Creation successful

You may now create an application.

EOF
        else
            app_info = user_info['app_info']
            dns_success = true
            if !app_info.empty? && opt['namespace'] != user_info['user_info']['namespace']
              #
              # Confirm that the host(s) exist in DNS
              #
              puts "Now your new domain name(s) are being propagated worldwide (this might take a minute)..."
              # Allow DNS to propogate
              sleep 15
              app_info.each_key do |appname|
                  fqdn = "#{appname}-#{opt['namespace']}.#{user_info['user_info']['rhc_domain']}"
                  
                  # Now start checking for DNS
                  loop = 0
                  sleep_time = 2
                  while loop < RHC::MAX_RETRIES && !RHC::hostexist?(fqdn)
                      sleep sleep_time
                      loop+=1
                      puts "  retry # #{loop} - Waiting for DNS: #{fqdn}"
                      sleep_time = RHC::delay(sleep_time)
                  end
                  
                  if loop >= RHC::MAX_RETRIES
                      puts "Host could not be found: #{fqdn}"
                      dns_success = false
                  end
              end
              puts "You can use rhc-user-info to view any url changes.  Be sure to update any links"
              puts "including the url in your local git config: <local_git_repo>/.git/config"
            end
            if dns_success
              puts "Alteration successful."
            else
              puts "Alteration successful but at least one of the urls is still updating in DNS."
            end
            puts ""
        end
        exit 0
    rescue JSON::ParserError
        RHC::print_response_err(response)
    end
else
    RHC::print_response_err(response)
end
exit 1