right_infrastructure_agent 1.1.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.
@@ -0,0 +1,54 @@
1
+ # -*-ruby-*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'rubygems'
24
+
25
+ Gem::Specification.new do |spec|
26
+ spec.name = 'right_infrastructure_agent'
27
+ spec.version = '1.1.2'
28
+ spec.date = '2014-07-24'
29
+ spec.authors = ['Lee Kirchhoff', 'Raphael Simon']
30
+ spec.email = 'lee@rightscale.com'
31
+ spec.homepage = 'https://github.com/rightscale/right_infrastructure_agent'
32
+ spec.platform = Gem::Platform::RUBY
33
+ spec.summary = 'RightAgent extension for use by RightScale infrastructure servers'
34
+ spec.has_rdoc = true
35
+ spec.rdoc_options = ["--main", "README.rdoc", "--title", "RightInfrastructureAgent"]
36
+ spec.extra_rdoc_files = ["README.rdoc"]
37
+ spec.required_ruby_version = '>= 1.8.7'
38
+ spec.require_path = 'lib'
39
+
40
+ spec.add_dependency('right_support', '~> 2.1')
41
+ spec.add_dependency('right_amqp', '~> 0.4')
42
+ spec.add_dependency('right_agent', '~> 2.0')
43
+
44
+ spec.description = <<-EOF
45
+ RightInfrastructureAgent provides the foundation for RightScale infrastructure
46
+ servers that connect into the RightScale system via the RabbitMQ message bus.
47
+ It extends RightAgent in configuration, monitoring, and packet handling areas
48
+ as needed generically by infrastructure servers.
49
+ EOF
50
+
51
+ candidates = Dir.glob("{lib,spec}/**/*") +
52
+ ["LICENSE", "README.rdoc", "Rakefile", "right_infrastructure_agent.gemspec"]
53
+ spec.files = candidates.sort
54
+ end
@@ -0,0 +1,305 @@
1
+ #--
2
+ # Copyright (c) 2011-2013 RightScale, Inc, All Rights Reserved Worldwide.
3
+ #
4
+ # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
5
+ # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
6
+ # reproduction, modification, or disclosure of this program is
7
+ # strictly prohibited. Any use of this program by an authorized
8
+ # licensee is strictly subject to the terms and conditions,
9
+ # including confidentiality obligations, set forth in the applicable
10
+ # License Agreement between RightScale.com, Inc. and the licensee.
11
+ #++
12
+
13
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
14
+
15
+ describe RightScale::GlobalObjectReplicatorSink do
16
+
17
+ include FlexMock::ArgumentTypes
18
+
19
+ class SystemConfig; end
20
+
21
+ module RightSharding
22
+ module ShardHandler
23
+ def self.fetch_this_shard_id(system_config)
24
+ 9
25
+ end
26
+ end
27
+ end
28
+
29
+ # A pseudo HTTP controller applying GlobalObjectReplicatorSink
30
+ class GlobalObjectReplicatorSinkController
31
+ include RightScale::GlobalObjectReplicatorSink
32
+
33
+ attr_reader :logger
34
+ attr_reader :params
35
+
36
+ def initialize(params = {})
37
+ @params = params
38
+ @logger = RightScale::Log
39
+ end
40
+
41
+ def global_object_replicator_sink
42
+ "core"
43
+ end
44
+
45
+ def render(hash)
46
+ nil
47
+ end
48
+ end
49
+
50
+ class FakeGlobalSinkObject
51
+
52
+ attr_accessor :id, :name, :foo, :global_object_version
53
+
54
+ def initialize
55
+ @id = 71
56
+ @name = "fake"
57
+ @foo = "bar"
58
+ @global_object_version = 999
59
+ self.class.store(self)
60
+ end
61
+
62
+ def attributes
63
+ {"name" => @name, "foo" => @foo}
64
+ end
65
+
66
+ def self.will_replicate_sink?
67
+ true
68
+ end
69
+
70
+ def self.will_replicate_current_schema_version
71
+ 3
72
+ end
73
+
74
+ def self.calculate_global_object_checksum(checksum_type, begin_id = nil, end_id = nil)
75
+ 123
76
+ end
77
+
78
+ def self.will_replicate_initialization_chunk_size
79
+ 2
80
+ end
81
+
82
+ def self.max_id
83
+ 101
84
+ end
85
+
86
+ def self.handle_global_object_change(id, schema_version, global_object_version, attrs)
87
+ object = (@objects ||= {})[id]
88
+ raise ArgumentError("Invalid id: #{id}") unless object
89
+ raise ArgumentError("Invalid schema verson: #{schema_version}") unless schema_version == FakeGlobalSinkObject.will_replicate_current_schema_version
90
+ object.global_object_version = global_object_version
91
+ YAML.load(attrs).each { |name, value| object.instance_variable_set(eval(":@#{name}"), value) }
92
+ end
93
+
94
+ def self.store(object)
95
+ (@objects ||= {})[object.id] = object
96
+ end
97
+
98
+ def self.purge
99
+ @objects = nil
100
+ end
101
+ end
102
+
103
+ before(:each) do
104
+ @request_params = {}
105
+ @controller = GlobalObjectReplicatorSinkController.new(@request_params)
106
+ flexmock(@controller).should_receive(:query).and_yield.by_default
107
+ @checksum_type = "global_object_version_sum"
108
+ end
109
+
110
+ context "handle_global_object_change" do
111
+
112
+ before(:each) do
113
+ @object = FakeGlobalSinkObject.new
114
+ @updated_name = "Updated Name"
115
+ @request_params.merge!({
116
+ :source => "library",
117
+ :api_version => "1.5",
118
+ :request_token => "1234",
119
+ :class_name => FakeGlobalSinkObject.to_s,
120
+ :id => @object.id,
121
+ :schema_version => FakeGlobalSinkObject.will_replicate_current_schema_version,
122
+ :global_object_version => @object.global_object_version + 1,
123
+ :attrs => @object.attributes.merge("name" => @updated_name).to_yaml })
124
+ flexmock(RightScale::RightHttpClient).should_receive(:push).by_default
125
+ end
126
+
127
+ it "should succeed for a valid global object" do
128
+ @controller.handle_global_object_change.should be_true
129
+ @object.name.should == @updated_name
130
+ end
131
+
132
+ it "should ignore requests for unknown objects" do
133
+ flexmock(@controller.logger).should_receive(:warn).with(/GlobalObjectReplica: Ignoring/).once
134
+ @request_params[:class_name] = "Server"
135
+ @controller.handle_global_object_change.should be_true
136
+ end
137
+ end
138
+
139
+ context "verify_next_replica_range" do
140
+
141
+ it "should send a request to the library_replicator" do
142
+ flexmock(EM).should_receive(:next_tick).and_yield.once
143
+ flexmock(RightScale::RightHttpClient).should_receive(:push).with("/library_replicator/verify_replica_range", hsh(:sink => "core")).once
144
+ @controller.send(:verify_next_replica_range, "library", FakeGlobalSinkObject, @checksum_type, 20, 1, 10).should be_true
145
+ end
146
+
147
+ it "logs exception if synchronize_replica_range request fails" do
148
+ flexmock(@controller.logger).should_receive(:error).with(/Failed to verify_replica_range.*failure/).once
149
+ flexmock(EM).should_receive(:next_tick).and_yield.once
150
+ flexmock(RightScale::RightHttpClient).should_receive(:push).and_raise(Exception, "failure").once
151
+ @controller.send(:verify_next_replica_range, "library", FakeGlobalSinkObject, @checksum_type, 20, 1, 10).should be_true
152
+ end
153
+ end
154
+
155
+ context "verify_replicas" do
156
+
157
+ before(:each) do
158
+ @request_params.merge!({
159
+ :source => "library",
160
+ :api_version => "1.5",
161
+ :request_token => "1234",
162
+ :class_name => "FakeGlobalSinkObject",
163
+ :checksum_type => @checksum_type,
164
+ :checksum_value => 123 })
165
+ end
166
+
167
+ it "should not start the synchronization process if the received sum matches the calculated" do
168
+ flexmock(@controller).should_receive(:verify_next_replica_range).never
169
+ @controller.verify_replicas.should be_true
170
+ end
171
+
172
+ it "should start the synchronization process if the received sum does not match the calculated" do
173
+ flexmock(@controller).should_receive(:verify_next_replica_range).once
174
+ @request_params[:checksum_value] = 999
175
+ @controller.verify_replicas.should be_true
176
+ end
177
+
178
+ it "should ignore requests for unknown objects" do
179
+ flexmock(@controller.logger).should_receive(:warn).with(/GlobalObjectReplica: Ignoring/).once
180
+ @request_params[:class_name] = "Server"
181
+ @controller.verify_replicas.should be_true
182
+ end
183
+ end
184
+
185
+ context "synchronize_replica_range" do
186
+
187
+ before(:each) do
188
+ @request_params.merge!({
189
+ :source => "library",
190
+ :api_version => "1.5",
191
+ :request_token => "1234",
192
+ :class_name => "FakeGlobalSinkObject",
193
+ :checksum_type => @checksum_type,
194
+ :max_id_at_start => 14114,
195
+ :begin_id => 1,
196
+ :end_id => 100,
197
+ :checksum_matched => true,
198
+ :has_more => false,
199
+ :records_to_synchronize => [] })
200
+ end
201
+
202
+ it "should update any received records" do
203
+ flexmock(FakeGlobalSinkObject).should_receive(:handle_global_object_change).with(1, 2, 3, {}).once
204
+ @request_params[:records_to_synchronize] = [{"id" => 1, "schema_version" => 2, "global_object_version" => 3, "attrs" => {}}]
205
+ @controller.synchronize_replica_range.should be_true
206
+ end
207
+
208
+ it "should continue synchronizing if has_more is true" do
209
+ flexmock(@controller).should_receive(:verify_next_replica_range).once
210
+ @request_params[:has_more] = true
211
+ @controller.synchronize_replica_range.should be_true
212
+ end
213
+
214
+ it "should stop synchronizing if has_more is false" do
215
+ flexmock(@replicator).should_receive(:verify_next_replica_range).never
216
+ @controller.synchronize_replica_range.should be_true
217
+ end
218
+
219
+ it "should ignore requests for unknown objects" do
220
+ flexmock(@controller.logger).should_receive(:warn).with(/GlobalObjectReplica: Ignoring/).once
221
+ @request_params[:class_name] = "Server"
222
+ @controller.synchronize_replica_range.should be_true
223
+ end
224
+ end
225
+
226
+ context "calculate_next_range_for_binary_sync" do
227
+
228
+ before(:each) do
229
+ @min_size = 250
230
+ end
231
+
232
+ context "context when max_id > min_size" do
233
+
234
+ before(:each) do
235
+ @max_id = 31021
236
+ @source = "library"
237
+ end
238
+
239
+ it "should return next min_size range if top level is in sync" do
240
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, 0, @max_id, true).
241
+ should == [@max_id + 1, @max_id + @min_size]
242
+ end
243
+
244
+ it "should return next min_size range if start is past max_id" do
245
+ start_id = @max_id + 50
246
+ end_id = @max_id + 100
247
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, start_id, end_id, true).
248
+ should == [end_id + 1, end_id + @min_size]
249
+ end
250
+
251
+ it "should return the 1st level left branch if top is not in sync" do
252
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
253
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, 0, @max_id, false).
254
+ should == [0, center]
255
+ end
256
+
257
+ it "should return the 1st level right branch if 1st level left is in sync" do
258
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
259
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, 0, center, true).
260
+ should == [center + 1, @max_id]
261
+ end
262
+
263
+ it "should return the 2nd level left-left branch if 1st level left is not in sync" do
264
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
265
+ size, left_center = @controller.send(:calc_size_and_center, 0, center)
266
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, 0, center, false).
267
+ should == [0, left_center]
268
+ end
269
+
270
+ it "should return the 2nd level left-right branch if 2nd left-left is in sync" do
271
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
272
+ size, left_center = @controller.send(:calc_size_and_center, 0, center)
273
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, 0, left_center, true).
274
+ should == [left_center + 1, center]
275
+ end
276
+
277
+ it "should return the 1st level right branch if 2nd left-right is in sync" do
278
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
279
+ size, left_center = @controller.send(:calc_size_and_center, 0, center)
280
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, left_center + 1, center, true).
281
+ should == [center + 1, @max_id]
282
+ end
283
+
284
+ it "should return the 1st level right branch if 3rd left-right-right is in sync" do
285
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
286
+ size, left_center = @controller.send(:calc_size_and_center, 0, center)
287
+ size, left_right_center = @controller.send(:calc_size_and_center, left_center + 1, center)
288
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, left_right_center + 1, center, true).
289
+ should == [center + 1, @max_id]
290
+ end
291
+
292
+ it "should return nils if 1st level right branch is in sync" do
293
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
294
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, center + 1, @max_id, true).
295
+ should == [@max_id + 1, @max_id + @min_size]
296
+ end
297
+
298
+ it "should return nils if 2nd level right-right branch is in sync" do
299
+ size, center = @controller.send(:calc_size_and_center, 0, @max_id)
300
+ size, right_center = @controller.send(:calc_size_and_center, center + 1, @max_id)
301
+ @controller.send(:calculate_next_range_for_binary_sync, @source, @max_id, @min_size, right_center + 1, @max_id, true).should == [@max_id + 1, @max_id + @min_size]
302
+ end
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,113 @@
1
+ #--
2
+ # Copyright (c) 2011-2013 RightScale, Inc, All Rights Reserved Worldwide.
3
+ #
4
+ # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
5
+ # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
6
+ # reproduction, modification, or disclosure of this program is
7
+ # strictly prohibited. Any use of this program by an authorized
8
+ # licensee is strictly subject to the terms and conditions,
9
+ # including confidentiality obligations, set forth in the applicable
10
+ # License Agreement between RightScale.com, Inc. and the licensee.
11
+ #++
12
+
13
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
14
+
15
+ describe RightScale::GlobalObjectReplicatorSource do
16
+
17
+ include FlexMock::ArgumentTypes
18
+
19
+ # A pseudo HTTP controller applying GlobalObjectReplicatorSource
20
+ class GlobalObjectReplicatorSourceController
21
+ include RightScale::GlobalObjectReplicatorSource
22
+
23
+ attr_reader :logger
24
+ attr_reader :params
25
+
26
+ def initialize(params)
27
+ @params = params
28
+ @logger = RightScale::Log
29
+ end
30
+
31
+ def global_object_replicator_source
32
+ "library"
33
+ end
34
+
35
+ def render(hash)
36
+ nil
37
+ end
38
+ end
39
+
40
+ class FakeGlobalSourceObject
41
+ def self.calculate_global_object_checksum(checksum_type, schema_version, begin_id, end_id)
42
+ 123
43
+ end
44
+
45
+ def self.max_id
46
+ 101
47
+ end
48
+ end
49
+
50
+ context "verify_replica_range" do
51
+
52
+ before(:each) do
53
+ @request_params = {
54
+ :sink => "core",
55
+ :class_name => "FakeGlobalSourceObject",
56
+ :schema_version => 1,
57
+ :max_id_at_start => 100,
58
+ :begin_id => 1,
59
+ :end_id => 2,
60
+ :send_records_on_checksum_mismatch => true,
61
+ :checksum_value => FakeGlobalSourceObject.calculate_global_object_checksum("x", 1, 1, 2),
62
+ :shard_id => 9}
63
+ @controller = GlobalObjectReplicatorSourceController.new(@request_params)
64
+ flexmock(@controller).should_receive(:query).and_yield.by_default
65
+ flexmock(RightScale::RightHttpClient).should_receive(:push).by_default
66
+ end
67
+
68
+ it "gets records to synchronize if the received sum does not match the calculated sum" do
69
+ flexmock(FakeGlobalSourceObject).should_receive(:get_initialization_hashes).and_return([{:a => :b}]).once
70
+ @request_params[:checksum_value] = 999
71
+ @controller.verify_replica_range.should be_true
72
+ end
73
+
74
+ it "sends synchronize_replica_range request to sink with records to synchronize" do
75
+ flexmock(EM).should_receive(:next_tick).and_yield.once
76
+ flexmock(FakeGlobalSourceObject).should_receive(:get_initialization_hashes).and_return([{:a => :b}]).once
77
+ flexmock(RightScale::RightHttpClient).should_receive(:push).with("/replicator/synchronize_replica_range",
78
+ on { |arg| arg[:records_to_synchronize] == [{:a => :b}] }, :scope => {:shard => 9}).once
79
+ @request_params[:checksum_value] = 999
80
+ @controller.verify_replica_range.should be_true
81
+ end
82
+
83
+ it "does not get records to synchronize if send_records_on_checksum_mismatch is false" do
84
+ flexmock(EM).should_receive(:next_tick).and_yield.once
85
+ flexmock(FakeGlobalSourceObject).should_receive(:get_initialization_hashes).never
86
+ flexmock(RightScale::RightHttpClient).should_receive(:push).with("/replicator/synchronize_replica_range",
87
+ on { |arg| arg[:records_to_synchronize] == [] }, :scope => {:shard => 9}).once
88
+ @request_params[:checksum_value] = 999
89
+ @request_params[:send_records_on_checksum_mismatch] = false
90
+ @controller.verify_replica_range.should be_true
91
+ end
92
+
93
+ it "does not get records to synchronize if the received checksum matches the calculated checksum" do
94
+ flexmock(EM).should_receive(:next_tick).and_yield.once
95
+ flexmock(FakeGlobalSourceObject).should_receive(:get_initialization_hashes).never
96
+ flexmock(RightScale::RightHttpClient).should_receive(:push).with("/replicator/synchronize_replica_range",
97
+ on { |arg| arg[:records_to_synchronize] == [] }, :scope => {:shard => 9}).once
98
+ @controller.verify_replica_range.should be_true
99
+ end
100
+
101
+ it "logs exception if synchronize_replica_range request fails" do
102
+ flexmock(@controller.logger).should_receive(:error).with(/Failed to synchronize_replica_range.*failure/).once
103
+ flexmock(EM).should_receive(:next_tick).and_yield.once
104
+ flexmock(RightScale::RightHttpClient).should_receive(:push).and_raise(Exception, "failure").once
105
+ @controller.verify_replica_range.should be_true
106
+ end
107
+
108
+ it "raises exception if query is unsuccessful" do
109
+ flexmock(@controller).should_receive(:query).and_return(false).once
110
+ lambda { @controller.verify_replica_range }.should raise_error(RightScale::Exceptions::QueryFailure)
111
+ end
112
+ end
113
+ end