From 52bf685764a71ef749c596fcafb46232e8b637a6 Mon Sep 17 00:00:00 2001 From: ggoodale Date: Mon, 24 Jan 2011 17:30:57 -0800 Subject: [PATCH] Basic framework, including all query mechanisms --- lib/fog/dns.rb | 3 + lib/fog/dns/bluebox.rb | 107 ++++++++ lib/fog/dns/models/bluebox/record.rb | 59 ++++ lib/fog/dns/models/bluebox/records.rb | 36 +++ lib/fog/dns/models/bluebox/zone.rb | 54 ++++ lib/fog/dns/models/bluebox/zones.rb | 28 ++ lib/fog/dns/parsers/bluebox/create_record.rb | 0 lib/fog/dns/parsers/bluebox/delete_record.rb | 0 lib/fog/dns/parsers/bluebox/get_record.rb | 21 ++ lib/fog/dns/parsers/bluebox/get_records.rb | 27 ++ lib/fog/dns/parsers/bluebox/get_zone.rb | 23 ++ lib/fog/dns/parsers/bluebox/get_zones.rb | 30 ++ lib/fog/dns/requests/bluebox/create_record.rb | 0 lib/fog/dns/requests/bluebox/delete_record.rb | 0 lib/fog/dns/requests/bluebox/get_record.rb | 40 +++ lib/fog/dns/requests/bluebox/get_records.rb | 41 +++ lib/fog/dns/requests/bluebox/get_zone.rb | 44 +++ lib/fog/dns/requests/bluebox/get_zones.rb | 43 +++ tests/dns/requests/bluebox/dns_tests.rb | 258 ++++++++++++++++++ 19 files changed, 814 insertions(+) create mode 100644 lib/fog/dns/bluebox.rb create mode 100644 lib/fog/dns/models/bluebox/record.rb create mode 100644 lib/fog/dns/models/bluebox/records.rb create mode 100644 lib/fog/dns/models/bluebox/zone.rb create mode 100644 lib/fog/dns/models/bluebox/zones.rb create mode 100644 lib/fog/dns/parsers/bluebox/create_record.rb create mode 100644 lib/fog/dns/parsers/bluebox/delete_record.rb create mode 100644 lib/fog/dns/parsers/bluebox/get_record.rb create mode 100644 lib/fog/dns/parsers/bluebox/get_records.rb create mode 100644 lib/fog/dns/parsers/bluebox/get_zone.rb create mode 100644 lib/fog/dns/parsers/bluebox/get_zones.rb create mode 100644 lib/fog/dns/requests/bluebox/create_record.rb create mode 100644 lib/fog/dns/requests/bluebox/delete_record.rb create mode 100644 lib/fog/dns/requests/bluebox/get_record.rb create mode 100644 lib/fog/dns/requests/bluebox/get_records.rb create mode 100644 lib/fog/dns/requests/bluebox/get_zone.rb create mode 100644 lib/fog/dns/requests/bluebox/get_zones.rb create mode 100644 tests/dns/requests/bluebox/dns_tests.rb diff --git a/lib/fog/dns.rb b/lib/fog/dns.rb index 89ca606db..089211849 100644 --- a/lib/fog/dns.rb +++ b/lib/fog/dns.rb @@ -7,6 +7,9 @@ module Fog when 'AWS' require 'fog/dns/aws' Fog::AWS::DNS.new(attributes) + when 'Bluebox' + require 'fog/dns/bluebox' + Fog::Bluebox::DNS.new(attributes) when 'Linode' require 'fog/dns/linode' Fog::Linode::DNS.new(attributes) diff --git a/lib/fog/dns/bluebox.rb b/lib/fog/dns/bluebox.rb new file mode 100644 index 000000000..61c4c79bb --- /dev/null +++ b/lib/fog/dns/bluebox.rb @@ -0,0 +1,107 @@ +module Fog + module Bluebox + class DNS < Fog::Service + requires :bluebox_api_key, :bluebox_customer_id + recognizes :bluebox_host, :bluebox_port, :bluebox_scheme, :persistent + recognizes :provider # remove post deprecation + + model_path 'fog/dns/models/bluebox' + model :record + collection :records + model :zone + collection :zones + + request_path 'fog/dns/requests/bluebox' + request :create_record + request :delete_record + request :get_record + request :get_records + request :get_zone + request :get_zones + + class Mock + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = {} + end + end + + def self.reset_data(keys=data.keys) + for key in [*keys] + data.delete(key) + end + end + + def initialize(options={}) + unless options.delete(:provider) + location = caller.first + warning = "[yellow][WARN] Fog::Bluebox::DNS.new is deprecated, use Fog::DNS.new(:provider => 'Bluebox') instead[/]" + warning << " [light_black](" << location << ")[/] " + Formatador.display_line(warning) + end + + @bluebox_customer_id = options[:bluebox_customer_id] + @bluebox_api_key = options[:bluebox_api_key] + @data = self.class.data[@bluebox_customer_id] + @data = self.class.data[@bluebox_api_key] + end + end + + class Real + def initialize(options ={}) + unless options.delete(:provider) + location = caller.first + warning = "[yellow][WARN] Fog::Bluebox::DNS.new is deprecated, use Fog::DNS.new(:provider => 'Bluebox') instead[/]" + warning << " [light_black](" << location << ")[/] " + Formatador.display_line(warning) + end + + @bluebox_customer_id = options[:bluebox_customer_id] + @bluebox_api_key = options[:bluebox_api_key] + + @host = options[:host] || "boxpanel.bluebox.net" + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", options[:persistent]) + end + + def reload + @connection.reset + end + + def request(params) + params[:headers] ||= {} + + params[:headers]['Authorization'] = "Basic #{auth_header}" + + case params[:method] + when 'DELETE', 'GET', 'HEAD' + params[:headers]['Accept'] = 'application/xml' + when 'POST', 'PUT' + params[:headers]['Content-Type'] = 'application/xml' + end + + begin + response = @connection.request(params.merge!({:host => @host})) + rescue Excon::Errors::HTTPStatusError => error + raise case error + when Excon::Errors::NotFound + Fog::Bluebox::DNS::NotFound.slurp(error) + else + error + end + end + + response + end + + protected + + def auth_header + @auth_header ||= Base64.encode64("#{@bluebox_customer_id}:#{@bluebox_api_key}").gsub("\n",'') + end + + end + end + end +end \ No newline at end of file diff --git a/lib/fog/dns/models/bluebox/record.rb b/lib/fog/dns/models/bluebox/record.rb new file mode 100644 index 000000000..11e1fe75c --- /dev/null +++ b/lib/fog/dns/models/bluebox/record.rb @@ -0,0 +1,59 @@ +require 'fog/core/model' + +module Fog + module Bluebox + class DNS + + class Record < Fog::Model + + identity :id + + attribute :name + attribute :domain_id, :aliases => 'domain-id' + attribute :domain + attribute :type + attribute :content + + def initialize(attributes={}) + super + end + + def destroy + requires :identity + connection.delete_record(identity) + true + end + + def zone + @zone + end + + def save + requires :zone, :type, :ip + options = {} + options[:hostname] = name if name + options[:notes] = description if description + options[:priority] = priority if priority + options[:ttl] = ttl if ttl + data = unless identity + connection.create_record(@zone.id, type, ip, options) + else + options[:host_type] = type + options[:data] = data + connection.update_record(identity, options) + end + merge_attributes(data.body) + true + end + + private + + def zone=(new_zone) + @zone = new_zone + end + + end + + end + end +end diff --git a/lib/fog/dns/models/bluebox/records.rb b/lib/fog/dns/models/bluebox/records.rb new file mode 100644 index 000000000..dd93548d0 --- /dev/null +++ b/lib/fog/dns/models/bluebox/records.rb @@ -0,0 +1,36 @@ +require 'fog/core/collection' +require 'fog/dns/models/bluebox/record' + +module Fog + module Bluebox + class DNS + + class Records < Fog::Collection + + attribute :zone + + model Fog::Bluebox::DNS::Record + + def all + requires :zone + data = connection.get_records(zone.identity).body['records'] + load(data) + end + + def get(record_id) + data = connection.get_record(zone.identity, record_id).body + new(data) + rescue Fog::Service::NotFound + nil + end + + def new(attributes = {}) + requires :zone + super({ :zone => zone }.merge!(attributes)) + end + + end + + end + end +end diff --git a/lib/fog/dns/models/bluebox/zone.rb b/lib/fog/dns/models/bluebox/zone.rb new file mode 100644 index 000000000..599518307 --- /dev/null +++ b/lib/fog/dns/models/bluebox/zone.rb @@ -0,0 +1,54 @@ +require 'fog/core/model' +require 'fog/dns/models/bluebox/records' + +module Fog + module Bluebox + class DNS + + class Zone < Fog::Model + + identity :id + + attribute :name + attribute :serial + attribute :ttl + attribute :retry + attribute :expires + attribute :record_count, :aliases => 'record-count' + attribute :refresh + attribute :minimum + + def initialize(attributes = {}) + super(attributes) + end + + def destroy + raise Fog::Errors::Error.new('Not implemented') + end + + def records + @records ||= begin + Fog::Bluebox::DNS::Records.new( + :zone => self, + :connection => connection + ) + end + end + + def nameservers + [ + 'ns1.blueblxgrid.com', + 'ns2.blueblxgrid.com', + 'ns3.blueblxgrid.com' + ] + end + + def save + raise Fog::Errors::Error.new('Not implemented') + end + + end + + end + end +end diff --git a/lib/fog/dns/models/bluebox/zones.rb b/lib/fog/dns/models/bluebox/zones.rb new file mode 100644 index 000000000..3a6ac9b43 --- /dev/null +++ b/lib/fog/dns/models/bluebox/zones.rb @@ -0,0 +1,28 @@ +require 'fog/core/collection' +require 'fog/dns/models/bluebox/zone' + +module Fog + module Bluebox + class DNS + + class Zones < Fog::Collection + + model Fog::Bluebox::DNS::Zone + + def all + data = connection.get_zones.body['zones'] + load(data) + end + + def get(zone_id) + data = connection.get_zone(zone_id).body + new(data) + rescue Fog::Service::NotFound + nil + end + + end + + end + end +end diff --git a/lib/fog/dns/parsers/bluebox/create_record.rb b/lib/fog/dns/parsers/bluebox/create_record.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/dns/parsers/bluebox/delete_record.rb b/lib/fog/dns/parsers/bluebox/delete_record.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/dns/parsers/bluebox/get_record.rb b/lib/fog/dns/parsers/bluebox/get_record.rb new file mode 100644 index 000000000..0b3a705fc --- /dev/null +++ b/lib/fog/dns/parsers/bluebox/get_record.rb @@ -0,0 +1,21 @@ +module Fog + module Parsers + module Bluebox + module DNS + + class GetRecord < Fog::Parsers::Base + + def reset + @response = { } + end + + def end_element(name) + @response[name] = @value + end + + end + + end + end + end +end diff --git a/lib/fog/dns/parsers/bluebox/get_records.rb b/lib/fog/dns/parsers/bluebox/get_records.rb new file mode 100644 index 000000000..29641cbde --- /dev/null +++ b/lib/fog/dns/parsers/bluebox/get_records.rb @@ -0,0 +1,27 @@ +module Fog + module Parsers + module Bluebox + module DNS + + class GetRecords < Fog::Parsers::Base + + def reset + @record = {} + @response = { 'records' => [] } + end + + def end_element(name) + case name + when 'record' + @response['records'] << @record + @record = {} + else + @record[name] = @value + end + end + end + + end + end + end +end diff --git a/lib/fog/dns/parsers/bluebox/get_zone.rb b/lib/fog/dns/parsers/bluebox/get_zone.rb new file mode 100644 index 000000000..6a3fbdbbe --- /dev/null +++ b/lib/fog/dns/parsers/bluebox/get_zone.rb @@ -0,0 +1,23 @@ +module Fog + module Parsers + module Bluebox + module DNS + class GetZone < Fog::Parsers::Base + + def reset + @response = {} + end + + def end_element(name) + case name + when 'serial', 'ttl', 'retry', 'expires', 'record-count', 'refresh', 'minimum' + @response[name] = @value.to_i + when 'name', 'id' + @response[name] = @value + end + end + end + end + end + end +end diff --git a/lib/fog/dns/parsers/bluebox/get_zones.rb b/lib/fog/dns/parsers/bluebox/get_zones.rb new file mode 100644 index 000000000..ade93a420 --- /dev/null +++ b/lib/fog/dns/parsers/bluebox/get_zones.rb @@ -0,0 +1,30 @@ +module Fog + module Parsers + module Bluebox + module DNS + + class GetZones < Fog::Parsers::Base + + def reset + @zone = {} + @response = { 'zones' => [] } + end + + def end_element(name) + case name + when 'serial', 'ttl', 'retry', 'expires', 'record-count', 'refresh', 'minimum' + @zone[name] = @value.to_i + when 'name', 'id' + @zone[name] = @value + when 'record' + @response['zones'] << @zone + @zone = {} + end + end + + end + + end + end + end +end diff --git a/lib/fog/dns/requests/bluebox/create_record.rb b/lib/fog/dns/requests/bluebox/create_record.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/dns/requests/bluebox/delete_record.rb b/lib/fog/dns/requests/bluebox/delete_record.rb new file mode 100644 index 000000000..e69de29bb diff --git a/lib/fog/dns/requests/bluebox/get_record.rb b/lib/fog/dns/requests/bluebox/get_record.rb new file mode 100644 index 000000000..fca904080 --- /dev/null +++ b/lib/fog/dns/requests/bluebox/get_record.rb @@ -0,0 +1,40 @@ +module Fog + module Bluebox + class DNS + class Real + + require 'fog/dns/parsers/bluebox/get_record' + + # Get an individual DNS record from the specified zone + # + # ==== Returns + # * response<~Excon::Response>: + # * hash<~Hash>: + # * 'id'<~String> - The id of this record + # * 'type'<~String> - type of DNS record to create (A, CNAME, etc) + # * 'domain-id'<~Integer> - ID of the zone + # * 'name'<~String> - empty? + # * 'domain'<~String> - The domain name + # * 'type'<~String> - The type of DNS record (e.g. A, MX, NS, etc.) + # * 'content'<~String> - data for the DNS record (ie for an A record, the IP address) + def get_record(zone_id, record_id) + request( + :expects => 200, + :method => 'GET', + :parser => Fog::Parsers::Bluebox::DNS::GetRecord.new, + :path => "/api/domains/#{zone_id}/records/#{record_id}.xml" + ) + end + + end + + class Mock + + def get_record(record_id) + Fog::Mock.not_implemented + end + + end + end + end +end diff --git a/lib/fog/dns/requests/bluebox/get_records.rb b/lib/fog/dns/requests/bluebox/get_records.rb new file mode 100644 index 000000000..186638e3f --- /dev/null +++ b/lib/fog/dns/requests/bluebox/get_records.rb @@ -0,0 +1,41 @@ +module Fog + module Bluebox + class DNS + class Real + + require 'fog/dns/parsers/bluebox/get_records' + + # Get all the DNS records across all the DNS zones for this account + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Array>: + # * 'addresses'<~Array> - Ip addresses for the slice + # * 'backup-id'<~Integer> - Id of backup slice was booted from + # * 'flavor_id'<~Integer> - Id of flavor slice was booted from + # * 'id'<~Integer> - Id of the slice + # * 'image-id'<~Integer> - Id of image slice was booted from + # * 'name'<~String> - Name of the slice + # * 'progress'<~Integer> - Progress of current action, in percentage + # * 'status'<~String> - Current status of the slice + def get_records(zone_id) + request( + :expects => 200, + :method => 'GET', + :parser => Fog::Parsers::Bluebox::DNS::GetRecords.new, + :path => "/api/domains/#{zone_id}/records.xml" + ) + end + + end + + class Mock + + def get_records + Fog::Mock.not_implemented + end + + end + end + end +end diff --git a/lib/fog/dns/requests/bluebox/get_zone.rb b/lib/fog/dns/requests/bluebox/get_zone.rb new file mode 100644 index 000000000..b98086cfb --- /dev/null +++ b/lib/fog/dns/requests/bluebox/get_zone.rb @@ -0,0 +1,44 @@ +module Fog + module Bluebox + class DNS + class Real + + require 'fog/dns/parsers/bluebox/get_zone' + + # Get details of a DNS zone + # + # ==== Parameters + # * zone_id<~Integer> - Id of zone to lookup + # + # ==== Returns + # * response<~Excon::Response>: + # * hash<~Hash>: + # * 'name'<~String> - The name of the zone + # * 'serial'<~Integer> - Serial number of the zone + # * 'ttl'<~Integer> - TimeToLive (ttl) for the domain, in seconds + # * 'retry'<~Integer> - Retry interval for the domain, in seconds + # * 'record-count'<~Integer> - Number of records in the zone + # * 'id'<~String> - Id for the zone + # * 'refresh'<~Integer> - Refresh interval for the zone + # * 'minimum'<~Integer> - Minimum refresh interval for the zone + def get_zone(zone_id) + request( + :expects => 200, + :method => 'GET', + :parser => Fog::Parsers::Bluebox::DNS::GetZone.new, + :path => "/api/domains/#{zone_id}.xml" + ) + end + + end + + class Mock + + def get_zone(zone_id) + Fog::Mock.not_implemented + end + + end + end + end +end diff --git a/lib/fog/dns/requests/bluebox/get_zones.rb b/lib/fog/dns/requests/bluebox/get_zones.rb new file mode 100644 index 000000000..9f7750890 --- /dev/null +++ b/lib/fog/dns/requests/bluebox/get_zones.rb @@ -0,0 +1,43 @@ +module Fog + module Bluebox + class DNS + class Real + + require 'fog/dns/parsers/bluebox/get_zones' + + # Get list of all DNS zones hosted on Bluebox (for this account) + # + # ==== Returns + # * response<~Excon::Response>: + # * 'records'<~Array> + # * 'record' + # * 'name'<~String> - name of the zone + # * 'serial'<~Integer> - Serial # for the zone + # * 'ttl'<~Integer> - TTL for the zone record in seconds + # * 'retry'<~Integer> - Retry interval for the zone record in seconds + # * 'expires'<~Integer> - Expiration interval for the zone record in seconds + # * 'record-count'<~Integer> - # of records in this zone + # * 'id'<~String> - Id for the zone record + # * 'refresh'<~Integer> - default refresh interval for this zone, in seconds + # * 'minimum'<~Integer> - minimum value for intervals for this zone, in seconds + def get_zones + request( + :expects => 200, + :method => 'GET', + :parser => Fog::Parsers::Bluebox::DNS::GetZones.new, + :path => '/api/domains.xml' + ) + end + + end + + class Mock + + def get_zones + Fog::Mock.not_implemented + end + + end + end + end +end diff --git a/tests/dns/requests/bluebox/dns_tests.rb b/tests/dns/requests/bluebox/dns_tests.rb new file mode 100644 index 000000000..d89dd7af6 --- /dev/null +++ b/tests/dns/requests/bluebox/dns_tests.rb @@ -0,0 +1,258 @@ +Shindo.tests('Bluebox::dns | DNS requests', ['bluebox', 'dns']) do + + @domain = '' + @new_zones = [] + @new_records =[] + + def generate_unique_domain( with_trailing_dot = false) + #get time (with 1/100th of sec accuracy) + #want unique domain name and if provider is fast, this can be called more than once per second + time= (Time.now.to_f * 100).to_i + domain = 'test-' + time.to_s + '.com' + if with_trailing_dot + domain+= '.' + end + + domain + end + + tests( 'success') do + + test('get current zone count') do + pending if Fog.mocking? + + @org_zone_count= 0 + response = Bluebox[:dns].get_zones() + if response.status == 200 + zones = response.body['zones'] + @org_zone_count = zones.count + end + + response.status == 200 + end + + test('create zone - simple') do + pending + end + + test('create zone - set all parameters') do + pending + end + + test("get zone #{@zone_id} - check all parameters for #{@domain}") do + pending if Fog.mocking? + + result = false + + response = Bluebox[:dns].get_zone(@zone_id) + if response.status == 200 + zone = response.body + if (zone['name'] == @domain) and (zone['ttl'] == 3600) + result = true + end + end + + result + end + + test('get zones - make sure total count is correct') do + pending if Fog.mocking? + + result = false + + response = Bluebox[:dns].get_zones() + if response.status == 200 + zones = response.body['records'] + if (@org_zone_count+2) == zones.count + result= true; + end + end + + result + end + + test('get zones - check all parameters for a zone') do + pending if Fog.mocking? + + result= false + + response = Bluebox[:dns].get_zones() + if response.status == 200 + zones = response.body['records'] + zones.each { |zone| + if zone['id'] == @new_zones[1] + if (zone['name'] == 'sub.' + @domain) and (zone['ttl'] == 3600) + result = true; + end + end + } + if (@org_zone_count+2) == zones.count + result = true; + end + end + + result + end + + test('create record - simple A record') do + pending if Fog.mocking? + + host= 'www.' + @domain + zone_id= @new_zones[1] + response = Bluebox[:dns].create_record( 'A', zone_id, host, '1.2.3.4') + if response.status == 201 + record_id = response.body['id'] + @new_records << record_id + end + + response.status == 201 + end + + test('create record - A record - all parameters set') do + pending if Fog.mocking? + + host= 'ftp.' + @domain + zone_id= @new_zones[1] + options = { :ttl => 3600, :active => 'N'} + response = Bluebox[:dns].create_record( 'A', zone_id, host, '1.2.3.4', options) + if response.status == 201 + record_id = response.body['id'] + @new_records << record_id + end + + response.status == 201 + end + + test('create record - CNAME record') do + pending if Fog.mocking? + + zone_id= @new_zones[1] + response = Bluebox[:dns].create_record( 'CNAME', zone_id, 'mail', @domain) + if response.status == 201 + record_id = response.body['id'] + @new_records << record_id + end + + response.status == 201 + end + + test('create record - NS record') do + pending if Fog.mocking? + + ns_domain = 'ns.' + @domain + zone_id= @new_zones[1] + options = { :ttl => 3600, :active => 'N'} + response = Bluebox[:dns].create_record( 'NS', zone_id, @domain, ns_domain, options) + if response.status == 201 + record_id = response.body['id'] + @new_records << record_id + end + + response.status == 201 + end + + test('create record - MX record') do + pending if Fog.mocking? + + mail_domain = 'mail.' + @domain + zone_id= @new_zones[1] + options = { :ttl => 3600, :active => 'N', :aux => '10'} + response = Slicehost[:dns].create_record( 'MX', zone_id, @domain, mail_domain, options) + if response.status == 201 + @record_id = response.body['id'] + @new_records << @record_id + end + + response.status == 201 + end + + test("get record #{@record_id} - verify all parameters") do + pending if Fog.mocking? + + result= false + + response = Slicehost[:dns].get_record(@record_id) + if response.status == 200 + mail_domain = 'mail.' + @domain + record = response.body['records'][0] + if (record['record-type'] == 'MX') and (record['name'] == @domain) and + (record['data'] == mail_domain) and (record['ttl'] == 3600) and (record['active'] == 'N') and + (record['aux'] == "10") + result= true + end + end + + result + end + + test('get records - verify all parameters for one record') do + pending if Fog.mocking? + + result= false + + response = Bluebox[:dns].get_records() + if response.status == 200 + records = response.body['records'] + + #find mx record + records.each {|record| + if record['record-type'] == 'MX' + + mail_domain = 'mail.' + @domain + if (record['record-type'] == 'MX') and (record['name'] == @domain) and + (record['data'] == mail_domain) and (record['ttl'] == 3600) and (record['active'] == 'N') and + (record['aux'] == "10") + result= true + break + end + + end + } + end + + result + end + + test("delete #{@new_records.count} records created") do + pending if Fog.mocking? + + result= true + @new_records.each { |record_id| + response = Slicehost[:dns].delete_record( record_id) + if response.status != 200 + result= false; + end + } + result + end + + test("delete #{@new_zones.count} zones created") do + pending if Fog.mocking? + + result= true + + @new_zones.each { |zone_id| + response = Slicehost[:dns].delete_zone( zone_id) + if response.status != 200 + result= false; + end + } + + result + end + + end + + + tests( 'failure') do + + #create a zone with invalid parameters + #get zonfo info with invalid zone id + #delete a zone with an invalid zone id + + tests('#create_zone') do + end + + end + +end