fly.io-rails 0.0.21-x64-mingw32 → 0.1.0-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 +225 -0
- data/lib/fly.io-rails/machines.rb +3 -3
- 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 +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31dbb298f72984f01bd39eb4859577e3442b4f4021b0e099bf0be2e3d7c16134
|
4
|
+
data.tar.gz: 374cee9b246abb711a1f6954d9a77f04aeada9f47fb6a6441cebd3105a627ced
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d6a32e791648274508e64ca20bb3234a42189bff8a9c6031549dcb12b6391b47685c7606c708a97327bb71a058238c76029788d753d263e294ef204a4167b18
|
7
|
+
data.tar.gz: 68481956ca5448163257265683cc72363f19a83f5eee2fe4e51c3a00baf6b38988336ac439cc87ecd7b4f6773021193248f0850c64b8652bb559edcd9181e649
|
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,223 @@ 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 = "fly 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 release(app, config)
|
107
|
+
start = Fly::Machines.create_start_machine(app, config: config)
|
108
|
+
machine = start[:id]
|
109
|
+
|
110
|
+
if !machine
|
111
|
+
STDERR.puts 'Error starting release machine'
|
112
|
+
PP.pp start, STDERR
|
113
|
+
exit 1
|
114
|
+
end
|
115
|
+
|
116
|
+
# wait for release to copmlete
|
117
|
+
status = nil
|
118
|
+
5.times do
|
119
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
120
|
+
timeout: 60, status: 'stopped'
|
121
|
+
return machine if status[:ok]
|
122
|
+
end
|
123
|
+
|
124
|
+
STDERR.puts status.to_json
|
125
|
+
exit 1
|
126
|
+
end
|
127
|
+
|
128
|
+
def deploy(app, image)
|
129
|
+
regions = JSON.parse(`flyctl regions list --json`)['Regions'].
|
130
|
+
map {|region| region['Code']} rescue []
|
131
|
+
region = regions.first || 'iad'
|
132
|
+
|
133
|
+
secrets = JSON.parse(`fly secrets list --json`).
|
134
|
+
map {|secret| secret["Name"]}
|
135
|
+
|
136
|
+
config = {
|
137
|
+
region: region,
|
138
|
+
app: app,
|
139
|
+
name: "#{app}-machine",
|
140
|
+
image: image,
|
141
|
+
guest: {
|
142
|
+
cpus: 1,
|
143
|
+
cpu_kind: "shared",
|
144
|
+
memory_mb: 256,
|
145
|
+
},
|
146
|
+
services: [
|
147
|
+
{
|
148
|
+
ports: [
|
149
|
+
{port: 443, handlers: ["tls", "http"]},
|
150
|
+
{port: 80, handlers: ["http"]}
|
151
|
+
],
|
152
|
+
protocol: "tcp",
|
153
|
+
internal_port: 8080
|
154
|
+
}
|
155
|
+
]
|
156
|
+
}
|
157
|
+
|
158
|
+
database = YAML.load_file('config/database.yml').
|
159
|
+
dig('production', 'adapter') rescue nil
|
160
|
+
cable = YAML.load_file('config/cable.yml').
|
161
|
+
dig('production', 'adapter') rescue nil
|
162
|
+
|
163
|
+
if database == 'sqlite3'
|
164
|
+
volume = create_volume(app, region, 3)
|
165
|
+
|
166
|
+
config[:mounts] = [
|
167
|
+
{ volume: volume, path: '/mnt/volume' }
|
168
|
+
]
|
169
|
+
|
170
|
+
config[:env] = {
|
171
|
+
"DATABASE_URL" => "sqlite3:///mnt/volume/production.sqlite3"
|
172
|
+
}
|
173
|
+
elsif database == 'postgresql' and not secrets.include? 'DATABASE_URL'
|
174
|
+
secret = create_postgres(app, @org, region, 'shared-cpu-1x', 1, 1)
|
175
|
+
|
176
|
+
cmd = "fly secrets set DATABASE_URL=#{secret}"
|
177
|
+
say_status :run, cmd
|
178
|
+
system cmd
|
179
|
+
end
|
180
|
+
|
181
|
+
# build config for release machine, overriding server command
|
182
|
+
release_config = config.dup
|
183
|
+
release_config.delete :services
|
184
|
+
release_config.delete :mounts
|
185
|
+
release_config[:env] = { 'SERVER_COMMAND' => 'bin/rails fly:release' }
|
186
|
+
|
187
|
+
# perform release
|
188
|
+
say_status :fly, release_config[:env]['SERVER_COMMAND']
|
189
|
+
machine = release(app, release_config)
|
190
|
+
Fly::Machines.delete_machine app, machine if machine
|
191
|
+
|
192
|
+
# start proxy, if necessary
|
193
|
+
endpoint = Fly::Machines::fly_api_hostname!
|
194
|
+
|
195
|
+
# start app
|
196
|
+
say_status :fly, "start #{app}"
|
197
|
+
start = Fly::Machines.create_start_machine(app, config: config)
|
198
|
+
machine = start[:id]
|
199
|
+
|
200
|
+
if !machine
|
201
|
+
STDERR.puts 'Error starting application'
|
202
|
+
PP.pp start, STDERR
|
203
|
+
exit 1
|
204
|
+
end
|
205
|
+
|
206
|
+
5.times do
|
207
|
+
status = Fly::Machines.wait_for_machine app, machine,
|
208
|
+
timeout: 60, status: 'started'
|
209
|
+
return if status[:ok]
|
210
|
+
end
|
211
|
+
|
212
|
+
STDERR.puts 'Timeout waiting for application to start'
|
213
|
+
end
|
214
|
+
|
215
|
+
def terraform(app, image)
|
216
|
+
# update main.tf with the image name
|
217
|
+
tf = IO.read('main.tf')
|
218
|
+
tf[/^\s*image\s*=\s*"(.*?)"/, 1] = image.strip
|
219
|
+
IO.write 'main.tf', tf
|
220
|
+
|
221
|
+
# find first machine in terraform config file
|
222
|
+
machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
|
223
|
+
block.keys.first == :resource and
|
224
|
+
block.values.first.keys.first == 'fly_machine'}
|
225
|
+
|
226
|
+
# extract HCL configuration for the machine
|
227
|
+
config = machines.values.first.values.first.values.first
|
228
|
+
|
229
|
+
# delete HCL specific configuration items
|
230
|
+
%i(services for_each region app name depends_on).each do |key|
|
231
|
+
config.delete key
|
232
|
+
end
|
233
|
+
|
234
|
+
# move machine configuration into guest object
|
235
|
+
config[:guest] = {
|
236
|
+
cpus: config.delete(:cpus),
|
237
|
+
memory_mb: config.delete(:memorymb),
|
238
|
+
cpu_kind: config.delete(:cputype)
|
239
|
+
}
|
240
|
+
|
241
|
+
# release machines should have no services or mounts
|
242
|
+
config.delete :services
|
243
|
+
config.delete :mounts
|
244
|
+
|
245
|
+
# override start command
|
246
|
+
config[:env] ||= {}
|
247
|
+
config[:env]['SERVER_COMMAND'] = 'bin/rails fly:release'
|
248
|
+
|
249
|
+
# start proxy, if necessary
|
250
|
+
endpoint = Fly::Machines::fly_api_hostname!
|
251
|
+
|
252
|
+
# start release machine
|
253
|
+
STDERR.puts "--> #{config[:env]['SERVER_COMMAND']}"
|
254
|
+
start = Fly::Machines.create_start_machine(app, config: config)
|
255
|
+
machine = start[:id]
|
256
|
+
|
257
|
+
if !machine
|
258
|
+
STDERR.puts 'Error starting release machine'
|
259
|
+
PP.pp start, STDERR
|
260
|
+
exit 1
|
261
|
+
end
|
262
|
+
|
263
|
+
# wait for release to copmlete
|
264
|
+
event = nil
|
265
|
+
90.times do
|
266
|
+
sleep 1
|
267
|
+
status = Fly::Machines.get_a_machine app, machine
|
268
|
+
event = status[:events]&.first
|
269
|
+
break if event && event[:type] == 'exit'
|
270
|
+
end
|
271
|
+
|
272
|
+
# extract exit code
|
273
|
+
exit_code = event.dig(:request, :exit_event, :exit_code)
|
274
|
+
|
275
|
+
if exit_code == 0
|
276
|
+
# delete release machine
|
277
|
+
Fly::Machines.delete_machine app, machine
|
278
|
+
|
279
|
+
# use terraform apply to deploy
|
280
|
+
ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
|
281
|
+
ENV['FLY_HTTP_ENDPOINT'] = endpoint if endpoint
|
282
|
+
system 'terraform apply -auto-approve'
|
283
|
+
else
|
284
|
+
STDERR.puts 'Error performing release'
|
285
|
+
STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
|
286
|
+
STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
|
287
|
+
exit 1
|
288
|
+
end
|
289
|
+
end
|
65
290
|
end
|
66
291
|
end
|
@@ -98,9 +98,9 @@ module Fly
|
|
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
|