smartmachine 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +661 -0
  3. data/README.md +147 -0
  4. data/bin/console +14 -0
  5. data/bin/setup +8 -0
  6. data/exe/smartmachine +3 -0
  7. data/lib/smart_machine/apps/app.rb +165 -181
  8. data/lib/smart_machine/apps/container.rb +120 -0
  9. data/lib/smart_machine/apps/manager.rb +182 -0
  10. data/lib/smart_machine/base.rb +24 -6
  11. data/lib/smart_machine/buildpackers/buildpacker.rb +95 -0
  12. data/lib/smart_machine/{engine/buildpacks → buildpackers}/rails/Dockerfile +3 -3
  13. data/lib/smart_machine/buildpackers/rails.rb +221 -0
  14. data/lib/smart_machine/commands/app.rb +112 -0
  15. data/lib/smart_machine/commands/buildpacker.rb +53 -0
  16. data/lib/smart_machine/commands/credentials.rb +17 -0
  17. data/lib/smart_machine/commands/docker.rb +23 -0
  18. data/lib/smart_machine/commands/engine.rb +27 -0
  19. data/lib/smart_machine/commands/grid.rb +33 -0
  20. data/lib/smart_machine/commands/grid_commands/elasticsearch.rb +68 -0
  21. data/lib/smart_machine/commands/grid_commands/minio.rb +65 -0
  22. data/lib/smart_machine/commands/grid_commands/mysql.rb +71 -0
  23. data/lib/smart_machine/commands/grid_commands/nginx.rb +53 -0
  24. data/lib/smart_machine/commands/grid_commands/prereceiver.rb +96 -0
  25. data/lib/smart_machine/commands/grid_commands/redis.rb +65 -0
  26. data/lib/smart_machine/commands/grid_commands/scheduler.rb +15 -0
  27. data/lib/smart_machine/commands/grid_commands/sub_thor.rb +15 -0
  28. data/lib/smart_machine/commands/machine.rb +24 -0
  29. data/lib/smart_machine/commands/syncer.rb +23 -0
  30. data/lib/smart_machine/commands/utilities.rb +37 -0
  31. data/lib/smart_machine/commands.rb +66 -0
  32. data/lib/smart_machine/configuration.rb +79 -0
  33. data/lib/smart_machine/credentials.rb +93 -95
  34. data/lib/smart_machine/docker.rb +144 -143
  35. data/lib/smart_machine/engine/Dockerfile +7 -5
  36. data/lib/smart_machine/engine.rb +104 -79
  37. data/lib/smart_machine/grids/elasticsearch.rb +70 -89
  38. data/lib/smart_machine/grids/minio.rb +79 -68
  39. data/lib/smart_machine/grids/mysql.rb +207 -202
  40. data/lib/smart_machine/grids/nginx.rb +176 -135
  41. data/lib/smart_machine/grids/prereceiver/Dockerfile +2 -2
  42. data/lib/smart_machine/grids/prereceiver/pre-receive +17 -0
  43. data/lib/smart_machine/grids/prereceiver.rb +169 -169
  44. data/lib/smart_machine/grids/redis.rb +73 -57
  45. data/lib/smart_machine/logger.rb +26 -26
  46. data/lib/smart_machine/machine.rb +128 -194
  47. data/lib/smart_machine/scp.rb +15 -0
  48. data/lib/smart_machine/ssh.rb +69 -40
  49. data/lib/smart_machine/syncer.rb +133 -0
  50. data/lib/smart_machine/templates/dotsmartmachine/Gemfile +7 -0
  51. data/lib/smart_machine/templates/dotsmartmachine/config/elasticsearch.yml +5 -0
  52. data/lib/smart_machine/templates/dotsmartmachine/config/environment.rb +0 -9
  53. data/lib/smart_machine/templates/dotsmartmachine/config/minio.yml +13 -0
  54. data/lib/smart_machine/templates/dotsmartmachine/config/mysql/schedule.rb +3 -3
  55. data/lib/smart_machine/templates/dotsmartmachine/config/mysql.yml +13 -0
  56. data/lib/smart_machine/templates/dotsmartmachine/config/prereceiver.yml +7 -0
  57. data/lib/smart_machine/templates/dotsmartmachine/config/redis.yml +13 -0
  58. data/lib/smart_machine/templates/dotsmartmachine/config/users.yml +1 -1
  59. data/lib/smart_machine/templates/dotsmartmachine/gitignore-template +47 -0
  60. data/lib/smart_machine/templates/dotsmartmachine/{grids/elasticsearch/data → vendor}/.keep +0 -0
  61. data/lib/smart_machine/version.rb +30 -6
  62. data/lib/smart_machine.rb +42 -16
  63. metadata +97 -47
  64. data/CHANGELOG.rdoc +0 -0
  65. data/MIT-LICENSE +0 -21
  66. data/README.rdoc +0 -87
  67. data/bin/buildpacker +0 -8
  68. data/bin/prereceiver +0 -8
  69. data/bin/scheduler +0 -18
  70. data/bin/smartmachine +0 -81
  71. data/bin/smartrunner +0 -33
  72. data/lib/smart_machine/apps/rails.rb +0 -250
  73. data/lib/smart_machine/apps.rb +0 -14
  74. data/lib/smart_machine/boot.rb +0 -32
  75. data/lib/smart_machine/buildpacker.rb +0 -106
  76. data/lib/smart_machine/gem_version.rb +0 -17
  77. data/lib/smart_machine/grids.rb +0 -18
  78. data/lib/smart_machine/sync.rb +0 -120
  79. data/lib/smart_machine/templates/dotsmartmachine/grids/elasticsearch/logs/.keep +0 -0
  80. data/lib/smart_machine/templates/dotsmartmachine/grids/minio/data/.keep +0 -0
  81. data/lib/smart_machine/templates/dotsmartmachine/grids/mysql/backups/.keep +0 -0
  82. data/lib/smart_machine/templates/dotsmartmachine/grids/mysql/data/.keep +0 -0
  83. data/lib/smart_machine/templates/dotsmartmachine/grids/prereceiver/pre-receive +0 -17
  84. data/lib/smart_machine/templates/dotsmartmachine/grids/redis/data/.keep +0 -0
  85. data/lib/smart_machine/user.rb +0 -38
@@ -0,0 +1,182 @@
1
+ module SmartMachine
2
+ module Apps
3
+ class Manager < SmartMachine::Base
4
+ attr_accessor :appname, :appversion
5
+
6
+ def initialize(appname:, appversion: nil)
7
+ @appname = appname
8
+ @appversion = appversion
9
+
10
+ @home_dir = File.expand_path('~')
11
+ @container_path = "#{@home_dir}/machine/apps/containers/#{@appname}"
12
+
13
+ # Checking if given appname exists
14
+ repository_path = "#{@home_dir}/machine/apps/repositories/#{@appname}.git"
15
+ raise "App with name '#{@appname}' does not exist. Please provide a valid appname." unless Dir.exist?(repository_path)
16
+ end
17
+
18
+ def deploy
19
+ logger.formatter = proc do |severity, datetime, progname, message|
20
+ severity_text = { "DEBUG" => "\u{1f527} #{severity}:", "INFO" => " \u{276f}", "WARN" => "\u{2757} #{severity}:",
21
+ "ERROR" => "\u{274c} #{severity}:", "FATAL" => "\u{2b55} #{severity}:", "UNKNOWN" => "\u{2753} #{severity}:"
22
+ }
23
+ "\t\t\t\t#{severity_text[severity]} #{message}\n"
24
+ end
25
+
26
+ Dir.chdir("#{@container_path}/releases") do
27
+ # Setting app version to latest if not set.
28
+ unless @appversion
29
+ versions = Dir.glob('*').select { |f| File.directory? f }.sort
30
+ @appversion = versions.last
31
+ end
32
+
33
+ buildpacker = SmartMachine::Buildpackers::Rails.new(appname: @appname, appversion: @appversion)
34
+ if buildpacker.package
35
+ if release
36
+ sleep 7
37
+ clean
38
+ logger.info "Launched Application ... Success."
39
+ exit 10
40
+ else
41
+ raise "Error: Could not release the application."
42
+ end
43
+ else
44
+ raise "Error: Could not package the application."
45
+ end
46
+ end
47
+
48
+ logger.formatter = nil
49
+ end
50
+
51
+ def ps_scaler(formation:)
52
+ Dir.chdir("#{@container_path}/releases") do
53
+ # Setting app version to latest if not set.
54
+ unless @appversion
55
+ versions = Dir.glob('*').select { |f| File.directory? f }.sort
56
+ @appversion = versions.last
57
+ end
58
+
59
+ formation.each do |proc_name, final_count|
60
+ config = processes.dig(proc_name.to_sym)
61
+ raise "no config found for the #{proc_name} process." unless config.present?
62
+
63
+ current_count = `docker ps -aq --filter name="#{@appname}-#{@appversion}-#{proc_name}-" | wc -l`
64
+
65
+ final_count = final_count.to_i
66
+ current_count = current_count.to_i
67
+
68
+ if final_count > current_count
69
+ ((current_count + 1)..final_count).each do |index|
70
+ containerize_process!(name: "#{@appname}-#{@appversion}-#{proc_name}-#{index}", config: config)
71
+ end
72
+ elsif final_count < current_count
73
+ ((final_count + 1)..current_count).each do |index|
74
+ container = SmartMachine::Apps::Container.new(name: "#{@appname}-#{@appversion}-#{proc_name}-#{index}", appname: @appname, appversion: @appversion)
75
+ container.stop!
76
+ end
77
+ else
78
+ # No Operation. Don't do anything.
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def env_vars
85
+ @env_vars ||= load_env_vars
86
+ end
87
+
88
+ private
89
+
90
+ def release
91
+ logger.info "Releasing Application ..."
92
+
93
+ if processes.present?
94
+ processes.each do |name, config|
95
+ containerize_process!(name: "#{@appname}-#{@appversion}-#{name}-1", config: config)
96
+ end
97
+ else
98
+ logger.fatal "No smartmachine.yml file found. Proceeding with default settings."
99
+ return false
100
+
101
+ # Use the below code when you want to provide a default when smartmachine.yml is not present.
102
+ # containerize_process!(name: "#{@appname}-#{@appversion}-web-1", config: { command: "bundle exec puma --config config/puma.rb", networks: "nginx-network" })
103
+ end
104
+ end
105
+
106
+ def containerize_process!(name:, config:)
107
+ container = SmartMachine::Apps::Container.new(name: name, appname: @appname, appversion: @appversion)
108
+ if container.create!(using_command: config.dig(:command))
109
+ networks = config.dig(:networks)&.split(" ")
110
+ networks.each do |network|
111
+ container.connect_to_network!(network_name: network)
112
+ end
113
+
114
+ unless container.start!
115
+ container.stop!
116
+ end
117
+ else
118
+ container.stop!
119
+ end
120
+ end
121
+
122
+ def clean
123
+ return unless env_vars.present?
124
+
125
+ logger.info "Cleaning up ..."
126
+
127
+ # Clean up very old versions
128
+ Dir.chdir("#{@container_path}/releases") do
129
+ versions = Dir.glob('*').select { |f| File.directory? f }.sort
130
+ destroy_count = versions.count - env_vars['KEEP_RELEASES'].to_i
131
+ if destroy_count > 0
132
+ logger.debug "Deleting older application releases ..."
133
+ destroy_count.times do
134
+ version = versions.shift
135
+ FileUtils.rm_r(File.join(Dir.pwd, version))
136
+
137
+ # Remove corresponding docker containers & images, if they exist.
138
+ system("docker ps -aq --filter ancestor=smartmachine/apps/#{@appname}:#{version} | xargs --no-run-if-empty docker stop | xargs --no-run-if-empty docker rm", out: File::NULL)
139
+ system("docker image ls -aq --filter reference=smartmachine/apps/#{@appname}:#{version} | xargs --no-run-if-empty docker image rm", out: File::NULL)
140
+ end
141
+ end
142
+
143
+ versions = Dir.glob('*').select { |f| File.directory? f }.sort
144
+ versions_count = versions.count
145
+ if versions_count > 0
146
+ versions_count.times do
147
+ version = versions.shift
148
+ unless version == @appversion
149
+ system("docker ps -aq --filter ancestor=smartmachine/apps/#{@appname}:#{version} | xargs --no-run-if-empty docker stop", out: File::NULL)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ def load_env_vars
157
+ unless File.exist? "#{@container_path}/env"
158
+ logger.fatal "Environment could not be loaded ... Failed."
159
+ return false
160
+ end
161
+
162
+ env_vars = {}
163
+ File.open("#{@container_path}/env").each_line do |line|
164
+ line.chomp!
165
+ next if line.empty? || line.start_with?('#')
166
+ key, value = line.split "="
167
+ env_vars[key] = value
168
+ end
169
+
170
+ env_vars
171
+ end
172
+
173
+ def processes
174
+ @processes ||= deserialize(IO.binread("#{@appversion}/smartmachine.yml")).deep_symbolize_keys
175
+ end
176
+
177
+ def deserialize(config)
178
+ YAML.load(ERB.new(config).result).presence || {}
179
+ end
180
+ end
181
+ end
182
+ end
@@ -2,10 +2,28 @@ require 'smart_machine/logger'
2
2
  require "active_support/inflector"
3
3
 
4
4
  module SmartMachine
5
- class Base
6
- include SmartMachine::Logger
5
+ class Base
6
+ include SmartMachine::Logger
7
7
 
8
- def initialize
9
- end
10
- end
11
- end
8
+ def initialize
9
+ end
10
+
11
+ def platform_on_machine?(os:, distro_name: nil)
12
+ case os
13
+ when "linux"
14
+ command = "(uname | grep -q 'Linux')"
15
+ command += " && (cat /etc/os-release | grep -q 'NAME=\"Debian GNU/Linux\"')" if distro_name == "debian"
16
+ when "mac"
17
+ command = "(uname | grep -q 'Darwin')"
18
+ end
19
+
20
+ machine = SmartMachine::Machine.new
21
+ command ? machine.run_on_machine(commands: command) : false
22
+ end
23
+
24
+ def machine_has_engine_installed?
25
+ machine = SmartMachine::Machine.new
26
+ machine.run_on_machine(commands: ["which smartengine | grep -q '/smartengine'"])
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,95 @@
1
+ module SmartMachine
2
+ module Buildpackers
3
+ class Buildpacker < SmartMachine::Base
4
+ def initialize(packname:)
5
+ @packname = packname
6
+ end
7
+
8
+ def installer
9
+ if @packname == "rails"
10
+ unless system("docker image inspect #{rails_image_name}", [:out, :err] => File::NULL)
11
+ print "-----> Creating image #{rails_image_name} ... "
12
+ command = [
13
+ "docker image build -t #{rails_image_name}",
14
+ "--build-arg SMARTMACHINE_VERSION=#{SmartMachine.version}",
15
+ "--build-arg USER_UID=`id -u`",
16
+ "--build-arg USER_NAME=`id -un`",
17
+ "#{SmartMachine.config.gem_dir}/lib/smart_machine/buildpackers/rails"
18
+ ]
19
+ if system(command.join(" "), out: File::NULL)
20
+ puts "done"
21
+ end
22
+ end
23
+ else
24
+ raise "Error: Pack with name #{name} not supported."
25
+ end
26
+ end
27
+
28
+ def uninstaller
29
+ if @packname == "rails"
30
+ if system("docker image inspect #{rails_image_name}", [:out, :err] => File::NULL)
31
+ print "-----> Removing image #{rails_image_name} ... "
32
+ if system("docker image rm #{rails_image_name}", out: File::NULL)
33
+ puts "done"
34
+ end
35
+ end
36
+ else
37
+ raise "Error: Pack with name #{name} not supported."
38
+ end
39
+ end
40
+
41
+ def packer
42
+ if @packname == "rails" && File.exist?("bin/rails")
43
+ rails = SmartMachine::Buildpackers::Rails.new(appname: nil, appversion: nil)
44
+ rails.packer
45
+ else
46
+ raise "Error: Pack with name #{@packname} not supported."
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def rails_image_name
53
+ "smartmachine/buildpackers/rails:#{SmartMachine.version}"
54
+ end
55
+
56
+ # These swapfile methods can be used (after required modification), when you need to make swapfile for more memory.
57
+ # def self.create_swapfile
58
+ # # Creating swapfile for bundler to work properly
59
+ # unless system("sudo swapon -s | grep -ci '/swapfile'", out: File::NULL)
60
+ # print "-----> Creating swap swapfile ... "
61
+ # system("sudo install -o root -g root -m 0600 /dev/null /swapfile", out: File::NULL)
62
+ # system("sudo dd if=/dev/zero of=/swapfile bs=1k count=2048k", [:out, :err] => File::NULL)
63
+ # system("sudo mkswap /swapfile", out: File::NULL)
64
+ # system("sudo sh -c 'echo \"/swapfile none swap sw 0 0\" >> /etc/fstab'", out: File::NULL)
65
+ # system("echo 10 | sudo tee /proc/sys/vm/swappiness", out: File::NULL)
66
+ # system("sudo sed -i '/^vm.swappiness = /d' /etc/sysctl.conf", out: File::NULL)
67
+ # system("echo vm.swappiness = 10 | sudo tee -a /etc/sysctl.conf", out: File::NULL)
68
+ # puts "done"
69
+ #
70
+ # print "-----> Starting swap swapfile ... "
71
+ # if system("sudo swapon /swapfile", out: File::NULL)
72
+ # puts "done"
73
+ # end
74
+ # end
75
+ # end
76
+ #
77
+ # def self.destroy_swapfile
78
+ # if system("sudo swapon -s | grep -ci '/swapfile'", out: File::NULL)
79
+ # print "-----> Stopping swap swapfile ... "
80
+ # if system("sudo swapoff /swapfile", out: File::NULL)
81
+ # system("sudo sed -i '/^vm.swappiness = /d' /etc/sysctl.conf", out: File::NULL)
82
+ # system("echo 60 | sudo tee /proc/sys/vm/swappiness", out: File::NULL)
83
+ # puts "done"
84
+ #
85
+ # print "-----> Removing swap swapfile ... "
86
+ # system("sudo sed -i '/^\\/swapfile/d' /etc/fstab", out: File::NULL)
87
+ # if system("sudo rm /swapfile", out: File::NULL)
88
+ # puts "done"
89
+ # end
90
+ # end
91
+ # end
92
+ # end
93
+ end
94
+ end
95
+ end
@@ -1,7 +1,7 @@
1
1
  ARG SMARTMACHINE_VERSION
2
2
 
3
- FROM smartmachine:$SMARTMACHINE_VERSION
4
- LABEL maintainer="Timeboard <hello@timeboard.me>"
3
+ FROM smartmachine/smartengine:$SMARTMACHINE_VERSION
4
+ LABEL maintainer="Gaurav Goel <gaurav@timeboard.me>"
5
5
 
6
6
  # Ruby on Rails Essentials
7
7
  RUN apk add --update build-base && \
@@ -18,4 +18,4 @@ RUN apk add --update build-base && \
18
18
  # Gems
19
19
  RUN gem install bundler -v 2.1.4
20
20
 
21
- CMD ["buildpacker", "pack"]
21
+ CMD ["smartmachine", "buildpacker", "packer", "rails"]
@@ -0,0 +1,221 @@
1
+ require 'open3'
2
+
3
+ module SmartMachine
4
+ module Buildpackers
5
+ class Rails < SmartMachine::Base
6
+ def initialize(appname:, appversion:)
7
+ @home_dir = File.expand_path('~')
8
+ @appname = appname
9
+ @appversion = appversion
10
+ @container_path = "#{@home_dir}/machine/apps/containers/#{@appname}"
11
+ end
12
+
13
+ def package
14
+ return unless File.exist? "#{@container_path}/releases/#{@appversion}/bin/rails"
15
+
16
+ logger.formatter = proc do |severity, datetime, progname, message|
17
+ severity_text = { "DEBUG" => "\u{1f527} #{severity}:", "INFO" => " \u{276f}", "WARN" => "\u{2757} #{severity}:",
18
+ "ERROR" => "\u{274c} #{severity}:", "FATAL" => "\u{2b55} #{severity}:", "UNKNOWN" => "\u{2753} #{severity}:"
19
+ }
20
+ "\t\t\t\t#{severity_text[severity]} #{message}\n"
21
+ end
22
+
23
+ logger.info "Ruby on Rails application detected."
24
+ logger.info "Packaging Application ..."
25
+
26
+ # Setup rails env
27
+ env_path = "#{@container_path}/env"
28
+ system("grep -q '^## Rails' #{env_path} || echo '## Rails' >> #{env_path}")
29
+ system("grep -q '^MALLOC_ARENA_MAX=' #{env_path} || echo '# MALLOC_ARENA_MAX=2' >> #{env_path}")
30
+ system("grep -q '^RAILS_ENV=' #{env_path} || echo 'RAILS_ENV=production' >> #{env_path}")
31
+ system("grep -q '^RACK_ENV=' #{env_path} || echo 'RACK_ENV=production' >> #{env_path}")
32
+ system("grep -q '^RAILS_LOG_TO_STDOUT=' #{env_path} || echo 'RAILS_LOG_TO_STDOUT=enabled' >> #{env_path}")
33
+ system("grep -q '^RAILS_SERVE_STATIC_FILES=' #{env_path} || echo 'RAILS_SERVE_STATIC_FILES=enabled' >> #{env_path}")
34
+ system("grep -q '^LANG=' #{env_path} || echo 'LANG=en_US.UTF-8' >> #{env_path}")
35
+ system("grep -q '^RAILS_MASTER_KEY=' #{env_path} || echo 'RAILS_MASTER_KEY=yourmasterkey' >> #{env_path}")
36
+ logger.warn "Please set your RAILS_MASTER_KEY env var for this rails app." if system("grep -q '^RAILS_MASTER_KEY=yourmasterkey' #{env_path}")
37
+
38
+ # Setup app folders needed for volumes. If this is not created then docker will create it while running the container,
39
+ # but the folder will have root user assigned instead of the current user.
40
+ FileUtils.mkdir_p("#{@container_path}/app/vendor/bundle")
41
+ FileUtils.mkdir_p("#{@container_path}/app/public/assets")
42
+ FileUtils.mkdir_p("#{@container_path}/app/public/packs")
43
+ FileUtils.mkdir_p("#{@container_path}/app/node_modules")
44
+ FileUtils.mkdir_p("#{@container_path}/app/storage")
45
+ FileUtils.mkdir_p("#{@container_path}/releases/#{@appversion}/vendor/bundle")
46
+ FileUtils.mkdir_p("#{@container_path}/releases/#{@appversion}/public/assets")
47
+ FileUtils.mkdir_p("#{@container_path}/releases/#{@appversion}/public/packs")
48
+ FileUtils.mkdir_p("#{@container_path}/releases/#{@appversion}/node_modules")
49
+ FileUtils.mkdir_p("#{@container_path}/releases/#{@appversion}/storage")
50
+
51
+ # Creating a valid docker app image.
52
+ container = SmartMachine::Apps::Container.new(name: "#{@appname}-#{@appversion}-packed", appname: @appname, appversion: @appversion)
53
+ if container.commit_app_image!
54
+ logger.formatter = nil
55
+ return true
56
+ end
57
+
58
+ logger.formatter = nil
59
+ return false
60
+ end
61
+
62
+ def packer
63
+ set_logger_formatter_arrow
64
+
65
+ if File.exist? "tmp/smartmachine/packed"
66
+ begin
67
+ pid = File.read('tmp/smartmachine/packed').to_i
68
+ Process.kill('QUIT', pid)
69
+ rescue Errno::ESRCH # No such process
70
+ end
71
+ exec "bundle", "exec", "puma", "--config", "config/puma.rb"
72
+ else
73
+ if initial_setup? && bundle_install? && precompile_assets? && db_migrate? && test_web_server?
74
+ logger.formatter = nil
75
+
76
+ exit 0
77
+ else
78
+ logger.error "Could not continue ... Launch Failed."
79
+ logger.formatter = nil
80
+
81
+ exit 1
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ # Perform initial_setup
89
+ def initial_setup?
90
+ logger.info "Performing initial setup ..."
91
+
92
+ exit_status = nil
93
+
94
+ # Fix for mysql2 gem to support sha256_password, until it is fixed in main mysql2 gem.
95
+ # https://github.com/brianmario/mysql2/issues/1023
96
+ exit_status = system("mkdir -p ./lib/mariadb && ln -s /usr/lib/mariadb/plugin ./lib/mariadb/plugin")
97
+
98
+ if exit_status
99
+ return true
100
+ else
101
+ logger.error "Could not complete initial setup."
102
+ return false
103
+ end
104
+ end
105
+
106
+ # Perform bundle install
107
+ def bundle_install?
108
+ logger.info "Performing bundle install ..."
109
+
110
+ set_logger_formatter_tabs
111
+
112
+ unless system("bundle config set deployment 'true' && bundle config set clean 'true'")
113
+ logger.error "Could not complete bundle config setting."
114
+ return false
115
+ end
116
+
117
+ exit_status = nil
118
+ Open3.popen2e("bundle", "install") do |stdin, stdout_and_stderr, wait_thr|
119
+ stdout_and_stderr.each { |line| logger.info "#{line}" }
120
+ exit_status = wait_thr.value.success?
121
+ end
122
+ set_logger_formatter_arrow
123
+
124
+ if exit_status
125
+ return true
126
+ else
127
+ logger.error "Could not complete bundle install."
128
+ return false
129
+ end
130
+ end
131
+
132
+ # Perform pre-compiling of assets
133
+ def precompile_assets?
134
+ logger.info "Installing Javascript dependencies & pre-compiling assets ..."
135
+
136
+ set_logger_formatter_tabs
137
+ exit_status = nil
138
+ Open3.popen2e("bundle", "exec", "rails", "assets:precompile") do |stdin, stdout_and_stderr, wait_thr|
139
+ stdout_and_stderr.each { |line| logger.info "#{line}" }
140
+ exit_status = wait_thr.value.success?
141
+ end
142
+ set_logger_formatter_arrow
143
+
144
+ if exit_status
145
+ return true
146
+ else
147
+ logger.error "Could not install Javascript dependencies or pre-compile assets."
148
+ return false
149
+ end
150
+ end
151
+
152
+ # Perform db_migrate
153
+ def db_migrate?
154
+ return true # remove this line when you want to start using db_migrate?
155
+
156
+ logger.info "Performing database migrations ..."
157
+
158
+ set_logger_formatter_tabs
159
+ exit_status = nil
160
+ Open3.popen2e("bundle", "exec", "rails", "db:migrate") do |stdin, stdout_and_stderr, wait_thr|
161
+ stdout_and_stderr.each { |line| logger.info "#{line}" }
162
+ exit_status = wait_thr.value.success?
163
+ end
164
+ set_logger_formatter_arrow
165
+
166
+ if exit_status
167
+ return true
168
+ else
169
+ logger.error "Could not complete database migrations."
170
+ return false
171
+ end
172
+ end
173
+
174
+ # Perform testing of web server
175
+ def test_web_server?
176
+ logger.info "Setting up Web Server ..."
177
+
178
+ # tmp folders
179
+ FileUtils.mkdir_p("tmp/pids")
180
+ FileUtils.mkdir_p("tmp/smartmachine")
181
+ FileUtils.rm_f("tmp/smartmachine/packed")
182
+
183
+ # Spawn Process
184
+ pid = Process.spawn("bundle", "exec", "puma", "--config", "config/puma.rb", out: File::NULL)
185
+ Process.detach(pid)
186
+
187
+ # Sleep
188
+ sleep 5
189
+
190
+ # Check PID running
191
+ status = nil
192
+ begin
193
+ Process.kill(0, pid)
194
+ system("echo '#{pid}' > tmp/smartmachine/packed")
195
+ status = true
196
+ rescue Errno::ESRCH # No such process
197
+ logger.info "Web Server could not start"
198
+ status = false
199
+ end
200
+
201
+ # Return status
202
+ return status
203
+ end
204
+
205
+ def set_logger_formatter_arrow
206
+ logger.formatter = proc do |severity, datetime, progname, message|
207
+ severity_text = { "DEBUG" => "\u{1f527} #{severity}:", "INFO" => " \u{276f}", "WARN" => "\u{2757} #{severity}:",
208
+ "ERROR" => "\u{274c} #{severity}:", "FATAL" => "\u{2b55} #{severity}:", "UNKNOWN" => "\u{2753} #{severity}:"
209
+ }
210
+ "\t\t\t\t#{severity_text[severity]} #{message}\n"
211
+ end
212
+ end
213
+
214
+ def set_logger_formatter_tabs
215
+ logger.formatter = proc do |severity, datetime, progname, message|
216
+ "\t\t\t\t #{message}"
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,112 @@
1
+ module SmartMachine
2
+ module Commands
3
+ class App < Thor
4
+ include Utilities
5
+
6
+ desc "create [APPNAME] [APPDOMAIN] [USERNAME]", "Create an App"
7
+ def create(appname, appdomain, username)
8
+ inside_machine_dir do
9
+ with_docker_running do
10
+ machine = SmartMachine::Machine.new
11
+ machine.run_on_machine commands: "smartengine app creater #{appname} #{appdomain} #{username}"
12
+ end
13
+ end
14
+ end
15
+
16
+ desc "destroy [APPNAME]", "Destroy an App"
17
+ def destroy(appname)
18
+ inside_machine_dir do
19
+ with_docker_running do
20
+ machine = SmartMachine::Machine.new
21
+ machine.run_on_machine commands: "smartengine app destroyer #{appname}"
22
+ end
23
+ end
24
+ end
25
+
26
+ desc "ps:scale [APPNAME]", "Scale the app processes"
27
+ map "ps:scale" => "ps_scale"
28
+ option :formation, type: :hash, required: true
29
+ option :version, type: :numeric, default: nil
30
+ def ps_scale(appname)
31
+ inside_machine_dir do
32
+ with_docker_running do
33
+ machine = SmartMachine::Machine.new
34
+ command = [
35
+ "smartengine app ps:scaler #{appname}"
36
+ ]
37
+ formation = options[:formation].map { |proctype, count| "#{proctype}:#{count}" }.join(' ')
38
+ command.push("--formation=#{formation}") if options[:formation]
39
+ command.push("--version=#{options[:version]}") if options[:version]
40
+ machine.run_on_machine commands: command.join(" ")
41
+ end
42
+ end
43
+ end
44
+
45
+ desc "up [APPNAME]", "Take UP the app"
46
+ option :version, type: :numeric, default: 0
47
+ def up(appname)
48
+ inside_machine_dir do
49
+ with_docker_running do
50
+ machine = SmartMachine::Machine.new
51
+ machine.run_on_machine commands: "smartengine app uper #{appname} --version=#{options[:version]}"
52
+ end
53
+ end
54
+ end
55
+
56
+ desc "down [APPNAME]", "Take DOWN the app"
57
+ def down(appname)
58
+ inside_machine_dir do
59
+ with_docker_running do
60
+ machine = SmartMachine::Machine.new
61
+ machine.run_on_machine commands: "smartengine app downer #{appname}"
62
+ end
63
+ end
64
+ end
65
+
66
+ desc "creater", "App creator", hide: true
67
+ def creater(appname, appdomain, username)
68
+ inside_engine_machine_dir do
69
+ app = SmartMachine::Apps::App.new(appname: appname, username: username)
70
+ prereceiver_name, prereceiver_config = SmartMachine.config.grids.prereceiver.first
71
+ app.creater(appdomain: appdomain, prereceiver_name: prereceiver_name)
72
+ end
73
+ end
74
+
75
+ desc "destroyer", "App destroyer", hide: true
76
+ def destroyer(appname)
77
+ inside_engine_machine_dir do
78
+ app = SmartMachine::Apps::App.new(appname: appname)
79
+ app.destroyer
80
+ end
81
+ end
82
+
83
+ desc "ps:scaler [APPNAME]", "Scale the app processes", hide: true
84
+ map "ps:scaler" => "ps_scaler"
85
+ option :formation, type: :hash, required: true
86
+ option :version, type: :numeric, default: nil
87
+ def ps_scaler(appname)
88
+ inside_engine_machine_dir do
89
+ manager = SmartMachine::Apps::Manager.new(appname: appname, appversion: options[:version])
90
+ manager.ps_scaler(formation: options[:formation])
91
+ end
92
+ end
93
+
94
+ desc "uper [APPNAME]", "App uper", hide: true
95
+ option :version, type: :numeric, default: 0
96
+ def uper(appname)
97
+ inside_engine_machine_dir do
98
+ app = SmartMachine::Apps::App.new(appname: appname)
99
+ app.uper(version: options[:version])
100
+ end
101
+ end
102
+
103
+ desc "downer [APPNAME]", "App downer", hide: true
104
+ def downer(appname)
105
+ inside_engine_machine_dir do
106
+ app = SmartMachine::Apps::App.new(appname: appname)
107
+ app.downer
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end