mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Changes to rely on fog-core
This references `fog-core` and removes the files it now contains.
This commit is contained in:
parent
e759687e03
commit
ee091cc992
27 changed files with 15 additions and 1845 deletions
1
Gemfile
1
Gemfile
|
@ -5,4 +5,5 @@ group :development, :test do
|
|||
gem 'coveralls', :require => false
|
||||
end
|
||||
|
||||
gem "fog-core", :github => "fog/fog-core", :branch => "master"
|
||||
gemspec
|
||||
|
|
|
@ -41,6 +41,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
## List your runtime dependencies here. Runtime dependencies are those
|
||||
## that are needed for an end user to actually USE your code.
|
||||
s.add_dependency("fog-core")
|
||||
s.add_dependency('builder')
|
||||
s.add_dependency('excon', '~>0.31.0')
|
||||
s.add_dependency('formatador', '~>0.2.0')
|
||||
|
|
13
lib/fog.rb
13
lib/fog.rb
|
@ -3,6 +3,19 @@
|
|||
__LIB_DIR__ = File.expand_path(File.dirname(__FILE__))
|
||||
$LOAD_PATH.unshift __LIB_DIR__ unless $LOAD_PATH.include?(__LIB_DIR__)
|
||||
|
||||
# Use core
|
||||
require 'fog/core'
|
||||
|
||||
# Previously treated as "core"
|
||||
# data exchange specific (to be extracted and used on a per provider basis)
|
||||
require 'fog/xml'
|
||||
require 'fog/json'
|
||||
require 'fog/core/parser'
|
||||
|
||||
# deprecation wrappers (XML wrapped version)
|
||||
require 'fog/core/deprecated/connection'
|
||||
require 'fog/core/deprecated_connection_accessors'
|
||||
|
||||
# any one of these can be required separately.
|
||||
# they all depend on fog/core for shared functionality.
|
||||
require 'fog/atmos'
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
module Fog
|
||||
module CDN
|
||||
|
||||
def self.[](provider)
|
||||
self.new(:provider => provider)
|
||||
end
|
||||
|
||||
def self.new(attributes)
|
||||
attributes = attributes.dup # prevent delete from having side effects
|
||||
provider = attributes.delete(:provider).to_s.downcase.to_sym
|
||||
if self.providers.include?(provider)
|
||||
require "fog/#{provider}/cdn"
|
||||
return Fog::CDN.const_get(Fog.providers[provider]).new(attributes)
|
||||
end
|
||||
raise ArgumentError.new("#{provider} is not a recognized cdn provider")
|
||||
end
|
||||
|
||||
def self.providers
|
||||
Fog.services[:cdn]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,80 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
|
||||
def self.[](provider)
|
||||
self.new(:provider => provider)
|
||||
end
|
||||
|
||||
def self.new(attributes)
|
||||
attributes = attributes.dup # prevent delete from having side effects
|
||||
provider = attributes.delete(:provider).to_s.downcase.to_sym
|
||||
|
||||
|
||||
case provider
|
||||
when :gogrid
|
||||
require 'fog/go_grid/compute'
|
||||
Fog::Compute::GoGrid.new(attributes)
|
||||
when :hp
|
||||
version = attributes.delete(:version)
|
||||
version = version.to_s.downcase.to_sym unless version.nil?
|
||||
if version == :v2
|
||||
require 'fog/hp/compute_v2'
|
||||
Fog::Compute::HPV2.new(attributes)
|
||||
else
|
||||
Fog::Logger.deprecation "HP Cloud Compute V1 service will be soon deprecated. Please use `:version => v2` attribute to use HP Cloud Compute V2 service."
|
||||
require 'fog/hp/compute'
|
||||
Fog::Compute::HP.new(attributes)
|
||||
end
|
||||
when :new_servers
|
||||
require 'fog/bare_metal_cloud/compute'
|
||||
Fog::Logger.deprecation "`new_servers` is deprecated. Please use `bare_metal_cloud` instead."
|
||||
Fog::Compute::BareMetalCloud.new(attributes)
|
||||
when :baremetalcloud
|
||||
require 'fog/bare_metal_cloud/compute'
|
||||
Fog::Compute::BareMetalCloud.new(attributes)
|
||||
when :rackspace
|
||||
version = attributes.delete(:version)
|
||||
version = version.to_s.downcase.to_sym unless version.nil?
|
||||
if version == :v1
|
||||
Fog::Logger.deprecation "First Gen Cloud Servers are deprecated. Please use `:version => :v2` attribute to use Next Gen Cloud Servers."
|
||||
require 'fog/rackspace/compute'
|
||||
Fog::Compute::Rackspace.new(attributes)
|
||||
else
|
||||
require 'fog/rackspace/compute_v2'
|
||||
Fog::Compute::RackspaceV2.new(attributes)
|
||||
end
|
||||
when :stormondemand
|
||||
require 'fog/storm_on_demand/compute'
|
||||
Fog::Compute::StormOnDemand.new(attributes)
|
||||
when :vcloud
|
||||
require 'fog/vcloud/compute'
|
||||
Fog::Vcloud::Compute.new(attributes)
|
||||
when :vclouddirector
|
||||
require 'fog/vcloud_director/compute'
|
||||
Fog::Compute::VcloudDirector.new(attributes)
|
||||
else
|
||||
if self.providers.include?(provider)
|
||||
require "fog/#{provider}/compute"
|
||||
return Fog::Compute.const_get(Fog.providers[provider]).new(attributes)
|
||||
end
|
||||
raise ArgumentError.new("#{provider} is not a recognized compute provider")
|
||||
end
|
||||
end
|
||||
|
||||
def self.providers
|
||||
Fog.services[:compute]
|
||||
end
|
||||
|
||||
def self.servers
|
||||
servers = []
|
||||
for provider in self.providers
|
||||
begin
|
||||
servers.concat(self[provider].servers)
|
||||
rescue # ignore any missing credentials/etc
|
||||
end
|
||||
end
|
||||
servers
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,104 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Server < Fog::Model
|
||||
|
||||
attr_writer :username, :private_key, :private_key_path, :public_key, :public_key_path, :ssh_port, :ssh_options
|
||||
|
||||
def username
|
||||
@username ||= 'root'
|
||||
end
|
||||
|
||||
def private_key_path
|
||||
@private_key_path ||= Fog.credentials[:private_key_path]
|
||||
@private_key_path &&= File.expand_path(@private_key_path)
|
||||
end
|
||||
|
||||
def private_key
|
||||
@private_key ||= private_key_path && File.read(private_key_path)
|
||||
end
|
||||
|
||||
def public_key_path
|
||||
@public_key_path ||= Fog.credentials[:public_key_path]
|
||||
@public_key_path &&= File.expand_path(@public_key_path)
|
||||
end
|
||||
|
||||
def public_key
|
||||
@public_key ||= public_key_path && File.read(public_key_path)
|
||||
end
|
||||
|
||||
# Port used for ssh/scp interactions with server.
|
||||
# @return [Integer] IP port
|
||||
# @note By default this returns 22
|
||||
def ssh_port
|
||||
@ssh_port ||= 22
|
||||
end
|
||||
|
||||
# Sets the proc used to determine the IP Address used for ssh/scp interactions.
|
||||
# @example
|
||||
# service.servers.bootstrap :name => 'bootstrap-server',
|
||||
# :flavor_id => service.flavors.first.id,
|
||||
# :image_id => service.images.find {|img| img.name =~ /Ubuntu/}.id,
|
||||
# :public_key_path => '~/.ssh/fog_rsa.pub',
|
||||
# :private_key_path => '~/.ssh/fog_rsa',
|
||||
# :ssh_ip_address => Proc.new {|server| server.private_ip_address }
|
||||
#
|
||||
# @note By default scp/ssh will use the public_ip_address if this proc is not set.
|
||||
def ssh_ip_address=(proc)
|
||||
@ssh_ip_address = proc
|
||||
end
|
||||
|
||||
# IP Address used for ssh/scp interactions with server.
|
||||
# @return [String] IP Address
|
||||
# @note By default this returns the public_ip_address
|
||||
def ssh_ip_address
|
||||
return public_ip_address unless @ssh_ip_address
|
||||
return @ssh_ip_address.call(self) if @ssh_ip_address.is_a?(Proc)
|
||||
@ssh_ip_address
|
||||
end
|
||||
|
||||
def ssh_options
|
||||
@ssh_options ||= {}
|
||||
ssh_options = @ssh_options.merge({:port => ssh_port})
|
||||
if private_key
|
||||
ssh_options[:key_data] = [private_key]
|
||||
ssh_options[:auth_methods] = ["publickey"]
|
||||
end
|
||||
ssh_options
|
||||
end
|
||||
|
||||
def scp(local_path, remote_path, upload_options = {})
|
||||
require 'net/scp'
|
||||
requires :ssh_ip_address, :username
|
||||
|
||||
Fog::SCP.new(ssh_ip_address, username, ssh_options).upload(local_path, remote_path, upload_options)
|
||||
end
|
||||
|
||||
alias_method :scp_upload, :scp
|
||||
|
||||
def scp_download(remote_path, local_path, download_options = {})
|
||||
require 'net/scp'
|
||||
requires :ssh_ip_address, :username
|
||||
|
||||
Fog::SCP.new(ssh_ip_address, username, ssh_options).download(remote_path, local_path, download_options)
|
||||
end
|
||||
|
||||
def ssh(commands, options={}, &blk)
|
||||
require 'net/ssh'
|
||||
requires :ssh_ip_address, :username
|
||||
|
||||
options = ssh_options.merge(options)
|
||||
|
||||
Fog::SSH.new(ssh_ip_address, username, options).run(commands, &blk)
|
||||
end
|
||||
|
||||
def sshable?(options={})
|
||||
ready? && !ssh_ip_address.nil? && !!Timeout::timeout(8) { ssh('pwd', options) }
|
||||
rescue SystemCallError, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Timeout::Error
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,52 +0,0 @@
|
|||
# external core dependencies
|
||||
require 'base64'
|
||||
require 'cgi'
|
||||
require 'uri'
|
||||
require 'excon'
|
||||
require 'fileutils'
|
||||
require 'formatador'
|
||||
require 'openssl'
|
||||
require 'time'
|
||||
require 'timeout'
|
||||
require 'ipaddr'
|
||||
|
||||
# internal core dependencies
|
||||
require "fog/version"
|
||||
require 'fog/core/attributes'
|
||||
require 'fog/core/collection'
|
||||
require 'fog/core/connection'
|
||||
require 'fog/core/credentials'
|
||||
require 'fog/core/current_machine'
|
||||
require 'fog/core/deprecation'
|
||||
require 'fog/core/errors'
|
||||
require 'fog/core/hmac'
|
||||
require 'fog/core/logger'
|
||||
require 'fog/core/model'
|
||||
require 'fog/core/mock'
|
||||
require 'fog/core/provider'
|
||||
require 'fog/core/service'
|
||||
require 'fog/core/ssh'
|
||||
require 'fog/core/scp'
|
||||
require 'fog/core/time'
|
||||
require 'fog/core/wait_for'
|
||||
require 'fog/core/wait_for_defaults'
|
||||
require 'fog/core/class_from_string'
|
||||
require 'fog/core/uuid'
|
||||
|
||||
# data exchange specific (to be extracted and used on a per provider basis)
|
||||
require 'fog/xml'
|
||||
require 'fog/json'
|
||||
|
||||
# deprecation wrappers
|
||||
require 'fog/core/deprecated/connection'
|
||||
|
||||
# service wrappers
|
||||
require 'fog/compute'
|
||||
require 'fog/identity'
|
||||
require 'fog/image'
|
||||
require 'fog/volume'
|
||||
require 'fog/cdn'
|
||||
require 'fog/dns'
|
||||
require 'fog/network'
|
||||
require 'fog/storage'
|
||||
require 'fog/orchestration'
|
|
@ -1,227 +0,0 @@
|
|||
module Fog
|
||||
module Attributes
|
||||
module ClassMethods
|
||||
|
||||
def _load(marshalled)
|
||||
new(Marshal.load(marshalled))
|
||||
end
|
||||
|
||||
def aliases
|
||||
@aliases ||= {}
|
||||
end
|
||||
|
||||
def attributes
|
||||
@attributes ||= []
|
||||
end
|
||||
|
||||
def attribute(name, options = {})
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}
|
||||
attributes[:#{name}]
|
||||
end
|
||||
EOS
|
||||
case options[:type]
|
||||
when :boolean
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = case new_#{name}
|
||||
when true,'true'
|
||||
true
|
||||
when false,'false'
|
||||
false
|
||||
end
|
||||
end
|
||||
EOS
|
||||
when :float
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = new_#{name}.to_f
|
||||
end
|
||||
EOS
|
||||
when :integer
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = new_#{name}.to_i
|
||||
end
|
||||
EOS
|
||||
when :string
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = new_#{name}.to_s
|
||||
end
|
||||
EOS
|
||||
when :time
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = if new_#{name}.nil? || new_#{name} == "" || new_#{name}.is_a?(Time)
|
||||
new_#{name}
|
||||
else
|
||||
Time.parse(new_#{name})
|
||||
end
|
||||
end
|
||||
EOS
|
||||
when :timestamp
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = Time.at(new_#{name}.to_i)
|
||||
end
|
||||
EOS
|
||||
when :array
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = [*new_#{name}]
|
||||
end
|
||||
EOS
|
||||
else
|
||||
if squash = options[:squash]
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_data)
|
||||
if new_data.is_a?(Hash)
|
||||
if new_data.has_key?(:'#{squash}')
|
||||
attributes[:#{name}] = new_data[:'#{squash}']
|
||||
elsif new_data.has_key?("#{squash}")
|
||||
attributes[:#{name}] = new_data["#{squash}"]
|
||||
else
|
||||
attributes[:#{name}] = [ new_data ]
|
||||
end
|
||||
else
|
||||
attributes[:#{name}] = new_data
|
||||
end
|
||||
end
|
||||
EOS
|
||||
else
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{name}=(new_#{name})
|
||||
attributes[:#{name}] = new_#{name}
|
||||
end
|
||||
EOS
|
||||
end
|
||||
end
|
||||
@attributes ||= []
|
||||
@attributes |= [name]
|
||||
for new_alias in [*options[:aliases]]
|
||||
aliases[new_alias] = name
|
||||
end
|
||||
end
|
||||
|
||||
def identity(name, options = {})
|
||||
@identity = name
|
||||
self.attribute(name, options)
|
||||
end
|
||||
|
||||
def ignore_attributes(*args)
|
||||
@ignored_attributes = args.collect {|attr| attr.to_s }
|
||||
end
|
||||
|
||||
def ignored_attributes
|
||||
@ignored_attributes ||= []
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def _dump(level)
|
||||
Marshal.dump(attributes)
|
||||
end
|
||||
|
||||
def attributes
|
||||
@attributes ||= {}
|
||||
end
|
||||
|
||||
def dup
|
||||
copy = super
|
||||
copy.dup_attributes!
|
||||
copy
|
||||
end
|
||||
|
||||
def identity
|
||||
send(self.class.instance_variable_get('@identity'))
|
||||
end
|
||||
|
||||
def identity=(new_identity)
|
||||
send("#{self.class.instance_variable_get('@identity')}=", new_identity)
|
||||
end
|
||||
|
||||
def merge_attributes(new_attributes = {})
|
||||
for key, value in new_attributes
|
||||
unless self.class.ignored_attributes.include?(key)
|
||||
if aliased_key = self.class.aliases[key]
|
||||
send("#{aliased_key}=", value)
|
||||
elsif self.respond_to?("#{key}=",true)
|
||||
send("#{key}=", value)
|
||||
else
|
||||
attributes[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# Returns true if a remote resource has been assigned an
|
||||
# identity and we can assume it has been persisted.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def persisted?
|
||||
!!identity
|
||||
end
|
||||
|
||||
# Returns true if a remote resource has not been assigned an
|
||||
# identity.
|
||||
#
|
||||
# This was added for a ActiveRecord like feel but has been
|
||||
# outdated by ActiveModel API using {#persisted?}
|
||||
#
|
||||
# @deprecated Use inverted form of {#persisted?}
|
||||
# @return [Boolean]
|
||||
def new_record?
|
||||
Fog::Logger.deprecation("#new_record? is deprecated, use !persisted? instead [light_black](#{caller.first})[/]")
|
||||
!persisted?
|
||||
end
|
||||
|
||||
# check that the attributes specified in args exist and is not nil
|
||||
def requires(*args)
|
||||
missing = missing_attributes(args)
|
||||
if missing.length == 1
|
||||
raise(ArgumentError, "#{missing.first} is required for this operation")
|
||||
elsif missing.any?
|
||||
raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
|
||||
end
|
||||
end
|
||||
|
||||
def requires_one(*args)
|
||||
missing = missing_attributes(args)
|
||||
if missing.length == args.length
|
||||
raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def missing_attributes(args)
|
||||
missing = []
|
||||
for arg in [:service] | args
|
||||
unless send("#{arg}") || attributes.has_key?(arg)
|
||||
missing << arg
|
||||
end
|
||||
end
|
||||
missing
|
||||
end
|
||||
|
||||
def dup_attributes!
|
||||
@attributes = @attributes.dup if @attributes
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def remap_attributes(attributes, mapping)
|
||||
for key, value in mapping
|
||||
if attributes.key?(key)
|
||||
attributes[value] = attributes.delete(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
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
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
require "fog/core/deprecated_connection_accessors"
|
||||
|
||||
module Fog
|
||||
class Collection < Array
|
||||
extend Fog::Attributes::ClassMethods
|
||||
include Fog::Attributes::InstanceMethods
|
||||
include Fog::Core::DeprecatedConnectionAccessors
|
||||
|
||||
attr_reader :service
|
||||
|
||||
Array.public_instance_methods(false).each do |method|
|
||||
unless [:reject, :select, :slice, :clear, :inspect].include?(method.to_sym)
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{method}(*args)
|
||||
unless @loaded
|
||||
lazy_load
|
||||
end
|
||||
super
|
||||
end
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
%w[reject select slice].each do |method|
|
||||
class_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{method}(*args)
|
||||
unless @loaded
|
||||
lazy_load
|
||||
end
|
||||
data = super
|
||||
self.clone.clear.concat(data)
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def self.model(new_model=nil)
|
||||
if new_model == nil
|
||||
@model
|
||||
else
|
||||
@model = new_model
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@loaded = true
|
||||
super
|
||||
end
|
||||
|
||||
def create(attributes = {})
|
||||
object = new(attributes)
|
||||
object.save
|
||||
object
|
||||
end
|
||||
|
||||
def destroy(identity)
|
||||
object = new(:identity => identity)
|
||||
object.destroy
|
||||
end
|
||||
|
||||
# Creates a new Fog::Collection based around the passed service
|
||||
#
|
||||
# @param [Hash] attributes
|
||||
# @option attributes [Fog::Service] service Instance of a service
|
||||
#
|
||||
# @return [Fog::Collection]
|
||||
#
|
||||
def initialize(attributes = {})
|
||||
@service = attributes.delete(:service)
|
||||
@loaded = false
|
||||
merge_attributes(attributes)
|
||||
end
|
||||
|
||||
|
||||
def inspect
|
||||
Thread.current[:formatador] ||= Formatador.new
|
||||
data = "#{Thread.current[:formatador].indentation}<#{self.class.name}\n"
|
||||
Thread.current[:formatador].indent do
|
||||
unless self.class.attributes.empty?
|
||||
data << "#{Thread.current[:formatador].indentation}"
|
||||
data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
|
||||
data << "\n"
|
||||
end
|
||||
data << "#{Thread.current[:formatador].indentation}["
|
||||
unless self.empty?
|
||||
data << "\n"
|
||||
Thread.current[:formatador].indent do
|
||||
data << self.map {|member| member.inspect}.join(",\n")
|
||||
data << "\n"
|
||||
end
|
||||
data << Thread.current[:formatador].indentation
|
||||
end
|
||||
data << "]\n"
|
||||
end
|
||||
data << "#{Thread.current[:formatador].indentation}>"
|
||||
data
|
||||
end
|
||||
|
||||
def load(objects)
|
||||
clear
|
||||
for object in objects
|
||||
self << new(object)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def model
|
||||
self.class.instance_variable_get('@model')
|
||||
end
|
||||
|
||||
def new(attributes = {})
|
||||
unless attributes.is_a?(::Hash)
|
||||
raise(ArgumentError.new("Initialization parameters must be an attributes hash, got #{attributes.class} #{attributes.inspect}"))
|
||||
end
|
||||
model.new(
|
||||
{
|
||||
:collection => self,
|
||||
:service => service
|
||||
}.merge(attributes)
|
||||
)
|
||||
end
|
||||
|
||||
def reload
|
||||
clear
|
||||
lazy_load
|
||||
self
|
||||
end
|
||||
|
||||
def table(attributes = nil)
|
||||
Formatador.display_table(self.map {|instance| instance.attributes}, attributes)
|
||||
end
|
||||
|
||||
def to_json(options = {})
|
||||
Fog::JSON.encode(self.map {|member| member.attributes})
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lazy_load
|
||||
self.all
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Base class for collection classes whose 'all' method returns only a single page of results and passes the
|
||||
# 'Marker' option along as self.filters[:marker]
|
||||
class PagedCollection < Collection
|
||||
|
||||
def each(filters=filters)
|
||||
if block_given?
|
||||
begin
|
||||
page = self.all(filters)
|
||||
# We need to explicitly use the base 'each' method here on the page, otherwise we get infinite recursion
|
||||
base_each = Fog::Collection.instance_method(:each)
|
||||
base_each.bind(page).call { |item| yield item }
|
||||
end while self.filters[:marker]
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,72 +0,0 @@
|
|||
module Fog
|
||||
module Core
|
||||
|
||||
# Fog::Core::Connection is a generic class to contain a HTTP link to an API.
|
||||
#
|
||||
# It is intended to be subclassed by providers who can then add their own
|
||||
# modifications such as authentication or response object.
|
||||
#
|
||||
class Connection
|
||||
# Prepares the connection and sets defaults for any future requests.
|
||||
#
|
||||
# @param [String] url The destination URL
|
||||
# @param persistent [Boolean]
|
||||
# @param [Hash] params
|
||||
# @option params [String] :body Default text to be sent over a socket. Only used if :body absent in Connection#request params
|
||||
# @option params [Hash<Symbol, String>] :headers The default headers to supply in a request. Only used if params[:headers] is not supplied to Connection#request
|
||||
# @option params [String] :host The destination host's reachable DNS name or IP, in the form of a String
|
||||
# @option params [String] :path Default path; appears after 'scheme://host:port/'. Only used if params[:path] is not supplied to Connection#request
|
||||
# @option params [Fixnum] :port The port on which to connect, to the destination host
|
||||
# @option params [Hash] :query Default query; appended to the 'scheme://host:port/path/' in the form of '?key=value'. Will only be used if params[:query] is not supplied to Connection#request
|
||||
# @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
|
||||
# @option params [String] :proxy Proxy server; e.g. 'http://myproxy.com:8888'
|
||||
# @option params [Fixnum] :retry_limit Set how many times we'll retry a failed request. (Default 4)
|
||||
# @option params [Class] :instrumentor Responds to #instrument as in ActiveSupport::Notifications
|
||||
# @option params [String] :instrumentor_name Name prefix for #instrument events. Defaults to 'excon'
|
||||
#
|
||||
def initialize(url, persistent=false, params={})
|
||||
unless params.has_key?(:debug_response)
|
||||
params[:debug_response] = true
|
||||
end
|
||||
params[:headers] ||= {}
|
||||
params[:headers]['User-Agent'] ||= "fog/#{Fog::VERSION}"
|
||||
params.merge!(:persistent => params.fetch(:persistent, persistent))
|
||||
@excon = Excon.new(url, params)
|
||||
end
|
||||
|
||||
# Makes a request using the connection using Excon
|
||||
#
|
||||
# @param [Hash] params
|
||||
# @option params [String] :body text to be sent over a socket
|
||||
# @option params [Hash<Symbol, String>] :headers The default headers to supply in a request
|
||||
# @option params [String] :host The destination host's reachable DNS name or IP, in the form of a String
|
||||
# @option params [String] :path appears after 'scheme://host:port/'
|
||||
# @option params [Fixnum] :port The port on which to connect, to the destination host
|
||||
# @option params [Hash] :query appended to the 'scheme://host:port/path/' in the form of '?key=value'
|
||||
# @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
|
||||
# @option params [Proc] :response_block
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
#
|
||||
# @raise [Excon::Errors::StubNotFound]
|
||||
# @raise [Excon::Errors::Timeout]
|
||||
# @raise [Excon::Errors::SocketError]
|
||||
#
|
||||
def request(params, &block)
|
||||
@excon.request(params, &block)
|
||||
end
|
||||
|
||||
# Make {#request} available even when it has been overidden by a subclass
|
||||
# to allow backwards compatibility.
|
||||
#
|
||||
alias_method :original_request, :request
|
||||
protected :original_request
|
||||
|
||||
# Closes the connection
|
||||
#
|
||||
def reset
|
||||
@excon.reset
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
require 'yaml'
|
||||
|
||||
module Fog
|
||||
require 'fog/core/deprecation'
|
||||
|
||||
# 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
|
||||
def self.credential=(new_credential)
|
||||
@credentials = nil
|
||||
@credential = new_credential && new_credential.to_sym
|
||||
end
|
||||
|
||||
# @return [String, Symbol] The credential to use in Fog
|
||||
def self.credential
|
||||
@credential ||= ( ENV["FOG_CREDENTIAL"] && ENV["FOG_CREDENTIAL"].to_sym ) || :default
|
||||
end
|
||||
|
||||
# @return [String] The path for configuration_file
|
||||
def self.credentials_path
|
||||
@credential_path ||= begin
|
||||
path = ENV["FOG_RC"] || (ENV['HOME'] && File.directory?(ENV['HOME']) && '~/.fog')
|
||||
File.expand_path(path) if path
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String] The new path for credentials file
|
||||
def self.credentials_path=(new_credentials_path)
|
||||
@credentials = nil
|
||||
@credential_path = new_credentials_path
|
||||
end
|
||||
|
||||
# @return [Hash] The credentials pulled from the configuration file
|
||||
# @raise [LoadError] Configuration unavailable in configuration file
|
||||
def self.credentials
|
||||
@credentials ||= begin
|
||||
if credentials_path && File.exists?(credentials_path)
|
||||
credentials = self.symbolize_credentials(YAML.load_file(credentials_path))
|
||||
(credentials && credentials[credential]) || Fog::Errors.missing_credentials
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Hash] The newly assigned credentials
|
||||
def self.credentials=(new_credentials)
|
||||
@credentials = new_credentials
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
require 'thread'
|
||||
module Fog
|
||||
class CurrentMachine
|
||||
@@lock = Mutex.new
|
||||
AMAZON_AWS_CHECK_IP = 'http://checkip.amazonaws.com'
|
||||
|
||||
def self.ip_address= ip_address
|
||||
@@lock.synchronize do
|
||||
@@ip_address = ip_address
|
||||
end
|
||||
end
|
||||
|
||||
# Get the ip address of the machine from which this command is run. It is
|
||||
# recommended that you surround calls to this function with a timeout block
|
||||
# to ensure optimum performance in the case where the amazonaws checkip
|
||||
# service is unavailable.
|
||||
#
|
||||
# @example Get the current ip address
|
||||
# begin
|
||||
# Timeout::timeout(5) do
|
||||
# puts "Your ip address is #{Fog::CurrentMachine.ip_address}"
|
||||
# end
|
||||
# rescue Timeout::Error
|
||||
# puts "Service timeout"
|
||||
# end
|
||||
#
|
||||
# @raise [Excon::Errors::Error] if the net/http request fails.
|
||||
def self.ip_address
|
||||
@@lock.synchronize do
|
||||
@@ip_address ||= Excon.get(AMAZON_AWS_CHECK_IP).body.chomp
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
module Fog
|
||||
module Deprecation
|
||||
|
||||
def deprecate(older, newer)
|
||||
module_eval <<-EOS, __FILE__, __LINE__
|
||||
def #{older}(*args)
|
||||
Fog::Logger.deprecation("#{self} => ##{older} is deprecated, use ##{newer} instead [light_black](#{caller.first})[/]")
|
||||
send(:#{newer}, *args)
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def self_deprecate(older, newer)
|
||||
module_eval <<-EOS, __FILE__, __LINE__
|
||||
def self.#{older}(*args)
|
||||
Fog::Logger.deprecation("#{self} => ##{older} is deprecated, use ##{newer} instead [light_black](#{caller.first})[/]")
|
||||
send(:#{newer}, *args)
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,118 +0,0 @@
|
|||
module Fog
|
||||
module Errors
|
||||
|
||||
class Error < StandardError
|
||||
attr_accessor :verbose
|
||||
|
||||
def self.slurp(error, message = nil)
|
||||
new_error = new(message || error.message)
|
||||
new_error.set_backtrace(error.backtrace)
|
||||
new_error.verbose = error.message
|
||||
new_error
|
||||
end
|
||||
end
|
||||
|
||||
class MockNotImplemented < Fog::Errors::Error; end
|
||||
|
||||
class NotFound < Fog::Errors::Error; end
|
||||
|
||||
class LoadError < LoadError; end
|
||||
|
||||
class TimeoutError< Fog::Errors::Error; end
|
||||
|
||||
class NotImplemented < Fog::Errors::Error; end
|
||||
|
||||
# @return [String] The error message that will be raised, if credentials cannot be found
|
||||
def self.missing_credentials
|
||||
missing_credentials_message = <<-YML
|
||||
Missing Credentials
|
||||
|
||||
To run as '#{Fog.credential}', add the following to your resource config file: #{Fog.credentials_path}
|
||||
An alternate file may be used by placing its path in the FOG_RC environment variable
|
||||
|
||||
#######################################################
|
||||
# Fog Credentials File
|
||||
#
|
||||
# Key-value pairs should look like:
|
||||
# :aws_access_key_id: 022QF06E7MXBSAMPLE
|
||||
:#{Fog.credential}:
|
||||
:aws_access_key_id:
|
||||
:aws_secret_access_key:
|
||||
:bluebox_api_key:
|
||||
:bluebox_customer_id:
|
||||
:brightbox_client_id:
|
||||
:brightbox_secret:
|
||||
:clodo_api_key:
|
||||
:clodo_username:
|
||||
:go_grid_api_key:
|
||||
:go_grid_shared_secret:
|
||||
:google_client_email:
|
||||
:google_key_location:
|
||||
:google_project:
|
||||
:google_storage_access_key_id:
|
||||
:google_storage_secret_access_key:
|
||||
:hp_access_key:
|
||||
:hp_secret_key:
|
||||
:hp_tenant_id:
|
||||
:hp_avl_zone:
|
||||
:linode_api_key:
|
||||
:local_root:
|
||||
:bare_metal_cloud_password:
|
||||
:bare_metal_cloud_username:
|
||||
:public_key_path:
|
||||
:private_key_path:
|
||||
:openstack_api_key:
|
||||
:openstack_username:
|
||||
:openstack_auth_url:
|
||||
:openstack_tenant:
|
||||
:openstack_region:
|
||||
:ovirt_username:
|
||||
:ovirt_password:
|
||||
:ovirt_url:
|
||||
:libvirt_uri:
|
||||
:rackspace_api_key:
|
||||
:rackspace_username:
|
||||
:rackspace_servicenet:
|
||||
:rackspace_cdn_ssl:
|
||||
:rage4_email:
|
||||
:rage4_password:
|
||||
:riakcs_access_key_id:
|
||||
:riakcs_secret_access_key:
|
||||
:stormondemand_username:
|
||||
:stormondemand_password:
|
||||
:terremark_username:
|
||||
:terremark_password:
|
||||
:voxel_api_key:
|
||||
:voxel_api_secret:
|
||||
:zerigo_email:
|
||||
:zerigo_token:
|
||||
:dnsimple_email:
|
||||
:dnsimple_password:
|
||||
:dnsmadeeasy_api_key:
|
||||
:dnsmadeeasy_secret_key:
|
||||
:dreamhost_api_key:
|
||||
:cloudstack_host:
|
||||
:cloudstack_api_key:
|
||||
:cloudstack_secret_access_key:
|
||||
:vsphere_server:
|
||||
:vsphere_username:
|
||||
:vsphere_password:
|
||||
:libvirt_username:
|
||||
:libvirt_password:
|
||||
:libvirt_uri:
|
||||
:libvirt_ip_command:
|
||||
:ibm_username:
|
||||
:ibm_password:
|
||||
:vcloud_director_host:
|
||||
:vcloud_director_username:
|
||||
:vcloud_director_password:
|
||||
#
|
||||
# End of Fog Credentials File
|
||||
#######################################################
|
||||
|
||||
YML
|
||||
raise(Fog::Errors::LoadError.new(missing_credentials_message))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
module Fog
|
||||
class HMAC
|
||||
|
||||
def initialize(type, key)
|
||||
@key = key
|
||||
case type
|
||||
when 'sha1'
|
||||
setup_sha1
|
||||
when 'sha256'
|
||||
setup_sha256
|
||||
end
|
||||
end
|
||||
|
||||
def sign(data)
|
||||
@signer.call(data)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def setup_sha1
|
||||
@digest = OpenSSL::Digest.new('sha1')
|
||||
@signer = lambda do |data|
|
||||
OpenSSL::HMAC.digest(@digest, @key, data)
|
||||
end
|
||||
end
|
||||
|
||||
def setup_sha256
|
||||
@digest = OpenSSL::Digest.new('sha256')
|
||||
@signer = lambda do |data|
|
||||
OpenSSL::HMAC.digest(@digest, @key, data)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
module Fog
|
||||
class Logger
|
||||
|
||||
@channels = {
|
||||
:deprecation => ::STDERR,
|
||||
:warning => ::STDERR
|
||||
}
|
||||
|
||||
@channels[:debug] = ::STDERR if ENV['DEBUG']
|
||||
|
||||
def self.[](channel)
|
||||
@channels[channel]
|
||||
end
|
||||
|
||||
def self.[]=(channel, value)
|
||||
@channels[channel] = value
|
||||
end
|
||||
|
||||
def self.debug(message)
|
||||
self.write(:debug, "[light_black][fog][DEBUG] #{message}[/]\n")
|
||||
end
|
||||
|
||||
def self.deprecation(message)
|
||||
self.write(:deprecation, "[yellow][fog][DEPRECATION] #{message}[/]\n")
|
||||
end
|
||||
|
||||
def self.warning(message)
|
||||
self.write(:warning, "[yellow][fog][WARNING] #{message}[/]\n")
|
||||
end
|
||||
|
||||
def self.write(key, value)
|
||||
if channel = @channels[key]
|
||||
message = if channel.tty?
|
||||
value.gsub(Formatador::PARSE_REGEX) { "\e[#{Formatador::STYLES[$1.to_sym]}m" }.gsub(Formatador::INDENT_REGEX, '')
|
||||
else
|
||||
value.gsub(Formatador::PARSE_REGEX, '').gsub(Formatador::INDENT_REGEX, '')
|
||||
end
|
||||
channel.write(message)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,115 +0,0 @@
|
|||
module Fog
|
||||
|
||||
@mocking = false
|
||||
|
||||
def self.mock!
|
||||
@mocking = true
|
||||
end
|
||||
|
||||
def self.unmock!
|
||||
@mocking = false
|
||||
end
|
||||
|
||||
def self.mock?
|
||||
@mocking
|
||||
end
|
||||
|
||||
def self.mocking?
|
||||
@mocking
|
||||
end
|
||||
|
||||
module Mock
|
||||
|
||||
@delay = 1
|
||||
def self.delay
|
||||
@delay
|
||||
end
|
||||
|
||||
def self.delay=(new_delay)
|
||||
raise ArgumentError, "delay must be non-negative" unless new_delay >= 0
|
||||
@delay = new_delay
|
||||
end
|
||||
|
||||
def self.not_implemented(message = 'Contributions welcome!')
|
||||
raise Fog::Errors::MockNotImplemented.new(message)
|
||||
end
|
||||
|
||||
def self.random_ip(opts = {:version => :v4})
|
||||
version = opts[:version]
|
||||
if version == :v6
|
||||
bit_length = 128
|
||||
family = Socket::AF_INET6
|
||||
elsif version == :v4
|
||||
bit_length = 32
|
||||
family = Socket::AF_INET
|
||||
else
|
||||
raise ArgumentError, "Unknown IP version: #{version}"
|
||||
end
|
||||
|
||||
seed = 1 + rand((2**bit_length)-1)
|
||||
IPAddr.new(seed, family).to_s
|
||||
end
|
||||
|
||||
def self.random_base64(length)
|
||||
random_selection(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
length
|
||||
)
|
||||
end
|
||||
|
||||
def self.random_hex(length)
|
||||
max = ('f' * length).to_i(16)
|
||||
rand(max).to_s(16).rjust(length, '0')
|
||||
end
|
||||
|
||||
def self.random_letters(length)
|
||||
random_selection(
|
||||
'abcdefghijklmnopqrstuvwxyz',
|
||||
length
|
||||
)
|
||||
end
|
||||
|
||||
def self.random_numbers(length)
|
||||
max = ('9' * length).to_i
|
||||
rand(max).to_s
|
||||
end
|
||||
|
||||
def self.random_letters_and_numbers(length)
|
||||
random_selection(
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
|
||||
length
|
||||
)
|
||||
end
|
||||
|
||||
def self.random_selection(characters, length)
|
||||
selection = ''
|
||||
length.times do
|
||||
position = rand(characters.length)
|
||||
selection << characters[position..position]
|
||||
end
|
||||
selection
|
||||
end
|
||||
|
||||
def self.reset
|
||||
mocked_services = []
|
||||
Fog.constants.map do |x|
|
||||
x_const = Fog.const_get(x)
|
||||
x_const.respond_to?(:constants) && x_const.constants.map do |y|
|
||||
y_const = x_const.const_get(y)
|
||||
y_const.respond_to?(:constants) && y_const.constants.map do |z|
|
||||
if z.to_sym == :Mock
|
||||
mocked_services << y_const.const_get(z)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for mocked_service in mocked_services
|
||||
next unless mocked_service.respond_to?(:reset)
|
||||
mocked_service.reset
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -1,80 +0,0 @@
|
|||
require "fog/core/deprecated_connection_accessors"
|
||||
|
||||
module Fog
|
||||
class Model
|
||||
|
||||
extend Fog::Attributes::ClassMethods
|
||||
include Fog::Attributes::InstanceMethods
|
||||
include Fog::Core::DeprecatedConnectionAccessors
|
||||
|
||||
attr_accessor :collection
|
||||
attr_reader :service
|
||||
|
||||
def initialize(new_attributes = {})
|
||||
# TODO Remove compatibility with old connection option
|
||||
@service = new_attributes.delete(:service)
|
||||
if @service.nil? && new_attributes[:connection]
|
||||
Fog::Logger.deprecation("Passing :connection option is deprecated, use :service instead [light_black](#{caller.first})[/]")
|
||||
@service = new_attributes[:connection]
|
||||
end
|
||||
merge_attributes(new_attributes)
|
||||
end
|
||||
|
||||
def inspect
|
||||
Thread.current[:formatador] ||= Formatador.new
|
||||
data = "#{Thread.current[:formatador].indentation}<#{self.class.name}"
|
||||
Thread.current[:formatador].indent do
|
||||
unless self.class.attributes.empty?
|
||||
data << "\n#{Thread.current[:formatador].indentation}"
|
||||
data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
|
||||
end
|
||||
end
|
||||
data << "\n#{Thread.current[:formatador].indentation}>"
|
||||
data
|
||||
end
|
||||
|
||||
def reload
|
||||
requires :identity
|
||||
|
||||
return unless data = begin
|
||||
collection.get(identity)
|
||||
rescue Excon::Errors::SocketError
|
||||
nil
|
||||
end
|
||||
|
||||
new_attributes = data.attributes
|
||||
merge_attributes(new_attributes)
|
||||
self
|
||||
end
|
||||
|
||||
def to_json(options = {})
|
||||
Fog::JSON.encode(attributes)
|
||||
end
|
||||
|
||||
def symbolize_keys(hash)
|
||||
return nil if hash.nil?
|
||||
hash.inject({}) do |options, (key, value)|
|
||||
options[(key.to_sym rescue key) || key] = value
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
def wait_for(timeout=Fog.timeout, interval=1, &block)
|
||||
reload_has_succeeded = false
|
||||
duration = Fog.wait_for(timeout, interval) do # Note that duration = false if it times out
|
||||
if reload
|
||||
reload_has_succeeded = true
|
||||
instance_eval(&block)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
if reload_has_succeeded
|
||||
return duration # false if timeout; otherwise {:duration => elapsed time }
|
||||
else
|
||||
raise Fog::Errors::Error.new("Reload failed, #{self.class} #{self.identity} not present.")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
module Fog
|
||||
|
||||
def self.providers
|
||||
@providers ||= {}
|
||||
end
|
||||
|
||||
def self.providers=(new_providers)
|
||||
@providers = new_providers
|
||||
end
|
||||
|
||||
module Provider
|
||||
|
||||
def self.extended(base)
|
||||
provider = base.to_s.split('::').last
|
||||
Fog.providers[provider.downcase.to_sym] = provider
|
||||
end
|
||||
|
||||
def [](service_key)
|
||||
eval(@services_registry[service_key]).new
|
||||
end
|
||||
|
||||
def service(new_service, constant_string)
|
||||
Fog.services[new_service] ||= []
|
||||
Fog.services[new_service] |= [self.to_s.split('::').last.downcase.to_sym]
|
||||
@services_registry ||= {}
|
||||
@services_registry[new_service] = [self.to_s, constant_string].join('::')
|
||||
end
|
||||
|
||||
def services
|
||||
@services_registry.keys
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,96 +0,0 @@
|
|||
module Fog
|
||||
module SCP
|
||||
|
||||
def self.new(address, username, options = {})
|
||||
if Fog.mocking?
|
||||
Fog::SCP::Mock.new(address, username, options)
|
||||
else
|
||||
Fog::SCP::Real.new(address, username, options)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] = []
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(address, username, options)
|
||||
@address = address
|
||||
@username = username
|
||||
@options = options
|
||||
end
|
||||
|
||||
def upload(local_path, remote_path, upload_options = {})
|
||||
self.class.data[@address] << { :username => @username,
|
||||
:options => @options,
|
||||
:local_path => local_path,
|
||||
:remote_path => remote_path,
|
||||
:upload_options => upload_options }
|
||||
end
|
||||
|
||||
def download(remote_path, local_path, download_options = {})
|
||||
self.class.data[@address] << { :username => @username,
|
||||
:options => @options,
|
||||
:remote_path => remote_path,
|
||||
:local_path => local_path,
|
||||
:download_options => download_options }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Real
|
||||
|
||||
def initialize(address, username, options)
|
||||
require 'net/scp'
|
||||
|
||||
key_manager = Net::SSH::Authentication::KeyManager.new(nil, options)
|
||||
|
||||
unless options[:key_data] || options[:keys] || options[:password] || key_manager.agent
|
||||
raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH')
|
||||
end
|
||||
|
||||
options[:timeout] = 30
|
||||
if options[:key_data] || options[:keys]
|
||||
options[:keys_only] = true
|
||||
#Explicitly set these so net-ssh doesn't add the default keys
|
||||
#as seen at https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/session.rb#L131-146
|
||||
options[:keys] = [] unless options[:keys]
|
||||
options[:key_data] = [] unless options[:key_data]
|
||||
end
|
||||
|
||||
@address = address
|
||||
@username = username
|
||||
@options = { :paranoid => false }.merge(options)
|
||||
end
|
||||
|
||||
def upload(local_path, remote_path, upload_options = {}, &block)
|
||||
begin
|
||||
Net::SCP.start(@address, @username, @options) do |scp|
|
||||
scp.upload!(local_path, remote_path, upload_options) do |ch, name, sent, total|
|
||||
block.call(ch, name, sent, total) if block
|
||||
end
|
||||
end
|
||||
rescue Exception => error
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
||||
def download(remote_path, local_path, download_options = {}, &block)
|
||||
begin
|
||||
Net::SCP.start(@address, @username, @options) do |scp|
|
||||
scp.download!(remote_path, local_path, download_options) do |ch, name, sent, total|
|
||||
block.call(ch, name, sent, total) if block
|
||||
end
|
||||
end
|
||||
rescue Exception => error
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,223 +0,0 @@
|
|||
module Fog
|
||||
|
||||
def self.services
|
||||
@services ||= {}
|
||||
end
|
||||
|
||||
class Service
|
||||
|
||||
class Error < Fog::Errors::Error; end
|
||||
class NotFound < Fog::Errors::NotFound; end
|
||||
|
||||
module NoLeakInspector
|
||||
def inspect
|
||||
"#<#{self.class}:#{self.object_id} #{(self.instance_variables - service.secrets).map {|iv| [iv, self.instance_variable_get(iv).inspect].join('=')}.join(' ')}>"
|
||||
end
|
||||
end
|
||||
|
||||
module Collections
|
||||
|
||||
def collections
|
||||
service.collections
|
||||
end
|
||||
|
||||
def mocked_requests
|
||||
service.mocked_requests
|
||||
end
|
||||
|
||||
def requests
|
||||
service.requests
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class << self
|
||||
|
||||
def inherited(child)
|
||||
child.class_eval <<-EOS, __FILE__, __LINE__
|
||||
class Error < Fog::Service::Error; end
|
||||
class NotFound < Fog::Service::NotFound; end
|
||||
|
||||
module Collections
|
||||
include Fog::Service::Collections
|
||||
|
||||
def service
|
||||
#{child}
|
||||
end
|
||||
end
|
||||
|
||||
def self.service
|
||||
#{child}
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
def new(options={})
|
||||
options = Fog.symbolize_credentials(options)
|
||||
options = fetch_credentials(options).merge(options)
|
||||
validate_options(options)
|
||||
coerce_options(options)
|
||||
setup_requirements
|
||||
|
||||
if Fog.mocking?
|
||||
service::Mock.send(:include, service::Collections)
|
||||
service::Mock.new(options)
|
||||
else
|
||||
service::Real.send(:include, service::Collections)
|
||||
service::Real.send(:include, service::NoLeakInspector)
|
||||
service::Real.new(options)
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_credentials(options)
|
||||
# attempt to load credentials from config file
|
||||
begin
|
||||
Fog.credentials.reject {|key, value| !(recognized | requirements).include?(key)}
|
||||
rescue LoadError
|
||||
# if there are no configured credentials, do nothing
|
||||
{}
|
||||
end
|
||||
end
|
||||
|
||||
def setup_requirements
|
||||
if superclass.respond_to?(:setup_requirements)
|
||||
superclass.setup_requirements
|
||||
end
|
||||
|
||||
@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
|
||||
@required = true
|
||||
end
|
||||
end
|
||||
|
||||
def model_path(new_path)
|
||||
@model_path = new_path
|
||||
end
|
||||
|
||||
def collection(new_collection)
|
||||
collections << new_collection
|
||||
end
|
||||
|
||||
def collections
|
||||
@collections ||= []
|
||||
end
|
||||
|
||||
def coerce_options(options)
|
||||
options.each do |key, value|
|
||||
value_string = value.to_s.downcase
|
||||
if value.nil?
|
||||
options.delete(key)
|
||||
elsif value == value_string.to_i.to_s
|
||||
options[key] = value.to_i
|
||||
else
|
||||
options[key] = case value_string
|
||||
when 'false'
|
||||
false
|
||||
when 'true'
|
||||
true
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mocked_requests
|
||||
@mocked_requests ||= []
|
||||
end
|
||||
|
||||
def model(new_model)
|
||||
models << new_model
|
||||
end
|
||||
|
||||
def models
|
||||
@models ||= []
|
||||
end
|
||||
|
||||
def request_path(new_path)
|
||||
@request_path = new_path
|
||||
end
|
||||
|
||||
def request(new_request)
|
||||
requests << new_request
|
||||
end
|
||||
|
||||
def requests
|
||||
@requests ||= []
|
||||
end
|
||||
|
||||
def secrets(*args)
|
||||
if args.empty?
|
||||
@secrets ||= []
|
||||
else
|
||||
args.inject(secrets) do |secrets, secret|
|
||||
secrets << "@#{secret}".to_sym
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def requires(*args)
|
||||
requirements.concat(args)
|
||||
end
|
||||
|
||||
def requirements
|
||||
@requirements ||= []
|
||||
end
|
||||
|
||||
def recognizes(*args)
|
||||
recognized.concat(args)
|
||||
end
|
||||
|
||||
def recognized
|
||||
@recognized ||= [:connection_options]
|
||||
end
|
||||
|
||||
def validate_options(options)
|
||||
keys = []
|
||||
for key, value in options
|
||||
unless value.nil?
|
||||
keys << key
|
||||
end
|
||||
end
|
||||
missing = requirements - keys
|
||||
unless missing.empty?
|
||||
raise ArgumentError, "Missing required arguments: #{missing.join(', ')}"
|
||||
end
|
||||
|
||||
unless recognizes.empty?
|
||||
unrecognized = options.keys - requirements - recognized
|
||||
unless unrecognized.empty?
|
||||
Fog::Logger.warning("Unrecognized arguments: #{unrecognized.join(', ')}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
require 'delegate'
|
||||
|
||||
module Fog
|
||||
module SSH
|
||||
|
||||
def self.new(address, username, options = {})
|
||||
if Fog.mocking?
|
||||
Fog::SSH::Mock.new(address, username, options)
|
||||
else
|
||||
Fog::SSH::Real.new(address, username, options)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] = []
|
||||
end
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@data= nil
|
||||
end
|
||||
|
||||
def initialize(address, username, options)
|
||||
@address = address
|
||||
@username = username
|
||||
@options = options
|
||||
end
|
||||
|
||||
def run(commands, &blk)
|
||||
self.class.data[@address] << {:commands => commands, :username => @username, :options => @options}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Real
|
||||
|
||||
def initialize(address, username, options)
|
||||
require 'net/ssh'
|
||||
|
||||
key_manager = Net::SSH::Authentication::KeyManager.new(nil, options)
|
||||
|
||||
unless options[:key_data] || options[:keys] || options[:password] || key_manager.agent
|
||||
raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH')
|
||||
end
|
||||
|
||||
options[:timeout] ||= 30
|
||||
if options[:key_data] || options[:keys]
|
||||
options[:keys_only] = true
|
||||
#Explicitly set these so net-ssh doesn't add the default keys
|
||||
#as seen at https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/session.rb#L131-146
|
||||
options[:keys] = [] unless options[:keys]
|
||||
options[:key_data] = [] unless options[:key_data]
|
||||
end
|
||||
|
||||
@address = address
|
||||
@username = username
|
||||
@options = { :paranoid => false }.merge(options)
|
||||
end
|
||||
|
||||
def run(commands, &blk)
|
||||
commands = [*commands]
|
||||
results = []
|
||||
begin
|
||||
Net::SSH.start(@address, @username, @options) do |ssh|
|
||||
commands.each do |command|
|
||||
result = Result.new(command)
|
||||
ssh.open_channel do |ssh_channel|
|
||||
ssh_channel.request_pty
|
||||
ssh_channel.exec(command) do |channel, success|
|
||||
unless success
|
||||
raise "Could not execute command: #{command.inspect}"
|
||||
end
|
||||
|
||||
channel.on_data do |ch, data|
|
||||
result.stdout << data
|
||||
yield [data, ''] if blk
|
||||
end
|
||||
|
||||
channel.on_extended_data do |ch, type, data|
|
||||
next unless type == 1
|
||||
result.stderr << data
|
||||
yield ['', data] if blk
|
||||
end
|
||||
|
||||
channel.on_request('exit-status') do |ch, data|
|
||||
result.status = data.read_long
|
||||
end
|
||||
|
||||
channel.on_request('exit-signal') do |ch, data|
|
||||
result.status = 255
|
||||
end
|
||||
end
|
||||
end
|
||||
ssh.loop
|
||||
results << result
|
||||
end
|
||||
end
|
||||
rescue Net::SSH::HostKeyMismatch => exception
|
||||
exception.remember_host!
|
||||
sleep 0.2
|
||||
retry
|
||||
end
|
||||
results
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Result
|
||||
|
||||
attr_accessor :command, :stderr, :stdout, :status
|
||||
|
||||
def display_stdout
|
||||
data = stdout.split("\r\n")
|
||||
if data.is_a?(String)
|
||||
Formatador.display_line(data)
|
||||
elsif data.is_a?(Array)
|
||||
Formatador.display_lines(data)
|
||||
end
|
||||
end
|
||||
|
||||
def display_stderr
|
||||
Formatador.display_line(stderr.split("\r\n"))
|
||||
end
|
||||
|
||||
def initialize(command)
|
||||
@command = command
|
||||
@stderr = ''
|
||||
@stdout = ''
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
require 'time'
|
||||
|
||||
module Fog
|
||||
class Time < ::Time
|
||||
|
||||
DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
||||
MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
|
||||
def self.now
|
||||
at((::Time.now - offset).to_i)
|
||||
end
|
||||
|
||||
def self.now=(new_now)
|
||||
old_now = ::Time.now
|
||||
@offset = old_now - new_now
|
||||
new_now
|
||||
end
|
||||
|
||||
def self.offset
|
||||
@offset ||= 0
|
||||
end
|
||||
|
||||
def to_date_header
|
||||
self.utc.strftime("#{DAYS[self.utc.wday]}, %d #{MONTHS[self.utc.month - 1]} %Y %H:%M:%S +0000")
|
||||
end
|
||||
|
||||
def to_iso8601_basic
|
||||
self.utc.strftime('%Y%m%dT%H%M%SZ')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
require 'securerandom'
|
||||
|
||||
module Fog
|
||||
class UUID
|
||||
class << self
|
||||
|
||||
def uuid
|
||||
if supported?
|
||||
SecureRandom.uuid
|
||||
else
|
||||
ary = SecureRandom.random_bytes(16).unpack("NnnnnN")
|
||||
ary[2] = (ary[2] & 0x0fff) | 0x4000
|
||||
ary[3] = (ary[3] & 0x3fff) | 0x8000
|
||||
"%08x-%04x-%04x-%04x-%04x%08x" % ary
|
||||
end
|
||||
end
|
||||
|
||||
def supported?
|
||||
SecureRandom.respond_to?(:uuid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
def self.wait_for(timeout=Fog.timeout, interval=Fog.interval, &block)
|
||||
duration = 0
|
||||
start = Time.now
|
||||
until yield || duration > timeout
|
||||
sleep(interval.to_f)
|
||||
duration = Time.now - start
|
||||
end
|
||||
if duration > timeout
|
||||
raise Errors::TimeoutError.new("The specified wait_for timeout (#{timeout} seconds) was exceeded")
|
||||
else
|
||||
{ :duration => duration }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
module Fog
|
||||
@interval = 1
|
||||
def self.interval
|
||||
@interval
|
||||
end
|
||||
|
||||
def self.interval=(interval)
|
||||
raise ArgumentError, "interval must be non-negative" unless interval >= 0
|
||||
@interval = interval
|
||||
end
|
||||
|
||||
@timeout = 600
|
||||
def self.timeout
|
||||
@timeout
|
||||
end
|
||||
|
||||
def self.timeout=(timeout)
|
||||
raise ArgumentError, "timeout must be non-negative" unless timeout >= 0
|
||||
@timeout = timeout
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue