philae 0.3.0 → 0.5.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
  SHA256:
3
- metadata.gz: 4058dbbd9d47df1d46c0bb68315c17dfd38981a3d8d884be768df8aca9fa68d0
4
- data.tar.gz: f745431b27b4371084f53ae649c94b362164ce68ab88353a7c8cee6213ccd014
3
+ metadata.gz: ffa3d30f51168d0d1ae72b1689900daf71eeb832aa9434f2c8d13040b962e156
4
+ data.tar.gz: e2eca87f43d64cf211f8d8705032f35378473c53e50dad83520bf408fbfcf857
5
5
  SHA512:
6
- metadata.gz: c3a8c85060058e306066489391a38abf0cd81dbc03f505b7bd033f75eb282dc9f9a1cc77f285755c32a92cf8739f5aba77c1d01018dbf27b29dad73c997cd1fa
7
- data.tar.gz: 96aab47fb98d8d03b6260046a4b3aa8bd6933ebf0c25126b25487bb8dead8d08db6d4ebdb00abb89b29cc8d0d67212f9ba68ca68b923f46b28cd9490aa284035
6
+ metadata.gz: 186c411027e257cd9d2b482c2228e0bdc1cd8be2f68730b40ff23329ecd8b544afed4866fdad86625ecd57d3ce6a31a6627c4450110846885d8c6389e6005bae
7
+ data.tar.gz: 19377fb811659ff0a3339f223ff1502ed3678e2e9626476338811caa7e258c27676ae63f4ddb8fd1147a7bd683af5a0b6a700e386302892530637d44d4d75b75
@@ -0,0 +1,54 @@
1
+ module Philae
2
+ class CollectionProbe
3
+ def initialize(*args)
4
+ raise ArgumentError, "can't be instantiate, use specialized class"
5
+ end
6
+
7
+ def probes
8
+ raise ArgumentError, 'specialized class should implement :probes'
9
+ end
10
+
11
+ def check
12
+ results = []
13
+ result_queue = Queue.new
14
+ probes.each do |probe|
15
+ Thread.new do
16
+ begin
17
+ result = probe.check
18
+ rescue StandardError => e
19
+ result = {
20
+ healthy: false,
21
+ error: "probe #{probe.name} check failed: #{e.class} - #{e.message}",
22
+ }
23
+ end
24
+ result[:probe] = probe
25
+ result_queue.push result
26
+ end
27
+ end
28
+
29
+ loop do
30
+ results.push result_queue.pop
31
+ break if results.count == probes.length
32
+ end
33
+
34
+ failed_results = results.select do |result|
35
+ result[:healthy] == false
36
+ end
37
+
38
+ error = failed_results.map do |result|
39
+ msg = "#{result[:probe].name}: #{result[:comment]} "
40
+ msg += result[:code] if result[:code]
41
+ msg += result[:error] if result[:error]
42
+ next msg
43
+ end.join(', ')
44
+
45
+ if failed_results.count == probes.count
46
+ return { healthy: false, comment: "All #{name} nodes are down", error: error }
47
+ elsif failed_results.count > 0
48
+ return { healthy: true, comment: "#{failed_results.count} #{name} nodes are down: #{error}" }
49
+ else
50
+ return { healthy: true, comment: '' }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -4,19 +4,19 @@ module Philae
4
4
  class DockerProbe
5
5
  attr_reader :name
6
6
 
7
- def initialize(name, endpoint = '/var/run/docker.sock', options = nil)
7
+ def initialize(name, endpoint = '/var/run/docker.sock', options = {})
8
8
  @name = name
9
9
  @endpoint = endpoint
10
- @docker_options = options
10
+ @docker_options = {read_timeout: 50, connect_timeout: 50}.merge(options)
11
11
  end
12
12
 
13
13
  def check
14
14
  Docker.url = @endpoint
15
- Docker.options = @docker_options if !@docker_options.nil?
15
+ Docker.options = @docker_options
16
16
  begin
17
17
  Docker::Container.all
18
- rescue
19
- return { healthy: false, comment: 'Unable to communicate with docker' }
18
+ rescue => e
19
+ return { healthy: false, comment: "Unable to communicate with docker (#{e.message})" }
20
20
  end
21
21
 
22
22
  return { healthy: true, comment: '' }
@@ -0,0 +1,30 @@
1
+ require_relative 'collection_probe'
2
+ require_relative 'etcd_probe'
3
+
4
+ module Philae
5
+ class EtcdClusterProbe < CollectionProbe
6
+ attr_reader :name, :etcd_probes
7
+
8
+ # @param [Integer] read_timeout Timeout in second for the HTTP request
9
+ def initialize(name, endpoints, read_timeout: 1, cacert: nil, ssl_cert: nil, ssl_key: nil)
10
+ raise ArgumentError, 'empty endpoints' if endpoints.nil? || endpoints.empty?
11
+
12
+ @etcd_probes = endpoints.map do |endpoint|
13
+ endpoint_uri = URI(endpoint)
14
+ next EtcdProbe.new(
15
+ "#{name}-#{endpoint_uri.host}-#{endpoint_uri.port}",
16
+ endpoint_uri.host,
17
+ endpoint_uri.port,
18
+ read_timeout: read_timeout, cacert: cacert,
19
+ ssl_cert: ssl_cert, ssl_key: ssl_key,
20
+ )
21
+ end
22
+
23
+ @name = name
24
+ end
25
+
26
+ def probes
27
+ return @etcd_probes
28
+ end
29
+ end
30
+ end
@@ -11,12 +11,13 @@ module Philae
11
11
  # key: "path/to/key",
12
12
  # ca: "path/to/ca"
13
13
  # }
14
- def initialize(name, uri, username = nil, password = nil, tls_context = nil)
14
+ def initialize(name, uri, username = nil, password = nil, tls_context = nil, timeout = nil)
15
15
  @name = name
16
16
  @uri = uri
17
17
  @username = username
18
18
  @password = password
19
19
  @tls_context = tls_context
20
+ @timeout = timeout
20
21
  end
21
22
 
22
23
  def check
@@ -32,6 +33,14 @@ module Philae
32
33
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
33
34
  end
34
35
  end
36
+
37
+ if !@timeout.nil?
38
+ http.read_timeout = @timeout
39
+ http.open_timeout = @timeout
40
+ http.write_timeout = @timeout
41
+ http.ssl_timeout = @timeout
42
+ end
43
+
35
44
  req = Net::HTTP::Get.new(uri)
36
45
  req.basic_auth @username, @password if !@username.nil? || !@password.nil?
37
46
  resp = http.start do |httpconn|
@@ -0,0 +1,46 @@
1
+ require_relative 'collection_probe.rb'
2
+ require_relative 'nsq_probe.rb'
3
+
4
+ module Philae
5
+ class NSQClusterProbe < CollectionProbe
6
+ DEFAULT_HTTP_PORT = 4152
7
+
8
+ attr_reader :name, :nsq_probes
9
+
10
+ def self.new_from_env(name, opts = {})
11
+ if ENV['NSQD_HOSTS'].nil? || ENV['NSQD_HTTP_PORT'].nil?
12
+ raise ArgumentError, 'no NSQD_HOSTS and NSQD_HTTP_PORT defined'
13
+ end
14
+
15
+ tls_context = nil
16
+ if ENV['NSQD_TLS'] == 'true'
17
+ tls_context = {
18
+ cert: ENV['NSQD_TLS_CERT'],
19
+ key: ENV['NSQD_TLS_KEY'],
20
+ ca: ENV['NSQD_TLS_CACERT'],
21
+ }
22
+ end
23
+
24
+ http_hosts = ENV['NSQD_HOSTS'].split(',').map do |host|
25
+ host.split(':')[0] + ":#{ENV['NSQD_HTTP_PORT']}"
26
+ end
27
+
28
+ new(name, http_hosts, tls_context, opts)
29
+ end
30
+
31
+ def initialize(name, hosts, tls_context = nil, opts = {})
32
+ raise ArgumentError, 'should have at least one host' if hosts.nil? || hosts.empty?
33
+
34
+ @name = name
35
+ @nsq_probes = hosts.map do |hostport|
36
+ host, port = hostport.split(':')
37
+ port = DEFAULT_HTTP_PORT if port.nil?
38
+ next Philae::NSQProbe.new("#{name}-#{host}-#{port}", host, port, tls_context, opts)
39
+ end
40
+ end
41
+
42
+ def probes
43
+ @nsq_probes
44
+ end
45
+ end
46
+ end
@@ -2,19 +2,19 @@ require File.join File.dirname(__FILE__), 'http_probe.rb'
2
2
 
3
3
  module Philae
4
4
  class NSQProbe < HttpProbe
5
- def self.new_from_env(name)
5
+ def self.new_from_env(name, opts = {})
6
6
  if ENV["NSQD_TLS"] == "true"
7
7
  return self.new(name, ENV["NSQD_HOST"], ENV["NSQD_HTTP_PORT"], {
8
8
  cert: ENV["NSQD_TLS_CERT"],
9
9
  key: ENV["NSQD_TLS_KEY"],
10
10
  ca: ENV["NSQD_TLS_CACERT"],
11
- })
11
+ }, opts)
12
12
  else
13
13
  return self.new(name, ENV["NSQD_HOST"], ENV["NSQD_HTTP_PORT"])
14
14
  end
15
15
  end
16
16
 
17
- def initialize(name, host, port = 4151, tls_context = nil)
17
+ def initialize(name, host, port = 4151, tls_context = nil, opts = {})
18
18
  @name = name
19
19
  scheme = "http"
20
20
  if !tls_context.nil?
@@ -22,6 +22,7 @@ module Philae
22
22
  end
23
23
  @uri = "#{scheme}://#{host}:#{port}/ping"
24
24
  @tls_context = tls_context
25
+ @timeout = opts.fetch(:timeout, 5)
25
26
  end
26
27
  end
27
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philae
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - leo@scalingo.com
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-10-24 00:00:00.000000000 Z
13
+ date: 2022-01-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: docker-api
@@ -68,6 +68,20 @@ dependencies:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
70
  version: '2.4'
71
+ - !ruby/object:Gem::Dependency
72
+ name: pg
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '0.18'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '0.18'
71
85
  description:
72
86
  email: hello@scalingo.com
73
87
  executables: []
@@ -75,10 +89,13 @@ extensions: []
75
89
  extra_rdoc_files: []
76
90
  files:
77
91
  - lib/philae.rb
92
+ - lib/philae/collection_probe.rb
78
93
  - lib/philae/docker_probe.rb
94
+ - lib/philae/etcd_cluster_probe.rb
79
95
  - lib/philae/etcd_probe.rb
80
96
  - lib/philae/http_probe.rb
81
97
  - lib/philae/mongo_probe.rb
98
+ - lib/philae/nsq_cluster_probe.rb
82
99
  - lib/philae/nsq_probe.rb
83
100
  - lib/philae/pgsql_probe.rb
84
101
  - lib/philae/philae_probe.rb
@@ -103,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
120
  - !ruby/object:Gem::Version
104
121
  version: '0'
105
122
  requirements: []
106
- rubygems_version: 3.0.3
123
+ rubygems_version: 3.2.22
107
124
  signing_key:
108
125
  specification_version: 4
109
126
  summary: Provide an health check API