meroku 0.1.36 → 2.0.0
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.
- checksums.yaml +4 -4
- data/.env.example +2 -0
- data/.gitignore +10 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Guardfile +58 -0
- data/LICENSE.txt +21 -0
- data/README.md +16 -0
- data/Rakefile +10 -0
- data/bin/meroku +6 -0
- data/exe/meroku +6 -2
- data/lib/meroku.rb +24 -15
- data/lib/meroku/infrastructure.rb +24 -0
- data/lib/meroku/version.rb +1 -1
- data/meroku.gemspec +40 -0
- metadata +111 -81
- data/lib/meroku/app.rb +0 -12
- data/lib/meroku/app/collaborator.rb +0 -18
- data/lib/meroku/application_record.rb +0 -8
- data/lib/meroku/apps_controller.rb +0 -112
- data/lib/meroku/cli.rb +0 -8
- data/lib/meroku/cli/certs.rb +0 -30
- data/lib/meroku/cli/certs.rb~ +0 -14
- data/lib/meroku/cli/cli.rb +0 -97
- data/lib/meroku/cli/config.rb +0 -111
- data/lib/meroku/cli/domains.rb +0 -69
- data/lib/meroku/cli/keys.rb +0 -38
- data/lib/meroku/cli/remote.rb +0 -13
- data/lib/meroku/cli/remote.rb~ +0 -12
- data/lib/meroku/cli/server.rb +0 -163
- data/lib/meroku/cli/server.rb~ +0 -4
- data/lib/meroku/config.rb +0 -6
- data/lib/meroku/configs_controller.rb +0 -62
- data/lib/meroku/core_ext.rb +0 -30
- data/lib/meroku/domain.rb +0 -6
- data/lib/meroku/domains_controller.rb +0 -83
- data/lib/meroku/error.rb +0 -6
- data/lib/meroku/key.rb +0 -11
- data/lib/meroku/keys_controller.rb +0 -82
- data/lib/meroku/sanitychecks.rb +0 -19
- data/lib/meroku/user.rb +0 -23
- data/lib/meroku/util.rb +0 -434
| @@ -1,82 +0,0 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            module Meroku
         | 
| 3 | 
            -
              
         | 
| 4 | 
            -
              class KeysController < ApplicationController
         | 
| 5 | 
            -
                before_action :set_key, only: [:show, :edit, :update, :destroy]
         | 
| 6 | 
            -
                skip_before_action :verify_authenticity_token, only: [:create]
         | 
| 7 | 
            -
                before_action :authenticate, only: [ :create ]
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                ## GET /keys
         | 
| 10 | 
            -
                ## GET /keys.json
         | 
| 11 | 
            -
                #def index
         | 
| 12 | 
            -
                #  @keys = Meroku::Key.allxb
         | 
| 13 | 
            -
                #  render json: { "data": @keys }
         | 
| 14 | 
            -
                #end
         | 
| 15 | 
            -
              
         | 
| 16 | 
            -
                ## GET /keys/1
         | 
| 17 | 
            -
                ## GET /keys/1.json
         | 
| 18 | 
            -
                #def show
         | 
| 19 | 
            -
                #end
         | 
| 20 | 
            -
                #
         | 
| 21 | 
            -
                ## GET /keys/new
         | 
| 22 | 
            -
                #def new
         | 
| 23 | 
            -
                #  @key = Key.new
         | 
| 24 | 
            -
                #end
         | 
| 25 | 
            -
                #
         | 
| 26 | 
            -
                ## GET /keys/1/edit
         | 
| 27 | 
            -
                #def edit
         | 
| 28 | 
            -
                #end
         | 
| 29 | 
            -
                #
         | 
| 30 | 
            -
                # POST /keys
         | 
| 31 | 
            -
                # POST /keys.json
         | 
| 32 | 
            -
                def create
         | 
| 33 | 
            -
                  @key = Meroku::Key.new(
         | 
| 34 | 
            -
                    key: params["key"],
         | 
| 35 | 
            -
                    user_id: @user.id
         | 
| 36 | 
            -
                  )
         | 
| 37 | 
            -
                  respond_to do |format|
         | 
| 38 | 
            -
                    if @key.save
         | 
| 39 | 
            -
                      format.json { render json: {  data: @key  } }
         | 
| 40 | 
            -
                    else
         | 
| 41 | 
            -
                     
         | 
| 42 | 
            -
                      format.json { render json: { :errors => @key.errors }, status: :unprocessable_entity }
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
                end
         | 
| 46 | 
            -
                #
         | 
| 47 | 
            -
                ## PATCH/PUT /keys/1
         | 
| 48 | 
            -
                ## PATCH/PUT /keys/1.json
         | 
| 49 | 
            -
                #def update
         | 
| 50 | 
            -
                #  respond_to do |format|
         | 
| 51 | 
            -
                #    if @key.update(key_params)
         | 
| 52 | 
            -
                #      format.html { redirect_to @key, notice: 'Key was successfully updated.' }
         | 
| 53 | 
            -
                #      format.json { render :show, status: :ok, location: @key }
         | 
| 54 | 
            -
                #    else
         | 
| 55 | 
            -
                #      format.html { render :edit }
         | 
| 56 | 
            -
                #      format.json { render json: @key.errors, status: :unprocessable_entity }
         | 
| 57 | 
            -
                #    end
         | 
| 58 | 
            -
                #  end
         | 
| 59 | 
            -
                #end
         | 
| 60 | 
            -
                #
         | 
| 61 | 
            -
                ## DELETE /keys/1
         | 
| 62 | 
            -
                ## DELETE /keys/1.json
         | 
| 63 | 
            -
                #def destroy
         | 
| 64 | 
            -
                #  @key.destroy
         | 
| 65 | 
            -
                #  respond_to do |format|
         | 
| 66 | 
            -
                #    format.html { redirect_to keys_url, notice: 'Key was successfully destroyed.' }
         | 
| 67 | 
            -
                #    format.json { head :no_content }
         | 
| 68 | 
            -
                #  end
         | 
| 69 | 
            -
                #end
         | 
| 70 | 
            -
              
         | 
| 71 | 
            -
                private
         | 
| 72 | 
            -
                  # Use callbacks to share common setup or constraints between actions.
         | 
| 73 | 
            -
                  def set_key
         | 
| 74 | 
            -
                    @key = Key.find(params[:id])
         | 
| 75 | 
            -
                  end
         | 
| 76 | 
            -
              
         | 
| 77 | 
            -
                  # Never trust parameters from the scary internet, only allow the white list through.
         | 
| 78 | 
            -
                  def key_params
         | 
| 79 | 
            -
                    params.require(:key).permit(:key, :original_filename, :user_id)
         | 
| 80 | 
            -
                  end
         | 
| 81 | 
            -
              end
         | 
| 82 | 
            -
            end
         | 
    
        data/lib/meroku/sanitychecks.rb
    DELETED
    
    | @@ -1,19 +0,0 @@ | |
| 1 | 
            -
            module Meroku
         | 
| 2 | 
            -
              module Sanitychecks
         | 
| 3 | 
            -
             | 
| 4 | 
            -
                def admin_secrets_required
         | 
| 5 | 
            -
                  secrets_dir = "#{Dir.home}/crypto/meroku/"
         | 
| 6 | 
            -
                  IO.read("#{secrets_dir}/meroku_secrets")
         | 
| 7 | 
            -
                  require 'dotenv'
         | 
| 8 | 
            -
                  Dotenv.load("#{secrets_dir}/meroku_secrets")
         | 
| 9 | 
            -
                  IO.read("#{secrets_dir}/meroku.id_rsa")
         | 
| 10 | 
            -
                  #IO.read("#{secrets_dir}/meroku.id_rsa.pub")
         | 
| 11 | 
            -
                  #IO.read("#{secrets_dir}/meroku_site_cert.pem")
         | 
| 12 | 
            -
                  #IO.read("#{secrets_dir}/meroku_site_chain.pem")
         | 
| 13 | 
            -
                  #IO.read("#{secrets_dir}/meroku_site_fullchain.pem")
         | 
| 14 | 
            -
                  #IO.read("#{secrets_dir}/meroku_site_privkey.pem")
         | 
| 15 | 
            -
                  #IO.read("#{secrets_dir}/meroku_ssh_host_keys.tgz")
         | 
| 16 | 
            -
                end
         | 
| 17 | 
            -
                
         | 
| 18 | 
            -
              end
         | 
| 19 | 
            -
            end
         | 
    
        data/lib/meroku/user.rb
    DELETED
    
    | @@ -1,23 +0,0 @@ | |
| 1 | 
            -
            module Meroku
         | 
| 2 | 
            -
              
         | 
| 3 | 
            -
              class User < Meroku::ApplicationRecord
         | 
| 4 | 
            -
                include Meroku::Util
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                # Include default devise modules. Others available are:
         | 
| 7 | 
            -
                # :confirmable, :lockable, :timeoutable and :omniauthable
         | 
| 8 | 
            -
                devise :database_authenticatable, :registerable,
         | 
| 9 | 
            -
                       :recoverable, :rememberable, :trackable, :validatable
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                has_many :keys
         | 
| 12 | 
            -
                
         | 
| 13 | 
            -
                after_create :add_unix_user
         | 
| 14 | 
            -
                after_create :install_rvm_for_user
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                def database_password
         | 
| 17 | 
            -
                  encrypted_password[7..20].gsub(/[^0-9a-z ]/i, '')
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
                
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            end
         | 
| 23 | 
            -
             | 
    
        data/lib/meroku/util.rb
    DELETED
    
    | @@ -1,434 +0,0 @@ | |
| 1 | 
            -
            module Meroku
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              # Methods that doesn't have a proper namespace yet
         | 
| 4 | 
            -
              module Util
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                require 'open3'
         | 
| 7 | 
            -
                class Subprocess
         | 
| 8 | 
            -
                  def initialize(cmd, &block)
         | 
| 9 | 
            -
                    # see: http://stackoverflow.com/a/1162850/83386
         | 
| 10 | 
            -
                    Open3.popen3(cmd) do |stdin, stdout, stderr, thread|
         | 
| 11 | 
            -
                      stdin.close
         | 
| 12 | 
            -
                      # read each stream from a new thread
         | 
| 13 | 
            -
                      { :out => stdout, :err => stderr }.each do |key, stream|
         | 
| 14 | 
            -
                        Thread.new do
         | 
| 15 | 
            -
                          until (line = stream.gets).nil? do
         | 
| 16 | 
            -
                            # yield the block depending on the stream
         | 
| 17 | 
            -
                            if key == :out
         | 
| 18 | 
            -
                              yield line, nil, thread if block_given?
         | 
| 19 | 
            -
                            else
         | 
| 20 | 
            -
                              yield nil, line, thread if block_given?
         | 
| 21 | 
            -
                            end
         | 
| 22 | 
            -
                          end
         | 
| 23 | 
            -
                        end
         | 
| 24 | 
            -
                      end
         | 
| 25 | 
            -
              
         | 
| 26 | 
            -
                      thread.join # don't exit until the external process is done
         | 
| 27 | 
            -
                      raise "ErrorDuringPopen3" if thread.value != 0
         | 
| 28 | 
            -
                    end
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                def additional_env_vars(app_name, dbtype)
         | 
| 33 | 
            -
                  require 'rest-client'
         | 
| 34 | 
            -
                  resp = RestClient.post 'https://www.meroku.com/meroku/apps/0/additional_env_vars.json', { :"dbtype" => dbtype, authentication: { app_name: app_name, token: cli_token} }
         | 
| 35 | 
            -
                  JSON.parse(resp)["data"]
         | 
| 36 | 
            -
                end
         | 
| 37 | 
            -
                
         | 
| 38 | 
            -
                def update_authorized_keys_file
         | 
| 39 | 
            -
                  `sudo -i -u u#{self.user_id} sh -c "echo '#{self.key}' | tee /home/u#{self.user_id}/.ssh/authorized_keys"`
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                def setup_repo
         | 
| 43 | 
            -
                  app = Meroku::App.find(self.app_id)
         | 
| 44 | 
            -
                  user = Meroku::User.find(self.user_id)
         | 
| 45 | 
            -
                  `sudo -i -u u#{user.id} sh -c "mkdir ~/#{app.name}.git"`
         | 
| 46 | 
            -
                  `sudo -i -u u#{user.id} sh -c "cd ~/#{app.name}.git && git init --bare"`
         | 
| 47 | 
            -
                end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
                def self.add_unix_users
         | 
| 51 | 
            -
                  puts "DB8 #{Meroku::User.all.size} users to add..."
         | 
| 52 | 
            -
                  Meroku::User.all.each do |user|
         | 
| 53 | 
            -
                    puts "DB8 Adding #{user.id} #{user.email}"
         | 
| 54 | 
            -
                    `sudo adduser --disabled-password --gecos "" u#{user.id}`
         | 
| 55 | 
            -
                    `sudo usermod -aG meroku u#{user.id}`
         | 
| 56 | 
            -
                    #`sudo -i -u u#{user.id} sh -c "mkdir ~/.ssh/"`
         | 
| 57 | 
            -
                    #`sudo -i -u u#{user.id} sh -c "touch ~/.ssh/authorized_keys"`
         | 
| 58 | 
            -
                    #a = IO.write("/tmp/tmp.txt",user.encrypted_password)
         | 
| 59 | 
            -
                    #`sudo -i -u u#{user.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password"`
         | 
| 60 | 
            -
                    #`sudo -i -u u#{user.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password 2>&1"`
         | 
| 61 | 
            -
                    `sudo -i -u u#{user.id} sh -c "git config --global core.hooksPath /opt/githooks"`
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                    #user.keys.each do |key|
         | 
| 64 | 
            -
                    #  puts "DB8 Adding key #{key.id} #{key.key[0..9]} ..."
         | 
| 65 | 
            -
                    #  `sudo -i -u u#{user.id} sh -c "echo '#{key.key}' | tee /home/u#{user.id}/.ssh/authorized_keys"`
         | 
| 66 | 
            -
                    #end
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                  end
         | 
| 69 | 
            -
                end
         | 
| 70 | 
            -
                
         | 
| 71 | 
            -
                # this is a callback called from the User model
         | 
| 72 | 
            -
                def add_unix_user
         | 
| 73 | 
            -
                  `sudo adduser --disabled-password --gecos "" u#{self.id}`
         | 
| 74 | 
            -
                  `sudo usermod -aG meroku u#{self.id}`
         | 
| 75 | 
            -
                  `sudo -i -u u#{self.id} sh -c "mkdir ~/.ssh/"`
         | 
| 76 | 
            -
                  `sudo -i -u u#{self.id} sh -c "touch ~/.ssh/authorized_keys"`
         | 
| 77 | 
            -
                  Rails.logger.debug "DB8 A"
         | 
| 78 | 
            -
                  a = IO.write("/tmp/tmp.txt",self.encrypted_password)
         | 
| 79 | 
            -
                  Rails.logger.debug a
         | 
| 80 | 
            -
                  Rails.logger.debug `sudo -i -u u#{self.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password"`
         | 
| 81 | 
            -
                  Rails.logger.debug `sudo -i -u u#{self.id} sh -c "cp /tmp/tmp.txt /home/u1/.encrypted_password 2>&1"`
         | 
| 82 | 
            -
                  Rails.logger.debug "DB8 A end"
         | 
| 83 | 
            -
                  `sudo -i -u u#{self.id} sh -c "git config --global core.hooksPath /opt/githooks"`
         | 
| 84 | 
            -
                end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                # this is a callback called from the Meroku::Collaborator model
         | 
| 87 | 
            -
                def add_mysql_user
         | 
| 88 | 
            -
                  user = Meroku::User.find(self.user_id)
         | 
| 89 | 
            -
                  `sudo mysql -pbitnami -e 'FLUSH PRIVILEGES; set password for "u#{self.user_id}"@"localhost" = PASSWORD("#{user.database_password}"); FLUSH PRIVILEGES;'`
         | 
| 90 | 
            -
                  Rails.logger.debug "DB8 add_mysql_user db password for user id #{user.id} set to #{user.database_password}"
         | 
| 91 | 
            -
                end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
                # self is a Meroku::Collaborator
         | 
| 94 | 
            -
                def add_mysql_grants
         | 
| 95 | 
            -
                  app = Meroku::App.find(self.app_id)
         | 
| 96 | 
            -
                  `sudo mysql -pbitnami -e 'FLUSH PRIVILEGES; GRANT ALL PRIVILEGES ON #{app.name}.* TO "u#{self.user_id}"@"localhost"; FLUSH PRIVILEGES;'`
         | 
| 97 | 
            -
                end
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                def create_empty_pg_db
         | 
| 100 | 
            -
                  app = Meroku::App.find(self.app_id)
         | 
| 101 | 
            -
                  `PGPASSWORD=bitnami psql -U postgres -c "CREATE DATABASE #{app.name};"`
         | 
| 102 | 
            -
                end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                def add_pg_user
         | 
| 105 | 
            -
                  user = Meroku::User.find(self.user_id)
         | 
| 106 | 
            -
                  `PGPASSWORD=bitnami psql -U postgres -c "CREATE USER u#{self.user_id} WITH PASSWORD '#{user.database_password}';"`
         | 
| 107 | 
            -
                end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                def add_pg_grants
         | 
| 110 | 
            -
                  app = Meroku::App.find(self.app_id)
         | 
| 111 | 
            -
                  `PGPASSWORD=bitnami psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE #{app.name} TO u#{self.user_id};"`
         | 
| 112 | 
            -
                end
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                # self is a Meroku::Collaborator
         | 
| 115 | 
            -
                def create_empty_mysql_db
         | 
| 116 | 
            -
                  app = Meroku::App.find(self.app_id)
         | 
| 117 | 
            -
                  `sudo mysql -pbitnami -e 'CREATE DATABASE #{app.name}'`
         | 
| 118 | 
            -
                end
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                # self refers to a Meroku::User
         | 
| 121 | 
            -
                def install_rvm_for_user
         | 
| 122 | 
            -
                  `sudo -i -u u#{self.id} /bin/bash -c 'curl -sSL https://get.rvm.io | bash'`
         | 
| 123 | 
            -
                end
         | 
| 124 | 
            -
                
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                def self.install_rvm_for_users
         | 
| 127 | 
            -
                  puts "DB8 #{Meroku::User.all.size} users to install rvm to..."
         | 
| 128 | 
            -
                  Meroku::User.all.each do |user|
         | 
| 129 | 
            -
                    puts "DB8 Installing rvm for Adding #{user.id} #{user.email}"
         | 
| 130 | 
            -
                    `sudo -i -u u#{user.id} /bin/bash -c 'curl -sSL https://get.rvm.io | bash'`
         | 
| 131 | 
            -
                  end
         | 
| 132 | 
            -
                end
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                def self.start_apps
         | 
| 135 | 
            -
                  puts "DB8 Starting #{Meroku::App.all.size} apps ..."
         | 
| 136 | 
            -
                  Meroku::App.all.each do |app|
         | 
| 137 | 
            -
                   puts "DB8 Starting app #{app.id} #{app.name}"
         | 
| 138 | 
            -
                   app_owner_id = Meroku::App::Collaborator.where(app_id: app.id).first.user_id
         | 
| 139 | 
            -
                   `sudo -i -u u#{app_owner_id} /bin/bash -lc 'source /opt/githooks/start_app; start_app "/home/u#{app_owner_id}/#{app.name}.git"'`
         | 
| 140 | 
            -
                  end
         | 
| 141 | 
            -
                end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                def public_key_exists?
         | 
| 144 | 
            -
                  File.exist?(Dir.home + "/.ssh/id_rsa.pub")
         | 
| 145 | 
            -
                end
         | 
| 146 | 
            -
             | 
| 147 | 
            -
                def valid_json?(json)
         | 
| 148 | 
            -
                  JSON.parse(json)
         | 
| 149 | 
            -
                  return true
         | 
| 150 | 
            -
                rescue JSON::ParserError => e
         | 
| 151 | 
            -
                  return false
         | 
| 152 | 
            -
                end
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                def cli_logged_in?
         | 
| 155 | 
            -
                  if File.exist?("/tmp/meroku.token")
         | 
| 156 | 
            -
                    return true
         | 
| 157 | 
            -
                  else
         | 
| 158 | 
            -
                    puts "Not logged in"
         | 
| 159 | 
            -
                    return false
         | 
| 160 | 
            -
                  end
         | 
| 161 | 
            -
                end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                def cli_token
         | 
| 164 | 
            -
                  `cat /tmp/meroku.token`.chomp
         | 
| 165 | 
            -
                end
         | 
| 166 | 
            -
             | 
| 167 | 
            -
                def cli_user_id
         | 
| 168 | 
            -
                  user_id = `cat /tmp/meroku.id`
         | 
| 169 | 
            -
                end
         | 
| 170 | 
            -
             | 
| 171 | 
            -
                def app_name
         | 
| 172 | 
            -
                  git_remote = `git remote get-url meroku`.chomp
         | 
| 173 | 
            -
                  git_remote =~ /\@www.meroku.com\:(.*?).git\Z/
         | 
| 174 | 
            -
                  $1
         | 
| 175 | 
            -
                end
         | 
| 176 | 
            -
                
         | 
| 177 | 
            -
                def ssh(ip, command)
         | 
| 178 | 
            -
                  puts `ssh -tt -o "StrictHostKeyChecking=no" -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'`
         | 
| 179 | 
            -
                end
         | 
| 180 | 
            -
             | 
| 181 | 
            -
                def ssh2(ip, command)
         | 
| 182 | 
            -
                  print "+ #{command} "
         | 
| 183 | 
            -
                  Meroku::Util::Subprocess.new "ssh -tt -o StrictHostKeyChecking=no -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'" do |stdout, stderr, thread|
         | 
| 184 | 
            -
                    print "."
         | 
| 185 | 
            -
                  end
         | 
| 186 | 
            -
                  print "\n"
         | 
| 187 | 
            -
             | 
| 188 | 
            -
                end
         | 
| 189 | 
            -
             | 
| 190 | 
            -
                def ssh3(ip, command)
         | 
| 191 | 
            -
                  puts "+ #{command} "
         | 
| 192 | 
            -
                  Meroku::Util::Subprocess.new "ssh -tt -o StrictHostKeyChecking=no -i ~/crypto/meroku/meroku.id_rsa bitnami@#{ip} '#{command}'" do |stdout, stderr, thread|
         | 
| 193 | 
            -
                    print stdout
         | 
| 194 | 
            -
                    print stderr
         | 
| 195 | 
            -
                  end
         | 
| 196 | 
            -
                  print "\n"
         | 
| 197 | 
            -
             | 
| 198 | 
            -
                end
         | 
| 199 | 
            -
                
         | 
| 200 | 
            -
                def ec2_client
         | 
| 201 | 
            -
                  @ec2_client ||= Aws::EC2::Client.new(
         | 
| 202 | 
            -
                      region: 'us-east-1',
         | 
| 203 | 
            -
                      access_key_id: ENV['AWS_ACCESS_KEY_ID'],
         | 
| 204 | 
            -
                      secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
         | 
| 205 | 
            -
                    )
         | 
| 206 | 
            -
                end
         | 
| 207 | 
            -
             | 
| 208 | 
            -
                def server_being_built
         | 
| 209 | 
            -
                  ec2_get_ip_by_instance_id(unused_servers.first)
         | 
| 210 | 
            -
                end
         | 
| 211 | 
            -
             | 
| 212 | 
            -
                def ec2_get_ip_by_instance_id(instance_id)
         | 
| 213 | 
            -
                  ec2_client.describe_instances(
         | 
| 214 | 
            -
                    filters:
         | 
| 215 | 
            -
                      [
         | 
| 216 | 
            -
                        { name: "instance-id", values: [ instance_id ] }
         | 
| 217 | 
            -
                      ]
         | 
| 218 | 
            -
                  ).reservations.first.instances.first.public_ip_address
         | 
| 219 | 
            -
                end
         | 
| 220 | 
            -
                
         | 
| 221 | 
            -
                def meroku_servers
         | 
| 222 | 
            -
                  ec2_client.describe_instances(
         | 
| 223 | 
            -
                    filters:
         | 
| 224 | 
            -
                      [
         | 
| 225 | 
            -
                        { name: "tag:Name", values: ['meroku'] },
         | 
| 226 | 
            -
                        { name: "instance-state-name", values: ['pending', 'running'] }
         | 
| 227 | 
            -
                      ]
         | 
| 228 | 
            -
                  ).reservations
         | 
| 229 | 
            -
                    .map{ |a| a.instances }
         | 
| 230 | 
            -
                    .map{ |b|
         | 
| 231 | 
            -
                      b.map { |c| c.instance_id }
         | 
| 232 | 
            -
                    }
         | 
| 233 | 
            -
                    .flatten
         | 
| 234 | 
            -
                end
         | 
| 235 | 
            -
                
         | 
| 236 | 
            -
                # Returns the production servers instance id
         | 
| 237 | 
            -
                def production_servers
         | 
| 238 | 
            -
                  ec2_client.describe_instances(
         | 
| 239 | 
            -
                    filters:
         | 
| 240 | 
            -
                      [
         | 
| 241 | 
            -
                        { name: "ip-address", values: [ Meroku::PRODUCTION_IP ] },
         | 
| 242 | 
            -
                        { name: "tag:Name", values: ['meroku'] },
         | 
| 243 | 
            -
                        { name: "instance-state-name", values: ['pending', 'running'] }
         | 
| 244 | 
            -
                      ]
         | 
| 245 | 
            -
                  ).map { |x| x.reservations }.flatten.map { |x| x.instances }.flatten.map { |x| x.instance_id }
         | 
| 246 | 
            -
                rescue
         | 
| 247 | 
            -
                  []
         | 
| 248 | 
            -
                end
         | 
| 249 | 
            -
                
         | 
| 250 | 
            -
                def unused_servers
         | 
| 251 | 
            -
                  meroku_servers - production_servers
         | 
| 252 | 
            -
                end
         | 
| 253 | 
            -
             | 
| 254 | 
            -
                def terminate_unused_servers
         | 
| 255 | 
            -
                  unused_servers.each do |server|
         | 
| 256 | 
            -
                    puts "Terminating #{server}"
         | 
| 257 | 
            -
                    ec2_client.terminate_instances({ instance_ids: [ server ] })
         | 
| 258 | 
            -
                    sleep 1
         | 
| 259 | 
            -
                  end
         | 
| 260 | 
            -
                end
         | 
| 261 | 
            -
             | 
| 262 | 
            -
                def ec2_start_instance
         | 
| 263 | 
            -
                  resp = ec2_client.run_instances(
         | 
| 264 | 
            -
                    {
         | 
| 265 | 
            -
                      :image_id => 'ami-52a5dd44', #bitnami 2.4.1
         | 
| 266 | 
            -
                      :min_count => 1,
         | 
| 267 | 
            -
                      :max_count => 1,
         | 
| 268 | 
            -
                      :instance_type => "t2.small",
         | 
| 269 | 
            -
                      :key_name => "meroku.id_rsa"
         | 
| 270 | 
            -
                    }
         | 
| 271 | 
            -
                  )
         | 
| 272 | 
            -
                  resp[:instances][0][:instance_id]
         | 
| 273 | 
            -
                end
         | 
| 274 | 
            -
             | 
| 275 | 
            -
                def ec2_tag_instance(instance_id)
         | 
| 276 | 
            -
                  retries ||= 0
         | 
| 277 | 
            -
                  puts "create_tags try ##{ retries }"
         | 
| 278 | 
            -
                  ec2_client.create_tags( resources: [ instance_id ], tags: [ { key: 'Name', value: "meroku"}])
         | 
| 279 | 
            -
                rescue
         | 
| 280 | 
            -
                  sleep 1
         | 
| 281 | 
            -
                  retry if (retries += 1) < 3      
         | 
| 282 | 
            -
                end
         | 
| 283 | 
            -
             | 
| 284 | 
            -
                def ec2_await_boot(instance_id)
         | 
| 285 | 
            -
                  wait_timeout = 60
         | 
| 286 | 
            -
                  ec2_client.wait_until(:instance_running, instance_ids:[ instance_id ]) do |w|
         | 
| 287 | 
            -
                    w.max_attempts = 10
         | 
| 288 | 
            -
                    w.interval = wait_timeout/10
         | 
| 289 | 
            -
                    w.before_attempt do |n|
         | 
| 290 | 
            -
                      print "#{n}/10 "
         | 
| 291 | 
            -
                    end
         | 
| 292 | 
            -
                  end
         | 
| 293 | 
            -
                  public_ip_address = ec2_client.describe_instances(instance_ids: [instance_id])[0][0].instances[0].public_ip_address
         | 
| 294 | 
            -
                  puts public_ip_address
         | 
| 295 | 
            -
                  wait_time=40
         | 
| 296 | 
            -
                  10.times do |i|
         | 
| 297 | 
            -
                    port_is_open = Socket.tcp(public_ip_address, 22, connect_timeout: 6) { true } rescue false
         | 
| 298 | 
            -
                    print "#{i}/10 "
         | 
| 299 | 
            -
                    break if port_is_open
         | 
| 300 | 
            -
                    sleep 8
         | 
| 301 | 
            -
                  end
         | 
| 302 | 
            -
                  print "\n"
         | 
| 303 | 
            -
                  puts `ssh -o "StrictHostKeyChecking=no" -i ~/crypto/meroku/meroku.id_rsa ubuntu@#{public_ip_address} uptime 2>/dev/null`
         | 
| 304 | 
            -
                end
         | 
| 305 | 
            -
             | 
| 306 | 
            -
                def self.shell_exec(command)
         | 
| 307 | 
            -
                  require 'open3'
         | 
| 308 | 
            -
                  Open3.popen2e(command) do |stdin, stdout_err, wait_thr|
         | 
| 309 | 
            -
                    while line = stdout_err.gets
         | 
| 310 | 
            -
                      IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", line, mode: 'a')
         | 
| 311 | 
            -
                    end
         | 
| 312 | 
            -
                	exit_status = wait_thr.value
         | 
| 313 | 
            -
                    unless exit_status.success?
         | 
| 314 | 
            -
                      raise "FAILED !!!"
         | 
| 315 | 
            -
                    end
         | 
| 316 | 
            -
                  end
         | 
| 317 | 
            -
                end
         | 
| 318 | 
            -
             | 
| 319 | 
            -
                def self.nginx_rebuild
         | 
| 320 | 
            -
                  IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", "ngin_rebuild() started\n")
         | 
| 321 | 
            -
                  command = <<-'HEREDOC'
         | 
| 322 | 
            -
                    set -ex;
         | 
| 323 | 
            -
                    sudo rm -vf /opt/bitnami/nginx/conf/vhosts/*;
         | 
| 324 | 
            -
                    sudo rm -vf /opt/bitnami/nginx/keys/clients/*;
         | 
| 325 | 
            -
            HEREDOC
         | 
| 326 | 
            -
                  shell_exec(command)
         | 
| 327 | 
            -
                  IO.write("/tmp/www.conf", generate_nginx_config("www.meroku.com", "3000", nil) )
         | 
| 328 | 
            -
                  IO.write("/tmp/_.conf",nginx_fallback_vhost)
         | 
| 329 | 
            -
             | 
| 330 | 
            -
                  command = <<-'HEREDOC'
         | 
| 331 | 
            -
                    set -ex;
         | 
| 332 | 
            -
                    sudo mv -v /tmp/www.conf /opt/bitnami/nginx/conf/vhosts/;
         | 
| 333 | 
            -
            	sudo mv -v /tmp/_.conf /opt/bitnami/nginx/conf/vhosts/;
         | 
| 334 | 
            -
            HEREDOC
         | 
| 335 | 
            -
                  shell_exec(command)
         | 
| 336 | 
            -
             | 
| 337 | 
            -
                  Meroku::App.all.each do |app|
         | 
| 338 | 
            -
                    port = (3000 + app.id).to_s
         | 
| 339 | 
            -
                    domains = "#{app.name}.meroku.com"
         | 
| 340 | 
            -
                    domains = "#{app.name}.meroku.com"
         | 
| 341 | 
            -
                    domains += " #{app.domains.pluck(:domain).join(" ")}" if app.domains.size > 0
         | 
| 342 | 
            -
                    cert = nil
         | 
| 343 | 
            -
                    cert = app.name if app.server_crt
         | 
| 344 | 
            -
                    IO.write("/tmp/#{app.name}.conf", generate_nginx_config(domains, port, cert) )
         | 
| 345 | 
            -
                    shell_exec("sudo mv -v /tmp/#{app.name}.conf /opt/bitnami/nginx/conf/vhosts/")
         | 
| 346 | 
            -
                    if app.server_crt
         | 
| 347 | 
            -
                      IO.write("/tmp/#{app.name}.crt", app.server_crt )
         | 
| 348 | 
            -
                      IO.write("/tmp/#{app.name}.key", app.server_key )
         | 
| 349 | 
            -
                      shell_exec "set -ex; sudo mv -v /tmp/#{app.name}.crt /opt/bitnami/nginx/keys/cli\
         | 
| 350 | 
            -
            ents/"
         | 
| 351 | 
            -
                      shell_exec "set -ex; sudo mv -v /tmp/#{app.name}.key /opt/bitnami/nginx/keys/cli\
         | 
| 352 | 
            -
            ents/"
         | 
| 353 | 
            -
                    end
         | 
| 354 | 
            -
                  end
         | 
| 355 | 
            -
                  command = <<-'HEREDOC'
         | 
| 356 | 
            -
                    set -ex;
         | 
| 357 | 
            -
                    sudo /opt/bitnami/nginx/sbin/nginx -s reload;
         | 
| 358 | 
            -
                    ls -la /opt/bitnami/nginx/conf/vhosts/;
         | 
| 359 | 
            -
            HEREDOC
         | 
| 360 | 
            -
                  shell_exec(command)
         | 
| 361 | 
            -
                  IO.write("/home/bitnami/meroku/rails_app/log/nginx_rebuild.log", "ngin_rebuild() ended\n", mode: 'a')      
         | 
| 362 | 
            -
                end
         | 
| 363 | 
            -
             | 
| 364 | 
            -
                
         | 
| 365 | 
            -
                def self.generate_nginx_config(domains, port, cert)
         | 
| 366 | 
            -
                  if cert
         | 
| 367 | 
            -
                    server_crt = "/opt/bitnami/nginx/keys/clients/#{cert}.crt"
         | 
| 368 | 
            -
                    server_key = "/opt/bitnami/nginx/keys/clients/#{cert}.key"
         | 
| 369 | 
            -
                  else
         | 
| 370 | 
            -
                    server_crt = "/opt/bitnami/nginx/keys/meroku_site_fullchain.pem"
         | 
| 371 | 
            -
                    server_key = "/opt/bitnami/nginx/keys/meroku_site_privkey.pem"
         | 
| 372 | 
            -
                  end
         | 
| 373 | 
            -
                  
         | 
| 374 | 
            -
                  template = nginx_template
         | 
| 375 | 
            -
                  template.gsub!('REPLACEMEDOMAINS', domains)
         | 
| 376 | 
            -
                  template.gsub!('REPLACEMEPORT', port)
         | 
| 377 | 
            -
                  template.gsub!('REPLACEMESERVERCERT', server_crt)
         | 
| 378 | 
            -
                  template.gsub!('REPLACEMESERVERKEY', server_key)
         | 
| 379 | 
            -
                  template
         | 
| 380 | 
            -
                end
         | 
| 381 | 
            -
             | 
| 382 | 
            -
                def self.nginx_template
         | 
| 383 | 
            -
                  <<-'HEREDOC'
         | 
| 384 | 
            -
                    server {
         | 
| 385 | 
            -
                        listen 80;
         | 
| 386 | 
            -
                        server_name REPLACEMEDOMAINS;
         | 
| 387 | 
            -
                        listen 443 ssl;
         | 
| 388 | 
            -
                        ssl_certificate REPLACEMESERVERCERT;
         | 
| 389 | 
            -
                        ssl_certificate_key REPLACEMESERVERKEY;
         | 
| 390 | 
            -
             | 
| 391 | 
            -
                        root /home/u1/onebody/public;
         | 
| 392 | 
            -
             | 
| 393 | 
            -
                        location ~ ^/assets/ {
         | 
| 394 | 
            -
                          expires 1y;
         | 
| 395 | 
            -
                          add_header Cache-Control public;
         | 
| 396 | 
            -
                    
         | 
| 397 | 
            -
                          add_header ETag "";
         | 
| 398 | 
            -
                          break;
         | 
| 399 | 
            -
                        }
         | 
| 400 | 
            -
                    
         | 
| 401 | 
            -
                        ssl_session_timeout 5m;
         | 
| 402 | 
            -
                        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
         | 
| 403 | 
            -
                        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
         | 
| 404 | 
            -
                        ssl_prefer_server_ciphers on;
         | 
| 405 | 
            -
                    
         | 
| 406 | 
            -
                        location / {
         | 
| 407 | 
            -
                          proxy_pass http://127.0.0.1:REPLACEMEPORT;
         | 
| 408 | 
            -
                          # got from https://github.com/mperham/sidekiq/issues/2560
         | 
| 409 | 
            -
                          proxy_set_header    Host                  $http_host;
         | 
| 410 | 
            -
                          proxy_set_header    X-Real-IP             $proxy_protocol_addr;
         | 
| 411 | 
            -
                          proxy_set_header    X-Forwarded-For       $proxy_protocol_addr;
         | 
| 412 | 
            -
                          proxy_set_header    X-Forwarded-Proto     https;
         | 
| 413 | 
            -
                    
         | 
| 414 | 
            -
                        }
         | 
| 415 | 
            -
                    }
         | 
| 416 | 
            -
            HEREDOC
         | 
| 417 | 
            -
                end
         | 
| 418 | 
            -
             | 
| 419 | 
            -
                def self.nginx_fallback_vhost
         | 
| 420 | 
            -
                  <<-'HEREDOC'
         | 
| 421 | 
            -
                  # _.conf
         | 
| 422 | 
            -
                  # Default server for clients who do not send correct Host header.
         | 
| 423 | 
            -
                  # The underline in the file name makes sure that this file comes first in the dir.
         | 
| 424 | 
            -
                  server {
         | 
| 425 | 
            -
                    server_name _;
         | 
| 426 | 
            -
                    listen *:80 default_server deferred;
         | 
| 427 | 
            -
                    return 404;
         | 
| 428 | 
            -
                  }
         | 
| 429 | 
            -
            HEREDOC
         | 
| 430 | 
            -
                end
         | 
| 431 | 
            -
             | 
| 432 | 
            -
                
         | 
| 433 | 
            -
              end
         | 
| 434 | 
            -
            end
         |