Class: RemoteCommandHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/help/remote_command_handler.rb

Overview

Provides methods to be executed via ssh to remote instances.

Direct Known Subclasses

DmCryptHelper

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRemoteCommandHandler

Returns a new instance of RemoteCommandHandler.



9
10
11
12
# File 'lib/help/remote_command_handler.rb', line 9

def initialize()
  @logger = Logger.new(STDOUT)
  @use_sudo = false
end

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



8
9
10
# File 'lib/help/remote_command_handler.rb', line 8

def logger
  @logger
end

#ssh_sessionObject

Returns the value of attribute ssh_session.



8
9
10
# File 'lib/help/remote_command_handler.rb', line 8

def ssh_session
  @ssh_session
end

#use_sudoObject

Returns the value of attribute use_sudo.



8
9
10
# File 'lib/help/remote_command_handler.rb', line 8

def use_sudo
  @use_sudo
end

Instance Method Details

#connect(ip, user, key_data, timeout = 30) ⇒ Object

Connect to the machine as root using keydata from a keyfile. Params:

  • ip: ip address of the machine to connect to

  • user: user name

  • key_data: key_data to be used for authentication



29
30
31
32
33
# File 'lib/help/remote_command_handler.rb', line 29

def connect(ip, user, key_data, timeout = 30)
  @use_sudo = false
  @ssh_session = Net::SSH.start(ip, user, {:key_data => [key_data], :timeout => timeout})
  @use_sudo = true unless user.strip == 'root'
end

#connect_with_keyfile(ip, user_name, keyfile, timeout = 30) ⇒ Object

Connect to the machine as root using a keyfile. Params:

  • ip: ip address of the machine to connect to

  • keyfile: path of the keyfile to be used for authentication



18
19
20
21
22
# File 'lib/help/remote_command_handler.rb', line 18

def connect_with_keyfile(ip, user_name, keyfile, timeout = 30)
  @use_sudo = false
  @ssh_session = Net::SSH.start(ip, user_name, {:keys => [keyfile], :timeout => timeout})
  @use_sudo = true unless user_name.strip == 'root'
end

#create_filesystem(fs_type, volume) ⇒ Object



71
72
73
74
# File 'lib/help/remote_command_handler.rb', line 71

def create_filesystem(fs_type, volume)
  e = "mkfs -t #{fs_type} #{volume}"
  remote_execute(e, "y") #TODO: quiet mode?
end

#disconnectObject

Disconnect the current handler



36
37
38
# File 'lib/help/remote_command_handler.rb', line 36

def disconnect
  @ssh_session.close
end

#drive_mounted?(path) ⇒ Boolean

Checks if the drive on path is mounted

Returns:

  • (Boolean)


87
88
89
90
91
92
93
94
95
96
# File 'lib/help/remote_command_handler.rb', line 87

def drive_mounted?(path)
  #check if drive mounted
  drive_found = stdout_contains?("mount", "on #{path} type")
  if drive_found
    return file_exists?(path)
  else
    @logger.debug "not mounted (since #{path} non-existing)"
    false
  end
end

#drive_mounted_as?(device, path) ⇒ Boolean

Checks if the drive on path is mounted with the specific device

Returns:

  • (Boolean)


99
100
101
102
# File 'lib/help/remote_command_handler.rb', line 99

def drive_mounted_as?(device, path)
  #check if drive mounted
  stdout_contains?("mount", "#{device} on #{path} type")
end

#echo(data, file) ⇒ Object



164
165
166
167
168
169
170
171
# File 'lib/help/remote_command_handler.rb', line 164

def echo(data, file)
  exec = "echo #{data} > #{file}"
  @logger.debug "going to execute #{exec}"
  remote_execute(exec, nil, true)
  if !file_exists?(file)
    raise Exception.new("file #{file} could not be created")
  end
end

#file_exists?(path) ⇒ Boolean

Check if the path/file specified exists

Returns:

  • (Boolean)


41
42
43
# File 'lib/help/remote_command_handler.rb', line 41

def file_exists?(path)
  remote_execute("ls #{path}")
end

#get_output(exec_string, push_data = nil, stdout = [], stderr = []) ⇒ Object

Executes the specified #exec_string on a remote session specified as #ssh_session. When #push_data is specified, the data will be used as input for the command and thus allows to respond in advance to commands that ask the user something. It returns stdout. When #stdout or #stderr is specified as arrays, the respective output is also written into those arrays.



212
213
214
215
216
217
218
# File 'lib/help/remote_command_handler.rb', line 212

def get_output(exec_string, push_data = nil, stdout = [], stderr = [])
  exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
  stdout = []
  stderr = []
  remote_exec_helper(exec_string, stdout, stderr)
  stdout.join()
end

#install(software_package) ⇒ Object

Installs the software package specified.



51
52
53
54
55
56
57
58
59
60
# File 'lib/help/remote_command_handler.rb', line 51

def install(software_package)
  e = "yum -yq install #{software_package}"
  yum = remote_execute(e)
  if !yum
    @logger.info("yum installation failed; try apt-get")
    e = "apt-get -yq install #{software_package}"
    apt = remote_execute(e)
    @logger.info("apt=get installation? #{apt}")
  end
end

#local_rcopy(source_path, dest_path, exclude_path = nil) ⇒ Object

Copy directory using basic cp exclude_path: a space separated list of directory



113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/help/remote_command_handler.rb', line 113

def local_rcopy(source_path, dest_path, exclude_path = nil)
  e = ""
  if exclude_path.nil? || exclude_path.empty? 
    e = "cp -Rpv #{source_path} #{dest_path}"
  else
    # only one level of exclusion
    exclusion_regexp = exclude_path.gsub(' ', '|')
    e = "for dir in $(ls -d #{source_path}* | grep -E -v '#{exclusion_regexp}'); do cp -Rpv $dir #{dest_path}; done;"
  end
  @logger.debug "going to execute #{e}"
  remote_exec_helper(e, nil, nil, false)
end

#local_rsync(source_path, dest_path, exclude_path = nil) ⇒ Object

Copy directory using options -avHx



127
128
129
130
131
132
133
134
135
# File 'lib/help/remote_command_handler.rb', line 127

def local_rsync(source_path, dest_path, exclude_path = nil)
  exclude = ""
  if exclude_path != nil
    exclude = "--exclude #{exclude_path}"
  end
  e = "rsync -avHx #{exclude} #{source_path} #{dest_path}"
  @logger.debug "going to execute #{e}"
  remote_exec_helper(e, nil, nil, false) #TODO: handle output in stderr?
end

#mkdir(path) ⇒ Object



76
77
78
79
# File 'lib/help/remote_command_handler.rb', line 76

def mkdir(path)
  e = "mkdir #{path}"
  remote_execute(e, nil, true)
end

#mount(device, path) ⇒ Object



81
82
83
84
# File 'lib/help/remote_command_handler.rb', line 81

def mount(device, path)
  e = "mount #{device} #{path}"
  remote_execute(e, nil, true)
end

#remote_execute(exec_string, push_data = nil, raise_exception = false) ⇒ Object

Executes the specified #exec_string on a remote session specified. When #push_data is specified, the data will be used as input for the command and thus allow to respond in advance to commands that ask the user something. The method will return true if nothing was written into stderr, otherwise false. When #raise_exception is set, an exception will be raised instead of returning false.

Raises:

  • (Exception)


180
181
182
183
184
185
186
187
188
189
190
# File 'lib/help/remote_command_handler.rb', line 180

def remote_execute(exec_string, push_data = nil, raise_exception = false)
  #XXX: command line: echo -e 'y' | mkfs -t ext3 /dev/sdf
  exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
  stdout = []
  stderr = []
  result = remote_exec_helper(exec_string, stdout, stderr)
  em = "RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}"
  @logger.info(em) unless stderr.size == 0
  raise Exception.new(em) unless result == true || raise_exception == false
  result
end

#remote_rsync(keyfile, source_path, dest_ip, dest_path) ⇒ Object

Copy directory via an ssh-tunnel.



138
139
140
141
142
# File 'lib/help/remote_command_handler.rb', line 138

def remote_rsync(keyfile, source_path, dest_ip, dest_path)
  e = "rsync -rlpgoDzq -e "+'"'+"ssh -o stricthostkeychecking=no -i #{keyfile}"+'"'+" #{source_path} root@#{dest_ip}:#{dest_path}"
  @logger.debug "going to execute #{e}"
  remote_exec_helper(e, nil, nil, false) #TODO: handle output in stderr?
end

#retrieve_osObject

Returns the result of uname -a (Linux)



46
47
48
# File 'lib/help/remote_command_handler.rb', line 46

def retrieve_os()
  get_output("uname -r").strip
end

#scp(keyfile, source_path, dest_ip, dest_path) ⇒ Object

Copy directory via an ssh-tunnel.



145
146
147
148
149
# File 'lib/help/remote_command_handler.rb', line 145

def scp(keyfile, source_path, dest_ip, dest_path)
  e = "scp -Cpqr -o stricthostkeychecking=no -i #{keyfile} #{source_path} root@#{dest_ip}:#{dest_path}"
  @logger.debug "going to execute #{e}"
  remote_exec_helper(e, nil, nil, false) #TODO: handle output in stderr?
end

#stdout_contains?(exec_string, search_string = "", push_data = nil) ⇒ Boolean

Executes the specified #exec_string on a remote session specified as #ssh_session and logs the command-output into the specified #logger. When #push_data is specified, the data will be used as input for the command and thus allows to respond in advance to commands that ask the user something. If the output in stdout contains the specified #search_string, the method returns true otherwise false. Output to stderr will be logged.

Returns:

  • (Boolean)


198
199
200
201
202
203
204
205
# File 'lib/help/remote_command_handler.rb', line 198

def stdout_contains?(exec_string, search_string = "", push_data = nil)
  exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
  stdout = []
  stderr = []
  remote_exec_helper(exec_string, stdout, stderr)
  @logger.info("RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}") unless stderr.size == 0
  stdout.join().include?(search_string)
end

#tools_installed?(software_package) ⇒ Boolean

Checks if the software package specified is installed.

Returns:

  • (Boolean)


63
64
65
66
67
68
69
# File 'lib/help/remote_command_handler.rb', line 63

def tools_installed?(software_package)
  exec_string = "which #{software_package}"
  stdout = []
  stderr = []
  result = remote_exec_helper(exec_string, stdout, stderr)
  return result == true && stdout.size > 0
end

#umount(path) ⇒ Object

Unmount the specified path.



105
106
107
108
109
# File 'lib/help/remote_command_handler.rb', line 105

def umount(path)
  exec_string = "umount #{path}"
  remote_execute(exec_string)
  !drive_mounted?(path)
end

#upload(ip, user, key_data, local_file, destination_file, timeout = 60) ⇒ Object



220
221
222
223
224
225
226
# File 'lib/help/remote_command_handler.rb', line 220

def upload(ip, user, key_data, local_file, destination_file, timeout = 60)
  Timeout::timeout(timeout) {
    Net::SCP.start(ip, user, {:key_data => [key_data], :timeout => timeout}) do |scp|
      scp.upload!(local_file, destination_file)
    end
  }
end

#zip(source_path, destination_file) ⇒ Object

Zip the complete contents of the source path into the destination file. Returns the an array with stderr output messages.



153
154
155
156
157
158
159
160
161
162
# File 'lib/help/remote_command_handler.rb', line 153

def zip(source_path, destination_file)
  begin
    exec = "cd #{source_path}; zip -ryq #{destination_file} *"
    stderr = []
    get_output(exec, nil, nil, stderr)
    return stderr
  rescue Exception => e
    raise Exception.new("zip failed due to #{e.message}")
  end
end