From 0dad896add1f95880a18b8fa696709135f1def64 Mon Sep 17 00:00:00 2001 From: Carlos Lima Date: Mon, 29 Jun 2015 02:58:59 +0800 Subject: [PATCH 1/2] The :geo_location attribute needs to be xml formatted before calling aws Without this, calling `record.destroy` on a record that has geolocation set will cause an exception with: Fog::DNS::AWS::Error: MalformedInput => Unexpected complex element termination --- .../dns/change_resource_record_sets.rb | 152 +++++++++--------- .../dns/change_resource_record_sets_tests.rb | 19 +++ 2 files changed, 98 insertions(+), 73 deletions(-) diff --git a/lib/fog/aws/requests/dns/change_resource_record_sets.rb b/lib/fog/aws/requests/dns/change_resource_record_sets.rb index 409e474181..b1f18a598c 100644 --- a/lib/fog/aws/requests/dns/change_resource_record_sets.rb +++ b/lib/fog/aws/requests/dns/change_resource_record_sets.rb @@ -61,93 +61,99 @@ class Real # change_resource_record_sets("ABCDEFGHIJKLMN", change_batch_options) # def change_resource_record_sets(zone_id, change_batch, options = {}) - # AWS methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use - # that form or just the actual id (which is what this request needs) - zone_id = zone_id.sub('/hostedzone/', '') - - optional_tags = '' - options.each do |option, value| - case option - when :comment - optional_tags += "#{value}" - end + body = AWS.change_resource_record_sets_data(zone_id, change_batch, options) + request({ + :body => body, + :idempotent => true, + :parser => Fog::Parsers::DNS::AWS::ChangeResourceRecordSets.new, + :expects => 200, + :method => 'POST', + :path => "hostedzone/#{zone_id}/rrset" + }) + end + end + + # Returns the xml request for a given changeset + def self.change_resource_record_sets_data(zone_id, change_batch, options = {}) + # AWS methods return zone_ids that looks like '/hostedzone/id'. Let the caller either use + # that form or just the actual id (which is what this request needs) + zone_id = zone_id.sub('/hostedzone/', '') + + optional_tags = '' + options.each do |option, value| + case option + when :comment + optional_tags += "#{value}" end + end - #build XML - if change_batch.count > 0 - - changes = "#{optional_tags}" - - change_batch.each do |change_item| - action_tag = %Q{#{change_item[:action]}} - name_tag = %Q{#{change_item[:name]}} - type_tag = %Q{#{change_item[:type]}} - - # TTL must be omitted if using an alias record - ttl_tag = '' - ttl_tag += %Q{#{change_item[:ttl]}} unless change_item[:alias_target] - - weight_tag = '' - set_identifier_tag = '' - region_tag = '' - if change_item[:set_identifier] - set_identifier_tag += %Q{#{change_item[:set_identifier]}} - if change_item[:weight] # Weighted Record - weight_tag += %Q{#{change_item[:weight]}} - elsif change_item[:region] # Latency record - region_tag += %Q{#{change_item[:region]}} - end - end + #build XML + if change_batch.count > 0 - failover_tag = if change_item[:failover] - %Q{#{change_item[:failover]}} - end + changes = "#{optional_tags}" - geolocation_tag = if change_item[:geo_location] - %Q{#{change_item[:geo_location]}} - end + change_batch.each do |change_item| + action_tag = %Q{#{change_item[:action]}} + name_tag = %Q{#{change_item[:name]}} + type_tag = %Q{#{change_item[:type]}} - resource_records = change_item[:resource_records] || [] - resource_record_tags = '' - resource_records.each do |record| - resource_record_tags += %Q{#{record}} - end + # TTL must be omitted if using an alias record + ttl_tag = '' + ttl_tag += %Q{#{change_item[:ttl]}} unless change_item[:alias_target] - # ResourceRecords must be omitted if using an alias record - resource_tag = '' - resource_tag += %Q{#{resource_record_tags}} if resource_records.any? - - alias_target_tag = '' - if change_item[:alias_target] - # Accept either underscore or camel case for hash keys. - dns_name = change_item[:alias_target][:dns_name] || change_item[:alias_target][:DNSName] - hosted_zone_id = change_item[:alias_target][:hosted_zone_id] || change_item[:alias_target][:HostedZoneId] || AWS.hosted_zone_for_alias_target(dns_name) - evaluate_target_health = change_item[:alias_target][:evaluate_target_health] || change_item[:alias_target][:EvaluateTargetHealth] || false - evaluate_target_health_xml = !evaluate_target_health.nil? ? %Q{#{evaluate_target_health}} : '' - alias_target_tag += %Q{#{hosted_zone_id}#{dns_name}#{evaluate_target_health_xml}} + weight_tag = '' + set_identifier_tag = '' + region_tag = '' + if change_item[:set_identifier] + set_identifier_tag += %Q{#{change_item[:set_identifier]}} + if change_item[:weight] # Weighted Record + weight_tag += %Q{#{change_item[:weight]}} + elsif change_item[:region] # Latency record + region_tag += %Q{#{change_item[:region]}} end + end - health_check_id_tag = if change_item[:health_check_id] - %Q{#{change_item[:health_check_id]}} - end + failover_tag = if change_item[:failover] + %Q{#{change_item[:failover]}} + end + + geolocation_tag = if change_item[:geo_location] + xml_geo = change_item[:geo_location].map { |k,v| "<#{k}>#{v}" }.join + %Q{#{xml_geo}} + end + + resource_records = change_item[:resource_records] || [] + resource_record_tags = '' + resource_records.each do |record| + resource_record_tags += %Q{#{record}} + end + + # ResourceRecords must be omitted if using an alias record + resource_tag = '' + resource_tag += %Q{#{resource_record_tags}} if resource_records.any? + + alias_target_tag = '' + if change_item[:alias_target] + # Accept either underscore or camel case for hash keys. + dns_name = change_item[:alias_target][:dns_name] || change_item[:alias_target][:DNSName] + hosted_zone_id = change_item[:alias_target][:hosted_zone_id] || change_item[:alias_target][:HostedZoneId] || AWS.hosted_zone_for_alias_target(dns_name) + evaluate_target_health = change_item[:alias_target][:evaluate_target_health] || change_item[:alias_target][:EvaluateTargetHealth] || false + evaluate_target_health_xml = !evaluate_target_health.nil? ? %Q{#{evaluate_target_health}} : '' + alias_target_tag += %Q{#{hosted_zone_id}#{dns_name}#{evaluate_target_health_xml}} + end - change_tags = %Q{#{action_tag}#{name_tag}#{type_tag}#{set_identifier_tag}#{weight_tag}#{region_tag}#{failover_tag}#{geolocation_tag}#{ttl_tag}#{resource_tag}#{alias_target_tag}#{health_check_id_tag}} - changes += change_tags + health_check_id_tag = if change_item[:health_check_id] + %Q{#{change_item[:health_check_id]}} end - changes += '' + change_tags = %Q{#{action_tag}#{name_tag}#{type_tag}#{set_identifier_tag}#{weight_tag}#{region_tag}#{failover_tag}#{geolocation_tag}#{ttl_tag}#{resource_tag}#{alias_target_tag}#{health_check_id_tag}} + changes += change_tags end - body = %Q{#{changes}} - request({ - :body => body, - :idempotent => true, - :parser => Fog::Parsers::DNS::AWS::ChangeResourceRecordSets.new, - :expects => 200, - :method => 'POST', - :path => "hostedzone/#{zone_id}/rrset" - }) + changes += '' end + + body = %Q{#{changes}} end class Mock diff --git a/tests/requests/dns/change_resource_record_sets_tests.rb b/tests/requests/dns/change_resource_record_sets_tests.rb index ab3047424c..fbd420fed4 100644 --- a/tests/requests/dns/change_resource_record_sets_tests.rb +++ b/tests/requests/dns/change_resource_record_sets_tests.rb @@ -7,4 +7,23 @@ zone_id == Fog::DNS::AWS.elb_hosted_zone_mapping['eu-west-1'] end end + tests("#change_resource_record_sets_data formats geolocation properly") do + change_batch = [{ + :action=>"CREATE", + :name=>"ark.m.example.net.", + :resource_records=>["1.1.1.1"], + :ttl=>"300", + :type=>"A", + :set_identifier=>"ark", + :geo_location=>{"CountryCode"=>"US", "SubdivisionCode"=>"AR"}, + }] + + result = Fog::DNS::AWS.change_resource_record_sets_data('zone_id123', change_batch) + .match(%r{.*}) + returns("USAR") { + result ? result[0] : '' + } + + result + end end From b19e6dc29230fe881a22228b0d913d2177ce38c9 Mon Sep 17 00:00:00 2001 From: Carlos Lima Date: Mon, 29 Jun 2015 03:27:44 +0800 Subject: [PATCH 2/2] Fix syntax for ruby 1.8.7 --- tests/requests/dns/change_resource_record_sets_tests.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/requests/dns/change_resource_record_sets_tests.rb b/tests/requests/dns/change_resource_record_sets_tests.rb index fbd420fed4..780756585e 100644 --- a/tests/requests/dns/change_resource_record_sets_tests.rb +++ b/tests/requests/dns/change_resource_record_sets_tests.rb @@ -19,9 +19,9 @@ }] result = Fog::DNS::AWS.change_resource_record_sets_data('zone_id123', change_batch) - .match(%r{.*}) + geo = result.match(%r{.*}) returns("USAR") { - result ? result[0] : '' + geo ? geo[0] : '' } result