cylons 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +3 -2
- data/Guardfile +39 -0
- data/README.md +93 -39
- data/bin/cylons +11 -12
- data/cylons.gemspec +13 -8
- data/lib/cylons.rb +43 -14
- data/lib/cylons/active_record_extensions.rb +20 -27
- data/lib/cylons/{remote_proxy.rb → agent.rb} +104 -47
- data/lib/cylons/config.rb +26 -0
- data/lib/cylons/connection.rb +11 -15
- data/lib/cylons/errors.rb +2 -1
- data/lib/cylons/local_registry.rb +5 -11
- data/lib/cylons/logging.rb +41 -0
- data/lib/cylons/railtie.rb +4 -25
- data/lib/cylons/registry_adapter.rb +10 -1
- data/lib/cylons/remote.rb +11 -22
- data/lib/cylons/remote_discovery.rb +29 -18
- data/lib/cylons/remote_pagination.rb +32 -0
- data/lib/cylons/remote_registry.rb +12 -15
- data/lib/cylons/remote_schema.rb +2 -2
- data/lib/cylons/rpc.rb +64 -72
- data/lib/cylons/service_manager.rb +30 -20
- data/lib/cylons/version.rb +1 -1
- data/spec/inventory_test_app.rb +24 -0
- data/spec/lib/cylons/connection_spec.rb +15 -0
- data/spec/lib/cylons/interface_spec.rb +7 -0
- data/spec/lib/cylons/remote_registry_spec.rb +57 -0
- data/spec/lib/cylons/service_manager_spec.rb +40 -4
- data/spec/spec_helper.rb +30 -2
- data/spec/support/inventory_test_node.rb +49 -0
- data/spec/support/schema.rb +24 -0
- metadata +181 -150
- data/lib/cylons/configuration.rb +0 -38
- data/spec/lib/cylons/remote_registry.rb +0 -7
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'dcell'
|
2
|
-
|
2
|
+
|
3
3
|
module Cylons
|
4
4
|
class RemoteDiscovery
|
5
5
|
class << self
|
@@ -7,33 +7,44 @@ module Cylons
|
|
7
7
|
attr_accessor :loaded, :loaded_remote_class_names
|
8
8
|
alias_method :loaded?, :loaded
|
9
9
|
end
|
10
|
-
|
11
|
-
def self.
|
10
|
+
|
11
|
+
def self.service_mappings
|
12
|
+
service_mapping_hash = {}
|
13
|
+
|
14
|
+
::DCell::Node.all.each do |node|
|
15
|
+
namespace = node.id
|
16
|
+
filtered_nodes = (node.actors - [:node_manager, :dcell_server, :info])
|
17
|
+
|
18
|
+
remote_class_names = filtered_nodes.select{|name| name.to_s.include?("Service") }.each do |remote_class_name|
|
19
|
+
service_mapping_hash[remote_class_name] = node.id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
service_mapping_hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.namespace_for_agent(agent_name)
|
27
|
+
service_mappings["#{agent_name}Service".to_sym]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.remote_class_names
|
31
|
+
discovered_remote_class_names = []
|
32
|
+
|
12
33
|
::DCell::Node.all.each do |node|
|
13
34
|
if node.id != ::Cylons.configuration.remote_namespace
|
14
35
|
namespace = node.id
|
15
36
|
remote_class_names = node.actors - [:node_manager, :dcell_server, :info]
|
16
37
|
remote_class_names.select{|name| name.to_s.include?("Service") }.each do |remote_class_name|
|
17
|
-
|
18
|
-
build_remote(namespace, remote_class_name)
|
38
|
+
discovered_remote_class_names << remote_class_name
|
19
39
|
end if remote_class_names.any?
|
20
40
|
end
|
21
41
|
end
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.build_remote(namespace, remote_class_name)
|
27
|
-
proxy_class_name = remote_class_name.to_s.gsub('Service', '')
|
28
|
-
Object.const_set(proxy_class_name, Class.new(Cylons::RemoteProxy))
|
29
|
-
|
30
|
-
proxy_class = proxy_class_name.constantize
|
31
|
-
proxy_class.load_schema
|
32
|
-
proxy_class.remote = ::DCell::Node[namespace][remote_class_name]
|
42
|
+
|
43
|
+
discovered_remote_class_names
|
33
44
|
end
|
34
|
-
|
45
|
+
|
35
46
|
def self.remote_proxy_class_name(namespace, remote_class_name)
|
36
47
|
"#{namespace}::#{remote_class_name.to_s}".gsub('Service', '')
|
37
48
|
end
|
38
49
|
end
|
39
|
-
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Cylons
|
2
|
+
module RemotePagination
|
3
|
+
extend ::ActiveSupport::Concern
|
4
|
+
|
5
|
+
META_METHODS = [
|
6
|
+
:total_pages,
|
7
|
+
:current_page
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
SEARCH_OPTION_KEYS = [:opts, :options].freeze
|
11
|
+
MAX_PER_PAGE = 1000
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def search(params = {})
|
15
|
+
search_options = params.extract!(*SEARCH_OPTION_KEYS)
|
16
|
+
|
17
|
+
search_options.delete_if {|k,v| v.nil? }
|
18
|
+
|
19
|
+
query_scope = params.inject(all) do |query, hash_pair|
|
20
|
+
query.__send__("by_#{hash_pair[0]}", hash_pair[1]).all
|
21
|
+
end.all
|
22
|
+
|
23
|
+
if search_options.present?
|
24
|
+
query_scope.paginate(:page => search_options[:options][:page], :per_page => search_options[:options][:per_page])
|
25
|
+
else
|
26
|
+
query_scope.paginate(:page => 1, :per_page => MAX_PER_PAGE)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -6,44 +6,41 @@ module Cylons
|
|
6
6
|
@remotes ||= []
|
7
7
|
@loaded_remotes ||= []
|
8
8
|
@remote_schemas ||= {}
|
9
|
-
|
9
|
+
|
10
10
|
class << self
|
11
11
|
attr_accessor :remotes, :loaded_remotes
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def self.clear_registry
|
15
15
|
::DCell.registry.instance_variable_get("@global_registry").clear
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def self.register(klass)
|
19
|
+
::Cylons::Connection.connect unless ::Cylons::Connection.connected?
|
19
20
|
@remotes << klass
|
20
21
|
end
|
21
|
-
|
22
|
-
def self.register_class?(namespaced_class_name)
|
23
|
-
!defined?(namespaced_class_name.constantize)
|
24
|
-
end
|
25
|
-
|
22
|
+
|
26
23
|
def self.register_schemas
|
27
24
|
@remotes.each do |remote|
|
28
25
|
::Cylons.logger.info remote
|
29
26
|
register_remote_schema(remote)
|
30
27
|
end
|
31
28
|
end
|
32
|
-
|
29
|
+
|
33
30
|
def self.remote_schemas
|
34
31
|
::DCell::Global.keys
|
35
32
|
end
|
36
|
-
|
33
|
+
|
37
34
|
def self.register_remote_schema(klass)
|
38
35
|
::DCell::Global["#{klass.name.downcase}_schema".to_sym] = ::Cylons::RemoteSchema.new(klass)
|
39
36
|
end
|
40
|
-
|
37
|
+
|
41
38
|
def self.remote_schema?(name)
|
42
|
-
::DCell::Global.
|
39
|
+
::DCell::Global.keys.include? "#{name}_schema".to_sym
|
43
40
|
end
|
44
|
-
|
41
|
+
|
45
42
|
def self.get_remote_schema(name)
|
46
43
|
::DCell::Global["#{name}_schema".to_sym]
|
47
44
|
end
|
48
|
-
end
|
49
|
-
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/cylons/remote_schema.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Cylons
|
2
2
|
class RemoteSchema
|
3
3
|
attr_accessor :remote_associations, :remote_attributes, :remote_search_scopes, :remote_klass
|
4
|
-
|
4
|
+
|
5
5
|
def initialize(klass)
|
6
6
|
@remote_attributes ||= klass.attribute_names
|
7
7
|
@remote_associations ||= klass.remote_associations
|
@@ -9,4 +9,4 @@ module Cylons
|
|
9
9
|
@remote_klass ||= klass.name.downcase.to_sym
|
10
10
|
end
|
11
11
|
end
|
12
|
-
end
|
12
|
+
end
|
data/lib/cylons/rpc.rb
CHANGED
@@ -1,86 +1,78 @@
|
|
1
|
-
require 'ransack'
|
2
1
|
module Cylons
|
3
2
|
module RPC
|
4
3
|
extend ::ActiveSupport::Concern
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
execute(:all)
|
12
|
-
end
|
13
|
-
|
14
|
-
def create(params)
|
15
|
-
execute(:create, params)
|
16
|
-
end
|
17
|
-
|
18
|
-
def destroy(id)
|
19
|
-
execute(:destroy, id)
|
20
|
-
end
|
21
|
-
|
22
|
-
def execute(rpc_method, request_params = {})
|
23
|
-
begin
|
24
|
-
@last_response = self.class.model.send(rpc_method.to_sym, request_params)
|
25
|
-
rescue => e
|
26
|
-
puts e.inspect
|
27
|
-
@last_response = {:error => e.message}
|
28
|
-
end
|
4
|
+
include ::ActiveModel::Dirty
|
5
|
+
include ::Cylons::Attributes
|
6
|
+
|
7
|
+
#need to wrap because to_a will leak connections otherwise
|
8
|
+
def all
|
9
|
+
::ActiveRecord::Base.connection_pool.with_connection do
|
10
|
+
execute(:all).to_a
|
29
11
|
end
|
30
|
-
|
31
|
-
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(params)
|
15
|
+
execute(:create, params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy(id)
|
19
|
+
execute(:destroy, id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(rpc_method, *args)
|
23
|
+
puts Thread.current.object_id
|
24
|
+
|
25
|
+
::ActiveRecord::Base.connection_pool.with_connection do
|
26
|
+
puts ::ActiveRecord::Base.connection_pool.instance_variable_get("@connections").size
|
32
27
|
begin
|
33
|
-
|
28
|
+
if args.any?
|
29
|
+
@last_response = self.class.model.send(rpc_method.to_sym, *args)
|
30
|
+
else
|
31
|
+
@last_response = self.class.model.send(rpc_method.to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
@last_response
|
34
35
|
rescue => e
|
35
36
|
puts e.inspect
|
36
|
-
puts e.message
|
37
|
-
puts @last_response.inspect
|
38
37
|
@last_response = {:error => e.message}
|
39
38
|
end
|
40
39
|
end
|
41
|
-
|
42
|
-
def find(id)
|
43
|
-
execute(:find, id)
|
44
|
-
end
|
45
|
-
|
46
|
-
def first
|
47
|
-
execute(:first)
|
48
|
-
end
|
49
|
-
|
50
|
-
def first_or_create(params)
|
51
|
-
execute(:first_or_create, params)
|
52
|
-
end
|
40
|
+
end
|
53
41
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
42
|
+
def find(id)
|
43
|
+
execute(:find, id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def first
|
47
|
+
execute(:first)
|
48
|
+
end
|
49
|
+
|
50
|
+
def first_or_create(params)
|
51
|
+
execute(:first_or_create, params)
|
52
|
+
end
|
53
|
+
|
54
|
+
def last
|
55
|
+
execute(:last)
|
56
|
+
end
|
57
|
+
|
58
|
+
def search(params)
|
59
|
+
response = execute(:search, params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def scope_by(params)
|
63
|
+
execute(:scope_by, params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def save(id = nil, attributes)
|
67
|
+
if(id)
|
68
|
+
execute(:update, id, attributes)
|
69
|
+
else
|
70
|
+
execute(:create, attributes)
|
79
71
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
72
|
+
end
|
73
|
+
|
74
|
+
def update(attributes)
|
75
|
+
execute(:update, attributes.keys, attributes.values)
|
84
76
|
end
|
85
77
|
end
|
86
|
-
end
|
78
|
+
end
|
@@ -4,41 +4,51 @@ require 'cylons/remote_registry'
|
|
4
4
|
module Cylons
|
5
5
|
class ServiceManager
|
6
6
|
def self.start
|
7
|
-
::Cylons.logger.info "
|
8
|
-
puts "LOADING REMOTES"
|
9
|
-
::Cylons::RemoteDiscovery.load_remotes unless ::Cylons::RemoteDiscovery.loaded?
|
10
|
-
puts "STARTING LOCAL REMOTE SERVICES"
|
11
|
-
::Cylons.logger.info "STARTING LOCAL REMOTE SERVICES"
|
7
|
+
::Cylons.logger.info "STARTING CYLON SERVICES"
|
12
8
|
start_services
|
13
9
|
end
|
14
|
-
|
10
|
+
|
11
|
+
#todo: split supervision and building
|
15
12
|
def self.start_service(model_klass)
|
16
|
-
|
17
|
-
|
13
|
+
unless service_defined?(model_klass)
|
14
|
+
service_klass = build_service(model_klass)
|
15
|
+
|
16
|
+
service_klass.supervise_as service_klass.name.to_sym
|
17
|
+
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def self.build_service(model_klass)
|
21
21
|
proxy_service_class_name = "#{model_klass.name}Service"
|
22
|
-
Object.const_set(proxy_service_class_name, Class.new(::Cylons::Service))
|
22
|
+
::Object.const_set(proxy_service_class_name, ::Class.new(::Cylons::Service))
|
23
23
|
service_klass = proxy_service_class_name.constantize
|
24
|
-
|
25
24
|
service_klass.model = model_klass
|
26
|
-
|
25
|
+
|
26
|
+
::Cylons.logger.info "REGISTERING_SERVICE_FOR #{model_klass}"
|
27
|
+
|
27
28
|
service_klass
|
28
29
|
end
|
29
|
-
|
30
|
+
|
31
|
+
def self.service_defined?(model_klass)
|
32
|
+
proxy_service_class_name = "#{model_klass.name}Service"
|
33
|
+
|
34
|
+
const_defined?(:"#{proxy_service_class_name}")
|
35
|
+
end
|
36
|
+
|
30
37
|
def self.start_services
|
31
38
|
::Cylons::RemoteRegistry.remotes.each do |remote|
|
32
39
|
start_service(remote)
|
33
40
|
end if remotes?
|
34
41
|
end
|
35
|
-
|
36
|
-
def self.service_klass_name
|
37
|
-
"#{klass.name}Service"
|
38
|
-
end
|
39
|
-
|
42
|
+
|
40
43
|
def self.remotes?
|
41
44
|
::Cylons::RemoteRegistry.remotes.any?
|
42
|
-
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.stop
|
48
|
+
::Cylons::RemoteRegistry.remotes.each do |remote|
|
49
|
+
::Cylons.logger.info{ "Shutting Down #{remote.name}"}
|
50
|
+
remote.stop
|
51
|
+
end
|
52
|
+
end
|
43
53
|
end
|
44
|
-
end
|
54
|
+
end
|
data/lib/cylons/version.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
# The DCell specs start a completely separate Ruby VM running this code
|
2
|
+
# for complete integration testing using 0MQ over TCP
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
require 'active_record'
|
7
|
+
Bundler.setup
|
8
|
+
|
9
|
+
require 'cylons'
|
10
|
+
|
11
|
+
ENV["RPC"] = "1"
|
12
|
+
|
13
|
+
::Cylons.configure do |config|
|
14
|
+
#if you are running multiple machines, connect to the ZK registry machine via:
|
15
|
+
# config.registry_address = "X.X.X.X"
|
16
|
+
config.remote_namespace = "InventoryTest"
|
17
|
+
# config.registry_adapter = :zk
|
18
|
+
end
|
19
|
+
|
20
|
+
class Product < ActiveRecord::Base
|
21
|
+
include ::Cylons::Remote
|
22
|
+
end
|
23
|
+
|
24
|
+
::Cylons::ServiceManager.start
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ::Cylons::Connection do
|
4
|
+
subject { described_class }
|
5
|
+
|
6
|
+
its(:connected) { should be true }
|
7
|
+
|
8
|
+
describe ".validate_configuration" do
|
9
|
+
it "should raise error if no remote namespace present" do
|
10
|
+
::Cylons.configuration.remote_namespace.stub(:present?).and_return(false)
|
11
|
+
expect{ subject.validate_configuration }.to raise_error ::Cylons::RemoteNamespaceNotSet
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|