mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Merge branch 'master' of github.com:fog/fog into reauth
This commit is contained in:
commit
553f848256
70 changed files with 1437 additions and 454 deletions
|
@ -6,7 +6,7 @@ rvm:
|
|||
- 1.9.3
|
||||
- 2.0.0
|
||||
|
||||
script: FOG_MOCK=true bundle exec shindont
|
||||
script: bundle exec rake travis
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -1,3 +1,8 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
group :development, :test do
|
||||
# This is here because gemspec doesn't support require: false
|
||||
gem 'coveralls', :require => false
|
||||
end
|
||||
|
||||
gemspec
|
||||
|
|
18
Rakefile
18
Rakefile
|
@ -47,20 +47,21 @@ end
|
|||
|
||||
GEM_NAME = "#{name}"
|
||||
task :default => :test
|
||||
task :travis => ['test:travis', 'coveralls_push_workaround']
|
||||
|
||||
require "tasks/test_task"
|
||||
Fog::Rake::TestTask.new
|
||||
|
||||
namespace :test do
|
||||
mock = 'true' || ENV['FOG_MOCK']
|
||||
task :travis do
|
||||
sh("export FOG_MOCK=#{mock} && bundle exec shindont")
|
||||
end
|
||||
task :vsphere do
|
||||
[true].each do |mock|
|
||||
sh("export FOG_MOCK=#{mock} && bundle exec shindont tests/vsphere")
|
||||
end
|
||||
end
|
||||
task :openvz do
|
||||
[true].each do |mock|
|
||||
sh("export FOG_MOCK=#{mock} && bundle exec shindont tests/openvz")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -186,3 +187,12 @@ end
|
|||
|
||||
require "tasks/changelog_task"
|
||||
Fog::Rake::ChangelogTask.new
|
||||
|
||||
task :coveralls_push_workaround do
|
||||
ENV['COVERAGE'] = 'false' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9')
|
||||
unless ENV['COVERAGE'] == 'false'
|
||||
require 'coveralls/rake/task'
|
||||
Coveralls::RakeTask.new
|
||||
Rake::Task["coveralls:push"].invoke
|
||||
end
|
||||
end
|
22
bin/fog
22
bin/fog
|
@ -1,7 +1,29 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'fog'))
|
||||
require 'optparse'
|
||||
require 'irb'
|
||||
require 'yaml'
|
||||
|
||||
options = OptionParser.new do |opts|
|
||||
opts.banner = 'usage: fog [options] CREDENTIAL'
|
||||
|
||||
opts.on('-C', '--credentials-path FILE', 'Path to the credentials file') do |file|
|
||||
Fog.credentials_path = file
|
||||
end
|
||||
|
||||
opts.on_tail('-V', '--version', 'Prints the version') do
|
||||
puts Fog::VERSION
|
||||
exit
|
||||
end
|
||||
|
||||
opts.on_tail('-h', '--help', 'Prints this message') do
|
||||
puts opts
|
||||
exit
|
||||
end
|
||||
end
|
||||
options.parse!
|
||||
|
||||
Fog.credential = ARGV.first ? ARGV.first.to_sym : nil
|
||||
Fog.mock! if ENV['FOG_MOCK']
|
||||
if Fog.credentials.empty?
|
||||
|
|
|
@ -41,7 +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('builder')
|
||||
s.add_dependency('excon', '~>0.24.0')
|
||||
s.add_dependency('excon', '~>0.25.0')
|
||||
s.add_dependency('formatador', '~>0.2.0')
|
||||
s.add_dependency('multi_json', '~>1.0')
|
||||
s.add_dependency('mime-types')
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'fog/core/json'
|
||||
require "fog/json"
|
||||
|
||||
module Fog
|
||||
module AWS
|
||||
module CredentialFetcher
|
||||
|
@ -14,7 +15,7 @@ module Fog
|
|||
|
||||
session = Fog::JSON.decode(role_data)
|
||||
credentials = {}
|
||||
credentials[:aws_access_key_id] = session['AccessKeyId']
|
||||
credentials[:aws_access_key_id] = session['AccessKeyId']
|
||||
credentials[:aws_secret_access_key] = session['SecretAccessKey']
|
||||
credentials[:aws_session_token] = session['Token']
|
||||
credentials[:aws_credentials_expire_at] = Time.xmlschema session['Expiration']
|
||||
|
@ -31,7 +32,7 @@ module Fog
|
|||
end
|
||||
|
||||
module ConnectionMethods
|
||||
|
||||
|
||||
def refresh_credentials_if_expired
|
||||
refresh_credentials if credentials_expired?
|
||||
end
|
||||
|
@ -39,8 +40,8 @@ module Fog
|
|||
private
|
||||
|
||||
def credentials_expired?
|
||||
@use_iam_profile &&
|
||||
(!@aws_credentials_expire_at ||
|
||||
@use_iam_profile &&
|
||||
(!@aws_credentials_expire_at ||
|
||||
(@aws_credentials_expire_at && Fog::Time.now > @aws_credentials_expire_at - 15)) #new credentials become available from around 5 minutes before expiration time
|
||||
end
|
||||
|
||||
|
@ -61,4 +62,3 @@ module Fog
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
require 'fog/brightbox'
|
||||
require 'fog/compute'
|
||||
require 'fog/brightbox/oauth2'
|
||||
require 'fog/brightbox/compute/shared'
|
||||
require 'fog/brightbox/compute/image_selector'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Brightbox < Fog::Service
|
||||
|
||||
API_URL = "https://api.gb1.brightbox.com/"
|
||||
|
||||
# Client credentials
|
||||
requires :brightbox_client_id, :brightbox_secret
|
||||
|
||||
|
@ -34,6 +32,8 @@ module Fog
|
|||
model :application
|
||||
collection :api_clients
|
||||
model :api_client
|
||||
collection :collaborations
|
||||
model :collaboration
|
||||
collection :servers
|
||||
model :server
|
||||
collection :server_groups
|
||||
|
@ -54,17 +54,22 @@ module Fog
|
|||
model :cloud_ip
|
||||
collection :users
|
||||
model :user
|
||||
collection :user_collaborations
|
||||
model :user_collaboration
|
||||
|
||||
request_path 'fog/brightbox/requests/compute'
|
||||
request :accept_user_collaboration
|
||||
request :activate_console_server
|
||||
request :add_listeners_load_balancer
|
||||
request :add_nodes_load_balancer
|
||||
request :add_servers_server_group
|
||||
request :apply_to_firewall_policy
|
||||
request :accept_user_collaboration
|
||||
request :remove_firewall_policy
|
||||
request :create_api_client
|
||||
request :create_application
|
||||
request :create_cloud_ip
|
||||
request :create_collaboration
|
||||
request :create_firewall_policy
|
||||
request :create_firewall_rule
|
||||
request :create_image
|
||||
|
@ -74,17 +79,20 @@ module Fog
|
|||
request :delete_api_client
|
||||
request :delete_application
|
||||
request :delete_cloud_ip
|
||||
request :delete_collaboration
|
||||
request :delete_firewall_policy
|
||||
request :delete_firewall_rule
|
||||
request :delete_image
|
||||
request :delete_load_balancer
|
||||
request :delete_server
|
||||
request :delete_server_group
|
||||
request :delete_user_collaboration
|
||||
request :get_account
|
||||
request :get_api_client
|
||||
request :get_application
|
||||
request :get_authenticated_user
|
||||
request :get_cloud_ip
|
||||
request :get_collaboration
|
||||
request :get_firewall_policy
|
||||
request :get_firewall_rule
|
||||
request :get_image
|
||||
|
@ -95,11 +103,13 @@ module Fog
|
|||
request :get_server_group
|
||||
request :get_server_type
|
||||
request :get_user
|
||||
request :get_user_collaboration
|
||||
request :get_zone
|
||||
request :list_accounts
|
||||
request :list_api_clients
|
||||
request :list_applications
|
||||
request :list_cloud_ips
|
||||
request :list_collaborations
|
||||
request :list_firewall_policies
|
||||
request :list_images
|
||||
request :list_load_balancers
|
||||
|
@ -107,16 +117,21 @@ module Fog
|
|||
request :list_server_types
|
||||
request :list_servers
|
||||
request :list_users
|
||||
request :list_user_collaborations
|
||||
request :list_zones
|
||||
request :map_cloud_ip
|
||||
request :move_servers_server_group
|
||||
request :reject_user_collaboration
|
||||
request :remove_listeners_load_balancer
|
||||
request :remove_nodes_load_balancer
|
||||
request :remove_servers_server_group
|
||||
request :resend_collaboration
|
||||
request :reset_ftp_password_account
|
||||
request :reset_ftp_password_scoped_account
|
||||
request :reset_secret_api_client
|
||||
request :reset_secret_application
|
||||
request :resend_collaboration
|
||||
request :reject_user_collaboration
|
||||
request :shutdown_server
|
||||
request :snapshot_server
|
||||
request :start_server
|
||||
|
@ -135,220 +150,13 @@ module Fog
|
|||
request :update_server_group
|
||||
request :update_user
|
||||
|
||||
module Shared
|
||||
include Fog::Brightbox::OAuth2
|
||||
|
||||
# Creates a new instance of the Brightbox Compute service
|
||||
#
|
||||
# @note If you create service using just a refresh token when it
|
||||
# expires the service will no longer be able to authenticate.
|
||||
#
|
||||
# @param [Hash] options
|
||||
# @option options [String] :brightbox_api_url Override the default (or configured) API endpoint
|
||||
# @option options [String] :brightbox_auth_url Override the default (or configured) API authentication endpoint
|
||||
# @option options [String] :brightbox_client_id Client identifier to authenticate with (overrides configured)
|
||||
# @option options [String] :brightbox_secret Client secret to authenticate with (overrides configured)
|
||||
# @option options [String] :brightbox_username Email or user identifier for user based authentication
|
||||
# @option options [String] :brightbox_password Password for user based authentication
|
||||
# @option options [String] :brightbox_account Account identifier to scope this connection to
|
||||
# @option options [String] :connection_options Settings to pass to underlying {Fog::Connection}
|
||||
# @option options [Boolean] :persistent Sets a persistent HTTP {Fog::Connection}
|
||||
# @option options [String] :brightbox_access_token Sets the OAuth access token to use rather than requesting a new token
|
||||
# @option options [String] :brightbox_refresh_token Sets the refresh token to use when requesting a newer access token
|
||||
# @option options [String] :brightbox_token_management Overide the existing behaviour to request access tokens if expired (default is `true`)
|
||||
#
|
||||
def initialize(options)
|
||||
# Currently authentication and api endpoints are the same but may change
|
||||
@auth_url = options[:brightbox_auth_url] || Fog.credentials[:brightbox_auth_url] || API_URL
|
||||
@auth_connection = Fog::Connection.new(@auth_url)
|
||||
|
||||
@api_url = options[:brightbox_api_url] || Fog.credentials[:brightbox_api_url] || API_URL
|
||||
@connection_options = options[:connection_options] || {}
|
||||
@persistent = options[:persistent] || false
|
||||
@connection = Fog::Connection.new(@api_url, @persistent, @connection_options)
|
||||
|
||||
# Authentication options
|
||||
client_id = options[:brightbox_client_id] || Fog.credentials[:brightbox_client_id]
|
||||
client_secret = options[:brightbox_secret] || Fog.credentials[:brightbox_secret]
|
||||
|
||||
username = options[:brightbox_username] || Fog.credentials[:brightbox_username]
|
||||
password = options[:brightbox_password] || Fog.credentials[:brightbox_password]
|
||||
@configured_account = options[:brightbox_account] || Fog.credentials[:brightbox_account]
|
||||
# Request account can be changed at anytime and changes behaviour of future requests
|
||||
@scoped_account = @configured_account
|
||||
|
||||
credential_options = {:username => username, :password => password}
|
||||
@credentials = CredentialSet.new(client_id, client_secret, credential_options)
|
||||
|
||||
# If existing tokens have been cached, allow continued use of them in the service
|
||||
@credentials.update_tokens(options[:brightbox_access_token], options[:brightbox_refresh_token])
|
||||
|
||||
@token_management = options.fetch(:brightbox_token_management, true)
|
||||
end
|
||||
|
||||
# Sets the scoped account for future requests
|
||||
# @param [String] scoped_account Identifier of the account to scope request to
|
||||
def scoped_account=(scoped_account)
|
||||
@scoped_account = scoped_account
|
||||
end
|
||||
|
||||
# This returns the account identifier that the request should be scoped by
|
||||
# based on the options passed to the request and current configuration
|
||||
#
|
||||
# @param [String] options_account Any identifier passed into the request
|
||||
#
|
||||
# @return [String, nil] The account identifier to scope the request to or nil
|
||||
def scoped_account(options_account = nil)
|
||||
[options_account, @scoped_account].compact.first
|
||||
end
|
||||
|
||||
# Resets the scoped account back to intially configured one
|
||||
def scoped_account_reset
|
||||
@scoped_account = @configured_account
|
||||
end
|
||||
|
||||
# Returns the scoped account being used for requests
|
||||
#
|
||||
# * For API clients this is the owning account
|
||||
# * For User applications this is the account specified by either +account_id+
|
||||
# option on the service or the +brightbox_account+ setting in your configuration
|
||||
#
|
||||
# @return [Fog::Compute::Brightbox::Account]
|
||||
#
|
||||
def account
|
||||
account_data = get_scoped_account.merge(:service => self)
|
||||
Fog::Compute::Brightbox::Account.new(account_data)
|
||||
end
|
||||
|
||||
# Returns true if authentication is being performed as a user
|
||||
# @return [Boolean]
|
||||
def authenticating_as_user?
|
||||
@credentials.user_details?
|
||||
end
|
||||
|
||||
# Returns true if an access token is set
|
||||
# @return [Boolean]
|
||||
def access_token_available?
|
||||
!! @credentials.access_token
|
||||
end
|
||||
|
||||
# Returns the current access token or nil
|
||||
# @return [String,nil]
|
||||
def access_token
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Returns the current refresh token or nil
|
||||
# @return [String,nil]
|
||||
def refresh_token
|
||||
@credentials.refresh_token
|
||||
end
|
||||
|
||||
# Returns the current token expiry time in seconds or nil
|
||||
# @return [Number,nil]
|
||||
def expires_in
|
||||
@credentials.expires_in
|
||||
end
|
||||
|
||||
# Requests a new access token
|
||||
#
|
||||
# @return [String] New access token
|
||||
def get_access_token
|
||||
begin
|
||||
get_access_token!
|
||||
rescue Excon::Errors::Unauthorized, Excon::Errors::BadRequest
|
||||
@credentials.update_tokens(nil, nil)
|
||||
end
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Requests a new access token and raises if there is a problem
|
||||
#
|
||||
# @return [String] New access token
|
||||
# @raise [Excon::Errors::BadRequest] The credentials are expired or incorrect
|
||||
#
|
||||
def get_access_token!
|
||||
response = request_access_token(@auth_connection, @credentials)
|
||||
update_credentials_from_response(@credentials, response)
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Returns an identifier for the default image for use
|
||||
#
|
||||
# Currently tries to find the latest version of Ubuntu (i686) from
|
||||
# Brightbox.
|
||||
#
|
||||
# Highly recommended that you actually select the image you want to run
|
||||
# on your servers yourself!
|
||||
#
|
||||
# @return [String] if image is found, returns the identifier
|
||||
# @return [NilClass] if no image is found or an error occurs
|
||||
#
|
||||
def default_image
|
||||
return @default_image_id unless @default_image_id.nil?
|
||||
@default_image_id = Fog.credentials[:brightbox_default_image] || select_default_image
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This makes a request of the API based on the configured setting for
|
||||
# token management.
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
||||
#
|
||||
# @return [Hash] Data of response body
|
||||
#
|
||||
def make_request(options)
|
||||
if @token_management
|
||||
managed_token_request(options)
|
||||
else
|
||||
authenticated_request(options)
|
||||
end
|
||||
end
|
||||
|
||||
# This request checks for access tokens and will ask for a new one if
|
||||
# it receives Unauthorized from the API before repeating the request
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
def managed_token_request(options)
|
||||
begin
|
||||
get_access_token unless access_token_available?
|
||||
response = authenticated_request(options)
|
||||
rescue Excon::Errors::Unauthorized
|
||||
get_access_token
|
||||
response = authenticated_request(options)
|
||||
end
|
||||
end
|
||||
|
||||
# This request makes an authenticated request of the API using currently
|
||||
# setup credentials.
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
#
|
||||
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
def authenticated_request(options)
|
||||
headers = options[:headers] || {}
|
||||
headers.merge!("Authorization" => "OAuth #{@credentials.access_token}", "Content-Type" => "application/json")
|
||||
options[:headers] = headers
|
||||
# TODO This is just a wrapper around a call to Excon::Connection#request
|
||||
# so can be extracted from Compute by passing in the connection,
|
||||
# credentials and options
|
||||
@connection.request(options)
|
||||
end
|
||||
end
|
||||
|
||||
# The Mock Service allows you to run a fake instance of the Service
|
||||
# which makes no real connections.
|
||||
#
|
||||
# @todo Implement
|
||||
#
|
||||
class Mock
|
||||
include Shared
|
||||
include Fog::Brightbox::Compute::Shared
|
||||
|
||||
def request(method, path, expected_responses, parameters = {})
|
||||
_request
|
||||
|
@ -373,7 +181,7 @@ module Fog
|
|||
# service.
|
||||
#
|
||||
class Real
|
||||
include Shared
|
||||
include Fog::Brightbox::Compute::Shared
|
||||
|
||||
# Makes an API request to the given path using passed options or those
|
||||
# set with the service setup
|
||||
|
|
232
lib/fog/brightbox/compute/shared.rb
Normal file
232
lib/fog/brightbox/compute/shared.rb
Normal file
|
@ -0,0 +1,232 @@
|
|||
require "fog/brightbox/oauth2"
|
||||
|
||||
module Fog
|
||||
module Brightbox
|
||||
module Compute
|
||||
|
||||
# The Shared module consists of code that was duplicated between the Real
|
||||
# and Mock implementations.
|
||||
#
|
||||
module Shared
|
||||
include Fog::Brightbox::OAuth2
|
||||
|
||||
API_URL = "https://api.gb1.brightbox.com/"
|
||||
|
||||
# Creates a new instance of the Brightbox Compute service
|
||||
#
|
||||
# @note If you create service using just a refresh token when it
|
||||
# expires the service will no longer be able to authenticate.
|
||||
#
|
||||
# @param [Hash] options
|
||||
# @option options [String] :brightbox_api_url
|
||||
# Override the default (or configured) API endpoint
|
||||
# @option options [String] :brightbox_auth_url
|
||||
# Override the default (or configured) API authentication endpoint
|
||||
# @option options [String] :brightbox_client_id
|
||||
# Client identifier to authenticate with (overrides configured)
|
||||
# @option options [String] :brightbox_secret
|
||||
# Client secret to authenticate with (overrides configured)
|
||||
# @option options [String] :brightbox_username
|
||||
# Email or user identifier for user based authentication
|
||||
# @option options [String] :brightbox_password
|
||||
# Password for user based authentication
|
||||
# @option options [String] :brightbox_account
|
||||
# Account identifier to scope this connection to
|
||||
# @option options [String] :connection_options
|
||||
# Settings to pass to underlying {Fog::Connection}
|
||||
# @option options [Boolean] :persistent
|
||||
# Sets a persistent HTTP {Fog::Connection}
|
||||
# @option options [String] :brightbox_access_token
|
||||
# Sets the OAuth access token to use rather than requesting a new token
|
||||
# @option options [String] :brightbox_refresh_token
|
||||
# Sets the refresh token to use when requesting a newer access token
|
||||
# @option options [String] (true) :brightbox_token_management
|
||||
# Overide the existing behaviour to request access tokens if expired
|
||||
#
|
||||
def initialize(options)
|
||||
# Currently authentication and api endpoints are the same but may change
|
||||
@auth_url = options[:brightbox_auth_url] || Fog.credentials[:brightbox_auth_url] || API_URL
|
||||
@auth_connection = Fog::Connection.new(@auth_url)
|
||||
|
||||
@api_url = options[:brightbox_api_url] || Fog.credentials[:brightbox_api_url] || API_URL
|
||||
@connection_options = options[:connection_options] || {}
|
||||
@persistent = options[:persistent] || false
|
||||
@connection = Fog::Connection.new(@api_url, @persistent, @connection_options)
|
||||
|
||||
# Authentication options
|
||||
client_id = options[:brightbox_client_id] || Fog.credentials[:brightbox_client_id]
|
||||
client_secret = options[:brightbox_secret] || Fog.credentials[:brightbox_secret]
|
||||
|
||||
username = options[:brightbox_username] || Fog.credentials[:brightbox_username]
|
||||
password = options[:brightbox_password] || Fog.credentials[:brightbox_password]
|
||||
@configured_account = options[:brightbox_account] || Fog.credentials[:brightbox_account]
|
||||
# Request account can be changed at anytime and changes behaviour of future requests
|
||||
@scoped_account = @configured_account
|
||||
|
||||
credential_options = {:username => username, :password => password}
|
||||
@credentials = CredentialSet.new(client_id, client_secret, credential_options)
|
||||
|
||||
# If existing tokens have been cached, allow continued use of them in the service
|
||||
@credentials.update_tokens(options[:brightbox_access_token], options[:brightbox_refresh_token])
|
||||
|
||||
@token_management = options.fetch(:brightbox_token_management, true)
|
||||
end
|
||||
|
||||
# Sets the scoped account for future requests
|
||||
# @param [String] scoped_account Identifier of the account to scope request to
|
||||
def scoped_account=(scoped_account)
|
||||
@scoped_account = scoped_account
|
||||
end
|
||||
|
||||
# This returns the account identifier that the request should be scoped by
|
||||
# based on the options passed to the request and current configuration
|
||||
#
|
||||
# @param [String] options_account Any identifier passed into the request
|
||||
#
|
||||
# @return [String, nil] The account identifier to scope the request to or nil
|
||||
def scoped_account(options_account = nil)
|
||||
[options_account, @scoped_account].compact.first
|
||||
end
|
||||
|
||||
# Resets the scoped account back to intially configured one
|
||||
def scoped_account_reset
|
||||
@scoped_account = @configured_account
|
||||
end
|
||||
|
||||
# Returns the scoped account being used for requests
|
||||
#
|
||||
# * For API clients this is the owning account
|
||||
# * For User applications this is the account specified by either +account_id+
|
||||
# option on the service or the +brightbox_account+ setting in your configuration
|
||||
#
|
||||
# @return [Fog::Compute::Brightbox::Account]
|
||||
#
|
||||
def account
|
||||
account_data = get_scoped_account.merge(:service => self)
|
||||
Fog::Compute::Brightbox::Account.new(account_data)
|
||||
end
|
||||
|
||||
# Returns true if authentication is being performed as a user
|
||||
# @return [Boolean]
|
||||
def authenticating_as_user?
|
||||
@credentials.user_details?
|
||||
end
|
||||
|
||||
# Returns true if an access token is set
|
||||
# @return [Boolean]
|
||||
def access_token_available?
|
||||
!! @credentials.access_token
|
||||
end
|
||||
|
||||
# Returns the current access token or nil
|
||||
# @return [String,nil]
|
||||
def access_token
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Returns the current refresh token or nil
|
||||
# @return [String,nil]
|
||||
def refresh_token
|
||||
@credentials.refresh_token
|
||||
end
|
||||
|
||||
# Returns the current token expiry time in seconds or nil
|
||||
# @return [Number,nil]
|
||||
def expires_in
|
||||
@credentials.expires_in
|
||||
end
|
||||
|
||||
# Requests a new access token
|
||||
#
|
||||
# @return [String] New access token
|
||||
def get_access_token
|
||||
begin
|
||||
get_access_token!
|
||||
rescue Excon::Errors::Unauthorized, Excon::Errors::BadRequest
|
||||
@credentials.update_tokens(nil, nil)
|
||||
end
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Requests a new access token and raises if there is a problem
|
||||
#
|
||||
# @return [String] New access token
|
||||
# @raise [Excon::Errors::BadRequest] The credentials are expired or incorrect
|
||||
#
|
||||
def get_access_token!
|
||||
response = request_access_token(@auth_connection, @credentials)
|
||||
update_credentials_from_response(@credentials, response)
|
||||
@credentials.access_token
|
||||
end
|
||||
|
||||
# Returns an identifier for the default image for use
|
||||
#
|
||||
# Currently tries to find the latest version of Ubuntu (i686) from
|
||||
# Brightbox.
|
||||
#
|
||||
# Highly recommended that you actually select the image you want to run
|
||||
# on your servers yourself!
|
||||
#
|
||||
# @return [String] if image is found, returns the identifier
|
||||
# @return [NilClass] if no image is found or an error occurs
|
||||
#
|
||||
def default_image
|
||||
return @default_image_id unless @default_image_id.nil?
|
||||
@default_image_id = Fog.credentials[:brightbox_default_image] || select_default_image
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This makes a request of the API based on the configured setting for
|
||||
# token management.
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
||||
#
|
||||
# @return [Hash] Data of response body
|
||||
#
|
||||
def make_request(options)
|
||||
if @token_management
|
||||
managed_token_request(options)
|
||||
else
|
||||
authenticated_request(options)
|
||||
end
|
||||
end
|
||||
|
||||
# This request checks for access tokens and will ask for a new one if
|
||||
# it receives Unauthorized from the API before repeating the request
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
def managed_token_request(options)
|
||||
begin
|
||||
get_access_token unless access_token_available?
|
||||
response = authenticated_request(options)
|
||||
rescue Excon::Errors::Unauthorized
|
||||
get_access_token
|
||||
response = authenticated_request(options)
|
||||
end
|
||||
end
|
||||
|
||||
# This request makes an authenticated request of the API using currently
|
||||
# setup credentials.
|
||||
#
|
||||
# @param [Hash] options Excon compatible options
|
||||
#
|
||||
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
def authenticated_request(options)
|
||||
headers = options[:headers] || {}
|
||||
headers.merge!("Authorization" => "OAuth #{@credentials.access_token}", "Content-Type" => "application/json")
|
||||
options[:headers] = headers
|
||||
# TODO This is just a wrapper around a call to Excon::Connection#request
|
||||
# so can be extracted from Compute by passing in the connection,
|
||||
# credentials and options
|
||||
@connection.request(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
43
lib/fog/brightbox/models/compute/collaboration.rb
Normal file
43
lib/fog/brightbox/models/compute/collaboration.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Collaboration < Fog::Model
|
||||
identity :id
|
||||
attribute :status
|
||||
attribute :email
|
||||
attribute :role
|
||||
attribute :role_label
|
||||
attribute :account
|
||||
attribute :user
|
||||
attribute :inviter
|
||||
|
||||
def account_id
|
||||
account['id'] || account[:id]
|
||||
end
|
||||
|
||||
def save
|
||||
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if identity
|
||||
|
||||
options = {
|
||||
:role => role,
|
||||
:email => email
|
||||
}.delete_if { |k, v| v.nil? || v == "" }
|
||||
|
||||
data = connection.create_collaboration(options)
|
||||
merge_attributes(data)
|
||||
true
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :identity
|
||||
connection.destroy_collaboration(identity)
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
23
lib/fog/brightbox/models/compute/collaborations.rb
Normal file
23
lib/fog/brightbox/models/compute/collaborations.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require "fog/core/collection"
|
||||
require "fog/brightbox/models/compute/collaboration"
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Collaborations < Fog::Collection
|
||||
model Fog::Compute::Brightbox::Collaboration
|
||||
|
||||
def all
|
||||
data = connection.list_collaborations
|
||||
load(data)
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :identity
|
||||
connection.destroy_collaboration(identity)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
29
lib/fog/brightbox/models/compute/user_collaboration.rb
Normal file
29
lib/fog/brightbox/models/compute/user_collaboration.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class UserCollaboration < Fog::Model
|
||||
identity :id
|
||||
attribute :status
|
||||
attribute :email
|
||||
attribute :role
|
||||
attribute :role_label
|
||||
attribute :account
|
||||
attribute :user
|
||||
attribute :inviter
|
||||
|
||||
def account_id
|
||||
account['id'] || account[:id]
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :identity
|
||||
connection.destroy_user_collaboration(identity)
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
lib/fog/brightbox/models/compute/user_collaborations.rb
Normal file
23
lib/fog/brightbox/models/compute/user_collaborations.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require "fog/core/collection"
|
||||
require "fog/brightbox/models/compute/user_collaboration"
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class UserCollaborations < Fog::Collection
|
||||
model Fog::Compute::Brightbox::UserCollaboration
|
||||
|
||||
def all
|
||||
data = connection.list_user_collaborations
|
||||
load(data)
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :identity
|
||||
connection.destroy_user_collaboration(identity)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Accepts the collaboration and gaining permitted access
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_accept_user_collaboration
|
||||
#
|
||||
def accept_user_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("post", "/1.0/user/collaborations/#{identifier}/accept", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
lib/fog/brightbox/requests/compute/create_collaboration.rb
Normal file
23
lib/fog/brightbox/requests/compute/create_collaboration.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Creates a new collaboration for a user for the account
|
||||
#
|
||||
# @param [Hash] options
|
||||
# @option options [String] :email Email address of user to invite
|
||||
# @option options [String] :role Role to grant to the user. Currently only `admin`
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
# @return [NilClass] if no options were passed
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#collaboration_create_collaboration
|
||||
#
|
||||
def create_collaboration(options)
|
||||
wrapped_request("post", "/1.0/collaborations", [201], options)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
lib/fog/brightbox/requests/compute/delete_collaboration.rb
Normal file
28
lib/fog/brightbox/requests/compute/delete_collaboration.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Cancels or completes the collaboration
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#collaboration_delete_collaboration
|
||||
#
|
||||
def delete_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("delete", "/1.0/collaborations/#{identifier}", [200])
|
||||
end
|
||||
|
||||
# Old format of the delete request.
|
||||
#
|
||||
# @deprecated Use +#delete_collaboration+ instead
|
||||
#
|
||||
def destroy_collaboration(identifier)
|
||||
delete_collaboration(identifier)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Ends an existing 'accepted' collaboration
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_delete_user_collaboration
|
||||
#
|
||||
def delete_user_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("delete", "/1.0/user/collaborations/#{identifier}", [200])
|
||||
end
|
||||
|
||||
# Old format of the delete request.
|
||||
#
|
||||
# @deprecated Use +#delete_user_collaboration+ instead
|
||||
#
|
||||
def destroy_user_collaboration(identifier)
|
||||
delete_user_collaboration(identifier)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Ends an existing 'accepted' collaboration
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] The JSON response parsed to a Hash
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_destroy_user_collaboration
|
||||
#
|
||||
def destroy_user_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("delete", "/1.0/user/collaborations/#{identifier}", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/brightbox/requests/compute/get_collaboration.rb
Normal file
21
lib/fog/brightbox/requests/compute/get_collaboration.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Shows details of one collaboration
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#collaboration_get_collaboration
|
||||
#
|
||||
def get_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("get", "/1.0/collaborations/#{identifier}", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/brightbox/requests/compute/get_user_collaboration.rb
Normal file
21
lib/fog/brightbox/requests/compute/get_user_collaboration.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Shows details of one collaboration
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_get_user_collaboration
|
||||
#
|
||||
def get_user_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("get", "/1.0/user/collaborations/#{identifier}", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
lib/fog/brightbox/requests/compute/list_collaborations.rb
Normal file
19
lib/fog/brightbox/requests/compute/list_collaborations.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Lists all the account collaborations
|
||||
#
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#collaboration_list_collaborations
|
||||
#
|
||||
def list_collaborations
|
||||
wrapped_request("get", "/1.0/collaborations", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Lists all collaborations the user is involved with
|
||||
#
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_list_user_collaborations
|
||||
#
|
||||
def list_user_collaborations
|
||||
wrapped_request("get", "/1.0/user/collaborations", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Rejects the collaboration and removes the offer
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#user_collaboration_reject_user_collaboration
|
||||
#
|
||||
def reject_user_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("post", "/1.0/user/collaborations/#{identifier}/reject", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/brightbox/requests/compute/resend_collaboration.rb
Normal file
21
lib/fog/brightbox/requests/compute/resend_collaboration.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Brightbox
|
||||
class Real
|
||||
# Resends the invitation email to the collaborator
|
||||
#
|
||||
# @param [String] identifier Unique reference to identify the resource
|
||||
#
|
||||
# @return [Hash] if successful Hash version of JSON object
|
||||
#
|
||||
# @see https://api.gb1.brightbox.com/1.0/#collaboration_resend_collaboration
|
||||
#
|
||||
def resend_collaboration(identifier)
|
||||
return nil if identifier.nil? || identifier == ""
|
||||
wrapped_request("post", "/1.0/collaborations/#{identifier}/resend", [200])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
59
lib/fog/cloudsigma/docs/getting_started.md
Normal file
59
lib/fog/cloudsigma/docs/getting_started.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Getting Started with Fog on CloudSigma
|
||||
|
||||
## Requirements
|
||||
|
||||
In order to use CloudSigma with Fog, you must use Fog version 1.12.0 or later.
|
||||
|
||||
## Setting credentials
|
||||
|
||||
Fog uses `~/.fog` to store credentials. To add CloudSigma as your default provider, simply add the following:
|
||||
|
||||
:default:
|
||||
:cloudsigma_username: user@example.com
|
||||
:cloudsigma_password: SomeRandomPassword
|
||||
:cloudsigma_host: zrh.cloudsigma.com
|
||||
|
||||
Please note that you need to specify the host. If you're on the Zurich-based cloud, you will need to enter `zrh.cloudsigma.com` and if you're on the Las Vegas cloud, you'll need to enter `lvs.cloudsigma.com`.
|
||||
|
||||
|
||||
## Creating a server
|
||||
|
||||
You can of course interact with Fog directly from your Ruby application, but in this example, we'll simply use the `fog` CLI tool. In the example below, we'll first create a 5GB disk, then we create server with 2Ghz CPU and 2GB RAM. Finally we attach the drive and boot up the server.
|
||||
|
||||
$ fog
|
||||
> cs = Compute[:CloudSigma]
|
||||
> drive = cs.volumes.create(:name => 'fog_drive', :size => '5368709120', :media => 'disk')
|
||||
> server = cs.servers.create(:name => 'fog_server', :cpu => '2000', :mem => '2147483648', :vnc_password => 'foobar')
|
||||
> server.mount_volume(drive.uuid)
|
||||
> server.update
|
||||
> server.start
|
||||
|
||||
Now, this wasn't very useful by itself since the drive we created was just a blank drive (as a result it cannot boot). It does however illustrate a minimal work flow.
|
||||
|
||||
To make this a bit more useful, let's try to attach an ISO image (in this case Ubuntu 12.04 LTS), and boot into the installer. To do this, we'll run the following commands (assuming you haven't closed the session from above). You can either upload your own installer image, or you can use one from the drives library. In either case, you need to pass the UUID for the drive.
|
||||
|
||||
> server.stop
|
||||
> ubuntu_image_uuid = '41d848c2-44e4-4428-9406-84e95bb1288d'
|
||||
> server.unmount(drive.uuid)
|
||||
> server.mount_volume(ubuntu_image_uuid, 'ide', '0:0', 1)
|
||||
> server.mount_volume(drive.uuid, 'virtio', '0:0', 2)
|
||||
> server.update
|
||||
> server.start
|
||||
|
||||
What this does is to stop the server, unmount the previous drive, then we attach the Ubuntu installation drive as an IDE device (on bus 0:0), with the boot order 1 (first). We then mount the system drive as Virtio device (on bus 0:0) with the boot order 2. Finally we push the changes to the server and start it. This will bring you into the Ubuntu installation.
|
||||
|
||||
In order to actually run the installer, you need to open a VNC session to the server. This can be done bye issue the following command:
|
||||
|
||||
> server.open_vnc
|
||||
|
||||
That will print out the VNC URL, among with other data. You can simply pass the value of 'vnc_url' into your VNC client. When opening the session, you also need to provide the password, which we set to 'foobar' during the server creation.
|
||||
|
||||
After you're done with the installation, you can unmount the Ubuntu installation disk by running the following command:
|
||||
|
||||
> server.unmount(ubuntu_image_uuid)
|
||||
|
||||
You might also want to close the VNC session to increase security. This can be done by running:
|
||||
|
||||
> server.close_vnc
|
||||
|
||||
That's it. You've now set up a fully working Ubuntu server on CloudSigma using fog.
|
|
@ -19,11 +19,9 @@ require 'fog/core/current_machine'
|
|||
require 'fog/core/deprecation'
|
||||
require 'fog/core/errors'
|
||||
require 'fog/core/hmac'
|
||||
require 'fog/core/json'
|
||||
require 'fog/core/logger'
|
||||
require 'fog/core/model'
|
||||
require 'fog/core/mock'
|
||||
require 'fog/core/parser' # FIXME: would be better to only load when nokogiri is required
|
||||
require 'fog/core/provider'
|
||||
require 'fog/core/service'
|
||||
require 'fog/core/ssh'
|
||||
|
@ -32,6 +30,13 @@ require 'fog/core/time'
|
|||
require 'fog/core/timeout'
|
||||
require 'fog/core/wait_for'
|
||||
|
||||
# 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'
|
||||
|
|
|
@ -1,40 +1,73 @@
|
|||
module Fog
|
||||
class Connection
|
||||
module Core
|
||||
|
||||
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}"
|
||||
@excon = Excon.new(url, params)
|
||||
@persistent = persistent
|
||||
end
|
||||
|
||||
def request(params, &block)
|
||||
unless @persistent
|
||||
reset
|
||||
end
|
||||
unless block_given?
|
||||
if (parser = params.delete(:parser))
|
||||
body = Nokogiri::XML::SAX::PushParser.new(parser)
|
||||
params[:response_block] = lambda { |chunk, remaining, total| body << chunk }
|
||||
# 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}"
|
||||
@excon = Excon.new(url, params)
|
||||
@persistent = persistent
|
||||
end
|
||||
|
||||
response = @excon.request(params, &block)
|
||||
|
||||
if parser
|
||||
body.finish
|
||||
response.body = parser.response
|
||||
# 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)
|
||||
reset unless @persistent
|
||||
@excon.request(params, &block)
|
||||
end
|
||||
|
||||
response
|
||||
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
|
||||
|
||||
def reset
|
||||
@excon.reset
|
||||
# Closes the connection
|
||||
#
|
||||
def reset
|
||||
@excon.reset
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
24
lib/fog/core/deprecated/connection.rb
Normal file
24
lib/fog/core/deprecated/connection.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
require "fog/xml"
|
||||
|
||||
module Fog
|
||||
|
||||
# @deprecated Use {Fog::Core::Connection} or {XML::SAXParserConnection} if you
|
||||
# require the response body to be parsed.
|
||||
#
|
||||
# The Connection class is a wrapper around an instance of Excon::Connection
|
||||
# supporting {#request} and {#reset} only.
|
||||
#
|
||||
# {#request} includes an option to perform SAX parsing for XML APIs.
|
||||
#
|
||||
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
||||
#
|
||||
class Connection < Fog::XML::SAXParserConnection
|
||||
def request(params, &block)
|
||||
if (parser = params.delete(:parser))
|
||||
super(parser, params)
|
||||
else
|
||||
original_request(params)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
require 'nokogiri'
|
||||
require "nokogiri"
|
||||
|
||||
module Fog
|
||||
module Parsers
|
||||
|
|
|
@ -41,6 +41,8 @@ module Fog
|
|||
request :insert_network
|
||||
request :insert_server
|
||||
|
||||
request :set_metadata
|
||||
|
||||
model_path 'fog/google/models/compute'
|
||||
model :server
|
||||
collection :servers
|
||||
|
@ -66,16 +68,15 @@ module Fog
|
|||
attr_reader :project
|
||||
|
||||
def initialize(options)
|
||||
|
||||
|
||||
base_url = 'https://www.googleapis.com/compute/'
|
||||
api_version = 'v1beta14'
|
||||
api_version = 'v1beta15'
|
||||
api_scope_url = 'https://www.googleapis.com/auth/compute'
|
||||
|
||||
@project = options[:google_project]
|
||||
google_client_email = options[:google_client_email]
|
||||
@api_url = base_url + api_version + '/projects/'
|
||||
#NOTE: loaded here to avoid requiring this as a core Fog dependency
|
||||
|
||||
# NOTE: loaded here to avoid requiring this as a core Fog dependency
|
||||
begin
|
||||
require 'google/api_client'
|
||||
rescue LoadError
|
||||
|
@ -87,6 +88,7 @@ module Fog
|
|||
:application_name => "fog",
|
||||
:application_version => Fog::VERSION,
|
||||
})
|
||||
|
||||
@client.authorization = Signet::OAuth2::Client.new({
|
||||
:audience => 'https://accounts.google.com/o/oauth2/token',
|
||||
:auth_provider_x509_cert_url => "https://www.googleapis.com/oauth2/v1/certs",
|
||||
|
@ -96,15 +98,14 @@ module Fog
|
|||
:signing_key => key,
|
||||
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
|
||||
})
|
||||
@client.authorization.fetch_access_token!
|
||||
|
||||
@client.authorization.fetch_access_token!
|
||||
@compute = @client.discovered_api('compute', api_version)
|
||||
@default_network = 'default'
|
||||
end
|
||||
|
||||
def build_result(api_method, parameters, body_object=nil)
|
||||
if body_object
|
||||
#p api_method, parameters
|
||||
result = @client.execute(
|
||||
:api_method => api_method,
|
||||
:parameters => parameters,
|
||||
|
@ -123,6 +124,10 @@ module Fog
|
|||
response.body = Fog::JSON.decode(result.body)
|
||||
if response.body["error"]
|
||||
response.status = response.body["error"]["code"]
|
||||
|
||||
response.body["error"]["errors"].each do |error|
|
||||
throw Fog::Errors::Error.new(error["message"])
|
||||
end
|
||||
else
|
||||
response.status = 200
|
||||
end
|
||||
|
@ -131,7 +136,7 @@ module Fog
|
|||
|
||||
end
|
||||
|
||||
RUNNING_STATE = 'RUNNING'
|
||||
RUNNING = 'RUNNING'
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,37 @@ module Fog
|
|||
attribute :creation_timestamp, :aliases => 'creationTimestamp'
|
||||
attribute :description
|
||||
attribute :preferred_kernel, :aliases => 'preferredKernel'
|
||||
attribute :project
|
||||
|
||||
def reload
|
||||
requires :name
|
||||
|
||||
data = {}
|
||||
if project
|
||||
data = service.get_image(name, project).body
|
||||
elsif
|
||||
[ 'google', 'debian-cloud', 'centos-cloud' ].each do |owner|
|
||||
begin
|
||||
data = service.get_image(name, owner).body
|
||||
data[:project] = owner
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
self.merge_attributes(data)
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def save
|
||||
requires :name
|
||||
|
||||
reload
|
||||
end
|
||||
|
||||
def resource_url
|
||||
"#{self.project}/global/images/#{name}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,8 +16,8 @@ module Fog
|
|||
attribute :metadata
|
||||
|
||||
def destroy
|
||||
requires :name
|
||||
service.delete_server(name)
|
||||
requires :name, :zone
|
||||
service.delete_server(name, zone)
|
||||
end
|
||||
|
||||
def image
|
||||
|
@ -25,22 +25,37 @@ module Fog
|
|||
end
|
||||
|
||||
def public_ip_address
|
||||
if self.network_interfaces.count
|
||||
self.network_interfaces[0]["networkIP"]
|
||||
else
|
||||
nil
|
||||
ip = nil
|
||||
if self.network_interfaces
|
||||
self.network_interfaces.each do |netif|
|
||||
netif["accessConfigs"].each do |access_config|
|
||||
if access_config["name"] == "External NAT"
|
||||
ip = access_config['natIP']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ip
|
||||
end
|
||||
|
||||
def ready?
|
||||
data = service.get_server(self.name, self.zone_name).body
|
||||
data['zone_name'] = self.zone_name
|
||||
self.merge_attributes(data)
|
||||
self.state == RUNNING_STATE
|
||||
self.state == RUNNING
|
||||
end
|
||||
|
||||
def zone
|
||||
service.get_zone(self.zone_name.split('/')[-1])
|
||||
if self.zone_name.is_a? String
|
||||
service.get_zone(self.zone_name.split('/')[-1]).body["name"]
|
||||
elsif zone_name.is_a? Excon::Response
|
||||
service.get_zone(zone_name.body["name"]).body["name"]
|
||||
else
|
||||
self.zone_name
|
||||
end
|
||||
end
|
||||
|
||||
def reload
|
||||
data = service.get_server(self.name, self.zone).body
|
||||
self.merge_attributes(data)
|
||||
end
|
||||
|
||||
def save
|
||||
|
@ -49,29 +64,20 @@ module Fog
|
|||
requires :machine_type
|
||||
requires :zone_name
|
||||
|
||||
if metadata.nil?
|
||||
metadata = {}
|
||||
end
|
||||
|
||||
metadata.merge!({
|
||||
"sshKeys" => "#{username}:#{File.read(public_key_path).strip}"
|
||||
}) if :public_key_path
|
||||
|
||||
data = service.insert_server(
|
||||
name,
|
||||
image_name,
|
||||
zone_name,
|
||||
machine_type)
|
||||
|
||||
data = service.get_server(self.name, self.zone_name).body
|
||||
service.servers.merge_attributes(data)
|
||||
end
|
||||
|
||||
def setup(credentials = {})
|
||||
requires :public_ip_address, :public_key, :username
|
||||
service.set_metadata(self.instance, self.zone, {'sshKeys' => self.public_key })
|
||||
rescue Errno::ECONNREFUSED
|
||||
sleep(1)
|
||||
retry
|
||||
end
|
||||
|
||||
def sshable?(options={})
|
||||
service.set_metadata(self.instance, self.zone, {'sshKeys' => self.public_key })
|
||||
ready? && !public_ip_address.nil? && public_key && metadata['sshKeys']
|
||||
rescue SystemCallError, Net::SSH::AuthenticationFailed, Timeout::Error
|
||||
false
|
||||
machine_type,
|
||||
metadata)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -22,20 +22,20 @@ module Fog
|
|||
end
|
||||
|
||||
def get(identity, zone=nil)
|
||||
data = nil
|
||||
response = nil
|
||||
if zone.nil?
|
||||
service.list_zones.body['items'].each do |zone|
|
||||
data = service.get_server(identity, zone['name']).body
|
||||
break if data["code"] == 200
|
||||
response = service.get_server(identity, zone['name'])
|
||||
break if response.status == 200
|
||||
end
|
||||
else
|
||||
data = service.get_server(identity, zone).body
|
||||
response = service.get_server(identity, zone)
|
||||
end
|
||||
|
||||
if data["code"] != 200
|
||||
if response.nil? or response.status != 200
|
||||
nil
|
||||
else
|
||||
new(data)
|
||||
new(response.body)
|
||||
end
|
||||
rescue Excon::Errors::NotFound
|
||||
nil
|
||||
|
@ -44,15 +44,17 @@ module Fog
|
|||
def bootstrap(new_attributes = {})
|
||||
defaults = {
|
||||
:name => "fog-#{Time.now.to_i}",
|
||||
:image_name => "gcel-12-04-v20130225",
|
||||
:image_name => "debian-7-wheezy-v20130617",
|
||||
:machine_type => "n1-standard-1",
|
||||
:zone_name => "us-central1-a",
|
||||
:private_key_path => File.expand_path("~/.ssh/id_rsa"),
|
||||
:public_key_path => File.expand_path("~/.ssh/id_rsa.pub"),
|
||||
:username => ENV['USER'],
|
||||
}
|
||||
|
||||
server = create(defaults.merge(new_attributes))
|
||||
server.wait_for(Fog.timeout, 30) { ready? }
|
||||
server.wait_for { sshable? }
|
||||
|
||||
server
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,11 +15,14 @@ module Fog
|
|||
def delete_server(server_name, zone_name=nil)
|
||||
if zone_name.nil?
|
||||
list_zones.body['items'].each do |zone|
|
||||
data = get_server(server_name, zone['name']).body
|
||||
if data["error"].nil?
|
||||
if get_server(server_name, zone['name']).status == 200
|
||||
zone_name = zone['name']
|
||||
end
|
||||
end
|
||||
else
|
||||
if zone_name.is_a? Excon::Response
|
||||
zone_name = zone_name.body["name"]
|
||||
end
|
||||
end
|
||||
|
||||
api_method = @compute.instances.delete
|
||||
|
|
|
@ -13,10 +13,16 @@ module Fog
|
|||
class Real
|
||||
|
||||
def get_server(server_name, zone_name)
|
||||
if zone_name.is_a? Excon::Response
|
||||
zone = zone_name.body["name"]
|
||||
else
|
||||
zone = zone_name
|
||||
end
|
||||
|
||||
api_method = @compute.instances.get
|
||||
parameters = {
|
||||
'project' => @project,
|
||||
'zone' => zone_name,
|
||||
'zone' => zone,
|
||||
'instance' => server_name
|
||||
}
|
||||
|
||||
|
|
|
@ -12,16 +12,17 @@ module Fog
|
|||
|
||||
class Real
|
||||
|
||||
def format_metadata(metadata)
|
||||
{ "items" => metadata.map {|k,v| {"key" => k, "value" => v}} }
|
||||
end
|
||||
|
||||
def insert_server(server_name, image_name,
|
||||
zone_name, machine_name,
|
||||
zone_name, machine_name, metadata,
|
||||
network_name=@default_network)
|
||||
|
||||
# We need to check if the image is owned by the user or a global image.
|
||||
if get_image(image_name, @project).data['code'] == 200
|
||||
image_url = @api_url + @project + "/global/images/#{image_name}"
|
||||
else
|
||||
image_url = @api_url + "google/global/images/#{image_name}"
|
||||
end
|
||||
# We don't know the owner of the image.
|
||||
image = images.create({:name => image_name})
|
||||
@image_url = @api_url + image.resource_url
|
||||
|
||||
api_method = @compute.instances.insert
|
||||
parameters = {
|
||||
|
@ -30,10 +31,15 @@ module Fog
|
|||
}
|
||||
body_object = {
|
||||
'name' => server_name,
|
||||
'image' => image_url,
|
||||
'machineType' => @api_url + @project + "/global/machineTypes/#{machine_name}",
|
||||
'image' => @image_url,
|
||||
'machineType' => @api_url + @project + "/zones/#{zone_name}/machineTypes/#{machine_name}",
|
||||
'metadata' => format_metadata(metadata),
|
||||
'networkInterfaces' => [{
|
||||
'network' => @api_url + @project + "/global/networks/#{network_name}"
|
||||
'network' => @api_url + @project + "/global/networks/#{network_name}",
|
||||
'accessConfigs' => [{
|
||||
'type' => 'ONE_TO_ONE_NAT',
|
||||
'name' => 'External NAT',
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -41,9 +47,7 @@ module Fog
|
|||
body_object=body_object)
|
||||
response = self.build_response(result)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,10 +12,11 @@ module Fog
|
|||
|
||||
class Real
|
||||
|
||||
def list_machine_types
|
||||
def list_machine_types(zone_name)
|
||||
api_method = @compute.machine_types.list
|
||||
parameters = {
|
||||
'project' => 'google'
|
||||
'project' => @project,
|
||||
'zone' => zone_name,
|
||||
}
|
||||
|
||||
result = self.build_result(api_method, parameters)
|
||||
|
|
|
@ -10,8 +10,11 @@ module Fog
|
|||
recognizes :persistent, :connection_options
|
||||
recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
|
||||
recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
|
||||
|
||||
# :os_account_meta_temp_url_key is an OpenStack specific setting used to generate temporary urls.
|
||||
recognizes :os_account_meta_temp_url_key
|
||||
|
||||
secrets :hp_secret_key
|
||||
secrets :hp_secret_key, :os_account_meta_temp_url_key
|
||||
|
||||
model_path 'fog/hp/models/storage'
|
||||
model :directory
|
||||
|
@ -167,14 +170,26 @@ module Fog
|
|||
encoded_path = "#{path}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
|
||||
|
||||
string_to_sign = "#{method}\n#{expires}\n#{sig_path}"
|
||||
# Only works with 1.9+ Not compatible with 1.8.7
|
||||
#signed_string = Digest::HMAC.hexdigest(string_to_sign, @hp_secret_key, Digest::SHA1)
|
||||
# Compatible with 1.8.7 onwards
|
||||
hmac = OpenSSL::HMAC.new(@hp_secret_key, OpenSSL::Digest::SHA1.new)
|
||||
signed_string = hmac.update(string_to_sign).hexdigest
|
||||
|
||||
signature = @hp_tenant_id.to_s + ":" + @hp_access_key.to_s + ":" + signed_string
|
||||
signature = Fog::HP.escape(signature)
|
||||
|
||||
signature = nil
|
||||
|
||||
# HP uses a different strategy to create the signature that is passed to swift than OpenStack.
|
||||
# As the HP provider is broadly used by OpenStack users the OpenStack strategy is applied when
|
||||
# the @os_account_meta_temp_url_key is given.
|
||||
if @os_account_meta_temp_url_key then
|
||||
hmac = OpenSSL::HMAC.new(@os_account_meta_temp_url_key, OpenSSL::Digest::SHA1.new)
|
||||
signature= hmac.update(string_to_sign).hexdigest
|
||||
else
|
||||
# Only works with 1.9+ Not compatible with 1.8.7
|
||||
#signed_string = Digest::HMAC.hexdigest(string_to_sign, @hp_secret_key, Digest::SHA1)
|
||||
|
||||
# Compatible with 1.8.7 onwards
|
||||
hmac = OpenSSL::HMAC.new(@hp_secret_key, OpenSSL::Digest::SHA1.new)
|
||||
signed_string = hmac.update(string_to_sign).hexdigest
|
||||
|
||||
signature = @hp_tenant_id.to_s + ":" + @hp_access_key.to_s + ":" + signed_string
|
||||
signature = Fog::HP.escape(signature)
|
||||
end
|
||||
|
||||
# generate the temp url using the signature and expiry
|
||||
"#{scheme}://#{host}:#{port}#{encoded_path}?temp_url_sig=#{signature}&temp_url_expires=#{expires}"
|
||||
|
@ -217,6 +232,7 @@ module Fog
|
|||
end
|
||||
@hp_secret_key = options[:hp_secret_key]
|
||||
@hp_tenant_id = options[:hp_tenant_id]
|
||||
@os_account_meta_temp_url_key = options[:os_account_meta_temp_url_key]
|
||||
end
|
||||
|
||||
def data
|
||||
|
@ -254,6 +270,7 @@ module Fog
|
|||
options[:hp_service_type] = "Object Storage"
|
||||
@hp_tenant_id = options[:hp_tenant_id]
|
||||
@hp_avl_zone = options[:hp_avl_zone]
|
||||
@os_account_meta_temp_url_key = options[:os_account_meta_temp_url_key]
|
||||
|
||||
### Make the authentication call
|
||||
if (auth_version == :v2)
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
require 'multi_json'
|
||||
require "multi_json"
|
||||
|
||||
module Fog
|
||||
|
||||
# @note Extracting JSON components out of core is a work in progress.
|
||||
#
|
||||
# The {JSON} module includes functionality that is common between APIs using
|
||||
# JSON to send and receive data.
|
||||
#
|
||||
# The intent is to provide common code for provider APIs using JSON but not
|
||||
# require it for those using XML.
|
||||
#
|
||||
# @todo Add +require "fog/json" and/or +include Fog::JSON+ to providers using
|
||||
# its services
|
||||
#
|
||||
module JSON
|
||||
|
||||
def self.sanitize(data)
|
||||
|
@ -28,6 +40,5 @@ module Fog
|
|||
def self.decode(obj)
|
||||
MultiJson.decode(obj)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -14,7 +14,7 @@ module Fog
|
|||
network_id = Fog::Rackspace::MockData.uuid
|
||||
|
||||
flavor = {
|
||||
"OS-FLV-DISABLED:disabled" => false,
|
||||
"OS-FLV-EXT-DATA:ephemeral" => 4,
|
||||
"disk" => 20,
|
||||
"id" => flavor_id,
|
||||
"links" => [
|
||||
|
@ -89,8 +89,8 @@ module Fog
|
|||
}
|
||||
|
||||
#Block Storage
|
||||
volume_type1_id = Fog::Mock.random_numbers(3).to_i
|
||||
volume_type2_id = Fog::Mock.random_numbers(3).to_i
|
||||
volume_type1_id = Fog::Mock.random_numbers(3).to_s
|
||||
volume_type2_id = Fog::Mock.random_numbers(3).to_s
|
||||
|
||||
volume_type1 = {
|
||||
"id" => volume_type1_id,
|
||||
|
|
|
@ -65,7 +65,7 @@ module Fog
|
|||
true
|
||||
end
|
||||
|
||||
def save
|
||||
def save(options = {})
|
||||
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
|
||||
requires :flavor_id, :image_id
|
||||
options = {
|
||||
|
|
|
@ -227,6 +227,7 @@ module Fog
|
|||
options['Access-Control-Allow-Origin'] = access_control_allow_origin if access_control_allow_origin
|
||||
options['Origin'] = origin if origin
|
||||
options['Content-Disposition'] = content_disposition if content_disposition
|
||||
options['Etag'] = etag if etag
|
||||
options.merge!(metadata.to_headers)
|
||||
|
||||
data = service.put_object(directory.key, key, body, options)
|
||||
|
|
|
@ -31,7 +31,7 @@ module Fog
|
|||
dc_root_folder = dc.vmFolder
|
||||
# Filter the root path for this datacenter not to be used."
|
||||
dc_root_folder_path=dc_root_folder.path.map { | id, name | name }.join("/")
|
||||
paths = path.sub(/^\/?#{Regex.quote(dc_root_folder_path)}\/?/, '').split('/')
|
||||
paths = path.sub(/^\/?#{Regexp.quote(dc_root_folder_path)}\/?/, '').split('/')
|
||||
|
||||
return dc_root_folder if paths.empty?
|
||||
# Walk the tree resetting the folder pointer as we go
|
||||
|
|
|
@ -74,6 +74,8 @@ module Fog
|
|||
request :destroy_network
|
||||
request :create_vlan
|
||||
request :destroy_vlan
|
||||
request :snapshot_server
|
||||
request :snapshot_revert
|
||||
|
||||
class Real
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ module Fog
|
|||
attribute :hvm_boot_policy, :aliases => :HVM_boot_policy
|
||||
attribute :hvm_boot_params, :aliases => :HVM_boot_params
|
||||
attribute :pci_bus, :aliases => :PCI_bus
|
||||
attribute :snapshots
|
||||
|
||||
def initialize(attributes={})
|
||||
super
|
||||
|
@ -198,14 +199,15 @@ module Fog
|
|||
service.provision_server reference
|
||||
end
|
||||
|
||||
# def snapshot
|
||||
# requires :reference, :name_label
|
||||
# data = service.snapshot_server(@reference, @name_label)
|
||||
# merge_attributes(data.body)
|
||||
# true
|
||||
# end
|
||||
def snapshot(name)
|
||||
service.snapshot_server(reference, name)
|
||||
end
|
||||
|
||||
def revert(snapshot_ref)
|
||||
service.snapshot_revert(snapshot_ref)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
lib/fog/xenserver/requests/compute/snapshot_revert.rb
Normal file
22
lib/fog/xenserver/requests/compute/snapshot_revert.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class XenServer
|
||||
|
||||
class Real
|
||||
|
||||
def snapshot_revert( snapshot_ref, extra_args = {})
|
||||
@connection.request({:parser => Fog::Parsers::XenServer::Base.new, :method => 'VM.revert'}, snapshot_ref)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def snapshot_revert()
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
lib/fog/xenserver/requests/compute/snapshot_server.rb
Normal file
22
lib/fog/xenserver/requests/compute/snapshot_server.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class XenServer
|
||||
|
||||
class Real
|
||||
|
||||
def snapshot_server( vm_ref , name, extra_args = {})
|
||||
@connection.request({:parser => Fog::Parsers::XenServer::Base.new, :method => 'VM.snapshot'}, vm_ref, name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def snapshot_server()
|
||||
Fog::Mock.not_implemented
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/xml.rb
Normal file
21
lib/fog/xml.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require "nokogiri"
|
||||
require "fog/core/parser"
|
||||
|
||||
module Fog
|
||||
|
||||
# @note Extracting XML components out of core is a work in progress.
|
||||
#
|
||||
# The {XML} module includes functionality that is common between APIs using
|
||||
# XML to send and receive data.
|
||||
#
|
||||
# The intent is to provide common code for provider APIs using XML but not
|
||||
# require it for those using JSON.
|
||||
#
|
||||
# @todo Add +require "fog/xml"+ and/or +include Fog::XML+ to providers using
|
||||
# its services
|
||||
#
|
||||
module XML
|
||||
end
|
||||
end
|
||||
|
||||
require "fog/xml/sax_parser_connection"
|
43
lib/fog/xml/sax_parser_connection.rb
Normal file
43
lib/fog/xml/sax_parser_connection.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
module Fog
|
||||
module XML
|
||||
class SAXParserConnection < Fog::Core::Connection
|
||||
|
||||
# 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
|
||||
# @option params [Nokogiri::XML::SAX::Document] :parser
|
||||
#
|
||||
# @return [Excon::Response]
|
||||
#
|
||||
# @raise [Excon::Errors::StubNotFound]
|
||||
# @raise [Excon::Errors::Timeout]
|
||||
# @raise [Excon::Errors::SocketError]
|
||||
#
|
||||
def request(parser, params)
|
||||
reset unless @persistent
|
||||
|
||||
# Prepare the SAX parser
|
||||
data_stream = Nokogiri::XML::SAX::PushParser.new(parser)
|
||||
params[:response_block] = lambda do |chunk, remaining, total|
|
||||
data_stream << chunk
|
||||
end
|
||||
|
||||
# Make request which read chunks into parser
|
||||
response = @excon.request(params)
|
||||
|
||||
# Cease parsing and override response.body with parsed data
|
||||
data_stream.finish
|
||||
response.body = parser.response
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
41
tests/brightbox/requests/compute/collaboration_tests.rb
Normal file
41
tests/brightbox/requests/compute/collaboration_tests.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
Shindo.tests('Fog::Compute[:brightbox] | collaboration requests', ['brightbox']) do
|
||||
|
||||
tests('success') do
|
||||
|
||||
tests("#create_collaboration") do
|
||||
pending if Fog.mocking?
|
||||
collaboration = Fog::Compute[:brightbox].create_collaboration(:email => "paul@example.com", :role => "admin")
|
||||
@collaboration_id = collaboration['id']
|
||||
formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { collaboration }
|
||||
end
|
||||
|
||||
|
||||
tests("#list_collaborations") do
|
||||
pending if Fog.mocking?
|
||||
result = Fog::Compute[:brightbox].list_collaborations
|
||||
|
||||
formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result }
|
||||
end
|
||||
|
||||
tests("#get_collaboration") do
|
||||
pending if Fog.mocking?
|
||||
result = Fog::Compute[:brightbox].get_collaboration(@collaboration_id)
|
||||
formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { result }
|
||||
end
|
||||
|
||||
|
||||
tests("#destroy_collaboration") do
|
||||
pending if Fog.mocking?
|
||||
result = Fog::Compute[:brightbox].destroy_collaboration(@collaboration_id)
|
||||
formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { result }
|
||||
end
|
||||
end
|
||||
|
||||
tests("failure") do
|
||||
tests("get_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
Fog::Compute[:brightbox].get_collaboration("col-abcde")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -8,6 +8,7 @@ module Fog
|
|||
module LoadBalancer; end
|
||||
module Server; end
|
||||
module ServerGroup; end
|
||||
module User; end
|
||||
module Zone; end
|
||||
end
|
||||
end
|
||||
|
@ -34,6 +35,9 @@ NilClass.send :include, Fog::Brightbox::Nullable::Server
|
|||
Hash.send :include, Fog::Brightbox::Nullable::ServerGroup
|
||||
NilClass.send :include, Fog::Brightbox::Nullable::ServerGroup
|
||||
|
||||
Hash.send :include, Fog::Brightbox::Nullable::User
|
||||
NilClass.send :include, Fog::Brightbox::Nullable::User
|
||||
|
||||
Hash.send :include, Fog::Brightbox::Nullable::Zone
|
||||
NilClass.send :include, Fog::Brightbox::Nullable::Zone
|
||||
|
||||
|
@ -75,8 +79,8 @@ class Brightbox
|
|||
raise "No available images!" if images.empty?
|
||||
images.select { |img| img["official"] && img["virtual_size"] != 0 }.sort_by { |img| img["disk_size"] }.first || images.first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module Formats
|
||||
module Struct
|
||||
CIP_PORT_TRANSLATOR = {
|
||||
|
@ -231,6 +235,20 @@ class Brightbox
|
|||
"email_address" => String
|
||||
}
|
||||
|
||||
|
||||
COLLABORATION = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
"url" => String,
|
||||
"status" => String,
|
||||
"email" => Fog::Nullable::String,
|
||||
"role" => String,
|
||||
"role_label" => String,
|
||||
"user" => Fog::Brightbox::Nullable::User,
|
||||
"account" => Brightbox::Compute::Formats::Nested::ACCOUNT,
|
||||
"inviter" => Brightbox::Compute::Formats::Nested::USER
|
||||
}
|
||||
|
||||
ZONE = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
|
@ -413,6 +431,19 @@ class Brightbox
|
|||
"default_account" => NilClass
|
||||
}
|
||||
|
||||
COLLABORATION = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
"url" => String,
|
||||
"status" => String,
|
||||
"role" => String,
|
||||
"role_label" => String,
|
||||
"email" => Fog::Nullable::String,
|
||||
"user" => Fog::Brightbox::Nullable::User,
|
||||
"account" => Brightbox::Compute::Formats::Nested::ACCOUNT,
|
||||
"inviter" => Brightbox::Compute::Formats::Nested::USER
|
||||
}
|
||||
|
||||
ZONE = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
|
@ -656,13 +687,25 @@ class Brightbox
|
|||
"messaging_pref" => Fog::Boolean
|
||||
}
|
||||
|
||||
COLLABORATION = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
"url" => String,
|
||||
"status" => String,
|
||||
"role" => String,
|
||||
"role_label" => String,
|
||||
"email" => Fog::Nullable::String,
|
||||
"user" => Fog::Brightbox::Nullable::User,
|
||||
"account" => Brightbox::Compute::Formats::Nested::ACCOUNT,
|
||||
"inviter" => Brightbox::Compute::Formats::Nested::USER
|
||||
}
|
||||
|
||||
ZONE = {
|
||||
"id" => String,
|
||||
"resource_type" => String,
|
||||
"url" => String,
|
||||
"handle" => String
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
module Collection
|
||||
|
@ -678,6 +721,7 @@ class Brightbox
|
|||
SERVER_TYPES = [Brightbox::Compute::Formats::Collected::SERVER_TYPE]
|
||||
USERS = [Brightbox::Compute::Formats::Collected::USER]
|
||||
ZONES = [Brightbox::Compute::Formats::Collected::ZONE]
|
||||
COLLABORATIONS = [Brightbox::Compute::Formats::Collected::COLLABORATION]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
67
tests/brightbox/requests/compute/user_collaboration_tests.rb
Normal file
67
tests/brightbox/requests/compute/user_collaboration_tests.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
Shindo.tests('Fog::Compute[:brightbox] | user collaboration requests', ['brightbox']) do
|
||||
|
||||
@service = Fog::Compute[:brightbox]
|
||||
|
||||
tests("when accessing with user application") do
|
||||
pending unless @service.authenticating_as_user?
|
||||
tests("success") do
|
||||
tests("#list_user_collaborations") do
|
||||
pending if Fog.mocking?
|
||||
result = @service.list_user_collaborations
|
||||
|
||||
formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result }
|
||||
end
|
||||
end
|
||||
|
||||
tests("failure") do
|
||||
tests("get_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.get_user_collaboration('col-abcde')
|
||||
end
|
||||
|
||||
tests("accept_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.accept_user_collaboration('col-abcde')
|
||||
end
|
||||
|
||||
tests("reject_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.reject_user_collaboration('col-abcde')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests("when accessing with API client") do
|
||||
pending if @service.authenticating_as_user?
|
||||
tests("forbidden") do
|
||||
|
||||
tests("#list_user_collaborations").raises(Excon::Errors::Forbidden) do
|
||||
pending if Fog.mocking?
|
||||
result = @service.list_user_collaborations
|
||||
|
||||
formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result }
|
||||
end
|
||||
|
||||
tests("get_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.get_user_collaboration('col-abcde')
|
||||
end
|
||||
|
||||
tests("accept_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.accept_user_collaboration('col-abcde')
|
||||
end
|
||||
|
||||
tests("reject_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do
|
||||
pending if Fog.mocking?
|
||||
|
||||
@service.reject_user_collaboration('col-abcde')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
tests/core/connection_tests.rb
Normal file
26
tests/core/connection_tests.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
Shindo.tests('Fog::Core::Connection', ['core']) do
|
||||
|
||||
raises(ArgumentError, "raises ArgumentError when no arguments given") do
|
||||
Fog::Core::Connection.new
|
||||
end
|
||||
|
||||
tests('new("http://example.com")') do
|
||||
@instance = Fog::Core::Connection.new("http://example.com")
|
||||
responds_to([:request, :reset])
|
||||
|
||||
tests('user agent').returns("fog/#{Fog::VERSION}") do
|
||||
@instance.instance_variable_get(:@excon).data[:headers]['User-Agent']
|
||||
end
|
||||
end
|
||||
|
||||
tests('new("http://example.com", true)') do
|
||||
Fog::Core::Connection.new("http://example.com", true)
|
||||
end
|
||||
|
||||
tests('new("http://example.com", false, options")') do
|
||||
options = {
|
||||
:debug_response => false
|
||||
}
|
||||
Fog::Core::Connection.new("http://example.com", true, options)
|
||||
end
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
Shindo.tests('Fog::Connection', 'core') do
|
||||
tests('user_agent').returns("fog/#{Fog::VERSION}") do
|
||||
conn = Fog::Connection.new("http://www.testserviceurl.com", false, {})
|
||||
conn.instance_variable_get(:@excon).data[:headers]['User-Agent']
|
||||
end
|
||||
end
|
|
@ -1,3 +1,16 @@
|
|||
require 'simplecov'
|
||||
require 'coveralls'
|
||||
|
||||
unless ENV['COVERAGE'] == 'false'
|
||||
SimpleCov.command_name "shindo:#{Process.pid.to_s}"
|
||||
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
Coveralls::SimpleCov::Formatter
|
||||
]
|
||||
SimpleCov.merge_timeout 3600
|
||||
SimpleCov.start
|
||||
end
|
||||
|
||||
ENV['FOG_RC'] = ENV['FOG_RC'] || File.expand_path('../.fog', __FILE__)
|
||||
ENV['FOG_CREDENTIAL'] = ENV['FOG_CREDENTIAL'] || 'default'
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ def openvz_fog_test_server
|
|||
# Server bootstrap took more than 120 secs!
|
||||
end
|
||||
end
|
||||
|
||||
openvz_fog_test_cleanup
|
||||
|
||||
server
|
||||
end
|
||||
|
||||
|
@ -27,15 +30,18 @@ def openvz_fog_test_server_destroy
|
|||
server.destroy if server
|
||||
end
|
||||
|
||||
at_exit do
|
||||
unless Fog.mocking?
|
||||
server = openvz_service.servers.find { |s| s.name == '104' }
|
||||
if server
|
||||
server.wait_for(120) do
|
||||
reload rescue nil; ready?
|
||||
# Prepare a callback to destroy the long lived test server
|
||||
def openvz_fog_test_cleanup
|
||||
at_exit do
|
||||
unless Fog.mocking?
|
||||
server = openvz_service.servers.find { |s| s.name == '104' }
|
||||
if server
|
||||
server.wait_for(120) do
|
||||
reload rescue nil; ready?
|
||||
end
|
||||
end
|
||||
server.stop
|
||||
openvz_fog_test_server_destroy
|
||||
end
|
||||
server.stop
|
||||
openvz_fog_test_server_destroy
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
module Shindo
|
||||
class Tests
|
||||
|
||||
|
||||
unless Fog.mocking?
|
||||
Fog.timeout = 2000
|
||||
Fog::Logger.warning "Setting default fog timeout to #{Fog.timeout} seconds"
|
||||
end
|
||||
|
||||
def given_a_load_balancer_service(&block)
|
||||
@service = Fog::Rackspace::LoadBalancers.new
|
||||
instance_eval(&block)
|
||||
|
@ -23,6 +28,12 @@ module Shindo
|
|||
end
|
||||
end
|
||||
|
||||
def wait_for_request(description = "waiting", &block)
|
||||
return if Fog.mocking?
|
||||
tests(description) do
|
||||
Fog.wait_for &block
|
||||
end
|
||||
end
|
||||
|
||||
def wait_for_server_deletion(server)
|
||||
return if Fog.mocking?
|
||||
|
|
|
@ -4,7 +4,7 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume', ['rackspace']) do
|
|||
options = { :display_name => "fog_#{Time.now.to_i.to_s}", :size => 100 }
|
||||
|
||||
model_tests(service.volumes, options, true) do
|
||||
@instance.wait_for(timeout=1200) { ready? }
|
||||
@instance.wait_for{ ready? }
|
||||
|
||||
tests('double save').raises(Fog::Rackspace::BlockStorage::IdentifierTaken) do
|
||||
@instance.save
|
||||
|
@ -18,7 +18,7 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume', ['rackspace']) do
|
|||
tests('#snapshots').succeeds do
|
||||
begin
|
||||
snapshot = @instance.create_snapshot
|
||||
snapshot.wait_for(timeout=1200) { ready? }
|
||||
snapshot.wait_for { ready? }
|
||||
|
||||
returns(true) { @instance.snapshots.first.id == snapshot.id }
|
||||
ensure
|
||||
|
|
|
@ -11,7 +11,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | metadata', ['rackspace']) do
|
|||
:flavor_id => rackspace_test_flavor_id(service),
|
||||
:image_id => rackspace_test_image_id(service))
|
||||
|
||||
@server.wait_for(timeout=1500) { ready? }
|
||||
@server.wait_for { ready? }
|
||||
|
||||
tests('server') do
|
||||
collection_tests(@server.metadata, {:key => 'my_key', :value => 'my_value'}) do
|
||||
|
@ -21,7 +21,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | metadata', ['rackspace']) do
|
|||
|
||||
tests('image') do
|
||||
@image = @server.create_image("fog_image_#{test_time}", :metadata => {:my_key => 'my_value'})
|
||||
@image.wait_for(timeout = 1500) { ready? }
|
||||
@image.wait_for { ready? }
|
||||
tests("#all").succeeds do
|
||||
pending if Fog.mocking? && !mocks_implemented
|
||||
metadata = @image.metadata.all
|
||||
|
|
|
@ -66,7 +66,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
end
|
||||
|
||||
model_tests(service.servers, options, true) do
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
|
||||
tests('#metadata[\'fog_test\']').returns('true') do
|
||||
@instance.metadata['fog_test']
|
||||
|
@ -79,12 +79,12 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
tests('#update').succeeds do
|
||||
@instance.name = "fog_server_update"
|
||||
@instance.access_ipv4_address= "10.10.0.1"
|
||||
@instance.access_ipv6_address= "0:0:0:0:0:0:0:1"
|
||||
@instance.access_ipv6_address= "::1"
|
||||
@instance.save
|
||||
sleep 60 unless Fog.mocking?
|
||||
@instance.reload
|
||||
returns("10.10.0.1") { @instance.access_ipv4_address }
|
||||
returns("0:0:0:0:0:0:0:1") { @instance.access_ipv6_address }
|
||||
returns("::1") { @instance.access_ipv6_address }
|
||||
returns("fog_server_update") { @instance.name }
|
||||
end
|
||||
|
||||
|
@ -93,13 +93,13 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
returns('REBOOT') { @instance.state }
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
tests('#reboot("HARD")').succeeds do
|
||||
@instance.reboot('HARD')
|
||||
returns('HARD_REBOOT') { @instance.state }
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
@test_image = nil
|
||||
begin
|
||||
tests('#create_image').succeeds do
|
||||
|
@ -112,7 +112,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
end
|
||||
|
||||
sleep 30 unless Fog.mocking?
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#rebuild').succeeds do
|
||||
@instance.rebuild rackspace_test_image_id(service)
|
||||
|
@ -120,7 +120,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
end
|
||||
|
||||
sleep 30 unless Fog.mocking?
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#resize').succeeds do
|
||||
@instance.resize(3)
|
||||
|
@ -128,37 +128,37 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
end
|
||||
|
||||
sleep 30 unless Fog.mocking?
|
||||
@instance.wait_for(timeout=1500) { ready?('VERIFY_RESIZE', ['ACTIVE', 'ERROR']) }
|
||||
@instance.wait_for { ready?('VERIFY_RESIZE', ['ACTIVE', 'ERROR']) }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#confirm_resize').succeeds do
|
||||
@instance.confirm_resize
|
||||
end
|
||||
|
||||
sleep 30 unless Fog.mocking?
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#resize').succeeds do
|
||||
@instance.resize(2)
|
||||
returns('RESIZE') { @instance.state }
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready?('VERIFY_RESIZE') }
|
||||
@instance.wait_for { ready?('VERIFY_RESIZE') }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#revert_resize').succeeds do
|
||||
@instance.revert_resize
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
tests('#rescue').succeeds do
|
||||
@instance.rescue
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready?('RESCUE') }
|
||||
@instance.wait_for { ready?('RESCUE') }
|
||||
tests('#unrescue').succeeds do
|
||||
@instance.unrescue
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
tests('#change_admin_password').succeeds do
|
||||
@instance.change_admin_password('somerandompassword')
|
||||
returns('PASSWORD') { @instance.state }
|
||||
|
@ -168,28 +168,29 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
tests('attachments') do
|
||||
begin
|
||||
@volume = cbs_service.volumes.create(:size => 100, :display_name => "fog-#{Time.now.to_i.to_s}")
|
||||
@volume.wait_for(timeout=1500) { ready? }
|
||||
@volume.wait_for { ready? }
|
||||
tests('#attach_volume').succeeds do
|
||||
@instance.attach_volume(@volume)
|
||||
end
|
||||
tests('#attachments').returns(true) do
|
||||
@instance.wait_for(timeout=1500) do
|
||||
@instance.wait_for do
|
||||
!attachments.empty?
|
||||
end
|
||||
@instance.attachments.any? {|a| a.volume_id == @volume.id }
|
||||
end
|
||||
ensure
|
||||
@volume.wait_for(timeout=1500) { !attachments.empty? }
|
||||
@volume.wait_for { !attachments.empty? }
|
||||
@instance.attachments.each {|a| a.detach }
|
||||
@volume.wait_for(timeout=1500) { ready? && attachments.empty? }
|
||||
@volume.wait_for { ready? && attachments.empty? }
|
||||
@volume.destroy if @volume
|
||||
end
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
end
|
||||
|
||||
wait_for_server_deletion(@instance)
|
||||
sleep 60 unless Fog.mocking?
|
||||
|
||||
tests("delete network #{@network.label}").succeeds do
|
||||
@network.destroy if @network
|
||||
|
@ -197,17 +198,17 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do
|
|||
|
||||
#When after testing resize/resize_confirm we get a 409 when we try to resize_revert so I am going to split it into two blocks
|
||||
model_tests(service.servers, options, true) do
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
tests('#resize').succeeds do
|
||||
@instance.resize(4)
|
||||
returns('RESIZE') { @instance.state }
|
||||
end
|
||||
|
||||
@instance.wait_for(timeout=1500) { ready?('VERIFY_RESIZE') }
|
||||
@instance.wait_for { ready?('VERIFY_RESIZE') }
|
||||
sleep 60 unless Fog.mocking?
|
||||
tests('#revert_resize').succeeds do
|
||||
@instance.revert_resize
|
||||
end
|
||||
@instance.wait_for(timeout=1500) { ready? }
|
||||
@instance.wait_for { ready? }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,11 +60,6 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do
|
|||
directories.
|
||||
create(directory_attributes)
|
||||
|
||||
model_tests(@directory.files, file_attributes.merge(:etag => 'foo'), Fog.mocking?) do
|
||||
tests('#save should not blow up with etag') do
|
||||
@instance.save
|
||||
end
|
||||
end
|
||||
|
||||
model_tests(@directory.files, file_attributes, Fog.mocking?) do
|
||||
|
||||
|
@ -187,8 +182,29 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do
|
|||
tests('#streaming_url').returns(0) do
|
||||
@instance.streaming_url =~ /http:\/\/.+\.stream\..*#{@instance.key}/
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests('etags') do
|
||||
text = lorem_file.read
|
||||
md5 = Digest::MD5.new
|
||||
md5 << text
|
||||
etag = md5.hexdigest
|
||||
|
||||
begin
|
||||
tests('valid tag').returns(true) do
|
||||
@file = @directory.files.create :key => 'valid-etag.txt', :body => text, :etag => etag
|
||||
@file.reload
|
||||
@file.etag == etag
|
||||
end
|
||||
ensure
|
||||
@file.destroy if @file
|
||||
end
|
||||
|
||||
tests('invalid tag').raises(Fog::Storage::Rackspace::ServiceError) do
|
||||
@directory.files.create :key => 'invalid-etag.txt', :body => text, :etag => "bad-bad-tag"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests('#metadata keys') do
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@ Shindo.tests('Fog::Rackspace::BlockStorage | snapshot_tests', ['rackspace']) do
|
|||
'display_description' => Fog::Nullable::String,
|
||||
'volume_id' => String,
|
||||
'size' => Integer,
|
||||
'created_at' => String,
|
||||
'availability_zone' => String
|
||||
}
|
||||
'created_at' => String
|
||||
}
|
||||
|
||||
get_snapshot_format = {
|
||||
'snapshot' => snapshot_format
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
Shindo.tests('Fog::Rackspace::BlockStorage | volume_type_tests', ['rackspace']) do
|
||||
volume_type_format = {
|
||||
'name' => String,
|
||||
'extra_specs' => Hash
|
||||
}
|
||||
|
||||
list_volume_type_format = {
|
||||
'volume_types' => [volume_type_format.merge({ 'id' => Integer })]
|
||||
}
|
||||
|
||||
get_volume_type_format = {
|
||||
'volume_type' => volume_type_format.merge({ 'id' => String })
|
||||
'extra_specs' => Hash,
|
||||
'id' => String
|
||||
}
|
||||
|
||||
service = Fog::Rackspace::BlockStorage.new
|
||||
|
@ -17,11 +10,11 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume_type_tests', ['rackspace'])
|
|||
tests('success') do
|
||||
volume_type_id = service.volume_types.first.id
|
||||
|
||||
tests("#list_volume_types").formats(list_volume_type_format) do
|
||||
tests("#list_volume_types").formats('volume_types' => [volume_type_format]) do
|
||||
service.list_volume_types.body
|
||||
end
|
||||
|
||||
tests("#get_volume_type(#{volume_type_id})").formats(get_volume_type_format) do
|
||||
tests("#get_volume_type(#{volume_type_id})").formats('volume_type' => volume_type_format) do
|
||||
service.get_volume_type(volume_type_id).body
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | address requests', ['rackspace']) do
|
|||
tests('success') do
|
||||
unless Fog.mocking?
|
||||
@server = @service.servers.create(:flavor_id => 2, :image_id => "8a3a9f96-b997-46fd-b7a8-a9e740796ffd", :name => "address-tests-#{Time.now.to_i}")
|
||||
@server.wait_for(timeout=1200) { ready? }
|
||||
@server.wait_for { ready? }
|
||||
@server_id = @server.id
|
||||
else
|
||||
@server_id = 42
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
Shindo.tests('Fog::Compute::RackspaceV2 | attachment_tests', ['rackspace']) do
|
||||
compute_service = Fog::Compute::RackspaceV2.new
|
||||
block_storage_service = Fog::Rackspace::BlockStorage.new
|
||||
image_id = Fog.credentials[:rackspace_image_id] || compute_service.images.first.id
|
||||
flavor_id = Fog.credentials[:rackspace_flavor_id] || compute_service.flavors.first.id
|
||||
timeout = Fog.mocking? ? 1 : 10
|
||||
image_id = rackspace_test_image_id(compute_service)
|
||||
flavor_id = rackspace_test_flavor_id(compute_service)
|
||||
|
||||
attachment_format = {
|
||||
'volumeAttachment' => {
|
||||
|
@ -27,12 +26,12 @@ Shindo.tests('Fog::Compute::RackspaceV2 | attachment_tests', ['rackspace']) do
|
|||
|
||||
|
||||
tests('success') do
|
||||
until compute_service.get_server(server_id).body['server']['status'] == 'ACTIVE'
|
||||
sleep timeout
|
||||
wait_for_request("Waiting for server to become ready") do
|
||||
compute_service.get_server(server_id).body['server']['status'] == 'ACTIVE'
|
||||
end
|
||||
|
||||
until block_storage_service.get_volume(volume_id).body['volume']['status'] == 'available'
|
||||
sleep timeout
|
||||
wait_for_request("Waiting for Volume to be ready") do
|
||||
block_storage_service.get_volume(volume_id).body['volume']['status'] == 'available'
|
||||
end
|
||||
|
||||
tests("#attach_volume(#{server_id}, #{volume_id}, #{device_id})").formats(attachment_format) do
|
||||
|
@ -43,8 +42,8 @@ Shindo.tests('Fog::Compute::RackspaceV2 | attachment_tests', ['rackspace']) do
|
|||
compute_service.list_attachments(server_id).body
|
||||
end
|
||||
|
||||
until block_storage_service.get_volume(volume_id).body['volume']['status'] == 'in-use'
|
||||
sleep timeout
|
||||
wait_for_request("Waiting for Volume to be ready") do
|
||||
block_storage_service.get_volume(volume_id).body['volume']['status'] == 'in-use'
|
||||
end
|
||||
|
||||
tests("#get_attachment(#{server_id}, #{volume_id})").formats(attachment_format) do
|
||||
|
|
|
@ -18,7 +18,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | flavor_tests', ['rackspace']) do
|
|||
|
||||
get_flavor_format = {
|
||||
'flavor' => flavor_format.merge({
|
||||
'OS-FLV-DISABLED:disabled' => Fog::Boolean,
|
||||
'OS-FLV-EXT-DATA:ephemeral' => Integer,
|
||||
'rxtx_factor' => Float,
|
||||
'swap' => Integer
|
||||
})
|
||||
|
|
|
@ -12,7 +12,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | metadata_tests', ['rackspace']) do
|
|||
:flavor_id => 2,
|
||||
:image_id => '3afe97b2-26dc-49c5-a2cc-a2fc8d80c001',
|
||||
:metadata => metadata)
|
||||
@server.wait_for(timeout = 1500) { ready? }
|
||||
@server.wait_for { ready? }
|
||||
|
||||
|
||||
@server_id = @server.id
|
||||
|
@ -40,12 +40,12 @@ Shindo.tests('Fog::Compute::RackspaceV2 | metadata_tests', ['rackspace']) do
|
|||
@service.set_metadata_item("servers", @server_id, "environment", "test").body
|
||||
end
|
||||
tests('delete_metadata_item').succeeds do
|
||||
@service.delete_metadata_item("servers", @server_id, "environment").body
|
||||
@service.delete_metadata_item("servers", @server_id, "environment")
|
||||
end
|
||||
end
|
||||
|
||||
tests("images") do
|
||||
@image.wait_for(timeout = 1500) { ready? } unless Fog.mocking?
|
||||
@image.wait_for { ready? } unless Fog.mocking?
|
||||
|
||||
tests('list_metadata').returns(metadata) do
|
||||
h = @service.list_metadata("images", @image_id).body
|
||||
|
@ -66,7 +66,7 @@ Shindo.tests('Fog::Compute::RackspaceV2 | metadata_tests', ['rackspace']) do
|
|||
@service.set_metadata_item("images", @image_id, "environment", "test").body
|
||||
end
|
||||
tests('delete_metadata_item').succeeds do
|
||||
@service.delete_metadata_item("images", @image_id, "environment").body
|
||||
@service.delete_metadata_item("images", @image_id, "environment")
|
||||
end
|
||||
end
|
||||
ensure
|
||||
|
|
|
@ -4,33 +4,36 @@ Shindo.tests('Fog::Rackspace::Database | database_tests', ['rackspace']) do
|
|||
|
||||
service = Fog::Rackspace::Databases.new
|
||||
instance_name = 'fog' + Time.now.to_i.to_s
|
||||
instance_id = service.create_instance(instance_name, 1, 1).body['instance']['id']
|
||||
|
||||
until service.get_instance(instance_id).body["instance"]["status"] == 'ACTIVE'
|
||||
sleep 10
|
||||
begin
|
||||
@instance_id = service.create_instance(instance_name, 1, 1).body['instance']['id']
|
||||
|
||||
wait_for_request("waiting for database to be created") do
|
||||
service.get_instance(@instance_id).body["instance"]["status"] == 'ACTIVE'
|
||||
end
|
||||
|
||||
tests('success') do
|
||||
database_name = 'fogdb' + Time.now.to_i.to_s
|
||||
|
||||
tests("#create_database(#{@instance_id}, #{database_name})").returns(202) do
|
||||
service.create_database(@instance_id, database_name).status
|
||||
end
|
||||
|
||||
tests("#list_databases{#{@instance_id})").formats(LIST_DATABASES_FORMAT) do
|
||||
service.list_databases(@instance_id).body
|
||||
end
|
||||
|
||||
tests("#delete_database(#{@instance_id}, #{database_name})").returns(202) do
|
||||
service.delete_database(@instance_id, database_name).status
|
||||
end
|
||||
end
|
||||
|
||||
tests('failure') do
|
||||
tests("#create_database(#{@instance_id}, '') => Invalid Create Critera").raises(Fog::Rackspace::Databases::BadRequest) do
|
||||
service.create_database(@instance_id, '')
|
||||
end
|
||||
end
|
||||
ensure
|
||||
service.delete_instance(@instance_id) if @instance_id
|
||||
end
|
||||
|
||||
tests('success') do
|
||||
database_name = 'fogdb' + Time.now.to_i.to_s
|
||||
|
||||
tests("#create_database(#{instance_id}, #{database_name})").succeeds do
|
||||
service.create_database(instance_id, database_name).body
|
||||
end
|
||||
|
||||
tests("#list_databases{#{instance_id})").formats(LIST_DATABASES_FORMAT) do
|
||||
service.list_databases(instance_id).body
|
||||
end
|
||||
|
||||
tests("#delete_database(#{instance_id}, #{database_name})").succeeds do
|
||||
service.delete_database(instance_id, database_name)
|
||||
end
|
||||
end
|
||||
|
||||
tests('failure') do
|
||||
tests("#create_database(#{instance_id}, '') => Invalid Create Critera").raises(Fog::Rackspace::Databases::BadRequest) do
|
||||
service.create_database(instance_id, '')
|
||||
end
|
||||
end
|
||||
|
||||
service.delete_instance(instance_id)
|
||||
end
|
||||
|
|
|
@ -6,24 +6,24 @@ Shindo.tests('Fog::Rackspace::Database | user_tests', ['rackspace']) do
|
|||
instance_name = 'fog' + Time.now.to_i.to_s
|
||||
instance_id = service.create_instance(instance_name, 1, 1).body['instance']['id']
|
||||
|
||||
until service.get_instance(instance_id).body["instance"]["status"] == 'ACTIVE'
|
||||
sleep 10
|
||||
wait_for_request("Waiting for database to be created") do
|
||||
service.get_instance(instance_id).body["instance"]["status"] == 'ACTIVE'
|
||||
end
|
||||
|
||||
tests('success') do
|
||||
user_name = 'fog' + Time.now.to_i.to_s
|
||||
password = 'password1'
|
||||
|
||||
tests("#create_user(#{instance_id}, #{user_name}, #{password})").succeeds do
|
||||
service.create_user(instance_id, user_name, password).body
|
||||
tests("#create_user(#{instance_id}, #{user_name}, #{password})").returns(202) do
|
||||
service.create_user(instance_id, user_name, password).status
|
||||
end
|
||||
|
||||
tests("#list_users{#{instance_id})").formats(LIST_USERS_FORMAT) do
|
||||
service.list_users(instance_id).body
|
||||
end
|
||||
|
||||
tests("#delete_user(#{instance_id}, #{user_name})").succeeds do
|
||||
service.delete_user(instance_id, user_name)
|
||||
tests("#delete_user(#{instance_id}, #{user_name})").returns(202) do
|
||||
service.delete_user(instance_id, user_name).status
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@ Shindo.tests('Fog::Rackspace::LoadBalancers | usage', ['rackspace']) do
|
|||
tests('success') do
|
||||
|
||||
tests("#get_usage()").formats(USAGE_FORMAT) do
|
||||
@service.get_usage.body
|
||||
pending
|
||||
# @service.get_usage.body
|
||||
end
|
||||
|
||||
tests("#get_usage(:start_time => '2010-05-10', :end_time => '2010-05-11')").formats(USAGE_FORMAT) do
|
||||
@service.get_usage(:start_time => '2010-05-10', :end_time => '2010-05-11').body
|
||||
pending
|
||||
# @service.get_usage(:start_time => '2010-05-10', :end_time => '2010-05-11').body
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,8 @@ Shindo.tests('Fog::Compute[:xenserver] | server model', ['xenserver']) do
|
|||
:pv_kernel,
|
||||
:pv_ramdisk,
|
||||
:pv_legacy_args,
|
||||
:pv_bootloader_args
|
||||
:pv_bootloader_args,
|
||||
:snapshots
|
||||
]
|
||||
tests("The server model should respond to") do
|
||||
attributes.each do |attribute|
|
||||
|
@ -157,6 +158,15 @@ Shindo.tests('Fog::Compute[:xenserver] | server model', ['xenserver']) do
|
|||
server.pv_bootloader == 'supergrub'
|
||||
end
|
||||
|
||||
tests("Creating a snapshot") do
|
||||
snap_ref = server.snapshot('newsnapshot')
|
||||
tests("it should create a snapshot") do
|
||||
snap_ref = server.snapshot('newsnapshot')
|
||||
servers.get(snap_ref).reference == snap_ref
|
||||
end
|
||||
test("and destroy it afterwards") { servers.get(snap_ref).destroy }
|
||||
end
|
||||
|
||||
test("be able to be destroyed!") do
|
||||
server.destroy
|
||||
servers.get_by_name('fog-test-server-shindo') == nil
|
||||
|
|
Loading…
Reference in a new issue