summaryrefslogtreecommitdiff
path: root/lib/leap_cli/commands/util.rb
blob: d9e69232d54ce8073d087061d8de674bc80bdc06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
module LeapCli; module Commands

  extend self
  extend LeapCli::Util

  def path(name)
    Path.named_path(name)
  end

  #
  # keeps prompting the user for a numbered choice, until they pick a good one or bail out.
  #
  # block is yielded and is responsible for rendering the choices.
  #
  def numbered_choice_menu(msg, items, &block)
    while true
      say("\n" + msg + ':')
      items.each_with_index &block
      say("q. quit")
      index = ask("number 1-#{items.length}> ")
      if index.empty?
        next
      elsif index =~ /q/
        bail!
      else
        i = index.to_i - 1
        if i < 0 || i >= items.length
          bail!
        else
          return i
        end
      end
    end
  end

  #
  #
  #
  # FYI
  #  Capistrano::Logger::IMPORTANT = 0
  #  Capistrano::Logger::INFO      = 1
  #  Capistrano::Logger::DEBUG     = 2
  #  Capistrano::Logger::TRACE     = 3
  #
  def ssh_connect(nodes, options={}, &block)
    node_list = parse_node_list(nodes)

    cap = new_capistrano
    cap.logger.level = LeapCli.log_level
    user = options[:user] || 'root'
    cap.set :user, user
    cap.set :ssh_options, ssh_options
    cap.set :use_sudo, false # we may want to change this in the future

    # # supply drop options
    # cap.set :puppet_source, [Path.platform, 'puppet'].join('/')
    # cap.set :puppet_destination, '/root/leap'
    # #cap.set :puppet_command, 'puppet apply'
    # cap.set :puppet_lib, "puppet/modules"
    # cap.set :puppet_parameters, '--confdir=puppet puppet/manifests/site.pp'
    # #cap.set :puppet_stream_output, false
    # #puppet apply --confdir=puppet puppet/manifests/site.pp  | grep -v 'warning:.*is deprecated'
    # #puppet_cmd = "cd #{puppet_destination} && #{sudo_cmd} #{puppet_command} --modulepath=#{puppet_lib} #{puppet_parameters}"

    #
    # allow password authentication when we are bootstraping a single node.
    #
    if options[:bootstrap] && node_list.size == 1
      hostname = node_list.values.first.name

      # the 'password' block is only called if key auth fails
      if options[:echo]
        cap.set(:password) { ask "Root SSH password for #{user}@#{hostname}> " }
      else
        cap.set(:password) { Capistrano::CLI.password_prompt " * Typed password will be hidden (use --echo to make it visible)\nRoot SSH password for #{user}@#{hostname}> " }
      end
    end

    node_list.each do |name, node|
      cap.server node.name, :dummy_arg, node_options(node)
    end

    yield cap
  end


  private


  #
  # For available options, see http://net-ssh.github.com/net-ssh/classes/Net/SSH.html#method-c-start
  #
  def ssh_options
    {
      :config => false,
      :user_known_hosts_file => path(:known_hosts),
      :paranoid => true
    }
  end

  #
  # For notes on advanced ways to set server-specific options, see
  # http://railsware.com/blog/2011/11/02/advanced-server-definitions-in-capistrano/
  #
  def node_options(node)
    #password_proc = Proc.new {Capistrano::CLI.password_prompt "Root SSH password for #{node.name}"}  # only called if needed
    {
      #:password => password_proc,
      :ssh_options => {
        :host_key_alias => node.name,
        :host_name => node.ip_address,
        :port => node.ssh.port
      }
    }
  end

  def new_capistrano
    # load once the library files
    @capistrano_enabled ||= begin
      require 'capistrano'
      require 'capistrano/cli'
      require 'leap_cli/remote/plugin'
      Capistrano.plugin :leap, LeapCli::Remote::Plugin
      true
    end

    # create capistrano instance
    cap = Capistrano::Configuration.new

    # add tasks to capistrano instance
    cap.load File.dirname(__FILE__) + '/../remote/tasks.rb'

    return cap
  end

  def parse_node_list(nodes)
    if nodes.is_a? Config::Object
      Config::ObjectList.new(nodes)
    elsif nodes.is_a? Config::ObjectList
      nodes
    elsif nodes.is_a? String
      manager.filter!(nodes)
    else
      bail! "argument error"
    end
  end

end; end