cuboid 0.0.5 → 0.1.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +13 -13
- data/lib/cuboid/application.rb +10 -10
- data/lib/cuboid/option_groups/{dispatcher.rb → agent.rb} +9 -9
- data/lib/cuboid/option_groups/paths.rb +1 -1
- data/lib/cuboid/options.rb +1 -1
- data/lib/cuboid/processes/{dispatchers.rb → agents.rb} +25 -25
- data/lib/cuboid/processes/executables/agent.rb +5 -0
- data/lib/cuboid/processes/helpers/agents.rb +23 -0
- data/lib/cuboid/processes/helpers/instances.rb +4 -4
- data/lib/cuboid/processes/helpers.rb +1 -1
- data/lib/cuboid/processes/instances.rb +9 -9
- data/lib/cuboid/processes/schedulers.rb +2 -2
- data/lib/cuboid/processes.rb +2 -2
- data/lib/cuboid/rest/server/instance_helpers.rb +13 -13
- data/lib/cuboid/rest/server/routes/dispatcher.rb +11 -11
- data/lib/cuboid/rest/server/routes/grid.rb +8 -8
- data/lib/cuboid/rest/server/routes/instances.rb +1 -1
- data/lib/cuboid/rest/server.rb +5 -5
- data/lib/cuboid/rpc/client/{dispatcher.rb → agent.rb} +4 -4
- data/lib/cuboid/rpc/client/instance.rb +2 -2
- data/lib/cuboid/rpc/client.rb +1 -1
- data/lib/cuboid/rpc/server/agent/node.rb +247 -0
- data/lib/cuboid/rpc/server/{dispatcher → agent}/service.rb +13 -13
- data/lib/cuboid/rpc/server/{dispatcher.rb → agent.rb} +32 -31
- data/lib/cuboid/rpc/server/application_wrapper.rb +1 -1
- data/lib/cuboid/rpc/server/instance.rb +4 -4
- data/lib/cuboid/rpc/server/scheduler.rb +12 -12
- data/lib/version +1 -1
- data/spec/cuboid/option_groups/dispatcher_spec.rb +2 -2
- data/spec/cuboid/rest/server_spec.rb +45 -45
- data/spec/cuboid/rpc/client/dispatcher_spec.rb +2 -2
- data/spec/cuboid/rpc/server/dispatcher/node_spec.rb +65 -65
- data/spec/cuboid/rpc/server/dispatcher/service_spec.rb +16 -16
- data/spec/cuboid/rpc/server/dispatcher_spec.rb +95 -95
- data/spec/cuboid/rpc/server/scheduler_spec.rb +8 -8
- data/spec/support/fixtures/executables/node.rb +3 -3
- data/spec/support/fixtures/mock_app/test_service.rb +8 -8
- data/spec/support/fixtures/mock_app.rb +1 -1
- data/spec/support/fixtures/services/echo.rb +6 -6
- data/spec/support/helpers/resets.rb +1 -1
- data/spec/support/lib/web_server_client.rb +2 -2
- data/spec/support/lib/web_server_dispatcher.rb +1 -1
- metadata +10 -348
- data/lib/cuboid/processes/executables/dispatcher.rb +0 -5
- data/lib/cuboid/processes/helpers/dispatchers.rb +0 -23
- data/lib/cuboid/rpc/server/dispatcher/node.rb +0 -247
- data/spec/support/logs/Dispatcher - 1520492-37227.log +0 -6
- data/spec/support/logs/Dispatcher - 1520680-13689.log +0 -6
- data/spec/support/logs/Dispatcher - 1520682-24167.log +0 -6
- data/spec/support/logs/Dispatcher - 1520688-42731.log +0 -6
- data/spec/support/logs/Dispatcher - 1520690-5750.log +0 -10
- data/spec/support/logs/Dispatcher - 1520692-55183.log +0 -10
- data/spec/support/logs/Dispatcher - 1520695-39752.log +0 -10
- data/spec/support/logs/Dispatcher - 1520697-44327.log +0 -10
- data/spec/support/logs/Dispatcher - 1520699-58785.log +0 -10
- data/spec/support/logs/Dispatcher - 1520701-60952.log +0 -10
- data/spec/support/logs/Dispatcher - 1520796-50420.log +0 -6
- data/spec/support/logs/Dispatcher - 1520894-56883.log +0 -6
- data/spec/support/logs/Dispatcher - 1520896-21419.log +0 -6
- data/spec/support/logs/Dispatcher - 1520898-62584.log +0 -6
- data/spec/support/logs/Dispatcher - 1520900-59721.log +0 -6
- data/spec/support/logs/Dispatcher - 1520910-51632.log +0 -6
- data/spec/support/logs/Dispatcher - 1520920-21801.log +0 -6
- data/spec/support/logs/Dispatcher - 1520930-49223.log +0 -6
- data/spec/support/logs/Dispatcher - 1520933-34241.log +0 -6
- data/spec/support/logs/Dispatcher - 1520935-64571.log +0 -6
- data/spec/support/logs/Dispatcher - 1520937-50734.log +0 -6
- data/spec/support/logs/Dispatcher - 1520939-60841.log +0 -6
- data/spec/support/logs/Dispatcher - 1520944-8124.log +0 -6
- data/spec/support/logs/Dispatcher - 1520946-25192.log +0 -16
- data/spec/support/logs/Dispatcher - 1520948-9752.log +0 -14
- data/spec/support/logs/Dispatcher - 1520952-45543.log +0 -10
- data/spec/support/logs/Dispatcher - 1520958-36653.log +0 -16
- data/spec/support/logs/Dispatcher - 1520960-17456.log +0 -14
- data/spec/support/logs/Dispatcher - 1520964-5774.log +0 -10
- data/spec/support/logs/Dispatcher - 1520976-40848.log +0 -16
- data/spec/support/logs/Dispatcher - 1520978-29867.log +0 -14
- data/spec/support/logs/Dispatcher - 1520982-17715.log +0 -10
- data/spec/support/logs/Dispatcher - 1520987-8925.log +0 -16
- data/spec/support/logs/Dispatcher - 1520989-25480.log +0 -14
- data/spec/support/logs/Dispatcher - 1520993-5124.log +0 -10
- data/spec/support/logs/Dispatcher - 1520999-12901.log +0 -16
- data/spec/support/logs/Dispatcher - 1521004-32265.log +0 -14
- data/spec/support/logs/Dispatcher - 1521008-33455.log +0 -10
- data/spec/support/logs/Dispatcher - 1521014-13779.log +0 -6
- data/spec/support/logs/Dispatcher - 1521017-14755.log +0 -6
- data/spec/support/logs/Dispatcher - 1521022-48687.log +0 -6
- data/spec/support/logs/Dispatcher - 1521024-59097.log +0 -6
- data/spec/support/logs/Dispatcher - 1521034-12604.log +0 -6
- data/spec/support/logs/Dispatcher - 1521038-64272.log +0 -6
- data/spec/support/logs/Dispatcher - 1521043-8680.log +0 -6
- data/spec/support/logs/Dispatcher - 1521047-22949.log +0 -6
- data/spec/support/logs/Dispatcher - 1521051-3355.log +0 -6
- data/spec/support/logs/Dispatcher - 1521074-12332.log +0 -6
- data/spec/support/logs/Dispatcher - 1521118-53130.log +0 -16
- data/spec/support/logs/Dispatcher - 1521128-47137.log +0 -14
- data/spec/support/logs/Dispatcher - 1521136-30328.log +0 -10
- data/spec/support/logs/Dispatcher - 1521161-21329.log +0 -16
- data/spec/support/logs/Dispatcher - 1521172-19183.log +0 -14
- data/spec/support/logs/Dispatcher - 1521179-34902.log +0 -10
- data/spec/support/logs/Dispatcher - 1521190-20155.log +0 -16
- data/spec/support/logs/Dispatcher - 1521204-43843.log +0 -14
- data/spec/support/logs/Dispatcher - 1521211-23972.log +0 -10
- data/spec/support/logs/Dispatcher - 1521237-20879.log +0 -10
- data/spec/support/logs/Dispatcher - 1521239-61999.log +0 -10
- data/spec/support/logs/Dispatcher - 1521242-20975.log +0 -16
- data/spec/support/logs/Dispatcher - 1521246-28409.log +0 -14
- data/spec/support/logs/Dispatcher - 1521250-58505.log +0 -10
- data/spec/support/logs/Dispatcher - 1521262-53292.log +0 -6
- data/spec/support/logs/Dispatcher - 1521266-42758.log +0 -6
- data/spec/support/logs/Dispatcher - 1521277-4215.log +0 -6
- data/spec/support/logs/Dispatcher - 1521292-16086.log +0 -6
- data/spec/support/logs/Dispatcher - 1521301-42112.log +0 -6
- data/spec/support/logs/Dispatcher - 1521312-61196.log +0 -6
- data/spec/support/logs/Dispatcher - 1521316-23353.log +0 -6
- data/spec/support/logs/Dispatcher - 1521321-46361.log +0 -6
- data/spec/support/logs/Dispatcher - 1521438-46016.log +0 -6
- data/spec/support/logs/Dispatcher - 1521454-49862.log +0 -6
- data/spec/support/logs/Dispatcher - 1521470-54737.log +0 -6
- data/spec/support/logs/Instance - 1521353-26273.error.log +0 -105
- data/spec/support/logs/Instance - 1521355-56591.error.log +0 -105
- data/spec/support/logs/Instance - 1521363-26218.error.log +0 -105
- data/spec/support/logs/Scheduler - 1520469-35703.log +0 -3
- data/spec/support/logs/Scheduler - 1520473-60524.log +0 -6
- data/spec/support/logs/Scheduler - 1520509-34951.log +0 -3
- data/spec/support/logs/Scheduler - 1520517-31455.log +0 -6
- data/spec/support/logs/Scheduler - 1520529-43808.log +0 -4
- data/spec/support/logs/Scheduler - 1520536-23387.log +0 -1
- data/spec/support/logs/Scheduler - 1520549-48260.log +0 -3
- data/spec/support/logs/Scheduler - 1520563-45636.log +0 -6
- data/spec/support/logs/Scheduler - 1520599-40643.log +0 -3
- data/spec/support/logs/Scheduler - 1520608-54106.log +0 -6
- data/spec/support/logs/Scheduler - 1520629-24722.log +0 -3
- data/spec/support/logs/Scheduler - 1520637-61755.log +0 -6
- data/spec/support/logs/Scheduler - 1520663-17447.log +0 -4
- data/spec/support/logs/Scheduler - 1520671-38282.log +0 -6
- data/spec/support/logs/Scheduler - 1520703-33082.log +0 -1
- data/spec/support/logs/Scheduler - 1520706-22309.log +0 -1
- data/spec/support/logs/Scheduler - 1520709-1816.log +0 -1
- data/spec/support/logs/Scheduler - 1520711-19998.log +0 -1
- data/spec/support/logs/Scheduler - 1520714-47570.log +0 -1
- data/spec/support/logs/Scheduler - 1520723-18521.log +0 -1
- data/spec/support/logs/Scheduler - 1520725-40913.log +0 -3
- data/spec/support/logs/Scheduler - 1520749-45742.log +0 -6
- data/spec/support/logs/Scheduler - 1520759-44350.log +0 -4
- data/spec/support/logs/Scheduler - 1520770-53219.log +0 -1
- data/spec/support/logs/Scheduler - 1520773-54792.log +0 -1
- data/spec/support/logs/Scheduler - 1520777-19636.log +0 -1
- data/spec/support/logs/Scheduler - 1520780-51801.log +0 -1
- data/spec/support/logs/Scheduler - 1520782-9652.log +0 -3
- data/spec/support/logs/Scheduler - 1520786-59472.log +0 -1
- data/spec/support/logs/Scheduler - 1520789-1603.log +0 -1
- data/spec/support/logs/Scheduler - 1520792-35476.log +0 -1
- data/spec/support/logs/Scheduler - 1521410-47324.log +0 -16
- data/spec/support/logs/Scheduler - 1521422-33737.log +0 -6
- data/spec/support/logs/Scheduler - 1521433-36637.log +0 -6
- data/spec/support/logs/Scheduler - 1521440-15066.log +0 -6
- data/spec/support/logs/Scheduler - 1521456-48637.log +0 -3
- data/spec/support/logs/Scheduler - 1521472-54425.log +0 -5
- data/spec/support/logs/Scheduler - 1521496-12923.log +0 -1
- data/spec/support/logs/Scheduler - 1521518-46819.log +0 -1
- data/spec/support/logs/Scheduler - 1521522-21417.log +0 -1
- data/spec/support/logs/Scheduler - 1521525-35088.log +0 -1
- data/spec/support/logs/Scheduler - 1521528-13676.log +0 -1
- data/spec/support/logs/Scheduler - 1521530-48176.log +0 -1
- data/spec/support/logs/Scheduler - 1521532-13207.log +0 -1
- data/spec/support/logs/Scheduler - 1521535-5799.log +0 -3
- data/spec/support/logs/Scheduler - 1521543-62784.log +0 -3
- data/spec/support/logs/Scheduler - 1521551-10263.log +0 -3
- data/spec/support/logs/Scheduler - 1521556-56026.log +0 -3
- data/spec/support/logs/Scheduler - 1521560-14551.log +0 -4
- data/spec/support/logs/Scheduler - 1521573-47584.log +0 -1
- data/spec/support/logs/Scheduler - 1521578-14443.log +0 -4
- data/spec/support/logs/Scheduler - 1521580-60337.log +0 -1
- data/spec/support/logs/Scheduler - 1521583-52039.log +0 -1
- data/spec/support/logs/Scheduler - 1521586-1500.log +0 -16
- data/spec/support/logs/Scheduler - 1521598-61298.log +0 -4
- data/spec/support/logs/Scheduler - 1521602-61490.log +0 -1
- data/spec/support/logs/Scheduler - 1521604-29209.log +0 -1
- data/spec/support/logs/Scheduler - 1521606-47734.log +0 -1
- data/spec/support/logs/Scheduler - 1521612-63269.log +0 -1
- data/spec/support/logs/Scheduler - 1521614-47018.log +0 -3
- data/spec/support/logs/Scheduler - 1521619-32411.log +0 -1
- data/spec/support/logs/Scheduler - 1521621-42861.log +0 -1
- data/spec/support/logs/Scheduler - 1521623-56258.log +0 -1
- data/spec/support/logs/Scheduler - 1521627-9487.log +0 -1
- data/spec/support/logs/Scheduler - 1521630-3345.log +0 -1
- data/spec/support/logs/Scheduler - 1521632-47325.log +0 -1
- data/spec/support/logs/Scheduler - 1521635-22156.log +0 -2
- data/spec/support/logs/error-1520329.log +0 -797
- data/spec/support/logs/output_spec_1520329.log +0 -390
- data/spec/support/reports/003bed585153336c2548d1c60a026a3e.crf +0 -0
- data/spec/support/reports/30e3c7a8c13e9b40a0a443a5e5a4ff94.crf +0 -0
- data/spec/support/reports/31655751a9f0eee91e588bc796985b1e.crf +0 -0
- data/spec/support/reports/40801b7993c0ed919b73242a9c078dde.crf +0 -0
- data/spec/support/reports/4719b89667e92bb80102f4b0bb4c0c75.crf +0 -0
- data/spec/support/reports/4e765a3d2870d2763ea72167bd3db9d6.crf +0 -0
- data/spec/support/reports/61968f732d8ae715c104175e43679915.crf +0 -0
- data/spec/support/reports/63446a8ec637d9991b8c6a1151ae59a9.crf +0 -0
- data/spec/support/reports/737144b18305c7a115ad7964b9bbe41c.crf +0 -0
- data/spec/support/reports/73fe5f7adf905045c3fe4669bdf60d02.crf +0 -0
- data/spec/support/reports/86cd396db9ef97472876f32e57c44ce7.crf +0 -0
- data/spec/support/reports/8a031ac2b2730dfd07a1d1ca870299f2.crf +0 -0
- data/spec/support/reports/8e16ac74484ee5d8cf7073fe22adf787.crf +0 -0
- data/spec/support/reports/8eff857213ab6ff712a0b0e8582855c9.crf +0 -0
- data/spec/support/reports/9e0e6ed8718973b3d4e63bbb7dd1d1c6.crf +0 -0
- data/spec/support/reports/a9c88f967d09cb9c4e8e1180cfb24828.crf +0 -0
- data/spec/support/reports/ba32970a64686e45ec8caa5032f65c2e.crf +0 -0
- data/spec/support/reports/cceb7596659fd619ab4438953cbda78b.crf +0 -0
- data/spec/support/reports/d2e0f4558b605ffd1215e9226815b951.crf +0 -0
- data/spec/support/snapshots/Cuboid 2022-01-24 14_38_16 +0200 8238609e31cedaf1bcb89205f9d42121.csf +0 -0
- data/spec/support/snapshots/Cuboid 2022-01-24 14_38_30 +0200 68690b002e79c7bc9e3aabfcbc7ac5a7.csf +0 -0
- data/spec/support/snapshots/Cuboid 2022-01-24 14_46_39 +0200 6fd3c9491d3e784e18f9c3c0d9deddec.csf +0 -0
- data/spec/support/snapshots/Cuboid 2022-01-24 14_46_44 +0200 c3a012fba59210bc7c169afb0565d5a8.csf +0 -0
- data/spec/support/snapshots/Cuboid 2022-01-24 14_46_46 +0200 e4c1ce35d8e62e6a16f84eccd36b2283.csf +0 -0
|
@@ -5,10 +5,10 @@ require Options.paths.lib + 'rpc/client/base'
|
|
|
5
5
|
module RPC
|
|
6
6
|
class Client
|
|
7
7
|
|
|
8
|
-
# RPC
|
|
8
|
+
# RPC Agent client
|
|
9
9
|
#
|
|
10
10
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
11
|
-
class
|
|
11
|
+
class Agent
|
|
12
12
|
# Not always available, set by the parent.
|
|
13
13
|
attr_accessor :pid
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@ class Dispatcher
|
|
|
18
18
|
@client = Base.new( url, nil, options )
|
|
19
19
|
@node = Arachni::RPC::Proxy.new( @client, 'node' )
|
|
20
20
|
|
|
21
|
-
Cuboid::Application.application.
|
|
21
|
+
Cuboid::Application.application.agent_services.keys.each do |name|
|
|
22
22
|
self.class.send( :attr_reader, name.to_sym )
|
|
23
23
|
|
|
24
24
|
instance_variable_set(
|
|
@@ -48,7 +48,7 @@ class Dispatcher
|
|
|
48
48
|
|
|
49
49
|
# Used to provide the illusion of locality for remote methods
|
|
50
50
|
def method_missing( sym, *args, &block )
|
|
51
|
-
@client.call( "
|
|
51
|
+
@client.call( "agent.#{sym.to_s}", *args, &block )
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
end
|
|
@@ -5,7 +5,7 @@ require Options.paths.lib + 'rpc/client/base'
|
|
|
5
5
|
module RPC
|
|
6
6
|
class Client
|
|
7
7
|
|
|
8
|
-
# RPC client for remote instances spawned by a remote
|
|
8
|
+
# RPC client for remote instances spawned by a remote agent
|
|
9
9
|
#
|
|
10
10
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
11
11
|
class Instance
|
|
@@ -47,7 +47,7 @@ class Instance
|
|
|
47
47
|
@instance = Proxy.new( @client )
|
|
48
48
|
@options = Arachni::RPC::Proxy.new( @client, 'options' )
|
|
49
49
|
|
|
50
|
-
# map
|
|
50
|
+
# map Agent handlers
|
|
51
51
|
Cuboid::Application.application.instance_services.keys.each do |name|
|
|
52
52
|
self.class.send( :attr_reader, name.to_sym )
|
|
53
53
|
|
data/lib/cuboid/rpc/client.rb
CHANGED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
module Cuboid
|
|
2
|
+
|
|
3
|
+
require Options.paths.lib + 'rpc/server/output'
|
|
4
|
+
|
|
5
|
+
module RPC
|
|
6
|
+
|
|
7
|
+
# Agent node class, helps maintain a list of all available Agents in
|
|
8
|
+
# the grid and announce itself to peering Agents.
|
|
9
|
+
#
|
|
10
|
+
# As soon as a new Node is fired up it checks-in with its peer and grabs
|
|
11
|
+
# a list of all available peers.
|
|
12
|
+
#
|
|
13
|
+
# As soon as it receives the peer list it then announces itself to them.
|
|
14
|
+
#
|
|
15
|
+
# Upon convergence there will be a grid of Agents each one with its own
|
|
16
|
+
# copy of all available Agent URLs.
|
|
17
|
+
#
|
|
18
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
19
|
+
class Server::Agent::Node
|
|
20
|
+
include UI::Output
|
|
21
|
+
|
|
22
|
+
# Initializes the node by:
|
|
23
|
+
#
|
|
24
|
+
# * Adding the peer (if the user has supplied one) to the peer list.
|
|
25
|
+
# * Getting the peer's peer list and appending them to its own.
|
|
26
|
+
# * Announces itself to the peer and instructs it to propagate our URL
|
|
27
|
+
# to the others.
|
|
28
|
+
#
|
|
29
|
+
# @param [Cuboid::Options] options
|
|
30
|
+
# @param [Server::Base] server
|
|
31
|
+
# Agent's RPC server.
|
|
32
|
+
# @param [String] logfile
|
|
33
|
+
# Where to send the output.
|
|
34
|
+
def initialize( options, server, logfile = nil )
|
|
35
|
+
@options = options
|
|
36
|
+
@server = server
|
|
37
|
+
@url = @server.url
|
|
38
|
+
|
|
39
|
+
reroute_to_file( logfile ) if logfile
|
|
40
|
+
|
|
41
|
+
print_status 'Initializing grid node...'
|
|
42
|
+
|
|
43
|
+
@dead_nodes = Set.new
|
|
44
|
+
@peers = Set.new
|
|
45
|
+
@nodes_info_cache = []
|
|
46
|
+
|
|
47
|
+
if (peer = @options.agent.peer)
|
|
48
|
+
# Grab the peer's peers.
|
|
49
|
+
connect_to_peer( peer ).peers do |urls|
|
|
50
|
+
if urls.rpc_exception?
|
|
51
|
+
add_dead_peer( peer )
|
|
52
|
+
print_info "Neighbour seems dead: #{peer}"
|
|
53
|
+
add_dead_peer( peer )
|
|
54
|
+
next
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Add peer and announce it to everyone.
|
|
58
|
+
add_peer( peer, true )
|
|
59
|
+
|
|
60
|
+
urls.each { |url| @peers << url if url != @url }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
print_status 'Node ready.'
|
|
65
|
+
|
|
66
|
+
log_updated_peers
|
|
67
|
+
|
|
68
|
+
Arachni::Reactor.global.at_interval( @options.agent.ping_interval ) do
|
|
69
|
+
ping
|
|
70
|
+
check_for_comebacks
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [Boolean]
|
|
75
|
+
# `true` if grid member, `false` otherwise.
|
|
76
|
+
def grid_member?
|
|
77
|
+
@peers.any?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def unplug
|
|
81
|
+
@peers.each do |peer|
|
|
82
|
+
connect_to_peer( peer ).remove_peer( @url ) {}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@peers.clear
|
|
86
|
+
@dead_nodes.clear
|
|
87
|
+
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Adds a peer to the peer list.
|
|
92
|
+
#
|
|
93
|
+
# @param [String] node_url
|
|
94
|
+
# URL of a peering node.
|
|
95
|
+
# @param [Boolean] propagate
|
|
96
|
+
# Whether or not to announce the new node to the peers.
|
|
97
|
+
def add_peer( node_url, propagate = false )
|
|
98
|
+
# we don't want ourselves in the Set
|
|
99
|
+
return false if node_url == @url
|
|
100
|
+
return false if @peers.include?( node_url )
|
|
101
|
+
|
|
102
|
+
print_status "Adding peer: #{node_url}"
|
|
103
|
+
|
|
104
|
+
@peers << node_url
|
|
105
|
+
log_updated_peers
|
|
106
|
+
announce( node_url ) if propagate
|
|
107
|
+
|
|
108
|
+
connect_to_peer( node_url ).add_peer( @url, propagate ) do |res|
|
|
109
|
+
next if !res.rpc_exception?
|
|
110
|
+
add_dead_peer( node_url )
|
|
111
|
+
print_status "Neighbour seems dead: #{node_url}"
|
|
112
|
+
end
|
|
113
|
+
true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def remove_peer( url )
|
|
117
|
+
@peers.delete url
|
|
118
|
+
@dead_nodes.delete url
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @return [Array]
|
|
123
|
+
# Neighbour/node/peer URLs.
|
|
124
|
+
def peers
|
|
125
|
+
@peers.to_a
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def peers_with_info( &block )
|
|
129
|
+
fail 'This method requires a block!' if !block_given?
|
|
130
|
+
|
|
131
|
+
@peers_cmp = ''
|
|
132
|
+
|
|
133
|
+
if @nodes_info_cache.empty? || @peers_cmp != peers.to_s
|
|
134
|
+
@peers_cmp = peers.to_s
|
|
135
|
+
|
|
136
|
+
each = proc do |peer, iter|
|
|
137
|
+
connect_to_peer( peer ).info do |info|
|
|
138
|
+
if info.rpc_exception?
|
|
139
|
+
print_info "Neighbour seems dead: #{peer}"
|
|
140
|
+
add_dead_peer( peer )
|
|
141
|
+
log_updated_peers
|
|
142
|
+
|
|
143
|
+
iter.return( nil )
|
|
144
|
+
else
|
|
145
|
+
iter.return( info )
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
after = proc do |nodes|
|
|
151
|
+
@nodes_info_cache = nodes.compact
|
|
152
|
+
block.call( @nodes_info_cache )
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
Arachni::Reactor.global.create_iterator( peers ).map( each, after )
|
|
156
|
+
else
|
|
157
|
+
block.call( @nodes_info_cache )
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @return [Hash]
|
|
162
|
+
#
|
|
163
|
+
# * `url` -- This node's URL.
|
|
164
|
+
# * `name` -- Nickname
|
|
165
|
+
# * `peers` -- Array of peers.
|
|
166
|
+
def info
|
|
167
|
+
{
|
|
168
|
+
'url' => @url,
|
|
169
|
+
'name' => @options.agent.name,
|
|
170
|
+
'peers' => @peers.to_a,
|
|
171
|
+
'unreachable_peers' => @dead_nodes.to_a
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def alive?
|
|
176
|
+
true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
private
|
|
180
|
+
|
|
181
|
+
def add_dead_peer( url )
|
|
182
|
+
remove_peer( url )
|
|
183
|
+
@dead_nodes << url
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def log_updated_peers
|
|
187
|
+
print_info 'Updated peers:'
|
|
188
|
+
|
|
189
|
+
if !peers.empty?
|
|
190
|
+
peers.each { |node| print_info( '---- ' + node ) }
|
|
191
|
+
else
|
|
192
|
+
print_info '<empty>'
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def ping
|
|
197
|
+
peers.each do |peer|
|
|
198
|
+
connect_to_peer( peer ).alive? do |res|
|
|
199
|
+
next if !res.rpc_exception?
|
|
200
|
+
add_dead_peer( peer )
|
|
201
|
+
print_status "Found dead peer: #{peer} "
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def check_for_comebacks
|
|
207
|
+
@dead_nodes.dup.each do |url|
|
|
208
|
+
peer = connect_to_peer( url )
|
|
209
|
+
peer.alive? do |res|
|
|
210
|
+
next if res.rpc_exception?
|
|
211
|
+
|
|
212
|
+
print_status "Agent came back to life: #{url}"
|
|
213
|
+
([@url] | peers).each do |node|
|
|
214
|
+
peer.add_peer( node ){}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
add_peer( url )
|
|
218
|
+
@dead_nodes.delete url
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Announces the node to the ones in the peer list
|
|
224
|
+
#
|
|
225
|
+
# @param [String] node
|
|
226
|
+
# URL
|
|
227
|
+
def announce( node )
|
|
228
|
+
print_status "Advertising: #{node}"
|
|
229
|
+
|
|
230
|
+
peers.each do |peer|
|
|
231
|
+
next if peer == node
|
|
232
|
+
|
|
233
|
+
print_info '---- to: ' + peer
|
|
234
|
+
connect_to_peer( peer ).add_peer( node ) do |res|
|
|
235
|
+
add_dead_peer( peer ) if res.rpc_exception?
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def connect_to_peer( url )
|
|
241
|
+
@rpc_clients ||= {}
|
|
242
|
+
@rpc_clients[url] ||= Client::Agent.new( url ).node
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Cuboid
|
|
2
2
|
module RPC
|
|
3
3
|
|
|
4
|
-
# Base class and namespace for all
|
|
4
|
+
# Base class and namespace for all Agent services.
|
|
5
5
|
#
|
|
6
6
|
# # RPC accessibility
|
|
7
7
|
#
|
|
@@ -26,20 +26,20 @@ module RPC
|
|
|
26
26
|
# results to that block instead of returning a value.
|
|
27
27
|
#
|
|
28
28
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
29
|
-
class Server::
|
|
29
|
+
class Server::Agent::Service
|
|
30
30
|
|
|
31
31
|
attr_reader :options
|
|
32
|
-
attr_reader :
|
|
32
|
+
attr_reader :agent
|
|
33
33
|
|
|
34
|
-
def initialize( options,
|
|
34
|
+
def initialize( options, agent )
|
|
35
35
|
@options = options
|
|
36
|
-
@
|
|
36
|
+
@agent = agent
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
# @return [Server::
|
|
39
|
+
# @return [Server::Agent::Node]
|
|
40
40
|
# Local node.
|
|
41
41
|
def node
|
|
42
|
-
|
|
42
|
+
agent.instance_eval { @node }
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Performs an asynchronous map operation over all running instances.
|
|
@@ -102,17 +102,17 @@ class Server::Dispatcher::Service
|
|
|
102
102
|
# @return [Array<Hash>]
|
|
103
103
|
# Alive instances.
|
|
104
104
|
def instances
|
|
105
|
-
|
|
105
|
+
agent.running_instances
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
-
# Connects to a
|
|
108
|
+
# Connects to a Agent by `url`
|
|
109
109
|
#
|
|
110
110
|
# @param [String] url
|
|
111
111
|
#
|
|
112
|
-
# @return [Client::
|
|
113
|
-
def
|
|
114
|
-
@
|
|
115
|
-
@
|
|
112
|
+
# @return [Client::Agent]
|
|
113
|
+
def connect_to_agent( url )
|
|
114
|
+
@agent_connections ||= {}
|
|
115
|
+
@agent_connections[url] ||= Client::Agent.new( url )
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
# Connects to an Instance by `url`.
|
|
@@ -14,24 +14,24 @@ class Server
|
|
|
14
14
|
#
|
|
15
15
|
# The process goes something like this:
|
|
16
16
|
#
|
|
17
|
-
# * A client issues a {#
|
|
18
|
-
# * The
|
|
17
|
+
# * A client issues a {#spawn} call.
|
|
18
|
+
# * The Agent spawns and returns Instance info to the client (url, auth token, etc.).
|
|
19
19
|
# * The client connects to the Instance using that info.
|
|
20
20
|
#
|
|
21
21
|
# Once the client finishes using the RPC Instance it *must* shut it down
|
|
22
22
|
# otherwise the system will be eaten away by zombie processes.
|
|
23
23
|
#
|
|
24
24
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
25
|
-
class
|
|
26
|
-
require Options.paths.lib + 'rpc/server/
|
|
27
|
-
require Options.paths.lib + 'rpc/server/
|
|
25
|
+
class Agent
|
|
26
|
+
require Options.paths.lib + 'rpc/server/agent/node'
|
|
27
|
+
require Options.paths.lib + 'rpc/server/agent/service'
|
|
28
28
|
|
|
29
29
|
include Utilities
|
|
30
30
|
include UI::Output
|
|
31
31
|
|
|
32
32
|
SERVICE_NAMESPACE = Service
|
|
33
33
|
|
|
34
|
-
PREFERENCE_STRATEGIES = Cuboid::OptionGroups::
|
|
34
|
+
PREFERENCE_STRATEGIES = Cuboid::OptionGroups::Agent::STRATEGIES
|
|
35
35
|
|
|
36
36
|
def initialize( options = Options.instance )
|
|
37
37
|
@options = options
|
|
@@ -46,20 +46,20 @@ class Dispatcher
|
|
|
46
46
|
method.parameters.flatten.include? :block
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
Options.
|
|
49
|
+
Options.agent.url = @url = @server.url
|
|
50
50
|
|
|
51
51
|
prep_logging
|
|
52
52
|
|
|
53
53
|
print_status 'Starting the RPC Server...'
|
|
54
54
|
|
|
55
|
-
@server.add_handler( '
|
|
55
|
+
@server.add_handler( 'agent', self )
|
|
56
56
|
|
|
57
57
|
# trap interrupts and exit cleanly when required
|
|
58
58
|
trap_interrupts { shutdown }
|
|
59
59
|
|
|
60
60
|
@instances = []
|
|
61
61
|
|
|
62
|
-
Cuboid::Application.application.
|
|
62
|
+
Cuboid::Application.application.agent_services.each do |name, service|
|
|
63
63
|
@server.add_handler( name.to_s, service.new( @options, self ) )
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -70,7 +70,7 @@ class Dispatcher
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def services
|
|
73
|
-
Cuboid::Application.application.
|
|
73
|
+
Cuboid::Application.application.agent_services.keys
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
# @return [TrueClass]
|
|
@@ -80,17 +80,17 @@ class Dispatcher
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# @param [Symbol] strategy
|
|
83
|
-
# `:horizontal` -- Pick the
|
|
84
|
-
# `:vertical` -- Pick the
|
|
83
|
+
# `:horizontal` -- Pick the Agent with the least amount of workload.
|
|
84
|
+
# `:vertical` -- Pick the Agent with the most amount of workload.
|
|
85
85
|
#
|
|
86
86
|
# @return [String, nil]
|
|
87
87
|
# Depending on strategy and availability:
|
|
88
88
|
#
|
|
89
|
-
# * URL of the preferred
|
|
90
|
-
# this
|
|
89
|
+
# * URL of the preferred Agent. If not a grid member it will return
|
|
90
|
+
# this Agent's URL.
|
|
91
91
|
# * `nil` if all nodes are at max utilization or on error.
|
|
92
92
|
# * `ArgumentError` -- On invalid `strategy`.
|
|
93
|
-
def preferred( strategy = Cuboid::Options.
|
|
93
|
+
def preferred( strategy = Cuboid::Options.agent.strategy, &block )
|
|
94
94
|
strategy = strategy.to_sym
|
|
95
95
|
if !PREFERENCE_STRATEGIES.include? strategy
|
|
96
96
|
block.call :error_unknown_strategy
|
|
@@ -117,9 +117,9 @@ class Dispatcher
|
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
each = proc do |
|
|
121
|
-
connect_to_peer(
|
|
122
|
-
iter.return pick_utilization.call(
|
|
120
|
+
each = proc do |peer, iter|
|
|
121
|
+
connect_to_peer( peer ).utilization do |utilization|
|
|
122
|
+
iter.return pick_utilization.call( peer, utilization )
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
@@ -136,25 +136,26 @@ class Dispatcher
|
|
|
136
136
|
block.call nodes.sort_by { |_, score| adjust_score_by_strategy.call score }[0][0]
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
-
Arachni::Reactor.global.create_iterator( @node.
|
|
139
|
+
Arachni::Reactor.global.create_iterator( @node.peers ).map( each, after )
|
|
140
140
|
end
|
|
141
141
|
|
|
142
142
|
# Dispatches an {Instance}.
|
|
143
143
|
#
|
|
144
|
-
# @param [String]
|
|
144
|
+
# @param [String] options
|
|
145
|
+
# @option [String] strategy
|
|
146
|
+
# @option [String] owner
|
|
145
147
|
# An owner to assign to the {Instance}.
|
|
146
|
-
# @
|
|
148
|
+
# @option [Hash] helpers
|
|
147
149
|
# Hash of helper data to be added to the instance info.
|
|
148
|
-
# @
|
|
149
|
-
#
|
|
150
|
-
# or from this one directly?
|
|
150
|
+
# @option [Boolean] load_balance
|
|
151
|
+
# Use the Grid (when available) or this one directly?
|
|
151
152
|
#
|
|
152
153
|
# @return [Hash, nil]
|
|
153
154
|
# Depending on availability:
|
|
154
155
|
#
|
|
155
156
|
# * `Hash`: Connection and proc info.
|
|
156
157
|
# * `nil`: Max utilization, wait for one of the instances to finish and retry.
|
|
157
|
-
def
|
|
158
|
+
def spawn( options = {}, &block )
|
|
158
159
|
options = options.my_symbolize_keys
|
|
159
160
|
strategy = options.delete(:strategy)
|
|
160
161
|
owner = options[:owner]
|
|
@@ -173,7 +174,7 @@ class Dispatcher
|
|
|
173
174
|
next
|
|
174
175
|
end
|
|
175
176
|
|
|
176
|
-
connect_to_peer( url ).
|
|
177
|
+
connect_to_peer( url ).spawn( options.merge(
|
|
177
178
|
helpers: helpers.merge( via: @url ),
|
|
178
179
|
load_balance: false
|
|
179
180
|
),
|
|
@@ -243,7 +244,7 @@ class Dispatcher
|
|
|
243
244
|
end
|
|
244
245
|
|
|
245
246
|
# @return [Float]
|
|
246
|
-
# Workload score for this
|
|
247
|
+
# Workload score for this Agent, calculated using {System#utilization}.
|
|
247
248
|
#
|
|
248
249
|
# * `0.0` => No utilization.
|
|
249
250
|
# * `1.0` => Max utilization.
|
|
@@ -285,7 +286,7 @@ class Dispatcher
|
|
|
285
286
|
end
|
|
286
287
|
end
|
|
287
288
|
|
|
288
|
-
# Starts the
|
|
289
|
+
# Starts the agent's server
|
|
289
290
|
def run
|
|
290
291
|
Arachni::Reactor.global.on_error do |_, e|
|
|
291
292
|
print_error "Reactor: #{e}"
|
|
@@ -314,7 +315,7 @@ class Dispatcher
|
|
|
314
315
|
def spawn_instance( options = {}, &block )
|
|
315
316
|
Processes::Instances.spawn( options.merge(
|
|
316
317
|
address: @server.address,
|
|
317
|
-
port_range: Options.
|
|
318
|
+
port_range: Options.agent.instance_port_range,
|
|
318
319
|
token: Utilities.generate_token,
|
|
319
320
|
application: Options.paths.application
|
|
320
321
|
)) do |client|
|
|
@@ -331,12 +332,12 @@ class Dispatcher
|
|
|
331
332
|
def prep_logging
|
|
332
333
|
# reroute all output to a logfile
|
|
333
334
|
@logfile ||= reroute_to_file( @options.paths.logs +
|
|
334
|
-
"/
|
|
335
|
+
"/Agent - #{Process.pid}-#{@options.rpc.server_port}.log" )
|
|
335
336
|
end
|
|
336
337
|
|
|
337
338
|
def connect_to_peer( url )
|
|
338
339
|
@rpc_clients ||= {}
|
|
339
|
-
@rpc_clients[url] ||= Client::
|
|
340
|
+
@rpc_clients[url] ||= Client::Agent.new( url )
|
|
340
341
|
end
|
|
341
342
|
|
|
342
343
|
end
|
|
@@ -111,7 +111,7 @@ class ApplicationWrapper
|
|
|
111
111
|
busy: running?,
|
|
112
112
|
application: @application.class.to_s,
|
|
113
113
|
seed: Utilities.random_seed,
|
|
114
|
-
|
|
114
|
+
agent_url: Cuboid::Options.agent.url,
|
|
115
115
|
scheduler_url: Cuboid::Options.scheduler.url
|
|
116
116
|
}
|
|
117
117
|
|
|
@@ -90,10 +90,10 @@ class Instance
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
# @return [String, nil]
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
def
|
|
96
|
-
@options.
|
|
93
|
+
# Agent URL that provided this Instance, `nil` if not provided by a
|
|
94
|
+
# Agent.
|
|
95
|
+
def agent_url
|
|
96
|
+
@options.agent.url
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# @param (see Cuboid::Application#restore)
|
|
@@ -6,7 +6,7 @@ require lib + 'processes/manager'
|
|
|
6
6
|
require lib + 'processes/instances'
|
|
7
7
|
|
|
8
8
|
require lib + 'rpc/client/instance'
|
|
9
|
-
require lib + 'rpc/client/
|
|
9
|
+
require lib + 'rpc/client/agent'
|
|
10
10
|
|
|
11
11
|
require lib + 'rpc/server/base'
|
|
12
12
|
require lib + 'rpc/server/output'
|
|
@@ -33,9 +33,9 @@ class Server
|
|
|
33
33
|
# * {#attach Attached} to the queue monitor and transfer the management
|
|
34
34
|
# responsibility to the queue.
|
|
35
35
|
#
|
|
36
|
-
# If a {
|
|
37
|
-
# {
|
|
38
|
-
# If no {
|
|
36
|
+
# If a {Agent} has been provided, {Instance instances} will be
|
|
37
|
+
# {Agent#spawn provided} by it.
|
|
38
|
+
# If no {Agent} has been given, {Instance instances} will be spawned on the
|
|
39
39
|
# Scheduler machine.
|
|
40
40
|
#
|
|
41
41
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
@@ -379,7 +379,7 @@ class Scheduler
|
|
|
379
379
|
end
|
|
380
380
|
end
|
|
381
381
|
|
|
382
|
-
# Starts the
|
|
382
|
+
# Starts the agent's server
|
|
383
383
|
def run
|
|
384
384
|
reactor.on_error do |_, e|
|
|
385
385
|
print_error "Reactor: #{e}"
|
|
@@ -415,16 +415,16 @@ class Scheduler
|
|
|
415
415
|
)
|
|
416
416
|
end
|
|
417
417
|
|
|
418
|
-
def
|
|
419
|
-
return if !Options.
|
|
420
|
-
@
|
|
418
|
+
def agent
|
|
419
|
+
return if !Options.agent.url
|
|
420
|
+
@agent ||= RPC::Client::Agent.new( Options.agent.url )
|
|
421
421
|
end
|
|
422
422
|
|
|
423
423
|
def spawn_instance( &block )
|
|
424
|
-
if
|
|
424
|
+
if agent
|
|
425
425
|
options = {
|
|
426
426
|
owner: self.class.to_s,
|
|
427
|
-
strategy: Cuboid::Options.
|
|
427
|
+
strategy: Cuboid::Options.agent.strategy,
|
|
428
428
|
helpers: {
|
|
429
429
|
owner: {
|
|
430
430
|
url: @url
|
|
@@ -432,9 +432,9 @@ class Scheduler
|
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
|
|
435
|
+
agent.spawn options do |info|
|
|
436
436
|
if info.rpc_exception?
|
|
437
|
-
print_error "Failed to contact
|
|
437
|
+
print_error "Failed to contact Agent at: #{agent.url}"
|
|
438
438
|
print_error "[#{info.class}] #{info.to_s}"
|
|
439
439
|
block.call :error
|
|
440
440
|
next
|
data/lib/version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0
|
|
1
|
+
0.1.0
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Cuboid::OptionGroups::
|
|
3
|
+
describe Cuboid::OptionGroups::Agent do
|
|
4
4
|
include_examples 'option_group'
|
|
5
5
|
subject { described_class.new }
|
|
6
6
|
|
|
7
|
-
%w(url instance_port_range
|
|
7
|
+
%w(url instance_port_range peer ping_interval name).each do |method|
|
|
8
8
|
it { is_expected.to respond_to method }
|
|
9
9
|
it { is_expected.to respond_to "#{method}=" }
|
|
10
10
|
end
|