Module: CloudProviders::Connections

Included in:
RemoteInstance
Defined in:
lib/cloud_providers/connections.rb

Instance Method Summary collapse

Instance Method Details

#host(n = nil) ⇒ Object

hostname or ip to use when running remote commands



7
8
9
10
11
12
13
# File 'lib/cloud_providers/connections.rb', line 7

def host(n=nil)
  if n.nil? 
    @host ||= dns_name
  else
    @host = n
  end
end

#ping_port(host, port = 22, retry_times = 400) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/cloud_providers/connections.rb', line 15

def ping_port(host, port=22, retry_times=400)
  connected = false
  retry_times.times do |i|
    begin
      break if connected = TCPSocket.new(host, port).is_a?(TCPSocket)
    rescue Exception => e
      sleep(2)
    end
  end
  connected
end

#rsync(opts = {}) ⇒ Object

Raises:

  • (StandardError)


102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/cloud_providers/connections.rb', line 102

def rsync( opts={} )
  raise StandardError.new("You must pass a :source=>uri option to rsync") unless opts[:source]
  ssh_error_msg="SSH is not available for this node. perhaps you need to authorize it?"
  raise PoolParty::PoolPartyError.create("SSHError", ssh_error_msg) unless ssh_available?
  destination_path = opts[:destination] || opts[:source]
  rsync_opts = opts[:rsync_opts] || '-va'
  rsync_opts += %q% --rsync-path="sudo rsync"% unless user=="root"
  rsync_opts += %q% --exclude=.svn --exclude=.git --exclude=.cvs %
  cmd_string =  "rsync -L  -e 'ssh #{ssh_options}' #{rsync_opts} #{opts[:source]}  #{user}@#{host}:#{destination_path}"
  out = system_run(cmd_string)
  out
end

#run(commands, o = {}) ⇒ Object



27
28
29
# File 'lib/cloud_providers/connections.rb', line 27

def run(commands, o={})
  ssh(commands)
end

#scp(opts = {}) ⇒ Object

Raises:

  • (StandardError)


115
116
117
118
119
120
121
122
123
# File 'lib/cloud_providers/connections.rb', line 115

def scp(opts={})
  source = opts[:source]
  destination_path = opts[:destination] || opts[:source]
  raise StandardError.new("You must pass a local_file to scp") unless source
  scp_opts = opts[:scp_opts] || ""
  cmd_string = "scp #{ssh_options(scp_opts)} #{source} #{user}@#{host}:#{destination_path}"
  out = system_run(cmd_string)
  out
end

#shell_escape(str) ⇒ Object



31
32
33
34
35
# File 'lib/cloud_providers/connections.rb', line 31

def shell_escape(str)
  String(str).gsub(/(?=["'\\$])/n, '\\').
    gsub(/\n/, "'\n'").
    sub(/^$/, "''")
end

#ssh(commands = [], extra_ssh_ops = {}) ⇒ Object



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
# File 'lib/cloud_providers/connections.rb', line 37

def ssh( commands=[], extra_ssh_ops={})
  # commands can be single commands, as well as array
  commands = [commands] unless commands.respond_to? :each

  # Get the environment hash out of
  # the extra_ssh_ops and then delete
  # the element
  ssh_error_msg="SSH is not available for this node. perhaps you need to authorize it?"
  raise PoolParty::PoolPartyError.create("SSHError", ssh_error_msg) unless ssh_available?
  env = extra_ssh_ops[:env] || {}
  extra_ssh_ops.delete :env

  # Decide to use sudo or not
  do_sudo = user!="root"

  if extra_ssh_ops.has_key? :do_sudo
    do_sudo = extra_ssh_ops[:do_sudo] 
    extra_ssh_ops.delete :do_sudo
  end

  envstring = env.collect {|k,v| "#{k}=#{v}"}.join ' && '
  envstring += " && " unless envstring.size == 0
  ssh_string = "ssh #{user}@#{host} #{ssh_options(extra_ssh_ops)}"

  if commands.empty?
    #TODO: replace this with a IO.popen call with read_nonblocking to show progress, and accept input
    Kernel.system(ssh_string)
  else
    r = nil
    commands.each do |command|

      cmd = "#{envstring}#{command}" 
      if do_sudo
        sudocmd = %Q% sudo sh -c "#{shell_escape cmd}" % 
      else
        sudocmd = cmd
      end

      r = system_run ssh_string + %Q% "#{shell_escape sudocmd}"% 
    end
    r
  end
end

#ssh_cleanup_known_hosts!(hosts = [host, public_ip]) ⇒ Object

remove hostname and corresponding from known_hosts file. Avoids warning when reusing elastic_ip, and less likely, if amazone reassigns ip. By default removes both dns_name and ip



83
84
85
86
87
88
# File 'lib/cloud_providers/connections.rb', line 83

def ssh_cleanup_known_hosts!(hosts=[host, public_ip])
  hosts = [hosts] unless hosts.respond_to? :each
  hosts.compact.each do |name|
    system_run "ssh-keygen -R %s" % name
  end
end

#ssh_options(opts = {}) ⇒ Object

Take a hash of options and join them into a string, combined with default options. Default options are -o StrictHostKeyChecking=no -i keypair.full_filepath -l user {‘-i’=>‘keyfile, ’-l’ => ‘fred’ } would become “-i keyfile -o StrictHostKeyChecking=no -i keypair.to_s -l fred”



94
95
96
97
98
99
100
# File 'lib/cloud_providers/connections.rb', line 94

def ssh_options(opts={})
  return @ssh_options if @ssh_options && opts.empty?
  ssh_opts = {"-i" => keypair.full_filepath,
       "-o" =>"StrictHostKeyChecking=no",
       }.merge(opts)
  @ssh_options = ssh_opts.collect{ |k,v| "#{k} #{v}"}.join(' ')
end