#
# Author:: Adam Jacob (<adam@opscode.com>)
# Copyright:: Copyright (c) 2009 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'chef/knife'
require 'json'
require 'tempfile'

class Chef
  class Knife
    class TerremarkServerCreate < Knife

      banner "knife terremark server create NAME [RUN LIST...] (options)"

      option :terremark_password,
        :short => "-K PASSWORD",
        :long => "--terremark-password PASSWORD",
        :description => "Your terremark password",
        :proc => Proc.new { |key| Chef::Config[:knife][:terremark_password] = key } 

      option :terremark_username,
        :short => "-A USERNAME",
        :long => "--terremark-username USERNAME",
        :description => "Your terremark username",
        :proc => Proc.new { |username| Chef::Config[:knife][:terremark_username] = username } 

      option :terremark_service,
        :short => "-S SERVICE",
        :long => "--terremark-service SERVICE",
        :description => "Your terremark service name",
        :proc => Proc.new { |service| Chef::Config[:knife][:terremark_service] = service } 

      def h
        @highline ||= HighLine.new
      end

      def run 
        require 'fog'
        require 'highline'
        require 'net/ssh/multi'
        require 'readline'
        require 'net/scp'

        server_name = @name_args[0]

        terremark = Fog::Terremark.new(
          :terremark_username => Chef::Config[:knife][:terremark_username],
          :terremark_password => Chef::Config[:knife][:terremark_password],
          :terremark_service  => Chef::Config[:knife][:terremark_service] || :vcloud
        )

        $stdout.sync = true

        puts "Instantiating vApp #{h.color(server_name, :bold)}"
        vapp_id = terremark.instantiate_vapp_template(server_name).body['href'].split('/').last

        deploy_task_id = terremark.deploy_vapp(vapp_id).body['href'].split('/').last
        print "Waiting for deploy task [#{h.color(deploy_task_id, :bold)}]"
        terremark.tasks.get(deploy_task_id).wait_for { print "."; ready? }
        print "\n"

        power_on_task_id = terremark.power_on(vapp_id).body['href'].split('/').last
        print "Waiting for power on task [#{h.color(power_on_task_id, :bold)}]"
        terremark.tasks.get(power_on_task_id).wait_for { print "."; ready? }
        print "\n"

        private_ip = terremark.get_vapp(vapp_id).body['IpAddress']
        ssh_internet_service = terremark.create_internet_service(terremark.default_vdc_id, 'SSH', 'TCP', 22).body
        ssh_internet_service_id = ssh_internet_service['Id']
        public_ip = ssh_internet_service['PublicIpAddress']['Name']
        public_ip_id = ssh_internet_service['PublicIpAddress']['Id']
        ssh_node_service_id = terremark.add_node_service(ssh_internet_service_id, private_ip, 'SSH', 22).body['Id']

        puts "\nBootstrapping #{h.color(server_name, :bold)}..."
        password = terremark.get_vapp_template(12).body['Description'].scan(/\npassword: (.*)\n/).first.first

        command =  <<EOH
bash -c '
echo nameserver 208.67.222.222 > /etc/resolv.conf
echo nameserver 208.67.220.220 >> /etc/resolv.conf

if [ ! -f /usr/bin/chef-client ]; then
  apt-get update
  apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras
  cd /tmp
  wget http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz
  tar xvf rubygems-1.3.6.tgz
  cd rubygems-1.3.6
  ruby setup.rb
  cp /usr/bin/gem1.8 /usr/bin/gem
  gem install chef ohai --no-rdoc --no-ri --verbose
fi

mkdir -p /etc/chef

(
cat <<'EOP'
#{IO.read(Chef::Config[:validation_key])}
EOP
) > /etc/chef/validation.pem

(
cat <<'EOP'
log_level        :info
log_location     STDOUT
chef_server_url  "#{Chef::Config[:chef_server_url]}" 
validation_client_name "#{Chef::Config[:validation_client_name]}"
EOP
) > /etc/chef/client.rb

(
cat <<'EOP'
#{{ "run_list" => @name_args[1..-1] }.to_json}
EOP
) > /etc/chef/first-boot.json

/usr/bin/chef-client -j /etc/chef/first-boot.json'
EOH

        begin
          ssh = Chef::Knife::Ssh.new
          ssh.name_args = [ public_ip, "sudo #{command}" ]
          ssh.config[:ssh_user] = "vcloud"
          ssh.config[:manual] = true
          ssh.config[:password] = password
          ssh.password = password
          ssh.run
        rescue Errno::ETIMEDOUT
          puts "Timed out on bootstrap, re-trying. Hit CTRL-C to abort."
          puts "You probably need to log in to Terremark and powercycle #{h.color(@name_args[0], :bold)}"
          retry
        end

      end
    end
  end
end