fly.io-rails 0.1.1-x64-mingw32 → 0.1.2-x64-mingw32
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/lib/fly.io-rails/actions.rb +118 -84
- data/lib/fly.io-rails/dsl.rb +79 -0
- data/lib/fly.io-rails/scanner.rb +26 -0
- data/lib/fly.io-rails/utils.rb +27 -8
- data/lib/fly.io-rails/version.rb +1 -1
- data/lib/generators/fly/app_generator.rb +29 -0
- data/lib/generators/fly/terraform_generator.rb +29 -0
- data/lib/generators/templates/fly.rake.erb +12 -0
- data/lib/generators/templates/fly.rb.erb +25 -0
- data/lib/generators/templates/main.tf.erb +9 -1
- data/lib/generators/templates/patches/action_cable.rb +20 -0
- data/lib/tasks/fly.rake +3 -8
- metadata +8 -3
- data/lib/generators/terraform_generator.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cec3ca4f27cbb576d74009dcdea78a60113a091c85b833efb1f83388bfd37475
|
4
|
+
data.tar.gz: 702966a87970bca9d3192dbc8cd76cb94bb5fdf0cfa25f331ea290a02f08f097
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17a5d4feb8fdfe76af46edb6b6f416c5387aab1d01a6a2e8dcf10d9c37925eafd0a17043f67b5faf3a6d056f58bacb147494964142957e3848199caf0bcec792
|
7
|
+
data.tar.gz: bf8f63c0bb7d6d890a3dbb1f1b8f5b4fb2190277ef606e6b2bca2016c58c649c1c474ba0c6c48be0dc99e2bbda4a6fbfc9e3cd35248a49617aff0d4f4a00d628
|
data/lib/fly.io-rails/actions.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
+
require 'open3'
|
1
2
|
require 'thor'
|
2
3
|
require 'active_support'
|
3
4
|
require 'active_support/core_ext/string/inflections'
|
4
5
|
require 'fly.io-rails/machines'
|
5
6
|
require 'fly.io-rails/utils'
|
7
|
+
require 'fly.io-rails/dsl'
|
8
|
+
require 'fly.io-rails/scanner'
|
6
9
|
|
7
10
|
module Fly
|
8
11
|
class Actions < Thor::Group
|
9
12
|
include Thor::Actions
|
10
13
|
include Thor::Base
|
11
14
|
include Thor::Shell
|
15
|
+
include Fly::Scanner
|
12
16
|
attr_accessor :options
|
13
17
|
|
14
|
-
def initialize(app = nil)
|
18
|
+
def initialize(app = nil, regions = nil)
|
15
19
|
self.app = app if app
|
16
20
|
|
17
21
|
@ruby_version = RUBY_VERSION
|
@@ -20,10 +24,25 @@ module Fly
|
|
20
24
|
@yarn = File.exist? 'yarn.lock'
|
21
25
|
@node_version = @node ? `node --version`.chomp.sub(/^v/, '') : '16.17.0'
|
22
26
|
@org = Fly::Machines.org
|
23
|
-
@regions = []
|
24
27
|
|
25
28
|
@options = {}
|
26
29
|
@destination_stack = [Dir.pwd]
|
30
|
+
|
31
|
+
if !regions or regions.empty?
|
32
|
+
@regions = JSON.parse(`flyctl regions list --json --app #{app}`)['Regions'].
|
33
|
+
map {|region| region['Code']} rescue []
|
34
|
+
else
|
35
|
+
@regions = regions
|
36
|
+
end
|
37
|
+
|
38
|
+
@region = @regions.first || 'iad'
|
39
|
+
|
40
|
+
@config = Fly::DSL::Config.new
|
41
|
+
if File.exist? 'config/fly.rb'
|
42
|
+
@config.instance_eval IO.read('config/fly.rb')
|
43
|
+
end
|
44
|
+
|
45
|
+
scan_rails_app
|
27
46
|
end
|
28
47
|
|
29
48
|
def app
|
@@ -43,6 +62,11 @@ module Fly
|
|
43
62
|
template 'fly.toml.erb', 'fly.toml'
|
44
63
|
end
|
45
64
|
|
65
|
+
def generate_fly_config
|
66
|
+
app
|
67
|
+
template 'fly.rb.erb', 'config/fly.rb'
|
68
|
+
end
|
69
|
+
|
46
70
|
def generate_dockerfile
|
47
71
|
app
|
48
72
|
template 'Dockerfile.erb', 'Dockerfile'
|
@@ -63,11 +87,28 @@ module Fly
|
|
63
87
|
template 'fly.rake.erb', 'lib/tasks/fly.rake'
|
64
88
|
end
|
65
89
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
90
|
+
def generate_key
|
91
|
+
credentials = nil
|
92
|
+
if File.exist? 'config/credentials/production.key'
|
93
|
+
credentials = 'config/credentials/production.key'
|
94
|
+
elsif File.exist? 'config/master.key'
|
95
|
+
credentials = 'config/master.key'
|
96
|
+
end
|
97
|
+
|
98
|
+
if credentials
|
99
|
+
say_status :run, "flyctl secrets set --stage RAILS_MASTER_KEY from #{credentials}"
|
100
|
+
system "flyctl secrets set --stage RAILS_MASTER_KEY=#{IO.read(credentials).chomp}"
|
101
|
+
puts
|
102
|
+
end
|
103
|
+
|
104
|
+
ENV['FLY_API_TOKEN'] = `flyctl auth token`
|
105
|
+
end
|
106
|
+
|
107
|
+
def generate_patches
|
108
|
+
if @redis_cable and not File.exist? 'config/initializers/action_cable.rb'
|
109
|
+
app
|
110
|
+
template 'patches/action_cable.rb', 'config/initializers/action_cable.rb'
|
111
|
+
end
|
71
112
|
end
|
72
113
|
|
73
114
|
def generate_ipv4
|
@@ -114,7 +155,7 @@ module Fly
|
|
114
155
|
end
|
115
156
|
|
116
157
|
# create a new redis
|
117
|
-
cmd = "flyctl redis create --org #{org} --name #{app}-redis --region #{region} --no-replicas #{eviction} --plan
|
158
|
+
cmd = "flyctl redis create --org #{org} --name #{app}-redis --region #{region} --no-replicas #{eviction} --plan #{@config.redis.plan}"
|
118
159
|
say_status :run, cmd
|
119
160
|
output = FlyIoRails::Utils.tee(cmd)
|
120
161
|
output[%r{redis://\S+}]
|
@@ -125,9 +166,9 @@ module Fly
|
|
125
166
|
machine = start[:id]
|
126
167
|
|
127
168
|
if !machine
|
128
|
-
|
129
|
-
|
130
|
-
|
169
|
+
STDERR.puts 'Error starting release machine'
|
170
|
+
PP.pp start, STDERR
|
171
|
+
exit 1
|
131
172
|
end
|
132
173
|
|
133
174
|
status = Fly::Machines.wait_for_machine app, machine,
|
@@ -144,10 +185,10 @@ module Fly
|
|
144
185
|
# wait for release to copmlete
|
145
186
|
event = nil
|
146
187
|
90.times do
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
188
|
+
sleep 1
|
189
|
+
status = Fly::Machines.get_a_machine app, machine
|
190
|
+
event = status[:events]&.first
|
191
|
+
return machine if event && event[:type] == 'exit'
|
151
192
|
end
|
152
193
|
|
153
194
|
STDERR.puts event.to_json
|
@@ -155,42 +196,38 @@ module Fly
|
|
155
196
|
end
|
156
197
|
|
157
198
|
def deploy(app, image)
|
158
|
-
regions = JSON.parse(`flyctl regions list --json`)['Regions'].
|
159
|
-
map {|region| region['Code']} rescue []
|
160
|
-
region = regions.first || 'iad'
|
161
199
|
|
162
200
|
secrets = JSON.parse(`flyctl secrets list --json`).
|
163
201
|
map {|secret| secret["Name"]}
|
164
202
|
|
165
203
|
config = {
|
166
|
-
region: region,
|
204
|
+
region: @region,
|
167
205
|
app: app,
|
168
206
|
name: "#{app}-machine",
|
169
207
|
image: image,
|
170
208
|
guest: {
|
171
|
-
cpus:
|
172
|
-
cpu_kind:
|
173
|
-
memory_mb:
|
209
|
+
cpus: @config.machine.cpus,
|
210
|
+
cpu_kind: @config.machine.cpu_kind,
|
211
|
+
memory_mb: @config.machine.memory_mb
|
174
212
|
},
|
175
213
|
services: [
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
214
|
+
{
|
215
|
+
ports: [
|
216
|
+
{port: 443, handlers: ["tls", "http"]},
|
217
|
+
{port: 80, handlers: ["http"]}
|
218
|
+
],
|
219
|
+
protocol: "tcp",
|
220
|
+
internal_port: 8080
|
221
|
+
}
|
184
222
|
]
|
185
223
|
}
|
186
224
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
dig('production', 'adapter') rescue nil
|
225
|
+
unless secrets.include? 'RAILS_MASTER_KEY'
|
226
|
+
generate_key
|
227
|
+
end
|
191
228
|
|
192
|
-
if
|
193
|
-
volume = create_volume(app, region,
|
229
|
+
if @sqlite3
|
230
|
+
volume = create_volume(app, @region, @config.sqlite3.size)
|
194
231
|
|
195
232
|
config[:mounts] = [
|
196
233
|
{ volume: volume, path: '/mnt/volume' }
|
@@ -199,8 +236,11 @@ module Fly
|
|
199
236
|
config[:env] = {
|
200
237
|
"DATABASE_URL" => "sqlite3:///mnt/volume/production.sqlite3"
|
201
238
|
}
|
202
|
-
elsif
|
203
|
-
secret = create_postgres(app, @org, region,
|
239
|
+
elsif @postgresql and not secrets.include? 'DATABASE_URL'
|
240
|
+
secret = create_postgres(app, @org, @region,
|
241
|
+
@config.postgres.vm_size,
|
242
|
+
@config.postgres.volume_size,
|
243
|
+
@config.postgres.initial_cluster_size)
|
204
244
|
|
205
245
|
if secret
|
206
246
|
cmd = "flyctl secrets set --stage DATABASE_URL=#{secret}"
|
@@ -209,20 +249,11 @@ module Fly
|
|
209
249
|
end
|
210
250
|
end
|
211
251
|
|
212
|
-
|
213
|
-
|
214
|
-
|
252
|
+
if @redis and not secrets.include? 'REDIS_URL'
|
253
|
+
# Set eviction policy to true if a cache provider, else false.
|
254
|
+
eviction = @redis_cache ? '--enable-eviction' : '--disable-eviction'
|
215
255
|
|
216
|
-
|
217
|
-
eviction = '--disable-eviction'
|
218
|
-
end
|
219
|
-
|
220
|
-
if (IO.read('config/environments/production.rb') =~ /redis/i rescue false)
|
221
|
-
eviction = '--enable-eviction'
|
222
|
-
end
|
223
|
-
|
224
|
-
if eviction and not secrets.include? 'REDIS_URL'
|
225
|
-
secret = create_redis(app, @org, region, eviction)
|
256
|
+
secret = create_redis(app, @org, @region, eviction)
|
226
257
|
|
227
258
|
if secret
|
228
259
|
cmd = "flyctl secrets set --stage REDIS_URL=#{secret}"
|
@@ -245,10 +276,13 @@ module Fly
|
|
245
276
|
# start proxy, if necessary
|
246
277
|
endpoint = Fly::Machines::fly_api_hostname!
|
247
278
|
|
248
|
-
# stop previous instances
|
249
|
-
|
250
|
-
|
251
|
-
|
279
|
+
# stop previous instances - list will fail on first run
|
280
|
+
stdout, stderr, status = Open3.capture3('fly machines list --json')
|
281
|
+
unless stdout.empty?
|
282
|
+
JSON.parse(stdout).each do |list|
|
283
|
+
next if list['id'] == machine
|
284
|
+
system "fly machines remove --force #{list['id']}"
|
285
|
+
end
|
252
286
|
end
|
253
287
|
|
254
288
|
# start app
|
@@ -257,15 +291,15 @@ module Fly
|
|
257
291
|
machine = start[:id]
|
258
292
|
|
259
293
|
if !machine
|
260
|
-
|
261
|
-
|
262
|
-
|
294
|
+
STDERR.puts 'Error starting application'
|
295
|
+
PP.pp start, STDERR
|
296
|
+
exit 1
|
263
297
|
end
|
264
298
|
|
265
299
|
5.times do
|
266
|
-
|
300
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
267
301
|
timeout: 60, status: 'started'
|
268
|
-
|
302
|
+
return if status[:ok]
|
269
303
|
end
|
270
304
|
|
271
305
|
STDERR.puts 'Timeout waiting for application to start'
|
@@ -279,22 +313,22 @@ module Fly
|
|
279
313
|
|
280
314
|
# find first machine in terraform config file
|
281
315
|
machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
|
282
|
-
|
283
|
-
|
316
|
+
block.keys.first == :resource and
|
317
|
+
block.values.first.keys.first == 'fly_machine'}
|
284
318
|
|
285
319
|
# extract HCL configuration for the machine
|
286
320
|
config = machines.values.first.values.first.values.first
|
287
321
|
|
288
322
|
# delete HCL specific configuration items
|
289
323
|
%i(services for_each region app name depends_on).each do |key|
|
290
|
-
|
324
|
+
config.delete key
|
291
325
|
end
|
292
326
|
|
293
327
|
# move machine configuration into guest object
|
294
328
|
config[:guest] = {
|
295
|
-
|
296
|
-
|
297
|
-
|
329
|
+
cpus: config.delete(:cpus),
|
330
|
+
memory_mb: config.delete(:memorymb),
|
331
|
+
cpu_kind: config.delete(:cputype)
|
298
332
|
}
|
299
333
|
|
300
334
|
# release machines should have no services or mounts
|
@@ -314,36 +348,36 @@ module Fly
|
|
314
348
|
machine = start[:id]
|
315
349
|
|
316
350
|
if !machine
|
317
|
-
|
318
|
-
|
319
|
-
|
351
|
+
STDERR.puts 'Error starting release machine'
|
352
|
+
PP.pp start, STDERR
|
353
|
+
exit 1
|
320
354
|
end
|
321
355
|
|
322
356
|
# wait for release to copmlete
|
323
357
|
event = nil
|
324
358
|
90.times do
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
359
|
+
sleep 1
|
360
|
+
status = Fly::Machines.get_a_machine app, machine
|
361
|
+
event = status[:events]&.first
|
362
|
+
break if event && event[:type] == 'exit'
|
329
363
|
end
|
330
364
|
|
331
365
|
# extract exit code
|
332
366
|
exit_code = event.dig(:request, :exit_event, :exit_code)
|
333
|
-
|
367
|
+
|
334
368
|
if exit_code == 0
|
335
|
-
|
336
|
-
|
369
|
+
# delete release machine
|
370
|
+
Fly::Machines.delete_machine app, machine
|
337
371
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
372
|
+
# use terraform apply to deploy
|
373
|
+
ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
|
374
|
+
ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
|
375
|
+
system 'terraform apply -auto-approve'
|
342
376
|
else
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
377
|
+
STDERR.puts 'Error performing release'
|
378
|
+
STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
|
379
|
+
STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
|
380
|
+
exit 1
|
347
381
|
end
|
348
382
|
end
|
349
383
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Fly
|
2
|
+
module DSL
|
3
|
+
class Base
|
4
|
+
def initialize
|
5
|
+
@value = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.option name, default=nil
|
9
|
+
@options ||= {}
|
10
|
+
@options[name] = default
|
11
|
+
|
12
|
+
define_method name do |*args|
|
13
|
+
if args.length == 1
|
14
|
+
@value[name] = args.first
|
15
|
+
elsif args.length > 1
|
16
|
+
raise ArgumentError.new("wrong number of arguments (given #{args.length}, expected 0..1)")
|
17
|
+
end
|
18
|
+
|
19
|
+
@value.include?(name) ? @value[name] : default
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.options
|
24
|
+
@options ||= {}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#############################################################
|
29
|
+
|
30
|
+
class Machine < Base
|
31
|
+
option :cpus, 1
|
32
|
+
option :cpu_kind, 'shared'
|
33
|
+
option :memory_mb, 256
|
34
|
+
end
|
35
|
+
|
36
|
+
class Postgres < Base
|
37
|
+
option :vm_size, 'shared-cpu-1x'
|
38
|
+
option :volume_size, 1
|
39
|
+
option :initial_cluster_size, 1
|
40
|
+
end
|
41
|
+
|
42
|
+
class Redis < Base
|
43
|
+
option :plan, "Free"
|
44
|
+
end
|
45
|
+
|
46
|
+
class Sqlite3 < Base
|
47
|
+
option :size, 3
|
48
|
+
end
|
49
|
+
|
50
|
+
#############################################################
|
51
|
+
|
52
|
+
class Config
|
53
|
+
@@blocks = {}
|
54
|
+
|
55
|
+
def initialize
|
56
|
+
@config = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.block name, kind
|
60
|
+
@@blocks[name] = kind
|
61
|
+
|
62
|
+
define_method name do |&block|
|
63
|
+
@config[name] ||= kind.new
|
64
|
+
@config[name].instance_eval(&block) if block
|
65
|
+
@config[name]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.blocks
|
70
|
+
@@blocks
|
71
|
+
end
|
72
|
+
|
73
|
+
block :machine, Machine
|
74
|
+
block :postgres, Postgres
|
75
|
+
block :redis, Redis
|
76
|
+
block :sqlite3, Sqlite3
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Fly
|
2
|
+
module Scanner
|
3
|
+
# scan for major features - things that if present will likely affect
|
4
|
+
# more than one artifact that is generated.
|
5
|
+
def scan_rails_app
|
6
|
+
database = YAML.load_file('config/database.yml').
|
7
|
+
dig('production', 'adapter') rescue nil
|
8
|
+
|
9
|
+
if database == 'sqlite3'
|
10
|
+
@sqlite3 = true
|
11
|
+
elsif database == 'postgresql'
|
12
|
+
@postgresql = true
|
13
|
+
end
|
14
|
+
|
15
|
+
if (YAML.load_file('config/cable.yml').dig('production', 'adapter') rescue false)
|
16
|
+
@redis_cable = true
|
17
|
+
end
|
18
|
+
|
19
|
+
if (IO.read('config/environments/production.rb') =~ /redis/i rescue false)
|
20
|
+
@redis_cache = true
|
21
|
+
end
|
22
|
+
|
23
|
+
@redis = @redis_cable || @redis_cache
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/fly.io-rails/utils.rb
CHANGED
@@ -4,7 +4,7 @@ module FlyIoRails
|
|
4
4
|
module Utils
|
5
5
|
|
6
6
|
def tee cmd
|
7
|
-
say_status :run, cmd
|
7
|
+
say_status :run, cmd if defined? say_status
|
8
8
|
FlyIoRails::Utils.tee cmd
|
9
9
|
end
|
10
10
|
|
@@ -12,21 +12,40 @@ module FlyIoRails
|
|
12
12
|
data = []
|
13
13
|
|
14
14
|
begin
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
PTY.spawn( cmd ) do |stdin, stdout, pid|
|
16
|
+
begin
|
17
|
+
# Do stuff with the output here. Just printing to show it works
|
18
|
+
stdin.each do |line|
|
19
19
|
print line
|
20
20
|
data << line
|
21
21
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
rescue Errno::EIO
|
23
|
+
end
|
24
|
+
end
|
25
25
|
rescue PTY::ChildExited
|
26
26
|
end
|
27
27
|
|
28
28
|
data.join
|
29
29
|
end
|
30
30
|
|
31
|
+
def create_app(name=nil, org='personal', regions=[])
|
32
|
+
cmd = if name
|
33
|
+
"flyctl apps create #{name.inspect} --org #{org.inspect} --machines"
|
34
|
+
else
|
35
|
+
"flyctl apps create --generate-name --org #{org.inspect} --machines"
|
36
|
+
end
|
37
|
+
|
38
|
+
output = tee cmd
|
39
|
+
exit 1 unless output =~ /^New app created: /
|
40
|
+
|
41
|
+
@app = output.split.last
|
42
|
+
template 'fly.toml.erb', 'fly.toml' if defined? template # rake tasks are on their own
|
43
|
+
|
44
|
+
unless regions.empty?
|
45
|
+
@regions = regions.flatten
|
46
|
+
end
|
47
|
+
|
48
|
+
@app
|
49
|
+
end
|
31
50
|
end
|
32
51
|
end
|
data/lib/fly.io-rails/version.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fly.io-rails/actions'
|
2
|
+
|
3
|
+
module Fly::Generators
|
4
|
+
class AppGenerator < Rails::Generators::Base
|
5
|
+
include FlyIoRails::Utils
|
6
|
+
|
7
|
+
class_option :name, type: :string, required: false
|
8
|
+
class_option :org, type: :string, default: 'personal'
|
9
|
+
class_option :region, type: :array, repeatable: true, default: []
|
10
|
+
|
11
|
+
def generate_app
|
12
|
+
source_paths.push File.expand_path('../templates', __dir__)
|
13
|
+
|
14
|
+
create_app(options[:name], options[:org], options)
|
15
|
+
|
16
|
+
action = Fly::Actions.new(@app, options[:region])
|
17
|
+
|
18
|
+
action.generate_fly_config unless File.exist? 'config/fly.rb'
|
19
|
+
action.generate_dockerfile unless File.exist? 'Dockerfile'
|
20
|
+
action.generate_dockerignore unless File.exist? '.dockerignore'
|
21
|
+
action.generate_raketask unless File.exist? 'lib/tasks/fly.rake'
|
22
|
+
action.generate_patches
|
23
|
+
action.generate_ipv4
|
24
|
+
action.generate_ipv6
|
25
|
+
action.generate_key
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'fly.io-rails/actions'
|
2
|
+
|
3
|
+
module Fly::Generators
|
4
|
+
class TerraformGenerator < Rails::Generators::Base
|
5
|
+
include FlyIoRails::Utils
|
6
|
+
|
7
|
+
class_option :name, type: :string, required: false
|
8
|
+
class_option :org, type: :string, default: 'personal'
|
9
|
+
class_option :region, type: :array, repeatable: true, default: []
|
10
|
+
|
11
|
+
def terraform
|
12
|
+
source_paths.push File.expand_path('../templates', __dir__)
|
13
|
+
|
14
|
+
create_app(options[:name], options[:org], options[:region])
|
15
|
+
|
16
|
+
action = Fly::Actions.new(@app, options[:region])
|
17
|
+
|
18
|
+
action.generate_dockerfile
|
19
|
+
action.generate_dockerignore
|
20
|
+
action.generate_terraform
|
21
|
+
action.generate_raketask
|
22
|
+
action.generate_patches
|
23
|
+
|
24
|
+
action.generate_key
|
25
|
+
|
26
|
+
tee 'terraform init'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -10,14 +10,22 @@ namespace :fly do
|
|
10
10
|
# - changes to the filesystem made here are DISCARDED
|
11
11
|
# - full access to secrets, databases
|
12
12
|
# - failures here prevent deployment
|
13
|
+
<%- if @sqlite3 -%>
|
14
|
+
task :release
|
15
|
+
<%- else -%>
|
13
16
|
task :release => 'db:migrate'
|
17
|
+
<%- end -%>
|
14
18
|
|
15
19
|
# SERVER step:
|
16
20
|
# - changes to the filesystem made here are deployed
|
17
21
|
# - full access to secrets, databases
|
18
22
|
# - failures here result in VM being stated, shutdown, and rolled back
|
19
23
|
# to last successful deploy (if any).
|
24
|
+
<%- if @sqlite3 -%>
|
25
|
+
task :server => [:swapfile, 'db:migrate'] do
|
26
|
+
<%- else -%>
|
20
27
|
task :server => :swapfile do
|
28
|
+
<%- end -%>
|
21
29
|
sh 'bin/rails server'
|
22
30
|
end
|
23
31
|
|
@@ -26,7 +34,11 @@ namespace :fly do
|
|
26
34
|
# - performance critical applications should scale memory to the
|
27
35
|
# point where swap is rarely used. 'fly scale help' for details.
|
28
36
|
# - disable by removing dependency on the :server task, thus:
|
37
|
+
<%- if @sqlite3 -%>
|
38
|
+
# task :server => 'db:migrate' do
|
39
|
+
<%- else -%>
|
29
40
|
# task :server do
|
41
|
+
<%- end -%>
|
30
42
|
task :swapfile do
|
31
43
|
sh 'fallocate -l 512M /swapfile'
|
32
44
|
sh 'chmod 0600 /swapfile'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
machine do
|
2
|
+
cpus 1
|
3
|
+
cpu_kind 'shared'
|
4
|
+
memory_mb 256
|
5
|
+
end
|
6
|
+
<% if @sqlite3 -%>
|
7
|
+
|
8
|
+
sqlite3 do
|
9
|
+
size 3
|
10
|
+
end
|
11
|
+
<% end -%>
|
12
|
+
<% if @postgresql -%>
|
13
|
+
|
14
|
+
postgres do
|
15
|
+
vm_size 'shared-cpu-1x'
|
16
|
+
volume_size 1
|
17
|
+
initial_cluster_size 1
|
18
|
+
end
|
19
|
+
<% end -%>
|
20
|
+
<% if @redis -%>
|
21
|
+
|
22
|
+
redis do
|
23
|
+
plan "Free"
|
24
|
+
end
|
25
|
+
<% end -%>
|
@@ -27,7 +27,9 @@ resource "fly_ip" "<%= @appName %>Ipv6" {
|
|
27
27
|
type = "v6"
|
28
28
|
}
|
29
29
|
|
30
|
+
<% unless @sqlite3 -%>
|
30
31
|
/* Uncomment this if you want a volume
|
32
|
+
<% end -%>
|
31
33
|
resource "fly_volume" "<%= @appName %>Volume" {
|
32
34
|
for_each = toset(<%= @regions.inspect %>)
|
33
35
|
region = each.value
|
@@ -36,7 +38,9 @@ resource "fly_volume" "<%= @appName %>Volume" {
|
|
36
38
|
app = <%= @app.inspect %>
|
37
39
|
size = 3
|
38
40
|
}
|
41
|
+
<% unless @sqlite3 -%>
|
39
42
|
*/
|
43
|
+
<% end -%>
|
40
44
|
|
41
45
|
# Start a fly machine
|
42
46
|
resource "fly_machine" "<%= @appName %>Machine" {
|
@@ -71,7 +75,7 @@ resource "fly_machine" "<%= @appName %>Machine" {
|
|
71
75
|
}
|
72
76
|
]
|
73
77
|
|
74
|
-
|
78
|
+
<%- if @sqlite3 -%>
|
75
79
|
env = {
|
76
80
|
DATABASE_URL = "sqlite3:///mnt/db/production.sqlite3"
|
77
81
|
}
|
@@ -83,6 +87,10 @@ resource "fly_machine" "<%= @appName %>Machine" {
|
|
83
87
|
}
|
84
88
|
]
|
85
89
|
|
90
|
+
depends_on = [fly_volume.<%= @appName %>Volume]
|
91
|
+
<%- else -%>
|
92
|
+
/* Uncomment this if you want a volume
|
86
93
|
depends_on = [fly_volume.<%= @appName %>Volume]
|
87
94
|
*/
|
95
|
+
<%- end -%>
|
88
96
|
}
|
@@ -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
CHANGED
@@ -12,25 +12,20 @@ namespace :fly do
|
|
12
12
|
if File.exist? 'fly.toml'
|
13
13
|
app = TOML.load_file('fly.toml')['app']
|
14
14
|
else
|
15
|
-
|
16
|
-
"flyctl apps create --generate-name --org personal --machines"
|
17
|
-
)
|
18
|
-
|
19
|
-
exit 1 unless output =~ /^New app created: /
|
20
|
-
|
21
|
-
@app = app = output.split.last
|
15
|
+
app = create_app
|
22
16
|
end
|
23
17
|
|
24
18
|
# ensure fly.toml and Dockerfile are present
|
25
19
|
action = Fly::Actions.new(app)
|
26
20
|
action.generate_toml if @app
|
21
|
+
action.generate_fly_config unless File.exist? 'config/fly.rb'
|
27
22
|
action.generate_dockerfile unless File.exist? 'Dockerfile'
|
28
23
|
action.generate_dockerignore unless File.exist? '.dockerignore'
|
29
24
|
action.generate_raketask unless File.exist? 'lib/tasks/fly.rake'
|
30
25
|
|
31
26
|
# build and push an image
|
32
27
|
out = FlyIoRails::Utils.tee 'fly deploy --build-only --push'
|
33
|
-
image = out[/image:\s+(.*)/, 1]
|
28
|
+
image = out[/image:\s+(.*)/, 1]&.strip
|
34
29
|
|
35
30
|
exit 1 unless image
|
36
31
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fly.io-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: x64-mingw32
|
6
6
|
authors:
|
7
7
|
- Sam Ruby
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fly-ruby
|
@@ -53,18 +53,23 @@ files:
|
|
53
53
|
- exe/x64-mingw32/wintun.dll
|
54
54
|
- lib/fly.io-rails.rb
|
55
55
|
- lib/fly.io-rails/actions.rb
|
56
|
+
- lib/fly.io-rails/dsl.rb
|
56
57
|
- lib/fly.io-rails/generators.rb
|
57
58
|
- lib/fly.io-rails/hcl.rb
|
58
59
|
- lib/fly.io-rails/machines.rb
|
59
60
|
- lib/fly.io-rails/platforms.rb
|
61
|
+
- lib/fly.io-rails/scanner.rb
|
60
62
|
- lib/fly.io-rails/utils.rb
|
61
63
|
- lib/fly.io-rails/version.rb
|
64
|
+
- lib/generators/fly/app_generator.rb
|
65
|
+
- lib/generators/fly/terraform_generator.rb
|
62
66
|
- lib/generators/templates/Dockerfile.erb
|
63
67
|
- lib/generators/templates/dockerignore.erb
|
64
68
|
- lib/generators/templates/fly.rake.erb
|
69
|
+
- lib/generators/templates/fly.rb.erb
|
65
70
|
- lib/generators/templates/fly.toml.erb
|
66
71
|
- lib/generators/templates/main.tf.erb
|
67
|
-
- lib/generators/
|
72
|
+
- lib/generators/templates/patches/action_cable.rb
|
68
73
|
- lib/tasks/fly.rake
|
69
74
|
homepage: https://github.com/rubys/fly-io.rails
|
70
75
|
licenses:
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'open3'
|
2
|
-
require 'fly.io-rails/actions'
|
3
|
-
|
4
|
-
class Fly::Generators::TerraformGenerator < Rails::Generators::Base
|
5
|
-
include FlyIoRails::Utils
|
6
|
-
|
7
|
-
class_option :name, type: :string, required: false
|
8
|
-
class_option :org, type: :string, default: 'personal'
|
9
|
-
class_option :region, type: :array, repeatable: true, default: []
|
10
|
-
|
11
|
-
def terraform
|
12
|
-
source_paths.push File.expand_path('./templates', __dir__)
|
13
|
-
|
14
|
-
cmd = if options[:name]
|
15
|
-
"flyctl apps create #{options[:name].inspect} --org #{options[:org].inspect}"
|
16
|
-
else
|
17
|
-
"flyctl apps create --generate-name --org #{options[:org].inspect}"
|
18
|
-
end
|
19
|
-
|
20
|
-
output = tee cmd
|
21
|
-
exit 1 unless output =~ /^New app created: /
|
22
|
-
|
23
|
-
@app = output.split.last
|
24
|
-
template 'fly.toml.erb', 'fly.toml'
|
25
|
-
|
26
|
-
if options[:region].empty?
|
27
|
-
@regions = JSON.parse(`flyctl regions list --json`)['Regions'].
|
28
|
-
map {|region| region['Code']}
|
29
|
-
else
|
30
|
-
@regions = options[:regions].flatten
|
31
|
-
end
|
32
|
-
|
33
|
-
action = Fly::Actions.new(@app)
|
34
|
-
action.generate_all
|
35
|
-
|
36
|
-
credentials = nil
|
37
|
-
if File.exist? 'config/credentials/production.key'
|
38
|
-
credentials = 'config/credentials/production.key'
|
39
|
-
elsif File.exist? 'config/master.key'
|
40
|
-
credentials = 'config/master.key'
|
41
|
-
end
|
42
|
-
|
43
|
-
if credentials
|
44
|
-
say_status :run, "flyctl secrets set RAILS_MASTER_KEY from #{credentials}"
|
45
|
-
system "flyctl secrets set RAILS_MASTER_KEY=#{IO.read(credentials).chomp}"
|
46
|
-
puts
|
47
|
-
end
|
48
|
-
|
49
|
-
ENV['FLY_API_TOKEN'] = `flyctl auth token`
|
50
|
-
tee 'terraform init'
|
51
|
-
end
|
52
|
-
end
|