boutons 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4eedf75f5b88e6bc0015378dd9cccd4e32123183
4
- data.tar.gz: 576fb18f8c227b183c8c104c6aca06a97b7ca8b1
3
+ metadata.gz: 6335817799c818e80c5e9b9042192f6d259d5ee1
4
+ data.tar.gz: bd818a6d33cc0fc7bb23ad3bb2aabc3714884a0d
5
5
  SHA512:
6
- metadata.gz: 4a2ff48868a766cd4ee4d7725b9f118f37badd575a3eb60294452e07fe792d5b0e63a4ef18fb6391ea6aba0de92304332bb44699ecd127c783c4f0ebbe6531da
7
- data.tar.gz: 400f48bfd41954399837c022f5ed11c8e59c5c12a03f16f33e102662c89e4c15fcd617186e858f70da05c0a6f79df1984e1ceff474b168ad679bdaf52a6d9013
6
+ metadata.gz: 4a401dee9068d6fbc4f595a36e6e132a607200fda967961a9f10bab13b1edda3d6becaf1b88356e3720796067f33b155cee52bcd727e8670b45aa8a2dfaeea64
7
+ data.tar.gz: 352b06e6490ffe2e2ee83925dfb7988d6dd17cd3e41730311a6c91c6a8d8d30cd247d102fb021cc785abdec5f5d4e360da01bdb7d139d5f8d22485a937dcbf00
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *.tml
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ boutons
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.2
data/bin/console CHANGED
@@ -2,13 +2,5 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "boutons"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
5
+ require "pry"
6
+ Pry.start
data/boutons.gemspec CHANGED
@@ -22,10 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "synapse-easy", "~> 0.1"
23
23
  spec.add_dependency "synapse-config", "~> 0.1"
24
24
  spec.add_dependency "synapse-logging-interchangeable", "~> 0.1"
25
- spec.add_dependency "toml-rb"
26
25
  spec.add_dependency "recursive-open-struct"
27
- spec.add_dependency "bundler", "~> 1.8"
26
+ spec.add_dependency "toml-rb"
27
+ spec.add_dependency "activesupport"
28
28
 
29
+ spec.add_development_dependency "bundler", "~> 1.8"
29
30
  spec.add_development_dependency "rake", "~> 10.0"
30
- spec.add_development_dependency "unirest"
31
+ spec.add_development_dependency "pry"
31
32
  end
@@ -1,5 +1,6 @@
1
1
  require "toml"
2
2
  require "recursive-open-struct"
3
+ require "active_support/core_ext/hash/deep_merge"
3
4
 
4
5
  module Boutons
5
6
  class Config < RecursiveOpenStruct
@@ -8,15 +9,27 @@ module Boutons
8
9
  %w{. config/ ~/.boutons ~/ /etc/boutons /etc}.product(%w{tml toml}).collect{|x|File.expand_path x.join("/boutons.")}.each do |file|
9
10
  return file if File.exists? file
10
11
  end
12
+ nil
11
13
  end
12
- def use
13
- services.zookeeper.each do |service,path|
14
- Boutons.add Synapse::Easy::Service.new application: service, path: path, hosts: (discovery.zookeeper.hosts rescue nil)
15
- end rescue nil
14
+ # privaste
15
+ def defaults
16
+ { :registry => { :zookeeper => { :hosts => [ "localhost:2181" ] } } }
16
17
  end
17
- private
18
+ def with_environment
19
+ environment = defaults
20
+ environment[:registry][:zookeeper][:hosts] = ENV["ZK_HOSTS"].split(",") if ENV["ZK_HOSTS"]
21
+ environment
22
+ end
23
+ def with_configuration
24
+ file ? TOML.load_file(file,symbolize_keys:true) : {}
25
+ end
18
26
  def config params={}
19
- @config ||= self.new TOML.load_file(file,symbolize_keys:true).deep_merge(params)
27
+ unless @config
28
+ params.deep_merge! with_environment
29
+ params.deep_merge! with_configuration
30
+ @config = self.new params
31
+ end
32
+ @config
20
33
  end
21
34
  def method_missing method, *args, &block
22
35
  config.send(method, *args, &block) rescue nil
@@ -0,0 +1,16 @@
1
+ module Boutons
2
+ class Resource
3
+ class << self
4
+ def add name, object
5
+ self.instance_variable_set("@#{name}",object)
6
+ end
7
+ private
8
+ def method_missing method, *args, &block
9
+ if self.instance_variable_defined?("@#{method.to_s}")
10
+ return self.instance_variable_get("@#{method.to_s}")
11
+ end
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,70 @@
1
+ require "uri"
2
+ require "boutons/resource"
3
+
4
+ module Boutons
5
+ class URI
6
+ class Registry
7
+ def initialize uri
8
+ @uri = uri
9
+ end
10
+ def service
11
+ @uri.scheme
12
+ end
13
+ def zk_hosts
14
+ Boutons::Config.registry.send(service).hosts
15
+ end
16
+ def zk
17
+ begin
18
+ # return existing, working zookeeper connection
19
+ Boutons::Resource.zk
20
+ rescue
21
+ queue = Queue.new
22
+ threads = []
23
+ zk_hosts.each do |zk_host|
24
+ threads << Thread.new do
25
+ # connect, push connection to queue
26
+ queue << [zk_host,ZK.new(zk_host)]
27
+ end
28
+ end
29
+ host,zk = queue.pop
30
+ # set first working host as host arrays
31
+ Boutons::Config.registry.zookeeper.hosts = [host]
32
+ # register connection
33
+ Boutons::Resource.add :zk, zk
34
+ # Add later connections if there are any
35
+ Thread.new do
36
+ threads.each{|t|t.join}
37
+ host,zk = queue.pop
38
+ Boutons::Config.registry.zookeeper.hosts << host if zk.ping?
39
+ end
40
+ retry
41
+ end
42
+ end
43
+ def zk_path
44
+ return @zk_path if @zk_path
45
+ paths = []
46
+ paths << "nerve"
47
+ paths += @uri.path.split("/")[1..-1].join("/#{@uri.host}/").split("/")
48
+ paths << "services"
49
+ paths.inject([Pathname.new("/")]) do |paths,dir|
50
+ paths << paths.last.join(dir)
51
+ end.map{|p|p.to_s}.reverse.each do |path|
52
+ return @zk_path = path unless zk.children(path).empty?
53
+ end
54
+ end
55
+ end
56
+ def initialize uri
57
+ @uri ||= URI uri
58
+ end
59
+ def registry
60
+ @registry ||= Registry.new @uri
61
+ end
62
+ def type
63
+ @uri.scheme
64
+ end
65
+ private
66
+ def method_missing method, *args, &block
67
+ @uri.send method, *args, &block
68
+ end
69
+ end
70
+ end
@@ -1,3 +1,3 @@
1
1
  module Boutons
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/boutons.rb CHANGED
@@ -4,130 +4,148 @@ require "synapse"
4
4
  require "synapse/easy"
5
5
  require "synapse/config"
6
6
  require "active_support/core_ext/hash/indifferent_access"
7
+ require "active_support/core_ext/string/inflections"
7
8
  require "zookeeper"
8
9
  require "boutons/synapse"
9
10
  require "synapse/logging/interchangeable"
11
+ require "boutons/uri"
12
+ require "boutons/resource"
10
13
 
11
14
  module Boutons
12
- class SynapseNotFound < Exception; end
15
+ class UnknownSynapse < Exception; end
16
+ class MissingSynapse < Exception; end
13
17
  class << self
14
- @@haproxy = Synapse::Config::Haproxy.new Synapse::Easy::Haproxy.new
15
- @@services = Synapse::Config::Services.new
16
- @@config = { services: @@services, haproxy: @@haproxy }.with_indifferent_access
17
- @@logger = Logger.new(STDERR,progname:"Boutons")
18
- @@mapping = {}
19
18
  def add synapse
20
- return if @@services[synapse.name]
21
- @@services[synapse.name] = synapse
22
- refresh
19
+ return if services[synapse.name]
20
+ services[synapse.name] = synapse
21
+ start
23
22
  update
24
23
  end
25
24
  def remove name
26
- @@services[@@mapping[name]] = nil
27
- refresh
25
+ services[mapping[name]] = nil
26
+ start
28
27
  update
29
28
  end
30
29
  def with_loggers
31
- @@synapse.service_watchers.collect{|s|s.logger}+[@@logger,@@synapse.logger].each do |logger|
30
+ synapse.service_watchers.collect{|s|s.logger}+[logger,synapse.logger].each do |logger|
32
31
  yield(logger) if block_given?
33
32
  end
34
33
  end
35
34
  def log_with logger, synapses:nil
36
- @@logger.info "Replace logger #{@@logger} with #{logger}"
37
- @@logger=logger
38
- @@synapse.logger=@@logger
35
+ logger.info "Replace logger #{logger} with #{logger}"
36
+ logger=logger
37
+ synapse.logger=logger
39
38
  return unless synapses
40
39
  if synapses.to_sym == :all
41
- return @@synapse.service_watchers.map{|s|s.logger=@@logger}
40
+ return synapse.service_watchers.map{|s|s.logger=logger}
42
41
  end
43
- @@synapse.service_watchers.each do |services_watcher|
42
+ synapse.service_watchers.each do |services_watcher|
44
43
  if synapses==services_watcher.name
45
- services_watcher.logger = @@logger
44
+ services_watcher.logger = logger
46
45
  end
47
46
  end
48
47
  end
49
48
  def haproxy
50
- @@haproxy
49
+ @@haproxy ||= Synapse::Config::Haproxy.new Synapse::Easy::Haproxy.new
51
50
  end
52
51
  def all
53
- @@services
52
+ services
54
53
  end
55
54
  private
56
- def refresh
57
- return if defined? @@synapse
58
- @@synapse ||= Synapse::Synapse.new @@config # rescue nil
59
- return unless @@synapse
60
- @@services.map{|n,s|s.active=true}
61
- @@haproxy.inform @@synapse
55
+ def mapping
56
+ @@mapping ||= {}
57
+ end
58
+ def config
59
+ @@config ||= { services: services, haproxy: haproxy }.with_indifferent_access
60
+ end
61
+ def services
62
+ @@services ||= Synapse::Config::Services.new
63
+ end
64
+ def logger
65
+ @@logger ||= Logger.new(STDERR,progname:"Boutons")
66
+ end
67
+ def synapse
68
+ @@synapse ||= Synapse::Synapse.new config rescue nil
69
+ end
70
+ def start
71
+ return if @started
72
+ services.map{|n,s|s.active=true}
73
+ haproxy.inform synapse
62
74
  at_exit do
63
- @@logger.info "HAproxy cleanup begin"
64
- pf = @@haproxy.pid_file_path
65
- cf = @@haproxy.config_file_path
66
- sf = @@haproxy.socket_file_path
75
+ logger.info "HAproxy cleanup begin"
76
+ pf = haproxy.pid_file_path
77
+ cf = haproxy.config_file_path
78
+ sf = haproxy.socket_file_path
67
79
  pids = File.read(pf).strip
68
- @@logger.info "HAproxy stop: `kill -9 #{pids}`"
80
+ logger.info "HAproxy stop: `kill -9 #{pids}`"
69
81
  `kill -9 #{pids}`
70
82
  File.unlink(pf)
71
83
  File.unlink(sf)
72
84
  File.unlink(cf)
73
- @@logger.info "HAproxy cleanup finish"
85
+ logger.info "HAproxy cleanup finish"
74
86
  end
75
- @@services.inform @@synapse
76
- @@synapse.services = @@services
87
+ services.inform synapse
88
+ synapse.services = services
77
89
  @@synapse_thread = Thread.new do
78
- @@synapse.run
90
+ synapse.run
79
91
  end
80
92
  wait
93
+ @started = true
81
94
  end
82
95
  def wait
83
96
  loop do
84
97
  break unless restart_required
85
- sleep 0.01
98
+ sleep 0.25
86
99
  end
87
100
  end
88
101
  def restart_required
89
- @@synapse.instance_variable_get("@haproxy").instance_variable_get("@restart_required")
102
+ synapse.instance_variable_get("@haproxy").instance_variable_get("@restart_required")
90
103
  end
91
104
  def update
92
- @@mapping = {}
93
- @@services.each do |name,synapse|
94
- next if @@mapping[normalize synapse.name]
95
- @@mapping[normalize synapse.name] = name
105
+ services.each do |name,synapse|
106
+ next if mapping[normalize synapse.name]
107
+ mapping[normalize synapse.name] = name
96
108
  end
97
- @@services.each do |name,synapse|
109
+ services.each do |name,synapse|
98
110
  synapse.aliases.each do |synapse_alias|
99
- next if @@mapping[normalize synapse_alias]
100
- @@mapping[normalize synapse_alias] = name
111
+ next if mapping[normalize synapse_alias]
112
+ mapping[normalize synapse_alias] = name
101
113
  end
102
114
  end
103
115
  end
104
116
  def normalize name
105
117
  name.to_s.gsub(/\./,"_").to_sym
106
118
  end
107
- def service_from_config name
108
- return if @@mapping[name]
109
- return unless Boutons::Config.services.zookeeper.keys.include? name
110
- params = Boutons::Config.discovery.zookeeper rescue {}
111
- params[:application] = name
112
- params[:path] = Boutons::Config.services.zookeeper.send(name)
113
- Boutons.add Synapse::Easy::Service.new params
114
- end
115
- def resolv_service method, *args, &block
116
- service_from_config method
117
- name = @@mapping[method]
118
- unless name
119
- return @@services.send(method, *args, &block) if @@services.respond_to? method
120
- raise SynapseNotFound.new("The Synapse #{method} is unavailable. Add service #{method} first.") unless name
119
+ def connect service
120
+ return if mapping[service]
121
+ Boutons::Config.services.send(service).each do |service_uri|
122
+ uri = Boutons::URI.new service_uri
123
+ params = {}
124
+ params[:application] = uri.host
125
+ params[:method] = uri.registry.service
126
+ params[:path] = uri.registry.zk_path
127
+ params[:hosts] = uri.registry.zk_hosts
128
+ params[:name] = uri.registry.zk_path[1..-1].gsub(/\//,"_")
129
+ add Synapse::Easy::Service.new params
121
130
  end
122
- synapse = @@services[name]
123
- unless synapse
124
- raise SynapseNotFound.new("The Synapse #{method} is unavailable. Add service #{method} first.")
125
- end
126
- return synapse if args.empty?
127
- synapse.send(args[0],*args,&block)
131
+ end
132
+ def connectable? service
133
+ Boutons::Config.services.keys.include? service
134
+ end
135
+ def connection service
136
+ services[mapping[service]]
137
+ end
138
+ def setup service, *args, &block
139
+ raise UnknownSynapse.new("Synapse #{service} is unknown") unless connectable? service
140
+ connect service
141
+ end
142
+ def resolv service
143
+ raise MissingSynapse.new("Synapse #{service} is missing") unless connection service
144
+ connection service
128
145
  end
129
146
  def method_missing method, *args, &block
130
- resolv_service method, *args, &block
147
+ setup method, *args, &block
148
+ resolv method
131
149
  end
132
150
  end
133
151
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boutons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mathias Kaufmann
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-04-21 00:00:00.000000000 Z
11
+ date: 2015-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: synapse
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: recursive-open-struct
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: toml-rb
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +95,7 @@ dependencies:
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: recursive-open-struct
98
+ name: activesupport
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
101
  - - ">="
@@ -101,7 +115,7 @@ dependencies:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
117
  version: '1.8'
104
- type: :runtime
118
+ type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
@@ -123,7 +137,7 @@ dependencies:
123
137
  - !ruby/object:Gem::Version
124
138
  version: '10.0'
125
139
  - !ruby/object:Gem::Dependency
126
- name: unirest
140
+ name: pry
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
143
  - - ">="
@@ -145,6 +159,8 @@ extensions: []
145
159
  extra_rdoc_files: []
146
160
  files:
147
161
  - ".gitignore"
162
+ - ".ruby-gemset"
163
+ - ".ruby-version"
148
164
  - ".travis.yml"
149
165
  - Gemfile
150
166
  - README.md
@@ -154,7 +170,9 @@ files:
154
170
  - boutons.gemspec
155
171
  - lib/boutons.rb
156
172
  - lib/boutons/config.rb
173
+ - lib/boutons/resource.rb
157
174
  - lib/boutons/synapse.rb
175
+ - lib/boutons/uri.rb
158
176
  - lib/boutons/version.rb
159
177
  homepage: https://synapse.stei.gr/boutons
160
178
  licenses: []