#!/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 = < [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( nil, '--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 <)" 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 c = cfg[ENV["API_DRIVER"].to_sym] 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"] unless options[:daemon] 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 puts 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 have_thin = options[:webrick].nil? && library_present?('thin') have_rerun = library_present?('rerun') unless have_thin require 'rack' # 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" unless RUBY_PLATFORM == 'java' set :root, $top_srcdir # Set Sinatra root since we can't chdir to ../ end 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" Rack::Server::start(:app => app, :Host => ENV["API_HOST"], :Port => port, :AccessLog => []) 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' ] argv_opts << [ "--log", File.join(options[:logdir], "#{ENV['API_DRIVER']}.log")] 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 => $top_srcdir) rerun.start rerun.join else thin = Thin::Runner.new(argv_opts) thin.run! end end