Commit f2088a55 authored by Praveen Arimbrathodiyil's avatar Praveen Arimbrathodiyil
Browse files

Imported Upstream version 1.22.0+gh

parent c32a87c8
* Anatol <anatol.pomozov@gmail.com>
* Chris Johnson <wchrisjohnson@gmail.com>
* Dominic Cleal <dcleal@redhat.com>
* Evan Light <evan@tripledogdare.net>
* Paul Thornthwaite <paul@brightbox.co.uk>
* Paul Thornthwaite <tokengeek@gmail.com>
* Wesley Beary <geemus+github@gmail.com>
* geemus <geemus@gmail.com>
\ No newline at end of file
* geemus <geemus@gmail.com>
* mountkin <moutkin@gmail.com>
\ No newline at end of file
source 'https://rubygems.org'
# Specify your gem's dependencies in fog-core.gemspec
gemspec
......@@ -4,6 +4,7 @@ gem 'nokogiri', '~>1.5.11'
gem 'mime-types', '~>1.16'
group :development, :test do
gem 'rake', '~> 10.1.0'
# This is here because gemspec doesn't support require: false
gem 'coveralls', :require => false
end
......
require 'bundler/setup'
task :travis => ['test:travis', 'coveralls_push_workaround']
task :default => [:test]
require "rake/testtask"
require "tasks/test_task"
Fog::Rake::TestTask.new
Rake::TestTask.new do |t|
t.libs << "lib"
t.libs << "spec"
t.pattern = "spec/**/*_spec.rb"
end
namespace :test do
mock = 'true' || ENV['FOG_MOCK']
task :travis do
# jruby coveralls causes an OOM in travis
ENV['COVERAGE'] = 'false' if RUBY_PLATFORM == 'java'
sh("export FOG_MOCK=#{mock} && bundle exec shindont")
sh("export FOG_MOCK=#{mock} && rake")
end
end
......
1.21.1 03/18/2014 3a803405ba60ded421f4bd14677cd3c76cb7e6ab
==========================================================
remove json/xml modules and code
add travis/coveralls
update from upstream
bump/loosen excon dependency
......@@ -10,27 +10,26 @@ Gem::Specification.new do |spec|
spec.email = ["evan@tripledogdare.net", "geemus@gmail.com"]
spec.summary = %q{Shared classes and tests for fog providers and services.}
spec.description = %q{Shared classes and tests for fog providers and services.}
spec.homepage = ""
spec.homepage = "https://github.com/fog/fog-core"
spec.license = "MIT"
spec.files = Dir.glob(File.join("lib", "**", "*.rb"))
spec.files = `git ls-files`.split($/)
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.add_dependency('builder')
spec.add_dependency('excon', '~>0.32')
spec.add_dependency('formatador', '~>0.2.0')
spec.add_dependency('excon', '~>0.33')
spec.add_dependency('formatador', '~>0.2')
spec.add_dependency('mime-types')
spec.add_dependency('net-scp', '~>1.1')
spec.add_dependency('net-ssh', '>=2.1.3')
## List your development dependencies here. Development dependencies are
## those that are only needed during development
spec.add_development_dependency('rake')
spec.add_development_dependency('yard')
spec.add_development_dependency('thor')
spec.add_development_dependency('shindo', '~>0.3.4')
spec.add_development_dependency('minitest')
spec.add_development_dependency('minitest-stub-const')
spec.add_development_dependency('pry')
spec.add_development_dependency('coveralls')
end
......@@ -55,9 +55,14 @@ module Fog
else
if self.providers.include?(provider)
require "fog/#{provider}/compute"
return Fog::Compute.const_get(Fog.providers[provider]).new(attributes)
begin
Fog::Compute.const_get(Fog.providers[provider])
rescue
Fog::const_get(Fog.providers[provider])::Compute
end.new(attributes)
else
raise ArgumentError.new("#{provider} is not a recognized compute provider")
end
raise ArgumentError.new("#{provider} is not a recognized compute provider")
end
end
......
......@@ -28,9 +28,9 @@ require 'fog/core/service'
require 'fog/core/ssh'
require 'fog/core/scp'
require 'fog/core/time'
require 'fog/core/utils'
require 'fog/core/wait_for'
require 'fog/core/wait_for_defaults'
require 'fog/core/class_from_string'
require 'fog/core/uuid'
# service wrappers
......
module Fog
# get class by string or nil
def self.class_from_string classname, defaultpath=""
if classname and classname.is_a? String then
chain = classname.split("::")
klass = Kernel
chain.each do |klass_string|
klass = klass.const_get klass_string
end
if klass.is_a? Class then
klass
elsif defaultpath != nil then
Fog.class_from_string((defaultpath.split("::")+chain).join("::"), nil)
else
nil
end
elsif classname and classname.is_a? Class then
classname
else
nil
end
rescue NameError
defaultpath != nil ? Fog.class_from_string((defaultpath.split("::")+chain).join("::"), nil) : nil
end
end
......@@ -3,19 +3,49 @@ require 'yaml'
module Fog
require 'fog/core/deprecation'
# Sets the global configuration up from a Hash rather than using background loading from a file
#
# @example
# Fog.credentials = {
# :default => {
# :example_url => "https://example.com/"
# :example_username => "bob",
# :example_password => "obo"
# },
# :production => {
# :example_username => "bob",
# :example_password => "obo"
# }
# }
#
# @return [Hash] The newly assigned credentials
def self.credentials=(new_credentials)
@credentials = new_credentials
end
# Assign a new credential to use from configuration file
# @param [String, Symbol] new_credential name of new credential to use
# @ return [Symbol] name of the new credential
#
# @param [String, Symbol] new_credential name of new credential to use
# @return [Symbol] name of the new credential
def self.credential=(new_credential)
@credentials = nil
@credential = new_credential && new_credential.to_sym
end
# @return [String, Symbol] The credential to use in Fog
# This is the named credential from amongst the configuration file being used or +:default+
#
# @note This can be set using the +FOG_CREDENTIAL+ environment variable
#
# @return [Symbol] The credential to use in Fog
def self.credential
@credential ||= ( ENV["FOG_CREDENTIAL"] && ENV["FOG_CREDENTIAL"].to_sym ) || :default
end
# This returns the path to the configuration file being used globally to look for sets of
# credentials
#
# @note This can be set using the +FOG_RC+ environment variable or defaults to +$HOME/.fog+
#
# @return [String] The path for configuration_file
def self.credentials_path
@credential_path ||= begin
......@@ -35,9 +65,9 @@ module Fog
# @return [Hash] The credentials pulled from the configuration file
# @raise [LoadError] Configuration unavailable in configuration file
def self.credentials
@credentials ||= begin
@credentials ||= begin
if credentials_path && File.exists?(credentials_path)
credentials = self.symbolize_credentials(YAML.load_file(credentials_path))
credentials = Fog::Core::Utils.prepare_service_settings(YAML.load_file(credentials_path))
(credentials && credentials[credential]) || Fog::Errors.missing_credentials
else
{}
......@@ -45,26 +75,15 @@ module Fog
end
end
# @return [Hash] The newly assigned credentials
def self.credentials=(new_credentials)
@credentials = new_credentials
end
# @deprecated Don't use!
# @param [Object] key
# @return [true] if key == :headers
def self.symbolize_credential?(key)
![:headers].include?(key)
end
def self.symbolize_credentials(args)
if args.is_a? Hash
copy = Array.new
args.each do |key, value|
obj = symbolize_credential?(key) ? self.symbolize_credentials(value) : value
copy.push(key.to_sym, obj)
end
Hash[*copy]
else
args
end
# @deprecated Use {Fog::Core::Utils.prepare_service_settings} instead
def self.symbolize_credentials(hash)
Fog::Core::Utils.prepare_service_settings(hash)
end
end
......@@ -12,12 +12,13 @@ module Fog
def initialize(new_attributes = {})
# TODO Remove compatibility with old connection option
@service = new_attributes.delete(:service)
if @service.nil? && new_attributes[:connection]
attribs = new_attributes.clone
@service = attribs.delete(:service)
if @service.nil? && attribs[:connection]
Fog::Logger.deprecation("Passing :connection option is deprecated, use :service instead [light_black](#{caller.first})[/]")
@service = new_attributes[:connection]
@service = attribs[:connection]
end
merge_attributes(new_attributes)
merge_attributes(attribs)
end
def inspect
......
module Fog
require "fog/core/utils"
module Fog
def self.services
@services ||= {}
end
class Service
class Error < Fog::Errors::Error; end
class NotFound < Fog::Errors::NotFound; end
......@@ -16,7 +16,6 @@ module Fog
end
module Collections
def collections
service.collections
end
......@@ -28,11 +27,9 @@ module Fog
def requests
service.requests
end
end
class << self
def inherited(child)
child.class_eval <<-EOS, __FILE__, __LINE__
class Error < Fog::Service::Error; end
......@@ -52,27 +49,78 @@ module Fog
EOS
end
def new(options={})
options = Fog.symbolize_credentials(options)
options = fetch_credentials(options).merge(options)
validate_options(options)
coerce_options(options)
# {Fog::Service} is (unfortunately) both a builder class and the subclass for any fog service.
#
# Creating a {new} instance using the builder will return either an instance of
# +Fog::<Service>::<Provider>::Real+ or +Fog::<Service>::<Provider>::Mock+ based on the value
# of {Fog.mock?} when the builder is used.
#
# Each provider can require or recognize different settings (often prefixed with the providers
# name). These settings map to keys in the +~/.fog+ file.
#
# Settings can be passed as either a Hash or an object that responds to +config_service?+ with
# +true+. This object will be passed through unchanged to the +Real+ or +Mock+ service that is
# created. It is up to providers to adapt services to use these config objects.
#
# @abstract Subclass and implement real or mock code
#
# @param [Hash,#config_service?] config
# Settings or an object used to build a service instance
# @option config [Hash] :headers
# Passed to the underlying {Fog::Core::Connection} unchanged
#
# @return [Fog::Service::Provider::Real] if created while mocking is disabled
# @return [Fog::Service::Provider::Mock] if created while mocking is enabled
# @raise [ArgumentError] if a setting required by the provider was not passed in
#
# @example Minimal options (dependent on ~/.fog)
# @service = Fog::Compute::Example.new # => <#Fog::Compute::Example::Real>
#
# @example Mocked service
# Fog.mock!
# @service = Fog::Compute::Example.new # => <#Fog::Compute::Example::Mock>
#
# @example Configured using many options (options merged into ~/.fog)
# @options = {
# :example_username => "fog",
# :example_password => "fog"
# }
# @service = Fog::Compute::Example.new(@options)
#
# @example Configured using external config object (~/.fog ignored completely)
# @config = Fog::Example::Config.new(...)
# @service = Fog::Compute::Example.new(@config)
#
def new(config = {})
if config.respond_to?(:config_service?) && config.config_service?
cleaned_settings = config
else
cleaned_settings = handle_settings(config)
end
setup_requirements
svc = service
if Fog.mocking?
service::Mock.send(:include, service::Collections)
service::Mock.new(options)
while svc != Fog::Service
service::Mock.send(:include, svc::Collections)
svc = svc.superclass
end
service::Mock.new(cleaned_settings)
else
service::Real.send(:include, service::Collections)
while svc != Fog::Service
service::Real.send(:include, svc::Collections)
svc = svc.superclass
end
service::Real.send(:include, service::NoLeakInspector)
service::Real.new(options)
service::Real.new(cleaned_settings)
end
end
# @deprecated
def fetch_credentials(options)
# attempt to load credentials from config file
begin
Fog.credentials.reject {|key, value| !(recognized | requirements).include?(key)}
Fog.credentials.reject { |key, value| !(recognized | requirements).include?(key) }
rescue LoadError
# if there are no configured credentials, do nothing
{}
......@@ -86,34 +134,14 @@ module Fog
@required ||= false
unless @required
for collection in collections
require [@model_path, collection].join('/')
constant = collection.to_s.split('_').map {|characters| characters[0...1].upcase << characters[1..-1]}.join('')
service::Collections.module_eval <<-EOS, __FILE__, __LINE__
def #{collection}(attributes = {})
#{service}::#{constant}.new({:service => self}.merge(attributes))
end
EOS
end
for model in models
require [@model_path, model].join('/')
end
for request in requests
require [@request_path, request].join('/')
if service::Mock.method_defined?(request)
mocked_requests << request
else
service::Mock.module_eval <<-EOS, __FILE__, __LINE__
def #{request}(*args)
Fog::Mock.not_implemented
end
EOS
end
end
require_models
require_collections_and_define
require_requests_and_mock
@required = true
end
end
# @note This path is used to require model and collection files
def model_path(new_path)
@model_path = new_path
end
......@@ -204,6 +232,7 @@ module Fog
end
end
missing = requirements - keys
unless missing.empty?
raise ArgumentError, "Missing required arguments: #{missing.join(', ')}"
end
......@@ -216,8 +245,66 @@ module Fog
end
end
end
private
# This is the original way service settings were handled. Settings from +~/.fog+ were merged
# together with the passed options, keys are turned to symbols and coerced into Boolean or
# Fixnums.
#
# If the class has declared any required settings then {ArgumentError} will be raised.
#
# Any setting that is not whitelisted will cause a warning to be output.
#
def handle_settings(settings)
combined_settings = fetch_credentials(settings).merge(settings)
prepared_settings = Fog::Core::Utils.prepare_service_settings(combined_settings)
validate_options(prepared_settings)
coerce_options(prepared_settings)
end
# This will attempt to require all model files declared by the service using fog's DSL
def require_models
models.each do |model|
require File.join(@model_path, model.to_s)
end
end
def require_collections_and_define
collections.each do |collection|
require File.join(@model_path, collection.to_s)
constant = camel_case_collection_name(collection)
service::Collections.module_eval <<-EOS, __FILE__, __LINE__
def #{collection}(attributes = {})
#{service}::#{constant}.new({ :service => self }.merge(attributes))
end
EOS
end
end
# This converts names of collections from Symbols as defined in the DSL (+:database_server+)
# into CamelCase version (+DatabaseServer+) for metaprogramming skulduggery.
#
# @param [String,Symbol] collection The name of the collection broken with underscores
# @return [String] in camel case
def camel_case_collection_name(collection)
collection.to_s.split('_').map(&:capitalize).join
end
# This will attempt to require all request files declared in the service using fog's DSL
def require_requests_and_mock
requests.each do |request|
require File.join(@request_path, request.to_s)
if service::Mock.method_defined?(request)
mocked_requests << request
else
service::Mock.module_eval <<-EOS, __FILE__, __LINE__
def #{request}(*args)
Fog::Mock.not_implemented
end
EOS
end
end
end
end
end
end
module Fog::Core::Utils
# This helper prepares a Hash of settings for passing into {Fog::Service.new}.
#
# The only special consideration is if +:header+ key is passed in the contents are unchanged. This
# allows the headers to be passed through to requests to customise HTTP headers without them being
# broken by the +#to_sym+ calls.
#
# @param [Hash] settings The String based Hash to prepare
# @option settings [Hash] :headers Passed to the underlying {Fog::Core::Connection} unchanged
# @return [Hash]
#
def self.prepare_service_settings(settings)
if settings.is_a? Hash
copy = Array.new
settings.each do |key, value|
obj = ![:headers].include?(key) ? self.prepare_service_settings(value) : value
copy.push(key.to_sym, obj)
end
Hash[*copy]
else
settings
end
end
end
......@@ -2,8 +2,9 @@ module Fog
def self.wait_for(timeout=Fog.timeout, interval=Fog.interval, &block)
duration = 0
start = Time.now
retries = 0
until yield || duration > timeout
sleep(interval.to_f)
sleep(interval.respond_to?(:call) ? interval.call(retries += 1).to_f : interval.to_f)
duration = Time.now - start
end
if duration > timeout
......
module Fog
@interval = 1
@interval = lambda { |retries| [2 ** (retries - 1), @max_interval].min }
def self.interval
@interval
end
def self.interval=(interval)
raise ArgumentError, "interval must be non-negative" unless interval >= 0
if interval.kind_of?(Proc)
raise ArgumentError, "interval proc must return a positive" unless interval.call(1) >= 0
else
raise ArgumentError, "interval must be non-negative" unless interval >= 0
end
@interval = interval
end
......@@ -18,4 +22,14 @@ module Fog
raise ArgumentError, "timeout must be non-negative" unless timeout >= 0
@timeout = timeout
end
@max_interval = 60
def self.max_interval
@max_interval
end
def self.max_interval=(interval)
raise ArgumentError, "interval must be non-negative" unless interval >= 0
@max_interval = interval
end
end
......@@ -7,22 +7,22 @@ module Fog
def self.new(attributes)
attributes = attributes.dup # Prevent delete from having side effects
case provider = attributes.delete(:provider).to_s.downcase.to_sym
when :rackspace
require 'fog/rackspace/identity'
Fog::Rackspace::Identity.new(attributes)
else
if self.providers.include?(provider)
require "fog/#{provider}/identity"
return Fog::Identity.const_get(Fog.providers[provider]).new(attributes)
end
provider = attributes.delete(:provider).to_s.downcase.to_sym
unless providers.include?(provider)
raise ArgumentError.new("#{provider} has no identity service")
end
require "fog/#{provider}/identity"
begin
Fog::Identity.const_get(Fog.providers[provider]).new(attributes)
rescue
Fog::const_get(Fog.providers[provider]).const_get("Identity").new(attributes)
end
end
def self.providers
Fog.services[:identity]
end
end
end
......@@ -19,10 +19,14 @@ module Fog
else
if self.providers.include?(provider)
require "fog/#{provider}/storage"
return Fog::Storage.const_get(Fog.providers[provider]).new(attributes)
begin
Fog::Storage.const_get(Fog.providers[provider])
rescue
Fog::const_get(Fog.providers[provider])::Storage
end.new(attributes)
else