fly-rails 0.3.5
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 +7 -0
- data/LICENSE +202 -0
- data/README.md +100 -0
- data/Rakefile +3 -0
- data/lib/fly-rails/actions.rb +652 -0
- data/lib/fly-rails/deploy.rb +42 -0
- data/lib/fly-rails/dsl.rb +92 -0
- data/lib/fly-rails/generators.rb +3 -0
- data/lib/fly-rails/hcl.rb +99 -0
- data/lib/fly-rails/machines.rb +209 -0
- data/lib/fly-rails/platforms.rb +10 -0
- data/lib/fly-rails/scanner.rb +68 -0
- data/lib/fly-rails/utils.rb +66 -0
- data/lib/fly-rails/version.rb +3 -0
- data/lib/fly-rails.rb +27 -0
- data/lib/generators/fly/app_generator.rb +72 -0
- data/lib/generators/fly/config_generator.rb +19 -0
- data/lib/generators/fly/terraform_generator.rb +36 -0
- data/lib/generators/templates/Dockerfile.erb +270 -0
- data/lib/generators/templates/Procfile.fly.erb +3 -0
- data/lib/generators/templates/dockerignore.erb +16 -0
- data/lib/generators/templates/fly.rake.erb +101 -0
- data/lib/generators/templates/fly.rb.erb +27 -0
- data/lib/generators/templates/fly.toml.erb +81 -0
- data/lib/generators/templates/hook_detached_process.erb +7 -0
- data/lib/generators/templates/litefs.yml.erb +14 -0
- data/lib/generators/templates/main.tf.erb +101 -0
- data/lib/generators/templates/nginx.conf.erb +77 -0
- data/lib/generators/templates/patches/action_cable.rb +20 -0
- data/lib/tasks/fly.rake +178 -0
- data/lib/tasks/mock.rake +17 -0
- metadata +87 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
<% if @passenger -%>
|
2
|
+
<% if @serverless -%>
|
3
|
+
passenger_ctl hook_detached_process /etc/nginx/hook_detached_process;
|
4
|
+
passenger_min_instances 0;
|
5
|
+
passenger_pool_idle_time 300;
|
6
|
+
|
7
|
+
<% end -%>
|
8
|
+
passenger_log_file /dev/stdout;
|
9
|
+
passenger_default_user root;
|
10
|
+
|
11
|
+
server {
|
12
|
+
listen 8080 default_server;
|
13
|
+
listen [::]:8080 default_server;
|
14
|
+
server_name <%= @app %>.fly.dev;
|
15
|
+
root /app/public;
|
16
|
+
|
17
|
+
access_log /dev/stdout;
|
18
|
+
error_log /dev/stdout info;
|
19
|
+
|
20
|
+
passenger_enabled on;
|
21
|
+
passenger_ruby /usr/lib/fullstaq-ruby/versions/<%= @ruby_version %>-jemalloc/bin/ruby;
|
22
|
+
|
23
|
+
<% if @anycable -%>
|
24
|
+
location /cable {
|
25
|
+
<%- if @passenger and (@avahi or @nats) -%>
|
26
|
+
proxy_pass http://${FLY_REGION}-anycable-go.local:8082/cable;
|
27
|
+
proxy_http_version 1.1;
|
28
|
+
proxy_set_header Upgrade $${_0_}http_upgrade;
|
29
|
+
proxy_set_header Connection "Upgrade";
|
30
|
+
proxy_set_header Host $${_0_}host;
|
31
|
+
<%- else -%>
|
32
|
+
proxy_pass http://localhost:8082/cable;
|
33
|
+
proxy_http_version 1.1;
|
34
|
+
proxy_set_header Upgrade $http_upgrade;
|
35
|
+
proxy_set_header Connection "Upgrade";
|
36
|
+
proxy_set_header Host $host;
|
37
|
+
<%- end -%>
|
38
|
+
}
|
39
|
+
|
40
|
+
<% elsif @cable -%>
|
41
|
+
location /cable {
|
42
|
+
passenger_app_group_name <%= @app %>-cable;
|
43
|
+
passenger_force_max_concurrent_requests_per_process 0;
|
44
|
+
}
|
45
|
+
|
46
|
+
<% end -%>
|
47
|
+
location / {
|
48
|
+
passenger_app_group_name <%= @app %>;
|
49
|
+
passenger_env_var RAILS_SERVE_STATIC_FILES true;
|
50
|
+
passenger_env_var RAILS_LOG_TO_STDOUT true;
|
51
|
+
}
|
52
|
+
|
53
|
+
# Nginx has a default limit of 1 MB for request bodies, which also applies
|
54
|
+
# to file uploads. The following line enables uploads of up to 50 MB:
|
55
|
+
client_max_body_size 50M;
|
56
|
+
}
|
57
|
+
<% else -%>
|
58
|
+
server {
|
59
|
+
listen 8080 default_server;
|
60
|
+
listen [::]:8080 default_server;
|
61
|
+
|
62
|
+
<% if @anycable -%>
|
63
|
+
location /cable {
|
64
|
+
proxy_pass http://localhost:8082/cable;
|
65
|
+
proxy_http_version 1.1;
|
66
|
+
proxy_set_header Upgrade $http_upgrade;
|
67
|
+
proxy_set_header Connection "Upgrade";
|
68
|
+
proxy_set_header Host $host;
|
69
|
+
}
|
70
|
+
|
71
|
+
<% end -%>
|
72
|
+
location / {
|
73
|
+
proxy_pass http://localhost:8081/;
|
74
|
+
proxy_set_header origin 'https://localhost:8081';
|
75
|
+
}
|
76
|
+
}
|
77
|
+
<% end -%>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Restart Action Cable server on Redis connection failures.
|
2
|
+
# See: https://github.com/rails/rails/pull/45478
|
3
|
+
require 'action_cable/subscription_adapter/redis'
|
4
|
+
|
5
|
+
module ActionCableRedisListenerPatch
|
6
|
+
private
|
7
|
+
|
8
|
+
def ensure_listener_running
|
9
|
+
@thread ||= Thread.new do
|
10
|
+
Thread.current.abort_on_exception = true
|
11
|
+
conn = @adapter.redis_connection_for_subscriptions
|
12
|
+
listen conn
|
13
|
+
rescue ::Redis::BaseConnectionError
|
14
|
+
@thread = @raw_client = nil
|
15
|
+
::ActionCable.server.restart
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
ActionCable::SubscriptionAdapter::Redis::Listener.prepend(ActionCableRedisListenerPatch)
|
data/lib/tasks/fly.rake
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'fly-rails/machines'
|
2
|
+
require 'fly-rails/hcl'
|
3
|
+
require 'fly-rails/actions'
|
4
|
+
require 'toml'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
config = File.expand_path('config/fly.rb', Rails.application.root)
|
8
|
+
if File.exist? config
|
9
|
+
@config = Fly::DSL::Config.new
|
10
|
+
@config.instance_eval IO.read(config), config
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :fly do
|
14
|
+
desc 'Deploy fly application'
|
15
|
+
task :deploy do
|
16
|
+
include FlyIoRails::Utils
|
17
|
+
|
18
|
+
# Get app name, creating one if necessary
|
19
|
+
if File.exist? 'fly.toml'
|
20
|
+
app = TOML.load_file('fly.toml')['app']
|
21
|
+
else
|
22
|
+
app = create_app
|
23
|
+
end
|
24
|
+
|
25
|
+
# ensure fly.toml and Dockerfile are present
|
26
|
+
action = Fly::Actions.new(app)
|
27
|
+
action.generate_toml if @app
|
28
|
+
action.generate_fly_config unless File.exist? 'config/fly.rb'
|
29
|
+
action.generate_dockerfile
|
30
|
+
action.generate_dockerignore
|
31
|
+
|
32
|
+
# look for missing gems
|
33
|
+
action.bundle_gems
|
34
|
+
|
35
|
+
# build and push an image
|
36
|
+
out = FlyIoRails::Utils.tee "flyctl deploy --build-only --push --dockerfile #{action.dockerfile} --ignorefile #{action.ignorefile}"
|
37
|
+
image = out[/image:\s+(.*)/, 1]&.strip
|
38
|
+
|
39
|
+
exit 1 unless image
|
40
|
+
|
41
|
+
if File.exist? 'main.tf'
|
42
|
+
action.terraform(app, image)
|
43
|
+
else
|
44
|
+
action.generate_ipv4 if @app
|
45
|
+
action.generate_ipv6 if @app
|
46
|
+
action.deploy(app, image)
|
47
|
+
end
|
48
|
+
|
49
|
+
JSON.parse(`fly apps list --json`).each do |info|
|
50
|
+
if info['Name'] == app
|
51
|
+
60.times do
|
52
|
+
response = Net::HTTP.get_response(URI::HTTPS.build(host: info['Hostname']))
|
53
|
+
puts "Server status: #{response.code} #{response.message}"
|
54
|
+
break
|
55
|
+
rescue Errno::ECONNRESET
|
56
|
+
sleep 0.5
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'dbus daemon - used for IPC'
|
63
|
+
task :dbus_deamon do
|
64
|
+
IO.write '/var/lib/dbus/machine-id', `hostname`
|
65
|
+
mkdir_p '/var/run/dbus'
|
66
|
+
sh 'dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address'
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'nats based service discovery'
|
70
|
+
task :nats_publish, [:formation] do |task, args|
|
71
|
+
nats_server = ENV['NATS_SERVER']
|
72
|
+
|
73
|
+
# start nats server
|
74
|
+
if nats_server == 'localhost'
|
75
|
+
pid = spawn('nats-server')
|
76
|
+
at_exit { Process.kill 7, pid }
|
77
|
+
else
|
78
|
+
open('/etc/hosts', 'a') do |file|
|
79
|
+
host = "#{ENV['FLY_REGION']}-nats-server.local"
|
80
|
+
file.puts "#{nats_server}\t#{host}"
|
81
|
+
nats_server = host
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# determine our local 6pn network address
|
86
|
+
address = IPSocket.getaddress('fly-local-6pn')
|
87
|
+
|
88
|
+
# Determine which applications we need addresses for and
|
89
|
+
# which applications we can provide addresses for.
|
90
|
+
hosts = {}
|
91
|
+
needs = []
|
92
|
+
args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
|
93
|
+
dnsname = "#{ENV['FLY_REGION']}-#{name}.local"
|
94
|
+
needs << dnsname
|
95
|
+
hosts[dnsname] = address unless count.to_i == 0
|
96
|
+
end
|
97
|
+
|
98
|
+
# share and collect hosts
|
99
|
+
require 'nats/client'
|
100
|
+
nats = NATS.connect(nats_server)
|
101
|
+
|
102
|
+
nats.subscribe('query_hosts') do |msg|
|
103
|
+
msg.respond hosts.to_json
|
104
|
+
end
|
105
|
+
|
106
|
+
update_hosts = Proc.new do |msg|
|
107
|
+
addresses = JSON.parse(msg.data)
|
108
|
+
|
109
|
+
open('/etc/hosts', 'r+') do |file|
|
110
|
+
file.flock(File::LOCK_EX)
|
111
|
+
contents = file.read
|
112
|
+
|
113
|
+
addresses.each do |dnsname, address|
|
114
|
+
file.puts "#{address}\t#{dnsname}" unless contents.include? dnsname
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
needs -= hosts.keys
|
119
|
+
end
|
120
|
+
|
121
|
+
nats.request('query_hosts', &update_hosts)
|
122
|
+
nats.subscribe('advertise_hosts', &update_hosts)
|
123
|
+
|
124
|
+
nats.publish('advertise_hosts', hosts.to_json)
|
125
|
+
|
126
|
+
at_exit { nats.close }
|
127
|
+
|
128
|
+
# wait for dependencies to be available
|
129
|
+
600.times do
|
130
|
+
break if needs.empty?
|
131
|
+
sleep 0.1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
desc 'Zeroconf/avahi/bonjour discovery'
|
136
|
+
task :avahi_publish, [:formation] => :dbus_deamon do |task, args|
|
137
|
+
pids = []
|
138
|
+
pids << spawn('avahi-daemon')
|
139
|
+
sleep 0.1
|
140
|
+
|
141
|
+
ip = IPSocket.getaddress(Socket.gethostname)
|
142
|
+
args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
|
143
|
+
next if count.to_i == 0
|
144
|
+
pids << spawn("avahi-publish -a -R #{ENV['FLY_REGION']}-#{name}.local #{ip}")
|
145
|
+
end
|
146
|
+
|
147
|
+
require 'resolv'
|
148
|
+
100.times do
|
149
|
+
begin
|
150
|
+
map = {}
|
151
|
+
args[:formation].scan(/([-\w]+)=(\d+)/).each do |name, count|
|
152
|
+
dnsname = "#{ENV['FLY_REGION']}-#{name}.local"
|
153
|
+
resolve = `avahi-resolve-host-name #{dnsname}`
|
154
|
+
raise Resolv::ResolvError.new if $?.exitstatus > 0 or resolve.empty?
|
155
|
+
map[dnsname] = resolve.split.last
|
156
|
+
end
|
157
|
+
|
158
|
+
open('/etc/hosts', 'a') do |hosts|
|
159
|
+
map.each do |dnsname, address|
|
160
|
+
hosts.puts "#{address} #{dnsname}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
break
|
165
|
+
rescue Resolv::ResolvError
|
166
|
+
sleep 0.1
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
at_exit do
|
171
|
+
pids.each {|pid| Process.kill 7, pid}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Alias, for convenience
|
177
|
+
desc 'Deploy fly application'
|
178
|
+
task deploy: 'fly:deploy'
|
data/lib/tasks/mock.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/handler/puma'
|
3
|
+
|
4
|
+
namespace :mock do
|
5
|
+
desc 'Mock server - useful for debugging startup issues'
|
6
|
+
task :server do
|
7
|
+
handler = Rack::Handler::Puma
|
8
|
+
|
9
|
+
class RackApp
|
10
|
+
def call(env)
|
11
|
+
[200, {"Content-Type" => "text/plain"}, ["Hello from Fly.io"]]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
handler.run RackApp.new, Port: ENV['PORT'] || 8080
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fly-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Ruby
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: toml
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description:
|
28
|
+
email: rubys@intertwingly.net
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- LICENSE
|
34
|
+
- README.md
|
35
|
+
- Rakefile
|
36
|
+
- lib/fly-rails.rb
|
37
|
+
- lib/fly-rails/actions.rb
|
38
|
+
- lib/fly-rails/deploy.rb
|
39
|
+
- lib/fly-rails/dsl.rb
|
40
|
+
- lib/fly-rails/generators.rb
|
41
|
+
- lib/fly-rails/hcl.rb
|
42
|
+
- lib/fly-rails/machines.rb
|
43
|
+
- lib/fly-rails/platforms.rb
|
44
|
+
- lib/fly-rails/scanner.rb
|
45
|
+
- lib/fly-rails/utils.rb
|
46
|
+
- lib/fly-rails/version.rb
|
47
|
+
- lib/generators/fly/app_generator.rb
|
48
|
+
- lib/generators/fly/config_generator.rb
|
49
|
+
- lib/generators/fly/terraform_generator.rb
|
50
|
+
- lib/generators/templates/Dockerfile.erb
|
51
|
+
- lib/generators/templates/Procfile.fly.erb
|
52
|
+
- lib/generators/templates/dockerignore.erb
|
53
|
+
- lib/generators/templates/fly.rake.erb
|
54
|
+
- lib/generators/templates/fly.rb.erb
|
55
|
+
- lib/generators/templates/fly.toml.erb
|
56
|
+
- lib/generators/templates/hook_detached_process.erb
|
57
|
+
- lib/generators/templates/litefs.yml.erb
|
58
|
+
- lib/generators/templates/main.tf.erb
|
59
|
+
- lib/generators/templates/nginx.conf.erb
|
60
|
+
- lib/generators/templates/patches/action_cable.rb
|
61
|
+
- lib/tasks/fly.rake
|
62
|
+
- lib/tasks/mock.rake
|
63
|
+
homepage: https://github.com/rubys/fly-rails
|
64
|
+
licenses:
|
65
|
+
- Apache-2.0
|
66
|
+
metadata:
|
67
|
+
homepage_uri: https://github.com/rubys/fly-rails
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubygems_version: 3.3.5
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Rails support for Fly-io
|
87
|
+
test_files: []
|