mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Merge pull request #486 from brianhartsock/rs_dns
[rackspace|dns] Rackspace DNS
This commit is contained in:
commit
22a7278a1e
30 changed files with 1124 additions and 37 deletions
|
@ -66,7 +66,7 @@ You can add more specifics if you need to, but reasonable defaults make it just
|
|||
|
||||
## No Zerigo? No Problem
|
||||
|
||||
If you already have an account with another service you can just as easily use this same code with different credentials. fog currently supports <a href="http://aws.amazon.com/route53/">AWS Route 53</a>, <a href="http://bluebox.net">Blue Box</a>, <a href="http://dnsimple.com">DNSimple</a>, <a href="http://www.linode.com">Linode</a>, <a href="http://www.slicehost.com">Slicehost</a> and <a href="http://www.zerigo.com/managed-dns">Zerigo</a>; so you can have your pick. As an example you can connect to AWS instead of Zerigo:
|
||||
If you already have an account with another service you can just as easily use this same code with different credentials. fog currently supports <a href="http://aws.amazon.com/route53/">AWS Route 53</a>, <a href="http://bluebox.net">Blue Box</a>, <a href="http://dnsimple.com">DNSimple</a>, <a href="http://www.linode.com">Linode</a>, <a href="http://www.rackspace.com">Rackspace</a>, <a href="http://www.slicehost.com">Slicehost</a> and <a href="http://www.zerigo.com/managed-dns">Zerigo</a>; so you can have your pick. As an example you can connect to AWS instead of Zerigo:
|
||||
|
||||
dns = Fog::DNS.new({
|
||||
:provider => 'AWS',
|
||||
|
|
|
@ -11,7 +11,9 @@ class Rackspace < Fog::Bin
|
|||
Fog::Storage::Rackspace
|
||||
when :load_balancers
|
||||
Fog::Rackspace::LoadBalancers
|
||||
else
|
||||
when :dns
|
||||
Fog::DNS::Rackspace
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,6 +32,9 @@ module Fog
|
|||
when :zerigo
|
||||
require 'fog/zerigo/dns'
|
||||
Fog::DNS::Zerigo.new(attributes)
|
||||
when :rackspace
|
||||
require 'fog/dns/rackspace'
|
||||
Fog::DNS::Rackspace.new(attributes)
|
||||
else
|
||||
raise ArgumentError.new("#{provider} is not a recognized dns provider")
|
||||
end
|
||||
|
|
28
lib/fog/dns/models/rackspace/callback.rb
Normal file
28
lib/fog/dns/models/rackspace/callback.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
|
||||
module Callback
|
||||
|
||||
protected
|
||||
|
||||
def wait_for_job(job_id, timeout=Fog.timeout, interval=1)
|
||||
retries = 5
|
||||
response = nil
|
||||
Fog.wait_for(timeout, interval) do
|
||||
response = connection.callback job_id
|
||||
if response.status != 202
|
||||
true
|
||||
elsif retries == 0
|
||||
raise Fog::Errors::Error.new("Wait on job #{job_id} took too long")
|
||||
else
|
||||
retries -= 1
|
||||
false
|
||||
end
|
||||
end
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
78
lib/fog/dns/models/rackspace/record.rb
Normal file
78
lib/fog/dns/models/rackspace/record.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/dns/models/rackspace/callback'
|
||||
|
||||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
|
||||
class Record < Fog::Model
|
||||
include Fog::DNS::Rackspace::Callback
|
||||
extend Fog::Deprecation
|
||||
deprecate :ip, :value
|
||||
deprecate :ip=, :value=
|
||||
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :value, :aliases => 'data'
|
||||
attribute :ttl
|
||||
attribute :type
|
||||
attribute :priority
|
||||
attribute :created
|
||||
attribute :updated
|
||||
|
||||
def destroy
|
||||
requires :zone, :identity
|
||||
wait_for_job connection.remove_record(@zone.identity, identity).body['jobId']
|
||||
true
|
||||
end
|
||||
|
||||
def zone
|
||||
@zone
|
||||
end
|
||||
|
||||
def save
|
||||
if identity
|
||||
update
|
||||
else
|
||||
create
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create
|
||||
requires :name, :type, :value, :zone
|
||||
|
||||
options = {
|
||||
:name => name,
|
||||
:type => type,
|
||||
:data => value
|
||||
}
|
||||
|
||||
response = wait_for_job connection.add_records(@zone.identity, [options]).body['jobId']
|
||||
merge_attributes(response.body['records'].first)
|
||||
true
|
||||
end
|
||||
|
||||
def update
|
||||
requires :identity, :zone
|
||||
|
||||
options = {}
|
||||
options[:name] = name if name
|
||||
options[:type] = type if type
|
||||
options[:data] = value if value
|
||||
options[:priority] = priority if priority
|
||||
|
||||
wait_for_job connection.modify_record(@zone.identity, identity, options).body['jobId']
|
||||
true
|
||||
end
|
||||
|
||||
def zone=(new_zone)
|
||||
@zone = new_zone
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/dns/models/rackspace/records.rb
Normal file
38
lib/fog/dns/models/rackspace/records.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/dns/models/rackspace/record'
|
||||
|
||||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
|
||||
class Records < Fog::Collection
|
||||
|
||||
attribute :zone
|
||||
|
||||
model Fog::DNS::Rackspace::Record
|
||||
|
||||
def all
|
||||
requires :zone
|
||||
data = connection.list_records(zone.identity)
|
||||
load(data.body['records'])
|
||||
end
|
||||
|
||||
def get(record_id)
|
||||
requires :zone
|
||||
data = connection.list_record_details(zone.identity, record_id).body
|
||||
new(data)
|
||||
#nil or empty string will trigger an argument error
|
||||
rescue ArgumentError
|
||||
nil
|
||||
rescue Fog::Rackspace::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
def new(attributes = {})
|
||||
requires :zone
|
||||
super({ :zone => zone }.merge!(attributes))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
67
lib/fog/dns/models/rackspace/zone.rb
Normal file
67
lib/fog/dns/models/rackspace/zone.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/dns/models/rackspace/records'
|
||||
|
||||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
|
||||
class Zone < Fog::Model
|
||||
include Fog::DNS::Rackspace::Callback
|
||||
|
||||
identity :id
|
||||
|
||||
attribute :email, :aliases => 'emailAddress'
|
||||
attribute :domain, :aliases => 'name'
|
||||
attribute :created
|
||||
attribute :updated
|
||||
attribute :account_id, :aliases => 'accountId'
|
||||
attribute :ttl
|
||||
attribute :nameservers
|
||||
attribute :comment
|
||||
|
||||
def destroy
|
||||
response = connection.remove_domain(identity)
|
||||
wait_for_job response.body['jobId'], Fog.timeout
|
||||
true
|
||||
end
|
||||
|
||||
def records
|
||||
@records ||= begin
|
||||
Fog::DNS::Rackspace::Records.new(
|
||||
:zone => self,
|
||||
:connection => connection
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
if identity
|
||||
update
|
||||
else
|
||||
create
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create
|
||||
requires :domain, :email
|
||||
|
||||
data = { :name => domain, :email => email }
|
||||
response = connection.create_domains([data])
|
||||
|
||||
response = wait_for_job response.body['jobId']
|
||||
merge_attributes(response.body['domains'].first)
|
||||
end
|
||||
|
||||
def update
|
||||
requires :ttl, :email
|
||||
|
||||
response = connection.modify_domain(identity, { :ttl => ttl, :comment => comment, :email => email})
|
||||
wait_for_job response.body['jobId']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
lib/fog/dns/models/rackspace/zones.rb
Normal file
33
lib/fog/dns/models/rackspace/zones.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/dns/models/rackspace/zone'
|
||||
|
||||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Zones < Fog::Collection
|
||||
|
||||
model Fog::DNS::Rackspace::Zone
|
||||
|
||||
def all
|
||||
clear
|
||||
data = connection.list_domains.body['domains']
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(zone_id)
|
||||
if zone_id.nil? or zone_id.to_s.empty?
|
||||
return nil
|
||||
end
|
||||
|
||||
data = connection.list_domain_details(zone_id).body
|
||||
new(data)
|
||||
rescue Fog::Rackspace::Errors::NotFound
|
||||
nil
|
||||
#Accessing a valid (but other customer's) id returns a 503 error
|
||||
rescue Fog::Rackspace::Errors::ServiceUnavailable
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
100
lib/fog/dns/rackspace.rb
Normal file
100
lib/fog/dns/rackspace.rb
Normal file
|
@ -0,0 +1,100 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace < Fog::Service
|
||||
|
||||
US_ENDPOINT = 'https://dns.api.rackspacecloud.com/v1.0'
|
||||
UK_ENDPOINT = 'https://lon.dns.api.rackspacecloud.com/v1.0'
|
||||
|
||||
requires :rackspace_api_key, :rackspace_username
|
||||
recognizes :rackspace_auth_url
|
||||
recognizes :rackspace_auth_token
|
||||
|
||||
model_path 'fog/dns/models/rackspace'
|
||||
model :record
|
||||
collection :records
|
||||
model :zone
|
||||
collection :zones
|
||||
|
||||
request_path 'fog/dns/requests/rackspace'
|
||||
#TODO - Import/Export, modify multiple domains, modify multiple records
|
||||
request :callback
|
||||
request :list_domains
|
||||
request :list_domain_details
|
||||
request :modify_domain
|
||||
request :create_domains
|
||||
request :remove_domain
|
||||
request :remove_domains
|
||||
request :list_subdomains
|
||||
request :list_records
|
||||
request :list_record_details
|
||||
request :modify_record
|
||||
request :remove_record
|
||||
request :remove_records
|
||||
request :add_records
|
||||
|
||||
class Mock
|
||||
end
|
||||
|
||||
class Real
|
||||
def initialize(options={})
|
||||
require 'multi_json'
|
||||
@rackspace_api_key = options[:rackspace_api_key]
|
||||
@rackspace_username = options[:rackspace_username]
|
||||
@rackspace_auth_url = options[:rackspace_auth_url]
|
||||
uri = URI.parse(options[:rackspace_dns_endpoint] || US_ENDPOINT)
|
||||
|
||||
@auth_token, @account_id = *authenticate
|
||||
@path = "#{uri.path}/#{@account_id}"
|
||||
headers = { 'Content-Type' => 'application/json', 'X-Auth-Token' => @auth_token }
|
||||
|
||||
@connection = Fog::Connection.new(uri.to_s, options[:persistent], { :headers => headers})
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request(params)
|
||||
#TODO - Unify code with other rackspace services
|
||||
begin
|
||||
response = @connection.request(params.merge!({
|
||||
:path => "#{@path}/#{params[:path]}"
|
||||
}))
|
||||
rescue Excon::Errors::BadRequest => error
|
||||
raise Fog::Rackspace::Errors::BadRequest.slurp error
|
||||
rescue Excon::Errors::Conflict => error
|
||||
raise Fog::Rackspace::Errors::Conflict.slurp error
|
||||
rescue Excon::Errors::NotFound => error
|
||||
raise Fog::Rackspace::Errors::NotFound.slurp error
|
||||
rescue Excon::Errors::ServiceUnavailable => error
|
||||
raise Fog::Rackspace::Errors::ServiceUnavailable.slurp error
|
||||
end
|
||||
unless response.body.empty?
|
||||
response.body = MultiJson.decode(response.body)
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
def authenticate
|
||||
options = {
|
||||
:rackspace_api_key => @rackspace_api_key,
|
||||
:rackspace_username => @rackspace_username,
|
||||
:rackspace_auth_url => @rackspace_auth_url
|
||||
}
|
||||
credentials = Fog::Rackspace.authenticate(options)
|
||||
auth_token = credentials['X-Auth-Token']
|
||||
account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1]
|
||||
[auth_token, account_id]
|
||||
end
|
||||
|
||||
def array_to_query_string(arr)
|
||||
arr.collect {|k,v| "#{k}=#{v}" }.join('&')
|
||||
end
|
||||
|
||||
def validate_path_fragment(name, fragment)
|
||||
if fragment.nil? or fragment.to_s.empty?
|
||||
raise ArgumentError.new ("#{name} cannot be null or empty")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
34
lib/fog/dns/requests/rackspace/add_records.rb
Normal file
34
lib/fog/dns/requests/rackspace/add_records.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def add_records(domain_id, records)
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
data = {
|
||||
'records' => records.collect do |record|
|
||||
record_data = {
|
||||
'name' => record[:name],
|
||||
'type' => record[:type],
|
||||
'data' => record[:data]
|
||||
}
|
||||
|
||||
if record.has_key? :priority
|
||||
record_data['priority'] = record[:priority]
|
||||
end
|
||||
record_data
|
||||
end
|
||||
}
|
||||
|
||||
request(
|
||||
:expects => 202,
|
||||
:method => 'POST',
|
||||
:path => "domains/#{domain_id}/records",
|
||||
:body => MultiJson.encode(data)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/fog/dns/requests/rackspace/callback.rb
Normal file
18
lib/fog/dns/requests/rackspace/callback.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def callback(job_id)
|
||||
|
||||
validate_path_fragment :job_id, job_id
|
||||
|
||||
request(
|
||||
:expects => [200, 202, 204],
|
||||
:method => 'GET',
|
||||
:path => "status/#{job_id}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
48
lib/fog/dns/requests/rackspace/create_domains.rb
Normal file
48
lib/fog/dns/requests/rackspace/create_domains.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def create_domains(domains)
|
||||
data = {
|
||||
'domains' => []
|
||||
}
|
||||
|
||||
domains.each do |domain|
|
||||
domain_data =
|
||||
{
|
||||
'name' => domain[:name],
|
||||
'emailAddress' => domain[:email]
|
||||
}
|
||||
|
||||
if domain.has_key? :records
|
||||
domain_data['recordsList'] = {
|
||||
'records' => domain[:records].collect do |record|
|
||||
record_data = {
|
||||
'ttl' => record[:ttl],
|
||||
'data' => record[:data],
|
||||
'name' => record[:name],
|
||||
'type' => record[:type],
|
||||
}
|
||||
|
||||
if record.has_key? :priority
|
||||
record_data.merge!({'priority' => record[:priority]})
|
||||
else
|
||||
record_data
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
data['domains'] << domain_data
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => 202,
|
||||
:method => 'POST',
|
||||
:path => 'domains',
|
||||
:body => MultiJson.encode(data)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/dns/requests/rackspace/list_domain_details.rb
Normal file
32
lib/fog/dns/requests/rackspace/list_domain_details.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def list_domain_details(domain_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}"
|
||||
query_data = {}
|
||||
|
||||
if options.has_key? :show_records
|
||||
query_data['showRecords'] = options[:show_records]
|
||||
end
|
||||
if options.has_key? :show_subdomains
|
||||
query_data['showSubdomains'] = options[:show_subdomains]
|
||||
end
|
||||
|
||||
if !query_data.empty?
|
||||
path = path + '?' + array_to_query_string(query_data)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/dns/requests/rackspace/list_domains.rb
Normal file
21
lib/fog/dns/requests/rackspace/list_domains.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def list_domains(options={})
|
||||
|
||||
path = 'domains'
|
||||
if !options.empty?
|
||||
path = path + '?' + array_to_query_string(options)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/dns/requests/rackspace/list_record_details.rb
Normal file
21
lib/fog/dns/requests/rackspace/list_record_details.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def list_record_details(domain_id, record_id)
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
validate_path_fragment :record_id, record_id
|
||||
|
||||
path = "domains/#{domain_id}/records/#{record_id}"
|
||||
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
lib/fog/dns/requests/rackspace/list_records.rb
Normal file
23
lib/fog/dns/requests/rackspace/list_records.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def list_records(domain_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}/records"
|
||||
if !options.empty?
|
||||
path = path + '?' + array_to_query_string(options)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
lib/fog/dns/requests/rackspace/list_subdomains.rb
Normal file
23
lib/fog/dns/requests/rackspace/list_subdomains.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def list_subdomains(domain_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}/subdomains"
|
||||
if !options.empty?
|
||||
path = path + '?' + array_to_query_string(options)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
36
lib/fog/dns/requests/rackspace/modify_domain.rb
Normal file
36
lib/fog/dns/requests/rackspace/modify_domain.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def modify_domain(domain_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}"
|
||||
data = {}
|
||||
|
||||
if options.has_key? :ttl
|
||||
data['ttl'] = options[:ttl]
|
||||
end
|
||||
if options.has_key? :comment
|
||||
data['comment'] = options[:comment]
|
||||
end
|
||||
if options.has_key? :email
|
||||
data['emailAddress'] = options[:email]
|
||||
end
|
||||
|
||||
if data.empty?
|
||||
return
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'PUT',
|
||||
:path => path,
|
||||
:body => MultiJson.encode(data)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
37
lib/fog/dns/requests/rackspace/modify_record.rb
Normal file
37
lib/fog/dns/requests/rackspace/modify_record.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def modify_record(domain_id, record_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
validate_path_fragment :record_id, record_id
|
||||
|
||||
path = "domains/#{domain_id}/records/#{record_id}"
|
||||
data = {}
|
||||
|
||||
if options.has_key? :ttl
|
||||
data['ttl'] = options[:ttl]
|
||||
end
|
||||
if options.has_key? :name
|
||||
data['name'] = options[:name]
|
||||
end
|
||||
if options.has_key? :data
|
||||
data['data'] = options[:data]
|
||||
end
|
||||
|
||||
if data.empty?
|
||||
return
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'PUT',
|
||||
:path => path,
|
||||
:body => MultiJson.encode(data)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
29
lib/fog/dns/requests/rackspace/remove_domain.rb
Normal file
29
lib/fog/dns/requests/rackspace/remove_domain.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def remove_domain(domain_id, options={})
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}"
|
||||
query_data = {}
|
||||
|
||||
if options.has_key? :delete_subdomains
|
||||
query_data['deleteSubdomains'] = options[:delete_subdomains].to_s
|
||||
end
|
||||
|
||||
if !query_data.empty?
|
||||
path = path + '?' + array_to_query_string(query_data)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'DELETE',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
27
lib/fog/dns/requests/rackspace/remove_domains.rb
Normal file
27
lib/fog/dns/requests/rackspace/remove_domains.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def remove_domains(domain_ids, options={})
|
||||
|
||||
path = "domains?" + domain_ids.collect { |domain_id| "id=#{domain_id}" }.join('&')
|
||||
query_data = {}
|
||||
|
||||
if options.has_key? :delete_subdomains
|
||||
query_data['deleteSubdomains'] = options[:delete_subdomains]
|
||||
end
|
||||
|
||||
if !query_data.empty?
|
||||
path = path + '&' + array_to_query_string(query_data)
|
||||
end
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'DELETE',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
lib/fog/dns/requests/rackspace/remove_record.rb
Normal file
21
lib/fog/dns/requests/rackspace/remove_record.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def remove_record(domain_id, record_id)
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
validate_path_fragment :record_id, record_id
|
||||
|
||||
path = "domains/#{domain_id}/records/#{record_id}"
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'DELETE',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
20
lib/fog/dns/requests/rackspace/remove_records.rb
Normal file
20
lib/fog/dns/requests/rackspace/remove_records.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
module Fog
|
||||
module DNS
|
||||
class Rackspace
|
||||
class Real
|
||||
def remove_records(domain_id, record_ids)
|
||||
|
||||
validate_path_fragment :domain_id, domain_id
|
||||
|
||||
path = "domains/#{domain_id}/records?" + record_ids.collect { |record_id| "id=#{record_id}" }.join('&')
|
||||
|
||||
request(
|
||||
:expects => [202, 204],
|
||||
:method => 'DELETE',
|
||||
:path => path
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,13 +2,51 @@ require 'fog/core'
|
|||
|
||||
module Fog
|
||||
module Rackspace
|
||||
|
||||
extend Fog::Provider
|
||||
|
||||
module Errors
|
||||
class ServiceError < Fog::Errors::Error
|
||||
attr_reader :response_data
|
||||
|
||||
def self.slurp(error)
|
||||
if error.response.body.empty?
|
||||
data = nil
|
||||
message = nil
|
||||
else
|
||||
data = MultiJson.decode(error.response.body)
|
||||
message = data['message']
|
||||
end
|
||||
|
||||
new_error = super(error, message)
|
||||
new_error.instance_variable_set(:@response_data, data)
|
||||
new_error
|
||||
end
|
||||
end
|
||||
|
||||
class InternalServerError < ServiceError; end
|
||||
class Conflict < ServiceError; end
|
||||
class NotFound < ServiceError; end
|
||||
class ServiceUnavailable < ServiceError; end
|
||||
|
||||
class BadRequest < ServiceError
|
||||
#TODO - Need to find a bette way to print out these validation errors when they are thrown
|
||||
attr_reader :validation_errors
|
||||
|
||||
def self.slurp(error)
|
||||
new_error = super(error)
|
||||
unless new_error.response_data.nil?
|
||||
new_error.instance_variable_set(:@validation_errors, new_error.response_data['validationErrors'])
|
||||
end
|
||||
new_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
service(:cdn, 'rackspace/cdn')
|
||||
service(:compute, 'rackspace/compute')
|
||||
service(:storage, 'rackspace/storage')
|
||||
service(:load_balancers, 'rackspace/load_balancers')
|
||||
service(:dns, 'dns/rackspace')
|
||||
|
||||
def self.authenticate(options)
|
||||
rackspace_auth_url = options[:rackspace_auth_url] || "auth.api.rackspacecloud.com"
|
||||
|
@ -32,6 +70,5 @@ module Fog
|
|||
!['X-Server-Management-Url', 'X-Storage-Url', 'X-CDN-Management-Url', 'X-Auth-Token'].include?(key)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,39 +1,12 @@
|
|||
|
||||
module Fog
|
||||
module Rackspace
|
||||
class LoadBalancers < Fog::Service
|
||||
|
||||
class ServiceError < Fog::Errors::Error
|
||||
attr_reader :response_data
|
||||
|
||||
def self.slurp(error)
|
||||
if error.response.body.empty?
|
||||
data = nil
|
||||
message = nil
|
||||
else
|
||||
data = MultiJson.decode(error.response.body)
|
||||
message = data['message']
|
||||
end
|
||||
|
||||
new_error = super(error, message)
|
||||
new_error.instance_variable_set(:@response_data, data)
|
||||
new_error
|
||||
end
|
||||
end
|
||||
|
||||
class InternalServerError < ServiceError; end
|
||||
|
||||
class BadRequest < ServiceError
|
||||
#TODO - Need to find a bette way to print out these validation errors when they are thrown
|
||||
attr_reader :validation_errors
|
||||
|
||||
def self.slurp(error)
|
||||
new_error = super(error)
|
||||
unless new_error.response_data.nil?
|
||||
new_error.instance_variable_set(:@validation_errors, new_error.response_data['validationErrors'])
|
||||
end
|
||||
new_error
|
||||
end
|
||||
end
|
||||
#These references exist for backwards compatibility
|
||||
class ServiceError < Fog::Rackspace::Errors::ServiceError; end
|
||||
class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end
|
||||
class BadRequest < Fog::Rackspace::Errors::BadRequest; end
|
||||
|
||||
DFW_ENDPOINT = 'https://dfw.loadbalancers.api.rackspacecloud.com/v1.0/'
|
||||
ORD_ENDPOINT = 'https://ord.loadbalancers.api.rackspacecloud.com/v1.0/'
|
||||
|
|
|
@ -32,6 +32,12 @@ def dns_providers
|
|||
},
|
||||
:zerigo => {
|
||||
:mocked => false
|
||||
},
|
||||
:rackspace => {
|
||||
:mocked => false,
|
||||
:zone_attributes => {
|
||||
:email => 'fog@example.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
119
tests/dns/requests/rackspace/dns_tests.rb
Normal file
119
tests/dns/requests/rackspace/dns_tests.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
Shindo.tests('Fog::DNS[:rackspace] | DNS requests', ['rackspace', 'dns']) do
|
||||
|
||||
@service = Fog::DNS[:rackspace]
|
||||
|
||||
tests('success on simple domain') do
|
||||
domain_tests(@service, {:name => 'basictestdomain.com', :email => 'hostmaster@basictestdomain.com', :records => [{:ttl => 300, :name => 'basictestdomain.com', :type => 'A', :data => '192.168.1.1'}]}) do
|
||||
|
||||
tests('list_domains').formats(LIST_DOMAIN_FORMAT) do
|
||||
@service.list_domains.body
|
||||
end
|
||||
|
||||
tests("list_domains :limit => 5, :offset => 10, :domain => #{@domain_details.first['name']} --> All possible attributes").formats(LIST_DOMAIN_FORMAT) do
|
||||
@service.list_domains(:limit => 5, :offset => 10, :domain => @domain_details.first['name']).body
|
||||
end
|
||||
|
||||
tests("list_domain_details('#{@domain_id}')").formats(LIST_DOMAIN_DETAILS_WITH_RECORDS) do
|
||||
@service.list_domain_details(@domain_id).body
|
||||
end
|
||||
|
||||
tests("modify_domain('#{@domain_id}', :ttl => 500, :comment => 'woot', :email => 'randomemail@randomhost.com')").succeeds do
|
||||
response = @service.modify_domain @domain_id, :ttl => 500, :comment => 'woot', :email => 'randomemail@randomhost.com'
|
||||
wait_for @service, response
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests('success for domain with multiple records') do
|
||||
domain_tests(@service,
|
||||
{
|
||||
:name => 'testdomainwithmultiplerecords.com',
|
||||
:email => 'hostmaster@testdomainwithmultiplerecords.com',
|
||||
:records =>
|
||||
[
|
||||
{
|
||||
:ttl => 300,
|
||||
:name => 'testdomainwithmultiplerecords.com',
|
||||
:type => 'A',
|
||||
:data => '192.168.1.1'
|
||||
},
|
||||
{
|
||||
:ttl => 3600,
|
||||
:name => 'testdomainwithmultiplerecords.com',
|
||||
:type => 'MX',
|
||||
:data => 'mx.testdomainwithmultiplerecords.com',
|
||||
:priority => 10
|
||||
}
|
||||
]
|
||||
})
|
||||
end
|
||||
|
||||
tests('success for multiple domains') do
|
||||
domains_tests(@service,
|
||||
[
|
||||
{:name => 'basictestdomain1.com', :email => 'hostmaster@basictestdomain1.com', :records => [{:ttl => 300, :name =>'basictestdomain1.com', :type => 'A', :data => '192.168.1.1'}]},
|
||||
{:name => 'basictestdomain2.com', :email => 'hostmaster@basictestdomain2.com', :records => [{:ttl => 300, :name =>'basictestdomain2.com', :type => 'A', :data => '192.168.1.1'}]}
|
||||
])
|
||||
end
|
||||
|
||||
tests('success for domain with subdomain') do
|
||||
domains_tests(@service,
|
||||
[
|
||||
{:name => 'basictestdomain.com', :email => 'hostmaster@basictestdomain.com', :records => [{:ttl => 300, :name =>'basictestdomain.com', :type => 'A', :data => '192.168.1.1'}]},
|
||||
{:name => 'subdomain.basictestdomain.com', :email => 'hostmaster@subdomain.basictestdomain.com', :records => [{:ttl => 300, :name =>'subdomain.basictestdomain.com', :type => 'A', :data => '192.168.1.1'}]}
|
||||
], true) do
|
||||
|
||||
@root_domain_id = @domain_details.find { |domain| domain['name'] == 'basictestdomain.com' }['id']
|
||||
|
||||
tests("list_domain_details('#{@root_domain_id}', :show_records => false, :show_subdomains => false)") do
|
||||
response = @service.list_domain_details(@root_domain_id, :show_records => false, :show_subdomains => false)
|
||||
|
||||
formats(LIST_DOMAIN_DETAILS_WITHOUT_RECORDS_AND_SUBDOMAINS_FORMAT) { response.body }
|
||||
returns(nil) { response.body['recordsList'] }
|
||||
returns(nil) { response.body['subdomains'] }
|
||||
end
|
||||
|
||||
tests("list_domain_details('#{@root_domain_id}', :show_records => true, :show_subdomains => true)") do
|
||||
response = @service.list_domain_details(@root_domain_id, :show_records => true, :show_subdomains => true)
|
||||
|
||||
formats(LIST_DOMAIN_DETAILS_WITH_RECORDS_AND_SUBDOMAINS_FORMAT) { response.body }
|
||||
returns(false) { response.body['recordsList'].nil? }
|
||||
returns(false) { response.body['subdomains'].nil? }
|
||||
end
|
||||
|
||||
tests("list_subdomains('#{@root_domain_id}')").formats(LIST_SUBDOMAINS_FORMAT) do
|
||||
@service.list_subdomains(@root_domain_id).body
|
||||
end
|
||||
|
||||
tests("remove_domain('#{@root_domain_id}', :delete_subdomains => true)") do
|
||||
wait_for @service, @service.remove_domain(@root_domain_id, :delete_subdomains => true)
|
||||
|
||||
test('domain and subdomains were really deleted') do
|
||||
(@service.list_domains.body['domains'].collect { |domain| domain['name'] } & ['basictestdomain.com', 'subdomain.basictestdomain.com']).empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests( 'failure') do
|
||||
|
||||
tests('create_domain(invalid)').raises(Fog::Rackspace::Errors::BadRequest) do
|
||||
wait_for @service, @service.create_domains([{:name => 'badtestdomain.com', :email => '', :records => [{:ttl => 300, :name => 'badtestdomain.com', :type => 'A', :data => '192.168.1.1'}]}])
|
||||
end
|
||||
|
||||
tests('list_domains :limit => 5, :offset => 8').raises(Fog::Rackspace::Errors::BadRequest) do
|
||||
@service.list_domains :limit => 5, :offset => 8
|
||||
end
|
||||
|
||||
tests('list_domain_details 34335353').raises(Fog::Rackspace::Errors::NotFound) do
|
||||
@service.list_domain_details 34335353
|
||||
end
|
||||
|
||||
#tests('create_domains(#{domains})').raises(Fog::Rackspace::Errors::Conflict) do
|
||||
# wait_for @service.create_domains(domains)
|
||||
#end
|
||||
#tests('remove_domain(34343435)').raises(Fog::DNS::Rackspace::DeleteFault) do
|
||||
# @service.remove_domain 34343435
|
||||
#end
|
||||
end
|
||||
end
|
132
tests/dns/requests/rackspace/helper.rb
Normal file
132
tests/dns/requests/rackspace/helper.rb
Normal file
|
@ -0,0 +1,132 @@
|
|||
SUBDOMAIN_FORMAT = {
|
||||
'name' => String,
|
||||
'id' => Integer,
|
||||
'created' => String,
|
||||
'updated' => String
|
||||
}
|
||||
|
||||
LIST_SUBDOMAINS_FORMAT = {
|
||||
'domains' => [SUBDOMAIN_FORMAT],
|
||||
'totalEntries' => Integer
|
||||
}
|
||||
|
||||
LIST_DOMAIN_FORMAT = {
|
||||
'domains' => [
|
||||
{
|
||||
'name' => String,
|
||||
'id' => Integer,
|
||||
'accountId' => Integer,
|
||||
'updated' => String,
|
||||
'created' => String
|
||||
}
|
||||
],
|
||||
'totalEntries' => Integer,
|
||||
'links' => [
|
||||
{
|
||||
'rel' => String,
|
||||
'href' => String
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
RECORD_FORMAT = {
|
||||
'name' => String,
|
||||
'id' => String,
|
||||
'type' => String,
|
||||
'data' => String,
|
||||
'updated' => String,
|
||||
'created' => String,
|
||||
'ttl' => Integer,
|
||||
'priority' => Fog::Nullable::Integer
|
||||
}
|
||||
|
||||
RECORD_LIST_FORMAT = {
|
||||
'records' => [RECORD_FORMAT],
|
||||
#In some cases this is returned (domain details) and in some cases it isn't (create domain). Marking as nullable.
|
||||
'totalEntries' => Fog::Nullable::Integer
|
||||
}
|
||||
|
||||
NAME_SERVERS_FORMAT = [{
|
||||
'name' => String
|
||||
}]
|
||||
|
||||
BASIC_DOMAIN_DETAIL_FORMAT = {
|
||||
'name' => String,
|
||||
'id' => Integer,
|
||||
'accountId' => Integer,
|
||||
'updated' => String,
|
||||
'created' =>String,
|
||||
'ttl' => Integer,
|
||||
'emailAddress' => String,
|
||||
'nameservers' => NAME_SERVERS_FORMAT
|
||||
}
|
||||
|
||||
LIST_DOMAIN_DETAILS_WITH_RECORDS = BASIC_DOMAIN_DETAIL_FORMAT.merge({
|
||||
'recordsList' => RECORD_LIST_FORMAT
|
||||
})
|
||||
|
||||
LIST_DOMAIN_DETAILS_WITH_RECORDS_AND_SUBDOMAINS_FORMAT = BASIC_DOMAIN_DETAIL_FORMAT.merge({
|
||||
'recordsList' => RECORD_LIST_FORMAT,
|
||||
'subdomains' => [SUBDOMAIN_FORMAT]
|
||||
})
|
||||
|
||||
LIST_DOMAIN_DETAILS_WITHOUT_RECORDS_AND_SUBDOMAINS_FORMAT = BASIC_DOMAIN_DETAIL_FORMAT
|
||||
|
||||
CREATE_DOMAINS_FORMAT = {
|
||||
'domains' => [
|
||||
BASIC_DOMAIN_DETAIL_FORMAT.merge({
|
||||
'recordsList' => RECORD_LIST_FORMAT
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
def wait_for(service, response)
|
||||
job_id = response.body['jobId']
|
||||
while true
|
||||
response = service.callback(job_id)
|
||||
return response if response.status != 202
|
||||
sleep 5
|
||||
end
|
||||
end
|
||||
|
||||
def domain_tests(service, domain_attributes)
|
||||
tests("create_domains([#{domain_attributes}])").formats(CREATE_DOMAINS_FORMAT) do
|
||||
response = wait_for service, service.create_domains([domain_attributes])
|
||||
@domain_details = response.body['domains']
|
||||
@domain_id = @domain_details[0]['id']
|
||||
response.body
|
||||
end
|
||||
|
||||
begin
|
||||
if block_given?
|
||||
yield
|
||||
end
|
||||
ensure
|
||||
tests("remove_domain('#{@domain_id}')").succeeds do
|
||||
wait_for service, service.remove_domain(@domain_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def domains_tests(service, domains_attributes, custom_delete = false)
|
||||
tests("create_domains(#{domains_attributes})").formats(CREATE_DOMAINS_FORMAT) do
|
||||
response = wait_for service, service.create_domains(domains_attributes)
|
||||
@domain_details = response.body['domains']
|
||||
@domain_ids = @domain_details.collect { |domain| domain['id'] }
|
||||
response.body
|
||||
end
|
||||
|
||||
begin
|
||||
if block_given?
|
||||
yield
|
||||
end
|
||||
ensure
|
||||
if !custom_delete
|
||||
tests("remove_domains(#{@domain_ids})").succeeds do
|
||||
wait_for service, service.remove_domains(@domain_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
81
tests/dns/requests/rackspace/records_tests.rb
Normal file
81
tests/dns/requests/rackspace/records_tests.rb
Normal file
|
@ -0,0 +1,81 @@
|
|||
Shindo.tests('Fog::DNS[:rackspace] | dns records requests', ['rackspace', 'dns']) do
|
||||
|
||||
@service = Fog::DNS[:rackspace]
|
||||
|
||||
domain_tests(@service, {:name => 'basictestdomain.com', :email => 'hostmaster@basictestdomain.com', :records => [{:ttl => 300, :name => 'basictestdomain.com', :type => 'A', :data => '192.168.1.1'}]}) do
|
||||
|
||||
tests('success on single record') do
|
||||
|
||||
tests("list_records(#{@domain_id})").formats(RECORD_LIST_FORMAT) do
|
||||
@service.list_records(@domain_id).body
|
||||
end
|
||||
|
||||
tests("add_records(#{@domain_id}, [{ :name => 'test1.basictestdomain.com', :type => 'A', :data => '192.168.2.1'}])").formats(RECORD_LIST_FORMAT) do
|
||||
response = wait_for @service, @service.add_records(@domain_id, [{ :name => 'test1.basictestdomain.com', :type => 'A', :data => '192.168.2.1'}])
|
||||
@record_id = response.body['records'].first['id']
|
||||
response.body
|
||||
end
|
||||
|
||||
tests("list_record_details(#{@domain_id}, #{@record_id})").formats(RECORD_FORMAT) do
|
||||
@service.list_record_details(@domain_id, @record_id).body
|
||||
end
|
||||
|
||||
tests("modify_record(#{@domain_id}, #{@record_id}, { :ttl => 500, :name => 'test2.basictestdomain.com', :data => '192.168.3.1' })").succeeds do
|
||||
wait_for @service, @service.modify_record(@domain_id, @record_id, { :ttl => 500, :name => 'test2.basictestdomain.com', :data => '192.168.3.1' })
|
||||
end
|
||||
|
||||
tests("remove_record(#{@domain_id}, #{@record_id})").succeeds do
|
||||
wait_for @service, @service.remove_record(@domain_id, @record_id)
|
||||
end
|
||||
end
|
||||
|
||||
tests('success on multiple records') do
|
||||
|
||||
records_attributes =
|
||||
[
|
||||
{ :name => 'test1.basictestdomain.com', :type => 'A', :data => '192.168.2.1'},
|
||||
{ :name => 'basictestdomain.com', :type => 'MX', :priority => 10, :data => 'mx.basictestdomain.com'}
|
||||
]
|
||||
|
||||
tests("add_records(#{@domain_id}, #{records_attributes})").formats(RECORD_LIST_FORMAT) do
|
||||
response = wait_for @service, @service.add_records(@domain_id, records_attributes)
|
||||
@record_ids = response.body['records'].collect { |record| record['id'] }
|
||||
response.body
|
||||
end
|
||||
|
||||
tests("remove_records(#{@domain_id}, #{@record_ids})").succeeds do
|
||||
wait_for @service, @service.remove_records(@domain_id, @record_ids)
|
||||
end
|
||||
end
|
||||
|
||||
tests( 'failure') do
|
||||
tests("list_records('')").raises(ArgumentError) do
|
||||
@service.list_records('')
|
||||
end
|
||||
|
||||
tests("list_records('abc')").raises(Fog::Rackspace::Errors::NotFound) do
|
||||
@service.list_records('abc')
|
||||
end
|
||||
|
||||
tests("list_record_details(#{@domain_id}, '')").raises(ArgumentError) do
|
||||
@service.list_record_details(@domain_id, '')
|
||||
end
|
||||
|
||||
tests("list_record_details(#{@domain_id}, 'abc')").raises(Fog::Rackspace::Errors::NotFound) do
|
||||
@service.list_record_details(@domain_id, 'abc')
|
||||
end
|
||||
|
||||
tests("remove_record(#{@domain_id}, '')").raises(ArgumentError) do
|
||||
@service.remove_record(@domain_id, '')
|
||||
end
|
||||
|
||||
tests("remove_record(#{@domain_id}, 'abc')").raises(Fog::Rackspace::Errors::NotFound) do
|
||||
@service.remove_record(@domain_id, 'abc')
|
||||
end
|
||||
|
||||
tests("add_record(#{@domain_id}, [{ :name => '', :type => '', :data => ''}])").raises(Fog::Rackspace::Errors::BadRequest) do
|
||||
@service.add_records(@domain_id, [{ :name => '', :type => '', :data => ''}])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,7 +21,7 @@ Shindo.tests('Fog::Rackspace::LoadBalancers | virtual_ip_tests', ['rackspace'])
|
|||
|
||||
tests('failure') do
|
||||
#TODO - I feel like this should really be a BadRequest, need to dig in
|
||||
tests('create_virtual_ip(invalid type)').raises(Fog::Rackspace::LoadBalancers::ServiceError) do
|
||||
tests('create_virtual_ip(invalid type)').raises(Fog::Rackspace::LoadBalancers::InteralServerError) do
|
||||
@service.create_virtual_ip(@lb.id, 'badtype')
|
||||
end
|
||||
tests('delete_virtual_ip(0)').raises(Fog::Rackspace::LoadBalancers::NotFound) do
|
||||
|
|
Loading…
Add table
Reference in a new issue