smartmachine 0.8.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +661 -0
- data/README.md +147 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/smartmachine +3 -0
- data/lib/smart_machine/apps/app.rb +165 -181
- data/lib/smart_machine/apps/container.rb +120 -0
- data/lib/smart_machine/apps/manager.rb +182 -0
- data/lib/smart_machine/base.rb +24 -6
- data/lib/smart_machine/buildpackers/buildpacker.rb +95 -0
- data/lib/smart_machine/{engine/buildpacks → buildpackers}/rails/Dockerfile +3 -3
- data/lib/smart_machine/buildpackers/rails.rb +221 -0
- data/lib/smart_machine/commands/app.rb +112 -0
- data/lib/smart_machine/commands/buildpacker.rb +53 -0
- data/lib/smart_machine/commands/credentials.rb +17 -0
- data/lib/smart_machine/commands/docker.rb +23 -0
- data/lib/smart_machine/commands/engine.rb +27 -0
- data/lib/smart_machine/commands/grid.rb +33 -0
- data/lib/smart_machine/commands/grid_commands/elasticsearch.rb +68 -0
- data/lib/smart_machine/commands/grid_commands/minio.rb +65 -0
- data/lib/smart_machine/commands/grid_commands/mysql.rb +71 -0
- data/lib/smart_machine/commands/grid_commands/nginx.rb +53 -0
- data/lib/smart_machine/commands/grid_commands/prereceiver.rb +96 -0
- data/lib/smart_machine/commands/grid_commands/redis.rb +65 -0
- data/lib/smart_machine/commands/grid_commands/scheduler.rb +15 -0
- data/lib/smart_machine/commands/grid_commands/sub_thor.rb +15 -0
- data/lib/smart_machine/commands/machine.rb +24 -0
- data/lib/smart_machine/commands/syncer.rb +23 -0
- data/lib/smart_machine/commands/utilities.rb +37 -0
- data/lib/smart_machine/commands.rb +66 -0
- data/lib/smart_machine/configuration.rb +79 -0
- data/lib/smart_machine/credentials.rb +93 -95
- data/lib/smart_machine/docker.rb +144 -143
- data/lib/smart_machine/engine/Dockerfile +7 -5
- data/lib/smart_machine/engine.rb +104 -79
- data/lib/smart_machine/grids/elasticsearch.rb +70 -89
- data/lib/smart_machine/grids/minio.rb +79 -68
- data/lib/smart_machine/grids/mysql.rb +207 -202
- data/lib/smart_machine/grids/nginx.rb +176 -135
- data/lib/smart_machine/grids/prereceiver/Dockerfile +2 -2
- data/lib/smart_machine/grids/prereceiver/pre-receive +17 -0
- data/lib/smart_machine/grids/prereceiver.rb +169 -169
- data/lib/smart_machine/grids/redis.rb +75 -57
- data/lib/smart_machine/grids/scheduler/Dockerfile +1 -1
- data/lib/smart_machine/logger.rb +26 -26
- data/lib/smart_machine/machine.rb +128 -194
- data/lib/smart_machine/scp.rb +15 -0
- data/lib/smart_machine/ssh.rb +69 -40
- data/lib/smart_machine/syncer.rb +133 -0
- data/lib/smart_machine/templates/dotsmartmachine/Gemfile +7 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/elasticsearch.yml +5 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/environment.rb +0 -9
- data/lib/smart_machine/templates/dotsmartmachine/config/minio.yml +13 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/mysql/schedule.rb +3 -3
- data/lib/smart_machine/templates/dotsmartmachine/config/mysql.yml +13 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/prereceiver.yml +7 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/redis.yml +15 -0
- data/lib/smart_machine/templates/dotsmartmachine/config/users.yml +1 -1
- data/lib/smart_machine/templates/dotsmartmachine/gitignore-template +47 -0
- data/lib/smart_machine/templates/dotsmartmachine/{grids/elasticsearch/data → vendor}/.keep +0 -0
- data/lib/smart_machine/version.rb +30 -6
- data/lib/smart_machine.rb +42 -16
- metadata +97 -47
- data/CHANGELOG.rdoc +0 -0
- data/MIT-LICENSE +0 -21
- data/README.rdoc +0 -87
- data/bin/buildpacker +0 -8
- data/bin/prereceiver +0 -8
- data/bin/scheduler +0 -18
- data/bin/smartmachine +0 -81
- data/bin/smartrunner +0 -33
- data/lib/smart_machine/apps/rails.rb +0 -250
- data/lib/smart_machine/apps.rb +0 -14
- data/lib/smart_machine/boot.rb +0 -32
- data/lib/smart_machine/buildpacker.rb +0 -106
- data/lib/smart_machine/gem_version.rb +0 -17
- data/lib/smart_machine/grids.rb +0 -18
- data/lib/smart_machine/sync.rb +0 -120
- data/lib/smart_machine/templates/dotsmartmachine/grids/elasticsearch/logs/.keep +0 -0
- data/lib/smart_machine/templates/dotsmartmachine/grids/minio/data/.keep +0 -0
- data/lib/smart_machine/templates/dotsmartmachine/grids/mysql/backups/.keep +0 -0
- data/lib/smart_machine/templates/dotsmartmachine/grids/mysql/data/.keep +0 -0
- data/lib/smart_machine/templates/dotsmartmachine/grids/prereceiver/pre-receive +0 -17
- data/lib/smart_machine/templates/dotsmartmachine/grids/redis/data/.keep +0 -0
- 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
|
data/lib/smart_machine/base.rb
CHANGED
@@ -2,10 +2,28 @@ require 'smart_machine/logger'
|
|
2
2
|
require "active_support/inflector"
|
3
3
|
|
4
4
|
module SmartMachine
|
5
|
-
|
6
|
-
|
5
|
+
class Base
|
6
|
+
include SmartMachine::Logger
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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="
|
3
|
+
FROM smartmachine/smartengine:$SMARTMACHINE_VERSION
|
4
|
+
LABEL maintainer="plainsource <plainsource@humanmind.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", "
|
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
|