tengine_resource_wakame 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTFlYTlhNmRlNTIwOTNkNGJhMDQ3M2M3YjQ3ZjNkZTQ3MjVhMzVkNw==
5
+ data.tar.gz: !binary |-
6
+ YjQxZDRkYTFkYjkyOTBjOGI2NTU5YjQwZmM1ZDRmZmQ2NmQwMGRlYQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MjU2MDgzNzJjODc4MTU2Y2U2NGI3MjI4ZWYwOTA4ZDI3ZWYyZjY5YTljYzNm
10
+ YWVlZTFhYTA5MzQwMzBhNjY1OTFiMWM5OWJmOGI1YmQwNDkyMjdkNzY4NWQz
11
+ OGQ4Y2FjNThhNzkyOGJjNWU3ZjUwZWRlMjQxYmEyNzQ5NjMzN2M=
12
+ data.tar.gz: !binary |-
13
+ N2ZiNGY3YzhjYmI3Njk0ZmZhYzI3ZjkwZDBlNGMxZDFjYjE0NjcwNjRlMjcz
14
+ OTUyYTczNWZiZWZmNDM3ZWY1YmE2YjAyMGQ3Y2EyYzQ3MGQ0OGUyOTZmNDhl
15
+ ZTQ5NmJjYjBlOTIxZmQyY2ExZGI2MjViMDQ3NTNmNTljZTJjN2Y=
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # -*- coding: utf-8 -*-
2
+ source "http://rubygems.org"
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,134 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ tengine_resource_wakame (1.2.0)
5
+ tengine_resource (~> 1.2.0)
6
+ wakame-adapters-tengine (~> 0.0.0)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ ZenTest (4.9.1)
12
+ activemodel (3.2.12)
13
+ activesupport (= 3.2.12)
14
+ builder (~> 3.0.0)
15
+ activesupport (3.2.12)
16
+ i18n (~> 0.6)
17
+ multi_json (~> 1.0)
18
+ amq-client (0.9.12)
19
+ amq-protocol (>= 1.2.0)
20
+ eventmachine
21
+ amq-protocol (1.2.0)
22
+ amqp (0.9.10)
23
+ amq-client (~> 0.9.12)
24
+ amq-protocol (~> 1.2.0)
25
+ eventmachine
26
+ autotest (4.4.6)
27
+ ZenTest (>= 4.4.1)
28
+ builder (3.0.4)
29
+ coderay (1.0.9)
30
+ columnize (0.3.6)
31
+ daemons (1.1.9)
32
+ debugger (1.5.0)
33
+ columnize (>= 0.3.1)
34
+ debugger-linecache (~> 1.2.0)
35
+ debugger-ruby_core_source (~> 1.2.0)
36
+ debugger-linecache (1.2.0)
37
+ debugger-ruby_core_source (1.2.0)
38
+ diff-lcs (1.1.3)
39
+ eventmachine (1.0.3)
40
+ i18n (0.6.4)
41
+ json (1.7.7)
42
+ macaddr (1.6.1)
43
+ systemu (~> 2.5.0)
44
+ method_source (0.8.1)
45
+ mongoid (3.1.3)
46
+ activemodel (~> 3.2)
47
+ moped (~> 1.4.2)
48
+ origin (~> 1.0)
49
+ tzinfo (~> 0.3.22)
50
+ moped (1.4.5)
51
+ multi_json (1.7.2)
52
+ net-ssh (2.5.2)
53
+ origin (1.1.0)
54
+ pry (0.9.12.1)
55
+ coderay (~> 1.0.5)
56
+ method_source (~> 0.8)
57
+ slop (~> 3.4)
58
+ pry-debugger (0.2.2)
59
+ debugger (~> 1.3)
60
+ pry (~> 0.9.10)
61
+ pry-doc (0.4.5)
62
+ pry (>= 0.9)
63
+ yard (>= 0.8)
64
+ rake (10.0.4)
65
+ right_aws (2.1.0)
66
+ right_http_connection (>= 1.2.5)
67
+ right_http_connection (1.3.0)
68
+ rspec (2.10.0)
69
+ rspec-core (~> 2.10.0)
70
+ rspec-expectations (~> 2.10.0)
71
+ rspec-mocks (~> 2.10.0)
72
+ rspec-core (2.10.1)
73
+ rspec-expectations (2.10.0)
74
+ diff-lcs (~> 1.1.3)
75
+ rspec-mocks (2.10.1)
76
+ selectable_attr (0.3.17)
77
+ i18n
78
+ simplecov (0.7.1)
79
+ multi_json (~> 1.0)
80
+ simplecov-html (~> 0.7.1)
81
+ simplecov-html (0.7.1)
82
+ slop (3.4.4)
83
+ systemu (2.5.2)
84
+ tengine_core (1.2.0)
85
+ activemodel (>= 3.1.0)
86
+ activesupport (>= 3.1.0)
87
+ daemons (~> 1.1.4)
88
+ mongoid (>= 3.0.22)
89
+ selectable_attr (~> 0.3.15)
90
+ tengine_event (~> 1.2.0)
91
+ tengine_support (~> 1.2.0)
92
+ tengine_event (1.2.0)
93
+ activesupport (>= 3.0.0)
94
+ amqp (~> 0.9.10)
95
+ tengine_support (~> 1.2.0)
96
+ uuid (~> 2.3.4)
97
+ tengine_resource (1.2.0)
98
+ net-ssh (~> 2.5.2)
99
+ tengine_core (~> 1.2.0)
100
+ tengine_support (~> 1.2.0)
101
+ text-table (~> 1.2.2)
102
+ thor (>= 0.14.6)
103
+ tengine_resource_ec2 (1.2.0)
104
+ right_aws (~> 2.1.0)
105
+ tengine_resource (~> 1.2.0)
106
+ tengine_support (1.2.0)
107
+ activesupport (>= 3.0.0)
108
+ text-table (1.2.3)
109
+ thor (0.18.1)
110
+ tzinfo (0.3.37)
111
+ uuid (2.3.7)
112
+ macaddr (~> 1.0)
113
+ wakame-adapters-tengine (0.0.1)
114
+ json
115
+ right_aws (= 2.1.0)
116
+ rspec
117
+ yard (0.8.6.1)
118
+
119
+ PLATFORMS
120
+ ruby
121
+
122
+ DEPENDENCIES
123
+ ZenTest (~> 4.9.0)
124
+ autotest
125
+ bundler
126
+ pry
127
+ pry-debugger
128
+ pry-doc
129
+ rake
130
+ rspec (~> 2.10.0)
131
+ simplecov
132
+ tengine_resource_ec2 (~> 1.2.0)
133
+ tengine_resource_wakame!
134
+ yard
data/README.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ = tengine_resource
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to tengine_resource
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == License
16
+ tengine_resource is distributed under the MPL2.0 or LGPLv3 or the dual license of MPL2.0/LGPLv3
17
+
18
+ == Copyright
19
+
20
+ Copyright (c) 2012 Groovenauts, Inc.
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine_resource_wakame'
3
+
4
+ module Tengine::ResourceWakame
5
+ autoload :Provider, 'tengine/resource_wakame/provider'
6
+ end
@@ -0,0 +1,325 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/resource'
3
+
4
+ require 'tama'
5
+ require 'tengine/support/core_ext/hash/keys'
6
+ require 'tengine/support/core_ext/enumerable/map_to_hash'
7
+
8
+ # 1.0.x ではTengine::Resource::Provider::Ec2を継承していましたが、
9
+ # 1.1.x ではクラス構造を見直して継承する必要はないと判断しTengine::Resource::Providerを継承するように変更しました。
10
+ class Tengine::ResourceWakame::Provider < Tengine::Resource::Provider
11
+
12
+ # モデルの継承時に問題が発生する場合があるので、collectionの呼び出しによる接続先の事前確定を行います。
13
+ # https://github.com/tengine/tengine/commit/9a986a3b52b18a95b1d5324b9731f720d087d1e4
14
+ collection
15
+
16
+ attr_accessor :retry_on_error
17
+
18
+ field :connection_settings, :type => Hash
19
+
20
+ PHYSICAL_SERVER_STATES = [:online, :offline].freeze
21
+
22
+ VIRTUAL_SERVER_STATES = [
23
+ :scheduling, :pending, :starting, :running,
24
+ :failingover, :shuttingdown, :terminated].freeze
25
+
26
+ # @param [String] name Name template for created virtual servers
27
+ # @param [Tengine::Resource::VirtualServerImage] image Virtual server image object
28
+ # @param [Tengine::Resource::VirtualServerType] type Virtual server type object
29
+ # @param [String] physical Data center name to put virtual machines (availability zone)
30
+ # @param [String] description What this virtual server is
31
+ # @param [Numeric] count number of vortial servers to boot
32
+ # @return [Array<Tengine::Resource::VirtualServer>]
33
+ def create_virtual_servers(name, image, type, physical, description = "", count = 1)
34
+ physical_provided_id = physical.respond_to?(:provided_id) ? physical.provided_id : physical
35
+ connect {|conn|
36
+ results = conn.run_instances(
37
+ image.provided_id,
38
+ count,
39
+ count,
40
+ [],
41
+ self.properties['key_name'] || self.properties[:key_name],
42
+ "",
43
+ nil, # <- addressing_type
44
+ type.provided_id,
45
+ nil,
46
+ nil,
47
+ physical_provided_id,
48
+ nil # <- block_device_mappings
49
+ )
50
+ yield if block_given? # テスト用のブロックの呼び出し
51
+ results.map.with_index {|hash, idx|
52
+ provided_id = hash.delete(:aws_instance_id)
53
+ if server = self.virtual_servers.where({:provided_id => provided_id}).first
54
+ server
55
+ else
56
+ # findではなくfirstで検索しているので、もしhost_server_provided_idで指定されるサーバが見つからなくても
57
+ # host_serverがnilとして扱われるが、仮想サーバ自身の登録は行われます
58
+ host_server = Tengine::Resource::PhysicalServer.by_provided_id(
59
+ [hash[:aws_availability_zone], physical_provided_id].detect{|i| !i.blank?})
60
+ self.find_virtual_server_on_duplicaion_error(provided_id) do
61
+ self.virtual_servers.create!(
62
+ :name => sprintf("%s%03d", name, idx + 1), # 1 origin
63
+ :address_order => address_order.dup,
64
+ :description => description,
65
+ :provided_id => provided_id,
66
+ :provided_image_id => hash.delete(:aws_image_id),
67
+ :provided_type_id => hash.delete(:aws_instance_type),
68
+ :host_server_id => host_server ? host_server.id : nil,
69
+ :status => hash.delete(:aws_state),
70
+ :properties => hash,
71
+ :addresses => {
72
+ # :dns_name => hash.delete(:dns_name),
73
+ # :ip_address => hash.delete(:ip_address),
74
+ # :private_dns_name => hash.delete(:private_dns_name),
75
+ # :private_ip_address => hash.delete(:private_ip_address),
76
+ })
77
+ end
78
+ end
79
+ }
80
+ }
81
+ end
82
+
83
+
84
+ def terminate_virtual_servers(servers)
85
+ connect do |conn|
86
+ conn.terminate_instances(servers.map {|i| i.provided_id }).map do |hash|
87
+ serv = self.virtual_servers.where(:provided_id => hash[:aws_instance_id]).first
88
+ serv
89
+ end
90
+ end
91
+ end
92
+
93
+ def capacities(keep_cache = false)
94
+ reload unless keep_cache
95
+ server_type_ids = virtual_server_types.map(&:provided_id)
96
+ server_type_to_cpu = virtual_server_types.map_to_hash(:provided_id, &:cpu_cores)
97
+ server_type_to_mem = virtual_server_types.map_to_hash(:provided_id, &:memory_size)
98
+ physical_servers.inject({}) do |result, physical_server|
99
+ if physical_server.status == 'online'
100
+ active_guests = physical_server.guest_servers.reject do |i|
101
+ i.status.to_s == "terminated" or
102
+ server_type_to_cpu[i.provided_type_id].nil? or
103
+ server_type_to_mem[i.provided_type_id].nil?
104
+ end
105
+ cpu_free = physical_server.cpu_cores - active_guests.map{|s| server_type_to_cpu[s.provided_type_id]}.sum
106
+ mem_free = physical_server.memory_size - active_guests.map{|s| server_type_to_mem[s.provided_type_id]}.sum
107
+ result[physical_server.provided_id] = server_type_ids.map_to_hash do |server_type_id|
108
+ [ cpu_free / server_type_to_cpu[server_type_id],
109
+ mem_free / server_type_to_mem[server_type_id]
110
+ ].min
111
+ end
112
+ else
113
+ result[physical_server.provided_id] = server_type_ids.map_to_hash{|server_type_id| 0}
114
+ end
115
+ result
116
+ end
117
+ end
118
+
119
+ def synchronize_physical_servers ; synchronize_by(:physical_servers ); end # 物理サーバの監視
120
+ def synchronize_virtual_server_types ; synchronize_by(:virtual_server_types ); end # 仮想サーバタイプの監視
121
+ def synchronize_virtual_server_images; synchronize_by(:virtual_server_images); end # 仮想サーバイメージの監視
122
+ def synchronize_virtual_servers ; synchronize_by(:virtual_servers ); end # 仮想サーバの監視
123
+
124
+ # wakame api for tama
125
+ def describe_instance_specs_for_api(uuids = [], options = {})
126
+ call_api_with_conversion(:describe_instance_specs, uuids, options)
127
+ end
128
+
129
+ def describe_host_nodes_for_api(uuids = [], options = {})
130
+ call_api_with_conversion(:describe_host_nodes, uuids, options)
131
+ end
132
+
133
+ def describe_instances_for_api(uuids = [], options = {})
134
+ result = call_api_with_conversion(:describe_instances, uuids, options)
135
+ result.each do |r|
136
+ replace_value_of_hash(r, :private_ip_address) do |v|
137
+ v.first if v.is_a?(Array)
138
+ end
139
+ replace_value_of_hash(r, :ip_address) do |v|
140
+ "nw-data\=#{$1}" if (v =~ /^nw\-data\=\[\"(.+)\"\]$/)
141
+ end
142
+ end
143
+ result
144
+ end
145
+
146
+ def describe_images_for_api(uuids = [], options = {})
147
+ call_api_with_conversion(:describe_images, uuids, options)
148
+ end
149
+
150
+ def run_instances_for_api(uuids = [], options = {})
151
+ call_api_with_conversion(:run_instances, uuids, options)
152
+ end
153
+
154
+ def terminate_instances_for_api(uuids = [], options = {})
155
+ call_api_with_conversion(:terminate_instances, uuids, options)
156
+ end
157
+
158
+ private
159
+
160
+ # wakame api からの戻り値がのキーが文字列だったりシンボルだったりで統一されてないので暫定対応で
161
+ # 戻り値の配列の要素となるHashのkeyをstringかsymbolかのどちらかに指定できるようにしています
162
+ def call_api_with_conversion(api_name, uuids, options)
163
+ result = connect{|conn| conn.send(api_name, uuids) }
164
+ case options[:convert]
165
+ when :string then result.map(&:deep_stringify_keys!)
166
+ when :symbol then result.map(&:deep_symbolize_keys!)
167
+ else result
168
+ end
169
+ end
170
+
171
+ def replace_value_of_hash(hash, key)
172
+ [key, key.to_s].each do |k|
173
+ if value = hash[k]
174
+ if result = yield(value)
175
+ hash[k] = result
176
+ return
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ public
183
+
184
+ def connect(&block)
185
+ send(retry_on_error ? :connect_with_retry : :connect_without_retry, &block)
186
+ end
187
+
188
+ CONNECTION_TEST_ATTRIBUTES = [:describe_instances_file, :describe_images_file, :run_instances_file,
189
+ :terminate_instances_file, :describe_host_nodes_file, :describe_instance_specs_file].freeze
190
+
191
+ def connect_without_retry
192
+ connection = nil
193
+ if self.connection_settings[:test] || self.connection_settings["test"]
194
+ # テスト用
195
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(:test)
196
+ options = self.connection_settings[:options] || self.connection_settings["options"]
197
+ if options
198
+ options.symbolize_keys!
199
+ CONNECTION_TEST_ATTRIBUTES.each do |key|
200
+ connection.send("#{key}=", File.expand_path(options[key])) if options[key]
201
+ end
202
+ end
203
+ else
204
+ options = self.connection_settings.symbolize_keys
205
+ args = [:account, :ec2_host, :ec2_port, :ec2_protocol, :wakame_host, :wakame_port, :wakame_protocol].map{|key| options[key]}
206
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(*args)
207
+ end
208
+ return yield(connection)
209
+ end
210
+
211
+ def connect_with_retry(&block)
212
+ retry_count = 1
213
+ begin
214
+ return connect_without_retry(&block)
215
+ rescue Exception => e
216
+ if retry_count > self.retry_count
217
+ Tengine.logger.error "#{e.class.name} #{e.message}"
218
+ raise e
219
+ else
220
+ Tengine.logger.warn "retry[#{retry_count}]: #{e.message}"
221
+ sleep self.retry_interval
222
+ retry_count += 1
223
+ retry
224
+ end
225
+ end
226
+ end
227
+
228
+ private
229
+
230
+ def address_order
231
+ @@address_order ||= ['private_ip_address'.freeze].freeze
232
+ end
233
+
234
+ public
235
+
236
+ class Synchronizer < Tengine::Resource::Provider::Synchronizer
237
+ end
238
+
239
+ class PhysicalServerSynchronizer < Synchronizer
240
+ fetch_known_target_method :describe_host_nodes_for_api
241
+
242
+ map(:provided_id, :id)
243
+ # wakame-adapters-tengine が name を返さない仕様の場合は、provided_id を name に登録します
244
+ map(:name){|hash, _| hash.delete(:name) || hash[:id]}
245
+ map(:status , :status)
246
+ map(:cpu_cores , :offering_cpu_cores)
247
+ map(:memory_size, :offering_memory_size)
248
+ end
249
+
250
+ class VirtualServerTypeSynchronizer < Synchronizer
251
+ fetch_known_target_method :describe_instance_specs_for_api
252
+
253
+ map :provided_id, :id
254
+ map :caption , :uuid
255
+ map :cpu_cores , :cpu_cores
256
+ map :memory_size, :memory_size
257
+ end
258
+
259
+ class VirtualServerImageSynchronizer < Synchronizer
260
+ fetch_known_target_method :describe_images_for_api
261
+
262
+ map :provided_id , :aws_id
263
+ map :provided_description, :description
264
+
265
+ def attrs_to_create(properties)
266
+ result = super(properties)
267
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
268
+ result[:name] = result[:provided_id]
269
+ result
270
+ end
271
+ end
272
+
273
+ class VirtualServerSynchronizer < Synchronizer
274
+ fetch_known_target_method :describe_instances_for_api
275
+
276
+ PRIVATE_IP_ADDRESS = "private_ip_address".freeze
277
+
278
+ map(:provided_id , :aws_instance_id)
279
+ map(:provided_image_id, :aws_image_id)
280
+ map(:provided_type_id , :aws_instance_type)
281
+ map(:status , :aws_state)
282
+ map(:host_server) do |props, provider|
283
+ provider.physical_servers.where(:provided_id => props[:aws_availability_zone]).first
284
+ end
285
+ map(:addresses) do|props, _|
286
+ result = { PRIVATE_IP_ADDRESS => props.delete(:private_ip_address) }
287
+ props.delete(:ip_address).split(",").map do |i|
288
+ k, v = *i.split("=", 2)
289
+ result[k] = v
290
+ end
291
+ result
292
+ end
293
+
294
+ def create_by_hash(hash)
295
+ super(hash)
296
+ rescue Mongo::OperationFailure => e
297
+ raise e unless e.message =~ /E11000 duplicate key error/
298
+ nil
299
+ rescue Mongoid::Errors::Validations => e
300
+ raise e unless e.document.errors[:provided_id].any?{|s| s =~ /taken/}
301
+ nil
302
+ end
303
+
304
+ def attrs_to_create(properties)
305
+ result = super(properties)
306
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
307
+ result[:name] = result[:provided_id]
308
+ result
309
+ end
310
+
311
+ def differential_update_by_hash(hash)
312
+ super(hash) do |virtual_server, properties|
313
+ virtual_server.save! if virtual_server.changed? && !virtual_server.changes.values.all?{|v| v.nil?}
314
+ end
315
+ end
316
+ end
317
+
318
+ register_synchronizers({
319
+ :physical_servers => PhysicalServerSynchronizer,
320
+ :virtual_server_types => VirtualServerTypeSynchronizer,
321
+ :virtual_server_images => VirtualServerImageSynchronizer,
322
+ :virtual_servers => VirtualServerSynchronizer,
323
+ })
324
+
325
+ end
@@ -0,0 +1,319 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine_resource'
3
+ require 'tengine/resource/provider/ec2'
4
+
5
+ require 'tama'
6
+ require 'tengine/support/core_ext/hash/keys'
7
+ require 'tengine/support/core_ext/enumerable/map_to_hash'
8
+
9
+
10
+ class Tengine::Resource::Provider::Wakame < Tengine::Resource::Provider::Ec2
11
+
12
+ attr_accessor :retry_on_error
13
+
14
+ # field :connection_settings, :type => Hash # 継承元のTengine::Resource::Provider::Ec2で定義されているので不要
15
+
16
+ PHYSICAL_SERVER_STATES = [:online, :offline].freeze
17
+
18
+ VIRTUAL_SERVER_STATES = [
19
+ :scheduling, :pending, :starting, :running,
20
+ :failingover, :shuttingdown, :terminated].freeze
21
+
22
+ def update_virtual_server_images
23
+ connect do |conn|
24
+ hashs = conn.describe_images.map do |hash|
25
+ {
26
+ :provided_id => hash.delete(:aws_id),
27
+ :provided_description => hash.delete(:aws_description),
28
+ }
29
+ end
30
+ update_virtual_server_images_by(hashs)
31
+ end
32
+ end
33
+
34
+ # @param [String] name Name template for created virtual servers
35
+ # @param [Tengine::Resource::VirtualServerImage] image virtual server image object
36
+ # @param [Tengine::Resource::VirtualServerType] type virtual server type object
37
+ # @param [Tengine::Resource::PhysicalServer] physical physical server object
38
+ # @param [String] description what this virtual server is
39
+ # @param [Numeric] count number of vortial servers to boot
40
+ # @return [Array<Tengine::Resource::VirtualServer>]
41
+ def create_virtual_servers(name, image, type, physical, description = "", count = 1, &block)
42
+ return super(
43
+ name,
44
+ image,
45
+ type,
46
+ physical.provided_id,
47
+ description,
48
+ count, # min
49
+ count, # max
50
+ [], # grouop id
51
+ self.properties['key_name'] || self.properties[:key_name],
52
+ "", # user data
53
+ nil, # kernel id
54
+ nil, # ramdisk id
55
+ &block
56
+ )
57
+ end
58
+
59
+ def terminate_virtual_servers(servers)
60
+ connect do |conn|
61
+ conn.terminate_instances(servers.map {|i| i.provided_id }).map do |hash|
62
+ serv = self.virtual_servers.where(:provided_id => hash[:aws_instance_id]).first
63
+ serv
64
+ end
65
+ end
66
+ end
67
+
68
+ def capacities(keep_cache = false)
69
+ reload unless keep_cache
70
+ server_type_ids = virtual_server_types.map(&:provided_id)
71
+ server_type_to_cpu = virtual_server_types.map_to_hash(:provided_id, &:cpu_cores)
72
+ server_type_to_mem = virtual_server_types.map_to_hash(:provided_id, &:memory_size)
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.map_to_hash do |server_type_id|
83
+ [ cpu_free / server_type_to_cpu[server_type_id],
84
+ mem_free / server_type_to_mem[server_type_id]
85
+ ].min
86
+ end
87
+ else
88
+ result[physical_server.provided_id] = server_type_ids.map_to_hash{|server_type_id| 0}
89
+ end
90
+ result
91
+ end
92
+ end
93
+
94
+ def synchronize_physical_servers ; synchronize_by(:physical_servers ); end # 物理サーバの監視
95
+ def synchronize_virtual_server_types ; synchronize_by(:virtual_server_types ); end # 仮想サーバタイプの監視
96
+ def synchronize_virtual_server_images; synchronize_by(:virtual_server_images); end # 仮想サーバイメージの監視
97
+ def synchronize_virtual_servers ; synchronize_by(:virtual_servers ); end # 仮想サーバの監視
98
+
99
+ private
100
+
101
+ def synchronize_by(target_name)
102
+ synchronizer = synchronizers_by(target_name)
103
+ synchronizer.execute
104
+ end
105
+
106
+ def synchronizers_by(target_name)
107
+ unless @synchronizers
108
+ @synchronizers = {}
109
+ SYNCHRONIZER_CLASSES.each do |target_name, klass|
110
+ @synchronizers[target_name] = klass.new(self, target_name)
111
+ end
112
+ end
113
+ @synchronizers[target_name]
114
+ end
115
+
116
+ public
117
+
118
+ # wakame api for tama
119
+ def describe_instance_specs_for_api(uuids = [], options = {})
120
+ call_api_with_conversion(:describe_instance_specs, uuids, options)
121
+ end
122
+
123
+ def describe_host_nodes_for_api(uuids = [], options = {})
124
+ call_api_with_conversion(:describe_host_nodes, uuids, options)
125
+ end
126
+
127
+ def describe_instances_for_api(uuids = [], options = {})
128
+ result = call_api_with_conversion(:describe_instances, uuids, options)
129
+ result.each do |r|
130
+ replace_value_of_hash(r, :private_ip_address) do |v|
131
+ v.first if v.is_a?(Array)
132
+ end
133
+ replace_value_of_hash(r, :ip_address) do |v|
134
+ "nw-data\=#{$1}" if (v =~ /^nw\-data\=\[\"(.+)\"\]$/)
135
+ end
136
+ end
137
+ result
138
+ end
139
+
140
+ def describe_images_for_api(uuids = [], options = {})
141
+ call_api_with_conversion(:describe_images, uuids, options)
142
+ end
143
+
144
+ def run_instances_for_api(uuids = [], options = {})
145
+ call_api_with_conversion(:run_instances, uuids, options)
146
+ end
147
+
148
+ def terminate_instances_for_api(uuids = [], options = {})
149
+ call_api_with_conversion(:terminate_instances, uuids, options)
150
+ end
151
+
152
+ private
153
+
154
+ # wakame api からの戻り値がのキーが文字列だったりシンボルだったりで統一されてないので暫定対応で
155
+ # 戻り値の配列の要素となるHashのkeyをstringかsymbolかのどちらかに指定できるようにしています
156
+ def call_api_with_conversion(api_name, uuids, options)
157
+ result = connect{|conn| conn.send(api_name, uuids) }
158
+ case options[:convert]
159
+ when :string then result.map(&:deep_stringify_keys!)
160
+ when :symbol then result.map(&:deep_symbolize_keys!)
161
+ else result
162
+ end
163
+ end
164
+
165
+ def replace_value_of_hash(hash, key)
166
+ [key, key.to_s].each do |k|
167
+ if value = hash[k]
168
+ if result = yield(value)
169
+ hash[k] = result
170
+ return
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ public
177
+
178
+ def connect(&block)
179
+ send(retry_on_error ? :connect_with_retry : :connect_without_retry, &block)
180
+ end
181
+
182
+ CONNECTION_TEST_ATTRIBUTES = [:describe_instances_file, :describe_images_file, :run_instances_file,
183
+ :terminate_instances_file, :describe_host_nodes_file, :describe_instance_specs_file].freeze
184
+
185
+ def connect_without_retry
186
+ connection = nil
187
+ if self.connection_settings[:test] || self.connection_settings["test"]
188
+ # テスト用
189
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(:test)
190
+ options = self.connection_settings[:options] || self.connection_settings["options"]
191
+ if options
192
+ options.symbolize_keys!
193
+ CONNECTION_TEST_ATTRIBUTES.each do |key|
194
+ connection.send("#{key}=", File.expand_path(options[key])) if options[key]
195
+ end
196
+ end
197
+ else
198
+ options = self.connection_settings.symbolize_keys
199
+ args = [:account, :ec2_host, :ec2_port, :ec2_protocol, :wakame_host, :wakame_port, :wakame_protocol].map{|key| options[key]}
200
+ connection = ::Tama::Controllers::ControllerFactory.create_controller(*args)
201
+ end
202
+ return yield(connection)
203
+ end
204
+
205
+ def connect_with_retry(&block)
206
+ retry_count = 1
207
+ begin
208
+ return connect_without_retry(&block)
209
+ rescue Exception => e
210
+ if retry_count > self.retry_count
211
+ Tengine.logger.error "#{e.class.name} #{e.message}"
212
+ raise e
213
+ else
214
+ Tengine.logger.warn "retry[#{retry_count}]: #{e.message}"
215
+ sleep self.retry_interval
216
+ retry_count += 1
217
+ retry
218
+ end
219
+ end
220
+ end
221
+
222
+ private
223
+
224
+ def address_order
225
+ @@address_order ||= ['private_ip_address'.freeze].freeze
226
+ end
227
+
228
+ public
229
+
230
+ class Synchronizer < Tengine::Resource::Provider::Synchronizer
231
+ end
232
+
233
+ class PhysicalServerSynchronizer < Synchronizer
234
+ fetch_known_target_method :describe_host_nodes_for_api
235
+
236
+ map(:provided_id, :id)
237
+ # wakame-adapters-tengine が name を返さない仕様の場合は、provided_id を name に登録します
238
+ map(:name){|hash, _| hash.delete(:name) || hash[:id]}
239
+ map(:status , :status)
240
+ map(:cpu_cores , :offering_cpu_cores)
241
+ map(:memory_size, :offering_memory_size)
242
+ end
243
+
244
+ class VirtualServerTypeSynchronizer < Synchronizer
245
+ fetch_known_target_method :describe_instance_specs_for_api
246
+
247
+ map :provided_id, :id
248
+ map :caption , :uuid
249
+ map :cpu_cores , :cpu_cores
250
+ map :memory_size, :memory_size
251
+ end
252
+
253
+ class VirtualServerImageSynchronizer < Synchronizer
254
+ fetch_known_target_method :describe_images_for_api
255
+
256
+ map :provided_id , :aws_id
257
+ map :provided_description, :description
258
+
259
+ def attrs_to_create(properties)
260
+ result = super(properties)
261
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
262
+ result[:name] = result[:provided_id]
263
+ result
264
+ end
265
+ end
266
+
267
+ class VirtualServerSynchronizer < Synchronizer
268
+ fetch_known_target_method :describe_instances_for_api
269
+
270
+ PRIVATE_IP_ADDRESS = "private_ip_address".freeze
271
+
272
+ map(:provided_id , :aws_instance_id)
273
+ map(:provided_image_id, :aws_image_id)
274
+ map(:provided_type_id , :aws_instance_type)
275
+ map(:status , :aws_state)
276
+ map(:host_server) do |props, provider|
277
+ provider.physical_servers.where(:provided_id => props[:aws_availability_zone]).first
278
+ end
279
+ map(:addresses) do|props, _|
280
+ result = { PRIVATE_IP_ADDRESS => props.delete(:private_ip_address) }
281
+ props.delete(:ip_address).split(",").map do |i|
282
+ k, v = *i.split("=", 2)
283
+ result[k] = v
284
+ end
285
+ result
286
+ end
287
+
288
+ def create_by_hash(hash)
289
+ super(hash)
290
+ rescue Mongo::OperationFailure => e
291
+ raise e unless e.message =~ /E11000 duplicate key error/
292
+ nil
293
+ rescue Mongoid::Errors::Validations => e
294
+ raise e unless e.document.errors[:provided_id].any?{|s| s =~ /taken/}
295
+ nil
296
+ end
297
+
298
+ def attrs_to_create(properties)
299
+ result = super(properties)
300
+ # 初期登録時、default 値として name には一意な provided_id を name へ登録します
301
+ result[:name] = result[:provided_id]
302
+ result
303
+ end
304
+
305
+ def differential_update_by_hash(hash)
306
+ super(hash) do |virtual_server, properties|
307
+ virtual_server.save! if virtual_server.changed? && !virtual_server.changes.values.all?{|v| v.nil?}
308
+ end
309
+ end
310
+ end
311
+
312
+ SYNCHRONIZER_CLASSES = {
313
+ :physical_servers => PhysicalServerSynchronizer,
314
+ :virtual_server_types => VirtualServerTypeSynchronizer,
315
+ :virtual_server_images => VirtualServerImageSynchronizer,
316
+ :virtual_servers => VirtualServerSynchronizer,
317
+ }.freeze
318
+
319
+ end
@@ -0,0 +1,5 @@
1
+ require 'tengine_resource'
2
+
3
+ module Tengine
4
+ autoload :ResourceWakame, 'tengine/resource_wakame'
5
+ end
data/tmp/.gitkeep ADDED
File without changes
metadata ADDED
@@ -0,0 +1,240 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tengine_resource_wakame
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - taigou
8
+ - totty
9
+ - g-morita
10
+ - shyouhei
11
+ - akm
12
+ - hiroshinakao
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2013-04-30 00:00:00.000000000 Z
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: tengine_resource
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.2.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ version: 1.2.0
32
+ - !ruby/object:Gem::Dependency
33
+ name: wakame-adapters-tengine
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.0.0
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: tengine_resource_ec2
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: 1.2.0
53
+ type: :development
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ version: 1.2.0
60
+ - !ruby/object:Gem::Dependency
61
+ name: bundler
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: rake
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ - !ruby/object:Gem::Dependency
89
+ name: rspec
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: 2.10.0
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.10.0
102
+ - !ruby/object:Gem::Dependency
103
+ name: yard
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ type: :development
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ - !ruby/object:Gem::Dependency
117
+ name: simplecov
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ - !ruby/object:Gem::Dependency
131
+ name: autotest
132
+ requirement: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ type: :development
138
+ prerelease: false
139
+ version_requirements: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ - !ruby/object:Gem::Dependency
145
+ name: pry
146
+ requirement: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ! '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ type: :development
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: pry-doc
160
+ requirement: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ! '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ type: :development
166
+ prerelease: false
167
+ version_requirements: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ! '>='
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ - !ruby/object:Gem::Dependency
173
+ name: pry-debugger
174
+ requirement: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ! '>='
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ type: :development
180
+ prerelease: false
181
+ version_requirements: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ! '>='
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ - !ruby/object:Gem::Dependency
187
+ name: ZenTest
188
+ requirement: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ~>
191
+ - !ruby/object:Gem::Version
192
+ version: 4.9.0
193
+ type: :development
194
+ prerelease: false
195
+ version_requirements: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ~>
198
+ - !ruby/object:Gem::Version
199
+ version: 4.9.0
200
+ description: tengine_resource_wakame provides physical/virtual server management for
201
+ wakame-vdc
202
+ email: tengine-info@groovenauts.jp
203
+ executables: []
204
+ extensions: []
205
+ extra_rdoc_files:
206
+ - README.rdoc
207
+ files:
208
+ - Gemfile
209
+ - Gemfile.lock
210
+ - README.rdoc
211
+ - lib/tengine/resource_wakame/provider.rb
212
+ - lib/tengine/resource_wakame/provider.rb~
213
+ - lib/tengine/resource_wakame.rb
214
+ - lib/tengine_resource_wakame.rb
215
+ - tmp/.gitkeep
216
+ homepage: http://github.com/tengine/tengine
217
+ licenses:
218
+ - MPL2.0/LGPLv3
219
+ metadata: {}
220
+ post_install_message:
221
+ rdoc_options: []
222
+ require_paths:
223
+ - lib
224
+ required_ruby_version: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ! '>='
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ required_rubygems_version: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - ! '>='
232
+ - !ruby/object:Gem::Version
233
+ version: '0'
234
+ requirements: []
235
+ rubyforge_project:
236
+ rubygems_version: 2.0.3
237
+ signing_key:
238
+ specification_version: 4
239
+ summary: tengine_resource_wakame provides physical/virtual server management for wakame-vdc
240
+ test_files: []