boutons 0.2.1 → 0.3.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 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: []