right_agent 1.0.1 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +10 -8
- data/Rakefile +31 -5
- data/lib/right_agent.rb +6 -1
- data/lib/right_agent/actor.rb +4 -20
- data/lib/right_agent/actors/agent_manager.rb +1 -1
- data/lib/right_agent/agent.rb +357 -144
- data/lib/right_agent/agent_config.rb +7 -6
- data/lib/right_agent/agent_identity.rb +13 -11
- data/lib/right_agent/agent_tag_manager.rb +60 -64
- data/{spec/results_mock.rb → lib/right_agent/clients.rb} +10 -24
- data/lib/right_agent/clients/api_client.rb +383 -0
- data/lib/right_agent/clients/auth_client.rb +247 -0
- data/lib/right_agent/clients/balanced_http_client.rb +369 -0
- data/lib/right_agent/clients/base_retry_client.rb +495 -0
- data/lib/right_agent/clients/right_http_client.rb +279 -0
- data/lib/right_agent/clients/router_client.rb +493 -0
- data/lib/right_agent/command/command_io.rb +4 -4
- data/lib/right_agent/command/command_parser.rb +2 -2
- data/lib/right_agent/command/command_runner.rb +1 -1
- data/lib/right_agent/connectivity_checker.rb +179 -0
- data/lib/right_agent/core_payload_types/secure_document_location.rb +2 -2
- data/lib/right_agent/dispatcher.rb +12 -10
- data/lib/right_agent/enrollment_result.rb +16 -12
- data/lib/right_agent/exceptions.rb +34 -20
- data/lib/right_agent/history.rb +10 -5
- data/lib/right_agent/log.rb +5 -5
- data/lib/right_agent/minimal.rb +1 -0
- data/lib/right_agent/multiplexer.rb +1 -1
- data/lib/right_agent/offline_handler.rb +270 -0
- data/lib/right_agent/packets.rb +7 -7
- data/lib/right_agent/payload_formatter.rb +1 -1
- data/lib/right_agent/pending_requests.rb +128 -0
- data/lib/right_agent/platform.rb +1 -1
- data/lib/right_agent/protocol_version_mixin.rb +69 -0
- data/lib/right_agent/{idempotent_request.rb → retryable_request.rb} +7 -7
- data/lib/right_agent/scripts/agent_controller.rb +28 -26
- data/lib/right_agent/scripts/agent_deployer.rb +37 -22
- data/lib/right_agent/scripts/common_parser.rb +10 -3
- data/lib/right_agent/secure_identity.rb +1 -1
- data/lib/right_agent/sender.rb +299 -785
- data/lib/right_agent/serialize/secure_serializer.rb +3 -1
- data/lib/right_agent/serialize/secure_serializer_initializer.rb +2 -2
- data/lib/right_agent/serialize/serializable.rb +8 -3
- data/right_agent.gemspec +49 -18
- data/spec/agent_config_spec.rb +7 -7
- data/spec/agent_identity_spec.rb +7 -4
- data/spec/agent_spec.rb +43 -7
- data/spec/agent_tag_manager_spec.rb +72 -83
- data/spec/clients/api_client_spec.rb +423 -0
- data/spec/clients/auth_client_spec.rb +272 -0
- data/spec/clients/balanced_http_client_spec.rb +576 -0
- data/spec/clients/base_retry_client_spec.rb +635 -0
- data/spec/clients/router_client_spec.rb +594 -0
- data/spec/clients/spec_helper.rb +111 -0
- data/spec/command/command_io_spec.rb +1 -1
- data/spec/command/command_parser_spec.rb +1 -1
- data/spec/connectivity_checker_spec.rb +83 -0
- data/spec/dispatcher_spec.rb +3 -2
- data/spec/enrollment_result_spec.rb +2 -2
- data/spec/history_spec.rb +51 -39
- data/spec/offline_handler_spec.rb +340 -0
- data/spec/pending_requests_spec.rb +136 -0
- data/spec/{idempotent_request_spec.rb → retryable_request_spec.rb} +73 -73
- data/spec/sender_spec.rb +835 -1052
- data/spec/serialize/secure_serializer_spec.rb +3 -2
- data/spec/spec_helper.rb +54 -1
- metadata +71 -12
@@ -26,6 +26,8 @@ module RightScale
|
|
26
26
|
# X.509 certificate signing
|
27
27
|
class SecureSerializer
|
28
28
|
|
29
|
+
include ProtocolVersionMixin
|
30
|
+
|
29
31
|
class MissingPrivateKey < Exception; end
|
30
32
|
class MissingCertificate < Exception; end
|
31
33
|
class InvalidSignature < Exception; end
|
@@ -90,7 +92,7 @@ module RightScale
|
|
90
92
|
# Exception:: If certificate identity, certificate store, certificate, or private key missing
|
91
93
|
def dump(obj, encrypt = nil)
|
92
94
|
must_encrypt = encrypt || @encrypt
|
93
|
-
serialize_format = if obj.respond_to?(:send_version) && obj.send_version
|
95
|
+
serialize_format = if obj.respond_to?(:send_version) && can_handle_msgpack_result?(obj.send_version)
|
94
96
|
@serializer.format
|
95
97
|
else
|
96
98
|
:json
|
@@ -36,8 +36,8 @@ module RightScale
|
|
36
36
|
def self.init(agent_type, agent_id)
|
37
37
|
cert = Certificate.load(AgentConfig.certs_file("#{agent_type}.cert"))
|
38
38
|
key = RsaKeyPair.load(AgentConfig.certs_file("#{agent_type}.key"))
|
39
|
-
|
40
|
-
store = StaticCertificateStore.new(cert, key,
|
39
|
+
router_cert = Certificate.load(AgentConfig.certs_file("router.cert"))
|
40
|
+
store = StaticCertificateStore.new(cert, key, router_cert, router_cert)
|
41
41
|
SecureSerializer.init(Serializer.new, agent_id, store)
|
42
42
|
true
|
43
43
|
end
|
@@ -128,6 +128,7 @@ module RightScale
|
|
128
128
|
|
129
129
|
# Symbolize keys of hash, use when retrieving hashes that use symbols
|
130
130
|
# for keys as JSON and MessagePack serialization will produce strings instead
|
131
|
+
# Simply return any object that is not a hash as is
|
131
132
|
#
|
132
133
|
# === Parameters
|
133
134
|
# hash(Hash):: Hash whose keys are to be symbolized
|
@@ -135,9 +136,13 @@ module RightScale
|
|
135
136
|
# === Return
|
136
137
|
# (Hash):: Hash with same values but symbol keys
|
137
138
|
def self.symbolize_keys(hash)
|
138
|
-
hash.
|
139
|
-
|
140
|
-
|
139
|
+
if hash.is_a?(Hash)
|
140
|
+
hash.inject({}) do |h, (key, value)|
|
141
|
+
h[(key.to_sym rescue key) || key] = value
|
142
|
+
h
|
143
|
+
end
|
144
|
+
else
|
145
|
+
hash
|
141
146
|
end
|
142
147
|
end
|
143
148
|
|
data/right_agent.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*-ruby-*-
|
2
|
-
# Copyright: Copyright (c) 2011 RightScale, Inc.
|
2
|
+
# Copyright: Copyright (c) 2011-2013 RightScale, Inc.
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -21,11 +21,12 @@
|
|
21
21
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
23
|
require 'rubygems'
|
24
|
+
require 'rbconfig'
|
24
25
|
|
25
26
|
Gem::Specification.new do |spec|
|
26
27
|
spec.name = 'right_agent'
|
27
|
-
spec.version = '
|
28
|
-
spec.date = '
|
28
|
+
spec.version = '2.0.7'
|
29
|
+
spec.date = '2014-02-28'
|
29
30
|
spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro', 'Scott Messier']
|
30
31
|
spec.email = 'lee@rightscale.com'
|
31
32
|
spec.homepage = 'https://github.com/rightscale/right_agent'
|
@@ -39,29 +40,59 @@ Gem::Specification.new do |spec|
|
|
39
40
|
|
40
41
|
spec.add_dependency('right_support', ['>= 2.4.1', '< 3.0'])
|
41
42
|
spec.add_dependency('right_amqp', '~> 0.7')
|
43
|
+
spec.add_dependency('rest-client', '1.7.0.alpha')
|
44
|
+
spec.add_dependency('faye-websocket', '0.7.0')
|
42
45
|
spec.add_dependency('eventmachine', ['>= 0.12.10', '< 2.0'])
|
43
46
|
spec.add_dependency('net-ssh', '~> 2.0')
|
44
47
|
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
# TEAL HACK: rake gem may override current RUBY_PLATFORM to allow building
|
49
|
+
# gems for all supported platforms from any platform. rubygems 1.8.x makes it
|
50
|
+
# necessary to produce platform-specific gems with context-sensitive gemspecs
|
51
|
+
# in order to retain Windows (or Linux)-specific gem requirements. this works
|
52
|
+
# from any platform because there is no native code to pre-compile and package
|
53
|
+
# with this gem.
|
54
|
+
gem_platform = defined?(::RightScale::MultiPlatformGemTask.gem_platform_override) ?
|
55
|
+
::RightScale::MultiPlatformGemTask.gem_platform_override :
|
56
|
+
nil
|
57
|
+
gem_platform ||= ::RbConfig::CONFIG['host_os']
|
58
|
+
case gem_platform
|
59
|
+
when /mswin/i
|
60
|
+
spec.add_dependency('win32-api', ['>= 1.4.5', '< 1.4.7'])
|
61
|
+
spec.add_dependency('win32-dir', '~> 0.3.5')
|
62
|
+
spec.add_dependency('win32-process', '~> 0.6.1')
|
63
|
+
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.5'])
|
64
|
+
spec.add_dependency('json', '1.4.6')
|
65
|
+
spec.platform = 'x86-mswin32-60'
|
66
|
+
when /mingw/i
|
67
|
+
spec.add_dependency('ffi')
|
68
|
+
spec.add_dependency('win32-dir', '>= 0.3.5')
|
69
|
+
spec.add_dependency('win32-process', '>= 0.6.1')
|
70
|
+
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.6'])
|
71
|
+
spec.add_dependency('json', '~> 1.4')
|
72
|
+
spec.platform = 'x86-mingw32'
|
73
|
+
when /win32|dos|cygwin|windows/i
|
52
74
|
raise ::NotImplementedError, 'Unsupported Ruby-on-Windows variant'
|
75
|
+
else
|
76
|
+
# ffi is not currently needed by Linux but it does no harm to have it and it
|
77
|
+
# allows bundler to generate a consistent Gemfile.lock when it is declared
|
78
|
+
# for both mingw and Linux.
|
79
|
+
spec.add_dependency('ffi')
|
80
|
+
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.6'])
|
81
|
+
spec.add_dependency('json', '~> 1.4')
|
53
82
|
end
|
54
|
-
spec.add_dependency('msgpack', ['>= 0.4.4', '< 0.6'])
|
55
|
-
spec.add_dependency('json', '~> 1.4')
|
56
83
|
|
57
84
|
spec.description = <<-EOF
|
58
85
|
RightAgent provides a foundation for running an agent on a server to interface
|
59
|
-
in a secure fashion with other agents in the RightScale system
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
86
|
+
in a secure fashion with other agents in the RightScale system using RightNet,
|
87
|
+
which operates in either HTTP or AMQP mode. When using HTTP, RightAgent
|
88
|
+
makes requests to RightApi servers and receives requests using long-polling or
|
89
|
+
WebSockets via the RightNet router. To respond to requests it posts to the
|
90
|
+
HTTP router. When using AMQP, RightAgent uses RabbitMQ as the message bus and
|
91
|
+
the RightNet router as the routing node to make requests; to receives requests
|
92
|
+
routed to it by the RightNet router, it establishes a queue on startup. The
|
93
|
+
packets are structured to invoke services in the agent represented by actors
|
94
|
+
and methods. The RightAgent may respond to these requests with a result packet
|
95
|
+
that the router then routes to the originator.
|
65
96
|
EOF
|
66
97
|
|
67
98
|
candidates = Dir.glob("{lib,spec}/**/*") +
|
data/spec/agent_config_spec.rb
CHANGED
@@ -43,10 +43,10 @@ describe RightScale::AgentConfig do
|
|
43
43
|
@actors = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'right_agent', 'actors'))
|
44
44
|
FileUtils.mkdir_p(@certs1 = File.join(@root_dir1, 'certs'))
|
45
45
|
FileUtils.mkdir_p(@certs2 = File.join(@root_dir2, 'certs'))
|
46
|
-
FileUtils.touch([@
|
47
|
-
FileUtils.touch([@
|
46
|
+
FileUtils.touch([@router_cert1 = File.join(@certs1, 'router.cert')])
|
47
|
+
FileUtils.touch([@router_cert2 = File.join(@certs2, 'router.cert')])
|
48
48
|
FileUtils.touch([@agent_cert2 = File.join(@certs2, 'agent.cert')])
|
49
|
-
FileUtils.touch([@
|
49
|
+
FileUtils.touch([@router_key2 = File.join(@certs2, 'router.key')])
|
50
50
|
FileUtils.mkdir_p(@lib1 = File.join(@root_dir1, 'lib'))
|
51
51
|
FileUtils.mkdir_p(@scripts3 = File.join(@root_dir3, 'scripts'))
|
52
52
|
FileUtils.mkdir_p(@cfg_dir = File.join(@test_dir, 'cfg'))
|
@@ -150,15 +150,15 @@ describe RightScale::AgentConfig do
|
|
150
150
|
|
151
151
|
it 'should return first certs file path found' do
|
152
152
|
@agent_config.root_dir = [@root_dir1, @root_dir2, @root_dir3]
|
153
|
-
@agent_config.certs_file('
|
154
|
-
@agent_config.certs_file('
|
153
|
+
@agent_config.certs_file('router.cert').should == @router_cert1
|
154
|
+
@agent_config.certs_file('router.key').should == @router_key2
|
155
155
|
@agent_config.certs_file('agent.key').should be_nil
|
156
156
|
end
|
157
157
|
|
158
158
|
it 'should return all certs file paths found without any duplicates and by root directory order' do
|
159
159
|
@agent_config.root_dir = [@root_dir1, @root_dir2, @root_dir3]
|
160
|
-
@agent_config.certs_files('*.cert').should == [@
|
161
|
-
@agent_config.certs_files('*.key').should == [@
|
160
|
+
@agent_config.certs_files('*.cert').should == [@router_cert1, @agent_cert2]
|
161
|
+
@agent_config.certs_files('*.key').should == [@router_key2]
|
162
162
|
@agent_config.certs_files('*.abc').should == []
|
163
163
|
end
|
164
164
|
|
data/spec/agent_identity_spec.rb
CHANGED
@@ -56,20 +56,23 @@ describe RightScale::AgentIdentity do
|
|
56
56
|
RightScale::AgentIdentity.valid?(id.to_s).should be_true
|
57
57
|
end
|
58
58
|
|
59
|
-
it "should treat serialized id with nanite or
|
59
|
+
it "should treat serialized id with nanite, mapper, or router prefix as valid" do
|
60
60
|
RightScale::AgentIdentity.valid?("nanite-prefix-agent_type-token-1").should be_true
|
61
61
|
RightScale::AgentIdentity.valid?("mapper-prefix-agent_type-token-1").should be_true
|
62
|
+
RightScale::AgentIdentity.valid?("router-prefix-agent_type-token-1").should be_true
|
62
63
|
end
|
63
64
|
|
64
|
-
it "should parse serialized id with nanite or
|
65
|
+
it "should parse serialized id with nanite, mapper, or router prefix but discard this prefix" do
|
65
66
|
RightScale::AgentIdentity.parse("nanite-prefix-agent_type-token-1").to_s.should == "prefix-agent_type-token-1"
|
66
67
|
RightScale::AgentIdentity.parse("mapper-prefix-agent_type-token-1").to_s.should == "prefix-agent_type-token-1"
|
68
|
+
RightScale::AgentIdentity.parse("router-prefix-agent_type-token-1").to_s.should == "prefix-agent_type-token-1"
|
67
69
|
end
|
68
70
|
|
69
71
|
it 'should prefix with nanite to make backward compatible' do
|
70
72
|
id = RightScale::AgentIdentity.new('prefix', 'agent_type', 1, 'token')
|
71
|
-
RightScale::AgentIdentity.compatible_serialized(id.to_s,
|
72
|
-
RightScale::AgentIdentity.compatible_serialized(id.to_s,
|
73
|
+
RightScale::AgentIdentity.compatible_serialized(id.to_s, version_can_handle_non_nanite_ids).should == "prefix-agent_type-token-1"
|
74
|
+
RightScale::AgentIdentity.compatible_serialized(id.to_s, version_cannot_handle_non_nanite_ids).should == "nanite-prefix-agent_type-token-1"
|
75
|
+
RightScale::AgentIdentity.compatible_serialized(id.to_s).should == "prefix-agent_type-token-1"
|
73
76
|
end
|
74
77
|
|
75
78
|
end
|
data/spec/agent_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2013 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -309,7 +309,7 @@ describe RightScale::Agent do
|
|
309
309
|
@agent.instance_variable_get(:@remaining_queue_setup).should == {@identity => @broker_ids.last(1)}
|
310
310
|
@sender.should_receive(:send_push).with("/registrar/connect", {:agent_identity => @identity, :host => "123",
|
311
311
|
:port => 2, :id => 1, :priority => 1}).once
|
312
|
-
@agent.
|
312
|
+
@agent.send(:check_status)
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
@@ -539,6 +539,38 @@ describe RightScale::Agent do
|
|
539
539
|
end
|
540
540
|
end
|
541
541
|
|
542
|
+
it "should sleep before an abnormal termination that is following a crash" do
|
543
|
+
run_in_em do
|
544
|
+
@agent = RightScale::Agent.new(:user => "me", :identity => @identity)
|
545
|
+
@broker.should_receive(:nil?).and_return(true)
|
546
|
+
@log.should_receive(:error).with(/Terminating because just because/, Exception, :trace).once
|
547
|
+
@log.should_receive(:info).with(/Delaying termination for 10 sec/).once.ordered
|
548
|
+
@log.should_receive(:info).with(/Terminating immediately/).once.ordered
|
549
|
+
now = Time.now
|
550
|
+
flexmock(Time).should_receive(:now).and_return(now)
|
551
|
+
flexmock(@agent.instance_variable_get(:@history)).should_receive(:analyze_service).
|
552
|
+
and_return({:last_crashed => true, :last_crash_time => now.to_i - 5}).once
|
553
|
+
flexmock(@agent).should_receive(:sleep).with(10).once
|
554
|
+
@agent.terminate("just because", Exception.new("error"))
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
it "should limit the sleep time before an abnormal termination" do
|
559
|
+
run_in_em do
|
560
|
+
@agent = RightScale::Agent.new(:user => "me", :identity => @identity)
|
561
|
+
@broker.should_receive(:nil?).and_return(true)
|
562
|
+
@log.should_receive(:error).with(/Terminating because just because/, Exception, :trace).once
|
563
|
+
@log.should_receive(:info).with(/Delaying termination for 60 min 0 sec/).once.ordered
|
564
|
+
@log.should_receive(:info).with(/Terminating immediately/).once.ordered
|
565
|
+
now = Time.now
|
566
|
+
flexmock(Time).should_receive(:now).and_return(now)
|
567
|
+
flexmock(@agent.instance_variable_get(:@history)).should_receive(:analyze_service).
|
568
|
+
and_return({:last_crashed => true, :last_crash_time => now.to_i - 1801}).once
|
569
|
+
flexmock(@agent).should_receive(:sleep).with(3600).once
|
570
|
+
@agent.terminate("just because", Exception.new("error"))
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
542
574
|
it "should close unusable broker connections at start of termination" do
|
543
575
|
@broker.should_receive(:unusable).and_return(["rs-broker-123-1"]).once
|
544
576
|
@broker.should_receive(:close_one).with("rs-broker-123-1", false).once
|
@@ -611,11 +643,13 @@ describe RightScale::Agent do
|
|
611
643
|
@broker.should_receive(:close).and_yield.once
|
612
644
|
flexmock(EM::Timer).should_receive(:new).with(20, Proc).and_return(@timer).and_yield.once
|
613
645
|
run_in_em do
|
646
|
+
called = 0
|
647
|
+
callback = lambda { called += 1}
|
614
648
|
@agent = RightScale::Agent.new(:user => "me", :identity => @identity)
|
649
|
+
@agent.instance_variable_set(:@terminate_callback, callback)
|
615
650
|
flexmock(@agent).should_receive(:load_actors).and_return(true)
|
616
651
|
@agent.run
|
617
|
-
|
618
|
-
@agent.terminate { called += 1 }
|
652
|
+
@agent.terminate
|
619
653
|
called.should == 1
|
620
654
|
end
|
621
655
|
end
|
@@ -647,13 +681,15 @@ describe RightScale::Agent do
|
|
647
681
|
@timer.should_receive(:cancel).once
|
648
682
|
@periodic_timer.should_receive(:cancel).once
|
649
683
|
run_in_em do
|
684
|
+
called = 0
|
685
|
+
callback = lambda { called += 1}
|
650
686
|
@agent = RightScale::Agent.new(:user => "me", :identity => @identity)
|
687
|
+
@agent.instance_variable_set(:@terminate_callback, callback)
|
651
688
|
flexmock(@agent).should_receive(:load_actors).and_return(true)
|
652
689
|
@agent.run
|
653
|
-
|
654
|
-
@agent.terminate { called += 1 }
|
690
|
+
@agent.terminate
|
655
691
|
called.should == 0
|
656
|
-
@agent.terminate
|
692
|
+
@agent.terminate
|
657
693
|
called.should == 1
|
658
694
|
end
|
659
695
|
end
|
@@ -29,18 +29,18 @@ describe RightScale::AgentTagManager do
|
|
29
29
|
before(:each) do
|
30
30
|
@log = flexmock(RightScale::Log)
|
31
31
|
@log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
|
32
|
-
@identity = "rs-agent-
|
33
|
-
@
|
34
|
-
@
|
35
|
-
@
|
36
|
-
@
|
32
|
+
@identity = "rs-agent-1-1"
|
33
|
+
@agent_href = "/api/clouds/1/instances/1"
|
34
|
+
@agent_href2 = "/api/clouds/2/instances/2"
|
35
|
+
@agent = flexmock("agent", :self_href => @agent_href, :identity => @identity)
|
36
|
+
@hrefs = [@agent_href, @agent_href2]
|
37
37
|
@manager = RightScale::AgentTagManager.instance
|
38
38
|
@manager.agent = @agent
|
39
39
|
@request = flexmock("request", :run => true)
|
40
40
|
@request.should_receive(:callback).and_yield("result").by_default
|
41
41
|
@request.should_receive(:errback).by_default
|
42
42
|
@request.should_receive(:raw_response).and_return("raw response").by_default
|
43
|
-
@
|
43
|
+
@retryable_request = flexmock(RightScale::RetryableRequest)
|
44
44
|
@tag = "some:tag=value"
|
45
45
|
@tag1 = "other:tag=value"
|
46
46
|
@tags = [@tag, @tag1]
|
@@ -50,13 +50,12 @@ describe RightScale::AgentTagManager do
|
|
50
50
|
context :tags do
|
51
51
|
|
52
52
|
before(:each) do
|
53
|
-
@
|
54
|
-
|
55
|
-
{}).and_return(@request).once.by_default
|
53
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
54
|
+
{:agent_identity => @identity, :hrefs => [@agent_href]}, {}).and_return(@request).once.by_default
|
56
55
|
end
|
57
56
|
|
58
57
|
it "retrieves current agent tags" do
|
59
|
-
@request.should_receive(:callback).and_yield({@
|
58
|
+
@request.should_receive(:callback).and_yield({@agent_href => {"tags" => [@tag]}}).once
|
60
59
|
@manager.tags { |r| @result = r }
|
61
60
|
@result.should == [@tag]
|
62
61
|
end
|
@@ -81,10 +80,9 @@ describe RightScale::AgentTagManager do
|
|
81
80
|
end
|
82
81
|
|
83
82
|
it "forwards timeout option" do
|
84
|
-
@
|
85
|
-
|
86
|
-
|
87
|
-
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}}).once
|
83
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
84
|
+
{:agent_identity => @identity, :hrefs => [@agent_href]}, {:timeout => 9}).and_return(@request).once
|
85
|
+
@request.should_receive(:callback).and_yield({@agent_href => {"tags" => [@tag]}}).once
|
88
86
|
@manager.tags(:timeout => 9) { |r| @result = r }
|
89
87
|
@result.should == [@tag]
|
90
88
|
end
|
@@ -101,27 +99,24 @@ describe RightScale::AgentTagManager do
|
|
101
99
|
context :query_tags do
|
102
100
|
|
103
101
|
it "queries for agents having individual tag" do
|
104
|
-
@
|
105
|
-
|
106
|
-
|
107
|
-
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_id1 => {"tags" => [@tag]}}).once
|
102
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
103
|
+
{:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
|
104
|
+
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
|
108
105
|
@manager.query_tags(@tag) { |r| @result = r }
|
109
|
-
@result.should == {@identity => {"tags" => [@tag]}, @
|
106
|
+
@result.should == {@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}
|
110
107
|
end
|
111
108
|
|
112
109
|
it "queries for agents having multiple tags" do
|
113
|
-
@
|
114
|
-
|
115
|
-
|
116
|
-
@request.should_receive(:callback).and_yield({@agent_id1 => {"tags" => @tags}}).once
|
110
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
111
|
+
{:agent_identity => @identity, :tags => @tags}, {}).and_return(@request).once
|
112
|
+
@request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
|
117
113
|
@manager.query_tags(@tags) { |r| @result = r }
|
118
|
-
@result.should == {@
|
114
|
+
@result.should == {@agent_href => {"tags" => @tags}}
|
119
115
|
end
|
120
116
|
|
121
117
|
it "forwards options" do
|
122
|
-
@
|
123
|
-
|
124
|
-
{:timeout => 9}).and_return(@request).once
|
118
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
119
|
+
{:agent_identity => @identity, :tags => @tags}, {:timeout => 9}).and_return(@request).once
|
125
120
|
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}}).once
|
126
121
|
@request.should_receive(:raw_response).and_return("raw response").once
|
127
122
|
@manager.query_tags(@tags, :raw => true, :timeout => 9) { |r| @result = r }
|
@@ -129,9 +124,8 @@ describe RightScale::AgentTagManager do
|
|
129
124
|
end
|
130
125
|
|
131
126
|
it "yields error result and logs error" do
|
132
|
-
@
|
133
|
-
|
134
|
-
{}).and_return(@request).once
|
127
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
128
|
+
{:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
|
135
129
|
@log.should_receive(:error).with(/Failed to query tags/).once
|
136
130
|
@request.should_receive(:errback).and_yield("error").once
|
137
131
|
@request.should_receive(:callback).once
|
@@ -147,45 +141,40 @@ describe RightScale::AgentTagManager do
|
|
147
141
|
end
|
148
142
|
|
149
143
|
it "always yields raw response" do
|
150
|
-
@
|
151
|
-
|
152
|
-
|
153
|
-
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_id1 => {"tags" => [@tag]}}).once
|
144
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
145
|
+
{:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
|
146
|
+
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
|
154
147
|
@manager.query_tags_raw(@tag) { |r| @result = r }
|
155
148
|
@result.should == "raw response"
|
156
149
|
end
|
157
150
|
|
158
151
|
it "queries for agents having individual tag and always yields raw response" do
|
159
|
-
@
|
160
|
-
|
161
|
-
|
162
|
-
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_id1 => {"tags" => [@tag]}}).once
|
152
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
153
|
+
{:agent_identity => @identity, :tags => [@tag]}, {}).and_return(@request).once
|
154
|
+
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}, @agent_href => {"tags" => [@tag]}}).once
|
163
155
|
@manager.query_tags_raw(@tag) { |r| @result = r }
|
164
156
|
@result.should == "raw response"
|
165
157
|
end
|
166
158
|
|
167
159
|
it "queries for agents having multiple tags always yields raw response" do
|
168
|
-
@
|
169
|
-
|
170
|
-
|
171
|
-
@request.should_receive(:callback).and_yield({@agent_id1 => {"tags" => @tags}}).once
|
160
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
161
|
+
{:agent_identity => @identity, :tags => @tags}, {}).and_return(@request).once
|
162
|
+
@request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
|
172
163
|
@manager.query_tags_raw(@tags) { |r| @result = r }
|
173
164
|
@result.should == "raw response"
|
174
165
|
end
|
175
166
|
|
176
167
|
it "queries for selected agents" do
|
177
|
-
@
|
178
|
-
|
179
|
-
|
180
|
-
@
|
181
|
-
@manager.query_tags_raw(@tags, @agent_ids) { |r| @result = r }
|
168
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
169
|
+
{:agent_identity => @identity, :hrefs => @hrefs, :tags => @tags}, {}).and_return(@request).once
|
170
|
+
@request.should_receive(:callback).and_yield({@agent_href => {"tags" => @tags}}).once
|
171
|
+
@manager.query_tags_raw(@tags, @hrefs) { |r| @result = r }
|
182
172
|
@result.should == "raw response"
|
183
173
|
end
|
184
174
|
|
185
175
|
it "forwards timeout option" do
|
186
|
-
@
|
187
|
-
|
188
|
-
{:timeout => 9}).and_return(@request).once
|
176
|
+
@retryable_request.should_receive(:new).with("/router/query_tags",
|
177
|
+
{:agent_identity => @identity, :tags => @tags}, {:timeout => 9}).and_return(@request).once
|
189
178
|
@request.should_receive(:callback).and_yield({@identity => {"tags" => [@tag]}}).once
|
190
179
|
@manager.query_tags_raw(@tags, nil, :timeout => 9) { |r| @result = r }
|
191
180
|
@result.should == "raw response"
|
@@ -201,20 +190,17 @@ describe RightScale::AgentTagManager do
|
|
201
190
|
end
|
202
191
|
|
203
192
|
it "adds individual tag to agent" do
|
204
|
-
@
|
205
|
-
{:new_tags => [@tag], :obsolete_tags => []}).and_return(@request).once
|
193
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
206
194
|
@manager.add_tags(@tag).should be_true
|
207
195
|
end
|
208
196
|
|
209
197
|
it "adds multiple tags to agent" do
|
210
|
-
@
|
211
|
-
{:new_tags => @tags, :obsolete_tags => []}).and_return(@request).once
|
198
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => @tags}).and_return(@request).once
|
212
199
|
@manager.add_tags(@tags).should be_true
|
213
200
|
end
|
214
201
|
|
215
202
|
it "optionally yields raw response" do
|
216
|
-
@
|
217
|
-
{:new_tags => @tags, :obsolete_tags => []}).and_return(@request).once
|
203
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => @tags}).and_return(@request).once
|
218
204
|
@request.should_receive(:callback).and_yield("result").once
|
219
205
|
@manager.add_tags(@tags) { |r| @result = r }
|
220
206
|
@result.should == "raw response"
|
@@ -223,8 +209,7 @@ describe RightScale::AgentTagManager do
|
|
223
209
|
it "updates local tags" do
|
224
210
|
@agent.should_receive(:tags).and_return([@tag1]).once
|
225
211
|
@agent.should_receive(:tags=).should_receive([@tag]).once
|
226
|
-
@
|
227
|
-
{:new_tags => [@tag], :obsolete_tags => []}).and_return(@request).once
|
212
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
228
213
|
@manager.add_tags(@tag).should be_true
|
229
214
|
end
|
230
215
|
end
|
@@ -238,20 +223,17 @@ describe RightScale::AgentTagManager do
|
|
238
223
|
end
|
239
224
|
|
240
225
|
it "removes individual tag to agent" do
|
241
|
-
@
|
242
|
-
{:new_tags => [], :obsolete_tags => [@tag]}).and_return(@request).once
|
226
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag]}).and_return(@request).once
|
243
227
|
@manager.remove_tags(@tag).should be_true
|
244
228
|
end
|
245
229
|
|
246
230
|
it "removes multiple tags to agent" do
|
247
|
-
@
|
248
|
-
{:new_tags => [], :obsolete_tags => @tags}).and_return(@request).once
|
231
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
|
249
232
|
@manager.remove_tags(@tags).should be_true
|
250
233
|
end
|
251
234
|
|
252
235
|
it "optionally yields raw response" do
|
253
|
-
@
|
254
|
-
{:new_tags => [], :obsolete_tags => @tags}).and_return(@request).once
|
236
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
|
255
237
|
@request.should_receive(:callback).and_yield("result").once
|
256
238
|
@manager.remove_tags(@tags) { |r| @result = r }
|
257
239
|
@result.should == "raw response"
|
@@ -260,13 +242,12 @@ describe RightScale::AgentTagManager do
|
|
260
242
|
it "updates local tags" do
|
261
243
|
@agent.should_receive(:tags).and_return([]).once
|
262
244
|
@agent.should_receive(:tags=).should_receive([@tag]).once
|
263
|
-
@
|
264
|
-
{:new_tags => [], :obsolete_tags => [@tag]}).and_return(@request).once
|
245
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag]}).and_return(@request).once
|
265
246
|
@manager.remove_tags(@tag).should be_true
|
266
247
|
end
|
267
248
|
end
|
268
249
|
|
269
|
-
context :
|
250
|
+
context :do_update do
|
270
251
|
|
271
252
|
before(:each) do
|
272
253
|
@agent.should_receive(:tags).and_return([]).once.by_default
|
@@ -275,42 +256,51 @@ describe RightScale::AgentTagManager do
|
|
275
256
|
it "checks that agent has been set" do
|
276
257
|
@manager.agent = nil
|
277
258
|
@agent.should_receive(:tags).never
|
278
|
-
lambda { @manager.
|
259
|
+
lambda { @manager.send(:do_update, [@tag], []) }.should \
|
260
|
+
raise_error(ArgumentError, "Must set agent= before using tag manager")
|
261
|
+
end
|
262
|
+
|
263
|
+
it "does not allow both add and removal of tags in same request" do
|
264
|
+
@agent.should_receive(:tags).never
|
265
|
+
lambda { @manager.send(:do_update, [@tag], [@tag1]) }.should \
|
266
|
+
raise_error(ArgumentError, "Cannot add and remove tags in same update")
|
267
|
+
end
|
268
|
+
|
269
|
+
it "adds tags for agent" do
|
270
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
271
|
+
@agent.should_receive(:tags=).never
|
272
|
+
@manager.send(:do_update, [@tag], []).should be_true
|
279
273
|
end
|
280
274
|
|
281
|
-
it "
|
282
|
-
@
|
283
|
-
{:new_tags => [@tag], :obsolete_tags => [@tag1]}).and_return(@request).once
|
275
|
+
it "removes tags for agent" do
|
276
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => [@tag1]}).and_return(@request).once
|
284
277
|
@agent.should_receive(:tags=).never
|
285
|
-
@manager.
|
278
|
+
@manager.send(:do_update, [], [@tag1]).should be_true
|
286
279
|
end
|
287
280
|
|
288
281
|
it "yields raw response if block given" do
|
289
|
-
@
|
290
|
-
{:new_tags => [@tag], :obsolete_tags => [@tag1]}).and_return(@request).once
|
282
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
291
283
|
@request.should_receive(:raw_response).and_return("raw response").once
|
292
284
|
@agent.should_receive(:tags=).once
|
293
|
-
@manager.
|
285
|
+
@manager.send(:do_update, [@tag], []) { |r| @result = r }
|
294
286
|
@result.should == "raw response"
|
295
287
|
end
|
296
288
|
|
297
289
|
it "updates local tags if block given and successful" do
|
298
|
-
@
|
299
|
-
{:new_tags => [@tag], :obsolete_tags => [@tag1]}).and_return(@request).once
|
290
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
300
291
|
@request.should_receive(:raw_response).and_return("raw response").once
|
301
292
|
@agent.should_receive(:tags=).with([@tag]).once
|
302
|
-
@manager.
|
293
|
+
@manager.send(:do_update, [@tag], []) { |r| @result = r }
|
303
294
|
@result.should == "raw response"
|
304
295
|
end
|
305
296
|
|
306
297
|
it "yields error result and does not update local tags" do
|
307
|
-
@
|
308
|
-
{:new_tags => [@tag], :obsolete_tags => [@tag1]}).and_return(@request).once
|
298
|
+
@retryable_request.should_receive(:new).with("/router/add_tags", {:tags => [@tag]}).and_return(@request).once
|
309
299
|
@request.should_receive(:raw_response).and_return("error").once
|
310
300
|
@request.should_receive(:errback).and_yield("error").once
|
311
301
|
@request.should_receive(:callback).once
|
312
302
|
@agent.should_receive(:tags=).never
|
313
|
-
@manager.
|
303
|
+
@manager.send(:do_update, [@tag], []) { |r| @result = r }
|
314
304
|
@result.should == "error"
|
315
305
|
end
|
316
306
|
end
|
@@ -321,8 +311,7 @@ describe RightScale::AgentTagManager do
|
|
321
311
|
@request.should_receive(:raw_response).and_return("raw response").once
|
322
312
|
@agent.should_receive(:tags).and_return(@tags).twice
|
323
313
|
@agent.should_receive(:tags=).with([]).once
|
324
|
-
@
|
325
|
-
{:new_tags => [], :obsolete_tags => @tags}).and_return(@request).once
|
314
|
+
@retryable_request.should_receive(:new).with("/router/delete_tags", {:tags => @tags}).and_return(@request).once
|
326
315
|
@manager.clear { |r| @result = r }
|
327
316
|
@result.should == "raw response"
|
328
317
|
end
|