class SmartCloud::Apps::Rails

Public Class Methods

new() click to toggle source
# File lib/smart_cloud/apps/rails.rb, line 5
def initialize
end

Public Instance Methods

pack() click to toggle source
# File lib/smart_cloud/apps/rails.rb, line 91
def pack
        set_logger_formatter_arrow

        if File.exist? "tmp/smartcloud/packed"
                begin
                        pid = File.read('tmp/smartcloud/packed').to_i
                        Process.kill('QUIT', pid)
                rescue Errno::ESRCH # No such process
                end
                exec "bundle", "exec", "puma", "--config", "config/puma.rb"
        else
                if initial_setup? && bundle_install? && precompile_assets? && db_migrate? && test_web_server?
                        logger.formatter = nil

                        exit 0
                else
                        logger.error "Could not continue ... Launch Failed."
                        logger.formatter = nil

                        exit 1
                end
        end
end
start(appname, container_path, container_path_with_version) click to toggle source
# File lib/smart_cloud/apps/rails.rb, line 8
def start(appname, container_path, container_path_with_version)
        return unless File.exist? "#{container_path_with_version}/bin/rails"

        logger.formatter = proc do |severity, datetime, progname, message|
                severity_text = { "DEBUG" => "\u{1f527} #{severity}:", "INFO" => " \u{276f}", "WARN" => "\u{2757} #{severity}:",
                        "ERROR" => "\u{274c} #{severity}:", "FATAL" => "\u{2b55} #{severity}:", "UNKNOWN" => "\u{2753} #{severity}:"
                }
                "\t\t\t\t#{severity_text[severity]} #{message}\n"
        end

        logger.info "Ruby on Rails application detected."

        # Setup rails env
        env_path = "#{container_path}/env"
        system("grep -q '^## Rails' #{env_path} || echo '## Rails' >> #{env_path}")
        system("grep -q '^MALLOC_ARENA_MAX=' #{env_path} || echo '# MALLOC_ARENA_MAX=2' >> #{env_path}")
        system("grep -q '^RAILS_ENV=' #{env_path} || echo 'RAILS_ENV=production' >> #{env_path}")
        system("grep -q '^RACK_ENV=' #{env_path} || echo 'RACK_ENV=production' >> #{env_path}")
        system("grep -q '^RAILS_LOG_TO_STDOUT=' #{env_path} || echo 'RAILS_LOG_TO_STDOUT=enabled' >> #{env_path}")
        system("grep -q '^RAILS_SERVE_STATIC_FILES=' #{env_path} || echo 'RAILS_SERVE_STATIC_FILES=enabled' >> #{env_path}")
        system("grep -q '^LANG=' #{env_path} || echo 'LANG=en_US.UTF-8' >> #{env_path}")
        system("grep -q '^RAILS_MASTER_KEY=' #{env_path} || echo 'RAILS_MASTER_KEY=yourmasterkey' >> #{env_path}")
        logger.warn "Please set your RAILS_MASTER_KEY env var for this rails app." if system("grep -q '^RAILS_MASTER_KEY=yourmasterkey' #{env_path}")

        # Setup app folders needed for volumes. If this is not created then docker will create it while running the container,
        # but the folder will have root user assigned instead of the current user.
        FileUtils.mkdir_p("#{container_path}/app/vendor/bundle")
        FileUtils.mkdir_p("#{container_path}/app/public/assets")
        FileUtils.mkdir_p("#{container_path}/app/public/packs")
        FileUtils.mkdir_p("#{container_path}/app/node_modules")
        FileUtils.mkdir_p("#{container_path}/app/storage")
        FileUtils.mkdir_p("#{container_path_with_version}/vendor/bundle")
        FileUtils.mkdir_p("#{container_path_with_version}/public/assets")
        FileUtils.mkdir_p("#{container_path_with_version}/public/packs")
        FileUtils.mkdir_p("#{container_path_with_version}/node_modules")
        FileUtils.mkdir_p("#{container_path_with_version}/storage")

        # Creating & Starting container
        container_id = `docker ps -a -q --filter='name=^#{appname}_1$' --filter='status=running'`.chomp
        new_container = container_id.empty? ? "#{appname}_1" : "#{appname}_2"
        old_container = container_id.empty? ? "#{appname}_2" : "#{appname}_1"

        SmartCloud::Apps::App.stop("#{new_container}")
        if system("docker create \
                --name='#{new_container}' \
                --env-file='#{container_path}/env' \
                --user `id -u`:`id -g` \
                --workdir /app \
                --expose='3000' \
                --volume='#{SmartCloud.config.user_home_path}/.smartcloud/config:#{SmartCloud.config.user_home_path}/.smartcloud/config' \
                --volume='#{container_path_with_version}:/app' \
                --volume='#{container_path}/app/vendor/bundle:/app/vendor/bundle' \
                --volume='#{container_path}/app/public/assets:/app/public/assets' \
                --volume='#{container_path}/app/public/packs:/app/public/packs' \
                --volume='#{container_path}/app/node_modules:/app/node_modules' \
                --volume='#{container_path}/app/storage:/app/storage' \
                --restart='always' \
                --init \
                --network='nginx-network' \
                smartcloud/buildpacks/rails", out: File::NULL)

                system("docker network connect elasticsearch-network #{new_container}")
                system("docker network connect minio-network #{new_container}")
                system("docker network connect mysql-network #{new_container}")

                if system("docker start --attach #{new_container}")
                        logger.debug "Starting Web Server ..."
                        if system("docker start #{new_container}", out: File::NULL)
                                sleep 7
                                logger.info "Web Server started successfully."
                                SmartCloud::Apps::App.stop(old_container)
                                SmartCloud::Apps::App.clean_up(container_path)
                                logger.info "Launched Application ... Success."
                                exit 10
                        end
                else
                        SmartCloud::Apps::App.stop("#{new_container}")
                end
        end

        logger.formatter = nil
end

Private Instance Methods

bundle_install?() click to toggle source

Perform bundle install

# File lib/smart_cloud/apps/rails.rb, line 136
def bundle_install?
        logger.info "Performing bundle install ..."

        set_logger_formatter_tabs

        unless system("bundle config set deployment 'true' && bundle config set clean 'true'")
                logger.error "Could not complete bundle config setting."
                return false
        end

        exit_status = nil
        Open3.popen2e("bundle", "install") do |stdin, stdout_and_stderr, wait_thr|
                stdout_and_stderr.each { |line| logger.info "#{line}" }
                exit_status = wait_thr.value.success?
        end
        set_logger_formatter_arrow

        if exit_status
                return true
        else
                logger.error "Could not complete bundle install."
                return false
        end
end
db_migrate?() click to toggle source

Perform db_migrate

# File lib/smart_cloud/apps/rails.rb, line 182
def db_migrate?
        return true # remove this line when you want to start using db_migrate?

        logger.info "Performing database migrations ..."

        set_logger_formatter_tabs
        exit_status = nil
        Open3.popen2e("bundle", "exec", "rails", "db:migrate") do |stdin, stdout_and_stderr, wait_thr|
                stdout_and_stderr.each { |line| logger.info "#{line}" }
                exit_status = wait_thr.value.success?
        end
        set_logger_formatter_arrow

        if exit_status
                return true
        else
                logger.error "Could not complete database migrations."
                return false
        end
end
initial_setup?() click to toggle source

Perform initial_setup

# File lib/smart_cloud/apps/rails.rb, line 118
def initial_setup?
        logger.info "Performing initial setup ..."

        exit_status = nil

        # Fix for mysql2 gem to support sha256_password, until it is fixed in main mysql2 gem.
        # https://github.com/brianmario/mysql2/issues/1023
        exit_status = system("mkdir -p ./lib/mariadb && ln -s /usr/lib/mariadb/plugin ./lib/mariadb/plugin")

        if exit_status
                return true
        else
                logger.error "Could not complete initial setup."
                return false
        end
end
precompile_assets?() click to toggle source

Perform pre-compiling of assets

# File lib/smart_cloud/apps/rails.rb, line 162
def precompile_assets?
        logger.info "Installing Javascript dependencies & pre-compiling assets ..."

        set_logger_formatter_tabs
        exit_status = nil
        Open3.popen2e("bundle", "exec", "rails", "assets:precompile") do |stdin, stdout_and_stderr, wait_thr|
                stdout_and_stderr.each { |line| logger.info "#{line}" }
                exit_status = wait_thr.value.success?
        end
        set_logger_formatter_arrow

        if exit_status
                return true
        else
                logger.error "Could not install Javascript dependencies or pre-compile assets."
                return false
        end
end
set_logger_formatter_arrow() click to toggle source
# File lib/smart_cloud/apps/rails.rb, line 234
def set_logger_formatter_arrow
        logger.formatter = proc do |severity, datetime, progname, message|
                severity_text = { "DEBUG" => "\u{1f527} #{severity}:", "INFO" => " \u{276f}", "WARN" => "\u{2757} #{severity}:",
                        "ERROR" => "\u{274c} #{severity}:", "FATAL" => "\u{2b55} #{severity}:", "UNKNOWN" => "\u{2753} #{severity}:"
                }
                "\t\t\t\t#{severity_text[severity]} #{message}\n"
        end
end
set_logger_formatter_tabs() click to toggle source
# File lib/smart_cloud/apps/rails.rb, line 243
def set_logger_formatter_tabs
        logger.formatter = proc do |severity, datetime, progname, message|
                "\t\t\t\t       #{message}"
        end
end
test_web_server?() click to toggle source

Perform testing of web server

# File lib/smart_cloud/apps/rails.rb, line 204
def test_web_server?
        logger.info "Setting up Web Server ..."

        # tmp folders
        FileUtils.mkdir_p("tmp/pids")
        FileUtils.mkdir_p("tmp/smartcloud")
        FileUtils.rm_f("tmp/smartcloud/packed")

        # Spawn Process
        pid = Process.spawn("bundle", "exec", "puma", "--config", "config/puma.rb", out: File::NULL)
        Process.detach(pid)

        # Sleep
        sleep 5

        # Check PID running
        status = nil
        begin
                Process.kill(0, pid)
                system("echo '#{pid}' > tmp/smartcloud/packed")
                status = true
        rescue Errno::ESRCH # No such process
                logger.info "Web Server could not start"
                status = false
        end

        # Return status
        return status
end