CloudyScripts 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,54 +1,54 @@
1
- require "AWS"
2
-
3
- # Implements some helper methods around the EC2 API and methods that are
4
- # not yet implemented in the amazon-ec2 gem
5
-
6
- class AWS::EC2::Base
7
- def describe_instance_attribute(options)
8
- params = {}
9
- params["InstanceId"] = options[:instance_id].to_s
10
- params["Attribute"] = "rootDeviceName" unless options[:attributes][:rootDeviceName] == nil
11
- return response_generator(:action => "DescribeInstanceAttribute", :params => params)
12
- end
13
- end
14
-
15
- class Ec2Helper
16
- # expects an instance of AWS::EC2::Base from the amazon-ec2 gem
17
- def initialize(ec2_api)
18
- @ec2_api = ec2_api
19
- end
20
-
21
- # Checks if the specified volume is acting as a root-device for the instance
22
- # to which it is attached. It therefore first calls ec2_describe_volumes() to
23
- # retrieve the instance linked to the volume specified, then calls
24
- # ec2_describe_instance_attribute() to retrieve the rootDeviceName of that
25
- # instance, and finally calls describe_instances() to retrieve all volumes
26
- # to check against volume_id and rootDeviceName.
27
- def is_root_device?(volume_id)
28
- vols = @ec2_api.describe_volumes(:volume_id => volume_id)
29
- if vols['volumeSet']['item'][0]['attachmentSet'] == nil || vols['volumeSet']['item'][0]['attachmentSet']['item'].size == 0
30
- #not linked to any instance, cannot be a root-device
31
- return false
32
- end
33
- instance_id = vols['volumeSet']['item'][0]['attachmentSet']['item'][0]['instanceId']
34
- res = @ec2_api.describe_instance_attribute(:instance_id => instance_id, :attributes => {:rootDeviceName => true})
35
- if res["rootDeviceName"] == nil
36
- return false
37
- end
38
- rdn = res['rootDeviceName']['value']
39
- res = @ec2_api.describe_instances(:instance_id => instance_id)
40
- if res['reservationSet']['item'][0]['instancesSet']['item'][0]['blockDeviceMapping']['item'].size == 0
41
- # volume unattached in the meantime
42
- return false
43
- end
44
- attached = res['reservationSet']['item'][0]['instancesSet']['item'][0]['blockDeviceMapping']['item']
45
- attached.each() {|ebs|
46
- volume = ebs['ebs']['volumeId']
47
- device_name = ebs['deviceName']
48
- if volume == volume_id && rdn == device_name
49
- return true
50
- end
51
- }
52
- return false
53
- end
54
- end
1
+ require "AWS"
2
+
3
+ # Implements some helper methods around the EC2 API and methods that are
4
+ # not yet implemented in the amazon-ec2 gem
5
+
6
+ class AWS::EC2::Base
7
+ def describe_instance_attribute(options)
8
+ params = {}
9
+ params["InstanceId"] = options[:instance_id].to_s
10
+ params["Attribute"] = "rootDeviceName" unless options[:attributes][:rootDeviceName] == nil
11
+ return response_generator(:action => "DescribeInstanceAttribute", :params => params)
12
+ end
13
+ end
14
+
15
+ class Ec2Helper
16
+ # expects an instance of AWS::EC2::Base from the amazon-ec2 gem
17
+ def initialize(ec2_api)
18
+ @ec2_api = ec2_api
19
+ end
20
+
21
+ # Checks if the specified volume is acting as a root-device for the instance
22
+ # to which it is attached. It therefore first calls ec2_describe_volumes() to
23
+ # retrieve the instance linked to the volume specified, then calls
24
+ # ec2_describe_instance_attribute() to retrieve the rootDeviceName of that
25
+ # instance, and finally calls describe_instances() to retrieve all volumes
26
+ # to check against volume_id and rootDeviceName.
27
+ def is_root_device?(volume_id)
28
+ vols = @ec2_api.describe_volumes(:volume_id => volume_id)
29
+ if vols['volumeSet']['item'][0]['attachmentSet'] == nil || vols['volumeSet']['item'][0]['attachmentSet']['item'].size == 0
30
+ #not linked to any instance, cannot be a root-device
31
+ return false
32
+ end
33
+ instance_id = vols['volumeSet']['item'][0]['attachmentSet']['item'][0]['instanceId']
34
+ res = @ec2_api.describe_instance_attribute(:instance_id => instance_id, :attributes => {:rootDeviceName => true})
35
+ if res["rootDeviceName"] == nil
36
+ return false
37
+ end
38
+ rdn = res['rootDeviceName']['value']
39
+ res = @ec2_api.describe_instances(:instance_id => instance_id)
40
+ if res['reservationSet']['item'][0]['instancesSet']['item'][0]['blockDeviceMapping']['item'].size == 0
41
+ # volume unattached in the meantime
42
+ return false
43
+ end
44
+ attached = res['reservationSet']['item'][0]['instancesSet']['item'][0]['blockDeviceMapping']['item']
45
+ attached.each() {|ebs|
46
+ volume = ebs['ebs']['volumeId']
47
+ device_name = ebs['deviceName']
48
+ if volume == volume_id && rdn == device_name
49
+ return true
50
+ end
51
+ }
52
+ return false
53
+ end
54
+ end
@@ -1,190 +1,203 @@
1
- require 'rubygems'
2
- require 'net/ssh'
3
-
4
- # Provides methods to be executed via ssh to remote instances.
5
- class RemoteCommandHandler
6
- attr_accessor :logger, :ssh_session
7
- def initialize
8
- @logger = Logger.new(STDOUT)
9
- end
10
-
11
- # Connect to the machine as root using a keyfile.
12
- # Params:
13
- # * ip: ip address of the machine to connect to
14
- # * keyfile: path of the keyfile to be used for authentication
15
- def connect_with_keyfile(ip, keyfile)
16
- @ssh_session = Net::SSH.start(ip, 'root', :keys => [keyfile])
17
- end
18
-
19
- # Connect to the machine as root using keydata from a keyfile.
20
- # Params:
21
- # * ip: ip address of the machine to connect to
22
- # * user: user name
23
- # * key_data: key_data to be used for authentication
24
- def connect(ip, user, key_data)
25
- @ssh_session = Net::SSH.start(ip, user, :key_data => [key_data])
26
- end
27
-
28
- # Disconnect the current handler
29
- def disconnect
30
- @ssh_session.close
31
- end
32
-
33
- # Check if the path/file specified exists
34
- def file_exists?(path)
35
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, "ls #{path}")
36
- end
37
-
38
- # Returns the result of uname -a (Linux)
39
- def retrieve_os()
40
- RemoteCommandHandler.get_output(@ssh_session, "uname -r").strip
41
- end
42
-
43
- # Installs the software package specified.
44
- def install(software_package)
45
- e = "yum -yq install #{software_package}; apt-get -yq install #{software_package}"
46
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e)
47
- end
48
-
49
- # Checks if the software package specified is installed.
50
- def tools_installed?(software_package)
51
- e = "which #{software_package}"
52
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e)
53
- end
54
-
55
- def create_filesystem(fs_type, volume)
56
- e = "mkfs -t #{fs_type} #{volume}"
57
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e, "y") #TODO: quiet mode?
58
- end
59
-
60
- def mkdir(path)
61
- e = "mkdir #{path}"
62
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e, nil, true)
63
- end
64
-
65
- def mount(device, path)
66
- e = "mount #{device} #{path}"
67
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e, nil, true)
68
- end
69
-
70
- # Checks if the drive on path is mounted
71
- def drive_mounted?(path)
72
- #check if drive mounted
73
- drive_found = RemoteCommandHandler.stdout_contains?(@ssh_session, @logger, "mount", "on #{path} type")
74
- if drive_found
75
- return file_exists?(path)
76
- else
77
- @logger.debug "not mounted (since #{path} non-existing)"
78
- false
79
- end
80
- end
81
-
82
- # Checks if the drive on path is mounted with the specific device
83
- def drive_mounted_as?(device, path)
84
- #check if drive mounted
85
- RemoteCommandHandler.stdout_contains?(@ssh_session, @logger, "mount", "#{device} on #{path} type")
86
- end
87
-
88
- # Unmount the specified path.
89
- def umount(path)
90
- exec_string = "umount #{path}"
91
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, exec_string)
92
- !drive_mounted?(path)
93
- end
94
-
95
- # Copy directory using options -avHx
96
- def rsync(source_path, dest_path)
97
- e = "rsync -avHx #{source_path} #{dest_path}"
98
- RemoteCommandHandler.remote_execute(@ssh_session, @logger, e, nil, true)
99
- end
100
-
101
- # Executes the specified #exec_string on a remote session specified as #ssh_session
102
- # and logs the command-output into the specified #logger. When #push_data is
103
- # specified, the data will be used as input for the command and thus allows
104
- # to respond in advance to commands that ask the user something.
105
- # The method will return true if nothing was written into stderr, otherwise false.
106
- # When #raise_exception is set, an exception will be raised instead of
107
- # returning false.
108
- def self.remote_execute(ssh_session, logger, exec_string, push_data = nil, raise_exception = false)
109
- exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
110
- stdout = []
111
- stderr = []
112
- result = remote_exec_helper(ssh_session, exec_string, stdout, stderr, logger)
113
- em = "RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}"
114
- logger.info(em) unless stderr.size == 0
115
- raise Exception.new(em) unless result == true || raise_exception == false
116
- result
117
- end
118
-
119
- # Executes the specified #exec_string on a remote session specified as #ssh_session
120
- # and logs the command-output into the specified #logger. When #push_data is
121
- # specified, the data will be used as input for the command and thus allows
122
- # to respond in advance to commands that ask the user something. If the output
123
- # in stdout contains the specified #search_string, the method returns true
124
- # otherwise false. Output to stderr will be logged.
125
- def self.stdout_contains?(ssh_session, logger, exec_string, search_string = "", push_data = nil)
126
- exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
127
- stdout = []
128
- stderr = []
129
- remote_exec_helper(ssh_session, exec_string, stdout, stderr, logger)
130
- logger.info("RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}") unless stderr.size == 0
131
- stdout.join().include?(search_string)
132
- end
133
-
134
- # Executes the specified #exec_string on a remote session specified as #ssh_session.
135
- # When #push_data is specified, the data will be used as input for the command and thus allows
136
- # to respond in advance to commands that ask the user something. It returns
137
- # stdout. When #stdout or #stderr is specified as arrays, the respective output is
138
- # also written into those arrays.
139
- def self.get_output(ssh_session, exec_string, push_data = nil, stdout = [], stderr = [])
140
- exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
141
- stdout = []
142
- stderr = []
143
- remote_exec_helper(ssh_session, exec_string, stdout, stderr)
144
- stdout.join()
145
- end
146
-
147
- private
148
-
149
- # Executes the specified #exec_string on a remote session specified as #ssh_session
150
- # and logs the command-output into the specified #logger.
151
- # The method will return true if nothing was written into stderr, otherwise false.
152
- # All stdout-data is written into #stdout, all stderr-data is written into #stderr
153
- def self.remote_exec_helper(ssh_session, exec_string, stdout = [], stderr = [], logger = nil, debug = false)
154
- result = true
155
- the_channel = ssh_session.open_channel do |channel|
156
- channel.exec(exec_string) do |ch, success|
157
- if success
158
- logger.debug("RemoteCommandHandler: starts executing #{exec_string}") if logger != nil && debug
159
- ch.on_data() do |ch, data|
160
- stdout << data unless data == nil
161
- end
162
- ch.on_extended_data do |ch, type, data|
163
- stderr << data unless data == nil
164
- result = false
165
- end
166
- ch.on_eof do |ch|
167
- logger.debug("RemoteCommandHandler.on_eof:remote end is done sending data") if logger != nil && debug
168
- end
169
- ch.on_close do |ch|
170
- logger.debug("RemoteCommandHandler.on_close:remote end is closing!") if logger != nil && debug
171
- end
172
- ch.on_open_failed do |ch, code, desc|
173
- logger.debug("RemoteCommandHandler.on_open_failed: code=#{code} desc=#{desc}") if logger != nil && debug
174
- end
175
- ch.on_process do |ch|
176
- logger.debug("RemoteCommandHandler.on_process; send line-feed/sleep") if logger != nil && debug
177
- sleep(1)
178
- ch.send_data("\n")
179
- end
180
- else
181
- stderr << "the remote command could not be invoked!"
182
- result = false
183
- end
184
- end
185
- end
186
- the_channel.wait
187
- result
188
- end
189
-
190
- end
1
+ require 'rubygems'
2
+ require 'net/ssh'
3
+
4
+ # Provides methods to be executed via ssh to remote instances.
5
+ class RemoteCommandHandler
6
+ attr_accessor :logger, :ssh_session
7
+ def initialize
8
+ @logger = Logger.new(STDOUT)
9
+ end
10
+
11
+ # Connect to the machine as root using a keyfile.
12
+ # Params:
13
+ # * ip: ip address of the machine to connect to
14
+ # * keyfile: path of the keyfile to be used for authentication
15
+ def connect_with_keyfile(ip, keyfile)
16
+ @ssh_session = Net::SSH.start(ip, 'root', :keys => [keyfile])
17
+ end
18
+
19
+ # Connect to the machine as root using keydata from a keyfile.
20
+ # Params:
21
+ # * ip: ip address of the machine to connect to
22
+ # * user: user name
23
+ # * key_data: key_data to be used for authentication
24
+ def connect(ip, user, key_data)
25
+ @ssh_session = Net::SSH.start(ip, user, :key_data => [key_data])
26
+ end
27
+
28
+ # Disconnect the current handler
29
+ def disconnect
30
+ @ssh_session.close
31
+ end
32
+
33
+ # Check if the path/file specified exists
34
+ def file_exists?(path)
35
+ remote_execute("ls #{path}")
36
+ end
37
+
38
+ # Returns the result of uname -a (Linux)
39
+ def retrieve_os()
40
+ get_output("uname -r").strip
41
+ end
42
+
43
+ # Installs the software package specified.
44
+ def install(software_package)
45
+ e = "yum -yq install #{software_package}"
46
+ yum = remote_execute(e)
47
+ if !yum
48
+ @logger.info("yum installation failed; try apt-get")
49
+ e = "apt-get -yq install #{software_package}"
50
+ apt = remote_execute(e)
51
+ @logger.info("apt=get installation? #{apt}")
52
+ end
53
+ end
54
+
55
+ # Checks if the software package specified is installed.
56
+ def tools_installed?(software_package)
57
+ exec_string = "which #{software_package}"
58
+ stdout = []
59
+ stderr = []
60
+ result = remote_exec_helper(exec_string, stdout, stderr)
61
+ return result == true && stdout.size > 0
62
+ end
63
+
64
+ def create_filesystem(fs_type, volume)
65
+ e = "mkfs -t #{fs_type} #{volume}"
66
+ remote_execute(e, "y") #TODO: quiet mode?
67
+ end
68
+
69
+ def mkdir(path)
70
+ e = "mkdir #{path}"
71
+ remote_execute(e, nil, true)
72
+ end
73
+
74
+ def mount(device, path)
75
+ e = "mount #{device} #{path}"
76
+ remote_execute(e, nil, true)
77
+ end
78
+
79
+ # Checks if the drive on path is mounted
80
+ def drive_mounted?(path)
81
+ #check if drive mounted
82
+ drive_found = stdout_contains?("mount", "on #{path} type")
83
+ if drive_found
84
+ return file_exists?(path)
85
+ else
86
+ @logger.debug "not mounted (since #{path} non-existing)"
87
+ false
88
+ end
89
+ end
90
+
91
+ # Checks if the drive on path is mounted with the specific device
92
+ def drive_mounted_as?(device, path)
93
+ #check if drive mounted
94
+ stdout_contains?("mount", "#{device} on #{path} type")
95
+ end
96
+
97
+ # Unmount the specified path.
98
+ def umount(path)
99
+ exec_string = "umount #{path}"
100
+ remote_execute(exec_string)
101
+ !drive_mounted?(path)
102
+ end
103
+
104
+ # Copy directory using options -avHx
105
+ def rsync(source_path, dest_path, exclude_path = nil)
106
+ exclude = ""
107
+ if exclude_path != nil
108
+ exclude = "--exclude #{exclude_path}"
109
+ end
110
+ e = "rsync -avHx #{exclude} #{source_path} #{dest_path}"
111
+ @logger.debug "going to execute #{e}"
112
+ remote_exec_helper(e, nil, nil, false)
113
+ end
114
+
115
+ # Executes the specified #exec_string on a remote session specified.
116
+ # When #push_data is specified, the data will be used as input for the
117
+ # command and thus allow to respond in advance to commands that ask the user
118
+ # something.
119
+ # The method will return true if nothing was written into stderr, otherwise false.
120
+ # When #raise_exception is set, an exception will be raised instead of
121
+ # returning false.
122
+ def remote_execute(exec_string, push_data = nil, raise_exception = false)
123
+ exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
124
+ stdout = []
125
+ stderr = []
126
+ result = remote_exec_helper(exec_string, stdout, stderr)
127
+ em = "RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}"
128
+ @logger.info(em) unless stderr.size == 0
129
+ raise Exception.new(em) unless result == true || raise_exception == false
130
+ result
131
+ end
132
+
133
+ # Executes the specified #exec_string on a remote session specified as #ssh_session
134
+ # and logs the command-output into the specified #logger. When #push_data is
135
+ # specified, the data will be used as input for the command and thus allows
136
+ # to respond in advance to commands that ask the user something. If the output
137
+ # in stdout contains the specified #search_string, the method returns true
138
+ # otherwise false. Output to stderr will be logged.
139
+ def stdout_contains?(exec_string, search_string = "", push_data = nil)
140
+ exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
141
+ stdout = []
142
+ stderr = []
143
+ remote_exec_helper(exec_string, stdout, stderr)
144
+ @logger.info("RemoteCommandHandler: #{exec_string} lead to stderr message: #{stderr.join().strip}") unless stderr.size == 0
145
+ stdout.join().include?(search_string)
146
+ end
147
+
148
+ # Executes the specified #exec_string on a remote session specified as #ssh_session.
149
+ # When #push_data is specified, the data will be used as input for the command and thus allows
150
+ # to respond in advance to commands that ask the user something. It returns
151
+ # stdout. When #stdout or #stderr is specified as arrays, the respective output is
152
+ # also written into those arrays.
153
+ def get_output(exec_string, push_data = nil, stdout = [], stderr = [])
154
+ exec_string = "echo #{push_data} >tmp.txt; #{exec_string} <tmp.txt; rm -f tmp.txt" unless push_data == nil
155
+ stdout = []
156
+ stderr = []
157
+ remote_exec_helper(exec_string, stdout, stderr)
158
+ stdout.join()
159
+ end
160
+
161
+ private
162
+
163
+ # Executes the specified #exec_string on the opened remote session.
164
+ # The method will return true if nothing was written into stderr, otherwise false.
165
+ # All stdout-data is written into #stdout, all stderr-data is written into #stderr
166
+ def remote_exec_helper(exec_string, stdout = [], stderr = [], debug = false)
167
+ result = true
168
+ the_channel = @ssh_session.open_channel do |channel|
169
+ channel.exec(exec_string) do |ch, success|
170
+ if success
171
+ @logger.debug("RemoteCommandHandler: starts executing #{exec_string}") if debug
172
+ ch.on_data() do |ch, data|
173
+ stdout << data unless data == nil || stdout == nil
174
+ end
175
+ ch.on_extended_data do |ch, type, data|
176
+ stderr << data unless data == nil || stderr == nil
177
+ result = false
178
+ end
179
+ ch.on_eof do |ch|
180
+ @logger.debug("RemoteCommandHandler.on_eof:remote end is done sending data") if debug
181
+ end
182
+ ch.on_close do |ch|
183
+ @logger.debug("RemoteCommandHandler.on_close:remote end is closing!") if debug
184
+ end
185
+ ch.on_open_failed do |ch, code, desc|
186
+ @logger.debug("RemoteCommandHandler.on_open_failed: code=#{code} desc=#{desc}") if debug
187
+ end
188
+ ch.on_process do |ch|
189
+ @logger.debug("RemoteCommandHandler.on_process; send line-feed/sleep") if debug
190
+ sleep(1)
191
+ ch.send_data("\n")
192
+ end
193
+ else
194
+ stderr << "the remote command could not be invoked!" unless stderr == nil
195
+ result = false
196
+ end
197
+ end
198
+ end
199
+ the_channel.wait
200
+ result
201
+ end
202
+
203
+ end