1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

[rackspace|autoscale] starting on rackspace auto scale implementation

This commit is contained in:
Kyle Rames 2013-08-06 16:32:04 -05:00
parent db5d9f0813
commit bf0dac91b0
12 changed files with 451 additions and 0 deletions

View file

@ -3,6 +3,8 @@ class Rackspace < Fog::Bin
def class_for(key)
case key
when :auto_scale
Fog::Rackspace::AutoScale
when :block_storage
Fog::Rackspace::BlockStorage
when :cdn
@ -29,6 +31,8 @@ class Rackspace < Fog::Bin
def [](service)
@@connections ||= Hash.new do |hash, key|
hash[key] = case key
when :auto_scale
Fog::Rackspace::AutoScale.new
when :cdn
Fog::Logger.warning("Rackspace[:cdn] is not recommended, use CDN[:rackspace] for portability")
Fog::CDN.new(:provider => 'Rackspace')

View file

@ -72,6 +72,7 @@ module Fog
end
end
service(:auto_scale, 'rackspace/auto_scale', 'AutoScale')
service(:block_storage, 'rackspace/block_storage', 'BlockStorage')
service(:cdn, 'rackspace/cdn', 'CDN')
service(:compute, 'rackspace/compute', 'Compute')

View file

@ -0,0 +1,103 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rackspace'))
module Fog
module Rackspace
class AutoScale < Fog::Service
include Fog::Rackspace::Errors
class ServiceError < Fog::Rackspace::Errors::ServiceError; end
class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end
class BadRequest < Fog::Rackspace::Errors::BadRequest
attr_reader :validation_errors
def self.slurp(error)
if error && error.response
status_code = error.response.status
if error.response.body
body = Fog::JSON.decode(error.response.body)
message = "#{body['type']} - #{body['message']}"
details = error.response.body['details']
end
end
new_error = new(message)
new_error.set_backtrace(error.backtrace)
new_error.instance_variable_set(:@validation_errors, details)
new_error.instance_variable_set(:@status_code, status_code)
new_error
end
end
requires :rackspace_username, :rackspace_api_key
recognizes :rackspace_auth_url
recognizes :rackspace_region
recognizes :rackspace_auto_scale_url
model_path 'fog/rackspace/models/auto_scale'
request_path 'fog/rackspace/requests/auto_scale'
request :list_groups
request :get_group
request :create_group
request :delete_group
request :get_group_state
request :update_config
request :get_config
class Mock < Fog::Rackspace::Service
def initialize(options)
@rackspace_api_key = options[:rackspace_api_key]
end
def request(params)
Fog::Mock.not_implemented
end
end
class Real < Fog::Rackspace::Service
def initialize(options = {})
@options = options
@options[:connection_options] ||= {}
@options[:persistent] ||= false
authenticate
@connection = Fog::Connection.new(endpoint_uri.to_s, @options[:persistent], @options[:connection_options])
end
def request(params, parse_json = true, &block)
super(params, parse_json, &block)
rescue Excon::Errors::NotFound => error
raise NotFound.slurp(error, region)
rescue Excon::Errors::BadRequest => error
raise BadRequest.slurp error
rescue Excon::Errors::InternalServerError => error
raise InternalServerError.slurp error
rescue Excon::Errors::HTTPStatusError => error
raise ServiceError.slurp error
end
def endpoint_uri(service_endpoint_url=nil)
@uri = super(@options[:rackspace_auto_scale_url], :rackspace_auto_scale_url)
end
def authenticate(options={})
super(select_options([:rackspace_username, :rackspace_api_key, :rackspace_auth_url, :connection_options]))
end
def service_name
:autoscale
end
def region
@options[:rackspace_region]
end
end
end
end
end

View file

@ -0,0 +1,88 @@
module Fog
module Rackspace
class AutoScale
class Real
def create_group
request(
:expects => [201],
:method => 'POST',
:path => 'groups',
:body => <<-JSON
{
\"groupConfiguration\": {
\"name\": \"workers2\",
\"cooldown\": 60,
\"minEntities\": 5,
\"maxEntities\": 25,
\"metadata\": {
\"firstkey\": \"this is a string\",
\"secondkey\": \"1\"
}
},
\"launchConfiguration\": {
\"type\": \"launch_server\",
\"args\": {
\"server\": {
\"flavorRef\": 3,
\"name\": \"webhead\",
\"imageRef\": \"0d589460-f177-4b0f-81c1-8ab8903ac7d8\",
\"OS-DCF:diskConfig\": \"AUTO\",
\"metadata\": {
\"mykey\": \"myvalue\"
},
\"personality\": [
{
\"path\": \"/root/.ssh/authorized_keys\",
\"contents\": \"ssh-rsa AAAAB3Nza...LiPk== user@example.net\"
}
],
\"networks\": [
{
\"uuid\": \"11111111-1111-1111-1111-111111111111\"
}
]
},
\"loadBalancers\": [
{
\"loadBalancerId\": 2200,
\"port\": 8081
}
]
}
},
\"scalingPolicies\": [
{
\"name\": \"scale up by 10\",
\"change\": 10,
\"cooldown\": 5,
\"type\": \"webhook\"
},
{
\"name\": \"scale down by 5.5 percent\",
\"changePercent\": -5.5,
\"cooldown\": 6,
\"type\": \"webhook\"
},
{
\"name\": \"set number of servers to 10\",
\"desiredCapacity\": 10,
\"cooldown\": 3,
\"type\": \"webhook\"
}
]
}
JSON
)
end
end
class Mock
def create_group
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,22 @@
module Fog
module Rackspace
class AutoScale
class Real
def delete_group(group_id)
request(
:expects => [204],
:method => 'DELETE',
:path => "groups/#{group_id}"
)
end
end
class Mock
def delete_group(group_id)
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,24 @@
module Fog
module Rackspace
class AutoScale
class Real
def get_config(group_id)
request(
:expects => [200],
:method => 'GET',
:path => "groups/#{group_id}/config",
)
end
end
class Mock
def get_config(group_id)
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,24 @@
module Fog
module Rackspace
class AutoScale
class Real
def get_group(group_id)
request(
:expects => [200],
:method => 'GET',
:path => "groups/#{group_id}",
)
end
end
class Mock
def get_group(group_id)
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,24 @@
module Fog
module Rackspace
class AutoScale
class Real
def get_group_state(group_id)
request(
:expects => [200],
:method => 'GET',
:path => "groups/#{group_id}/state",
)
end
end
class Mock
def get_group_state(group_id)
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,35 @@
module Fog
module Rackspace
class AutoScale
class Real
# Retrieves a list of images
# @return [Excon::Response] response:
# * body [Hash]:
# * images [Array]:
# * [Hash]:
# * id [String] - flavor id
# * links [Array] - image links
# * name [String] - image name
# @raise [Fog::Compute::RackspaceV2::NotFound] - HTTP 404
# @raise [Fog::Compute::RackspaceV2::BadRequest] - HTTP 400
# @raise [Fog::Compute::RackspaceV2::InternalServerError] - HTTP 500
# @raise [Fog::Compute::RackspaceV2::ServiceError]
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Flavors-d1e4188.html
def list_groups
request(
:expects => [200],
:method => 'GET',
:path => 'groups'
)
end
end
class Mock
def list_groups
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Fog
module Rackspace
class AutoScale
class Real
def update_config(group_id)
h = {
"name" => "workers",
"cooldown" => 60,
"minEntities" => 0,
"maxEntities" => 0,
"metadata" => {
"firstkey" => "this is a string",
"secondkey" => "1"
}
}
request(
:expects => [204],
:method => 'PUT',
:path => "groups/#{group_id}/config",
:body => Fog::JSON.encode(h)
)
end
end
class Mock
def update_config(group_id)
Fog::Mock.not_implemented
end
end
end
end
end

View file

@ -116,6 +116,11 @@ module Fog
@auth_token || @identity_service.auth_token
end
def select_options(keys)
return nil unless @options && keys
@options.select {|k,v| keys.include?(k)}
end
end
end
end

View file

@ -0,0 +1,84 @@
Shindo.tests('Fog::Rackspace::AutoScale', ['rackspace']) do
def assert_method(url, method)
@service.instance_variable_set "@rackspace_auth_url", url
returns(method) { @service.send :authentication_method }
end
tests('#authentication_method') do
@service = Fog::Rackspace::AutoScale.new :rackspace_region => :dfw
assert_method nil, :authenticate_v2
assert_method 'auth.api.rackspacecloud.com', :authenticate_v1 # chef's default auth endpoint
assert_method 'https://identity.api.rackspacecloud.com', :authenticate_v1
assert_method 'https://identity.api.rackspacecloud.com/v1', :authenticate_v1
assert_method 'https://identity.api.rackspacecloud.com/v1.1', :authenticate_v1
assert_method 'https://identity.api.rackspacecloud.com/v2.0', :authenticate_v2
assert_method 'https://lon.identity.api.rackspacecloud.com', :authenticate_v1
assert_method 'https://lon.identity.api.rackspacecloud.com/v1', :authenticate_v1
assert_method 'https://lon.identity.api.rackspacecloud.com/v1.1', :authenticate_v1
assert_method 'https://lon.identity.api.rackspacecloud.com/v2.0', :authenticate_v2
end
tests('current authentation') do
pending if Fog.mocking?
tests('variables populated').succeeds do
@service = Fog::Rackspace::AutoScale.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :connection_options => {:ssl_verify_peer => true}, :rackspace_region => :dfw
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(false, "path populated") { @service.instance_variable_get("@uri").host.nil? }
identity_service = @service.instance_variable_get("@identity_service")
returns(false, "identity service was used") { identity_service.nil? }
returns(true, "connection_options are passed") { identity_service.instance_variable_get("@connection_options").has_key?(:ssl_verify_peer) }
@service.list_groups
end
tests('dfw region').succeeds do
@service = Fog::Rackspace::AutoScale.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :rackspace_region => :dfw
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(true) { (@service.instance_variable_get("@uri").host =~ /dfw/) != nil }
@service.list_groups
end
tests('ord region').succeeds do
@service = Fog::Rackspace::AutoScale.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0', :rackspace_region => :ord
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(true) { (@service.instance_variable_get("@uri").host =~ /ord/) != nil }
@service.list_groups
end
tests('custom endpoint') do
@service = Fog::Rackspace::AutoScale.new :rackspace_auth_url => 'https://identity.api.rackspacecloud.com/v2.0',
:rackspace_auto_scale_url => 'https://my-custom-endpoint.com'
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(true, "uses custom endpoint") { (@service.instance_variable_get("@uri").host =~ /my-custom-endpoint\.com/) != nil }
end
end
tests('default auth') do
pending if Fog.mocking?
tests('specify region').succeeds do
@service = Fog::Rackspace::AutoScale.new :rackspace_region => :ord
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(true) { (@service.instance_variable_get("@uri").host =~ /ord/ ) != nil }
@service.list_groups
end
tests('custom endpoint') do
@service = Fog::Rackspace::AutoScale.new :rackspace_auto_scale_url => 'https://my-custom-endpoint.com'
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
returns(true, "uses custom endpoint") { (@service.instance_variable_get("@uri").host =~ /my-custom-endpoint\.com/) != nil }
end
end
tests('reauthentication') do
pending if Fog.mocking?
@service = Fog::Rackspace::AutoScale.new :rackspace_region => :ord
returns(true, "auth token populated") { !@service.send(:auth_token).nil? }
@service.instance_variable_set("@auth_token", "bad_token")
returns(true) { [200, 203].include? @service.list_groups.status }
end
end