kaiser 0.0.0 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +281 -0
- data/exe/kaiser +87 -0
- data/lib/kaiser/after_dotter.rb +23 -0
- data/lib/kaiser/cli.rb +579 -0
- data/lib/kaiser/cli_options.rb +14 -0
- data/lib/kaiser/cmds/attach.rb +23 -0
- data/lib/kaiser/cmds/db_load.rb +29 -0
- data/lib/kaiser/cmds/db_reset.rb +22 -0
- data/lib/kaiser/cmds/db_reset_hard.rb +21 -0
- data/lib/kaiser/cmds/db_save.rb +26 -0
- data/lib/kaiser/cmds/deinit.rb +22 -0
- data/lib/kaiser/cmds/down.rb +19 -0
- data/lib/kaiser/cmds/init.rb +39 -0
- data/lib/kaiser/cmds/login.rb +21 -0
- data/lib/kaiser/cmds/logs.rb +19 -0
- data/lib/kaiser/cmds/root.rb +21 -0
- data/lib/kaiser/cmds/set.rb +70 -0
- data/lib/kaiser/cmds/show.rb +39 -0
- data/lib/kaiser/cmds/shutdown.rb +26 -0
- data/lib/kaiser/cmds/up.rb +42 -0
- data/lib/kaiser/command_runner.rb +50 -0
- data/lib/kaiser/config.rb +66 -0
- data/lib/kaiser/docker_control.rb +10 -0
- data/lib/kaiser/dotter.rb +18 -0
- data/lib/kaiser/error.rb +14 -0
- data/lib/kaiser/kaiserfile.rb +80 -0
- data/lib/kaiser/plugin.rb +58 -0
- data/lib/kaiser/plugins/git_submodule.rb +20 -0
- data/lib/kaiser/version.rb +5 -0
- data/lib/kaiser.rb +51 -5
- metadata +142 -13
data/lib/kaiser/cli.rb
ADDED
@@ -0,0 +1,579 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kaiser/command_runner'
|
4
|
+
|
5
|
+
module Kaiser
|
6
|
+
# The commandline
|
7
|
+
class Cli
|
8
|
+
extend Kaiser::CliOptions
|
9
|
+
|
10
|
+
def set_config
|
11
|
+
# This is here for backwards compatibility since it can be used in Kaiserfiles.
|
12
|
+
# It would be a good idea to deprecate this and make it more abstract.
|
13
|
+
@work_dir = Config.work_dir
|
14
|
+
@config_dir = Config.work_dir
|
15
|
+
@config_file = Config.config_file
|
16
|
+
@kaiserfile = Config.kaiserfile
|
17
|
+
@config = Config.config
|
18
|
+
@out = Config.out
|
19
|
+
@info_out = Config.info_out
|
20
|
+
end
|
21
|
+
|
22
|
+
# At first I did this in the constructor but the problem with that is Optimist
|
23
|
+
# will parse the entire commandline for the first Cli command registered.
|
24
|
+
# That means no matter what you call -h or --help on, it will always return the help
|
25
|
+
# for the first subcommand. Fixed this by only running define_options when
|
26
|
+
# a command is run. We can't just run the constructor at that point because
|
27
|
+
# we need each Cli class to be constructed in the beginning so we can add their
|
28
|
+
# usage text to the output of `kaiser -h`.
|
29
|
+
def define_options(global_opts = [])
|
30
|
+
# We can't just call usage within the options block because that actually shifts
|
31
|
+
# the scope to Optimist::Parser. We can still reference variables but we can't
|
32
|
+
# call instance methods of a Kaiser::Cli class.
|
33
|
+
u = usage
|
34
|
+
Optimist.options do
|
35
|
+
banner u
|
36
|
+
|
37
|
+
global_opts.each { |o| opt *o }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.register(name, klass)
|
42
|
+
@subcommands ||= {}
|
43
|
+
@subcommands[name] = klass.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.run_command(name, global_opts)
|
47
|
+
cmd = @subcommands[name]
|
48
|
+
opts = cmd.define_options(global_opts + cmd.class.options)
|
49
|
+
|
50
|
+
# The define_options method has stripped all arguments from the cli so now
|
51
|
+
# all that we're left with in ARGV are the subcommand to be run and possibly
|
52
|
+
# its own subcommands. We remove the subcommand here so each subcommand can
|
53
|
+
# easily use ARGV.shift to access its own subcommands.
|
54
|
+
ARGV.shift
|
55
|
+
|
56
|
+
Kaiser::Config.load(Dir.pwd)
|
57
|
+
|
58
|
+
# We do all this work in here instead of the exe/kaiser file because we
|
59
|
+
# want -h options to output before we check if a Kaiserfile exists.
|
60
|
+
# If we do it in exe/kaiser, people won't be able to check help messages
|
61
|
+
# unless they create a Kaiserfile firest.
|
62
|
+
if opts[:quiet]
|
63
|
+
Config.out = File.open(File::NULL, 'w')
|
64
|
+
Config.info_out = File.open(File::NULL, 'w')
|
65
|
+
elsif opts[:verbose] || Config.always_verbose?
|
66
|
+
Config.out = $stderr
|
67
|
+
Config.info_out = Kaiser::AfterDotter.new(dotter: Kaiser::Dotter.new)
|
68
|
+
else
|
69
|
+
Config.out = Kaiser::Dotter.new
|
70
|
+
Config.info_out = Kaiser::AfterDotter.new(dotter: Config.out)
|
71
|
+
end
|
72
|
+
|
73
|
+
cmd.set_config
|
74
|
+
|
75
|
+
cmd.execute(opts)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.all_subcommands_usage
|
79
|
+
output = ''
|
80
|
+
|
81
|
+
@subcommands.each do |name, klass|
|
82
|
+
name_s = name.to_s
|
83
|
+
|
84
|
+
output += name_s + "\n"
|
85
|
+
output += name_s.gsub(/./, '-')
|
86
|
+
output += "\n"
|
87
|
+
output += klass.usage
|
88
|
+
output += "\n\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
output
|
92
|
+
end
|
93
|
+
|
94
|
+
def down
|
95
|
+
stop_db
|
96
|
+
stop_app
|
97
|
+
delete_db_volume
|
98
|
+
end
|
99
|
+
|
100
|
+
def stop_app
|
101
|
+
Config.info_out.puts 'Stopping application'
|
102
|
+
killrm app_container_name
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def ensure_db_volume
|
108
|
+
create_if_volume_not_exist db_volume_name
|
109
|
+
end
|
110
|
+
|
111
|
+
def setup_db
|
112
|
+
ensure_db_volume
|
113
|
+
start_db
|
114
|
+
return if File.exist?(default_db_image)
|
115
|
+
|
116
|
+
# Some databases keep state around, best to clean it.
|
117
|
+
stop_db
|
118
|
+
delete_db_volume
|
119
|
+
start_db
|
120
|
+
|
121
|
+
Config.info_out.puts 'Provisioning database'
|
122
|
+
killrm "#{envname}-apptemp"
|
123
|
+
CommandRunner.run! Config.out, "docker run -ti
|
124
|
+
--rm
|
125
|
+
--name #{envname}-apptemp
|
126
|
+
--network #{Config.config[:networkname]}
|
127
|
+
#{app_params}
|
128
|
+
kaiser:#{envname}-#{current_branch} #{db_reset_command}"
|
129
|
+
|
130
|
+
save_db('.default')
|
131
|
+
end
|
132
|
+
|
133
|
+
def save_db(name)
|
134
|
+
killrm db_container_name
|
135
|
+
save_db_state_from container: db_volume_name, to_file: db_image_path(name)
|
136
|
+
start_db
|
137
|
+
end
|
138
|
+
|
139
|
+
def load_db(name)
|
140
|
+
check_db_image_exists(name)
|
141
|
+
killrm db_container_name
|
142
|
+
CommandRunner.run Config.out, "docker volume rm #{db_volume_name}"
|
143
|
+
delete_db_volume
|
144
|
+
create_if_volume_not_exist db_volume_name
|
145
|
+
load_db_state_from file: db_image_path(name), to_container: db_volume_name
|
146
|
+
start_db
|
147
|
+
end
|
148
|
+
|
149
|
+
def check_db_image_exists(name)
|
150
|
+
return if File.exist?(db_image_path(name))
|
151
|
+
|
152
|
+
Optimist.die 'No saved state exists with that name'
|
153
|
+
end
|
154
|
+
|
155
|
+
def save_db_state_from(container:, to_file:)
|
156
|
+
Config.info_out.puts 'Saving database state'
|
157
|
+
File.write(to_file, '')
|
158
|
+
CommandRunner.run Config.out, "docker run --rm
|
159
|
+
-v #{container}:#{db_data_directory}
|
160
|
+
-v #{to_file}:#{to_file}
|
161
|
+
ruby:alpine
|
162
|
+
tar cvjf #{to_file} #{db_data_directory}"
|
163
|
+
end
|
164
|
+
|
165
|
+
def load_db_state_from(file:, to_container:)
|
166
|
+
Config.info_out.puts 'Loading database state'
|
167
|
+
CommandRunner.run Config.out, "docker run --rm
|
168
|
+
-v #{to_container}:#{db_data_directory}
|
169
|
+
-v #{file}:#{file}
|
170
|
+
ruby:alpine
|
171
|
+
tar xvjf #{file} -C #{db_data_directory}
|
172
|
+
--strip #{db_data_directory.scan(%r{\/}).count}"
|
173
|
+
end
|
174
|
+
|
175
|
+
def stop_db
|
176
|
+
Config.info_out.puts 'Stopping database'
|
177
|
+
killrm db_container_name
|
178
|
+
end
|
179
|
+
|
180
|
+
def start_db
|
181
|
+
Config.info_out.puts 'Starting up database'
|
182
|
+
run_if_dead db_container_name, "docker run -d
|
183
|
+
-p #{db_port}:#{db_expose}
|
184
|
+
-v #{db_volume_name}:#{db_data_directory}
|
185
|
+
--name #{db_container_name}
|
186
|
+
--network #{network_name}
|
187
|
+
#{db_params}
|
188
|
+
#{db_image}
|
189
|
+
#{db_commands}"
|
190
|
+
wait_for_db unless db_waitscript.nil?
|
191
|
+
end
|
192
|
+
|
193
|
+
def delete_db_volume
|
194
|
+
CommandRunner.run Config.out, "docker volume rm #{db_volume_name}"
|
195
|
+
end
|
196
|
+
|
197
|
+
def current_branch_db_image_dir
|
198
|
+
"#{Config.config_dir}/databases/#{envname}/#{current_branch}"
|
199
|
+
end
|
200
|
+
|
201
|
+
def db_image_path(name)
|
202
|
+
if name.start_with?('./')
|
203
|
+
path = "#{`pwd`.chomp}/#{name.sub('./', '')}"
|
204
|
+
Config.info_out.puts "Database image path is: #{path}"
|
205
|
+
return path
|
206
|
+
end
|
207
|
+
FileUtils.mkdir_p current_branch_db_image_dir
|
208
|
+
"#{current_branch_db_image_dir}/#{name}.tar.bz"
|
209
|
+
end
|
210
|
+
|
211
|
+
def default_db_image
|
212
|
+
db_image_path('.default')
|
213
|
+
end
|
214
|
+
|
215
|
+
def attach_app
|
216
|
+
cmd = (ARGV || []).join(' ')
|
217
|
+
killrm app_container_name
|
218
|
+
|
219
|
+
attach_mounts = Config.kaiserfile.attach_mounts
|
220
|
+
volumes = attach_mounts.map { |from, to| "-v #{`pwd`.chomp}/#{from}:#{to}" }.join(' ')
|
221
|
+
|
222
|
+
system "docker run -ti
|
223
|
+
--name #{app_container_name}
|
224
|
+
--network #{network_name}
|
225
|
+
--dns #{ip_of_container(Config.config[:shared_names][:dns])}
|
226
|
+
--dns-search #{http_suffix}
|
227
|
+
-p #{app_port}:#{app_expose}
|
228
|
+
-e DEV_APPLICATION_HOST=#{envname}.#{http_suffix}
|
229
|
+
-e VIRTUAL_HOST=#{envname}.#{http_suffix}
|
230
|
+
-e VIRTUAL_PORT=#{app_expose}
|
231
|
+
#{volumes}
|
232
|
+
#{app_params}
|
233
|
+
kaiser:#{envname}-#{current_branch} #{cmd}".tr("\n", ' ')
|
234
|
+
|
235
|
+
Config.out.puts 'Cleaning up...'
|
236
|
+
end
|
237
|
+
|
238
|
+
def start_app
|
239
|
+
Config.info_out.puts 'Starting up application'
|
240
|
+
killrm app_container_name
|
241
|
+
CommandRunner.run! Config.out, "docker run -d
|
242
|
+
--name #{app_container_name}
|
243
|
+
--network #{network_name}
|
244
|
+
--dns #{ip_of_container(Config.config[:shared_names][:dns])}
|
245
|
+
--dns-search #{http_suffix}
|
246
|
+
-p #{app_port}:#{app_expose}
|
247
|
+
-e DEV_APPLICATION_HOST=#{envname}.#{http_suffix}
|
248
|
+
-e VIRTUAL_HOST=#{envname}.#{http_suffix}
|
249
|
+
-e VIRTUAL_PORT=#{app_expose}
|
250
|
+
#{app_params}
|
251
|
+
kaiser:#{envname}-#{current_branch}"
|
252
|
+
wait_for_app
|
253
|
+
end
|
254
|
+
|
255
|
+
def tmp_waitscript_name
|
256
|
+
"#{Config.config_dir}/.#{envname}-dbwaitscript"
|
257
|
+
end
|
258
|
+
|
259
|
+
def tmp_dockerfile_name
|
260
|
+
"#{Config.config_dir}/.#{envname}-dockerfile"
|
261
|
+
end
|
262
|
+
|
263
|
+
def tmp_db_waiter
|
264
|
+
"#{envname}-dbwait"
|
265
|
+
end
|
266
|
+
|
267
|
+
def tmp_file_container
|
268
|
+
"#{envname}-tmpfiles"
|
269
|
+
end
|
270
|
+
|
271
|
+
def tmp_file_volume
|
272
|
+
"#{envname}-tmpfiles-vol"
|
273
|
+
end
|
274
|
+
|
275
|
+
def run_blocking_script(image, params, script, &block)
|
276
|
+
killrm tmp_db_waiter
|
277
|
+
killrm tmp_file_container
|
278
|
+
|
279
|
+
create_if_volume_not_exist tmp_file_volume
|
280
|
+
|
281
|
+
CommandRunner.run! Config.out, "docker create
|
282
|
+
-v #{tmp_file_volume}:/tmpvol
|
283
|
+
--name #{tmp_file_container} alpine"
|
284
|
+
|
285
|
+
File.write(tmp_waitscript_name, script)
|
286
|
+
|
287
|
+
CommandRunner.run! Config.out, "docker cp
|
288
|
+
#{tmp_waitscript_name}
|
289
|
+
#{tmp_file_container}:/tmpvol/wait.sh"
|
290
|
+
|
291
|
+
CommandRunner.run!(
|
292
|
+
Config.out,
|
293
|
+
"docker run --rm -ti
|
294
|
+
--name #{tmp_db_waiter}
|
295
|
+
--network #{network_name}
|
296
|
+
-v #{tmp_file_volume}:/tmpvol
|
297
|
+
#{params}
|
298
|
+
#{image} sh /tmpvol/wait.sh",
|
299
|
+
&block
|
300
|
+
)
|
301
|
+
ensure
|
302
|
+
killrm tmp_file_container
|
303
|
+
FileUtils.rm(tmp_waitscript_name)
|
304
|
+
end
|
305
|
+
|
306
|
+
def wait_for_app
|
307
|
+
return unless server_type == :http
|
308
|
+
|
309
|
+
Config.info_out.puts 'Waiting for server to start...'
|
310
|
+
|
311
|
+
http_code_extractor = "curl -s -o /dev/null -I -w \"\%{http_code}\" http://#{app_container_name}:#{app_expose}"
|
312
|
+
unreachable_test = "#{http_code_extractor} | grep -q 000"
|
313
|
+
|
314
|
+
# This waitscript runs until curl returns a non-unreachable status code
|
315
|
+
# and then checks to see if its 200. If its not, it will raise an error.
|
316
|
+
wait_script = <<-SCRIPT
|
317
|
+
apk update
|
318
|
+
apk add curl
|
319
|
+
while #{unreachable_test}; do
|
320
|
+
echo 'o'
|
321
|
+
sleep 1
|
322
|
+
done
|
323
|
+
echo '#{http_code_extractor}'
|
324
|
+
echo $(#{http_code_extractor})
|
325
|
+
if [ "$(#{http_code_extractor})" != "200" ]; then
|
326
|
+
echo $(#{http_code_extractor})
|
327
|
+
else
|
328
|
+
echo '!'
|
329
|
+
fi
|
330
|
+
SCRIPT
|
331
|
+
run_blocking_script('alpine', '', wait_script) do |line|
|
332
|
+
# This script gets run every line that gets output.
|
333
|
+
# The '!' exclamation mark means success
|
334
|
+
# Three numbers means a status code has been returned
|
335
|
+
# If curl returns an error status the script will cut out and
|
336
|
+
# the app container died error will be displayed.
|
337
|
+
raise Kaiser::Error, "Failed with HTTP status: #{line}" if line =~ /^[0-9]{3}$/ && line != '200'
|
338
|
+
raise Kaiser::Error, 'App container died. Run `kaiser logs` to see why.' if line != '!' && container_dead?(app_container_name)
|
339
|
+
end
|
340
|
+
|
341
|
+
Config.info_out.puts 'Started successfully!'
|
342
|
+
end
|
343
|
+
|
344
|
+
def wait_for_db
|
345
|
+
Config.info_out.puts 'Waiting for database to start...'
|
346
|
+
run_blocking_script(db_image, db_waitscript_params, db_waitscript)
|
347
|
+
Config.info_out.puts 'Started.'
|
348
|
+
end
|
349
|
+
|
350
|
+
def network_name
|
351
|
+
Config.config[:networkname]
|
352
|
+
end
|
353
|
+
|
354
|
+
def db_port
|
355
|
+
Config.config[:envs][envname][:db_port]
|
356
|
+
end
|
357
|
+
|
358
|
+
def db_expose
|
359
|
+
Config.kaiserfile.database[:port]
|
360
|
+
end
|
361
|
+
|
362
|
+
def db_params
|
363
|
+
eval_template Config.kaiserfile.database[:params]
|
364
|
+
end
|
365
|
+
|
366
|
+
def db_image
|
367
|
+
Config.kaiserfile.database[:image]
|
368
|
+
end
|
369
|
+
|
370
|
+
def db_commands
|
371
|
+
eval_template Config.kaiserfile.database[:commands]
|
372
|
+
end
|
373
|
+
|
374
|
+
def db_data_directory
|
375
|
+
Config.kaiserfile.database[:data_dir]
|
376
|
+
end
|
377
|
+
|
378
|
+
def server_type
|
379
|
+
Config.kaiserfile.server_type
|
380
|
+
end
|
381
|
+
|
382
|
+
def db_waitscript
|
383
|
+
eval_template Config.kaiserfile.database[:waitscript]
|
384
|
+
end
|
385
|
+
|
386
|
+
def db_waitscript_params
|
387
|
+
eval_template Config.kaiserfile.database[:waitscript_params]
|
388
|
+
end
|
389
|
+
|
390
|
+
def docker_file_contents
|
391
|
+
eval_template Config.kaiserfile.docker_file_contents
|
392
|
+
end
|
393
|
+
|
394
|
+
def docker_build_args
|
395
|
+
Config.kaiserfile.docker_build_args
|
396
|
+
end
|
397
|
+
|
398
|
+
def app_params
|
399
|
+
eval_template Config.kaiserfile.params
|
400
|
+
end
|
401
|
+
|
402
|
+
def db_reset_command
|
403
|
+
eval_template Config.kaiserfile.database_reset_command
|
404
|
+
end
|
405
|
+
|
406
|
+
def eval_template(value)
|
407
|
+
ERB.new(value).result(binding)
|
408
|
+
end
|
409
|
+
|
410
|
+
def app_port
|
411
|
+
Config.config[:envs][envname][:app_port]
|
412
|
+
end
|
413
|
+
|
414
|
+
def app_expose
|
415
|
+
Config.kaiserfile.port
|
416
|
+
end
|
417
|
+
|
418
|
+
def db_volume_name
|
419
|
+
"#{envname}-database"
|
420
|
+
end
|
421
|
+
|
422
|
+
def app_container_name
|
423
|
+
"#{envname}-app"
|
424
|
+
end
|
425
|
+
|
426
|
+
def db_container_name
|
427
|
+
"#{envname}-db"
|
428
|
+
end
|
429
|
+
|
430
|
+
def current_branch
|
431
|
+
`git branch | grep \\* | cut -d ' ' -f2`.chomp.gsub(/[^\-_0-9a-z]+/, '-')
|
432
|
+
end
|
433
|
+
|
434
|
+
def ensure_env
|
435
|
+
return unless envname.nil?
|
436
|
+
|
437
|
+
Optimist.die('No environment? Please use kaiser init <name>')
|
438
|
+
end
|
439
|
+
|
440
|
+
def http_suffix
|
441
|
+
Config.config[:http_suffix] || 'lvh.me'
|
442
|
+
end
|
443
|
+
|
444
|
+
def copy_keyfile(file)
|
445
|
+
if Config.config[:cert_source][:folder]
|
446
|
+
CommandRunner.run! Config.out, "docker run --rm
|
447
|
+
-v #{Config.config[:shared_names][:certs]}:/certs
|
448
|
+
-v #{Config.config[:cert_source][:folder]}:/cert_source
|
449
|
+
alpine cp /cert_source/#{file} /certs/#{file}"
|
450
|
+
|
451
|
+
elsif Config.config[:cert_source][:url]
|
452
|
+
CommandRunner.run! Config.out, "docker run --rm
|
453
|
+
-v #{Config.config[:shared_names][:certs]}:/certs
|
454
|
+
alpine wget #{Config.config[:cert_source][:url]}/#{file}
|
455
|
+
-O /certs/#{file}"
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
def prepare_cert_volume!
|
460
|
+
create_if_volume_not_exist Config.config[:shared_names][:certs]
|
461
|
+
return unless Config.config[:cert_source]
|
462
|
+
|
463
|
+
%w[
|
464
|
+
chain.pem
|
465
|
+
crt
|
466
|
+
key
|
467
|
+
].each do |file_ext|
|
468
|
+
copy_keyfile("#{http_suffix}.#{file_ext}")
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def ensure_setup
|
473
|
+
ensure_env
|
474
|
+
|
475
|
+
setup if network.nil?
|
476
|
+
|
477
|
+
create_if_network_not_exist Config.config[:networkname]
|
478
|
+
if_container_dead Config.config[:shared_names][:nginx] do
|
479
|
+
prepare_cert_volume!
|
480
|
+
end
|
481
|
+
run_if_dead(
|
482
|
+
Config.config[:shared_names][:redis],
|
483
|
+
"docker run -d
|
484
|
+
--name #{Config.config[:shared_names][:redis]}
|
485
|
+
--network #{Config.config[:networkname]}
|
486
|
+
redis:alpine"
|
487
|
+
)
|
488
|
+
run_if_dead(
|
489
|
+
Config.config[:shared_names][:chrome],
|
490
|
+
"docker run -d
|
491
|
+
-p 5900:5900
|
492
|
+
--name #{Config.config[:shared_names][:chrome]}
|
493
|
+
--network #{Config.config[:networkname]}
|
494
|
+
selenium/standalone-chrome-debug"
|
495
|
+
)
|
496
|
+
run_if_dead(
|
497
|
+
Config.config[:shared_names][:nginx],
|
498
|
+
"docker run -d
|
499
|
+
-p 80:80
|
500
|
+
-p 443:443
|
501
|
+
-v #{Config.config[:shared_names][:certs]}:/etc/nginx/certs
|
502
|
+
-v /var/run/docker.sock:/tmp/docker.sock:ro
|
503
|
+
--privileged
|
504
|
+
--name #{Config.config[:shared_names][:nginx]}
|
505
|
+
--network #{Config.config[:networkname]}
|
506
|
+
jwilder/nginx-proxy"
|
507
|
+
)
|
508
|
+
run_if_dead(
|
509
|
+
Config.config[:shared_names][:dns],
|
510
|
+
"docker run -d
|
511
|
+
--name #{Config.config[:shared_names][:dns]}
|
512
|
+
--network #{Config.config[:networkname]}
|
513
|
+
--privileged
|
514
|
+
-v /var/run/docker.sock:/docker.sock:ro
|
515
|
+
davidsiaw/docker-dns
|
516
|
+
--domain #{http_suffix}
|
517
|
+
--record :#{ip_of_container(Config.config[:shared_names][:nginx])}"
|
518
|
+
)
|
519
|
+
end
|
520
|
+
|
521
|
+
def ip_of_container(containername)
|
522
|
+
networkname = ".NetworkSettings.Networks.#{Config.config[:networkname]}.IPAddress"
|
523
|
+
`docker inspect -f '{{#{networkname}}}' #{containername}`.chomp
|
524
|
+
end
|
525
|
+
|
526
|
+
def network
|
527
|
+
`docker network inspect #{Config.config[:networkname]} 2>/dev/null`
|
528
|
+
end
|
529
|
+
|
530
|
+
def container_dead?(container)
|
531
|
+
x = JSON.parse(`docker inspect #{container} 2>/dev/null`)
|
532
|
+
return true if x.length.zero? || x[0]['State']['Running'] == false
|
533
|
+
end
|
534
|
+
|
535
|
+
def if_container_dead(container)
|
536
|
+
return unless container_dead?(container)
|
537
|
+
|
538
|
+
yield if block_given?
|
539
|
+
end
|
540
|
+
|
541
|
+
def create_if_volume_not_exist(vol)
|
542
|
+
x = JSON.parse(`docker volume inspect #{vol} 2>/dev/null`)
|
543
|
+
return unless x.length.zero?
|
544
|
+
|
545
|
+
CommandRunner.run! Config.out, "docker volume create #{vol}"
|
546
|
+
end
|
547
|
+
|
548
|
+
def create_if_network_not_exist(net)
|
549
|
+
x = JSON.parse(`docker inspect #{net} 2>/dev/null`)
|
550
|
+
return unless x.length.zero?
|
551
|
+
|
552
|
+
CommandRunner.run! Config.out, "docker network create #{net}"
|
553
|
+
end
|
554
|
+
|
555
|
+
def run_if_dead(container, command)
|
556
|
+
if_container_dead container do
|
557
|
+
Config.info_out.puts "Starting up #{container}"
|
558
|
+
killrm container
|
559
|
+
CommandRunner.run Config.out, command
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def envname
|
564
|
+
Config.config[:envnames][Config.work_dir]
|
565
|
+
end
|
566
|
+
|
567
|
+
def save_config
|
568
|
+
File.write(Config.config_file, Config.config.to_yaml)
|
569
|
+
end
|
570
|
+
|
571
|
+
def killrm(container)
|
572
|
+
x = JSON.parse(`docker inspect #{container} 2>/dev/null`)
|
573
|
+
return if x.length.zero?
|
574
|
+
|
575
|
+
CommandRunner.run Config.out, "docker kill #{container}" if x[0]['State'] && x[0]['State']['Running'] == true
|
576
|
+
CommandRunner.run Config.out, "docker rm #{container}" if x[0]['State']
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Attach < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down the application container and starts it up again with the current directory bind mounted inside. This way the application will run from the source code in the current directory and any edits you make will immediately show up inside the container. This is ideal for development.
|
9
|
+
|
10
|
+
Once the attached container exits (through the use of control+c for example) it will be replaced by a regular non-attached version of the app container.
|
11
|
+
|
12
|
+
USAGE: kaiser attach
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(_opts)
|
17
|
+
ensure_setup
|
18
|
+
attach_app
|
19
|
+
start_app
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class DbLoad < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down the database docker container, *replaces* the database with the backup provided and brings the container up again.
|
9
|
+
|
10
|
+
The database will be restored from a tarball saved as \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/<DB_BACKUP_FILENAME>.tar.bz\`
|
11
|
+
|
12
|
+
Alternatively you can also load it from your current directory.
|
13
|
+
|
14
|
+
If no database name was provided, the default database stored at \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/.default.tar.bz\` will be used.
|
15
|
+
|
16
|
+
USAGE: kaiser db_load
|
17
|
+
kaiser db_load DB_BACKUP_FILENAME
|
18
|
+
kaiser db_load ./my_database.tar.bz
|
19
|
+
EOS
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(_opts)
|
23
|
+
ensure_setup
|
24
|
+
name = ARGV.shift || '.default'
|
25
|
+
load_db(name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class DbReset < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down the database docker container, *replaces* the database with the default database image stored at \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/.default.tar.bz\` and brings the container up again.
|
9
|
+
|
10
|
+
This is the same as running \`kaiser db_load\` with no arguments.
|
11
|
+
|
12
|
+
USAGE: kaiser db_reset
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(_opts)
|
17
|
+
ensure_setup
|
18
|
+
load_db('.default')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class DbResetHard < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down the database docker container, deletes the docker volume on which the db was stored, deletes the default database image stored at \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/.default.tar.bz\`, rebuilds the docker volume and the default database image from scratch and then brings the container up again.
|
9
|
+
|
10
|
+
USAGE: kaiser db_reset_hard
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
ensure_setup
|
16
|
+
FileUtils.rm db_image_path('.default') if File.exist?(db_image_path('.default'))
|
17
|
+
setup_db
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|