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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 431aea946bdc9bad848c22a46dcceb7bf7c10615db23bde0b893fea8e1969ac6
4
- data.tar.gz: 035d7c1f8a29daaf1f01a86de8a35d6ff5f8c607b6c7105624d7d8ac0467d721
3
+ metadata.gz: 31dbb298f72984f01bd39eb4859577e3442b4f4021b0e099bf0be2e3d7c16134
4
+ data.tar.gz: 374cee9b246abb711a1f6954d9a77f04aeada9f47fb6a6441cebd3105a627ced
5
5
  SHA512:
6
- metadata.gz: 219d59e7f3aca66dcbd177391450ecf1864686fcb00a47dbcc547adba9acc2c79d84b28d1fad7d9d2cdea6424c17a6411ad65526c1ba71e1208dbc0aed010ee3
7
- data.tar.gz: 6a0c99e63ebfb079a25671ab7a3a3c075d2724e0f2dd73775776a337e264f1b027f8ab5cd38583eeace8944bcf12b84f6e500340e1a92961861292f367f53c1b
6
+ metadata.gz: 9d6a32e791648274508e64ca20bb3234a42189bff8a9c6031549dcb12b6391b47685c7606c708a97327bb71a058238c76029788d753d263e294ef204a4167b18
7
+ data.tar.gz: 68481956ca5448163257265683cc72363f19a83f5eee2fe4e51c3a00baf6b38988336ac439cc87ecd7b4f6773021193248f0850c64b8652bb559edcd9181e649
@@ -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
- # wait_for_machine_to_start 'user-functions', '73d8d46dbee589'
102
- def self.wait_for_machine_to_start app, machine, timeout=60
103
- get "/v1/apps/#{app}/machines/#{machine}/wait?timeout=#{timeout}"
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'
@@ -1,3 +1,3 @@
1
1
  module Fly_io
2
- VERSION = '0.0.21'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require 'open3'
2
2
  require 'fly.io-rails/actions'
3
3
 
4
- class TerraformGenerator < Rails::Generators::Base
4
+ class Fly::Generators::TerraformGenerator < Rails::Generators::Base
5
5
  include FlyIoRails::Utils
6
6
 
7
7
  class_option :name, type: :string, required: false
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
- # build and push an image
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
- # find first machine in terraform config file
19
- machines = Fly::HCL.parse(IO.read('main.tf')).find {|block|
20
- block.keys.first == :resource and
21
- block.values.first.keys.first == 'fly_machine'}
22
-
23
- # extract HCL configuration for the machine
24
- config = machines.values.first.values.first.values.first
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
- # extract fly application name
27
- app = config[:app]
19
+ exit 1 unless output =~ /^New app created: /
28
20
 
29
- # delete HCL specific configuration items
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
- # move machine configuration into guest object
35
- config[:guest] = {
36
- cpus: config.delete(:cpus),
37
- memory_mb: config.delete(:memorymb),
38
- cpu_kind: config.delete(:cputype)
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
- # start proxy, if necessary
50
- endpoint = Fly::Machines::fly_api_hostname!
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
- # extract exit code
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
- # use terraform apply to deploy
80
- ENV['FLY_API_TOKEN'] = `flyctl auth token`.chomp
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
- STDERR.puts 'Error performing release'
85
- STDERR.puts (exit_code ? {exit_code: exit_code} : event).inspect
86
- STDERR.puts "run 'flyctl logs --instance #{machine}' for more information"
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,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fly.io-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.1.0
5
5
  platform: x64-mingw32
6
6
  authors:
7
7
  - Sam Ruby