right_agent 0.5.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +78 -0
  3. data/Rakefile +86 -0
  4. data/lib/right_agent.rb +66 -0
  5. data/lib/right_agent/actor.rb +163 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +189 -0
  8. data/lib/right_agent/agent.rb +735 -0
  9. data/lib/right_agent/agent_config.rb +403 -0
  10. data/lib/right_agent/agent_identity.rb +209 -0
  11. data/lib/right_agent/agent_tags_manager.rb +213 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/broker_client.rb +683 -0
  14. data/lib/right_agent/command.rb +30 -0
  15. data/lib/right_agent/command/agent_manager_commands.rb +134 -0
  16. data/lib/right_agent/command/command_client.rb +136 -0
  17. data/lib/right_agent/command/command_constants.rb +42 -0
  18. data/lib/right_agent/command/command_io.rb +128 -0
  19. data/lib/right_agent/command/command_parser.rb +87 -0
  20. data/lib/right_agent/command/command_runner.rb +105 -0
  21. data/lib/right_agent/command/command_serializer.rb +63 -0
  22. data/lib/right_agent/console.rb +65 -0
  23. data/lib/right_agent/core_payload_types.rb +42 -0
  24. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  25. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  26. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  27. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  28. data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
  29. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  30. data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
  31. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  32. data/lib/right_agent/core_payload_types/login_user.rb +62 -0
  33. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  34. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
  35. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  36. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  37. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
  38. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  39. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  40. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  41. data/lib/right_agent/daemonize.rb +35 -0
  42. data/lib/right_agent/dispatcher.rb +348 -0
  43. data/lib/right_agent/enrollment_result.rb +217 -0
  44. data/lib/right_agent/exceptions.rb +30 -0
  45. data/lib/right_agent/ha_broker_client.rb +1278 -0
  46. data/lib/right_agent/idempotent_request.rb +140 -0
  47. data/lib/right_agent/log.rb +418 -0
  48. data/lib/right_agent/monkey_patches.rb +29 -0
  49. data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
  50. data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
  51. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  52. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  53. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  54. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  55. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  56. data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
  57. data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
  58. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  64. data/lib/right_agent/multiplexer.rb +91 -0
  65. data/lib/right_agent/operation_result.rb +270 -0
  66. data/lib/right_agent/packets.rb +637 -0
  67. data/lib/right_agent/payload_formatter.rb +104 -0
  68. data/lib/right_agent/pid_file.rb +159 -0
  69. data/lib/right_agent/platform.rb +319 -0
  70. data/lib/right_agent/platform/darwin.rb +227 -0
  71. data/lib/right_agent/platform/linux.rb +268 -0
  72. data/lib/right_agent/platform/windows.rb +1204 -0
  73. data/lib/right_agent/scripts/agent_controller.rb +522 -0
  74. data/lib/right_agent/scripts/agent_deployer.rb +379 -0
  75. data/lib/right_agent/scripts/common_parser.rb +153 -0
  76. data/lib/right_agent/scripts/log_level_manager.rb +193 -0
  77. data/lib/right_agent/scripts/stats_manager.rb +256 -0
  78. data/lib/right_agent/scripts/usage.rb +58 -0
  79. data/lib/right_agent/secure_identity.rb +92 -0
  80. data/lib/right_agent/security.rb +32 -0
  81. data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
  82. data/lib/right_agent/security/certificate.rb +102 -0
  83. data/lib/right_agent/security/certificate_cache.rb +89 -0
  84. data/lib/right_agent/security/distinguished_name.rb +56 -0
  85. data/lib/right_agent/security/encrypted_document.rb +84 -0
  86. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  87. data/lib/right_agent/security/signature.rb +86 -0
  88. data/lib/right_agent/security/static_certificate_store.rb +69 -0
  89. data/lib/right_agent/sender.rb +937 -0
  90. data/lib/right_agent/serialize.rb +29 -0
  91. data/lib/right_agent/serialize/message_pack.rb +102 -0
  92. data/lib/right_agent/serialize/secure_serializer.rb +131 -0
  93. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  94. data/lib/right_agent/serialize/serializable.rb +135 -0
  95. data/lib/right_agent/serialize/serializer.rb +149 -0
  96. data/lib/right_agent/stats_helper.rb +731 -0
  97. data/lib/right_agent/subprocess.rb +38 -0
  98. data/lib/right_agent/tracer.rb +124 -0
  99. data/right_agent.gemspec +60 -0
  100. data/spec/actor_registry_spec.rb +81 -0
  101. data/spec/actor_spec.rb +99 -0
  102. data/spec/agent_config_spec.rb +226 -0
  103. data/spec/agent_identity_spec.rb +75 -0
  104. data/spec/agent_spec.rb +571 -0
  105. data/spec/broker_client_spec.rb +961 -0
  106. data/spec/command/agent_manager_commands_spec.rb +51 -0
  107. data/spec/command/command_io_spec.rb +93 -0
  108. data/spec/command/command_parser_spec.rb +79 -0
  109. data/spec/command/command_runner_spec.rb +72 -0
  110. data/spec/command/command_serializer_spec.rb +51 -0
  111. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  112. data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
  113. data/spec/core_payload_types/login_user_spec.rb +98 -0
  114. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  115. data/spec/core_payload_types/spec_helper.rb +23 -0
  116. data/spec/dispatcher_spec.rb +372 -0
  117. data/spec/enrollment_result_spec.rb +53 -0
  118. data/spec/ha_broker_client_spec.rb +1673 -0
  119. data/spec/idempotent_request_spec.rb +136 -0
  120. data/spec/log_spec.rb +177 -0
  121. data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
  122. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  123. data/spec/monkey_patches/string_patch_spec.rb +99 -0
  124. data/spec/multiplexer_spec.rb +48 -0
  125. data/spec/operation_result_spec.rb +171 -0
  126. data/spec/packets_spec.rb +418 -0
  127. data/spec/platform/platform_spec.rb +60 -0
  128. data/spec/results_mock.rb +45 -0
  129. data/spec/secure_identity_spec.rb +50 -0
  130. data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
  131. data/spec/security/certificate_cache_spec.rb +71 -0
  132. data/spec/security/certificate_spec.rb +49 -0
  133. data/spec/security/distinguished_name_spec.rb +46 -0
  134. data/spec/security/encrypted_document_spec.rb +55 -0
  135. data/spec/security/rsa_key_pair_spec.rb +55 -0
  136. data/spec/security/signature_spec.rb +66 -0
  137. data/spec/security/static_certificate_store_spec.rb +52 -0
  138. data/spec/sender_spec.rb +887 -0
  139. data/spec/serialize/message_pack_spec.rb +131 -0
  140. data/spec/serialize/secure_serializer_spec.rb +102 -0
  141. data/spec/serialize/serializable_spec.rb +90 -0
  142. data/spec/serialize/serializer_spec.rb +174 -0
  143. data/spec/spec.opts +2 -0
  144. data/spec/spec_helper.rb +77 -0
  145. data/spec/stats_helper_spec.rb +681 -0
  146. data/spec/tracer_spec.rb +114 -0
  147. metadata +320 -0
@@ -0,0 +1,75 @@
1
+ #
2
+ # Copyright (c) 2009-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
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
24
+
25
+ describe RightScale::AgentIdentity do
26
+
27
+ it 'should create a token if none is provided' do
28
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1)
29
+ id.token.should_not be_nil
30
+ end
31
+
32
+ it 'should create unique tokens' do
33
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1)
34
+ id.token.should_not be_nil
35
+ id2 = RightScale::AgentIdentity.new('prefix', 'agent_type', 1)
36
+ id2.token.should_not be_nil
37
+ id.token.should_not == id2.token
38
+ end
39
+
40
+ it 'should use preset tokens' do
41
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1, 'token')
42
+ id.token.should == 'token'
43
+ end
44
+
45
+ it 'should serialize' do
46
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1, 'token')
47
+ id2 = RightScale::AgentIdentity.parse(id.to_s)
48
+ id2.prefix.should == id.prefix
49
+ id2.agent_type.should == id.agent_type
50
+ id2.base_id.should == id.base_id
51
+ id2.token.should == id.token
52
+ end
53
+
54
+ it 'should validate' do
55
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1, 'token')
56
+ RightScale::AgentIdentity.valid?(id.to_s).should be_true
57
+ end
58
+
59
+ it "should treat serialized id with nanite or mapper prefix as valid" do
60
+ RightScale::AgentIdentity.valid?("nanite-prefix-agent_type-token-1").should be_true
61
+ RightScale::AgentIdentity.valid?("mapper-prefix-agent_type-token-1").should be_true
62
+ end
63
+
64
+ it "should parse serialized id with nanite or mapper prefix but discard this prefix" do
65
+ RightScale::AgentIdentity.parse("nanite-prefix-agent_type-token-1").to_s.should == "prefix-agent_type-token-1"
66
+ RightScale::AgentIdentity.parse("mapper-prefix-agent_type-token-1").to_s.should == "prefix-agent_type-token-1"
67
+ end
68
+
69
+ it 'should prefix with nanite to make backward compatible' do
70
+ id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1, 'token')
71
+ RightScale::AgentIdentity.compatible_serialized(id.to_s, 10).should == "prefix-agent_type-token-1"
72
+ RightScale::AgentIdentity.compatible_serialized(id.to_s, 9).should == "nanite-prefix-agent_type-token-1"
73
+ end
74
+
75
+ end
@@ -0,0 +1,571 @@
1
+ #
2
+ # Copyright (c) 2009-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
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
24
+ require 'tmpdir'
25
+
26
+ def run_in_em(stop_event_loop = true)
27
+ EM.run do
28
+ yield
29
+ EM.stop_event_loop if stop_event_loop
30
+ end
31
+ end
32
+
33
+ describe RightScale::Agent do
34
+
35
+ include FlexMock::ArgumentTypes
36
+
37
+ describe "Default Option" do
38
+
39
+ before(:all) do
40
+ flexmock(RightScale::Log).should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
41
+ flexmock(EM).should_receive(:next_tick).and_yield
42
+ flexmock(EM).should_receive(:add_timer).and_yield
43
+ @timer = flexmock("timer")
44
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer)
45
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer)
46
+ @timer.should_receive(:cancel)
47
+ @broker = flexmock("broker", :subscribe => ["b1"], :publish => ["b1"], :prefetch => true,
48
+ :all => ["b1"], :connected => ["b1"], :failed => [], :close_one => true,
49
+ :non_delivery => true).by_default
50
+ @broker.should_receive(:connection_status).and_yield(:connected)
51
+ flexmock(RightScale::HABrokerClient).should_receive(:new).and_return(@broker)
52
+ flexmock(RightScale::PidFile).should_receive(:new).
53
+ and_return(flexmock("pid file", :check=>true, :write=>true, :remove=>true))
54
+ @identity = "rs-instance-123-1"
55
+ @agent = RightScale::Agent.new(:identity => @identity)
56
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
57
+ @agent.run
58
+ end
59
+
60
+ after(:each) do
61
+ FileUtils.rm_rf(File.normalize_path(File.join(@agent.options[:root_dir], 'config.yml'))) if @agent
62
+ end
63
+
64
+ it "for daemonize is false" do
65
+ @agent.options.should include(:daemonize)
66
+ @agent.options[:daemonize].should == false
67
+ end
68
+
69
+ it "for console is false" do
70
+ @agent.options.should include(:console)
71
+ @agent.options[:console].should == false
72
+ end
73
+
74
+ it "for user is agent" do
75
+ @agent.options.should include(:user)
76
+ @agent.options[:user].should == "agent"
77
+ end
78
+
79
+ it "for pass(word) is testing" do
80
+ @agent.options.should include(:pass)
81
+ @agent.options[:pass].should == "testing"
82
+ end
83
+
84
+ it "for secure is true" do
85
+ @agent.options.should include(:secure)
86
+ @agent.options[:secure].should == true
87
+ end
88
+
89
+ it "for log_level is info" do
90
+ @agent.options.should include(:log_level)
91
+ @agent.options[:log_level].should == :info
92
+ end
93
+
94
+ it "for vhost is /right_net" do
95
+ @agent.options.should include(:vhost)
96
+ @agent.options[:vhost].should == "/right_net"
97
+ end
98
+
99
+ it "for root_dir is #{Dir.pwd}" do
100
+ @agent.options.should include(:root_dir)
101
+ @agent.options[:root_dir].should == Dir.pwd
102
+ end
103
+
104
+ end
105
+
106
+ describe "Options from config.yml" do
107
+
108
+ before(:all) do
109
+ @agent = RightScale::Agent.new(:identity => @identity)
110
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
111
+ @agent.run
112
+ end
113
+
114
+ after(:each) do
115
+ FileUtils.rm_rf(File.normalize_path(File.join(@agent.options[:root_dir], 'config.yml'))) if @agent
116
+ end
117
+
118
+ end
119
+
120
+ describe "Passed in Options" do
121
+
122
+ before(:each) do
123
+ flexmock(RightScale::Log).should_receive(:error).never.by_default
124
+ flexmock(EM).should_receive(:next_tick).and_yield
125
+ flexmock(EM).should_receive(:add_timer).and_yield
126
+ @timer = flexmock("timer")
127
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer)
128
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer)
129
+ @timer.should_receive(:cancel)
130
+ @broker = flexmock("broker", :subscribe => ["b1"], :publish => ["b1"], :prefetch => true,
131
+ :connected => ["b1"], :failed => [], :all => ["b0", "b1"],
132
+ :non_delivery => true).by_default
133
+ @broker.should_receive(:connection_status).and_yield(:connected)
134
+ flexmock(RightScale::HABrokerClient).should_receive(:new).and_return(@broker)
135
+ flexmock(RightScale::PidFile).should_receive(:new).
136
+ and_return(flexmock("pid file", :check=>true, :write=>true, :remove=>true))
137
+ @identity = "rs-instance-123-1"
138
+ @agent = nil
139
+ end
140
+
141
+ after(:each) do
142
+ FileUtils.rm_rf(File.normalize_path(File.join(@agent.options[:root_dir], 'config.yml'))) if @agent
143
+ end
144
+
145
+ it "for user should override default (agent)" do
146
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
147
+ @agent.options.should include(:user)
148
+ @agent.options[:user].should == "me"
149
+ end
150
+
151
+ it "for pass(word) should override default (testing)" do
152
+ @agent = RightScale::Agent.new(:pass => "secret", :identity => @identity)
153
+ @agent.options.should include(:pass)
154
+ @agent.options[:pass].should == "secret"
155
+ end
156
+
157
+ it "for secure should override default (false)" do
158
+ @agent = RightScale::Agent.new(:secure => true, :identity => @identity)
159
+ @agent.options.should include(:secure)
160
+ @agent.options[:secure].should == true
161
+ end
162
+
163
+ it "for host should override default (localhost)" do
164
+ @agent = RightScale::Agent.new(:host => "127.0.0.1", :identity => @identity)
165
+ @agent.options.should include(:host)
166
+ @agent.options[:host].should == "127.0.0.1"
167
+ end
168
+
169
+ it "for log_dir" do
170
+ # testing path, remove it before the test to verify the directory is
171
+ # actually created
172
+ test_log_path = File.normalize_path(File.join(Dir.tmpdir, "right_net", "testing"))
173
+ FileUtils.rm_rf(test_log_path)
174
+
175
+ @agent = RightScale::Agent.new(:log_dir => File.normalize_path(File.join(Dir.tmpdir, "right_net", "testing")),
176
+ :identity => @identity)
177
+
178
+ # passing log_dir will cause log_path to be set to the same value and the
179
+ # directory wil be created
180
+ @agent.options.should include(:log_dir)
181
+ @agent.options[:log_dir].should == test_log_path
182
+
183
+ @agent.options.should include(:log_path)
184
+ @agent.options[:log_path].should == test_log_path
185
+
186
+ File.directory?(@agent.options[:log_path]).should == true
187
+ end
188
+
189
+ it "for log_level should override default (info)" do
190
+ @agent = RightScale::Agent.new(:log_level => :debug, :identity => @identity)
191
+ @agent.options.should include(:log_level)
192
+ @agent.options[:log_level].should == :debug
193
+ end
194
+
195
+ it "for vhost should override default (/right_net)" do
196
+ @agent = RightScale::Agent.new(:vhost => "/virtual_host", :identity => @identity)
197
+ @agent.options.should include(:vhost)
198
+ @agent.options[:vhost].should == "/virtual_host"
199
+ end
200
+
201
+ it "for ping_time should override default (15)" do
202
+ @agent = RightScale::Agent.new(:ping_time => 5, :identity => @identity)
203
+ @agent.options.should include(:ping_time)
204
+ @agent.options[:ping_time].should == 5
205
+ end
206
+
207
+ it "for root_dir should override default (#{File.dirname(__FILE__)})" do
208
+ root_dir = File.normalize_path(File.join(File.dirname(__FILE__), '..', '..'))
209
+ @agent = RightScale::Agent.new(:root_dir => root_dir, :identity => @identity)
210
+ @agent.options.should include(:root_dir)
211
+ @agent.options[:root_dir].should == root_dir
212
+ end
213
+
214
+ it "for a single tag should result in the agent's tags being set" do
215
+ @agent = RightScale::Agent.new(:tag => "sample_tag", :identity => @identity)
216
+ @agent.tags.should include("sample_tag")
217
+ end
218
+
219
+ it "for multiple tags should result in the agent's tags being set" do
220
+ @agent = RightScale::Agent.new(:tag => ["sample_tag_1", "sample_tag_2"], :identity => @identity)
221
+ @agent.tags.should include("sample_tag_1")
222
+ @agent.tags.should include("sample_tag_2")
223
+ end
224
+
225
+ it "for threadpool_size" do
226
+ @agent = RightScale::Agent.new(:threadpool_size => 5, :identity => @identity)
227
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
228
+ @agent.run
229
+ @agent.dispatcher.em.threadpool_size.should == 5
230
+ end
231
+
232
+ end
233
+
234
+ describe "" do
235
+
236
+ before(:each) do
237
+ flexmock(RightScale::Log).should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
238
+ flexmock(EM).should_receive(:next_tick).and_yield
239
+ flexmock(EM).should_receive(:add_timer).and_yield
240
+ @timer = flexmock("timer")
241
+ flexmock(EM::Timer).should_receive(:new).and_return(@timer).by_default
242
+ @timer.should_receive(:cancel).by_default
243
+ @periodic_timer = flexmock("timer")
244
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@periodic_timer)
245
+ @periodic_timer.should_receive(:cancel).by_default
246
+ @broker_id = "rs-broker-123-1"
247
+ @broker_ids = ["rs-broker-123-1", "rs-broker-123-2"]
248
+ @broker = flexmock("broker", :subscribe => @broker_ids, :publish => @broker_ids.first(1), :prefetch => true,
249
+ :all => @broker_ids, :connected => @broker_ids.first(1), :failed => @broker_ids.last(1),
250
+ :unusable => @broker_ids.last(1), :close_one => true, :non_delivery => true,
251
+ :stats => "", :identity_parts => ["123", 2, 1, 1, nil], :status => "status",
252
+ :hosts => ["123"], :ports => [1, 2], :get => true, :alias_ => "b1",
253
+ :aliases => ["b1"]).by_default
254
+ @broker.should_receive(:connection_status).and_yield(:connected)
255
+ flexmock(RightScale::HABrokerClient).should_receive(:new).and_return(@broker)
256
+ flexmock(RightScale::PidFile).should_receive(:new).
257
+ and_return(flexmock("pid file", :check=>true, :write=>true, :remove=>true))
258
+ @sender = flexmock("sender", :pending_requests => [], :request_age => nil,
259
+ :message_received => true, :stats => "").by_default
260
+ @sender.should_receive(:terminate).and_return([0, 0]).by_default
261
+ flexmock(RightScale::Sender).should_receive(:new).and_return(@sender)
262
+ @dispatcher = flexmock("dispatcher", :dispatch_age => nil, :dispatch => true, :stats => "").by_default
263
+ flexmock(RightScale::Dispatcher).should_receive(:new).and_return(@dispatcher)
264
+ @identity = "rs-instance-123-1"
265
+ @agent = RightScale::Agent.new(:user => "tester", :identity => @identity)
266
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
267
+ end
268
+
269
+ after(:each) do
270
+ FileUtils.rm_rf(File.normalize_path(File.join(@agent.options[:root_dir], 'config.yml'))) if @agent
271
+ end
272
+
273
+ describe "Setting up queues" do
274
+
275
+ it "should subscribe to identity queue using identity exchange" do
276
+ run_in_em do
277
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).and_return(@broker_ids).once
278
+ @agent.run
279
+ end
280
+ end
281
+
282
+ it "should try to finish setup by connecting to failed brokers when check status" do
283
+ run_in_em do
284
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
285
+ and_return(@broker_ids.first(1)).once
286
+ @agent.run
287
+ @agent.instance_variable_get(:@remaining_setup).should == {:setup_identity_queue => @broker_ids.last(1)}
288
+ @sender.should_receive(:send_push).with("/registrar/connect", {:agent_identity => @identity, :host => "123",
289
+ :port => 2, :id => 1, :priority => 1}).once
290
+ @agent.__send__(:check_status)
291
+ end
292
+ end
293
+
294
+ it "should try to connect to broker when requested" do
295
+ run_in_em do
296
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
297
+ and_return(@broker_ids.first(1)).once
298
+ @agent.run
299
+ @broker.should_receive(:connect).with("123", 2, 1, 1, nil, false, Proc).once
300
+ @agent.connect("123", 2, 1, 1)
301
+ end
302
+ end
303
+
304
+ it "should setup queues and update configuration when successfully connect to broker" do
305
+ run_in_em do
306
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
307
+ and_return(@broker_ids.first(1)).once
308
+ @agent.run
309
+ @broker.should_receive(:connect).with("123", 2, 1, 1, nil, false, Proc).and_yield(@broker_ids.last).once
310
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => @broker_ids.last(1)), Proc).
311
+ and_return(@broker_ids.last(1)).once
312
+ flexmock(@agent).should_receive(:update_configuration).with(:host => ["123"], :port => [1, 2]).and_return(true).once
313
+ @agent.connect("123", 2, 1, 1)
314
+ end
315
+ end
316
+
317
+ it "should log error if fail to connect to broker" do
318
+ run_in_em do
319
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
320
+ and_return(@broker_ids.first(1)).once
321
+ @agent.run
322
+ @broker.should_receive(:connect).with("123", 2, 1, 1, nil, false, Proc).and_yield(@broker_ids.last).once
323
+ @broker.should_receive(:connection_status).and_yield(:failed)
324
+ flexmock(RightScale::Log).should_receive(:error).with(/Failed to connect to broker/).once
325
+ flexmock(@agent).should_receive(:update_configuration).never
326
+ @agent.connect("123", 2, 1, 1)
327
+ end
328
+ end
329
+
330
+ it "should disconnect from broker when requested" do
331
+ run_in_em do
332
+ @broker.should_receive(:connected).and_return(@broker_ids)
333
+ @broker.should_receive(:failed).and_return([])
334
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
335
+ and_return(@broker_ids).once
336
+ @agent.run
337
+ @broker.should_receive(:close_one).with(@broker_ids.last).once
338
+ @agent.disconnect("123", 2)
339
+ end
340
+ end
341
+
342
+ it "should remove broker from configuration if requested" do
343
+ run_in_em do
344
+ @broker.should_receive(:connected).and_return(@broker_ids)
345
+ @broker.should_receive(:failed).and_return([])
346
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
347
+ and_return(@broker_ids).once
348
+ @agent.run
349
+ @broker.should_receive(:remove).with("123", 2, Proc).and_yield(@broker_ids.last).once
350
+ @broker.should_receive(:ports).and_return([1])
351
+ flexmock(@agent).should_receive(:update_configuration).with(:host => ["123"], :port => [1]).and_return(true).once
352
+ @agent.disconnect("123", 2, remove = true)
353
+ end
354
+ end
355
+
356
+ it "should not disconnect broker if it is the last connected broker" do
357
+ run_in_em do
358
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, hsh(:brokers => nil), Proc).
359
+ and_return(@broker_ids.first(1)).once
360
+ @agent.run
361
+ @broker.should_receive(:remove).never
362
+ @broker.should_receive(:close_one).never
363
+ flexmock(@agent).should_receive(:update_configuration).never
364
+ flexmock(RightScale::Log).should_receive(:error).with(/Not disconnecting.*last connected broker/).once
365
+ @agent.disconnect("123", 1)
366
+ end
367
+ end
368
+
369
+ it "should declare broker connection unusable if requested to do so" do
370
+ run_in_em do
371
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).and_return(@broker_ids).once
372
+ @agent.run
373
+ @broker.should_receive(:declare_unusable).with(@broker_ids.last(1)).once
374
+ @agent.connect_failed(@broker_ids.last(1))
375
+ end
376
+ end
377
+
378
+ it "should not declare a broker connection unusable if currently connected" do
379
+ run_in_em do
380
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).and_return(@broker_ids).once
381
+ @agent.run
382
+ @broker.should_receive(:declare_unusable).with([]).once
383
+ @agent.connect_failed(@broker_ids.first(1))
384
+ end
385
+ end
386
+
387
+ end
388
+
389
+ describe "Handling messages" do
390
+
391
+ it "should use dispatcher to handle requests" do
392
+ run_in_em do
393
+ request = RightScale::Request.new("/foo/bar", "payload")
394
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).
395
+ and_return(@broker_ids).and_yield(@broker_id, request).once
396
+ @dispatcher.should_receive(:dispatch).with(request).once
397
+ @agent.run
398
+ end
399
+ end
400
+
401
+ it "should use sender to handle results" do
402
+ run_in_em do
403
+ result = RightScale::Result.new("token", "to", "results", "from")
404
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).
405
+ and_return(@broker_ids).and_yield(@broker_id, result).once
406
+ @sender.should_receive(:handle_response).with(result).once
407
+ @agent.run
408
+ end
409
+ end
410
+
411
+ it "should notify sender when a message is received" do
412
+ run_in_em do
413
+ result = RightScale::Result.new("token", "to", "results", "from")
414
+ @broker.should_receive(:subscribe).with(hsh(:name => @identity), nil, Hash, Proc).
415
+ and_return(@broker_ids).and_yield(@broker_id, result).once
416
+ @sender.should_receive(:handle_response).with(result).once
417
+ @sender.should_receive(:message_received).once
418
+ @agent.run
419
+ end
420
+ end
421
+
422
+ end
423
+
424
+ describe "Terminating" do
425
+
426
+ it "should close unusable broker connections at start of termination" do
427
+ @broker.should_receive(:unusable).and_return(["rs-broker-123-1"]).once
428
+ @broker.should_receive(:close_one).with("rs-broker-123-1", false).once
429
+ run_in_em do
430
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
431
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
432
+ @agent.run
433
+ @agent.terminate
434
+ end
435
+ end
436
+
437
+ it "should wait to terminate if there are recent unfinished requests" do
438
+ @sender.should_receive(:terminate).and_return([1, 10]).once
439
+ flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).once
440
+ run_in_em do
441
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
442
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
443
+ @agent.run
444
+ @agent.terminate
445
+ end
446
+ end
447
+
448
+ it "should wait to terminate if there are recent dispatches" do
449
+ @sender.should_receive(:terminate).and_return([0, 20]).once
450
+ @dispatcher.should_receive(:dispatch_age).and_return(20).and_return(@timer).once
451
+ flexmock(EM::Timer).should_receive(:new).with(10, Proc).once
452
+ run_in_em do
453
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
454
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
455
+ @agent.run
456
+ @agent.terminate
457
+ end
458
+ end
459
+
460
+ it "should wait to terminate if there are recent unfinished requests or recent dispatches" do
461
+ @sender.should_receive(:terminate).and_return([1, 21]).once
462
+ @dispatcher.should_receive(:dispatch_age).and_return(22).once
463
+ flexmock(EM::Timer).should_receive(:new).with(9, Proc).and_return(@timer).once
464
+ run_in_em do
465
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
466
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
467
+ @agent.run
468
+ @agent.terminate
469
+ end
470
+ end
471
+
472
+ it "should log that terminating and then log the reason for waiting to terminate" do
473
+ @sender.should_receive(:terminate).and_return([1, 21]).once
474
+ @dispatcher.should_receive(:dispatch_age).and_return(22).once
475
+ flexmock(EM::Timer).should_receive(:new).with(9, Proc).and_return(@timer).once
476
+ run_in_em do
477
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
478
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
479
+ @agent.run
480
+ flexmock(RightScale::Log).should_receive(:info).with(/Agent rs-instance-123-1 terminating/).once
481
+ flexmock(RightScale::Log).should_receive(:info).with(/Termination waiting 9 seconds for/).once
482
+ @agent.terminate
483
+ end
484
+ end
485
+
486
+ it "should not log reason for waiting to terminate if no need to wait" do
487
+ @sender.should_receive(:terminate).and_return([0, nil]).twice
488
+ @dispatcher.should_receive(:dispatch_age).and_return(nil).once
489
+ @broker.should_receive(:close).once
490
+ flexmock(EM::Timer).should_receive(:new).with(0, Proc).never
491
+ run_in_em do
492
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
493
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
494
+ @agent.run
495
+ flexmock(RightScale::Log).should_receive(:info).with(/Agent rs-instance-123-1 terminating/).once
496
+ flexmock(RightScale::Log).should_receive(:info).with(/Termination waiting/).never
497
+ @agent.terminate
498
+ end
499
+ end
500
+
501
+ it "should continue with termination after waiting and log that continuing" do
502
+ @sender.should_receive(:terminate).and_return([1, 10]).twice
503
+ @sender.should_receive(:dump_requests).and_return(["request"]).once
504
+ @dispatcher.should_receive(:dispatch_age).and_return(10).once
505
+ @broker.should_receive(:close).once
506
+ flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).and_yield.once
507
+ run_in_em do
508
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
509
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
510
+ @agent.run
511
+ flexmock(RightScale::Log).should_receive(:info).with(/Agent rs-instance-123-1 terminating/).once
512
+ flexmock(RightScale::Log).should_receive(:info).with(/Termination waiting/).once
513
+ flexmock(RightScale::Log).should_receive(:info).with(/Continuing with termination/).once
514
+ flexmock(RightScale::Log).should_receive(:info).with(/The following 1 request/).once
515
+ @agent.terminate
516
+ end
517
+ end
518
+
519
+ it "should execute block after all brokers have been closed" do
520
+ @sender.should_receive(:terminate).and_return([1, 10]).twice
521
+ @sender.should_receive(:dump_requests).and_return(["request"]).once
522
+ @dispatcher.should_receive(:dispatch_age).and_return(10).once
523
+ @broker.should_receive(:close).and_yield.once
524
+ flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).and_yield.once
525
+ run_in_em do
526
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
527
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
528
+ @agent.run
529
+ called = 0
530
+ @agent.terminate { called += 1 }
531
+ called.should == 1
532
+ end
533
+ end
534
+
535
+ it "should stop EM if no block specified" do
536
+ @sender.should_receive(:terminate).and_return([1, 10]).twice
537
+ @sender.should_receive(:dump_requests).and_return(["request"]).once
538
+ @dispatcher.should_receive(:dispatch_age).and_return(10).once
539
+ @broker.should_receive(:close).once
540
+ flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).and_yield.once
541
+ run_in_em(stop_event_loop = false) do
542
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
543
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
544
+ @agent.run
545
+ @agent.terminate
546
+ end
547
+ end
548
+
549
+ it "should terminate immediately if called a second time but should still execute block" do
550
+ @sender.should_receive(:terminate).and_return([1, 10]).once
551
+ @dispatcher.should_receive(:dispatch_age).and_return(10).once
552
+ flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).once
553
+ @timer.should_receive(:cancel).once
554
+ @periodic_timer.should_receive(:cancel).once
555
+ run_in_em do
556
+ @agent = RightScale::Agent.new(:user => "me", :identity => @identity)
557
+ flexmock(@agent).should_receive(:load_actors).and_return(true)
558
+ @agent.run
559
+ called = 0
560
+ @agent.terminate { called += 1 }
561
+ called.should == 0
562
+ @agent.terminate { called += 1 }
563
+ called.should == 1
564
+ end
565
+ end
566
+
567
+ end
568
+
569
+ end
570
+
571
+ end