swarm_orca 0.1.1

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.
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