diff --git a/doc/source/api_ext/ext_floating_ip_dns.rst b/doc/source/api_ext/ext_floating_ip_dns.rst new file mode 100644 index 000000000..e2ee3b763 --- /dev/null +++ b/doc/source/api_ext/ext_floating_ip_dns.rst @@ -0,0 +1,160 @@ +About The Floating IP DNS Extension +================================ +The Floating IP DNS extension provides an interface for managing DNS records associated with IP addresses +allocated by the Floating Ips extension. Requests are dispatched to a DNS driver selected at startup. + +To obtain current information the extensions available to you, issue an EXTENSION query on the OpenStack system where it is installed, such as http://mycloud.com/v1.1/tenant/extension. + +Floating IPs Extension Overview +------------------------------- + +Name + Floating IP DNS + +Namespace + http://docs.openstack.org/ext/floating_ip_dns/api/v1.1 + +Alias + OPS-DNS + +Contact + Andrew Bogott + +Status + Alpha + +Extension Version + v1.0 (2011-12-22) + +Dependencies + Compute API v1.1 + Floating IPs Extension, v1.0 + +Doc Link (PDF) + http:// + +Doc Link (WADL) + http:// + +Short Description + This extension enables associated DNS entries with floating IPs. + +Sample Query Responses +---------------------- + +As shown below, responses to an EXTENSION query in XML or JSON provide basic information about the extension. + +Extension Query Response: XML:: + + None + +Extension Query Response: JSON:: + + {'extensions': + [{'updated': '2011-12-23T00:00:00+00:00', + 'name': 'Floating_ip_dns', + 'links': [], + 'namespace': 'http://docs.openstack.org/ext/floating_ip_dns/api/v1.1', + 'alias': 'os-floating-ip_dns', + 'description': 'Floating IP DNS support'}]} + +Document Change History +----------------------- + +============= ===================================== +Revision Date Summary of Changes +2011-12-23 Initial draft +============= ===================================== + + +Summary of Changes +================== +This extension to the Compute API enables management of DNS entries for floating IP addresses. + +New Action +---------- +None + +New Faults +---------- +None + +New Headers +----------- +None + +New Resources +------------- +Get a list of DNS Domains (aka 'zones') published by the DNS driver: + + GET /v1.1//os-floating-ip-dns/ + + # Sample Response: + { 'zones' : [ + {'zone' : 'example.org'} + {'zone' : 'example.net'}]} + + +Create a DNS entry: + + POST /v1.1//os-floating-ip-dns/ + + # Sample body: + { 'dns_entry' : + { 'name': 'instance1', + 'ip': '192.168.53.11', + 'dns_type': 'A', + 'zone': 'example.org'}} + + # Sample Response (success): + { 'dns_entry' : + { 'ip' : '192.168.53.11', + 'type' : 'A', + 'zone' : 'example.org', + 'name' : 'instance1' }} + + Failure Response Code: 409 (indicates an entry with name & zone already exists.) + +Find DNS entries for a given domain and name: + + GET /v1.1//os-floating-ip-dns/?name= + + # Sample Response: + { 'dns_entries' : [ + { 'ip' : '192.168.53.11', + 'type' : 'A', + 'zone' : , + 'name' : }]} + + +Find DNS entries for a given domain and ip: + + GET /v1.1//os-floating-ip-dns//?ip= + + # Sample Response: + { 'dns_entries' : [ + { 'ip' : , + 'type' : 'A', + 'zone' : , + 'name' : 'example1' } + { 'ip' : , + 'type' : 'A', + 'zone' : , + 'name' : 'example2' }]} + + +Delete a DNS entry: + +DELETE /v1.1//os-floating-ip-dns/?name= + + Normal Response Code: 200 + Failure Response Code: 404 (Entry to be deleted not found) + +New States +---------- +None + +Changes to the Cloud Servers Specification +------------------------------------------ +None + diff --git a/nova/exception.py b/nova/exception.py index 043322607..95e34afe2 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -555,6 +555,10 @@ class FloatingIpNotFound(NotFound): message = _("Floating ip not found for id %(id)s.") +class FloatingIpDNSExists(Invalid): + message = _("The DNS entry %(name)s already exists in zone %(zone)s.") + + class FloatingIpNotFoundForAddress(FloatingIpNotFound): message = _("Floating ip not found for address %(address)s.") diff --git a/nova/flags.py b/nova/flags.py index 599dcb0f7..9c4aeffeb 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -370,6 +370,12 @@ DEFINE_string('instance_dns_manager', 'DNS Manager for instance IPs') DEFINE_string('instance_dns_zone', '', 'DNS Zone for instance IPs') +DEFINE_string('floating_ip_dns_manager', + 'nova.network.dns_driver.DNSDriver', + 'DNS Manager for floating IPs') +DEFINE_multistring('floating_ip_dns_zones', '', + 'DNS zones for floating IPs.' + 'e.g. "example.org"') DEFINE_string('network_manager', 'nova.network.manager.VlanManager', 'Manager for network') DEFINE_string('volume_manager', 'nova.volume.manager.VolumeManager', diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py index dc26b0298..9ed779f4e 100644 --- a/nova/tests/test_network.py +++ b/nova/tests/test_network.py @@ -19,11 +19,13 @@ import mox from nova import context from nova import db from nova import exception +from nova import flags from nova import log as logging from nova import rpc from nova import test from nova import utils from nova.network import manager as network_manager +from nova.network import api as network_api from nova.tests import fake_network @@ -1123,11 +1125,17 @@ class FloatingIPTestCase(test.TestCase): def setUp(self): super(FloatingIPTestCase, self).setUp() self.network = TestFloatingIPManager() + temp = utils.import_object('nova.network.minidns.MiniDNS') + self.network.floating_dns_manager = temp self.network.db = db self.project_id = 'testproject' self.context = context.RequestContext('testuser', self.project_id, is_admin=False) + def tearDown(self): + super(FloatingIPTestCase, self).tearDown() + self.network.floating_dns_manager.delete_dns_file() + def test_double_deallocation(self): instance_ref = db.api.instance_create(self.context, {"project_id": self.project_id}) @@ -1138,3 +1146,66 @@ class FloatingIPTestCase(test.TestCase): instance_id=instance_ref['id']) self.network.deallocate_for_instance(self.context, instance_id=instance_ref['id']) + + def test_floating_dns_zones(self): + zone1 = "example.org" + zone2 = "example.com" + flags.FLAGS.floating_ip_dns_zones = [zone1, zone2] + + zones = self.network.get_dns_zones(self.context) + self.assertEqual(len(zones), 2) + self.assertEqual(zones[0], zone1) + self.assertEqual(zones[1], zone2) + + def test_floating_dns_create_conflict(self): + zone = "example.org" + address1 = "10.10.10.11" + name1 = "foo" + name2 = "bar" + + self.network.add_dns_entry(self.context, address1, name1, "A", zone) + + self.assertRaises(exception.FloatingIpDNSExists, + self.network.add_dns_entry, self.context, + address1, name1, "A", zone) + + def test_floating_create_and_get(self): + zone = "example.org" + address1 = "10.10.10.11" + name1 = "foo" + name2 = "bar" + entries = self.network.get_dns_entries_by_address(self.context, + address1, zone) + self.assertFalse(entries) + + self.network.add_dns_entry(self.context, address1, name1, "A", zone) + self.network.add_dns_entry(self.context, address1, name2, "A", zone) + entries = self.network.get_dns_entries_by_address(self.context, + address1, zone) + self.assertEquals(len(entries), 2) + self.assertEquals(entries[0], name1) + self.assertEquals(entries[1], name2) + + entries = self.network.get_dns_entries_by_name(self.context, + name1, zone) + self.assertEquals(len(entries), 1) + self.assertEquals(entries[0], address1) + + def test_floating_dns_delete(self): + zone = "example.org" + address1 = "10.10.10.11" + name1 = "foo" + name2 = "bar" + + self.network.add_dns_entry(self.context, address1, name1, "A", zone) + self.network.add_dns_entry(self.context, address1, name2, "A", zone) + self.network.delete_dns_entry(self.context, name1, zone) + + entries = self.network.get_dns_entries_by_address(self.context, + address1, zone) + self.assertEquals(len(entries), 1) + self.assertEquals(entries[0], name2) + + self.assertRaises(exception.NotFound, + self.network.delete_dns_entry, self.context, + name1, zone)