fly.io-rails 0.0.21-arm64-darwin → 0.1.1-arm64-darwin
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/exe/arm64-darwin/flyctl +0 -0
- data/lib/fly.io-rails/actions.rb +284 -0
- data/lib/fly.io-rails/machines.rb +5 -5
- data/lib/fly.io-rails/version.rb +1 -1
- data/lib/generators/terraform_generator.rb +1 -1
- data/lib/tasks/fly.rake +27 -72
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fd535a7501f08c7e1314a14b6a2875b334182fca732dd994df20ac2979e0bf9
|
4
|
+
data.tar.gz: e9667f63230a373fd8feb431ca7a551e74a6b17a118418f2f13f37da80086964
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dafa2169129603c071bcf199f215074e66ae166c4fd7cf78feb081276d14f1460c3fb3f81186a0aa1cf0708fdc47ca5e62dd0ce4fe742002369abfe4eb043f34
|
7
|
+
data.tar.gz: 75d78bab12736653419348eca68f94fdcd4bd20532e6310ade12fc96f8a78065d973ebfcf7fd276972da28b44701251c31421421928c64a5d716fce70521301c
|
data/exe/arm64-darwin/flyctl
CHANGED
Binary file
|
data/lib/fly.io-rails/actions.rb
CHANGED
@@ -2,11 +2,13 @@ require 'thor'
|
|
2
2
|
require 'active_support'
|
3
3
|
require 'active_support/core_ext/string/inflections'
|
4
4
|
require 'fly.io-rails/machines'
|
5
|
+
require 'fly.io-rails/utils'
|
5
6
|
|
6
7
|
module Fly
|
7
8
|
class Actions < Thor::Group
|
8
9
|
include Thor::Actions
|
9
10
|
include Thor::Base
|
11
|
+
include Thor::Shell
|
10
12
|
attr_accessor :options
|
11
13
|
|
12
14
|
def initialize(app = nil)
|
@@ -36,6 +38,11 @@ module Fly
|
|
36
38
|
|
37
39
|
source_paths.push File::expand_path('../generators/templates', __dir__)
|
38
40
|
|
41
|
+
def generate_toml
|
42
|
+
app
|
43
|
+
template 'fly.toml.erb', 'fly.toml'
|
44
|
+
end
|
45
|
+
|
39
46
|
def generate_dockerfile
|
40
47
|
app
|
41
48
|
template 'Dockerfile.erb', 'Dockerfile'
|
@@ -62,5 +69,282 @@ module Fly
|
|
62
69
|
generate_terraform
|
63
70
|
generate_raketask
|
64
71
|
end
|
72
|
+
|
73
|
+
def generate_ipv4
|
74
|
+
cmd = 'flyctl ips allocate-v4'
|
75
|
+
say_status :run, cmd
|
76
|
+
system cmd
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_ipv6
|
80
|
+
cmd = 'flyctl ips allocate-v6'
|
81
|
+
say_status :run, cmd
|
82
|
+
system cmd
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_volume(app, region, size)
|
86
|
+
volume = "#{app.gsub('-', '_')}_volume"
|
87
|
+
volumes = JSON.parse(`flyctl volumes list --json`).
|
88
|
+
map {|volume| volume['Name']}
|
89
|
+
|
90
|
+
unless volumes.include? volume
|
91
|
+
cmd = "flyctl volumes create #{volume} --app #{app} --region #{region} --size #{size}"
|
92
|
+
say_status :run, cmd
|
93
|
+
system cmd
|
94
|
+
end
|
95
|
+
|
96
|
+
volume
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_postgres(app, org, region, vm_size, volume_size, cluster_size)
|
100
|
+
cmd = "flyctl postgres create --name #{app}-db --org #{org} --region #{region} --vm-size #{vm_size} --volume-size #{volume_size} --initial-cluster-size #{cluster_size}"
|
101
|
+
say_status :run, cmd
|
102
|
+
output = FlyIoRails::Utils.tee(cmd)
|
103
|
+
output[%r{postgres://\S+}]
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_redis(app, org, region, eviction)
|
107
|
+
# see if redis is already defined
|
108
|
+
name = `flyctl redis list`.lines[1..-2].map(&:split).
|
109
|
+
find {|tokens| tokens[1] == org}&.first
|
110
|
+
|
111
|
+
if name
|
112
|
+
secret = `flyctl redis status #{name}`[%r{redis://\S+}]
|
113
|
+
return secret if secret
|
114
|
+
end
|
115
|
+
|
116
|
+
# create a new redis
|
117
|
+
cmd = "flyctl redis create --org #{org} --name #{app}-redis --region #{region} --no-replicas #{eviction} --plan Free"
|
118
|
+
say_status :run, cmd
|
119
|
+
output = FlyIoRails::Utils.tee(cmd)
|
120
|
+
output[%r{redis://\S+}]
|
121
|
+
end
|
122
|
+
|
123
|
+
def release(app, config)
|
124
|
+
start = Fly::Machines.create_and_start_machine(app, config: config)
|
125
|
+
machine = start[:id]
|
126
|
+
|
127
|
+
if !machine
|
128
|
+
STDERR.puts 'Error starting release machine'
|
129
|
+
PP.pp start, STDERR
|
130
|
+
exit 1
|
131
|
+
end
|
132
|
+
|
133
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
134
|
+
timeout: 60, state: 'started'
|
135
|
+
|
136
|
+
# wait for release to copmlete
|
137
|
+
status = nil
|
138
|
+
5.times do
|
139
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
140
|
+
timeout: 60, state: 'stopped'
|
141
|
+
return machine if status[:ok]
|
142
|
+
end
|
143
|
+
|
144
|
+
# wait for release to copmlete
|
145
|
+
event = nil
|
146
|
+
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'
|
151
|
+
end
|
152
|
+
|
153
|
+
STDERR.puts event.to_json
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
|
157
|
+
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
|
+
|
162
|
+
secrets = JSON.parse(`flyctl secrets list --json`).
|
163
|
+
map {|secret| secret["Name"]}
|
164
|
+
|
165
|
+
config = {
|
166
|
+
region: region,
|
167
|
+
app: app,
|
168
|
+
name: "#{app}-machine",
|
169
|
+
image: image,
|
170
|
+
guest: {
|
171
|
+
cpus: 1,
|
172
|
+
cpu_kind: "shared",
|
173
|
+
memory_mb: 256,
|
174
|
+
},
|
175
|
+
services: [
|
176
|
+
{
|
177
|
+
ports: [
|
178
|
+
{port: 443, handlers: ["tls", "http"]},
|
179
|
+
{port: 80, handlers: ["http"]}
|
180
|
+
],
|
181
|
+
protocol: "tcp",
|
182
|
+
internal_port: 8080
|
183
|
+
}
|
184
|
+
]
|
185
|
+
}
|
186
|
+
|
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
|
191
|
+
|
192
|
+
if database == 'sqlite3'
|
193
|
+
volume = create_volume(app, region, 3)
|
194
|
+
|
195
|
+
config[:mounts] = [
|
196
|
+
{ volume: volume, path: '/mnt/volume' }
|
197
|
+
]
|
198
|
+
|
199
|
+
config[:env] = {
|
200
|
+
"DATABASE_URL" => "sqlite3:///mnt/volume/production.sqlite3"
|
201
|
+
}
|
202
|
+
elsif database == 'postgresql' and not secrets.include? 'DATABASE_URL'
|
203
|
+
secret = create_postgres(app, @org, region, 'shared-cpu-1x', 1, 1)
|
204
|
+
|
205
|
+
if secret
|
206
|
+
cmd = "flyctl secrets set --stage DATABASE_URL=#{secret}"
|
207
|
+
say_status :run, cmd
|
208
|
+
system cmd
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
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
|
215
|
+
|
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)
|
226
|
+
|
227
|
+
if secret
|
228
|
+
cmd = "flyctl secrets set --stage REDIS_URL=#{secret}"
|
229
|
+
say_status :run, cmd
|
230
|
+
system cmd
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# build config for release machine, overriding server command
|
235
|
+
release_config = config.dup
|
236
|
+
release_config.delete :services
|
237
|
+
release_config.delete :mounts
|
238
|
+
release_config[:env] = { 'SERVER_COMMAND' => 'bin/rails fly:release' }
|
239
|
+
|
240
|
+
# perform release
|
241
|
+
say_status :fly, release_config[:env]['SERVER_COMMAND']
|
242
|
+
machine = release(app, release_config)
|
243
|
+
Fly::Machines.delete_machine app, machine if machine
|
244
|
+
|
245
|
+
# start proxy, if necessary
|
246
|
+
endpoint = Fly::Machines::fly_api_hostname!
|
247
|
+
|
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']}"
|
252
|
+
end
|
253
|
+
|
254
|
+
# start app
|
255
|
+
say_status :fly, "start #{app}"
|
256
|
+
start = Fly::Machines.create_and_start_machine(app, config: config)
|
257
|
+
machine = start[:id]
|
258
|
+
|
259
|
+
if !machine
|
260
|
+
STDERR.puts 'Error starting application'
|
261
|
+
PP.pp start, STDERR
|
262
|
+
exit 1
|
263
|
+
end
|
264
|
+
|
265
|
+
5.times do
|
266
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
267
|
+
timeout: 60, status: 'started'
|
268
|
+
return if status[:ok]
|
269
|
+
end
|
270
|
+
|
271
|
+
STDERR.puts 'Timeout waiting for application to start'
|
272
|
+
end
|
273
|
+
|
274
|
+
def terraform(app, image)
|
275
|
+
# update main.tf with the image name
|
276
|
+
tf = IO.read('main.tf')
|
277
|
+
tf[/^\s*image\s*=\s*"(.*?)"/, 1] = image.strip
|
278
|
+
IO.write 'main.tf', tf
|
279
|
+
|
280
|
+
# find first machine in terraform config file
|
281
|
+
machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
|
282
|
+
block.keys.first == :resource and
|
283
|
+
block.values.first.keys.first == 'fly_machine'}
|
284
|
+
|
285
|
+
# extract HCL configuration for the machine
|
286
|
+
config = machines.values.first.values.first.values.first
|
287
|
+
|
288
|
+
# delete HCL specific configuration items
|
289
|
+
%i(services for_each region app name depends_on).each do |key|
|
290
|
+
config.delete key
|
291
|
+
end
|
292
|
+
|
293
|
+
# move machine configuration into guest object
|
294
|
+
config[:guest] = {
|
295
|
+
cpus: config.delete(:cpus),
|
296
|
+
memory_mb: config.delete(:memorymb),
|
297
|
+
cpu_kind: config.delete(:cputype)
|
298
|
+
}
|
299
|
+
|
300
|
+
# release machines should have no services or mounts
|
301
|
+
config.delete :services
|
302
|
+
config.delete :mounts
|
303
|
+
|
304
|
+
# override start command
|
305
|
+
config[:env] ||= {}
|
306
|
+
config[:env]['SERVER_COMMAND'] = 'bin/rails fly:release'
|
307
|
+
|
308
|
+
# start proxy, if necessary
|
309
|
+
endpoint = Fly::Machines::fly_api_hostname!
|
310
|
+
|
311
|
+
# start release machine
|
312
|
+
STDERR.puts "--> #{config[:env]['SERVER_COMMAND']}"
|
313
|
+
start = Fly::Machines.create_and_start_machine(app, config: config)
|
314
|
+
machine = start[:id]
|
315
|
+
|
316
|
+
if !machine
|
317
|
+
STDERR.puts 'Error starting release machine'
|
318
|
+
PP.pp start, STDERR
|
319
|
+
exit 1
|
320
|
+
end
|
321
|
+
|
322
|
+
# wait for release to copmlete
|
323
|
+
event = nil
|
324
|
+
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'
|
329
|
+
end
|
330
|
+
|
331
|
+
# extract exit code
|
332
|
+
exit_code = event.dig(:request, :exit_event, :exit_code)
|
333
|
+
|
334
|
+
if exit_code == 0
|
335
|
+
# delete release machine
|
336
|
+
Fly::Machines.delete_machine app, machine
|
337
|
+
|
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'
|
342
|
+
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
|
347
|
+
end
|
348
|
+
end
|
65
349
|
end
|
66
350
|
end
|
@@ -80,7 +80,7 @@ module Fly
|
|
80
80
|
get "/v1/apps/#{app}"
|
81
81
|
end
|
82
82
|
|
83
|
-
#
|
83
|
+
# create_and_start_machine 'user-functions', name: 'quirky_machine', config: {
|
84
84
|
# image: 'flyio/fastify-functions',
|
85
85
|
# env: {'APP_ENV' => 'production'},
|
86
86
|
# services: [
|
@@ -94,13 +94,13 @@ module Fly
|
|
94
94
|
# }
|
95
95
|
# ]
|
96
96
|
# }
|
97
|
-
def self.
|
97
|
+
def self.create_and_start_machine app, options
|
98
98
|
post "/v1/apps/#{app}/machines", options
|
99
99
|
end
|
100
100
|
|
101
|
-
#
|
102
|
-
def self.
|
103
|
-
get "/v1/apps/#{app}/machines/#{machine}/wait
|
101
|
+
# wait_for_machine 'user-functions', '73d8d46dbee589'
|
102
|
+
def self.wait_for_machine app, machine, options = {timeout:60, status: 'started'}
|
103
|
+
get "/v1/apps/#{app}/machines/#{machine}/wait?#{options.to_query}"
|
104
104
|
end
|
105
105
|
|
106
106
|
# get_a_machine machine 'user-functions', '73d8d46dbee589'
|
data/lib/fly.io-rails/version.rb
CHANGED
data/lib/tasks/fly.rake
CHANGED
@@ -1,90 +1,45 @@
|
|
1
1
|
require 'fly.io-rails/machines'
|
2
2
|
require 'fly.io-rails/hcl'
|
3
|
+
require 'fly.io-rails/actions'
|
4
|
+
require 'toml'
|
3
5
|
|
4
6
|
namespace :fly do
|
5
7
|
desc 'Deploy fly application'
|
6
8
|
task :deploy do
|
7
|
-
|
8
|
-
out = FlyIoRails::Utils.tee 'fly deploy --build-only --push'
|
9
|
-
image = out[/image:\s+(.*)/, 1]
|
10
|
-
|
11
|
-
exit 1 unless image
|
12
|
-
|
13
|
-
# update main.tf with the image name
|
14
|
-
tf = IO.read('main.tf')
|
15
|
-
tf[/^\s*image\s*=\s*"(.*?)"/, 1] = image.strip
|
16
|
-
IO.write 'main.tf', tf
|
9
|
+
include FlyIoRails::Utils
|
17
10
|
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
# Get app name, creating one if necessary
|
12
|
+
if File.exist? 'fly.toml'
|
13
|
+
app = TOML.load_file('fly.toml')['app']
|
14
|
+
else
|
15
|
+
output = FlyIoRails::Utils.tee(
|
16
|
+
"flyctl apps create --generate-name --org personal --machines"
|
17
|
+
)
|
25
18
|
|
26
|
-
|
27
|
-
app = config[:app]
|
19
|
+
exit 1 unless output =~ /^New app created: /
|
28
20
|
|
29
|
-
|
30
|
-
%i(services for_each region app name depends_on).each do |key|
|
31
|
-
config.delete key
|
21
|
+
@app = app = output.split.last
|
32
22
|
end
|
33
23
|
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# release machines should have no services or mounts
|
42
|
-
config.delete :services
|
43
|
-
config.delete :mounts
|
44
|
-
|
45
|
-
# override start command
|
46
|
-
config[:env] ||= {}
|
47
|
-
config[:env]['SERVER_COMMAND'] = 'bin/rails fly:release'
|
24
|
+
# ensure fly.toml and Dockerfile are present
|
25
|
+
action = Fly::Actions.new(app)
|
26
|
+
action.generate_toml if @app
|
27
|
+
action.generate_dockerfile unless File.exist? 'Dockerfile'
|
28
|
+
action.generate_dockerignore unless File.exist? '.dockerignore'
|
29
|
+
action.generate_raketask unless File.exist? 'lib/tasks/fly.rake'
|
48
30
|
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
# start release machine
|
53
|
-
STDERR.puts "--> #{config[:env]['SERVER_COMMAND']}"
|
54
|
-
start = Fly::Machines.create_start_machine(app, config: config)
|
55
|
-
machine = start[:id]
|
56
|
-
|
57
|
-
if !machine
|
58
|
-
STDERR.puts 'Error starting release machine'
|
59
|
-
PP.pp start, STDERR
|
60
|
-
exit 1
|
61
|
-
end
|
62
|
-
|
63
|
-
# wait for release to copmlete
|
64
|
-
event = nil
|
65
|
-
90.times do
|
66
|
-
sleep 1
|
67
|
-
status = Fly::Machines.get_a_machine app, machine
|
68
|
-
event = status[:events]&.first
|
69
|
-
break if event && event[:type] == 'exit'
|
70
|
-
end
|
31
|
+
# build and push an image
|
32
|
+
out = FlyIoRails::Utils.tee 'fly deploy --build-only --push'
|
33
|
+
image = out[/image:\s+(.*)/, 1].strip
|
71
34
|
|
72
|
-
|
73
|
-
exit_code = event.dig(:request, :exit_event, :exit_code)
|
74
|
-
|
75
|
-
if exit_code == 0
|
76
|
-
# delete release machine
|
77
|
-
Fly::Machines.delete_machine app, machine
|
35
|
+
exit 1 unless image
|
78
36
|
|
79
|
-
|
80
|
-
|
81
|
-
ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
|
82
|
-
system 'terraform apply -auto-approve'
|
37
|
+
if File.exist? 'main.tf'
|
38
|
+
action.terraform(app, image)
|
83
39
|
else
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
exit 1
|
40
|
+
action.generate_ipv4 if @app
|
41
|
+
action.generate_ipv6 if @app
|
42
|
+
action.deploy(app, image)
|
88
43
|
end
|
89
44
|
end
|
90
45
|
end
|
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.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: arm64-darwin
|
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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fly-ruby
|