def _is_valid_record_placement(self, context, domain, record_name, record_type, record_id=None): # CNAME's must not share a name with other records criterion = {'name': record_name} if record_type != 'CNAME': criterion['type'] = 'CNAME' records = self.storage_api.find_records(context, domain['id'], criterion=criterion) if ((len(records) == 1 and records[0]['id'] != record_id) or len(records) > 1): raise exceptions.InvalidRecordLocation('CNAME records may not ' 'share a name with any ' 'other records') # Duplicate PTR's with the same name are not allowed if record_type == 'PTR': criterion = {'name': record_name, 'type': 'PTR'} records = self.storage_api.find_records(context, domain['id'], criterion=criterion) if ((len(records) == 1 and records[0]['id'] != record_id) or len(records) > 1): raise exceptions.DuplicateRecord() return True
def update_record(self, context, record_id, values): record = self._find_records(context, {'id': record_id}, one=True) record.update(values) try: record.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateRecord() return dict(record)
def create_record(self, context, domain_id, values): record = models.Record() record.update(values) record.domain_id = domain_id try: record.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateRecord() return dict(record)
def create_record(self, context, domain_id, recordset_id, values): # Fetch the domain as we need the tenant_id domain = self._find_domains(context, {'id': domain_id}, one=True) # Create and populate the new Record model record = models.Record() record.update(values) record.tenant_id = domain['tenant_id'] record.domain_id = domain_id record.recordset_id = recordset_id try: # Save the new Record model record.save(self.session) except exceptions.Duplicate: raise exceptions.DuplicateRecord() return self._get_record_object(context, record)
class ApiV2RecordsTest(ApiV2TestCase): def setUp(self): super(ApiV2RecordsTest, self).setUp() # Create a domain self.domain = self.create_domain() name = 'www.%s' % self.domain['name'] self.rrset = self.create_recordset(self.domain, name=name) def test_create(self): # Create a zone fixture = self.get_record_fixture(self.rrset['type'], fixture=0) url = '/zones/%s/recordsets/%s/records' % (self.domain['id'], self.rrset['id']) response = self.client.post_json(url, {'record': fixture}) self.assertIn('record', response.json) self.assertIn('links', response.json['record']) self.assertIn('self', response.json['record']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['record']) self.assertIn('created_at', response.json['record']) self.assertIsNone(response.json['record']['updated_at']) for k in fixture: self.assertEqual(fixture[k], response.json['record'][k]) def test_create_validation(self): fixture = self.get_record_fixture(self.rrset['type'], fixture=0) # Add a junk field to the wrapper body = {'record': fixture, 'junk': 'Junk Field'} url = '/zones/%s/recordsets/%s/records' % (self.domain['id'], self.rrset['id']) # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.post_json, url, body) # Add a junk field to the body fixture['junk'] = 'Junk Field' body = {'record': fixture} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.post_json, url, body) @patch.object(central_service.Service, 'create_record', side_effect=messaging.MessagingTimeout()) def test_create_recordset_timeout(self, _): fixture = self.get_record_fixture(self.rrset['type'], fixture=0) body = {'record': fixture} url = '/zones/%s/recordsets/%s/records' % (self.domain['id'], self.rrset['id']) self._assert_exception('timeout', 504, self.client.post_json, url, body) @patch.object(central_service.Service, 'create_record', side_effect=exceptions.DuplicateRecord()) def test_create_record_duplicate(self, _): fixture = self.get_record_fixture(self.rrset['type'], fixture=0) body = {'record': fixture} url = '/zones/%s/recordsets/%s/records' % (self.domain['id'], self.rrset['id']) self._assert_exception('duplicate_record', 409, self.client.post_json, url, body) def test_create_record_invalid_domain(self): fixture = self.get_record_fixture(self.rrset['type'], fixture=0) body = {'record': fixture} url = '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets/' \ 'ba751950-6193-11e3-949a-0800200c9a66/records' self._assert_exception('domain_not_found', 404, self.client.post_json, url, body) def test_create_record_invalid_rrset(self): fixture = self.get_record_fixture(self.rrset['type'], fixture=0) body = {'record': fixture} url = '/zones/%s/recordsets/' \ 'ba751950-6193-11e3-949a-0800200c9a66/records' % self.domain['id'] self._assert_exception('recordset_not_found', 404, self.client.post_json, url, body) def test_get_records(self): url = '/zones/%s/recordsets/%s/records' % (self.domain['id'], self.rrset['id']) response = self.client.get(url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('records', response.json) self.assertIn('links', response.json) self.assertIn('self', response.json['links']) # We should start with 0 recordsets self.assertEqual(0, len(response.json['records'])) data = [ self.create_record(self.domain, self.rrset, data='192.168.0.%s' % i) for i in xrange(2, 10) ] self._assert_paging(data, url, key='records') self._assert_invalid_paging(data, url, key='records') @patch.object(central_service.Service, 'find_records', side_effect=messaging.MessagingTimeout()) def test_get_records_timeout(self, _): url = '/zones/ba751950-6193-11e3-949a-0800200c9a66/recordsets/' \ 'ba751950-6193-11e3-949a-0800200c9a66/records' self._assert_exception('timeout', 504, self.client.get, url) def test_get_record(self): # Create a record record = self.create_record(self.domain, self.rrset) url = '/zones/%s/recordsets/%s/records/%s' % ( self.domain['id'], self.rrset['id'], record['id']) response = self.client.get(url) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('record', response.json) self.assertIn('links', response.json['record']) self.assertIn('self', response.json['record']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['record']) self.assertIn('created_at', response.json['record']) self.assertIn('version', response.json['record']) self.assertIsNone(response.json['record']['updated_at']) self.assertEqual(record['data'], response.json['record']['data']) @patch.object(central_service.Service, 'get_record', side_effect=messaging.MessagingTimeout()) def test_get_record_timeout(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) self._assert_exception('timeout', 504, self.client.get, url, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_record', side_effect=exceptions.RecordNotFound()) def test_get_record_missing(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) self._assert_exception('record_not_found', 404, self.client.get, url, headers={'Accept': 'application/json'}) def test_get_record_invalid_id(self): url = '/zones/%s/recordsets/%s/records/%s' self._assert_invalid_uuid(self.client.get, url) def test_update_record(self): # Create a recordset record = self.create_record(self.domain, self.rrset) # Prepare an update body body = {'record': {'description': 'Tester'}} url = '/zones/%s/recordsets/%s/records/%s' % ( self.domain['id'], self.rrset['id'], record['id']) response = self.client.patch_json(url, body, status=200) # Check the headers are what we expect self.assertEqual(200, response.status_int) self.assertEqual('application/json', response.content_type) # Check the body structure is what we expect self.assertIn('record', response.json) self.assertIn('links', response.json['record']) self.assertIn('self', response.json['record']['links']) # Check the values returned are what we expect self.assertIn('id', response.json['record']) self.assertIsNotNone(response.json['record']['updated_at']) self.assertEqual('Tester', response.json['record']['description']) def test_update_record_validation(self): # NOTE: The schemas should be tested separatly to the API. So we # don't need to test every variation via the API itself. # Create a zone record = self.create_record(self.domain, self.rrset) url = '/zones/%s/recordsets/%s/records/%s' % ( self.domain['id'], self.rrset['id'], record['id']) # Prepare an update body with junk in the wrapper body = {'record': {'description': 'Tester'}, 'junk': 'Junk Field'} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) # Prepare an update body with junk in the body body = {'record': {'description': 'Tester', 'junk': 'Junk Field'}} # Ensure it fails with a 400 self._assert_exception('invalid_object', 400, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_record', side_effect=exceptions.DuplicateRecord()) def test_update_record_duplicate(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) # Prepare an update body body = {'record': {'description': 'Tester'}} # Ensure it fails with a 409 self._assert_exception('duplicate_record', 409, self.client.patch_json, url, body, headers={'Accept': 'application/json'}) @patch.object(central_service.Service, 'get_record', side_effect=messaging.MessagingTimeout()) def test_update_record_timeout(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) # Prepare an update body body = {'record': {'description': 'Tester'}} # Ensure it fails with a 504 self._assert_exception('timeout', 504, self.client.patch_json, url, body) @patch.object(central_service.Service, 'get_record', side_effect=exceptions.RecordNotFound()) def test_update_record_missing(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) # Prepare an update body body = {'record': {'description': 'Tester'}} # Ensure it fails with a 404 self._assert_exception('record_not_found', 404, self.client.patch_json, url, body) def test_update_record_invalid_id(self): url = '/zones/%s/recordsets/%s/records/%s' self._assert_invalid_uuid(self.client.patch_json, url) def test_delete_record(self): record = self.create_record(self.domain, self.rrset) url = '/zones/%s/recordsets/%s/records/%s' % ( self.domain['id'], self.rrset['id'], record['id']) self.client.delete(url, status=204) @patch.object(central_service.Service, 'delete_record', side_effect=messaging.MessagingTimeout()) def test_delete_record_timeout(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) self._assert_exception('timeout', 504, self.client.delete, url) @patch.object(central_service.Service, 'delete_record', side_effect=exceptions.RecordNotFound()) def test_delete_record_missing(self, _): url = '/zones/%s/recordsets/%s/records/' \ 'ba751950-6193-11e3-949a-0800200c9a66' % ( self.domain['id'], self.rrset['id']) self._assert_exception('record_not_found', 404, self.client.delete, url) def test_delete_record_invalid_id(self): url = '/zones/%s/recordsets/%s/records/%s' self._assert_invalid_uuid(self.client.delete, url)