tengine_resource 0.5.13

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 (100) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +30 -0
  4. data/Gemfile.lock +106 -0
  5. data/README.rdoc +20 -0
  6. data/Rakefile +42 -0
  7. data/VERSION +1 -0
  8. data/bin/tengine_resource_watchd +8 -0
  9. data/config/.gitignore +2 -0
  10. data/config/watchd.yml.erb.example +52 -0
  11. data/lib/tengine/resource.rb +29 -0
  12. data/lib/tengine/resource/config.rb +6 -0
  13. data/lib/tengine/resource/config/resource.rb +194 -0
  14. data/lib/tengine/resource/credential.rb +156 -0
  15. data/lib/tengine/resource/credential/ec2.rb +5 -0
  16. data/lib/tengine/resource/credential/ec2/dummy.rb +148 -0
  17. data/lib/tengine/resource/credential/ec2/launch_options.rb +179 -0
  18. data/lib/tengine/resource/drivers/resource_control_driver.rb +58 -0
  19. data/lib/tengine/resource/net_ssh.rb +134 -0
  20. data/lib/tengine/resource/observer.rb +25 -0
  21. data/lib/tengine/resource/physical_server.rb +7 -0
  22. data/lib/tengine/resource/provider.rb +82 -0
  23. data/lib/tengine/resource/provider/ec2.rb +187 -0
  24. data/lib/tengine/resource/provider/wakame.rb +615 -0
  25. data/lib/tengine/resource/server.rb +62 -0
  26. data/lib/tengine/resource/virtual_server.rb +62 -0
  27. data/lib/tengine/resource/virtual_server_image.rb +34 -0
  28. data/lib/tengine/resource/virtual_server_type.rb +21 -0
  29. data/lib/tengine/resource/watcher.rb +121 -0
  30. data/lib/tengine_resource.rb +4 -0
  31. data/spec/fixtures/goku_at_ec2_ap_northeast.rb +177 -0
  32. data/spec/mongoid.yml +35 -0
  33. data/spec/spec_helper.rb +40 -0
  34. data/spec/support/ec2.rb +129 -0
  35. data/spec/support/mongo_index_key_log.rb +91 -0
  36. data/spec/tengine/resource/bugfix/watcher_for_wakame_spec.rb +232 -0
  37. data/spec/tengine/resource/credential_spec.rb +205 -0
  38. data/spec/tengine/resource/drivers/resource_control_driver_spec.rb +84 -0
  39. data/spec/tengine/resource/net_ssh_spec.rb +148 -0
  40. data/spec/tengine/resource/physical_server_spec.rb +47 -0
  41. data/spec/tengine/resource/provider/ec2_spec.rb +473 -0
  42. data/spec/tengine/resource/provider/test_files/describe_host_nodes.json +22 -0
  43. data/spec/tengine/resource/provider/test_files/describe_images.json +23 -0
  44. data/spec/tengine/resource/provider/test_files/describe_instance_specs.json +23 -0
  45. data/spec/tengine/resource/provider/test_files/describe_instances.json +56 -0
  46. data/spec/tengine/resource/provider/test_files/run_instances.json +30 -0
  47. data/spec/tengine/resource/provider/test_files/terminate_instances.json +3 -0
  48. data/spec/tengine/resource/provider/wakame/00_describe_host_nodes_0_physical_servers.json +8 -0
  49. data/spec/tengine/resource/provider/wakame/01_describe_host_nodes_10_physical_servers.json +139 -0
  50. data/spec/tengine/resource/provider/wakame/02_describe_host_nodes_60_physical_servers.json +795 -0
  51. data/spec/tengine/resource/provider/wakame/10_describe_instances_0_virtual_servers.json +8 -0
  52. data/spec/tengine/resource/provider/wakame/11_describe_instances_10_virtual_servers.json +469 -0
  53. data/spec/tengine/resource/provider/wakame/12_describe_instances_after_run_instances.json +280 -0
  54. data/spec/tengine/resource/provider/wakame/13_describe_instances_after_terminate_instances.json +279 -0
  55. data/spec/tengine/resource/provider/wakame/20_describe_images_0_virtual_server_images.json +8 -0
  56. data/spec/tengine/resource/provider/wakame/21_describe_images_5_virtual_server_images.json +84 -0
  57. data/spec/tengine/resource/provider/wakame/22_describe_images_60_virtual_server_images.json +856 -0
  58. data/spec/tengine/resource/provider/wakame/30_describe_instance_specs_0_virtual_server_specs.json +8 -0
  59. data/spec/tengine/resource/provider/wakame/31_describe_instance_specs_4_virtual_server_specs.json +66 -0
  60. data/spec/tengine/resource/provider/wakame/40_run_instances_0_virtual_servers.json +1 -0
  61. data/spec/tengine/resource/provider/wakame/41_run_instances_1_virtual_servers.json +22 -0
  62. data/spec/tengine/resource/provider/wakame/42_run_instances_5_virtual_servers.json +106 -0
  63. data/spec/tengine/resource/provider/wakame/50_terminate_instances_0_virtual_servers.json +1 -0
  64. data/spec/tengine/resource/provider/wakame/51_terminate_instances_3_virtual_servers.json +5 -0
  65. data/spec/tengine/resource/provider/wakame/sync_physical_servers_spec.rb +114 -0
  66. data/spec/tengine/resource/provider/wakame/sync_virtual_server_images_spec.rb +116 -0
  67. data/spec/tengine/resource/provider/wakame/sync_virtual_server_types_spec.rb +116 -0
  68. data/spec/tengine/resource/provider/wakame/sync_virtual_servers_spec.rb +216 -0
  69. data/spec/tengine/resource/provider/wakame_api_spec.rb +319 -0
  70. data/spec/tengine/resource/provider/wakame_spec.rb +339 -0
  71. data/spec/tengine/resource/provider_spec.rb +252 -0
  72. data/spec/tengine/resource/server_spec.rb +195 -0
  73. data/spec/tengine/resource/test_files/.gitignore +6 -0
  74. data/spec/tengine/resource/test_files/00_describe_host_nodes_0_physical_servers.json +8 -0
  75. data/spec/tengine/resource/test_files/01_describe_host_nodes_10_physical_servers.json +139 -0
  76. data/spec/tengine/resource/test_files/02_describe_host_nodes_60_physical_servers.json +795 -0
  77. data/spec/tengine/resource/test_files/10_describe_instances_0_virtual_servers.json +8 -0
  78. data/spec/tengine/resource/test_files/11_describe_instances_10_virtual_servers.json +469 -0
  79. data/spec/tengine/resource/test_files/12_describe_instances_after_run_instances.json +280 -0
  80. data/spec/tengine/resource/test_files/13_describe_instances_after_terminate_instances.json +279 -0
  81. data/spec/tengine/resource/test_files/14_describe_instances_after_run_1_instance.json +55 -0
  82. data/spec/tengine/resource/test_files/20_describe_images_0_virtual_server_images.json +8 -0
  83. data/spec/tengine/resource/test_files/21_describe_images_5_virtual_server_images.json +84 -0
  84. data/spec/tengine/resource/test_files/22_describe_images_60_virtual_server_images.json +856 -0
  85. data/spec/tengine/resource/test_files/30_describe_instance_specs_0_virtual_server_specs.json +8 -0
  86. data/spec/tengine/resource/test_files/31_describe_instance_specs_4_virtual_server_specs.json +66 -0
  87. data/spec/tengine/resource/test_files/40_run_instances_0_virtual_servers.json +1 -0
  88. data/spec/tengine/resource/test_files/41_run_instances_1_virtual_servers.json +22 -0
  89. data/spec/tengine/resource/test_files/42_run_instances_5_virtual_servers.json +106 -0
  90. data/spec/tengine/resource/test_files/43_run_instances_1_virtual_servers_without_aws_availability_zone.json +22 -0
  91. data/spec/tengine/resource/test_files/50_terminate_instances_0_virtual_servers.json +1 -0
  92. data/spec/tengine/resource/test_files/51_terminate_instances_3_virtual_servers.json +5 -0
  93. data/spec/tengine/resource/virtual_server_image_spec.rb +94 -0
  94. data/spec/tengine/resource/virtual_server_spec.rb +116 -0
  95. data/spec/tengine/resource/virtual_server_type_spec.rb +4 -0
  96. data/spec/tengine/resource/watcher_spec.rb +1026 -0
  97. data/spec/tengine_resource_spec.rb +5 -0
  98. data/tengine_resource.gemspec +171 -0
  99. data/tmp/log/.gitignore +1 -0
  100. metadata +286 -0
@@ -0,0 +1,615 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tama'
3
+ require 'tengine/support/core_ext/hash/keys'
4
+
5
+ class Tengine::Resource::Provider::Wakame < Tengine::Resource::Provider::Ec2
6
+
7
+ attr_accessor :retry_on_error
8
+
9
+ # field :connection_settings, :type => Hash # 継承元のTengine::Resource::Provider::Ec2で定義されているので不要
10
+
11
+ PHYSICAL_SERVER_STATES = [:online, :offline].freeze
12
+
13
+ VIRTUAL_SERVER_STATES = [
14
+ :scheduling, :pending, :starting, :running,
15
+ :failingover, :shuttingdown, :terminated].freeze
16
+
17
+ def update_virtual_server_images
18
+ connect do |conn|
19
+ hashs = conn.describe_images.map do |hash|
20
+ {
21
+ :provided_id => hash.delete(:aws_id),
22
+ :provided_description => hash.delete(:aws_description),
23
+ }
24
+ end
25
+ update_virtual_server_images_by(hashs)
26
+ end
27
+ end
28
+
29
+ # @param [String] name Name template for created virtual servers
30
+ # @param [Tengine::Resource::VirtualServerImage] image virtual server image object
31
+ # @param [Tengine::Resource::VirtualServerType] type virtual server type object
32
+ # @param [Tengine::Resource::PhysicalServer] physical physical server object
33
+ # @param [String] description what this virtual server is
34
+ # @param [Numeric] count number of vortial servers to boot
35
+ # @return [Array<Tengine::Resource::VirtualServer>]
36
+ def create_virtual_servers(name, image, type, physical, description = "", count = 1, &block)
37
+ return super(
38
+ name,
39
+ image,
40
+ type,
41
+ physical.provided_id,
42
+ description,
43
+ count, # min
44
+ count, # max
45
+ [], # grouop id
46
+ self.properties['key_name'] || self.properties[:key_name],
47
+ "", # user data
48
+ nil, # kernel id
49
+ nil, # ramdisk id
50
+ &block
51
+ )
52
+ end
53
+
54
+ def terminate_virtual_servers servers
55
+ connect do |conn|
56
+ conn.terminate_instances(servers.map {|i| i.provided_id }).map do |hash|
57
+ serv = self.virtual_servers.where(:provided_id => hash[:aws_instance_id]).first
58
+ serv
59
+ end
60
+ end
61
+ end
62
+
63
+ def capacities
64
+ server_type_ids = virtual_server_types.map(&:provided_id)
65
+ server_type_to_cpu = virtual_server_types.inject({}) do |d, server_type|
66
+ d[server_type.provided_id] = server_type.cpu_cores
67
+ d
68
+ end
69
+ server_type_to_mem = virtual_server_types.inject({}) do |d, server_type|
70
+ d[server_type.provided_id] = server_type.memory_size
71
+ d
72
+ end
73
+ physical_servers.inject({}) do |result, physical_server|
74
+ if physical_server.status == 'online'
75
+ active_guests = physical_server.guest_servers.reject do |i|
76
+ i.status.to_s == "terminated" or
77
+ server_type_to_cpu[i.provided_type_id].nil? or
78
+ server_type_to_mem[i.provided_type_id].nil?
79
+ end
80
+ cpu_free = physical_server.cpu_cores - active_guests.map{|s| server_type_to_cpu[s.provided_type_id]}.sum
81
+ mem_free = physical_server.memory_size - active_guests.map{|s| server_type_to_mem[s.provided_type_id]}.sum
82
+ result[physical_server.provided_id] = server_type_ids.inject({}) do |dest, server_type_id|
83
+ dest[server_type_id] = [
84
+ cpu_free / server_type_to_cpu[server_type_id],
85
+ mem_free / server_type_to_mem[server_type_id]
86
+ ].min
87
+ dest
88
+ end
89
+ else
90
+ result[physical_server.provided_id] = server_type_ids.inject({}) do |dest, server_type_id|
91
+ dest[server_type_id] = 0; dest
92
+ end
93
+ end
94
+ result
95
+ end
96
+ end
97
+
98
+
99
+ # 仮想サーバタイプの監視
100
+ def virtual_server_type_watch
101
+ log_prefix = "#{self.class.name}#virtual_server_type_watch (provider:#{self.name}):"
102
+
103
+ # APIからの仮想サーバタイプ情報を取得
104
+ instance_specs = describe_instance_specs_for_api
105
+ Tengine.logger.debug "#{log_prefix} describe_instance_specs for api (wakame)"
106
+ Tengine.logger.debug "#{log_prefix} #{instance_specs.inspect}"
107
+
108
+ create_instance_specs = []
109
+ update_instance_specs = []
110
+ destroy_server_types = []
111
+
112
+ # 仮想イメージタイプの取得
113
+ self.reload
114
+ old_server_types = self.virtual_server_types
115
+ Tengine.logger.debug "#{log_prefix} virtual_server_types on provider (#{self.name})"
116
+ Tengine.logger.debug "#{log_prefix} #{old_server_types.inspect}"
117
+
118
+ old_server_types.each do |old_server_type|
119
+ instance_spec = instance_specs.detect do |instance_spec|
120
+ (instance_spec[:id] || instance_spec["id"]) == old_server_type.provided_id
121
+ end
122
+
123
+ if instance_spec
124
+ # APIで取得したサーバタイプと一致するものがあれば更新対象
125
+ Tengine.logger.debug "#{log_prefix} registed virtual_server_type % <update> (#{old_server_type.provided_id})"
126
+ update_instance_specs << instance_spec
127
+ else
128
+ # APIで取得したサーバタイプと一致するものがなければ削除対象
129
+ Tengine.logger.debug "#{log_prefix} removed virtual_server_type % <destroy> (#{old_server_type.provided_id})"
130
+ destroy_server_types << old_server_type
131
+ end
132
+ end
133
+ # APIで取得したサーバタイプがTengine上に存在しないものであれば登録対象
134
+ create_instance_specs = instance_specs - update_instance_specs
135
+ create_instance_specs.each do |spec|
136
+ Tengine.logger.debug "#{log_prefix} new virtual_server_type % <create> (#{spec['id']})"
137
+ end
138
+
139
+ # 更新
140
+ self.differential_update_virtual_server_type_hashs(update_instance_specs) unless update_instance_specs.empty?
141
+ # 登録
142
+ self.create_virtual_server_type_hashs(create_instance_specs) unless create_instance_specs.empty?
143
+ # 削除
144
+ destroy_server_types.each { |target| target.destroy }
145
+ end
146
+
147
+ # 物理サーバの監視
148
+ def physical_server_watch
149
+ log_prefix = "#{self.class.name}#physical_server_watch (provider:#{self.name}):"
150
+
151
+ # APIからの物理サーバ情報を取得
152
+ host_nodes = describe_host_nodes_for_api
153
+ Tengine.logger.debug "#{log_prefix} describe_host_nodes for api (wakame)"
154
+ Tengine.logger.debug "#{log_prefix} #{host_nodes.inspect}"
155
+
156
+ create_host_nodes = []
157
+ update_host_nodes = []
158
+ destroy_servers = []
159
+
160
+ # 物理サーバの取得
161
+ self.reload
162
+ old_servers = self.physical_servers
163
+ Tengine.logger.debug "#{log_prefix} physical_server on provider (#{self.name})"
164
+ Tengine.logger.debug "#{log_prefix} #{old_servers.inspect}"
165
+
166
+ old_servers.each do |old_server|
167
+ host_node = host_nodes.detect do |host_node|
168
+ (host_node[:id] || host_node["id"]) == old_server.provided_id
169
+ end
170
+
171
+ if host_node
172
+ Tengine.logger.debug "#{log_prefix} registed physical_server % <update> (#{old_server.provided_id})"
173
+ update_host_nodes << host_node
174
+ else
175
+ Tengine.logger.debug "#{log_prefix} removed physical_server % <destroy> (#{old_server.provided_id})"
176
+ destroy_servers << old_server
177
+ end
178
+ end
179
+ create_host_nodes = host_nodes - update_host_nodes
180
+ create_host_nodes.each do |host_node|
181
+ Tengine.logger.debug "#{log_prefix} new physical_server% <create> (#{host_node['id']})"
182
+ end
183
+
184
+ self.differential_update_physical_server_hashs(update_host_nodes) unless update_host_nodes.empty?
185
+ self.create_physical_server_hashs(create_host_nodes) unless create_host_nodes.empty?
186
+ destroy_servers.each { |target| target.destroy }
187
+ end
188
+
189
+ # 仮想サーバの監視
190
+ def virtual_server_watch
191
+ log_prefix = "#{self.class.name}#virtual_server_watch (provider:#{self.name}):"
192
+
193
+ # APIからの仮想サーバ情報を取得
194
+ instances = describe_instances_for_api
195
+ Tengine.logger.debug "#{log_prefix} describe_instances for api (wakame)"
196
+ Tengine.logger.debug "#{log_prefix} #{instances.inspect}"
197
+
198
+ Tengine.logger.debug "#{log_prefix} virtual_servers on provider (#{self.name})"
199
+ create_instances, update_instances, destroy_servers = partion_instances(instances)
200
+ create_instances.each do |instance|
201
+ Tengine.logger.debug "#{log_prefix} new virtual_server % <create> (#{instance[:aws_instance_id]})"
202
+ end
203
+
204
+ self.differential_update_virtual_server_hashs(update_instances) unless update_instances.empty?
205
+ self.create_virtual_server_hashs(create_instances) unless create_instances.empty?
206
+ destroy_servers.each { |target| target.destroy }
207
+ end
208
+
209
+ private
210
+
211
+ def partion_instances(instances)
212
+ log_prefix = "#{self.class.name}#virtual_server_watch (provider:#{self.name}):"
213
+ create_instances, update_instances, destroy_servers = [], [], []
214
+ self.reload
215
+ old_servers = self.virtual_servers
216
+ Tengine.logger.debug "#{log_prefix} #{old_servers.inspect}"
217
+ old_servers.each do |old_server|
218
+ instance = instances.detect do |instance|
219
+ (instance[:aws_instance_id] || instance["aws_instance_id"]) == old_server.provided_id
220
+ end
221
+ if instance
222
+ Tengine.logger.debug "#{log_prefix} registed virtual_server % <update> (#{old_server.provided_id})"
223
+ update_instances << instance
224
+ else
225
+ Tengine.logger.debug "#{log_prefix} removed virtual_server % <destroy> (#{old_server.provided_id})"
226
+ destroy_servers << old_server
227
+ end
228
+ end
229
+ create_instances = instances - update_instances
230
+ return create_instances, update_instances, destroy_servers
231
+ end
232
+
233
+
234
+ public
235
+
236
+ # 仮想サーバイメージの監視
237
+ def virtual_server_image_watch
238
+ log_prefix = "#{self.class.name}#virtual_server_image_watch (provider:#{self.name}):"
239
+
240
+ # APIからの仮想サーバイメージ情報を取得
241
+ images = describe_images_for_api
242
+ Tengine.logger.debug "#{log_prefix} describe_images for api (wakame)"
243
+ Tengine.logger.debug "#{log_prefix} #{images.inspect}"
244
+
245
+ create_images = []
246
+ update_images = []
247
+ destroy_server_images = []
248
+
249
+ # 仮想サーバイメージの取得
250
+ self.reload
251
+ old_images = self.virtual_server_images
252
+ Tengine.logger.debug "#{log_prefix} virtual_server_images on provider (#{self.name})"
253
+ Tengine.logger.debug "#{log_prefix} #{old_images.inspect}"
254
+
255
+ old_images.each do |old_image|
256
+ image = images.detect do |image|
257
+ (image[:aws_id] || image["aws_id"]) == old_image.provided_id
258
+ end
259
+
260
+ if image
261
+ Tengine.logger.debug "#{log_prefix} registed virtualserver_image % <update> (#{old_image.provided_id})"
262
+ update_images << image
263
+ else
264
+ Tengine.logger.debug "#{log_prefix} removed virtual_server_image % <destroy> (#{old_image.provided_id})"
265
+ destroy_server_images << old_image
266
+ end
267
+ end
268
+ create_images = images - update_images
269
+ create_images.each do |image|
270
+ Tengine.logger.debug "#{log_prefix} new server_image % <create> (#{image[:aws_id]})"
271
+ end
272
+
273
+ self.differential_update_virtual_server_image_hashs(update_images) unless update_images.empty?
274
+ self.create_virtual_server_image_hashs(create_images) unless create_images.empty?
275
+ destroy_server_images.each { |target| target.destroy }
276
+ end
277
+
278
+ # virtual_server_type
279
+ def differential_update_virtual_server_type_hash(hash)
280
+ properties = hash.dup
281
+ properties.deep_symbolize_keys!
282
+ virtual_server_type = self.virtual_server_types.where(:provided_id => properties[:id]).first
283
+ virtual_server_type.provided_id = properties.delete(:id)
284
+ virtual_server_type.caption = properties.delete(:uuid)
285
+ virtual_server_type.cpu_cores = properties.delete(:cpu_cores)
286
+ virtual_server_type.memory_size = properties.delete(:memory_size)
287
+ properties.each do |key, val|
288
+ value = properties.delete(key)
289
+ unless val.to_s == value.to_s
290
+ if virtual_server_type.properties[key.to_sym]
291
+ virtual_server_type.properties[key.to_sym] = value
292
+ else
293
+ virtual_server_type.properties[key.to_s] = value
294
+ end
295
+ end
296
+ end
297
+ virtual_server_type.save! if virtual_server_type.changed?
298
+ end
299
+
300
+ def differential_update_virtual_server_type_hashs(hashs)
301
+ updated_server_types = []
302
+ hashs.each do |hash|
303
+ server_type = differential_update_virtual_server_type_hash(hash)
304
+ updated_server_types << server_type
305
+ end
306
+ updated_server_types
307
+ end
308
+
309
+ def create_virtual_server_type_hash(hash)
310
+ properties = hash.dup
311
+ properties.deep_symbolize_keys!
312
+ self.virtual_server_types.create!(
313
+ :provided_id => properties.delete(:id),
314
+ :caption => properties.delete(:uuid),
315
+ :cpu_cores => properties.delete(:cpu_cores),
316
+ :memory_size => properties.delete(:memory_size),
317
+ :properties => properties)
318
+ end
319
+
320
+ def create_virtual_server_type_hashs(hashs)
321
+ created_ids = []
322
+ hashs.each do |hash|
323
+ server_type = create_virtual_server_type_hash(hash)
324
+ created_ids << server_type.id
325
+ end
326
+ created_ids
327
+ end
328
+
329
+ # physical_server
330
+ def differential_update_physical_server_hash(hash)
331
+ properties = hash.dup
332
+ properties.deep_symbolize_keys!
333
+ physical_server = self.physical_servers.where(:provided_id => properties[:id]).first
334
+ # wakame-adapters-tengine が name を返さない仕様の場合は、provided_id を name に登録します
335
+ physical_server.name = properties.delete(:name) || properties[:id]
336
+ physical_server.provided_id = properties.delete(:id)
337
+ physical_server.status = properties.delete(:status)
338
+ physical_server.cpu_cores = properties.delete(:offering_cpu_cores)
339
+ physical_server.memory_size = properties.delete(:offering_memory_size)
340
+ properties.each do |key, val|
341
+ value = properties.delete(key)
342
+ unless val.to_s == value.to_s
343
+ if physical_server.properties[key.to_sym]
344
+ physical_server.properties[key.to_sym] = value
345
+ else
346
+ physical_server.properties[key.to_s] = value
347
+ end
348
+ end
349
+ end
350
+ physical_server.save! if physical_server.changed?
351
+ end
352
+
353
+ def differential_update_physical_server_hashs(hashs)
354
+ updated_servers = []
355
+ hashs.each do |hash|
356
+ server = differential_update_physical_server_hash(hash)
357
+ updated_servers << server
358
+ end
359
+ updated_servers
360
+ end
361
+
362
+ def create_physical_server_hash(hash)
363
+ properties = hash.dup
364
+ properties.deep_symbolize_keys!
365
+ self.physical_servers.create!(
366
+ # wakame-adapters-tengine が name を返さない仕様の場合は、provided_id を name に登録します
367
+ :name => properties.delete(:name) || properties[:id],
368
+ :provided_id => properties.delete(:id),
369
+ :status => properties.delete(:status),
370
+ :cpu_cores => properties.delete(:offering_cpu_cores),
371
+ :memory_size => properties.delete(:offering_memory_size),
372
+ :properties => properties)
373
+ end
374
+
375
+ def create_physical_server_hashs(hashs)
376
+ created_ids = []
377
+ hashs.each do |hash|
378
+ server = create_physical_server_hash(hash)
379
+ created_ids << server.id
380
+ end
381
+ created_ids
382
+ end
383
+
384
+ # virtual_server_image
385
+ def differential_update_virtual_server_image_hash(hash)
386
+ properties = hash.dup
387
+ properties.deep_symbolize_keys!
388
+ server_image = self.virtual_server_images.where(:provided_id => properties[:aws_id]).first
389
+ server_image.provided_id = properties.delete(:aws_id)
390
+ server_image.provided_description = properties.delete(:description)
391
+ server_image.save! if server_image.changed?
392
+ end
393
+
394
+ def differential_update_virtual_server_image_hashs(hashs)
395
+ updated_images = []
396
+ hashs.each do |hash|
397
+ image = differential_update_virtual_server_image_hash(hash)
398
+ updated_images << image
399
+ end
400
+ updated_images
401
+ end
402
+
403
+ def create_virtual_server_image_hash(hash)
404
+ properties = hash.dup
405
+ properties.deep_symbolize_keys!
406
+ self.virtual_server_images.create!(
407
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
408
+ :name => properties[:aws_id],
409
+ :provided_id => properties.delete(:aws_id),
410
+ :provided_description => properties.delete(:description))
411
+ end
412
+
413
+ def create_virtual_server_image_hashs(hashs)
414
+ created_ids = []
415
+ hashs.each do |hash|
416
+ image = create_virtual_server_image_hash(hash)
417
+ created_ids << image.id
418
+ end
419
+ created_ids
420
+ end
421
+
422
+ # virtual_server
423
+ PRIVATE_IP_ADDRESS = "private_ip_address".freeze
424
+
425
+ def differential_update_virtual_server_hash(hash)
426
+ properties = hash.dup
427
+ properties.deep_symbolize_keys!
428
+ host_server = self.physical_servers.where(:provided_id => properties[:aws_availability_zone]).first
429
+ virtual_server = self.virtual_servers.where(:provided_id => properties[:aws_instance_id]).first
430
+ virtual_server.provided_id = properties.delete(:aws_instance_id)
431
+ virtual_server.provided_image_id = properties.delete(:aws_image_id)
432
+ virtual_server.provided_type_id = properties.delete(:aws_instance_type)
433
+ virtual_server.status = properties.delete(:aws_state)
434
+ virtual_server.host_server = host_server
435
+ virtual_server.addresses[PRIVATE_IP_ADDRESS] = properties.delete(:private_ip_address)
436
+ properties.delete(:ip_address).split(",").map do |i|
437
+ k, v = i.split("=")
438
+ virtual_server.addresses[k] = v
439
+ end
440
+ properties.each do |key, val|
441
+ value = properties.delete(key)
442
+ unless val.to_s == value.to_s
443
+ if virtual_server.properties[key.to_sym]
444
+ virtual_server.properties[key.to_sym] = value
445
+ else
446
+ virtual_server.properties[key.to_s] = value
447
+ end
448
+ end
449
+ end
450
+ virtual_server.save! if virtual_server.changed? && !virtual_server.changes.values.all?{|v| v.nil?}
451
+ end
452
+
453
+ def differential_update_virtual_server_hashs(hashs)
454
+ updated_servers = []
455
+ hashs.each do |hash|
456
+ server = differential_update_virtual_server_hash(hash)
457
+ updated_servers << server
458
+ end
459
+ updated_servers
460
+ end
461
+
462
+ def create_virtual_server_hash(hash)
463
+ properties = hash.dup
464
+ properties.deep_symbolize_keys!
465
+ host_server = self.physical_servers.where(:provided_id => properties[:aws_availability_zone]).first
466
+ addresses = {PRIVATE_IP_ADDRESS => properties.delete(:private_ip_address)}
467
+ properties.delete(:ip_address).split(",").map do |i|
468
+ k, v = i.split("=")
469
+ addresses[k] = v
470
+ end
471
+ self.virtual_servers.create!(
472
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
473
+ :name => properties[:aws_instance_id],
474
+ :provided_id => properties.delete(:aws_instance_id),
475
+ :provided_image_id => properties.delete(:aws_image_id),
476
+ :provided_type_id => properties.delete(:aws_instance_type),
477
+ :status => properties.delete(:aws_state),
478
+ :host_server => host_server,
479
+ :addresses => addresses,
480
+ :address_order => [PRIVATE_IP_ADDRESS],
481
+ :properties => properties)
482
+ rescue Mongo::OperationFailure => e
483
+ raise e unless e.message =~ /E11000 duplicate key error/
484
+ rescue Mongoid::Errors::Validations => e
485
+ raise e unless e.document.errors[:provided_id].any?{|s| s =~ /taken/}
486
+ end
487
+
488
+ def create_virtual_server_hashs(hashs)
489
+ created_ids = []
490
+ hashs.each do |hash|
491
+ if server = create_virtual_server_hash(hash)
492
+ created_ids << server.id
493
+ end
494
+ end
495
+ created_ids
496
+ end
497
+
498
+ # wakame api for tama
499
+
500
+ # wakame api からの戻り値がのキーが文字列だったりシンボルだったりで統一されてないので暫定対応で
501
+ # 戻り値のkeyをstringかsymbolかのどちらかに指定できるようにしています
502
+
503
+ def hash_key_convert(hash_list, convert)
504
+ case convert
505
+ when :string
506
+ hash_list = hash_list.map do |hash|
507
+ hash.deep_stringify_keys!
508
+ end
509
+ when :symbol
510
+ hash_list = hash_list.map do |hash|
511
+ hash.deep_symbolize_keys!
512
+ end
513
+ end
514
+ hash_list
515
+ end
516
+
517
+ def describe_instance_specs_for_api(uuids = [], option = {})
518
+ result = connect do |conn|
519
+ conn.describe_instance_specs(uuids)
520
+ end
521
+ hash_key_convert(result, option[:convert])
522
+ end
523
+
524
+ def describe_host_nodes_for_api(uuids = [], option = {})
525
+ result = connect do |conn|
526
+ conn.describe_host_nodes(uuids)
527
+ end
528
+ hash_key_convert(result, option[:convert])
529
+ end
530
+
531
+ def describe_instances_for_api(uuids = [], option = {})
532
+ result = connect do |conn|
533
+ conn.describe_instances(uuids)
534
+ end
535
+ hash_key_convert(result, option[:convert])
536
+ end
537
+
538
+ def describe_images_for_api(uuids = [], option = {})
539
+ result = connect do |conn|
540
+ conn.describe_images(uuids)
541
+ end
542
+ hash_key_convert(result, option[:convert])
543
+ end
544
+
545
+ def run_instances_for_api(uuids = [], option = {})
546
+ result = connect do |conn|
547
+ conn.run_instances(uuids)
548
+ end
549
+ hash_key_convert(result, option[:convert])
550
+ end
551
+
552
+ def terminate_instances_for_api(uuids = [], option = {})
553
+ result = connect do |conn|
554
+ conn.terminate_instances(uuids)
555
+ end
556
+ hash_key_convert(result, option[:convert])
557
+ end
558
+
559
+ def connect(&block)
560
+ send(retry_on_error ? :connect_with_retry : :connect_without_retry, &block)
561
+ end
562
+
563
+ def connect_without_retry
564
+ connection = nil
565
+ if self.connection_settings[:test] || self.connection_settings["test"]
566
+ # テスト用
567
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(:test)
568
+ options = self.connection_settings[:options] || self.connection_settings["options"]
569
+ if options
570
+ options.symbolize_keys!
571
+ connection.describe_instances_file =
572
+ File.expand_path(options[:describe_instances_file]) if options[:describe_instances_file]
573
+ connection.describe_images_file =
574
+ File.expand_path(options[:describe_images_file]) if options[:describe_images_file]
575
+ connection.run_instances_file =
576
+ File.expand_path(options[:run_instances_file]) if options[:run_instances_file]
577
+ connection.terminate_instances_file =
578
+ File.expand_path(options[:terminate_instances_file]) if options[:terminate_instances_file]
579
+ connection.describe_host_nodes_file =
580
+ File.expand_path(options[:describe_host_nodes_file]) if options[:describe_host_nodes_file]
581
+ connection.describe_instance_specs_file =
582
+ File.expand_path(options[:describe_instance_specs_file]) if options[:describe_instance_specs_file]
583
+ end
584
+ else
585
+ options = self.connection_settings.symbolize_keys
586
+ args = [:account, :ec2_host, :ec2_port, :ec2_protocol, :wakame_host, :wakame_port, :wakame_protocol].map{|key| options[key]}
587
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(*args)
588
+ end
589
+ yield connection
590
+ end
591
+
592
+ def connect_with_retry(&block)
593
+ retry_count = 1
594
+ begin
595
+ connect_without_retry(&block)
596
+ rescue Exception => e
597
+ if retry_count > self.retry_count
598
+ Tengine.logger.error "#{e.class.name} #{e.message}"
599
+ raise e
600
+ else
601
+ Tengine.logger.warn "retry[#{retry_count}]: #{e.message}"
602
+ sleep self.retry_interval
603
+ retry_count += 1
604
+ retry
605
+ end
606
+ end
607
+ end
608
+
609
+ private
610
+
611
+ def address_order
612
+ @@address_order ||= ['private_ip_address'.freeze].freeze
613
+ end
614
+
615
+ end