From 782b935a9b7f2f8cf33453263178afebbdfd3bb3 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 10 Mar 2012 23:02:28 +0100 Subject: [PATCH 01/22] * [dreamhost|dns] initial import --- fog.gemspec | 1 + lib/fog/bin.rb | 1 + lib/fog/bin/dreamhost.rb | 31 +++++ lib/fog/core/errors.rb | 1 + lib/fog/dns.rb | 3 + lib/fog/dreamhost.rb | 11 ++ lib/fog/dreamhost/dns.rb | 97 ++++++++++++++++ lib/fog/dreamhost/models/dns/record.rb | 34 ++++++ lib/fog/dreamhost/models/dns/records.rb | 33 ++++++ .../dreamhost/requests/dns/create_record.rb | 32 ++++++ .../dreamhost/requests/dns/delete_record.rb | 31 +++++ lib/fog/dreamhost/requests/dns/get_record.rb | 16 +++ .../dreamhost/requests/dns/list_records.rb | 25 ++++ tests/dreamhost/requests/dns/dns_tests.rb | 108 ++++++++++++++++++ 14 files changed, 424 insertions(+) create mode 100644 lib/fog/bin/dreamhost.rb create mode 100644 lib/fog/dreamhost.rb create mode 100644 lib/fog/dreamhost/dns.rb create mode 100644 lib/fog/dreamhost/models/dns/record.rb create mode 100644 lib/fog/dreamhost/models/dns/records.rb create mode 100644 lib/fog/dreamhost/requests/dns/create_record.rb create mode 100644 lib/fog/dreamhost/requests/dns/delete_record.rb create mode 100644 lib/fog/dreamhost/requests/dns/get_record.rb create mode 100644 lib/fog/dreamhost/requests/dns/list_records.rb create mode 100644 tests/dreamhost/requests/dns/dns_tests.rb diff --git a/fog.gemspec b/fog.gemspec index 72bc0d45c..809e1bd08 100644 --- a/fog.gemspec +++ b/fog.gemspec @@ -50,6 +50,7 @@ Gem::Specification.new do |s| s.add_dependency('net-ssh', '>=2.1.3') s.add_dependency('nokogiri', '~>1.5.0') s.add_dependency('ruby-hmac') + s.add_dependency('uuid') ## List your development dependencies here. Development dependencies are ## those that are only needed during development diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb index d81432e81..a9285cf64 100644 --- a/lib/fog/bin.rb +++ b/lib/fog/bin.rb @@ -65,6 +65,7 @@ require 'fog/bin/cloudstack' require 'fog/bin/clodo' require 'fog/bin/dnsimple' require 'fog/bin/dnsmadeeasy' +require 'fog/bin/dreamhost' require 'fog/bin/dynect' require 'fog/bin/ecloud' require 'fog/bin/glesys' diff --git a/lib/fog/bin/dreamhost.rb b/lib/fog/bin/dreamhost.rb new file mode 100644 index 000000000..158b8ed11 --- /dev/null +++ b/lib/fog/bin/dreamhost.rb @@ -0,0 +1,31 @@ +class Dreamhost < Fog::Bin + class << self + + def class_for(key) + case key + when :dns + Fog::DNS::Dreamhost + else + raise ArgumentError, "Unrecognized service: #{key}" + end + end + + def [](service) + @@connections ||= Hash.new do |hash, key| + hash[key] = case key + when :dns + Fog::Logger.warning("Dreamhost[:dns] is not recommended, use DNS[:dreamhost] for portability") + Fog::DNS.new(:provider => 'Dreamhost') + else + raise ArgumentError, "Unrecognized service: #{key.inspect}" + end + end + @@connections[service] + end + + def services + Fog::Dreamhost.services + end + + end +end diff --git a/lib/fog/core/errors.rb b/lib/fog/core/errors.rb index aaea7e6f8..54b783ddf 100644 --- a/lib/fog/core/errors.rb +++ b/lib/fog/core/errors.rb @@ -80,6 +80,7 @@ An alternate file may be used by placing its path in the FOG_RC environment vari :dnsimple_password: :dnsmadeeasy_api_key: :dnsmadeeasy_secret_key: + :dreamhost_api_key: :cloudstack_host: :cloudstack_api_key: :cloudstack_secret_access_key: diff --git a/lib/fog/dns.rb b/lib/fog/dns.rb index 7157f4e05..cf003f2ce 100644 --- a/lib/fog/dns.rb +++ b/lib/fog/dns.rb @@ -20,6 +20,9 @@ module Fog when :dnsmadeeasy require 'fog/dnsmadeeasy/dns' Fog::DNS::DNSMadeEasy.new(attributes) + when :dreamhost + require 'fog/dreamhost/dns' + Fog::DNS::Dreamhost.new(attributes) when :dynect require 'fog/dynect/dns' Fog::DNS::Dynect.new(attributes) diff --git a/lib/fog/dreamhost.rb b/lib/fog/dreamhost.rb new file mode 100644 index 000000000..5cae60ad8 --- /dev/null +++ b/lib/fog/dreamhost.rb @@ -0,0 +1,11 @@ +require(File.expand_path(File.join(File.dirname(__FILE__), 'core'))) + +module Fog + module Dreamhost + + extend Fog::Provider + + service(:dns, 'dreamhost/dns', 'DNS') + + end +end diff --git a/lib/fog/dreamhost/dns.rb b/lib/fog/dreamhost/dns.rb new file mode 100644 index 000000000..f805952f0 --- /dev/null +++ b/lib/fog/dreamhost/dns.rb @@ -0,0 +1,97 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'dreamhost')) +require 'fog/dns' +require 'uuid' + +module Fog + module DNS + class Dreamhost < Fog::Service + + requires :dreamhost_api_key + + model_path 'fog/dreamhost/models/dns' + model :record + collection :records + + request_path 'fog/dreamhost/requests/dns' + request :create_record + request :list_records + request :delete_record + request :get_record + + class Mock + + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = {} + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @dreamhost_api_key = options[:dreamhost_api_key] + end + + def data + self.class.data + end + + def reset_data + self.class.data.delete + end + + end + + class Real + + def initialize(options={}) + require 'multi_json' + + @dreamhost_api_key = options[:dreamhost_api_key] + if options[:dreamhost_url] + uri = URI.parse(options[:dreamhost_url]) + options[:host] = uri.host + options[:port] = uri.port + options[:scheme] = uri.scheme + end + @host = options[:host] || "api.dreamhost.com" + @persistent = options[:persistent] || false + @port = options[:port] || 443 + @scheme = options[:scheme] || 'https' + @connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent) + end + + def reload + @connection.reset + end + + def request(params) + #response = @connection.request(params.merge!({:host => @host})) + params[:query].merge!( { :key => @dreamhost_api_key, + :format => 'json', + :unique_id => UUID.generate } ) + response = @connection.request(params) + + unless response.body.empty? + response.body = MultiJson.decode(response.body) + end + if ENV['DEBUG_DREAMHOST'] + require 'pp' + puts "--- REQUEST PARAMS ---" + pp params + puts "--- END PARAMS --- " + puts "--- REQUEST RESPONSE ---" + pp response + puts "--- END RESPONSE --- " + end + if response.body['result'] != 'success' + raise response.body['data'] + end + response + end + end + end + end +end diff --git a/lib/fog/dreamhost/models/dns/record.rb b/lib/fog/dreamhost/models/dns/record.rb new file mode 100644 index 000000000..16df40f00 --- /dev/null +++ b/lib/fog/dreamhost/models/dns/record.rb @@ -0,0 +1,34 @@ +require 'fog/core/model' + +module Fog + module DNS + class Dreamhost + + class Record < Fog::Model + + identity :name, :aliases => 'record' + + attribute :value + attribute :zone + attribute :type + attribute :editable + attribute :account_id + attribute :comment + + def destroy + connection.delete_record(name, type, value) + true + end + + def save + requires :name, :type, :value + + data = connection.create_record(name, type, value, comment) + true + end + + end + + end + end +end diff --git a/lib/fog/dreamhost/models/dns/records.rb b/lib/fog/dreamhost/models/dns/records.rb new file mode 100644 index 000000000..28985582c --- /dev/null +++ b/lib/fog/dreamhost/models/dns/records.rb @@ -0,0 +1,33 @@ +require 'fog/core/collection' +require 'fog/dreamhost/models/dns/record' + +module Fog + module DNS + class Dreamhost + + class Records < Fog::Collection + + model Fog::DNS::Dreamhost::Record + + def all(filter = {}) + clear + if filter[:zone] + data = connection.list_records.body['data'].find_all { |r| r['zone'] == filter[:zone] } + else + data = connection.list_records.body['data'] + end + load(data) + end + + def get(record_name) + data = connection.get_record(record_name).body['data'].find { |r| r['record'] == record_name } + new(data) + rescue Excon::Errors::NotFound + nil + end + + end + + end + end +end diff --git a/lib/fog/dreamhost/requests/dns/create_record.rb b/lib/fog/dreamhost/requests/dns/create_record.rb new file mode 100644 index 000000000..c763a7b02 --- /dev/null +++ b/lib/fog/dreamhost/requests/dns/create_record.rb @@ -0,0 +1,32 @@ +module Fog + module DNS + class Dreamhost + + class Mock + + def create_record(record, type, value, comment = "") + Fog::Mock.not_implemented + end + + end + + class Real + + def create_record(record, type, value, comment = "") + request( :expects => 200, + :method => 'GET', + :path => "/", + :query => { + :record => record, + :type => type, + :value => value, + :cmd => 'dns-add_record', + :comment => comment + } + ) + end + + end + end + end +end diff --git a/lib/fog/dreamhost/requests/dns/delete_record.rb b/lib/fog/dreamhost/requests/dns/delete_record.rb new file mode 100644 index 000000000..9a113839e --- /dev/null +++ b/lib/fog/dreamhost/requests/dns/delete_record.rb @@ -0,0 +1,31 @@ +module Fog + module DNS + class Dreamhost + + class Mock + + def delete_record(name, type, value) + raise Fog::Mock.not_implemented + end + + end + + class Real + + def delete_record(name, type, value) + request( :expects => 200, + :method => "GET", + :path => "/", + :query => { + :cmd => 'dns-remove_record', + :type => type, + :record => name, + :value => value, + } + ) + end + + end + end + end +end diff --git a/lib/fog/dreamhost/requests/dns/get_record.rb b/lib/fog/dreamhost/requests/dns/get_record.rb new file mode 100644 index 000000000..676fb913e --- /dev/null +++ b/lib/fog/dreamhost/requests/dns/get_record.rb @@ -0,0 +1,16 @@ +module Fog + module DNS + class Dreamhost + class Real + + def get_record(record_name) + data = request( :expects => 200, + :method => "GET", + :path => "/", + :query => { :cmd => 'dns-list_records' } ) + end + + end + end + end +end diff --git a/lib/fog/dreamhost/requests/dns/list_records.rb b/lib/fog/dreamhost/requests/dns/list_records.rb new file mode 100644 index 000000000..591ce418a --- /dev/null +++ b/lib/fog/dreamhost/requests/dns/list_records.rb @@ -0,0 +1,25 @@ +module Fog + module DNS + class Dreamhost + + class Mock + + def request(*args) + Fog::Mock.not_implemented + end + + end + + class Real + + def list_records + request( :expects => 200, + :method => "GET", + :path => "/", + :query => { :cmd => 'dns-list_records' } ) + end + + end + end + end +end diff --git a/tests/dreamhost/requests/dns/dns_tests.rb b/tests/dreamhost/requests/dns/dns_tests.rb new file mode 100644 index 000000000..4733c37ec --- /dev/null +++ b/tests/dreamhost/requests/dns/dns_tests.rb @@ -0,0 +1,108 @@ +Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do + + tests("success") do + + test("list records") do + pending if Fog.mocking? + + response = Fog::DNS[:dreamhost].list_records + + if response.status == 200 + @records = response.body["data"] + end + + (response.status == 200) and (response.body.size == 2) + end + + test("list all the records") do + pending if Fog.mocking? + + Fog::DNS[:dreamhost].records.all.size > 0 + end + + test("list records from existing zone") do + pending if Fog.mocking? + + Fog::DNS[:dreamhost].records.all(:zone => 'rbel.co').size > 0 + end + + test("list records from nonexistent zone") do + pending if Fog.mocking? + + Fog::DNS[:dreamhost].records.all(:zone => 'foozoone.local').size == 0 + end + + test("create an A resource record without comment") do + pending if Fog.mocking? + + name = "foo.testing.rbel.co" + type = "A" + value = "1.2.3.4" + response = Fog::DNS[:dreamhost].create_record(name, type, value) + + response.body['result'] == 'success' + end + + test("create an A resource record with comment") do + pending if Fog.mocking? + + name = "foo2.testing.rbel.co" + type = "A" + value = "1.2.3.4" + comment = "test" + response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) + + response.body['result'] == 'success' + end + + test("create TXT record") do + pending if Fog.mocking? + + name = "txt.testing.rbel.co" + type = "txt" + value = "foobar" + comment = "test" + response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) + + response.body['result'] == 'success' + end + + test("TXT record found") do + pending if Fog.mocking? + + rec = Fog::DNS[:dreamhost].records.get 'txt.testing.rbel.co' + + rec != nil + end + + test("delete testing records") do + pending if Fog.mocking? + + sleep 5 + + success = true + r = %w( + foo.testing.rbel.co + foo2.testing.rbel.co + txt.testing.rbel.co + ) + r.each do |rec| + name = rec + @records.each do |record| + if record['record'] == name + response = Fog::DNS[:dreamhost].delete_record(name, record["type"], record["value"]) + success = false if (response.body['result'] != 'success') + end + end + end + + success + end + + + end + + tests( 'failure') do + end + +end From 705cf8e2d8db3eab795a2d528784fdd1c353bf74 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 19 Jan 2013 23:39:33 +0100 Subject: [PATCH 02/22] [dreamhost|dns] remove connection deprecation notices --- lib/fog/dreamhost/models/dns/record.rb | 4 ++-- lib/fog/dreamhost/models/dns/records.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/fog/dreamhost/models/dns/record.rb b/lib/fog/dreamhost/models/dns/record.rb index 16df40f00..abcd2a5b4 100644 --- a/lib/fog/dreamhost/models/dns/record.rb +++ b/lib/fog/dreamhost/models/dns/record.rb @@ -16,14 +16,14 @@ module Fog attribute :comment def destroy - connection.delete_record(name, type, value) + service.delete_record(name, type, value) true end def save requires :name, :type, :value - data = connection.create_record(name, type, value, comment) + data = service.create_record(name, type, value, comment) true end diff --git a/lib/fog/dreamhost/models/dns/records.rb b/lib/fog/dreamhost/models/dns/records.rb index 28985582c..a5aa9de25 100644 --- a/lib/fog/dreamhost/models/dns/records.rb +++ b/lib/fog/dreamhost/models/dns/records.rb @@ -12,15 +12,15 @@ module Fog def all(filter = {}) clear if filter[:zone] - data = connection.list_records.body['data'].find_all { |r| r['zone'] == filter[:zone] } + data = service.list_records.body['data'].find_all { |r| r['zone'] == filter[:zone] } else - data = connection.list_records.body['data'] + data = service.list_records.body['data'] end load(data) end def get(record_name) - data = connection.get_record(record_name).body['data'].find { |r| r['record'] == record_name } + data = service.get_record(record_name).body['data'].find { |r| r['record'] == record_name } new(data) rescue Excon::Errors::NotFound nil From 05371c5a6a032ed11d0ef610ebcc81c7b7704320 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Sat, 19 Jan 2013 23:40:13 +0100 Subject: [PATCH 03/22] [dreamhost|dns] Use the new fog-dream.com domain for testing --- tests/dreamhost/requests/dns/dns_tests.rb | 30 +++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/dreamhost/requests/dns/dns_tests.rb b/tests/dreamhost/requests/dns/dns_tests.rb index 4733c37ec..930b16187 100644 --- a/tests/dreamhost/requests/dns/dns_tests.rb +++ b/tests/dreamhost/requests/dns/dns_tests.rb @@ -1,5 +1,14 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do + # Create some domains for testing + %w{one two three}.each do |dom| + name = "#{dom}.fog-dream.com" + type = "A" + value = "1.2.3.4" + comment = "test" + response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) + end + tests("success") do test("list records") do @@ -23,7 +32,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("list records from existing zone") do pending if Fog.mocking? - Fog::DNS[:dreamhost].records.all(:zone => 'rbel.co').size > 0 + Fog::DNS[:dreamhost].records.all(:zone => 'fog-dream.com').size > 0 end test("list records from nonexistent zone") do @@ -35,7 +44,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create an A resource record without comment") do pending if Fog.mocking? - name = "foo.testing.rbel.co" + name = "foo.testing.fog-dream.com" type = "A" value = "1.2.3.4" response = Fog::DNS[:dreamhost].create_record(name, type, value) @@ -46,7 +55,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create an A resource record with comment") do pending if Fog.mocking? - name = "foo2.testing.rbel.co" + name = "foo2.testing.fog-dream.com" type = "A" value = "1.2.3.4" comment = "test" @@ -58,7 +67,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create TXT record") do pending if Fog.mocking? - name = "txt.testing.rbel.co" + name = "txt.testing.fog-dream.com" type = "txt" value = "foobar" comment = "test" @@ -70,7 +79,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("TXT record found") do pending if Fog.mocking? - rec = Fog::DNS[:dreamhost].records.get 'txt.testing.rbel.co' + rec = Fog::DNS[:dreamhost].records.get 'txt.testing.fog-dream.com' rec != nil end @@ -82,9 +91,9 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do success = true r = %w( - foo.testing.rbel.co - foo2.testing.rbel.co - txt.testing.rbel.co + foo.testing.fog-dream.com + foo2.testing.fog-dream.com + txt.testing.fog-dream.com ) r.each do |rec| name = rec @@ -105,4 +114,9 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do tests( 'failure') do end + ## Cleanup + Fog::DNS[:dreamhost].records.each do |r| + r.destroy if r.name =~ /fog-dream.com/ + end + end From 2650d6d53b8c131bc2f43764b24a5c3a4c7ddf10 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 19:43:49 +0100 Subject: [PATCH 04/22] [dreamhost|dns] remove silly debugging code --- lib/fog/dreamhost/dns.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/fog/dreamhost/dns.rb b/lib/fog/dreamhost/dns.rb index f805952f0..46ae84496 100644 --- a/lib/fog/dreamhost/dns.rb +++ b/lib/fog/dreamhost/dns.rb @@ -68,7 +68,6 @@ module Fog end def request(params) - #response = @connection.request(params.merge!({:host => @host})) params[:query].merge!( { :key => @dreamhost_api_key, :format => 'json', :unique_id => UUID.generate } ) @@ -77,15 +76,6 @@ module Fog unless response.body.empty? response.body = MultiJson.decode(response.body) end - if ENV['DEBUG_DREAMHOST'] - require 'pp' - puts "--- REQUEST PARAMS ---" - pp params - puts "--- END PARAMS --- " - puts "--- REQUEST RESPONSE ---" - pp response - puts "--- END RESPONSE --- " - end if response.body['result'] != 'success' raise response.body['data'] end From 9c041bc9d331236babfbe4851b4cfc99f44c1e8c Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 19:44:23 +0100 Subject: [PATCH 05/22] [dreamhost|dns] do not delete the do-not-delete record when testing --- tests/dreamhost/requests/dns/dns_tests.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/dreamhost/requests/dns/dns_tests.rb b/tests/dreamhost/requests/dns/dns_tests.rb index 930b16187..590e76734 100644 --- a/tests/dreamhost/requests/dns/dns_tests.rb +++ b/tests/dreamhost/requests/dns/dns_tests.rb @@ -115,8 +115,13 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do end ## Cleanup + # We need to have at least one record defined for the Dreamhost DNS api to work + # or you will get a no_such_zone runtime error + # The first record needs to be created using the Dreamhost Web panel AFAIK + # Fog::DNS[:dreamhost].records.each do |r| - r.destroy if r.name =~ /fog-dream.com/ + # Do not delete the 'do-not-delete' record, we need it for the tests + r.destroy if r.name =~ /fog-dream.com/ and r.name != 'do-not-delete.fog-dream.com' end end From 94e44d44e5dfd9bf08ecd4f7421660bed4387ebe Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 19:52:35 +0100 Subject: [PATCH 06/22] [dreamhost|dns] added test helpers Also, use a helper instead of hardcoding the test domain in the tests --- tests/dreamhost/helper.rb | 19 +++++++++++++++ tests/dreamhost/requests/dns/dns_tests.rb | 29 +++++++++-------------- 2 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 tests/dreamhost/helper.rb diff --git a/tests/dreamhost/helper.rb b/tests/dreamhost/helper.rb new file mode 100644 index 000000000..d47fc08bd --- /dev/null +++ b/tests/dreamhost/helper.rb @@ -0,0 +1,19 @@ +def test_domain + 'fog-dream.com' +end + +def do_not_delete_record + "do-not-delete.#{test_domain}" +end + +## Cleanup +# We need to have at least one record defined for the Dreamhost DNS api to work +# or you will get a no_such_zone runtime error +# The first record needs to be created using the Dreamhost Web panel AFAIK +# +def cleanup_records + Fog::DNS[:dreamhost].records.each do |r| + # Do not delete the 'do-not-delete' record, we need it for the tests + r.destroy if r.name =~ /#{test_domain}/ and r.name != do_not_delete_record + end +end diff --git a/tests/dreamhost/requests/dns/dns_tests.rb b/tests/dreamhost/requests/dns/dns_tests.rb index 590e76734..26669d182 100644 --- a/tests/dreamhost/requests/dns/dns_tests.rb +++ b/tests/dreamhost/requests/dns/dns_tests.rb @@ -2,7 +2,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do # Create some domains for testing %w{one two three}.each do |dom| - name = "#{dom}.fog-dream.com" + name = "#{dom}.#{test_domain}" type = "A" value = "1.2.3.4" comment = "test" @@ -32,7 +32,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("list records from existing zone") do pending if Fog.mocking? - Fog::DNS[:dreamhost].records.all(:zone => 'fog-dream.com').size > 0 + Fog::DNS[:dreamhost].records.all(:zone => "#{test_domain}").size > 0 end test("list records from nonexistent zone") do @@ -44,7 +44,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create an A resource record without comment") do pending if Fog.mocking? - name = "foo.testing.fog-dream.com" + name = "foo.testing.#{test_domain}" type = "A" value = "1.2.3.4" response = Fog::DNS[:dreamhost].create_record(name, type, value) @@ -55,7 +55,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create an A resource record with comment") do pending if Fog.mocking? - name = "foo2.testing.fog-dream.com" + name = "foo2.testing.#{test_domain}" type = "A" value = "1.2.3.4" comment = "test" @@ -67,7 +67,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("create TXT record") do pending if Fog.mocking? - name = "txt.testing.fog-dream.com" + name = "txt.testing.#{test_domain}" type = "txt" value = "foobar" comment = "test" @@ -79,7 +79,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do test("TXT record found") do pending if Fog.mocking? - rec = Fog::DNS[:dreamhost].records.get 'txt.testing.fog-dream.com' + rec = Fog::DNS[:dreamhost].records.get "txt.testing.#{test_domain}" rec != nil end @@ -91,9 +91,9 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do success = true r = %w( - foo.testing.fog-dream.com - foo2.testing.fog-dream.com - txt.testing.fog-dream.com + foo.testing.#{test_domain} + foo2.testing.#{test_domain} + txt.testing.#{test_domain} ) r.each do |rec| name = rec @@ -114,14 +114,7 @@ Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do tests( 'failure') do end - ## Cleanup - # We need to have at least one record defined for the Dreamhost DNS api to work - # or you will get a no_such_zone runtime error - # The first record needs to be created using the Dreamhost Web panel AFAIK - # - Fog::DNS[:dreamhost].records.each do |r| - # Do not delete the 'do-not-delete' record, we need it for the tests - r.destroy if r.name =~ /fog-dream.com/ and r.name != 'do-not-delete.fog-dream.com' - end + # helper + cleanup_records end From f0d9c8aebdc2bd8e7018457f793945491127f2b5 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 20:20:53 +0100 Subject: [PATCH 07/22] [dreamhost|dns] Added README.md file documenting testing procedure --- tests/dreamhost/README.md | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/dreamhost/README.md diff --git a/tests/dreamhost/README.md b/tests/dreamhost/README.md new file mode 100644 index 000000000..d7591597a --- /dev/null +++ b/tests/dreamhost/README.md @@ -0,0 +1,56 @@ +# Testing the Dreamhost DNS API + +Dreamhost API sandbox only permits read-only commands, so you'll need a Dreamhost +PS account for the testing and a dedicated domain. + +See http://wiki.dreamhost.com/Application_programming_interface#Test_Account + +## Create an API key + +You'll need a Dreamhost (PS I think) account and a dedicated domain for testing. + +1. Go to the Dreamhost web panel and create an API key to manage DNS records + + https://panel.dreamhost.com/index.cgi?tree=home.api + + Select 'All dns functions' for the new API key to be able to add/remove/list +records. + +2. Create a .fog file in the tests/ directory with the following contents: + + ```yaml + :default: + :dreamhost_api_key: SDFASDFWQWASDFASDFAS + ``` + Where dreamhost_api_key is the key you created in the previous step. + +3. Update the test_domain helper in tests/dreamhost/helper.rb to use your own + domain for testing. You will also need at least a record created via + the Dreamhost Webpanel (you'll get a **no_such_zone** error otherwise). + + I usually create a do-not-delete.my-domain.com record. The tests skip that + record when cleaning up (see the do_not_delete_record helper). + +4. Run the tests + + ``` + shindo tests/dreamhost + ``` + +## Notes + +The API is rate limited, so do not smash the DH servers too often. + +You'll see a **slow_down_bucko** error if the frequency is too high. + +http://wiki.dreamhost.com/Application_programming_interface#Rate_Limit + +## Resources + +Dreamhost API: + +http://wiki.dreamhost.com/Application_programming_interface + +Dreamhost DNS API: + +http://wiki.dreamhost.com/API/Dns_commands From 87d81967fabafb01dbff6accd74b5e2f2ceb7978 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 21:36:11 +0100 Subject: [PATCH 08/22] [dreamhost|dns] Removed get_record request - The request does not map to a Dreamhost API request, remove it. - Updated the Records collection to use list_records instead of get_record in Records#get - Added Records collection model test --- lib/fog/dreamhost/dns.rb | 1 - lib/fog/dreamhost/models/dns/records.rb | 2 +- lib/fog/dreamhost/requests/dns/get_record.rb | 16 ----------- tests/dreamhost/models/dns/records_tests.rb | 29 ++++++++++++++++++++ 4 files changed, 30 insertions(+), 18 deletions(-) delete mode 100644 lib/fog/dreamhost/requests/dns/get_record.rb create mode 100644 tests/dreamhost/models/dns/records_tests.rb diff --git a/lib/fog/dreamhost/dns.rb b/lib/fog/dreamhost/dns.rb index 46ae84496..3aad66f61 100644 --- a/lib/fog/dreamhost/dns.rb +++ b/lib/fog/dreamhost/dns.rb @@ -16,7 +16,6 @@ module Fog request :create_record request :list_records request :delete_record - request :get_record class Mock diff --git a/lib/fog/dreamhost/models/dns/records.rb b/lib/fog/dreamhost/models/dns/records.rb index a5aa9de25..fc10a8e79 100644 --- a/lib/fog/dreamhost/models/dns/records.rb +++ b/lib/fog/dreamhost/models/dns/records.rb @@ -20,7 +20,7 @@ module Fog end def get(record_name) - data = service.get_record(record_name).body['data'].find { |r| r['record'] == record_name } + data = service.list_records.body['data'].find { |r| r['record'] == record_name } new(data) rescue Excon::Errors::NotFound nil diff --git a/lib/fog/dreamhost/requests/dns/get_record.rb b/lib/fog/dreamhost/requests/dns/get_record.rb deleted file mode 100644 index 676fb913e..000000000 --- a/lib/fog/dreamhost/requests/dns/get_record.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Fog - module DNS - class Dreamhost - class Real - - def get_record(record_name) - data = request( :expects => 200, - :method => "GET", - :path => "/", - :query => { :cmd => 'dns-list_records' } ) - end - - end - end - end -end diff --git a/tests/dreamhost/models/dns/records_tests.rb b/tests/dreamhost/models/dns/records_tests.rb new file mode 100644 index 000000000..3573e8789 --- /dev/null +++ b/tests/dreamhost/models/dns/records_tests.rb @@ -0,0 +1,29 @@ +Shindo.tests("Fog::DNS[:dreamhost] | records", ['dreamhost', 'dns']) do + + service = Fog::DNS[:dreamhost] + + tests('#all') do + records = service.records + + test('should be an array') { records.is_a? Array } + + test('should not be empty') { !records.empty? } + + tests('should list Fog::DNS::Dreamhost::Record') do + records.each do |r| + test("as records") { r.is_a?(Fog::DNS::Dreamhost::Record) } + end + end + end + + tests('#get') do + tests('should fetch a record') do + record = service.records.get do_not_delete_record + test('should be a Fog::DNS::Dreamhost::Record') do + record.is_a? Fog::DNS::Dreamhost::Record + end + end + end + +end + From 87c4afcdd2693f5eb2f27e9c3682536e76c57515 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 21:39:24 +0100 Subject: [PATCH 09/22] [dreamhost|dns] refactor dns requests tests Every request now has it's own test file. --- .../requests/dns/create_record_tests.rb | 39 ++++++ .../requests/dns/delete_record_tests.rb | 26 ++++ tests/dreamhost/requests/dns/dns_tests.rb | 120 ------------------ .../requests/dns/list_records_tests.rb | 31 +++++ 4 files changed, 96 insertions(+), 120 deletions(-) create mode 100644 tests/dreamhost/requests/dns/create_record_tests.rb create mode 100644 tests/dreamhost/requests/dns/delete_record_tests.rb delete mode 100644 tests/dreamhost/requests/dns/dns_tests.rb create mode 100644 tests/dreamhost/requests/dns/list_records_tests.rb diff --git a/tests/dreamhost/requests/dns/create_record_tests.rb b/tests/dreamhost/requests/dns/create_record_tests.rb new file mode 100644 index 000000000..ab15f25bd --- /dev/null +++ b/tests/dreamhost/requests/dns/create_record_tests.rb @@ -0,0 +1,39 @@ +Shindo.tests('Fog::DNS[:dreamhost] | create_record request', ['dreamhost', 'dns']) do + + tests("success") do + + test("create an A resource record without comment") do + name = "foo.testing.#{test_domain}" + type = "A" + value = "1.2.3.4" + response = Fog::DNS[:dreamhost].create_record(name, type, value) + + response.body['result'] == 'success' + end + + test("create an A resource record with comment") do + name = "foo2.testing.#{test_domain}" + type = "A" + value = "1.2.3.4" + comment = "test" + response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) + + response.body['result'] == 'success' + end + + test("create TXT record") do + name = "txt.testing.#{test_domain}" + type = "txt" + value = "foobar" + comment = "test" + response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) + + response.body['result'] == 'success' + end + + end + + # helper + cleanup_records + +end diff --git a/tests/dreamhost/requests/dns/delete_record_tests.rb b/tests/dreamhost/requests/dns/delete_record_tests.rb new file mode 100644 index 000000000..0f8b82afa --- /dev/null +++ b/tests/dreamhost/requests/dns/delete_record_tests.rb @@ -0,0 +1,26 @@ +Shindo.tests('Fog::DNS[:dreamhost] | delete_record request', ['dreamhost', 'dns']) do + + tests("success") do + + test("delete testing records") do + name = "delete-test.#{test_domain}" + type = "A" + value = "1.2.3.4" + comment = "test" + Fog::DNS[:dreamhost].create_record(name, type, value, comment) + response = Fog::DNS[:dreamhost].delete_record(name, type, value) + response.body['result'] == 'success' + end + + end + + tests( 'failure') do + raises(RuntimeError, 'deleting non-existent record') do + Fog::DNS[:dreamhost].delete_record('foo.bar.bar', 'A', '1.2.3.4') + end + end + + # helper + cleanup_records + +end diff --git a/tests/dreamhost/requests/dns/dns_tests.rb b/tests/dreamhost/requests/dns/dns_tests.rb deleted file mode 100644 index 26669d182..000000000 --- a/tests/dreamhost/requests/dns/dns_tests.rb +++ /dev/null @@ -1,120 +0,0 @@ -Shindo.tests('Fog::DNS[:dreamhost] | DNS requests', ['dreamhost', 'dns']) do - - # Create some domains for testing - %w{one two three}.each do |dom| - name = "#{dom}.#{test_domain}" - type = "A" - value = "1.2.3.4" - comment = "test" - response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) - end - - tests("success") do - - test("list records") do - pending if Fog.mocking? - - response = Fog::DNS[:dreamhost].list_records - - if response.status == 200 - @records = response.body["data"] - end - - (response.status == 200) and (response.body.size == 2) - end - - test("list all the records") do - pending if Fog.mocking? - - Fog::DNS[:dreamhost].records.all.size > 0 - end - - test("list records from existing zone") do - pending if Fog.mocking? - - Fog::DNS[:dreamhost].records.all(:zone => "#{test_domain}").size > 0 - end - - test("list records from nonexistent zone") do - pending if Fog.mocking? - - Fog::DNS[:dreamhost].records.all(:zone => 'foozoone.local').size == 0 - end - - test("create an A resource record without comment") do - pending if Fog.mocking? - - name = "foo.testing.#{test_domain}" - type = "A" - value = "1.2.3.4" - response = Fog::DNS[:dreamhost].create_record(name, type, value) - - response.body['result'] == 'success' - end - - test("create an A resource record with comment") do - pending if Fog.mocking? - - name = "foo2.testing.#{test_domain}" - type = "A" - value = "1.2.3.4" - comment = "test" - response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) - - response.body['result'] == 'success' - end - - test("create TXT record") do - pending if Fog.mocking? - - name = "txt.testing.#{test_domain}" - type = "txt" - value = "foobar" - comment = "test" - response = Fog::DNS[:dreamhost].create_record(name, type, value, comment) - - response.body['result'] == 'success' - end - - test("TXT record found") do - pending if Fog.mocking? - - rec = Fog::DNS[:dreamhost].records.get "txt.testing.#{test_domain}" - - rec != nil - end - - test("delete testing records") do - pending if Fog.mocking? - - sleep 5 - - success = true - r = %w( - foo.testing.#{test_domain} - foo2.testing.#{test_domain} - txt.testing.#{test_domain} - ) - r.each do |rec| - name = rec - @records.each do |record| - if record['record'] == name - response = Fog::DNS[:dreamhost].delete_record(name, record["type"], record["value"]) - success = false if (response.body['result'] != 'success') - end - end - end - - success - end - - - end - - tests( 'failure') do - end - - # helper - cleanup_records - -end diff --git a/tests/dreamhost/requests/dns/list_records_tests.rb b/tests/dreamhost/requests/dns/list_records_tests.rb new file mode 100644 index 000000000..0c48270d8 --- /dev/null +++ b/tests/dreamhost/requests/dns/list_records_tests.rb @@ -0,0 +1,31 @@ +Shindo.tests('Fog::DNS[:dreamhost] | list_records request', ['dreamhost', 'dns']) do + + tests("success") do + + response = Fog::DNS[:dreamhost].list_records + + test("should return 200") do + if response.status == 200 + @records = response.body["data"] + end + (response.status == 200) and (response.body.size == 2) + end + + test("data should be an Array") do + @records.is_a? Array + end + + tests("should return records") do + %w{type zone value comment record}.each do |elem| + test("with #{elem}") do + @records.first[elem].is_a? String + end + end + end + + end + + # helper + cleanup_records + +end From b4f05f68932d46c64199cd1702776740956ac6d2 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 21:50:05 +0100 Subject: [PATCH 10/22] [dremhost|dns] added DNS service tests --- tests/dreamhost/dns_tests.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/dreamhost/dns_tests.rb diff --git a/tests/dreamhost/dns_tests.rb b/tests/dreamhost/dns_tests.rb new file mode 100644 index 000000000..ea94eb3ca --- /dev/null +++ b/tests/dreamhost/dns_tests.rb @@ -0,0 +1,20 @@ +Shindo.tests('Fog::DNS[:dreamhost]', ['dreamhost', 'dns']) do + + service = Fog::DNS[:dreamhost] + + tests("collections") do + %w{ records }.each do |collection| + test("it should respond to #{collection}") { service.respond_to? collection } + test("it should respond to #{collection}.all") { eval("service.#{collection}").respond_to? 'all' } + test("it should respond to #{collection}.get") { eval("service.#{collection}").respond_to? 'get' } + end + end + + tests("requests") do + %w{ list_records create_record delete_record }.each do |request| + test("it should respond to #{request}") { service.respond_to? request } + end + end + +end + From 90b5d84c6ddd3adb215e03bf1d4caa8c36d54650 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 22:16:56 +0100 Subject: [PATCH 11/22] [dreamhost|dns] added Record model tests, fix Record.save Record.save was missing attribute merging before returning --- lib/fog/dreamhost/models/dns/record.rb | 3 +- tests/dreamhost/models/dns/record_tests.rb | 59 ++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/dreamhost/models/dns/record_tests.rb diff --git a/lib/fog/dreamhost/models/dns/record.rb b/lib/fog/dreamhost/models/dns/record.rb index abcd2a5b4..bf1333e9d 100644 --- a/lib/fog/dreamhost/models/dns/record.rb +++ b/lib/fog/dreamhost/models/dns/record.rb @@ -23,7 +23,8 @@ module Fog def save requires :name, :type, :value - data = service.create_record(name, type, value, comment) + data = service.create_record(name, type, value, comment).body + merge_attributes(data) true end diff --git a/tests/dreamhost/models/dns/record_tests.rb b/tests/dreamhost/models/dns/record_tests.rb new file mode 100644 index 000000000..3803c852a --- /dev/null +++ b/tests/dreamhost/models/dns/record_tests.rb @@ -0,0 +1,59 @@ +Shindo.tests("Fog::DNS[:dreamhost] | record", ['dreamhost', 'dns']) do + + service = Fog::DNS[:dreamhost] + record = service.records.first + + tests('#attributes') do + tests('should have') do + model_attribute_hash = record.attributes + attributes = [ + :name, + :value, + :zone, + :type, + :editable, + :account_id, + :comment, + ] + attributes.each do |attribute| + test("#{attribute} method") { record.respond_to? attribute } + end + attributes.each do |attribute| + test("#{attribute} key") { model_attribute_hash.has_key? attribute } + end + end + + test('be a kind of Fog::DNS::Dreamhost::Record') do + record.kind_of? Fog::DNS::Dreamhost::Record + end + + tests('Write operations') do + name = "test.#{test_domain}" + r = service.records.create :name => name, + :type => 'A', + :value => "8.8.8.8" + tests('#save') do + test('returns Fog::DNS::Dreamhost::Record') do + r.is_a? Fog::DNS::Dreamhost::Record + end + test('value is 8.8.8.8') do + r.value == '8.8.8.8' + end + test("name is #{name}") do + r.name == name + end + end + tests('#destroy') do + test('returns true') { r.destroy == true } + test('destroyed record not listed') do + (service.records.find { |r| r.name == name }).nil? + end + end + end + end + + # cleanup + cleanup_records + +end + From 4c95f8e209a3e7d055cd853feaf3eedee6f14de8 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 23:04:08 +0100 Subject: [PATCH 12/22] [dreamhost|dns] record tests fixes Wait 10 secs for the new record to appear. --- tests/dreamhost/models/dns/record_tests.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/dreamhost/models/dns/record_tests.rb b/tests/dreamhost/models/dns/record_tests.rb index 3803c852a..654702cc6 100644 --- a/tests/dreamhost/models/dns/record_tests.rb +++ b/tests/dreamhost/models/dns/record_tests.rb @@ -32,6 +32,7 @@ Shindo.tests("Fog::DNS[:dreamhost] | record", ['dreamhost', 'dns']) do r = service.records.create :name => name, :type => 'A', :value => "8.8.8.8" + sleep 10 tests('#save') do test('returns Fog::DNS::Dreamhost::Record') do r.is_a? Fog::DNS::Dreamhost::Record @@ -42,6 +43,9 @@ Shindo.tests("Fog::DNS[:dreamhost] | record", ['dreamhost', 'dns']) do test("name is #{name}") do r.name == name end + test("listed") do + !(service.records.find { |r| r.name == name }).nil? + end end tests('#destroy') do test('returns true') { r.destroy == true } From 9dd24ab2bd332727b845ae102614aafd9b81515c Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 23:26:30 +0100 Subject: [PATCH 13/22] [dreamhost|dns] Emulate zone model and collection, added tests Dreamhost API has no concept of Zone, but we can emulate it. --- lib/fog/dreamhost/dns.rb | 2 + lib/fog/dreamhost/models/dns/records.rb | 5 ++ lib/fog/dreamhost/models/dns/zone.rb | 57 ++++++++++++++++++++ lib/fog/dreamhost/models/dns/zones.rb | 37 +++++++++++++ tests/dreamhost/dns_tests.rb | 2 +- tests/dreamhost/models/dns/record_tests.rb | 10 ++++ tests/dreamhost/models/dns/zone_tests.rb | 62 ++++++++++++++++++++++ tests/dreamhost/models/dns/zones_tests.rb | 29 ++++++++++ 8 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 lib/fog/dreamhost/models/dns/zone.rb create mode 100644 lib/fog/dreamhost/models/dns/zones.rb create mode 100644 tests/dreamhost/models/dns/zone_tests.rb create mode 100644 tests/dreamhost/models/dns/zones_tests.rb diff --git a/lib/fog/dreamhost/dns.rb b/lib/fog/dreamhost/dns.rb index 3aad66f61..04a2f3aef 100644 --- a/lib/fog/dreamhost/dns.rb +++ b/lib/fog/dreamhost/dns.rb @@ -10,7 +10,9 @@ module Fog model_path 'fog/dreamhost/models/dns' model :record + model :zone collection :records + collection :zones request_path 'fog/dreamhost/requests/dns' request :create_record diff --git a/lib/fog/dreamhost/models/dns/records.rb b/lib/fog/dreamhost/models/dns/records.rb index fc10a8e79..5f374bfcd 100644 --- a/lib/fog/dreamhost/models/dns/records.rb +++ b/lib/fog/dreamhost/models/dns/records.rb @@ -28,6 +28,11 @@ module Fog end + def new(attributes = {}) + requires :zone + super({ :zone => zone }.merge!(attributes)) + end + end end end diff --git a/lib/fog/dreamhost/models/dns/zone.rb b/lib/fog/dreamhost/models/dns/zone.rb new file mode 100644 index 000000000..7ef3e231d --- /dev/null +++ b/lib/fog/dreamhost/models/dns/zone.rb @@ -0,0 +1,57 @@ +require 'fog/core/model' +require 'fog/dreamhost/models/dns/records' + +module Fog + module DNS + class Dreamhost + + # + # Dreamhost API has no concept of 'Zone', but we + # can emulate it. + # + # http://wiki.dreamhost.com/API/Dns_commands + # + class Zone < Fog::Model + + identity :id + attribute :domain, :aliases => 'name' + + # + # There's no destroy API call + # + def destroy + raise NotImplementedError.new + end + + # + # Return a list of records for this zone + # + def records + @records ||= begin + Fog::DNS::Dreamhost::Records.new( :zone => self, :service => service ) + end + end + + # + # Return the Dreamhost nameserver list + # + def nameservers + [ + "ns1.dreamhost.com", + "ns2.dreamhost.com", + "ns3.dreamhost.com", + ] + end + + # + # There's no zone create API call + # + def save + raise NotImplementedError.new + end + + end + + end + end +end diff --git a/lib/fog/dreamhost/models/dns/zones.rb b/lib/fog/dreamhost/models/dns/zones.rb new file mode 100644 index 000000000..90da72f46 --- /dev/null +++ b/lib/fog/dreamhost/models/dns/zones.rb @@ -0,0 +1,37 @@ +require 'fog/core/collection' +require 'fog/dreamhost/models/dns/zone' + +module Fog + module DNS + class Dreamhost + + # + # Dreamhost API has no concept of 'Zone', but we + # can emulate it. + # + # http://wiki.dreamhost.com/API/Dns_commands + # + class Zones < Fog::Collection + + model Fog::DNS::Dreamhost::Zone + + def all + clear + zones = [] + service.records.each do |r| + zones << { :id => r.zone, :domain => r.zone } + end + load(zones) + end + + def get(zone_id) + service.zones.find { |z| z.domain == zone_id } + rescue Excon::Errors::NotFound + nil + end + + end + + end + end +end diff --git a/tests/dreamhost/dns_tests.rb b/tests/dreamhost/dns_tests.rb index ea94eb3ca..60c8cd542 100644 --- a/tests/dreamhost/dns_tests.rb +++ b/tests/dreamhost/dns_tests.rb @@ -3,7 +3,7 @@ Shindo.tests('Fog::DNS[:dreamhost]', ['dreamhost', 'dns']) do service = Fog::DNS[:dreamhost] tests("collections") do - %w{ records }.each do |collection| + %w{ records zones }.each do |collection| test("it should respond to #{collection}") { service.respond_to? collection } test("it should respond to #{collection}.all") { eval("service.#{collection}").respond_to? 'all' } test("it should respond to #{collection}.get") { eval("service.#{collection}").respond_to? 'get' } diff --git a/tests/dreamhost/models/dns/record_tests.rb b/tests/dreamhost/models/dns/record_tests.rb index 654702cc6..00e3e1cce 100644 --- a/tests/dreamhost/models/dns/record_tests.rb +++ b/tests/dreamhost/models/dns/record_tests.rb @@ -53,6 +53,16 @@ Shindo.tests("Fog::DNS[:dreamhost] | record", ['dreamhost', 'dns']) do (service.records.find { |r| r.name == name }).nil? end end + tests('#save from zone') do + name = "zone-create.#{test_domain}" + r = service.zones.first.records.create :name => name, + :type => 'A', + :value => "8.8.8.8" + sleep 10 + test("listed") do + !(service.records.find { |r| r.name == name }).nil? + end + end end end diff --git a/tests/dreamhost/models/dns/zone_tests.rb b/tests/dreamhost/models/dns/zone_tests.rb new file mode 100644 index 000000000..2df835a4d --- /dev/null +++ b/tests/dreamhost/models/dns/zone_tests.rb @@ -0,0 +1,62 @@ +Shindo.tests("Fog::DNS[:dreamhost] | zone", ['dreamhost', 'dns']) do + + service = Fog::DNS[:dreamhost] + zone = service.zones.first + + tests('#attributes') do + tests('should have') do + model_attribute_hash = zone.attributes + attributes = [ + :domain, + :id, + ] + attributes.each do |attribute| + test("#{attribute} method") { zone.respond_to? attribute } + end + attributes.each do |attribute| + test("#{attribute} key") { model_attribute_hash.has_key? attribute } + end + end + + test('be a kind of Fog::DNS::Dreamhost::Zone') do + zone.kind_of? Fog::DNS::Dreamhost::Zone + end + + tests('Write operations') do + name = "#{test_domain}" + tests('#save') do + # Does not capture the exception for some reason + #raises(NotImplementedError, 'raises NotImplementedError') do + # service.zones.create :domain => name + #end + test 'raises NotImplementedError' do + begin + service.zones.create :domain => name + false + rescue NotImplementedError => e + true + end + end + end + tests('#destroy') do + test 'raises NotImplementedError' do + begin + zone.destroy + false + rescue NotImplementedError => e + true + end + end + end + + tests('#records') do + zone.records.each do |r| + test('list records') { r.is_a? Fog::DNS::Dreamhost::Record } + test('zone matches') { r.zone == test_domain } + end + end + end + end + +end + diff --git a/tests/dreamhost/models/dns/zones_tests.rb b/tests/dreamhost/models/dns/zones_tests.rb new file mode 100644 index 000000000..3ea0565ae --- /dev/null +++ b/tests/dreamhost/models/dns/zones_tests.rb @@ -0,0 +1,29 @@ +Shindo.tests("Fog::DNS[:dreamhost] | Zones Collection", ['dreamhost', 'dns']) do + + service = Fog::DNS[:dreamhost] + + tests('#all') do + zones = service.zones + + test('should be an array') { zones.is_a? Array } + + test('should not be empty') { !zones.empty? } + + tests('should list Fog::DNS::Dreamhost::Zone') do + zones.each do |r| + test("as zone") { r.is_a?(Fog::DNS::Dreamhost::Zone) } + end + end + end + + tests('#get') do + tests('should fetch a zone') do + zone = service.zones.get test_domain + test('should be a Fog::DNS::Dreamhost::Zone') do + zone.is_a? Fog::DNS::Dreamhost::Zone + end + end + end + +end + From 19c8c4d877835511d72c0287a65afd8dc069db3d Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 21 Jan 2013 23:53:59 +0100 Subject: [PATCH 14/22] [dreamhost|docs] Added getting started guide, initial release --- lib/fog/dreamhost/examples/getting_started.md | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 lib/fog/dreamhost/examples/getting_started.md diff --git a/lib/fog/dreamhost/examples/getting_started.md b/lib/fog/dreamhost/examples/getting_started.md new file mode 100644 index 000000000..ec644f0f1 --- /dev/null +++ b/lib/fog/dreamhost/examples/getting_started.md @@ -0,0 +1,83 @@ +# Getting started with Fog::DNS and Dreamhost (2013/01/21) + +You'll need a [Dreamhost](http://www.dreamhost.com) account and API key +to use this. + +See http://wiki.dreamhost.com/API. + +Create an API key selecting **'All dns functions'** to be able to add/remove/list +records. + +## Create the service + +We need to create the service first, using the key we added: + +```ruby +require 'fog' +require 'pp' + +dh = Fog::DNS.new( :provider => "Dreamhost", + :dreamhost_api_key => '6SHU5P2HLDAYECUM' + ) +``` + +## Retrieve all the records + +List all the records available to your Dreamhost account, accross all the zones: + +```ruby +dh.records.all.each do |r| + puts r.name +end +``` + +See http://wiki.dreamhost.com/API/Dns_commands#dns-list_records + +## Fetch a single record + +We can only retrieve a single record, if that's what we need. Then, +read some of the attributes: + +```ruby +rec = dh.records.get 'msn.jabber.groo.com' +rec.type # A, CNAME, TXT, etc +rec.zone # zone the record belongs to +rec.account_id # Dreamhost account ID +rec.comment # Record text comment +rec.value # record value +``` + +## Fetch all the records from zone foobar.com + +```ruby +zone = dh.zones.get 'foobar.com' +zone.records +``` + +## Create a new A record + +```ruby +dh.records.create( + :name => 'stuff.rbel.co', + :type => 'A', + :value => '8.8.8.8' +) +``` + +You can also use the following code, similar to other fog providers: + +``` +zone = dh.zones.get 'foobar.com' +zone.records.create :name => 'stuff.rbel.co', + :type => 'TXT', + :value => 'foobar bar bar' +``` + + +## Destroy all the records in a zone + +```ruby +(dh.zones.get 'foobar.com').each do |rec| + rec.destroy +end +``` From c38aa22e3a8fae70d64f4bc562d49a05f4e13815 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 20:13:09 +0100 Subject: [PATCH 15/22] [dreamhost|dns] Do not add duplicated zones to the Zones collection --- lib/fog/dreamhost/models/dns/zones.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/fog/dreamhost/models/dns/zones.rb b/lib/fog/dreamhost/models/dns/zones.rb index 90da72f46..3463f6cae 100644 --- a/lib/fog/dreamhost/models/dns/zones.rb +++ b/lib/fog/dreamhost/models/dns/zones.rb @@ -18,8 +18,12 @@ module Fog def all clear zones = [] + zones_added = [] service.records.each do |r| - zones << { :id => r.zone, :domain => r.zone } + unless zones_added.include?(r.zone) + zones << { :id => r.zone, :domain => r.zone } + zones_added << r.zone + end end load(zones) end From 6dcbd016955d040a5b50e2344a86fe5af51d475f Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 20:14:50 +0100 Subject: [PATCH 16/22] [dreamhost|dns] Moved getting started guide to examples/dns --- lib/fog/dreamhost/examples/{ => dns}/getting_started.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/fog/dreamhost/examples/{ => dns}/getting_started.md (100%) diff --git a/lib/fog/dreamhost/examples/getting_started.md b/lib/fog/dreamhost/examples/dns/getting_started.md similarity index 100% rename from lib/fog/dreamhost/examples/getting_started.md rename to lib/fog/dreamhost/examples/dns/getting_started.md From 6d2a500b7661cb5b21b40dd0b1b476f6e1aca2e3 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 20:36:59 +0100 Subject: [PATCH 17/22] [dreamhost|dns] Zone.records: list only records matching the current zone --- lib/fog/dreamhost/models/dns/zone.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/fog/dreamhost/models/dns/zone.rb b/lib/fog/dreamhost/models/dns/zone.rb index 7ef3e231d..c583960f8 100644 --- a/lib/fog/dreamhost/models/dns/zone.rb +++ b/lib/fog/dreamhost/models/dns/zone.rb @@ -26,10 +26,12 @@ module Fog # # Return a list of records for this zone # + # Since Dreamhost does not support zones, this is + # emulated. Iterates over all the records and discards + # the ones where Record.zone != domain (the current zone domain) + # def records - @records ||= begin - Fog::DNS::Dreamhost::Records.new( :zone => self, :service => service ) - end + service.records.all :zone => domain end # From 52dbca5f20451007d9723bd437e205787312a304 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 20:49:22 +0100 Subject: [PATCH 18/22] [dreamhost|dns] Updated testing documentation Mention that two consecutive test runs will trigger the rate limit. --- tests/dreamhost/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/dreamhost/README.md b/tests/dreamhost/README.md index d7591597a..cffc31a8c 100644 --- a/tests/dreamhost/README.md +++ b/tests/dreamhost/README.md @@ -39,8 +39,8 @@ records. ## Notes -The API is rate limited, so do not smash the DH servers too often. - +The API is rate limited, so do not smash the DH servers too often. Two +consecutive test runs will trigger the rate limit. You'll see a **slow_down_bucko** error if the frequency is too high. http://wiki.dreamhost.com/Application_programming_interface#Rate_Limit From e469d70eaf91d91853ba622acc08a046b54ce19b Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 21:08:50 +0100 Subject: [PATCH 19/22] [dreamhost|dns] Updated Dreamhost/DNS getting started guide --- .../dreamhost/examples/dns/getting_started.md | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/lib/fog/dreamhost/examples/dns/getting_started.md b/lib/fog/dreamhost/examples/dns/getting_started.md index ec644f0f1..c026d4fd9 100644 --- a/lib/fog/dreamhost/examples/dns/getting_started.md +++ b/lib/fog/dreamhost/examples/dns/getting_started.md @@ -10,33 +10,50 @@ records. ## Create the service -We need to create the service first, using the key we added: +We need to create the service first, using the API key from our account: ```ruby require 'fog' require 'pp' dh = Fog::DNS.new( :provider => "Dreamhost", - :dreamhost_api_key => '6SHU5P2HLDAYECUM' - ) + :dreamhost_api_key => '6SHU5P2HLDAYECUM' ) +``` + +## List all the DNS zones + +This will list all the DNS zones avaialble in your account: + +```ruby +dh.zones.each do |zone| + puts zone.domain +end ``` ## Retrieve all the records -List all the records available to your Dreamhost account, accross all the zones: +List all the records available in your Dreamhost account, accross all the zones: ```ruby -dh.records.all.each do |r| +dh.records.each do |r| puts r.name end ``` +If you want to fetch all the records in a single zone: + +```ruby +zone = dh.zones.get 'fog-dream.com' +zone.records.each do |r| + # do something with the record +end +``` + See http://wiki.dreamhost.com/API/Dns_commands#dns-list_records -## Fetch a single record +## Retrieve a single record -We can only retrieve a single record, if that's what we need. Then, -read some of the attributes: +Get a single record and do something with the attributes: ```ruby rec = dh.records.get 'msn.jabber.groo.com' @@ -47,14 +64,19 @@ rec.comment # Record text comment rec.value # record value ``` -## Fetch all the records from zone foobar.com +## Create a new A record -```ruby -zone = dh.zones.get 'foobar.com' -zone.records +Let's create a new A record: + +``` +zone = dh.zones.get 'rbel.co' +zone.records.create :name => 'stuff.rbel.co', + :type => 'TXT', + :value => 'foobar bar bar' ``` -## Create a new A record +Since Dreamhost API does not support the concept of zone, +you can also use this code to accomplish the same thing: ```ruby dh.records.create( @@ -64,20 +86,20 @@ dh.records.create( ) ``` -You can also use the following code, similar to other fog providers: - -``` -zone = dh.zones.get 'foobar.com' -zone.records.create :name => 'stuff.rbel.co', - :type => 'TXT', - :value => 'foobar bar bar' -``` - - ## Destroy all the records in a zone ```ruby -(dh.zones.get 'foobar.com').each do |rec| +(dh.zones.get 'rbel.co').records.each do |rec| rec.destroy end ``` + +## Resources + +The Dreamhost API: + +http://wiki.dreamhost.com/Application_programming_interface + +DNS API commands: + +http://wiki.dreamhost.com/API/Dns_commands From 3ba2f45cd9eab89ad78af88c144321a0991b34a5 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 21:32:23 +0100 Subject: [PATCH 20/22] [dreamhost|dns] drop uuid gem requirements, not needed Not sure to understand unique_id documentation from Dreamhost, but experimentation shows that a new UUID every request isn't required and Dreamhost says it's optional. http://wiki.dreamhost.com/Application_programming_interface#Required --- lib/fog/dreamhost/dns.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/fog/dreamhost/dns.rb b/lib/fog/dreamhost/dns.rb index 04a2f3aef..2dc8b4f07 100644 --- a/lib/fog/dreamhost/dns.rb +++ b/lib/fog/dreamhost/dns.rb @@ -1,6 +1,5 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'dreamhost')) require 'fog/dns' -require 'uuid' module Fog module DNS @@ -70,8 +69,7 @@ module Fog def request(params) params[:query].merge!( { :key => @dreamhost_api_key, - :format => 'json', - :unique_id => UUID.generate } ) + :format => 'json' } ) response = @connection.request(params) unless response.body.empty? From 47c2a6575f1cb19b3859a93ec227ef8f3b2a7dbe Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 21:56:37 +0100 Subject: [PATCH 21/22] [dreamhost|dns] drop uuid gem dep from fog.gemspec --- fog.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/fog.gemspec b/fog.gemspec index 809e1bd08..72bc0d45c 100644 --- a/fog.gemspec +++ b/fog.gemspec @@ -50,7 +50,6 @@ Gem::Specification.new do |s| s.add_dependency('net-ssh', '>=2.1.3') s.add_dependency('nokogiri', '~>1.5.0') s.add_dependency('ruby-hmac') - s.add_dependency('uuid') ## List your development dependencies here. Development dependencies are ## those that are only needed during development From bedc17295e6554bdb1628254afdd79099c3251c9 Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Tue, 22 Jan 2013 22:05:39 +0100 Subject: [PATCH 22/22] [dreamhost|dns] Add dreamhost to the list of providers --- lib/fog/providers.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/fog/providers.rb b/lib/fog/providers.rb index 62b456fd5..33b4f4fa7 100644 --- a/lib/fog/providers.rb +++ b/lib/fog/providers.rb @@ -6,6 +6,7 @@ require 'fog/cloudstack' require 'fog/clodo' require 'fog/dnsimple' require 'fog/dnsmadeeasy' +require 'fog/dreamhost' require 'fog/dynect' require 'fog/ecloud' require 'fog/glesys'