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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c489a48122e3cceb5ad3378fee25516fd4d9bf756ddf3b93bc07965252662f1
4
- data.tar.gz: a432c8d0efdbd27b455d27dff14c1c7f72c99fc26472789beb833db3cad26f8d
3
+ metadata.gz: cec3ca4f27cbb576d74009dcdea78a60113a091c85b833efb1f83388bfd37475
4
+ data.tar.gz: 702966a87970bca9d3192dbc8cd76cb94bb5fdf0cfa25f331ea290a02f08f097
5
5
  SHA512:
6
- metadata.gz: 1bcf0a18c1b3fef021a8c9aad0b31407108360f5253103ddba996a34b1414fc72ecdb07be66991343341112e0e5ff3e0c08be50308ad1b1b140e644cd952ac22
7
- data.tar.gz: 15ac2cc1b6838aa9d3e9ea15cb3ca8b721aff2f4225fa957fa94f607f9b8731687233287c5022ef6aee30e068cfbaea86be613efa1cd41940221810c65c2ee56
6
+ metadata.gz: 17a5d4feb8fdfe76af46edb6b6f416c5387aab1d01a6a2e8dcf10d9c37925eafd0a17043f67b5faf3a6d056f58bacb147494964142957e3848199caf0bcec792
7
+ data.tar.gz: bf8f63c0bb7d6d890a3dbb1f1b8f5b4fb2190277ef606e6b2bca2016c58c649c1c474ba0c6c48be0dc99e2bbda4a6fbfc9e3cd35248a49617aff0d4f4a00d628
@@ -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 generate_all
67
- generate_dockerfile
68
- generate_dockerignore
69
- generate_terraform
70
- generate_raketask
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 Free"
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
- STDERR.puts 'Error starting release machine'
129
- PP.pp start, STDERR
130
- exit 1
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
- sleep 1
148
- status = Fly::Machines.get_a_machine app, machine
149
- event = status[:events]&.first
150
- return machine if event && event[:type] == 'exit'
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: 1,
172
- cpu_kind: "shared",
173
- memory_mb: 256,
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
- ports: [
178
- {port: 443, handlers: ["tls", "http"]},
179
- {port: 80, handlers: ["http"]}
180
- ],
181
- protocol: "tcp",
182
- internal_port: 8080
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
- database = YAML.load_file('config/database.yml').
188
- dig('production', 'adapter') rescue nil
189
- cable = YAML.load_file('config/cable.yml').
190
- dig('production', 'adapter') rescue nil
225
+ unless secrets.include? 'RAILS_MASTER_KEY'
226
+ generate_key
227
+ end
191
228
 
192
- if database == 'sqlite3'
193
- volume = create_volume(app, region, 3)
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 database == 'postgresql' and not secrets.include? 'DATABASE_URL'
203
- secret = create_postgres(app, @org, region, 'shared-cpu-1x', 1, 1)
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
- # Enable redis if mentioned as a cache provider or a cable provider.
213
- # Set eviction policy to true if a cache provider, else false.
214
- eviction = nil
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
- if (YAML.load_file('config/cable.yml').dig('production', 'adapter') rescue false)
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
- JSON.parse(`fly machines list --json`).each do |list|
250
- next if list['id'] == machine
251
- system "fly machines remove --force #{list['id']}"
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
- STDERR.puts 'Error starting application'
261
- PP.pp start, STDERR
262
- exit 1
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
- status = Fly::Machines.wait_for_machine app, machine,
300
+ status = Fly::Machines.wait_for_machine app, machine,
267
301
  timeout: 60, status: 'started'
268
- return if status[:ok]
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
- block.keys.first == :resource and
283
- block.values.first.keys.first == 'fly_machine'}
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
- config.delete key
324
+ config.delete key
291
325
  end
292
326
 
293
327
  # move machine configuration into guest object
294
328
  config[:guest] = {
295
- cpus: config.delete(:cpus),
296
- memory_mb: config.delete(:memorymb),
297
- cpu_kind: config.delete(:cputype)
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
- STDERR.puts 'Error starting release machine'
318
- PP.pp start, STDERR
319
- exit 1
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
- sleep 1
326
- status = Fly::Machines.get_a_machine app, machine
327
- event = status[:events]&.first
328
- break if event && event[:type] == 'exit'
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
- # delete release machine
336
- Fly::Machines.delete_machine app, machine
369
+ # delete release machine
370
+ Fly::Machines.delete_machine app, machine
337
371
 
338
- # use terraform apply to deploy
339
- ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
340
- ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
341
- system 'terraform apply -auto-approve'
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
- STDERR.puts 'Error performing release'
344
- STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
345
- STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
346
- exit 1
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
@@ -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
- 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|
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
- rescue Errno::EIO
23
- end
24
- end
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
@@ -1,3 +1,3 @@
1
1
  module Fly_io
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -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
- /* Uncomment this if you want sqlite3 on a volume
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
- output = FlyIoRails::Utils.tee(
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].strip
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.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-24 00:00:00.000000000 Z
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/terraform_generator.rb
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