class Google::Cloud::Gemserver::CLI::Server

# Server

Object responsible for deploying the gemserver to Google Cloud Platform and starting it.

Attributes

config[R]

The Configuration object used to deploy the gemserver @return [Configuration]

Public Class Methods

new() click to toggle source

Creates a Server instance by initializing a Configuration object that will be used to access paths to necessary configuration files.

# File lib/google/cloud/gemserver/cli/server.rb, line 40
def initialize
  @config = Configuration.new
end

Public Instance Methods

delete(proj_id) click to toggle source

Deletes a given gemserver by its parent project's ID.

@param [String] proj_id The project ID of the project the gemserver was deployed to.

# File lib/google/cloud/gemserver/cli/server.rb, line 90
def delete proj_id
  return unless Configuration.deployed?
  full_delete = user_input("This will delete the entire Google Cloud"\
     " Platform project #{proj_id}. Continue"\
     " deletion? (Y|n, default n) If no, all relevant resources will"\
     " be deleted besides the parent GCP project.").downcase
  if full_delete == "y"
    puts "Deleting gemserver with parent project"
    system "gcloud projects delete #{proj_id}"
  else
    @config.delete_from_cloud
    del_gcs_files
    inst = @config.app["beta_settings"]["cloud_sql_instances"]
      .split(":").pop
    puts "Deleting child Cloud SQL instance #{inst}..."
    params = "delete #{inst} --project #{proj_id}"
    status = system "gcloud beta sql instances #{params}"
    fail "Unable to delete instance" unless status
    puts "The Cloud SQL instance has been deleted. Visit:\n "\
      "https://console.cloud.google.com/appengine/settings?project="\
      "#{proj_id} and click \"Disable Application\" to delete the "\
      "Google App Engine application the gemserver was deployed to."
  end
end
deploy() click to toggle source

Deploys the gemserver to Google Cloud Platform if the app environment variable is set to “production.” Otherwise, the gemserver is started locally.

# File lib/google/cloud/gemserver/cli/server.rb, line 66
def deploy
  begin
    return start if ["test", "dev"].include? ENV["APP_ENV"]
    deploy_to_gae
    setup_default_keys
  ensure
    cleanup
  end
end
start() click to toggle source

Starts the gemserver by starting up the gemstash server with predefined options.

# File lib/google/cloud/gemserver/cli/server.rb, line 47
def start
  path = if ENV["APP_ENV"] == "production"
           Configuration::GAE_PATH
         else
           @config.config_path
         end
  args = [
    "start",
    "--no-daemonize",
    "--config-file=#{path}"
  ].freeze
  Google::Cloud::Gemserver::Backend::StorageSync.download_service
  Google::Cloud::Gemserver::Backend::GemstashServer.start args
end
update() click to toggle source

Updates the gemserver on a Google Cloud Platform project by redeploying it.

# File lib/google/cloud/gemserver/cli/server.rb, line 79
def update
  return unless Configuration.deployed?
  puts "Updating gemserver..."
  deploy_to_gae
end

Private Instance Methods

cleanup() click to toggle source

@private Deletes the temporary directory containing the files used to deploy the gemserver.

# File lib/google/cloud/gemserver/cli/server.rb, line 311
def cleanup
  FileUtils.rm_rf Configuration::SERVER_PATH
end
del_gcs_files() click to toggle source

@private Deletes all gem data files on Google Cloud Storage.

# File lib/google/cloud/gemserver/cli/server.rb, line 135
def del_gcs_files
  puts "Deleting all gem data on Google Cloud Storage..."
  gem_files = GCS.files Configuration::GEMSTASH_DIR
  gem_files.each { |f| f.delete }
end
deploy_to_gae() click to toggle source

Deploys the gemserver to Google App Engine and uploads the configuration file used by the gemserver to Google Cloud Storage for later convenience.

# File lib/google/cloud/gemserver/cli/server.rb, line 121
def deploy_to_gae
  puts "Beginning gemserver deployment..."
  prepare_dir
  path = "#{Configuration::SERVER_PATH}/app.yaml"
  flags = "-q --project #{@config[:proj_id]}"
  status = system "gcloud app deploy #{path} #{flags}"
  fail "Gemserver deployment failed. " unless status
  wait_until_server_accessible
  @config.save_to_cloud
  display_next_steps
end
display_next_steps() click to toggle source

@private Outputs helpful information to the console indicating the URL the gemserver is running at and how to use the gemserver.

# File lib/google/cloud/gemserver/cli/server.rb, line 220
def display_next_steps
  puts "\nThe gemserver has been deployed! It is running on #{remote}"
  puts "\nTo see the status of the gemserver, visit: \n" \
    " #{remote}/health"
  puts "\nTo see how to use your gemserver to push and download " \
    "gems read https://github.com/GoogleCloudPlatform/google-cloud-" \
    "gemserver/blob/master/docs/usage_example.md for some examples."
  puts "\nFor general information, visit https://github.com/" \
    "GoogleCloudPlatform/google-cloud-gemserver/blob/master/README.md"
end
gemfile() click to toggle source

@private Creates a Gemfile and Gemfile.lock for the gemserver that runs on Google App Engine such that gemstash is not required client side for the CLI.

# File lib/google/cloud/gemserver/cli/server.rb, line 284
def gemfile
  File.open("#{Configuration::SERVER_PATH}/Gemfile", "w") do |f|
    f.write gemfile_source
  end

  require "bundler"
  Bundler.with_clean_env do
    run_cmd "cd #{Configuration::SERVER_PATH} && bundle lock"
  end
end
gemfile_source() click to toggle source

@private The Gemfile used by the gemserver on Google App Engine.

@return [String]

# File lib/google/cloud/gemserver/cli/server.rb, line 265
          def gemfile_source
            <<~SOURCE
              source "https://rubygems.org"

              gem "google-cloud-gemserver", "#{Google::Cloud::Gemserver::VERSION}", path: "."
              gem "concurrent-ruby", require: "concurrent"
              gem "gemstash", git: "https://github.com/bundler/gemstash.git", ref: "a5a78e2"
              gem "mysql2", "~> 0.4"
              gem "filelock", "~> 1.1.1"
              gem "google-cloud-storage", "~> 1.1.0"
              gem "google-cloud-resource_manager", "~> 0.24"
              gem "activesupport", "~> 4.2"
            SOURCE
          end
prepare_dir() click to toggle source

@private Creates a temporary directory with the necessary files to deploy the gemserver.

# File lib/google/cloud/gemserver/cli/server.rb, line 298
def prepare_dir
  dir = Gem::Specification.find_by_name(Configuration::GEM_NAME).gem_dir
  cleanup if Dir.exist? Configuration::SERVER_PATH
  FileUtils.mkpath Configuration::SERVER_PATH
  FileUtils.cp_r "#{dir}/.", Configuration::SERVER_PATH
  FileUtils.cp @config.config_path, Configuration::SERVER_PATH
  FileUtils.cp @config.app_path, Configuration::SERVER_PATH
  gemfile
end
remote() click to toggle source

@private The URL of the gemserver.

@return [String]

# File lib/google/cloud/gemserver/cli/server.rb, line 255
def remote
  flag = "--project #{@config[:proj_id]}"
  descrip = YAML.load(run_cmd "gcloud app describe #{flag}")
  descrip["defaultHostname"]
end
run_cmd(args) click to toggle source

@private Runs a given command on the local machine.

@param [String] args The command to be run.

# File lib/google/cloud/gemserver/cli/server.rb, line 319
def run_cmd args
  `#{args}`
end
sanitize_name(name) click to toggle source

@private Sanitizes a name by removing special symbols and ensuring it is alphanumeric (and hyphens, underscores).

@param [String] name The name to be sanitized.

@return [String]

# File lib/google/cloud/gemserver/cli/server.rb, line 212
def sanitize_name name
  name = name.chomp
  name.gsub(/[^0-9a-z\-\_]/i, "")
end
set_bundle(key, gemserver_url) click to toggle source

@private Sets a given key in the bundle config used by bundler for installing gems.

@param [String] key The key to be added to the bundle config. @param [String] gemserver_url The URL of the gemserver.

# File lib/google/cloud/gemserver/cli/server.rb, line 164
def set_bundle key, gemserver_url
  puts "Updating bundle config"
  run_cmd "bundle config http://#{gemserver_url}/private #{key}"
end
set_gem_credentials(key) click to toggle source

@private Sets a given key in the gem credentials file used by Rubygems.org

@param [String] key The key to be added to the credentials.

# File lib/google/cloud/gemserver/cli/server.rb, line 174
def set_gem_credentials key
  key_name = sanitize_name(user_input("Updating bundle config. Enter"\
    " a name for your key (default is \"master-gemserver-key\""))
  key_name = key_name.empty? == true ? Configuration::DEFAULT_KEY_NAME : key_name
  puts "Updating #{Configuration::CREDS_PATH}"

  FileUtils.touch Configuration::CREDS_PATH
  keys = YAML.load_file(Configuration::CREDS_PATH) || {}

  if keys[key_name.to_sym].nil?
    system "echo \":#{key_name}: #{key}\" >> #{Configuration::CREDS_PATH}"
  else
    puts "The key name \"#{key_name}\" already exists. Please update"\
      " #{Configuration::CREDS_PATH} manually to replace the key or" \
      " manually enter a different name into the file for your key:" \
      " #{key}."
  end
end
setup_default_keys() click to toggle source

@private Creates a key with all permissions and sets it in the necessary configurations (gem credentials and bundle config).

# File lib/google/cloud/gemserver/cli/server.rb, line 144
def setup_default_keys
  should_create = user_input("Would you like to setup a default " \
    "key? [Y/n] (default yes)")
  return if should_create.downcase == "n"
  gemserver_url = remote
  res = Request.new(gemserver_url).create_key
  abort "Error generating key" unless res.code.to_i == 200
  key = Backend::Key.send :parse_key, res.body
  abort "Invalid key" unless valid_key? key
  puts "Generated key: #{key}"
  set_bundle key, gemserver_url
  set_gem_credentials key
end
user_input(msg) click to toggle source

@private Gets input from the user after displaying a message.

@param [String] msg The message to be displayed.

@return [String]

# File lib/google/cloud/gemserver/cli/server.rb, line 329
def user_input msg
  puts msg
  STDIN.gets.chomp
end
valid_key?(key) click to toggle source

@private Checks if a key is valid by its length and value.

@param [String] key The key to be validated.

@return [Boolean]

# File lib/google/cloud/gemserver/cli/server.rb, line 199
def valid_key? key
  size = key.size == Backend::Key::KEY_LENGTH
  m_size = key.gsub(/[^0-9a-z]/i, "").size == Backend::Key::KEY_LENGTH
  size && m_size
end
wait_until_server_accessible(timeout = 60) click to toggle source

@private Pings the gemserver until a timeout or the gemserver replies with a 200 response code.

@param [Integer] timeout The length of time the gemserver is pinged. Optional.

# File lib/google/cloud/gemserver/cli/server.rb, line 237
def wait_until_server_accessible timeout = 60
  puts "Waiting for the gemserver to be accessible..."
  start_time = Time.now
  loop do
    if Time.now - start_time > timeout
      fail "Could not establish a connection to the gemserver"
    else
      r = Request.new(nil, @config[:proj_id]).health
      break if r.code.to_i == 200
    end
    sleep 5
  end
end