cylons 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,69 +1,68 @@
|
|
1
1
|
require 'cylons/associations'
|
2
2
|
|
3
3
|
module Cylons
|
4
|
-
|
4
|
+
|
5
5
|
#this is the local application remote which is dynamically built, from the registry
|
6
|
-
class
|
6
|
+
class Agent
|
7
7
|
include ::ActiveModel::Dirty
|
8
8
|
include ::ActiveModel::AttributeMethods
|
9
|
-
include ActiveAttr::Model
|
10
|
-
include ActiveAttr::MassAssignment
|
9
|
+
include ::ActiveAttr::Model
|
10
|
+
include ::ActiveAttr::MassAssignment
|
11
11
|
include ::Cylons::Attributes
|
12
|
-
|
13
|
-
|
12
|
+
include ::Cylons::Associations
|
13
|
+
|
14
|
+
class_attribute :unsucessful_remote_connection_attempts
|
15
|
+
self.unsucessful_remote_connection_attempts ||= 0
|
16
|
+
|
17
|
+
class << self
|
18
|
+
attr_accessor :schema, :built
|
19
|
+
end
|
20
|
+
|
21
|
+
@built = false
|
22
|
+
|
23
|
+
def self.inherited(subklass)
|
24
|
+
::Cylons.connect unless ::Cylons.connected?
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.build_agent
|
28
|
+
load_schema
|
29
|
+
@built = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.service_class_name
|
33
|
+
"#{name}Service"
|
34
|
+
end
|
35
|
+
|
14
36
|
def self.load_schema
|
15
|
-
|
16
|
-
|
37
|
+
::Cylons.logger.debug { "Loading schema for #{name}" }
|
38
|
+
|
39
|
+
@schema = ::Cylons::RemoteRegistry.get_remote_schema(name.downcase)
|
40
|
+
|
17
41
|
@schema.remote_attributes.each do |remote_attribute|
|
18
42
|
attribute remote_attribute.to_sym
|
19
43
|
end
|
20
|
-
|
44
|
+
|
21
45
|
@schema.remote_associations.each do |association_hash|
|
22
46
|
__send__("build_remote_#{association_hash[:association_type]}_association", association_hash)
|
23
47
|
end
|
24
48
|
end
|
25
|
-
|
26
|
-
class << self
|
27
|
-
attr_accessor :remote, :schema
|
28
|
-
end
|
29
|
-
|
30
|
-
attr_accessor :errors
|
31
|
-
|
32
|
-
def destroy
|
33
|
-
return unless self.attributes["id"]
|
34
|
-
result = self.class.remote.destroy(self.attributes["id"])
|
35
|
-
end
|
36
|
-
|
37
|
-
#have to manually update attributes if id wasnt set, i believe attr_accessible oddity so maybe can rip out later
|
38
|
-
def save
|
39
|
-
if self.attributes["id"]
|
40
|
-
result = self.class.remote.save(self.attributes["id"], self.attributes.with_indifferent_access.slice(*self.changed))
|
41
|
-
self.changed_attributes.clear
|
42
|
-
else
|
43
|
-
result = self.class.remote.save(nil, self.attributes.with_indifferent_access.slice(*self.changed))
|
44
|
-
|
45
|
-
if result.errors.messages.present?
|
46
|
-
self.assign_attributes({:errors => result.errors})
|
47
|
-
else
|
48
|
-
self.assign_attributes(result.attributes)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
result
|
53
|
-
end
|
54
49
|
|
55
50
|
def self.all
|
56
51
|
remote.all
|
57
52
|
end
|
58
|
-
|
53
|
+
|
54
|
+
def self.agent_namespace
|
55
|
+
@agent_namespace ||= ::Cylons::RemoteDiscovery.namespace_for_agent(self.name)
|
56
|
+
end
|
57
|
+
|
59
58
|
def self.count
|
60
59
|
remote.count
|
61
60
|
end
|
62
|
-
|
61
|
+
|
63
62
|
def self.first
|
64
63
|
remote.first
|
65
64
|
end
|
66
|
-
|
65
|
+
|
67
66
|
def self.find(id)
|
68
67
|
remote.find(id)
|
69
68
|
end
|
@@ -71,29 +70,87 @@ module Cylons
|
|
71
70
|
def self.last
|
72
71
|
remote.last
|
73
72
|
end
|
74
|
-
|
73
|
+
|
75
74
|
def self.create(params)
|
76
75
|
remote.create(params)
|
77
76
|
end
|
78
|
-
|
77
|
+
|
79
78
|
def self.search(params)
|
80
79
|
remote.search(params)
|
81
80
|
end
|
82
|
-
|
81
|
+
|
83
82
|
def self.scope_by(params)
|
84
83
|
remote.scope_by(params)
|
85
84
|
end
|
86
|
-
|
85
|
+
|
87
86
|
def self.first_or_create(params)
|
88
87
|
result = remote.scope_by(params).first
|
89
88
|
result = remote.create(params) unless result.present?
|
90
89
|
result
|
91
90
|
end
|
92
|
-
|
91
|
+
|
93
92
|
def self.first_or_initialize(params)
|
94
93
|
result = remote.scope_by(params).first
|
95
94
|
result ||= remote.new(params) unless result.present?
|
96
95
|
result
|
97
96
|
end
|
97
|
+
|
98
|
+
def self.remote
|
99
|
+
remote_connection_failed! unless remote?
|
100
|
+
|
101
|
+
build_agent unless built
|
102
|
+
|
103
|
+
::DCell::Node[agent_namespace][service_class_name.to_sym]
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.remote?
|
107
|
+
agent_namespace && remote_application? && remote_service?
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.remote_application?
|
111
|
+
::DCell::Node.all.any?{ |node|
|
112
|
+
node.id == agent_namespace
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.remote_service?
|
117
|
+
::DCell::Node[agent_namespace].actors.include?(service_class_name.to_sym)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.remote_connection_failed!
|
121
|
+
if self.unsucessful_remote_connection_attempts > ::Cylons.config.remote_connection_failure_threshold
|
122
|
+
self.unsucessful_remote_connection_attempts = 0
|
123
|
+
raise ::Cylons::CylonsRemoteServiceNotFound, "#{service_class_name} not found"
|
124
|
+
else
|
125
|
+
sleep(::Cylons.config.remote_connection_failure_timeout)
|
126
|
+
self.unsucessful_remote_connection_attempts += 1
|
127
|
+
remote_connection_failed! unless remote?
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
attr_accessor :errors
|
132
|
+
|
133
|
+
def destroy
|
134
|
+
return unless self.attributes["id"]
|
135
|
+
result = self.class.remote.destroy(self.attributes["id"])
|
136
|
+
end
|
137
|
+
|
138
|
+
#have to manually update attributes if id wasnt set, i believe attr_accessible oddity so maybe can rip out later
|
139
|
+
def save
|
140
|
+
if self.attributes["id"]
|
141
|
+
result = self.class.remote.save(self.attributes["id"], self.attributes.with_indifferent_access.slice(*self.changed))
|
142
|
+
self.changed_attributes.clear
|
143
|
+
else
|
144
|
+
result = self.class.remote.save(nil, self.attributes.with_indifferent_access.slice(*self.changed))
|
145
|
+
|
146
|
+
if result.errors.messages.present?
|
147
|
+
self.assign_attributes({:errors => result.errors})
|
148
|
+
else
|
149
|
+
self.assign_attributes(result.attributes)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
result
|
154
|
+
end
|
98
155
|
end
|
99
|
-
end
|
156
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support/ordered_options'
|
2
|
+
require 'cylons'
|
3
|
+
require 'cylons/registry_adapter'
|
4
|
+
|
5
|
+
module Cylons
|
6
|
+
class Config < ::ActiveSupport::InheritableOptions
|
7
|
+
def initialize(*args)
|
8
|
+
super(*args)
|
9
|
+
|
10
|
+
self[:address] ||= ::Cylons::Interface.primary
|
11
|
+
self[:port] ||= (9000 + rand(100))
|
12
|
+
self[:logger] ||= ::Cylons::Logging.logger
|
13
|
+
self[:model_paths] ||= nil
|
14
|
+
self[:registry] ||= nil
|
15
|
+
self[:registry_adapter] ||= :zk
|
16
|
+
self[:registry_port] ||= nil
|
17
|
+
self[:remote_namespace] ||= nil
|
18
|
+
self[:remote_connection_failure_timeout] ||= 10
|
19
|
+
self[:remote_connection_failure_threshold] ||= 2
|
20
|
+
end
|
21
|
+
|
22
|
+
def registry
|
23
|
+
@registry ||= ::Cylons::RegistryAdapter.send(self[:registry_adapter])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/cylons/connection.rb
CHANGED
@@ -5,40 +5,36 @@ module Cylons
|
|
5
5
|
class << self
|
6
6
|
@connected ||= false
|
7
7
|
attr_accessor :connected
|
8
|
-
|
8
|
+
|
9
9
|
alias_method :connected?, :connected
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def self.validate_configuration
|
13
13
|
raise ::Cylons::RemoteNamespaceNotSet unless ::Cylons.configuration.remote_namespace.present?
|
14
14
|
end
|
15
|
-
|
16
|
-
#todo: FixMe
|
17
|
-
#super hacky.. pass in SKIP_CYLONS=true when running rake tasks for now, ew
|
18
|
-
def self.connect?
|
19
|
-
ENV['SKIP_CYLONS'].present?
|
20
|
-
end
|
21
|
-
|
15
|
+
|
22
16
|
def self.connect
|
23
|
-
return if
|
17
|
+
return if ::Cylons.silence?
|
18
|
+
|
24
19
|
validate_configuration
|
20
|
+
|
25
21
|
::Cylons.logger.info "STARTING DCELL FOR #{::Cylons.configuration.remote_namespace} NOW"
|
26
|
-
|
22
|
+
|
27
23
|
::Cylons.logger.info "Cylons attempting to connect to registry at #{node_address}"
|
28
24
|
|
29
25
|
::DCell.start :id => ::Cylons.configuration.remote_namespace,
|
30
26
|
:addr => node_address,
|
31
27
|
:registry => registry_hash
|
32
|
-
|
28
|
+
|
33
29
|
@connected = true
|
34
30
|
end
|
35
|
-
|
31
|
+
|
36
32
|
def self.node_address
|
37
33
|
"tcp://#{::Cylons.configuration.address}:#{::Cylons.configuration.port}"
|
38
34
|
end
|
39
|
-
|
35
|
+
|
40
36
|
def self.registry_hash
|
41
37
|
::Cylons.configuration.registry
|
42
38
|
end
|
43
39
|
end
|
44
|
-
end
|
40
|
+
end
|
data/lib/cylons/errors.rb
CHANGED
@@ -2,10 +2,11 @@ module Cylons
|
|
2
2
|
class CylonsError < StandardError; end
|
3
3
|
class CylonsConfigurationError < CylonsError; end
|
4
4
|
class CylonsRemoteError < CylonsError; end
|
5
|
+
class CylonsRemoteServiceNotFound < CylonsError; end
|
5
6
|
class CylonsRemoteProxyError < CylonsError; end
|
6
7
|
class CylonsRecordNotFound < CylonsRemoteError; end
|
7
8
|
class InvalidRegistryAdapter < CylonsConfigurationError; end
|
8
9
|
class CouldNotConnectToRegistry < CylonsConfigurationError; end
|
9
10
|
class RemoteNamespaceNotSet < CylonsConfigurationError; end
|
10
11
|
class HowDoYouKillThatWhichHasNoLife < CylonsRemoteProxyError; end
|
11
|
-
end
|
12
|
+
end
|
@@ -4,27 +4,21 @@ require 'cylons/remote_registry'
|
|
4
4
|
|
5
5
|
module Cylons
|
6
6
|
class LocalRegistry
|
7
|
-
|
8
7
|
@remotes ||= []
|
9
8
|
@loaded_remotes ||= []
|
10
|
-
|
9
|
+
|
11
10
|
class << self
|
12
11
|
attr_accessor :remotes, :loaded_remotes
|
13
12
|
end
|
14
|
-
|
13
|
+
|
15
14
|
def self.register(klass)
|
16
15
|
@remotes << klass
|
17
16
|
end
|
18
|
-
|
19
|
-
def self.register_class?(namespaced_class_name)
|
20
|
-
!defined?(namespaced_class_name.constantize)
|
21
|
-
end
|
22
|
-
|
17
|
+
|
23
18
|
def self.register_remote_schemas
|
24
19
|
@remotes.each do |remote|
|
25
20
|
::Cylons::RemoteRegistry.register_remote_schema(remote)
|
26
21
|
end
|
27
22
|
end
|
28
|
-
|
29
|
-
|
30
|
-
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Cylons
|
4
|
+
module Logging
|
5
|
+
def self.initialize_logger(log_target=$stdout, log_level=::Logger::INFO)
|
6
|
+
@counter ||= 0
|
7
|
+
@counter = @counter + 1
|
8
|
+
@logger = ::Logger.new(log_target)
|
9
|
+
@logger.level = log_level
|
10
|
+
@logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.logger
|
14
|
+
defined?(@logger) ? @logger : initialize_logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.logger=(new_logger)
|
18
|
+
@logger = new_logger
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger
|
22
|
+
::Cylons::Logging.logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_exception(ex)
|
26
|
+
logger.error { ex.message }
|
27
|
+
logger.error { ex.backtrace[0..5].join("\n") }
|
28
|
+
logger.debug { ex.backtrace.join("\n") }
|
29
|
+
end
|
30
|
+
|
31
|
+
def log_signature
|
32
|
+
@_log_signature ||= "[#{self.class == Class ? self.name : self.class.name}]"
|
33
|
+
end
|
34
|
+
|
35
|
+
def sign_message(message)
|
36
|
+
"#{log_signature} #{message}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Taken from [protobuf](https://github.com/localshred/protobuf)
|
data/lib/cylons/railtie.rb
CHANGED
@@ -2,37 +2,16 @@ require 'cylons'
|
|
2
2
|
require 'rails'
|
3
3
|
require 'rails/railtie'
|
4
4
|
require 'active_record'
|
5
|
-
require '
|
6
|
-
require 'ransack/search'
|
7
|
-
require 'ransack/adapters/active_record/base'
|
8
|
-
require 'will_paginate'
|
5
|
+
require 'will_paginate/array'
|
9
6
|
|
10
7
|
module Cylons
|
11
8
|
class Railtie < ::Rails::Railtie
|
12
|
-
config.after_initialize do
|
13
|
-
::Cylons::RemoteDiscovery.load_remotes unless ::Cylons.silence? || ::Cylons::RemoteDiscovery.loaded?
|
14
|
-
end
|
15
|
-
|
16
9
|
::ActiveSupport.on_load(:cylons) do
|
17
10
|
::Cylons::Connection.connect unless ::Cylons.silence? || ::Cylons::RemoteDiscovery.loaded? || ::Cylons::Connection.connected?
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
#todo: overwrite ransack search method to auto paginate by default, or pull ransack out..
|
11
|
+
end if ::Cylons.connect?
|
12
|
+
|
22
13
|
::ActiveSupport.on_load(:active_record) do
|
23
|
-
::ActiveRecord::Base.extend ::Ransack::Adapters::ActiveRecord::Base
|
24
14
|
require 'will_paginate/active_record'
|
25
|
-
|
26
|
-
case ::ActiveRecord::VERSION::STRING
|
27
|
-
when /^3\.0\./
|
28
|
-
require 'ransack/adapters/active_record/3.0/context'
|
29
|
-
when /^3\.1\./
|
30
|
-
require 'ransack/adapters/active_record/3.1/context'
|
31
|
-
when /^3\.2\./
|
32
|
-
require 'ransack/adapters/active_record/3.2/context'
|
33
|
-
else
|
34
|
-
require 'ransack/adapters/active_record/context'
|
35
|
-
end
|
36
15
|
end
|
37
16
|
end
|
38
|
-
end
|
17
|
+
end
|
@@ -15,8 +15,17 @@ module Cylons
|
|
15
15
|
def self.zk(options = {})
|
16
16
|
zk_registry_hash = zk_defaults.dup
|
17
17
|
zk_registry_hash[:server] = ::Cylons.configuration.registry_address if ::Cylons.configuration.registry_address
|
18
|
-
zk_registry_hash[:
|
18
|
+
zk_registry_hash[:registry_port] = ::Cylons.configuration.registry_port if ::Cylons.configuration.registry_port
|
19
19
|
zk_registry_hash
|
20
20
|
end
|
21
|
+
|
22
|
+
def self.redis_defaults
|
23
|
+
{:adapter => 'redis', :port => 6379, :address => "127.0.0.1"}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.redis(options = {})
|
27
|
+
redis_registry_hash = redis_defaults.dup
|
28
|
+
redis_registry_hash
|
29
|
+
end
|
21
30
|
end
|
22
31
|
end
|
data/lib/cylons/remote.rb
CHANGED
@@ -1,29 +1,18 @@
|
|
1
1
|
require 'cylons/remote_registry'
|
2
2
|
require 'cylons/active_record_extensions'
|
3
3
|
|
4
|
-
#todo: fix
|
5
|
-
#think RemoteRegistry needs to be split into a local registry, which the remote registry
|
6
|
-
#is pushed information to, or pulls information from, because the damn dcell wont stop
|
7
|
-
#trying to connect or throwing not configured errors when rake tasks and what not,
|
8
|
-
#need complete separation of local/remote
|
9
|
-
#update, think I mostly fixed issue but leaving note here becaue better separation
|
10
|
-
#still needs to be done.
|
11
4
|
module Cylons
|
12
5
|
module Remote
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
extend ::Cylons::Associations::ClassMethods
|
24
|
-
|
25
|
-
::Cylons::RemoteRegistry.register(klass)
|
26
|
-
end
|
6
|
+
extend ::ActiveSupport::Concern
|
7
|
+
|
8
|
+
include ::Cylons::ActiveRecordExtensions
|
9
|
+
include ::Cylons::Associations
|
10
|
+
|
11
|
+
included do
|
12
|
+
class_attribute :remote_associations
|
13
|
+
self.remote_associations = []
|
14
|
+
|
15
|
+
::Cylons::RemoteRegistry.register(self)
|
27
16
|
end
|
28
17
|
end
|
29
|
-
end
|
18
|
+
end
|