swarm_orca 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.overcommit.yml +33 -0
  4. data/.rubocop.yml +1 -0
  5. data/.rubocop_todo.yml +17 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +15 -0
  9. data/Gemfile +5 -0
  10. data/Gemfile.lock +57 -0
  11. data/README.md +335 -0
  12. data/Rakefile +3 -0
  13. data/bin/orca +7 -0
  14. data/lib/capistrano/scm/copy.rb +62 -0
  15. data/lib/capistrano/scm/tasks/copy.cap +33 -0
  16. data/lib/capistrano/scm/tasks/deploy.rb +16 -0
  17. data/lib/capistrano/swarm_orca/bash/crypt +1 -0
  18. data/lib/capistrano/swarm_orca/deploy.rb +3 -0
  19. data/lib/capistrano/swarm_orca/docker.rb +3 -0
  20. data/lib/capistrano/swarm_orca/helpers/fetch_config.rb +134 -0
  21. data/lib/capistrano/swarm_orca/local.rb +43 -0
  22. data/lib/capistrano/swarm_orca/set_global_config.rb +3 -0
  23. data/lib/capistrano/swarm_orca/tasks/deploy.cap +200 -0
  24. data/lib/capistrano/swarm_orca/tasks/docker.cap +318 -0
  25. data/lib/capistrano/swarm_orca/tasks/set_global_config.cap +28 -0
  26. data/lib/swarm_orca.rb +11 -0
  27. data/lib/swarm_orca/encrypt.rb +40 -0
  28. data/lib/swarm_orca/new.rb +73 -0
  29. data/lib/swarm_orca/orca_cli.rb +41 -0
  30. data/lib/swarm_orca/templates/orca/.gitignore +50 -0
  31. data/lib/swarm_orca/templates/orca/.ruby-gemset.tt +1 -0
  32. data/lib/swarm_orca/templates/orca/.ruby-version +1 -0
  33. data/lib/swarm_orca/templates/orca/README.md +93 -0
  34. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-elasticsearch.yml.erb.tt +22 -0
  35. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-errbit.yml.erb.tt +43 -0
  36. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-mysql.yml.erb.tt +17 -0
  37. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-nginx.yml.erb.tt +22 -0
  38. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-rabbitmq.yml.erb.tt +19 -0
  39. data/lib/swarm_orca/templates/orca/application_stack/docker-stack-redis.yml.erb.tt +19 -0
  40. data/lib/swarm_orca/templates/orca/capistrano/Capfile +45 -0
  41. data/lib/swarm_orca/templates/orca/capistrano/Gemfile.tt +4 -0
  42. data/lib/swarm_orca/templates/orca/capistrano/config/deploy.rb.tt +30 -0
  43. data/lib/swarm_orca/templates/orca/capistrano/config/deploy/template_stage.rb +64 -0
  44. data/lib/swarm_orca/templates/orca/nginx/Dockerfile +5 -0
  45. data/lib/swarm_orca/templates/orca/nginx/nginx.conf +31 -0
  46. data/lib/swarm_orca/templates/orca/redis/Dockerfile +5 -0
  47. data/lib/swarm_orca/templates/orca/redis/redis.conf +2 -0
  48. data/lib/swarm_orca/version.rb +5 -0
  49. data/swarm_orca.gemspec +26 -0
  50. metadata +174 -0
@@ -0,0 +1,318 @@
1
+ namespace :docker do
2
+ include Capistrano::SwarmOrca
3
+ namespace :rm do
4
+ stacks.each do |stack|
5
+ desc "Docker Remove #{stack}"
6
+ task stack do
7
+ shell_command = <<-EOF
8
+ #{env_vars_command stack}
9
+ #{docker_command} stack rm $STACK_NAME
10
+ EOF
11
+
12
+ on roles(stack.to_sym) do |host|
13
+ execute_orca_script(host, shell_command, "remove_#{stack}")
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ namespace :deploy do
20
+ def seed_cmd(application)
21
+ seed_file_path = File.join('seeds', "#{application}.rb")
22
+ seed_file_on_host = File.join('..', seed_file_path)
23
+ seed_file_on_server = File.join('/tmp', seed_file_path)
24
+ return "rails runner #{seed_file_on_server}" if File.exist?(seed_file_on_host)
25
+ return 'rake db:seed'
26
+ end
27
+
28
+ def db_command(stack, application, command)
29
+ config = "-e DATABASE_URL=$#{application.upcase}_DATABASE_URL"
30
+ config = "#{config} #{env_vars_command_for_docker stack}"
31
+ config = "#{config} -v \$PWD/seeds:/tmp/seeds:ro"
32
+
33
+ prefix = fetch_config(stack, 'docker_image_prefix')
34
+ image = fetch_config(stack, "#{application}_docker_image")
35
+ tag = fetch_config(stack, "#{application}_docker_image_tag")
36
+
37
+ config = config.tr("\n",'').strip
38
+
39
+ "#{docker_command} run --network=#{fetch(:network)} #{config} -i #{prefix}#{image}:#{tag} /bin/sh -c \"#{command}\""
40
+ end
41
+
42
+ db_apps.each do |app|
43
+ desc "migrate #{app}"
44
+ task "migrate_#{app}".to_sym, :stack do |t, args|
45
+ stack = args[:stack]
46
+ data_migrate = ":with_data" if fetch_config(stack, "#{app}_data_migrate") == "true"
47
+ data_migrate_status = "db:migrate:status:with_data" if fetch_config(stack, "#{app}_data_migrate_status") == "true"
48
+
49
+ shell_command = <<-EOF
50
+ cd #{current_path}
51
+ #{env_vars_command stack}
52
+ #{db_command stack, app, "rake db:migrate#{data_migrate} #{data_migrate_status}"}
53
+ EOF
54
+
55
+ on roles("#{stack}_db".to_sym) do |host|
56
+ execute_orca_script(host, shell_command, "migrate_#{stack}")
57
+ end
58
+ end
59
+ end
60
+
61
+ db_apps.each do |app|
62
+ desc "Execute one Time Data Migration"
63
+ task "otm_#{app}".to_sym, [:stack, :task_name] do |t, args|
64
+ stack = args[:stack]
65
+ task_name = args[:task_name]
66
+
67
+ shell_command = <<-EOF
68
+ cd #{current_path}
69
+ #{env_vars_command stack}
70
+ #{db_command stack, app, "rake one_time_migrations:#{task_name}"}
71
+ EOF
72
+
73
+ on roles("#{stack}_db".to_sym) do |host|
74
+ execute_orca_script(host, shell_command, "otm_migrate_#{stack}")
75
+ end
76
+ end
77
+ end
78
+
79
+ db_apps.each do |app|
80
+ desc "drop db #{app}"
81
+ task "drop_#{app}_db".to_sym, :stack do |t, args|
82
+ stack = args[:stack]
83
+
84
+ shell_command = <<-EOF
85
+ cd #{current_path}
86
+ #{env_vars_command stack}
87
+ #{db_command stack, app, 'rake db:drop DISABLE_DATABASE_ENVIRONMENT_CHECK=1'}
88
+ EOF
89
+
90
+ on roles("#{stack}_db".to_sym) do |host|
91
+ execute_orca_script(host, shell_command, "drop_db_#{stack}")
92
+ end
93
+ end
94
+ end
95
+
96
+ db_apps.each do |app|
97
+ desc "created db #{app}"
98
+ task "create_#{app}_db".to_sym, :stack do |t, args|
99
+ stack = args[:stack]
100
+ data_migrate = ':with_data' if fetch_config(stack, "#{app}_data_migrate") == 'true'
101
+
102
+ shell_command = <<-EOF
103
+ cd #{current_path}
104
+ #{env_vars_command stack}
105
+ #{db_command stack, app, "rake db:create && ( rake db:schema:load#{data_migrate} || rake db:drop db:create db:migrate#{data_migrate} )"}
106
+ EOF
107
+
108
+ on roles("#{stack}_db".to_sym) do |host|
109
+ execute_orca_script(host, shell_command, "create_db_#{stack}")
110
+ end
111
+ end
112
+ end
113
+
114
+ db_apps.each do |app|
115
+ desc "seed db #{app}"
116
+ task "seed_#{app}_db".to_sym, :stack do |t, args|
117
+ stack = args[:stack]
118
+
119
+ shell_command = <<-EOF
120
+ cd #{current_path}
121
+ #{env_vars_command stack}
122
+ #{db_command stack, app, seed_cmd(app)}
123
+ EOF
124
+
125
+ on roles("#{stack}_db".to_sym) do |host|
126
+ execute_orca_script(host, shell_command, "seed_db_#{stack}")
127
+ end
128
+ end
129
+ end
130
+
131
+ elasticsearch_apps.each do |app|
132
+ desc "reindex elasticsearch #{app}"
133
+ task "reindex_elasticsearch_#{app}".to_sym, :stack do |t, args|
134
+ stack = args[:stack]
135
+
136
+ shell_command = <<-EOF
137
+ cd #{current_path}
138
+ #{env_vars_command stack}
139
+ #{db_command stack, app, 'bundle exec rake searchkick:reindex:all'}
140
+ EOF
141
+
142
+ on roles("#{stack}_reindex".to_sym) do |host|
143
+ execute_orca_script(host, shell_command, "searchkick_reindex_#{stack}")
144
+ end
145
+ end
146
+ end
147
+
148
+ service_stacks_with_build_image.each do |stack|
149
+ task "build_#{stack}".to_sym do
150
+
151
+ prefix = fetch_config(stack, "docker_image_prefix")
152
+ image = fetch_config(stack, "#{stack}_docker_image")
153
+ tag = fetch_config(stack, "#{stack}_docker_image_tag") || "latest"
154
+
155
+ image_name = "#{prefix}#{image}:#{tag}"
156
+
157
+ shell_command = <<-EOF
158
+ cd #{current_path}
159
+ #{env_vars_command stack}
160
+ #{docker_command} build -q -t #{image_name} #{stack}
161
+ #{docker_command} push #{image_name} | cat
162
+ EOF
163
+
164
+ on roles(stack.to_sym) do |host|
165
+ execute_orca_script(host, shell_command, "build_image_#{stack}")
166
+ end
167
+ end
168
+ end
169
+
170
+ stacks.each do |stack|
171
+ desc "Deploy #{stack}"
172
+ task stack do
173
+
174
+ shell_erb_command = <<-EOF
175
+ cd #{current_path}
176
+ (#{env_vars_command stack}; echo "<% #{erb_vars_command stack} %>" && cat application_stack/docker-stack-#{stack}.yml.erb) | erb > application_stack/docker-stack-#{stack}.yml
177
+ EOF
178
+
179
+ shell_deploy_command = <<-EOF
180
+ cd #{current_path}
181
+ #{env_vars_command stack}
182
+ #{docker_command} stack deploy -c application_stack/docker-stack-#{stack}.yml #{fetch_config(stack, 'stack_name')}
183
+ EOF
184
+
185
+ on roles(stack.to_sym) do |host|
186
+ execute_orca_script(host, shell_erb_command, "genrate_stack_#{stack}") if docker_erb_templates
187
+ execute_orca_script(host, shell_deploy_command, "deploy_#{stack}")
188
+ end
189
+ end
190
+ end
191
+
192
+ desc "Create docker network"
193
+ task :create_network do
194
+
195
+ shell_command = <<-EOF
196
+ #{docker_command} network create --driver=overlay --attachable #{fetch(:network)} || true
197
+ EOF
198
+
199
+ on roles(:swarm_manager) do |host|
200
+ execute_orca_script(host, shell_command, "create_network")
201
+ end
202
+ end
203
+
204
+ stacks.each do |stack|
205
+ desc "Stop #{stack}"
206
+ task "stop_#{stack}".to_sym do
207
+
208
+ shell_command = <<-EOF
209
+ cd #{current_path}
210
+ #{docker_command} stack rm #{stack}
211
+ EOF
212
+
213
+ on roles(stack.to_sym) do |host|
214
+ execute_orca_script(host, shell_command, "stop_#{stack}")
215
+ end
216
+ end
217
+ end
218
+
219
+ stacks.each do |stack|
220
+ desc "Scale #{stack} to 0 instances"
221
+ task "scale_down_#{stack}".to_sym do
222
+
223
+ shell_command = <<-EOF
224
+ cd #{current_path}
225
+ #{docker_command} stack services #{fetch_config(stack, "stack_name")} --format "{{.Name}}" | xargs -I % docker service scale %=0 > /dev/null
226
+ EOF
227
+
228
+ on roles(stack.to_sym) do |host|
229
+ execute_orca_script(host, shell_command, "scale_down_#{stack}")
230
+ end
231
+ end
232
+ end
233
+
234
+ stacks.each do |stack|
235
+ desc "Scale #{stack} to 1 instances"
236
+ task "scale_up_#{stack}".to_sym do
237
+
238
+ shell_command = <<-EOF
239
+ cd #{current_path}
240
+ #{docker_command} stack services #{fetch_config(stack, "stack_name")} --format "{{.Name}}" | xargs -I % docker service scale %=1 > /dev/null
241
+ EOF
242
+
243
+ on roles(stack.to_sym) do |host|
244
+ execute_orca_script(host, shell_command, "scale_up_#{stack}")
245
+ end
246
+ end
247
+ end
248
+
249
+ desc "docker cleanup"
250
+ task :cleanup do
251
+ s_line = "------------------------------------------------------------"
252
+
253
+ shell_command = <<-EOF
254
+ echo #{s_line}; echo "Removing stopped containers.."
255
+ echo #{s_line}; #{docker_command} container prune -f
256
+ echo #{s_line}; echo "Removing unused images..."
257
+ echo #{s_line}; #{docker_command} image prune -a -f
258
+ EOF
259
+
260
+ on roles(:all) do |host|
261
+ execute_orca_script(host, shell_command, "cleanup")
262
+ end
263
+ end
264
+
265
+ desc "docker info"
266
+ task :info do
267
+ s_line = "------------------------------------------------------------"
268
+
269
+ shell_command = <<-EOF
270
+ echo #{s_line}; echo "Running docker stacks"
271
+ echo #{s_line}; #{docker_command} stack ls
272
+ echo #{s_line}; echo "Running docker services"
273
+ echo #{s_line}; #{docker_command} service ls
274
+ echo #{s_line}; echo "Docker services info"
275
+ echo #{s_line}; for service in $(docker service ls -q); do #{docker_command} service ps $service; echo #{s_line}; done
276
+ EOF
277
+
278
+ on roles(:swarm_manager) do |host|
279
+ execute_orca_script(host, shell_command, "info")
280
+ end
281
+ end
282
+ end
283
+
284
+ namespace :pull do
285
+
286
+ def docker_images(stack)
287
+ fetch_application_config(stack).keys.map do |key|
288
+ key.to_s.sub(/_docker_image[_a-z]*/, "") if key =~ /_docker_image/
289
+ end.compact.uniq.map do |app|
290
+ prefix = fetch_config(stack, "docker_image_prefix")
291
+ image = fetch_config(stack, "#{app}_docker_image")
292
+ tag = fetch_config(stack, "#{app}_docker_image_tag") || "latest"
293
+ "#{prefix}#{image}:#{tag}"
294
+ end
295
+ end
296
+ desc "Pull All images"
297
+ task :all do
298
+ stacks.each do |stack|
299
+ invoke "docker:pull:#{stack}"
300
+ end
301
+ end
302
+ stacks.each do |stack|
303
+ desc "Pull #{stack} docker image"
304
+ task stack do
305
+ on roles(stack.to_sym) do |host|
306
+ docker_images(stack).each do |docker_image|
307
+ shell_command = <<-EOF
308
+ echo "Pull #{stack} docker image #{docker_image}"
309
+ #{docker_command} pull #{docker_image} | cat
310
+ EOF
311
+
312
+ execute_orca_script(host, shell_command, "pull_docker_image_#{stack}")
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
@@ -0,0 +1,28 @@
1
+ require 'capistrano/dsl'
2
+
3
+ set (:fork) { "wshihadeh" }
4
+ set (:repo_url) { ENV["REPO_URL"] || "git@github.com:#{ENV.fetch('FORK', fetch(:fork))}/orca.git" }
5
+
6
+ # Default branch is :master
7
+ if branch = ENV["BRANCH"]
8
+ set :branch, branch
9
+ else
10
+ ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
11
+ end
12
+
13
+ set :keep_releases, 5
14
+ set (:application) { "orca" }
15
+ set (:deploy_to) { "$HOME/orca" }
16
+ set :pty, true
17
+
18
+ set (:service_stacks) { %w(elasticsearch rabbitmq errbit mysql) }
19
+ set (:service_stacks_with_build_image) { %w(nginx redis) }
20
+
21
+ set (:db_apps_stacks_mapping), {}
22
+
23
+ set (:elasticsearch_apps) {}
24
+
25
+ set (:docker_path) { "" }
26
+ set (:docker_cleanup) { %w(yes 1 true).include? ENV.fetch("PRUNE", 'true') }
27
+
28
+ set (:auto_image_build){ %w(yes 1 true).include? ENV.fetch("BUILD_IMAGE", 'true') }
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'swarm_orca/version'
4
+
5
+ module Capistrano
6
+ # SwarmOrca
7
+ module SwarmOrca
8
+ require 'capistrano/swarm_orca/helpers/fetch_config'
9
+ require 'capistrano/swarm_orca/local'
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ module SwarmOrca
7
+ module Cli
8
+ # Orca encrypt class
9
+ class Encrypt
10
+ CIPHER = 'aes-256-cbc'
11
+ IV = '2adae58101d71b14cbfa3bdaf17d26c8'
12
+
13
+ def initialize(key)
14
+ @key = key
15
+ end
16
+
17
+ def self.generate_key
18
+ SecureRandom.hex(32)
19
+ end
20
+
21
+ def encrypt(clear_text)
22
+ cipher = OpenSSL::Cipher.new(CIPHER)
23
+ cipher.encrypt
24
+ cipher.key = [@key].pack('H*')
25
+ cipher.iv = [IV].pack('H*')
26
+ cipher_text = cipher.update(clear_text) + cipher.final
27
+ Base64.encode64(cipher_text).tr("\n", '')
28
+ end
29
+
30
+ def decrypt(encoded_text)
31
+ cipher_text = Base64.decode64(encoded_text)
32
+ cipher = OpenSSL::Cipher.new(CIPHER)
33
+ cipher.decrypt
34
+ cipher.key = [@key].pack('H*')
35
+ cipher.iv = [IV].pack('H*')
36
+ cipher.update(cipher_text) + cipher.final
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SwarmOrca
4
+ module Cli
5
+ # Orca new command class
6
+ class New
7
+ include Thor::Base
8
+ include Thor::Actions
9
+ source_root "#{File.dirname(__FILE__)}/templates/orca"
10
+
11
+ def initialize(root_dir:, orca_dir_name: 'orca', git_fork: nil, network: 'default_network')
12
+ self.destination_root = "#{root_dir}/#{orca_dir_name}"
13
+ @options = { pretend: false }
14
+ self.behavior = :invoke
15
+ @orca_directory_name = orca_dir_name
16
+ @orca_version = SwarmOrca::VERSION
17
+ @git_fork = git_fork
18
+ @docker_network = network
19
+ @gemset = "orca_#{git_fork}_#{network}"
20
+ end
21
+
22
+ # rubocop:disable Metrics/MethodLength
23
+ def execute
24
+ say('Start Generating orca files')
25
+ %w[
26
+ .gitignore
27
+ .ruby-version
28
+ README.md
29
+ capistrano/Capfile
30
+ nginx/Dockerfile
31
+ nginx/nginx.conf
32
+ redis/Dockerfile
33
+ redis/redis.conf
34
+ capistrano/config/deploy/template_stage.rb
35
+ ].each do |file|
36
+ copy_file "#{source_root}/#{file}", "#{destination_root}/#{file}"
37
+ end
38
+
39
+ %w[
40
+ capistrano/Gemfile
41
+ .ruby-gemset
42
+ capistrano/config/deploy.rb
43
+ application_stack/docker-stack-elasticsearch.yml.erb
44
+ application_stack/docker-stack-errbit.yml.erb
45
+ application_stack/docker-stack-mysql.yml.erb
46
+ application_stack/docker-stack-nginx.yml.erb
47
+ application_stack/docker-stack-rabbitmq.yml.erb
48
+ application_stack/docker-stack-redis.yml.erb
49
+ ].each do |file|
50
+ template "#{source_root}/#{file}.tt", "#{destination_root}/#{file}"
51
+ end
52
+
53
+ say('Complete!', :green)
54
+ say('Next step is to create development stage file from the', :green)
55
+ say(' template file use the following commands to do it', :green)
56
+ say("cd #{destination_root}/capistrano", :green)
57
+ say('gem install bundler', :green)
58
+ say('bundle install', :green)
59
+ say("cd #{destination_root}/capistrano/config/deploy", :green)
60
+ say('cp template_stage.rb development.rb', :green)
61
+ say('Replace all ${VAR} with a valid value', :green)
62
+ say('Read Readme for more information', :green)
63
+ end
64
+ # rubocop:enable Metrics/MethodLength
65
+
66
+ private
67
+
68
+ def source_root
69
+ self.class.source_root
70
+ end
71
+ end
72
+ end
73
+ end