uninterruptible 2.3.1 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -6
- data/lib/uninterruptible/binder.rb +15 -4
- data/lib/uninterruptible/file_descriptor_server.rb +51 -0
- data/lib/uninterruptible/server.rb +15 -6
- data/lib/uninterruptible/version.rb +1 -1
- data/lib/uninterruptible.rb +2 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c0bee80d95f929271d75f691c59788a9716e8e3
|
4
|
+
data.tar.gz: 877066cf757d14caab769f7585713170f7db08e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f2f1edad24e0bad293acb8f70a3171388c98d73f266f025c570ed58fda332d47cf0f95c00cfd1f8b293b142b4d8882b496201daa5da30beada562363b8999df
|
7
|
+
data.tar.gz: 775f0729644939e948a87adb085105651a00500793d6db9b19b5965faf008f5bea4dbab21fb279bd030604f134c177530c65db64ea37530c4bf3f9f23ecfa543
|
data/CHANGELOG.md
CHANGED
@@ -1,22 +1,25 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
## 2.4.0
|
4
|
+
* When restarting a server, the socket is passed to the new server via a UNIX socket instead of inheriting open file descriptors from the parent.
|
5
|
+
|
6
|
+
## 2.3.0
|
4
7
|
* Incoming connections can be restricted to certain networks by setting `allowed_networks` in the configuration.
|
5
8
|
|
6
|
-
|
9
|
+
## 2.2.1
|
7
10
|
* Allow multiple certificates to be used in one build file
|
8
11
|
|
9
|
-
|
12
|
+
## 2.2.0
|
10
13
|
* Verify client TLS certificates
|
11
14
|
* Allow trusted client CA to be set
|
12
15
|
|
13
|
-
|
16
|
+
## 2.1.1
|
14
17
|
* Prevent bad SSL handshakes from crashing server
|
15
18
|
|
16
|
-
|
19
|
+
## 2.1.0
|
17
20
|
* Add TLS support for TCP connections
|
18
21
|
|
19
|
-
|
22
|
+
## 2.0.0
|
20
23
|
* Use an internal pipe for delivering signals to the main thread.
|
21
24
|
* `accept_connections` retired in favour of a select loop and `accept_client_connection` being called for each waiting connection
|
22
25
|
* Logging when shutting down or restarting
|
@@ -34,8 +34,8 @@ module Uninterruptible
|
|
34
34
|
#
|
35
35
|
# @return [TCPServer] Socket server for the configured address and port
|
36
36
|
def bind_to_tcp_socket
|
37
|
-
if ENV[
|
38
|
-
TCPServer.for_fd(
|
37
|
+
if ENV[FILE_DESCRIPTOR_SERVER_VAR]
|
38
|
+
TCPServer.for_fd(read_file_descriptor_from_fds)
|
39
39
|
else
|
40
40
|
TCPServer.new(bind_uri.host, bind_uri.port)
|
41
41
|
end
|
@@ -45,14 +45,16 @@ module Uninterruptible
|
|
45
45
|
#
|
46
46
|
# @return [UNIXServer] Socket server for the configured path
|
47
47
|
def bind_to_unix_socket
|
48
|
-
if ENV[
|
49
|
-
UNIXServer.for_fd(
|
48
|
+
if ENV[FILE_DESCRIPTOR_SERVER_VAR]
|
49
|
+
UNIXServer.for_fd(read_file_descriptor_from_fds)
|
50
50
|
else
|
51
51
|
File.delete(bind_uri.path) if File.exist?(bind_uri.path)
|
52
52
|
UNIXServer.new(bind_uri.path)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
private
|
57
|
+
|
56
58
|
# Parse the bind address in the configuration
|
57
59
|
#
|
58
60
|
# @param [String] bind_address The config for a server we're returning the socket for
|
@@ -65,5 +67,14 @@ module Uninterruptible
|
|
65
67
|
rescue URI::Error
|
66
68
|
raise Uninterruptible::ConfigurationError, "Couldn't parse the bind address: \"#{bind_address}\""
|
67
69
|
end
|
70
|
+
|
71
|
+
# Open a connection to a running FileDesciptorServer on the parent of this server and obtain a file descriptor
|
72
|
+
# for the running socket server on there.
|
73
|
+
def read_file_descriptor_from_fds
|
74
|
+
fds_socket = UNIXSocket.new(ENV[FILE_DESCRIPTOR_SERVER_VAR])
|
75
|
+
socket_file_descriptor = fds_socket.recv_io
|
76
|
+
fds_socket.close
|
77
|
+
socket_file_descriptor.to_i
|
78
|
+
end
|
68
79
|
end
|
69
80
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module Uninterruptible
|
5
|
+
class FileDescriptorServer
|
6
|
+
attr_reader :io_object, :socket_server
|
7
|
+
|
8
|
+
# Creates a new FileDescriptorServer and starts a listenting socket server
|
9
|
+
#
|
10
|
+
# @param [IO] Any IO object that will be shared by this server
|
11
|
+
def initialize(io_object)
|
12
|
+
@io_object = io_object
|
13
|
+
|
14
|
+
start_socket_server
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String] Location on disk where socket server is listening
|
18
|
+
def socket_path
|
19
|
+
@socket_path ||= File.join(socket_directory, 'file_descriptor_server.sock')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Accept the next client connection and send it the file descriptor
|
23
|
+
#
|
24
|
+
# @raise [RuntimeError] Raises a runtime error if the socket server is closed
|
25
|
+
def serve_file_descriptor
|
26
|
+
raise "File descriptor server has been closed" if socket_server.closed?
|
27
|
+
|
28
|
+
client = socket_server.accept
|
29
|
+
client.send_io(io_object)
|
30
|
+
client.close
|
31
|
+
end
|
32
|
+
|
33
|
+
# Close the socket server and tidy up any created files
|
34
|
+
def close
|
35
|
+
socket_server.close
|
36
|
+
|
37
|
+
File.delete(socket_path)
|
38
|
+
Dir.rmdir(socket_directory)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def socket_directory
|
44
|
+
@socket_directory ||= Dir.mktmpdir('uninterruptible-')
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_socket_server
|
48
|
+
@socket_server = UNIXServer.new(socket_path)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -113,12 +113,12 @@ module Uninterruptible
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
# Listen (or reconnect) to the bind address and port specified in the config. If
|
117
|
-
# reconnect to that file descriptor.
|
116
|
+
# Listen (or reconnect) to the bind address and port specified in the config. If FILE_DESCRIPTOR_SERVER_PATH is set
|
117
|
+
# in the env, reconnect to that file descriptor.
|
118
118
|
def establish_socket_server
|
119
119
|
@socket_server = Uninterruptible::Binder.new(server_configuration.bind).bind_to_socket
|
120
120
|
# If there's a file descriptor present, take over from a previous instance of this server and kill it off
|
121
|
-
kill_parent if ENV[
|
121
|
+
kill_parent if ENV[FILE_DESCRIPTOR_SERVER_VAR]
|
122
122
|
|
123
123
|
@socket_server.autoclose = false
|
124
124
|
@socket_server.close_on_exec = false
|
@@ -126,8 +126,6 @@ module Uninterruptible
|
|
126
126
|
if server_configuration.tls_enabled?
|
127
127
|
@socket_server = Uninterruptible::TLSServerFactory.new(server_configuration).wrap_with_tls(@socket_server)
|
128
128
|
end
|
129
|
-
|
130
|
-
ENV[SERVER_FD_VAR] = @socket_server.to_i.to_s
|
131
129
|
end
|
132
130
|
|
133
131
|
# Send a TERM signal to the parent process. This will be called by a newly spawned server if it has been started
|
@@ -194,11 +192,22 @@ module Uninterruptible
|
|
194
192
|
|
195
193
|
# Start a new copy of this server, maintaining all current file descriptors and env.
|
196
194
|
def hot_restart
|
195
|
+
# Start a FileDescriptorServer running on a unix socket
|
196
|
+
file_descriptor_server = FileDescriptorServer.new(socket_server)
|
197
|
+
|
197
198
|
fork do
|
199
|
+
# Let the new server know where to find the file descriptor server
|
200
|
+
ENV[FILE_DESCRIPTOR_SERVER_VAR] = file_descriptor_server.socket_path
|
201
|
+
|
198
202
|
Dir.chdir(ENV['APP_ROOT']) if ENV['APP_ROOT']
|
199
203
|
ENV.delete('BUNDLE_GEMFILE') # Ensure a fresh bundle is used
|
200
|
-
|
204
|
+
|
205
|
+
exec("bundle exec #{server_configuration.start_command}")
|
201
206
|
end
|
207
|
+
|
208
|
+
# Provide the new server with the file descriptor for @socket_server
|
209
|
+
file_descriptor_server.serve_file_descriptor
|
210
|
+
file_descriptor_server.close
|
202
211
|
end
|
203
212
|
|
204
213
|
def network_restrictions
|
data/lib/uninterruptible.rb
CHANGED
@@ -5,6 +5,7 @@ require "uninterruptible/version"
|
|
5
5
|
require 'uninterruptible/ssl_extensions'
|
6
6
|
require 'uninterruptible/configuration'
|
7
7
|
require 'uninterruptible/binder'
|
8
|
+
require 'uninterruptible/file_descriptor_server'
|
8
9
|
require 'uninterruptible/network_restrictions'
|
9
10
|
require 'uninterruptible/tls_server_factory'
|
10
11
|
require 'uninterruptible/server'
|
@@ -13,5 +14,5 @@ require 'uninterruptible/server'
|
|
13
14
|
module Uninterruptible
|
14
15
|
class ConfigurationError < StandardError; end
|
15
16
|
|
16
|
-
|
17
|
+
FILE_DESCRIPTOR_SERVER_VAR = 'FILE_DESCRIPTOR_SERVER_PATH'.freeze
|
17
18
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uninterruptible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Wentworth
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- lib/uninterruptible.rb
|
76
76
|
- lib/uninterruptible/binder.rb
|
77
77
|
- lib/uninterruptible/configuration.rb
|
78
|
+
- lib/uninterruptible/file_descriptor_server.rb
|
78
79
|
- lib/uninterruptible/network_restrictions.rb
|
79
80
|
- lib/uninterruptible/server.rb
|
80
81
|
- lib/uninterruptible/ssl_extensions.rb
|
@@ -101,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
102
|
version: '0'
|
102
103
|
requirements: []
|
103
104
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.
|
105
|
+
rubygems_version: 2.6.14.3
|
105
106
|
signing_key:
|
106
107
|
specification_version: 4
|
107
108
|
summary: Zero-downtime restarts for your trivial socket servers
|