svengali 0.2.7.2

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.
Files changed (63) hide show
  1. data/LICENSE +20 -0
  2. data/README +0 -0
  3. data/README.rdoc +17 -0
  4. data/Rakefile +47 -0
  5. data/VERSION +1 -0
  6. data/api_document020_en.pdf +0 -0
  7. data/api_document020_ja.pdf +0 -0
  8. data/api_document_en.pptx +0 -0
  9. data/api_document_ja.pptx +0 -0
  10. data/lib/svengali.rb +2 -0
  11. data/lib/svengali/config.rb +78 -0
  12. data/lib/svengali/ext_string.rb +55 -0
  13. data/lib/svengali/ext_string/command.yml +6 -0
  14. data/lib/svengali/ext_string/path.yml +6 -0
  15. data/lib/svengali/file_io.rb +106 -0
  16. data/lib/svengali/machine.rb +123 -0
  17. data/lib/svengali/platforms/debian.rb +5 -0
  18. data/lib/svengali/platforms/default.rb +4 -0
  19. data/lib/svengali/plugins/eucalyptus.rb +339 -0
  20. data/lib/svengali/plugins/machine_config.rb +126 -0
  21. data/lib/svengali/plugins/package.rb +7 -0
  22. data/lib/svengali/ssh.rb +106 -0
  23. data/lib/svengali/svengali.rb +19 -0
  24. data/lib/svengali/util.rb +117 -0
  25. data/rdoc/classes/CLibIPAddr.html +230 -0
  26. data/rdoc/classes/Cloud.html +506 -0
  27. data/rdoc/classes/Config.html +151 -0
  28. data/rdoc/classes/Config/ConfigFile.html +319 -0
  29. data/rdoc/classes/ExtStr.html +209 -0
  30. data/rdoc/classes/ExtStrAccessor.html +183 -0
  31. data/rdoc/classes/FileIO.html +415 -0
  32. data/rdoc/classes/Machine.html +771 -0
  33. data/rdoc/classes/MachineMaster.html +117 -0
  34. data/rdoc/classes/Platform.html +121 -0
  35. data/rdoc/classes/SSH.html +315 -0
  36. data/rdoc/created.rid +1 -0
  37. data/rdoc/files/README.html +101 -0
  38. data/rdoc/files/README_rdoc.html +133 -0
  39. data/rdoc/files/lib/svengali/config_rb.html +114 -0
  40. data/rdoc/files/lib/svengali/ext_string_rb.html +108 -0
  41. data/rdoc/files/lib/svengali/file_io_rb.html +115 -0
  42. data/rdoc/files/lib/svengali/machine_rb.html +108 -0
  43. data/rdoc/files/lib/svengali/platforms/debian_rb.html +107 -0
  44. data/rdoc/files/lib/svengali/platforms/default_rb.html +107 -0
  45. data/rdoc/files/lib/svengali/plugins/eucalyptus_rb.html +389 -0
  46. data/rdoc/files/lib/svengali/plugins/machine_config_rb.html +101 -0
  47. data/rdoc/files/lib/svengali/plugins/package_rb.html +101 -0
  48. data/rdoc/files/lib/svengali/ssh_rb.html +110 -0
  49. data/rdoc/files/lib/svengali/svengali_rb.html +125 -0
  50. data/rdoc/files/lib/svengali/util_rb.html +439 -0
  51. data/rdoc/files/lib/svengali_rb.html +108 -0
  52. data/rdoc/fr_class_index.html +37 -0
  53. data/rdoc/fr_file_index.html +41 -0
  54. data/rdoc/fr_method_index.html +100 -0
  55. data/rdoc/index.html +26 -0
  56. data/rdoc/rdoc-style.css +208 -0
  57. data/spec/spec.opts +1 -0
  58. data/spec/spec_helper.rb +9 -0
  59. data/spec/svengali_spec.rb +7 -0
  60. data/svengali.gemspec +113 -0
  61. data/svengali_sample.rb +43 -0
  62. data/test/scenario.sh +3 -0
  63. metadata +179 -0
@@ -0,0 +1,5 @@
1
+ #Debian
2
+
3
+ class Platform
4
+
5
+ end
@@ -0,0 +1,4 @@
1
+ #defualt platform: CentOS
2
+ class Platform
3
+
4
+ end
@@ -0,0 +1,339 @@
1
+ require 'timeout'
2
+ require "yaml"
3
+
4
+ # return -> symbol : one of values below
5
+ # :running, :pending, :shutdown, :terminated
6
+ def get_instance_state(instance_id_str)
7
+ exec_result = ""
8
+ while exec_result == ""
9
+ exec_result = `euca-describe-instances #{instance_id_str}`
10
+ end
11
+
12
+ if exec_result.index("pending")
13
+ return :pending
14
+ elsif exec_result.index("running")
15
+ return :running
16
+ elsif exec_result.index("shutting-down")
17
+ return :shutdown
18
+ elsif exec_result.index("terminated")
19
+ return :terminated
20
+ end
21
+ end
22
+
23
+ # return -> string: id of running instance
24
+ # this function..
25
+ # blocks until kicked image starts running
26
+ # uses c1.medium machine spec
27
+ def run_image(image_id_str)
28
+ begin
29
+ debug_p "trying kick instance from image #{image_id_str}"
30
+ instance_id = `euca-run-instances #{image_id_str} -t c1.medium`.scan(/\s+(i-\w+)\s+/)[0].to_s
31
+ rescue
32
+ debug_p "retry!"
33
+ retry
34
+ end
35
+
36
+ # waits until instance finishes booting
37
+ while(get_instance_state(instance_id) != :running)
38
+ end
39
+
40
+ debug_p "instance( #{instance_id} ) has been running successfully."
41
+
42
+ return instance_id
43
+ end
44
+
45
+ # this method blocks until the instance finishs terminating
46
+ def terminate_instance(instance_id_str)
47
+ `euca-terminate-instances #{instance_id_str}`
48
+
49
+ while(get_instance_state(instance_id_str) != :terminated)
50
+ end
51
+
52
+ debug_p "instance( #{instance_id_str} ) has been terminated successfully."
53
+ end
54
+
55
+ # this method blocks until the instance finishs terminating
56
+ def terminate_instance_all()
57
+ instance_id_arr = get_all_instance_id()
58
+
59
+ instance_id_arr.each{ |instance_id|
60
+ terminate_instance(instance_id)
61
+ }
62
+ end
63
+
64
+ # return -> array : like this
65
+ # ["i-xxxx","i-xxxx","i-xxxx",...]
66
+ def get_all_instance_id()
67
+ ret_arr = `euca-describe-instances`.scan(/\s+(i-\w+)\s+/)
68
+ debug_p ret_arr.inspect()
69
+ return ret_arr
70
+ end
71
+
72
+ # return -> string: image id
73
+ # when timeout, returns nil
74
+ def upload_and_register_image(image_path_str,timeout_sec = nil)
75
+ `euca-bundle-image -i #{image_path_str}`
76
+ dir_name = File::dirname(image_path_str)
77
+ if(dir_name == ".")
78
+ bucket_and_image_name = image_path_str.gsub("./","")
79
+ else
80
+ bucket_and_image_name = image_path_str.gsub(dir_name,"")
81
+ end
82
+
83
+ begin
84
+ timeout(timeout_sec) do
85
+ `euca-upload-bundle -b #{bucket_and_image_name} -m /tmp/#{bucket_and_image_name}.manifest.xml`
86
+ end
87
+ rescue TimeoutError
88
+ "Too long time elapsed to upload image file. It is highly possible that uploading is missed"
89
+ return nil
90
+ end
91
+
92
+ begin
93
+ image_id = `euca-register #{bucket_and_image_name}/#{bucket_and_image_name}.manifest.xml`.scan(/IMAGE\s+(emi\-\w+)\s*/)[0].to_s
94
+ rescue
95
+ debug_p "retry!"
96
+ retry
97
+ end
98
+
99
+ `rm -f /tmp/#{bucket_and_image_name}*`
100
+
101
+ debug_p "uploaded and registerd #{image_path_str}"
102
+ return image_id
103
+ end
104
+
105
+ # deregister specified image and delete images on server
106
+ def delete_image(image_id_str)
107
+ `euca-deregister #{image_id_str}`
108
+ bucket_and_image = get_bucket_and_image_name_by_id(image_id_str)
109
+
110
+ `euca-delete-bundle -b #{bucket_and_image[:bucket]} -p #{bucket_and_image[:image]} --clear`
111
+
112
+ debug_p "deregisterd and deleted #{image_id_str}"
113
+ end
114
+
115
+ # return -> {:bucket => string: name of bucket, :image => string: image name }
116
+ def get_bucket_and_image_name_by_id(image_id_str)
117
+ begin
118
+ bucket_and_image = `euca-describe-images #{image_id_str}`.scan(/^IMAGE\s+#{image_id_str}\s+(.+\.manifect\.xml)/)
119
+ rescue
120
+ debug_p "retry!"
121
+ retry
122
+ end
123
+
124
+ return {:bucket => bucket_and_image[0], :image => bucket_and_image[1]}
125
+ end
126
+ private :get_bucket_and_image_name_by_id
127
+
128
+ class Machine
129
+ @instance_id_str
130
+ @@do_cache = false
131
+
132
+ def set_instance_info(instance_id_str)
133
+ @instance_id_str = instance_id_str
134
+ end
135
+
136
+ # return -> string: ID of vm instance
137
+ def get_instance_info()
138
+ return @instance_id_str
139
+ end
140
+
141
+ def destroy_instance()
142
+ unless @instance_id_str
143
+ puts "set_cloud_info() should be called appropriately before destroying instance"
144
+ puts "exit destroy_instance() without terminating"
145
+ return
146
+ end
147
+
148
+ unless @@do_cache
149
+ terminate_instance(@instance_id_str)
150
+ end
151
+
152
+ end
153
+
154
+ # set whether cache and reuse guest instance on Eucalyptus
155
+ # if true value is set
156
+ # - destroy_instance(...) doesn't terminate instance
157
+ def set_whether_do_cache(true_or_false)
158
+ @@do_cache = true_or_false
159
+ end
160
+
161
+ end
162
+
163
+ class Cloud
164
+ # TODO: enabling lib to find newly booted node without pinging
165
+ DHCP_LEASE_RANGE = "xxx.xxx.xxx.xxx"
166
+
167
+ CACHE_FILE_NAME = "./machine_cache_hash.yml"
168
+
169
+ # whether cache and reuse guest instance on Eucalyptus
170
+ # default value is false
171
+ @@do_cache = false
172
+
173
+ @@default_user
174
+ @@default_pass
175
+
176
+ def self.Cloud(default_user,default_pass)
177
+ @@default_user = default_user
178
+ @@default_pass = default_pass
179
+ end
180
+
181
+ # return -> Machine : Machine instance applied network configuration and establised session
182
+ def self.get_a_machine_with_imageup(params_hash)
183
+ check_has_keys(params_hash,[:imagepath])
184
+
185
+ unless params_hash[:imageid] = upload_and_register_image(params_hash[image_path_str],120)
186
+ puts "uploading and registration of image failed"
187
+ err_message_and_exit("I wll exit")
188
+ end
189
+
190
+ not_tested()
191
+ return self.get_a_machine(params_hash)
192
+ end
193
+
194
+
195
+ # return -> Machine : Machine instance applied network configuration and establised session
196
+ def self.get_a_machine(params_hash)
197
+
198
+ # if @@do_cache true, Cloud class tries to reuse guest instance on Eucalyptus
199
+ # whether exist appropriate instace is checked in terms of IP address
200
+ if Cloud.is_exist_requested_machine(params_hash[:ipaddr]) && @@do_cache
201
+ debug_p "reused a guset instance which has address #{params_hash[:ipaddr]}"
202
+ # load instance ID corresponding to requested IP address from cache file
203
+ machine_cache_hash = Cloud.load_machine_cache_info()
204
+ instance_id = machine_cache_hash[params_hash[:ipaddr]]
205
+ else
206
+ # calling of this method isn't needed under normal conditions
207
+ get_ipaddr_of_instance_pre()
208
+
209
+ debug_p "executing euca-run-instance...."
210
+ # ** Attention ** below is draft code
211
+ instance_id = run_image(params_hash[:imageid])
212
+ debug_p "euca-run-instance finished."
213
+
214
+ #get a CLibIPAddr insance
215
+ ipaddr = get_ipaddr_of_instance(instance_id)
216
+ debug_p "IP address of the kicked instance: " + ipaddr.to_s
217
+
218
+ debug_p "configure network setting to the kicked instance."
219
+ vanilla_machine = Machine.new(ipaddr)
220
+ vanilla_machine.set_auth_info(DEFAULT_USER,DEFAULT_PASS)
221
+ vanilla_machine.establish_session()
222
+
223
+ vanilla_machine.config_nw_interface(:ipaddr => params_hash[:ipaddr], :interface => params_hash[:interface], :netmask => params_hash[:netmask], :gateway => params_hash[:gateway], :onboot => "yes")
224
+ vanilla_machine.set_resolver(:primary_ip => params_hash[:dns],:interface => params_hash[:interface])
225
+
226
+ #reloads network configuration
227
+ #10 seconds after, this will return with nil value
228
+ # TODO: should eliminate assumption for platform
229
+ debug_p "reload network configuration...."
230
+ puts vanilla_machine.exec!("/sbin/service network restart", 10)
231
+ debug_p "reloading of network configuration may have finished."
232
+
233
+ # write machine info to cache file
234
+ if @@do_cache
235
+ machine_cache_hash = Cloud.load_machine_cache_info()
236
+ debug_p "----------------loaded_hash------------------"
237
+ debug_p machine_cache_hash.inspect()
238
+ debug_p "class name of machine_cache_hash is #{machine_cache_hash.class}"
239
+ debug_p "---------------------------------------------"
240
+ machine_cache_hash[params_hash[:ipaddr]] = instance_id
241
+ Cloud.dump_machine_cache_info(machine_cache_hash)
242
+ end
243
+
244
+ end
245
+
246
+ configured_machine = Machine.new(params_hash[:ipaddr])
247
+ configured_machine.set_auth_info(DEFAULT_USER,DEFAULT_PASS)
248
+ configured_machine.establish_session()
249
+ configured_machine.set_instance_info(instance_id)
250
+
251
+ if @@do_cache
252
+ configured_machine.set_whether_do_cache(true)
253
+ end
254
+
255
+ return configured_machine
256
+ end
257
+
258
+ # ipaddr -> CLibIPAddr
259
+ # whether exist appropriate instace is checked in terms of IP address
260
+ def self.is_exist_requested_machine(ipaddr)
261
+ return is_exist_by_ping(ipaddr)
262
+ end
263
+
264
+ # ** Attention ** this is quick-fix implementation
265
+ # this method can't work on parallel kicking
266
+ #
267
+ # return -> CLibIPAddr : xxx
268
+ def self.get_ipaddr_of_instance(instance_id)
269
+ unless @@pre_alived_hash
270
+ err_message_and_exit("get_ipaddr_of_instance_pre() should be called on the eve of run_image(...)")
271
+ end
272
+
273
+ debug_p @@pre_alived_hash.inspect()
274
+
275
+ while(true)
276
+ alived_hash = find_machines_on_range_by_ping(DHCP_LEASE_RANGE)
277
+
278
+ # find difference
279
+ alived_hash.delete_if{ |key,value| @@pre_alived_hash.has_key?(key)}
280
+
281
+ if alived_hash.size == 1
282
+ debug_p alived_hash.inspect()
283
+ ret = alived_hash.shift()[0]
284
+ debug_p "found #{ret}"
285
+ return CLibIPAddr.new(ret)
286
+ elsif alived_hash.size > 1
287
+ err_message_and_exit("There may be other booting machine!")
288
+ end
289
+ sleep 1 #leave a space
290
+ end
291
+
292
+ end
293
+
294
+ # call of this method isn't needed under normal conditions
295
+ # this method should be called on the eve of run_image(...)
296
+ def self.get_ipaddr_of_instance_pre()
297
+ @@pre_alived_hash = find_machines_on_range_by_ping(DHCP_LEASE_RANGE)
298
+ end
299
+
300
+ # set whether cache and reuse guest instance on Eucalyptus
301
+ # if true value is set
302
+ # - get_a_machine(...) tries to reuse guest instance on Eucalyptus
303
+ # - destroy_instance(...) of Machine class doesn't terminate instance
304
+ # - write kicked machine info to cache file
305
+ def self.set_whether_do_cache(true_or_false)
306
+ @@do_cache = true_or_false
307
+ end
308
+
309
+ # machine_cache_hash -> hash : {"xxx.xxx.xxx.xxx" => "i-xxxxxxx", ... }
310
+ def self.dump_machine_cache_info(machine_cache_hash)
311
+ file = open(CACHE_FILE_NAME,"w")
312
+ YAML.dump(machine_cache_hash,file)
313
+ file.close()
314
+ end
315
+
316
+ # return -> hash: {"xxx.xxx.xxx.xxx" => "i-xxxxxxx", ... }
317
+ # if chache file doesn't exist, return a empty hash
318
+ def self.load_machine_cache_info()
319
+ if File.exist?(CACHE_FILE_NAME)
320
+ ret_hash = nil
321
+ open(CACHE_FILE_NAME){ |file|
322
+ ret_hash = YAML.load(file)
323
+ }
324
+
325
+ return ret_hash
326
+ else
327
+ return Hash.new()
328
+ end
329
+ end
330
+
331
+ end
332
+
333
+
334
+ # check source_certificate.sh has executed correctly
335
+ unless ENV["EC2_URL"]
336
+ puts "ERROR: please run command below before use this library with eucalyptus plugin!!\n \"source ./utility_scripts/source_certificate.sh\"\n"
337
+ exit()
338
+ end
339
+
@@ -0,0 +1,126 @@
1
+ class Machine
2
+
3
+ # :ipaddr -> CLibIPAddr : IP address which assigned to interface
4
+ # :interface -> string : interface name
5
+ # :netmask -> string : netmask
6
+ # :gateway -> CLibIPAddr : IP address of gateway
7
+ # :onboot -> string : yes or no (you can omit)
8
+ # :hwaddr -> string : MAC address (you can omit)
9
+ def config_nw_interface(params_hash)
10
+ config_file = nil
11
+ if interface_name_str = params_hash[:interface]
12
+ #open or create target file
13
+ target_path = ExtStr.path["network_configs"]+"ifcfg-" + interface_name_str
14
+ config_file = self.get_config_file(target_path)
15
+ else
16
+ err_message_and_exit("please specify a value of :interface!")
17
+ end
18
+
19
+ if netmask = params_hash[:netmask]
20
+ netmask_str = netmask.to_s()
21
+ # remove_col_by_regexp should be used under normal condition
22
+ config_file.remove_col_by_str("NETMASK")
23
+ config_file.append_str("NETMASK=" + netmask_str + "\n")
24
+ else
25
+ err_message_and_exit("please specify a value of :netmask!")
26
+ end
27
+
28
+ if ipaddr = params_hash[:ipaddr]
29
+ ipaddr_str = ipaddr.to_s()
30
+ # remove_col_by_regexp should be used under normal condition
31
+ config_file.remove_col_by_str("IPADDR")
32
+ config_file.append_str("IPADDR=" + ipaddr_str + "\n")
33
+ else
34
+ err_message_and_exit("please specify a value of :ipaddr!")
35
+ end
36
+
37
+ if gateway = params_hash[:gateway]
38
+ gateway_str = gateway.to_s()
39
+ # remove_col_by_regexp should be used under normal condition
40
+ config_file.remove_col_by_str("GATEWAY")
41
+ config_file.append_str("GATEWAY=" + gateway_str + "\n")
42
+ else
43
+ err_message_and_exit("please specify a value of :gateway!")
44
+ end
45
+
46
+ if hwaddr = params_hash[:hwaddr]
47
+ # remove_col_by_regexp should be used under normal condition
48
+ config_file.remove_col_by_str("HWADDR")
49
+ config_file.append_str("HWADDR=" + hwaddr + "\n")
50
+ end
51
+
52
+ onboot = params_hash[:onboot] || "yes" # default is "yes"
53
+ # remove_col_by_regexp should be used under normal condition
54
+ config_file.remove_col_by_str("ONBOOT")
55
+ config_file.append_str("ONBOOT=" + onboot + "\n")
56
+
57
+ config_file.remove_col_by_str("BOOTPROTO")
58
+ config_file.append_str("BOOTRPROTO=static\n")
59
+
60
+ config_file.save()
61
+ lazy_inp()
62
+ end
63
+
64
+ # !!!! Now, this method write resolver information !!!!
65
+ # !!!! to /etc/sysconfig/network-scripts/ifcfg-ethX !!!!
66
+ # !!!! due to baffling behavior of CentOS !!!!
67
+ #
68
+ # :primary_ip -> CLibIPAddr : IP address of primary DNS
69
+ # :secondry_ip -> CLibIPAddr : IP address of secondly DNS
70
+ # :search_domain -> string : domain of search directive
71
+ #
72
+ # :interface -> string : interface name (for CentOS)
73
+ def set_resolver(params_hash)
74
+ #open or create target file
75
+ config_file = nil
76
+ if interface_name_str = params_hash[:interface]
77
+ target_path = ExtStr.path["network_configs"]+"ifcfg-" + interface_name_str
78
+ config_file = self.get_config_file(target_path)
79
+ else
80
+ err_message_and_exit("please specify a value of :interface!")
81
+ end
82
+
83
+
84
+ # target_path = ExtStr.path["resolver_config"]
85
+ # config_file = self.get_config_file(target_path)
86
+ #
87
+ # if search_domain = params_hash[:search_domain]
88
+ # # remove_col_by_regexp should be used under normal condition
89
+ # config_file.append_str("search " + search_domain + "\n")
90
+ # end
91
+ #
92
+ # if primary_ip = params_hash[:primary_ip]
93
+ # primary_ip_str = primary_ip.to_s()
94
+ # # remove_col_by_regexp should be used under normal condition
95
+ # config_file.remove_col_by_str("nameserver")
96
+ # config_file.append_str("nameserver " + primary_ip_str + "\n")
97
+ # else
98
+ # err_message_and_exit("please specify a value of :primary_ip!")
99
+ # end
100
+ #
101
+ # if secondly_ip = params_hash[:secondly_ip]
102
+ # secondly_ip_str = secondly_ip.to_s()
103
+ # # remove_col_by_regexp should be used under normal condition
104
+ # config_file.append_str("nameserver " + secondly_ip_str + "\n")
105
+ # end
106
+
107
+
108
+ if primary_ip = params_hash[:primary_ip]
109
+ primary_ip_str = primary_ip.to_s()
110
+ # remove_col_by_regexp should be used under normal condition
111
+ config_file.remove_col_by_str("PEERDNS")
112
+ config_file.append_str("PEERDNS=yes\n")
113
+
114
+ config_file.remove_col_by_str("DNS1")
115
+ config_file.append_str("DNS1=" + primary_ip_str + "\n")
116
+ else
117
+ err_message_and_exit("please specify a value of :primary_ip!")
118
+ end
119
+
120
+ config_file.save()
121
+
122
+ lazy_inp()
123
+ end
124
+
125
+ end
126
+