def delete_record(self, context, domain_id, record_id, increment_serial=True): domain = self.storage_api.get_domain(context, domain_id) record = self.storage_api.get_record(context, record_id) # Ensure the domain_id matches the record's domain_id if domain['id'] != record['domain_id']: raise exceptions.RecordNotFound() target = { 'domain_id': domain_id, 'domain_name': domain['name'], 'record_id': record['id'], 'tenant_id': domain['tenant_id'] } policy.check('delete_record', context, target) with self.storage_api.delete_record(context, record_id) as record: with wrap_backend_call(): self.backend.delete_record(context, domain, record) if increment_serial: self._increment_domain_serial(context, domain_id) # Send Record deletion notification utils.notify(context, 'central', 'record.delete', record) return record
def _find_records(self, context, criterion, one=False, marker=None, limit=None, sort_key=None, sort_dir=None): try: return self._find(models.Record, context, criterion, one=one, marker=marker, limit=limit, sort_key=sort_key, sort_dir=sort_dir) except exceptions.NotFound: raise exceptions.RecordNotFound()
def _get_record(self, record_id=None, domain=None, type=None): query = self.session.query(models.Record) if record_id: query = query.filter_by(designate_id=record_id) if type: query = query.filter_by(type=type) if domain: query = query.filter_by(domain_id=domain.id) try: record = query.one() except sqlalchemy_exceptions.NoResultFound: raise exceptions.RecordNotFound('No record found') except sqlalchemy_exceptions.MultipleResultsFound: raise exceptions.RecordNotFound('Too many records found') else: return record
def get_record(self, context, domain_id, record_id): domain = self.storage_api.get_domain(context, domain_id) record = self.storage_api.get_record(context, record_id) # Ensure the domain_id matches the record's domain_id if domain['id'] != record['domain_id']: raise exceptions.RecordNotFound() target = { 'domain_id': domain_id, 'domain_name': domain['name'], 'record_id': record['id'], 'tenant_id': domain['tenant_id'] } policy.check('get_record', context, target) return record
def update_record(self, context, domain_id, record_id, values, increment_serial=True): domain = self.storage_api.get_domain(context, domain_id) record = self.storage_api.get_record(context, record_id) # Ensure the domain_id matches the record's domain_id if domain['id'] != record['domain_id']: raise exceptions.RecordNotFound() target = { 'domain_id': domain_id, 'domain_name': domain['name'], 'record_id': record['id'], 'tenant_id': domain['tenant_id'] } policy.check('update_record', context, target) # Ensure the record name is valid record_name = values['name'] if 'name' in values else record['name'] record_type = values['type'] if 'type' in values else record['type'] self._is_valid_record_name(context, domain, record_name, record_type) self._is_valid_record_placement(context, domain, record_name, record_type, record_id) # Update the record with self.storage_api.update_record(context, record_id, values) as record: with wrap_backend_call(): self.backend.update_record(context, domain, record) if increment_serial: self._increment_domain_serial(context, domain_id) # Send Record update notification utils.notify(context, 'central', 'record.update', record) return record
def _find_records(self, context, criterion, one=False): try: return self._find(models.Record, context, criterion, one) except exceptions.NotFound: raise exceptions.RecordNotFound()
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)