# -*- encoding: utf-8 -*-
#
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
# Copyright:: Copyright (c) 2012 Fletcher Nichol
# 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/server_bootstrap_base"

class Chef
  class Knife
    # Provisions a standalone server that is reachable on the network and
    # sets up an Open Source Chef Server.
    class ServerBootstrapStandalone < Knife

      banner "knife server bootstrap standalone (options)"

      include Knife::ServerBootstrapBase

      deps do
        require "knife/server/ssh"
        require "knife/server/credentials"
        require "chef/knife/bootstrap"
        Chef::Knife::Bootstrap.load_deps

        current_options = options
        self.options = Chef::Knife::Bootstrap.options.dup
        options.merge!(current_options)
      end

      option :host,
        :short => "-H FQDN_OR_IP",
        :long => "--host FQDN_OR_IP",
        :description => "Hostname or IP address of host to bootstrap"

      def run
        super
        check_ssh_connection
        standalone_bootstrap.run
        fetch_validation_key
        create_root_client
        install_client_key
      end

      def standalone_bootstrap
        setup_environment
        bootstrap = Chef::Knife::Bootstrap.new
        bootstrap.name_args = [config[:host]]
        Chef::Knife::Bootstrap.options.keys.each do |attr|
          val = config_val(attr)
          next if val.nil?

          bootstrap.config[attr] = val
        end
        bootstrap.ui = ui
        bootstrap.config[:distro] = bootstrap_distro
        bootstrap.config[:use_sudo] = true if config_val(:ssh_user) != "root"
        bootstrap
      end

      private

      def validate!
        super

        if config[:chef_node_name].nil?
          ui.error "You did not provide a valid --node-name value."
          exit 1
        end
        if config[:host].nil?
          ui.error "You did not provide a valid --host value."
          exit 1
        end
      end

      def setup_environment
        ENV["WEBUI_PASSWORD"] = config_val(:webui_password)
        ENV["AMQP_PASSWORD"] = config_val(:amqp_password)
        ENV["NO_TEST"] = "1" if config[:no_test]
      end

      def check_ssh_connection
        ssh_connection.exec! "hostname -f"
      rescue Net::SSH::AuthenticationFailed
        ui.warn("Failed to authenticate #{config_val(:ssh_user)} - " \
          "trying password auth")
        config[:ssh_password] = ui.ask(
          "Enter password for #{config_val(:ssh_user)}@#{config_val(:host)}: "
        ) { |q| q.echo = false }
      end

      def ssh_connection
        opts = {
          :host => config_val(:host),
          :user => config_val(:ssh_user),
          :password => config_val(:ssh_password),
          :port => config_val(:ssh_port),
          :keys => [config_val(:identity_file)].compact
        }
        if config_val(:host_key_verify) == false
          opts[:user_known_hosts_file] = "/dev/null"
          opts[:paranoid] = false
        end

        ::Knife::Server::SSH.new(opts)
      end
    end
  end
end
