fly.io-rails 0.1.1-x86-linux → 0.1.2-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ae2eb431bc02977e776f060fca9f15373c64a5dc212ba584bfb318b9c1b54e3
4
- data.tar.gz: 1ff8e6992b955e86146536dfaf926387c82bf06b465122e11a3ad59e8f69ffcd
3
+ metadata.gz: 8aa1c4040ccebf009b5ffe230412dd59d49d69de4bdbc8a4aa9db6c4ece01225
4
+ data.tar.gz: 12b87e4079e6543fec6dc515df5ea2d73b75295c2ed57f903aa99673952a0b6b
5
5
  SHA512:
6
- metadata.gz: 3e9dca7ab20bc360de7eabaf6a63449e1bd9a607431d23ed9ad7889269bacc5bc856bc6c0ace0b653f4e111dcfe2f883e6c5aaa31552de1f05255759ee27bc90
7
- data.tar.gz: 40e8697df6f63334ea54ddff94506cc85240c19da33dae98f2d9322d83ffebb53e7f223f84d859f7934132cbf6cf61da5392b127bff51d941199646404bd5c56
6
+ metadata.gz: a210b5b5caea3bda202bb309cdc7402abf62690bfdaf96e6b25a3f17a5f654dcd2e23ba3ff7506dc5c0555d654650fd1be9f395be7dfd403dfe984e9fe983671
7
+ data.tar.gz: 6038ce927e28afbc8433c5b46cb5d6dd1fa158e4a90f69a44c151eb913fa93e37ec719b06ecaac004f5af55b589f10ee456b97582f3757dc55e48e5472c51435
@@ -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: x86-linux
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
@@ -52,18 +52,23 @@ files:
52
52
  - exe/x86-linux/flyctl
53
53
  - lib/fly.io-rails.rb
54
54
  - lib/fly.io-rails/actions.rb
55
+ - lib/fly.io-rails/dsl.rb
55
56
  - lib/fly.io-rails/generators.rb
56
57
  - lib/fly.io-rails/hcl.rb
57
58
  - lib/fly.io-rails/machines.rb
58
59
  - lib/fly.io-rails/platforms.rb
60
+ - lib/fly.io-rails/scanner.rb
59
61
  - lib/fly.io-rails/utils.rb
60
62
  - lib/fly.io-rails/version.rb
63
+ - lib/generators/fly/app_generator.rb
64
+ - lib/generators/fly/terraform_generator.rb
61
65
  - lib/generators/templates/Dockerfile.erb
62
66
  - lib/generators/templates/dockerignore.erb
63
67
  - lib/generators/templates/fly.rake.erb
68
+ - lib/generators/templates/fly.rb.erb
64
69
  - lib/generators/templates/fly.toml.erb
65
70
  - lib/generators/templates/main.tf.erb
66
- - lib/generators/terraform_generator.rb
71
+ - lib/generators/templates/patches/action_cable.rb
67
72
  - lib/tasks/fly.rake
68
73
  homepage: https://github.com/rubys/fly-io.rails
69
74
  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