Add dns domain manipulation to nova.
Adding this functionality required the existing DNS api to be rearranged considerably. Nova needs to track some information about domains that is outside the scope of the DNS driver, specifically the availability zone of a private domain and the project of a public domain. In order to track those attributes, this patch adds a new table to the Nova database, dns_domains. This patch perpetuates some naming ambiguities (e.g. zone vs. domain). A future renaming patch will sort all this out. For blueprint public-and-private-dns. Change-Id: I80865207d34ab7c6e2afc5638863a299b3913f8e
This commit is contained in:
@@ -85,70 +85,90 @@ None
|
||||
|
||||
New Resources
|
||||
-------------
|
||||
Get a list of DNS Domains (aka 'zones') published by the DNS driver:
|
||||
Get a list of registered DNS Domains published by the DNS drivers:
|
||||
|
||||
GET /v1.1/<tenant_id>/os-floating-ip-dns/
|
||||
|
||||
# Sample Response:
|
||||
{ 'zones' : [
|
||||
{'zone' : 'example.org'}
|
||||
{'zone' : 'example.net'}]}
|
||||
{'zone_entries' : [
|
||||
{'domain': 'domain1.example.org', 'scope': 'public', 'project': 'proj1'}
|
||||
{'domain': 'domain2.example.net', 'scope': 'public', 'project': 'proj2'}
|
||||
{'domain': 'example.net', 'scope': 'public', 'project': ''}
|
||||
{'domain': 'example.internal', 'scope': 'private', 'zone': 'zone1'}]}
|
||||
|
||||
|
||||
Create a DNS entry:
|
||||
Create or modify a DNS domain:
|
||||
|
||||
POST /v1.1/<tenant_id>/os-floating-ip-dns/
|
||||
PUT /v1.1/<tenant_id>/os-floating-ip-dns/<zone>
|
||||
|
||||
# Sample body, public domain:
|
||||
{'zone_entry' :
|
||||
{'scope': 'public',
|
||||
'project' : 'project1'}}
|
||||
|
||||
# Sample body, public (projectless) domain:
|
||||
{'zone_entry' :
|
||||
{'scope': 'public'}}
|
||||
|
||||
# Sample Response, public domain (success):
|
||||
{'zone_entry' :
|
||||
{'zone': 'domain1.example.org',
|
||||
'scope': 'public',
|
||||
'project': 'project1'}}
|
||||
|
||||
# Sample body, private domain:
|
||||
{'zone_entry' :
|
||||
{'scope': 'private',
|
||||
'availability_zone': 'zone1'}}
|
||||
|
||||
# Sample Response, private domain (success):
|
||||
{'zone_entry' :
|
||||
{'zone': 'domain1.private',
|
||||
'scope': 'private',
|
||||
'availability_zone': 'zone1'}}
|
||||
|
||||
Failure Response Code: 403 (Insufficient permissions.)
|
||||
|
||||
|
||||
Delete a DNS domain and all associated host entries:
|
||||
|
||||
DELETE /v1.1/<tenant_id>/os-floating-ip-dns/<domain>
|
||||
|
||||
Normal Response Code: 200
|
||||
Failure Response Code: 404 (Domain to be deleted not found.)
|
||||
Failure Response Code: 403 (Insufficient permissions to delete.)
|
||||
|
||||
|
||||
Create or modify a DNS entry:
|
||||
|
||||
PUT /v1.1/<tenant_id>/os-floating-ip-dns/<zone>/entries/<name>
|
||||
|
||||
# Sample body:
|
||||
{ 'dns_entry' :
|
||||
{ 'name': 'instance1',
|
||||
'ip': '192.168.53.11',
|
||||
'dns_type': 'A',
|
||||
'zone': 'example.org'}}
|
||||
{ 'ip': '192.168.53.11',
|
||||
'dns_type': 'A' }}
|
||||
|
||||
# Sample Response (success):
|
||||
{ 'dns_entry' :
|
||||
{ 'ip' : '192.168.53.11',
|
||||
'type' : 'A',
|
||||
'zone' : 'example.org',
|
||||
{ 'type' : 'A',
|
||||
'name' : 'instance1' }}
|
||||
|
||||
Failure Response Code: 409 (indicates an entry with name & zone already exists.)
|
||||
|
||||
Find unique DNS entry for a given domain and name:
|
||||
|
||||
Change the ip address of an existing DNS entry:
|
||||
|
||||
PUT /v1.1/<tenant_id>/os-floating-ip-dns/<domain>
|
||||
|
||||
# Sample body:
|
||||
{ 'dns_entry' :
|
||||
{ 'name': 'instance1',
|
||||
'ip': '192.168.53.99'}}
|
||||
|
||||
# Sample Response (success):
|
||||
{ 'dns_entry' :
|
||||
{ 'ip' : '192.168.53.99',
|
||||
'name' : 'instance1',
|
||||
'zone' : 'example.org'}}
|
||||
|
||||
Failure Response Code: 404 (Entry to be modified not found)
|
||||
|
||||
|
||||
Find DNS entries for a given domain and name:
|
||||
|
||||
GET /v1.1/<tenant_id>/os-floating-ip-dns/<domain>?name=<name>
|
||||
GET /v1.1/<tenant_id>/os-floating-ip-dns/<domain>/entries/<name>
|
||||
|
||||
# Sample Response:
|
||||
{ 'dns_entries' : [
|
||||
{ 'dns_entry' :
|
||||
{ 'ip' : '192.168.53.11',
|
||||
'type' : 'A',
|
||||
'zone' : <domain>,
|
||||
'name' : <name> }]}
|
||||
'name' : <name> }}
|
||||
|
||||
|
||||
Find DNS entries for a given domain and ip:
|
||||
|
||||
GET /v1.1/<tenant_id>/os-floating-ip-dns/<domain>/?ip=<ip>
|
||||
GET /v1.1/<tenant_id>/os-floating-ip-dns/<domain>/entries?ip=<ip>
|
||||
|
||||
# Sample Response:
|
||||
{ 'dns_entries' : [
|
||||
@@ -164,11 +184,12 @@ Find DNS entries for a given domain and ip:
|
||||
|
||||
Delete a DNS entry:
|
||||
|
||||
DELETE /v1.1/<tenant_id>/os-floating-ip-dns/<domain>?name=<name>
|
||||
DELETE /v1.1/<tenant_id>/os-floating-ip-dns/<domain>/entries/<name>
|
||||
|
||||
Normal Response Code: 200
|
||||
Failure Response Code: 404 (Entry to be deleted not found)
|
||||
|
||||
|
||||
New States
|
||||
----------
|
||||
None
|
||||
@@ -176,4 +197,3 @@ None
|
||||
Changes to the Cloud Servers Specification
|
||||
------------------------------------------
|
||||
None
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"compute:create:attach_volume": [],
|
||||
|
||||
"compute:get": [],
|
||||
"compute:get_all" :[],
|
||||
"compute:get_all": [],
|
||||
|
||||
"compute:update": [],
|
||||
|
||||
@@ -122,5 +122,8 @@
|
||||
"network:modify_dns_entry": [],
|
||||
"network:delete_dns_entry": [],
|
||||
"network:get_dns_entries_by_address": [],
|
||||
"network:get_dns_entries_by_name": []
|
||||
"network:get_dns_entries_by_name": [],
|
||||
"network:create_private_dns_domain": [],
|
||||
"network:create_public_dns_domain": [],
|
||||
"network:delete_dns_domain": []
|
||||
}
|
||||
|
||||
@@ -521,3 +521,27 @@ class AggregateDBApiTestCase(test.TestCase):
|
||||
self.assertRaises(exception.AggregateHostNotFound,
|
||||
db.aggregate_host_delete,
|
||||
ctxt, result.id, _get_fake_aggr_hosts()[0])
|
||||
|
||||
def test_dns_registration(self):
|
||||
domain1 = 'test.domain.one'
|
||||
domain2 = 'test.domain.two'
|
||||
testzone = 'testzone'
|
||||
ctxt = context.get_admin_context()
|
||||
|
||||
db.dnsdomain_register_for_zone(ctxt, domain1, testzone)
|
||||
domain_ref = db.dnsdomain_get(ctxt, domain1)
|
||||
zone = domain_ref.availability_zone
|
||||
scope = domain_ref.scope
|
||||
self.assertEqual(scope, 'private')
|
||||
self.assertEqual(zone, testzone)
|
||||
|
||||
db.dnsdomain_register_for_project(ctxt, domain2,
|
||||
self.project_id)
|
||||
domain_ref = db.dnsdomain_get(ctxt, domain2)
|
||||
project = domain_ref.project_id
|
||||
scope = domain_ref.scope
|
||||
self.assertEqual(project, self.project_id)
|
||||
self.assertEqual(scope, 'public')
|
||||
|
||||
db.dnsdomain_unregister(ctxt, domain1)
|
||||
db.dnsdomain_unregister(ctxt, domain2)
|
||||
|
||||
@@ -277,6 +277,8 @@ class FlatNetworkTestCase(test.TestCase):
|
||||
db.instance_get(self.context,
|
||||
1).AndReturn({'display_name': HOST,
|
||||
'uuid': 'test-00001'})
|
||||
db.instance_get(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn({'availability_zone': ''})
|
||||
db.fixed_ip_associate_pool(mox.IgnoreArg(),
|
||||
mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn('192.168.0.101')
|
||||
@@ -343,6 +345,8 @@ class FlatNetworkTestCase(test.TestCase):
|
||||
db.instance_get(self.context,
|
||||
1).AndReturn({'display_name': HOST,
|
||||
'uuid': 'test-00001'})
|
||||
db.instance_get(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn({'availability_zone': ''})
|
||||
db.fixed_ip_associate_pool(mox.IgnoreArg(),
|
||||
mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn(fixedip)
|
||||
@@ -750,7 +754,8 @@ class VlanNetworkTestCase(test.TestCase):
|
||||
|
||||
db.instance_get(mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn({'security_groups':
|
||||
[{'id': 0}]})
|
||||
[{'id': 0}],
|
||||
'availability_zone': ''})
|
||||
db.fixed_ip_associate_pool(mox.IgnoreArg(),
|
||||
mox.IgnoreArg(),
|
||||
mox.IgnoreArg()).AndReturn('192.168.0.101')
|
||||
@@ -1264,16 +1269,6 @@ class FloatingIPTestCase(test.TestCase):
|
||||
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"
|
||||
@@ -1327,6 +1322,49 @@ class FloatingIPTestCase(test.TestCase):
|
||||
self.network.delete_dns_entry, self.context,
|
||||
name1, zone)
|
||||
|
||||
def test_floating_dns_domains_public(self):
|
||||
zone1 = "testzone"
|
||||
domain1 = "example.org"
|
||||
domain2 = "example.com"
|
||||
address1 = '10.10.10.10'
|
||||
entryname = 'testentry'
|
||||
|
||||
context_admin = context.RequestContext('testuser', 'testproject',
|
||||
is_admin=True)
|
||||
|
||||
self.assertRaises(exception.AdminRequired,
|
||||
self.network.create_public_dns_domain, self.context,
|
||||
domain1, zone1)
|
||||
self.network.create_public_dns_domain(context_admin, domain1,
|
||||
'testproject')
|
||||
self.network.create_public_dns_domain(context_admin, domain2,
|
||||
'fakeproject')
|
||||
|
||||
domains = self.network.get_dns_zones(self.context)
|
||||
self.assertEquals(len(domains), 2)
|
||||
self.assertEquals(domains[0]['domain'], domain1)
|
||||
self.assertEquals(domains[1]['domain'], domain2)
|
||||
self.assertEquals(domains[0]['project'], 'testproject')
|
||||
self.assertEquals(domains[1]['project'], 'fakeproject')
|
||||
|
||||
self.network.add_dns_entry(self.context, address1, entryname,
|
||||
'A', domain1)
|
||||
entries = self.network.get_dns_entries_by_name(self.context,
|
||||
entryname, domain1)
|
||||
self.assertEquals(len(entries), 1)
|
||||
self.assertEquals(entries[0], address1)
|
||||
|
||||
self.assertRaises(exception.AdminRequired,
|
||||
self.network.delete_dns_domain, self.context,
|
||||
domain1)
|
||||
self.network.delete_dns_domain(context_admin, domain1)
|
||||
self.network.delete_dns_domain(context_admin, domain2)
|
||||
|
||||
# Verify that deleting the domain deleted the associated entry
|
||||
entries = self.network.get_dns_entries_by_name(self.context,
|
||||
entryname, domain1)
|
||||
self.assertFalse(entries)
|
||||
|
||||
|
||||
class NetworkPolicyTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
@@ -1355,3 +1393,44 @@ class NetworkPolicyTestCase(test.TestCase):
|
||||
network_manager.check_policy(self.context, 'get_all')
|
||||
self.mox.UnsetStubs()
|
||||
self.mox.VerifyAll()
|
||||
|
||||
|
||||
class InstanceDNSTestCase(test.TestCase):
|
||||
"""Tests nova.network.manager instance DNS"""
|
||||
def setUp(self):
|
||||
super(InstanceDNSTestCase, self).setUp()
|
||||
self.network = TestFloatingIPManager()
|
||||
temp = utils.import_object('nova.network.minidns.MiniDNS')
|
||||
self.network.instance_dns_manager = temp
|
||||
temp = utils.import_object('nova.network.dns_driver.DNSDriver')
|
||||
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(InstanceDNSTestCase, self).tearDown()
|
||||
self.network.instance_dns_manager.delete_dns_file()
|
||||
|
||||
def test_dns_domains_private(self):
|
||||
zone1 = 'testzone'
|
||||
domain1 = 'example.org'
|
||||
|
||||
context_admin = context.RequestContext('testuser', 'testproject',
|
||||
is_admin=True)
|
||||
|
||||
self.assertRaises(exception.AdminRequired,
|
||||
self.network.create_private_dns_domain, self.context,
|
||||
domain1, zone1)
|
||||
|
||||
self.network.create_private_dns_domain(context_admin, domain1, zone1)
|
||||
domains = self.network.get_dns_zones(self.context)
|
||||
self.assertEquals(len(domains), 1)
|
||||
self.assertEquals(domains[0]['domain'], domain1)
|
||||
self.assertEquals(domains[0]['availability_zone'], zone1)
|
||||
|
||||
self.assertRaises(exception.AdminRequired,
|
||||
self.network.delete_dns_domain, self.context,
|
||||
domain1)
|
||||
self.network.delete_dns_domain(context_admin, domain1)
|
||||
|
||||
Reference in New Issue
Block a user