uninterruptible 2.3.1 → 2.4.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 +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
|