blob: 71e55d3fed77c3261c8093f6d2847b4f07f57244 [file] [log] [blame]
#!/usr/bin/env ruby
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
$top_srcdir = File::expand_path(File.join(File.dirname(__FILE__), '..'))
require 'rubygems'
require 'optparse'
require 'yaml'
# See if we can require +name+ and return +true+ if the library is there,
# +false+ otherwise. Note that, as a side effect, the library will be
# loaded
def library_present?(name)
begin
require name
true
rescue LoadError
false
end
end
DEFAULT_CONFIG = "~/.deltacloud/config"
options = {
:env => 'development',
:logdir => "/var/log/deltacloud-core"
}
optparse = OptionParser.new do |opts|
opts.banner = <<BANNER
Usage:
deltacloudd -i <driver> [options]
Options:
BANNER
opts.on( '-i', '--driver DRIVER', 'Driver to use') do |driver|
ENV["API_DRIVER"] = driver
end
opts.on( '-r', '--hostname HOSTNAME',
'Bind to HOST address (default: localhost)') do |host|
ENV["API_HOST"] = host
end
opts.on( '-p', '--port PORT', 'Use PORT (default: 3001)') do |port|
ENV["API_PORT"] = port
end
opts.on( '-P', '--provider PROVIDER', 'Use PROVIDER (default is set in the driver)') do |provider|
ENV['API_PROVIDER'] = provider
end
opts.on('-f', '--frontends FRONTENDS', 'Enable different frontends (cimi, ec2, deltacloud)') do |frontend|
ENV['API_FRONTEND'] = frontend
end
opts.on( '-c', '--config [FILE]', 'Read provider and other config from FILE (default: ~/.deltacloud/config)') do |config|
options[:config] = File::expand_path(config || DEFAULT_CONFIG)
end
opts.on( '-e', '--env ENV', 'Environment (default: "development")') { |env| options[:env] = env }
opts.on( '-d', '--daemon', 'Run daemonized in the background, logging to SYSLOG (default: "disabled")') do
options[:daemon] = true
end
opts.on( '-u', '--user USER', 'User to run daemon as. Use with -d (default: "nobody")') { |user| options[:user] = user }
opts.on( '-g', '--group GROUP', 'Group to run daemon as. Use with -d (default: "nobody")') { |group| options[:group] = group }
opts.on( '-b', '--pid PID', 'File to store PID (default: tmp/pids/thin.pid)') { |pid| options[:pid] = pid }
opts.on( '-l', '--drivers', 'List available drivers') { |env| options[:drivers] = true }
opts.on( '-L', '--log FILE', 'Log requests to a file (default: disabled)') { |log| ENV['API_LOG'] = log }
opts.on( '-s', '--ssl', 'Enable SSL (default: disabled)') { |ssl| options[:ssl] = true }
opts.on( '-k', '--ssl-key KEY', 'SSL key file to use') { |key| options[:ssl_key] = key }
opts.on( '-C', '--ssl-cert CERT', 'SSL certificate file to use') { |cert| options[:ssl_cert] = cert }
opts.on( '-t', '--timeout TIMEOUT', 'Timeout for single request (default: 60)') do |timeout|
ENV["API_TIMEOUT"] = timeout
end
opts.on( '-V', '--verbose', 'Set verbose logging on') do |verbose|
ENV["API_VERBOSE"] ||= 'true'
end
opts.on( '-w', '--webrick', 'Force the use of WEBRick as a server') do |opt|
options[:webrick] = true
end
opts.on('--logdir LOGDIR', "Directory for log files, defaults to #{options[:logdir]}") do |opt|
options[:logdir] = opt
end
opts.on( '-h', '--help', '') { options[:help] = true }
opts.separator <<EOS
Config file:
Server configuration can be specified in a YAML file; the file must
contain a hash, where the keys are driver names; each driver entry is
also a hash. Possible keys are
:provider - the provider to use for this driver
:user - the user name for this driver
:password - the password for this driver
Note that specifying :user and :password turns off authentication on the
server, and any request is forwarded to the backend cloud with the
specified credentials.
Note, for SSL you need to have API_SSL_KEY and API_SSL_CERT environment
variables set.
EOS
end
optparse.parse!
if options[:help]
puts optparse
exit(0)
end
unless options[:drivers] or ENV["API_DRIVER"]
puts "You need to specify a driver to use (-i <driver>)"
puts "To list all available drivers try: deltacloudd --drivers"
exit(1)
end
if options[:drivers]
$:.unshift File.join($top_srcdir, 'lib')
server_dir = ENV['API_FRONTEND'] == 'cimi' ? 'cimi' : 'deltacloud'
load File.join($top_srcdir, 'lib', server_dir, 'api.rb')
puts "Available drivers:\n\n"
puts Deltacloud.drivers.keys.join("\n")
puts
exit(0)
end
if options[:ssl]
unless options[:ssl_key]
puts "You need to set SSL key using '-k /path/to/keyfile.key'"
exit(1)
end
unless options[:ssl_cert]
puts "You need to set SSL certificate using '-C /path/to/certificate.crt'"
exit(1)
end
end
if options[:config]
cfg = YAML::load(File.read(options[:config]))
if cfg.keys.any? { |k| k.is_a?(Symbol) }
puts "The config file #{options[:config]} uses symbols as keys"
puts " Change them to be ordinary strings"
exit(1)
end
if c = cfg[ENV["API_DRIVER"]]
ENV["API_PROVIDER"] ||= c["provider"]
ENV["API_USER"] ||= c["user"]
ENV["API_PASSWORD"] ||= c["password"]
end
end
ENV["API_HOST"] = "localhost" unless ENV["API_HOST"]
ENV["API_PORT"] = "3001" unless ENV["API_PORT"]
have_thin = options[:webrick].nil? && library_present?('thin')
have_rerun = library_present?('rerun')
if !options[:daemon] || options[:daemon] && !have_thin
msg = "Starting Deltacloud API :: #{ENV["API_DRIVER"]} "
msg << ":: #{ENV['API_PROVIDER']} " if ENV['API_PROVIDER']
api_uri = ENV['API_FRONTEND'] == 'cimi' ? 'cimi/cloudEntryPoint' : 'api'
if options[:ssl]
msg << ":: https://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/#{api_uri}"
else
msg << ":: http://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/#{api_uri}"
end
puts msg
end
if ENV['API_USER'] && ENV['API_PASSWORD']
puts "Warning: API_USER and API_PASSWORD set in environment"
puts " anybody can access this server with your credentials"
puts
end
unless have_thin
require 'rack'
puts "To start Deltacloud as a daemon, install 'thin' (gem install thin)\n\n" if options[:daemon]
port = ENV["API_PORT"].to_i
# Read in config.ru and convert it to an instance of Rack::Builder
cfgfile = File.read(File.join($top_srcdir, 'config.ru'))
inner_app = eval("Rack::Builder.new {(" + cfgfile + "\n )}.to_app",
nil, 'config.ru')
app = Rack::Builder.new {
use Rack::CommonLogger # apache-like logging
use Rack::Reloader #if options[:env] == "development"
run inner_app
}.to_app
# There's a bug with string ports on JRuby so convert to int
# http://jira.codehaus.org/browse/JRUBY-4868
port = ENV["API_PORT"].to_i
puts "=> Ctrl-C to shutdown server"
Dir::chdir($top_srcdir)
if RUBY_PLATFORM == 'java'
require 'puma'
events = Puma::Events.new STDOUT, STDERR
server = Puma::Server.new app, events
server.add_tcp_listener ENV['API_HOST'], port
server.run(false)
else
Rack::Server::start(:app => app,
:Host => ENV["API_HOST"],
:Port => port,
:server => 'webrick',
:AccessLog => [])
end
else
argv_opts = ARGV.clone
argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0])
argv_opts << ['--address', ENV["API_HOST"] ]
argv_opts << ['--port', ENV["API_PORT"] ]
argv_opts << ['--rackup', File.join($top_srcdir, 'config.ru') ]
argv_opts << ['-e', options[:env] ]
argv_opts << ['--timeout', ENV["API_TIMEOUT"] || '60']
argv_opts << ['--threaded', '-D' ]
if options[:ssl]
argv_opts << [ '--ssl', '--ssl-key-file', options[:ssl_key], '--ssl-cert-file', options[:ssl_cert]]
end
if options[:daemon]
options[:env] = "production"
argv_opts << [ "--daemonize", "--user", options[:user] || 'nobody', "--tag", "deltacloud-#{ENV['API_DRIVER']}"]
argv_opts << [ "--pid", options[:pid]] if options[:pid]
argv_opts << [ "--group", options[:group] || 'nobody' ]
unless ENV['API_LOG']
argv_opts << [ "--log", File.join(options[:logdir], "#{ENV['API_DRIVER']}.log")]
end
end
argv_opts.flatten!
if have_rerun && options[:env] == "development"
argv_opts.unshift "thin"
command = argv_opts.join(" ")
Dir::chdir($top_srcdir)
rerun = Rerun::Runner.new(command,
:dir => File::join($top_srcdir, "lib"),
:pattern => "**/*")
rerun.start
rerun.join
else
thin = Thin::Runner.new(argv_opts)
thin.run!
end
end