def run_quarantine_zero_byte_post(self): container = 'container-zbyte-%s' % uuid4() obj = 'object-zbyte-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'DATA') metadata = read_metadata(data_file) unlink(data_file) with open(data_file, 'w') as fpointer: write_metadata(fpointer, metadata) try: headers = { 'X-Object-Meta-1': 'One', 'X-Object-Meta-Two': 'Two', 'X-Backend-Storage-Policy-Index': self.policy.idx } direct_client.direct_post_object(onode, opart, self.account, container, obj, headers=headers, conn_timeout=1, response_timeout=1) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def test_object_run_fast_track_non_zero(self): self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 data = "0" * 1024 etag = md5() with self.disk_file.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { "ETag": etag, "X-Timestamp": str(normalize_timestamp(time.time())), "Content-Length": str(os.fstat(writer._fd).st_size), } writer.put(metadata) etag = md5() etag.update("1" + "0" * 1023) etag = etag.hexdigest() metadata["ETag"] = etag write_metadata(writer._fd, metadata) quarantine_path = os.path.join(self.devices, "sda", "quarantined", "objects") kwargs = {"mode": "once"} kwargs["zero_byte_fps"] = 50 self.auditor.run_audit(**kwargs) self.assertFalse(os.path.isdir(quarantine_path)) del (kwargs["zero_byte_fps"]) self.auditor.run_audit(**kwargs) self.assertTrue(os.path.isdir(quarantine_path))
def test_object_run_fast_track_non_zero(self): self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 data = '0' * 1024 etag = md5() with self.disk_file.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': str(normalize_timestamp(time.time())), 'Content-Length': str(os.fstat(writer.fd).st_size), } writer.put(metadata) etag = md5() etag.update('1' + '0' * 1023) etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer.fd, metadata) quarantine_path = os.path.join(self.devices, 'sda', 'quarantined', 'objects') self.auditor.run_once(zero_byte_fps=50) self.assertFalse(os.path.isdir(quarantine_path)) self.auditor.run_once() self.assertTrue(os.path.isdir(quarantine_path))
def run_quarantine_range_etag(self): container = 'container-range-%s' % uuid4() obj = 'object-range-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'RANGE') metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) base_headers = {'X-Backend-Storage-Policy-Index': self.policy.idx} for header, result in [({'Range': 'bytes=0-2'}, 'RAN'), ({'Range': 'bytes=1-11'}, 'ANGE'), ({'Range': 'bytes=0-11'}, 'RANGE')]: req_headers = base_headers.copy() req_headers.update(header) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers=req_headers)[-1] self.assertEqual(odata, result) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def run_quarantine(self): container = 'container-%s' % uuid4() obj = 'object-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, b'VERIFY') # Stash the on disk data for future comparison - this may not equal # 'VERIFY' if for example the proxy has crypto enabled backend_data = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] self.assertEqual(odata, backend_data) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def test_object_run_fast_track_non_zero(self): self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 data = '0' * 1024 etag = md5() with self.disk_file.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() timestamp = str(normalize_timestamp(time.time())) metadata = { 'ETag': etag, 'X-Timestamp': timestamp, 'Content-Length': str(os.fstat(writer._fd).st_size), } writer.put(metadata) writer.commit(Timestamp(timestamp)) etag = md5() etag.update('1' + '0' * 1023) etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer._fd, metadata) quarantine_path = os.path.join(self.devices, 'sda', 'quarantined', 'objects') kwargs = {'mode': 'once'} kwargs['zero_byte_fps'] = 50 self.auditor.run_audit(**kwargs) self.assertFalse(os.path.isdir(quarantine_path)) del (kwargs['zero_byte_fps']) clear_auditor_status(self.devices) self.auditor.run_audit(**kwargs) self.assertTrue(os.path.isdir(quarantine_path))
def run_quarantine_range_etag(self): container = 'container-range-%s' % uuid4() obj = 'object-range-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, b'RANGE') # Stash the on disk data for future comparison - this may not equal # 'VERIFY' if for example the proxy has crypto enabled backend_data = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) base_headers = {'X-Backend-Storage-Policy-Index': self.policy.idx} for header, result in [({'Range': 'bytes=0-2'}, backend_data[0:3]), ({'Range': 'bytes=1-11'}, backend_data[1:]), ({'Range': 'bytes=0-11'}, backend_data)]: req_headers = base_headers.copy() req_headers.update(header) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers=req_headers)[-1] self.assertEqual(odata, result) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def run_quarantine_range_etag(self): container = "container-range-%s" % uuid4() obj = "object-range-%s" % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, "RANGE") metadata = read_metadata(data_file) metadata["ETag"] = "badetag" write_metadata(data_file, metadata) base_headers = {"X-Backend-Storage-Policy-Index": self.policy.idx} for header, result in [ ({"Range": "bytes=0-2"}, "RAN"), ({"Range": "bytes=1-11"}, "ANGE"), ({"Range": "bytes=0-11"}, "RANGE"), ]: req_headers = base_headers.copy() req_headers.update(header) odata = direct_client.direct_get_object(onode, opart, self.account, container, obj, headers=req_headers)[-1] self.assertEquals(odata, result) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={"X-Backend-Storage-Policy-Index": self.policy.idx} ) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def run_quarantine(self): container = 'container-%s' % uuid4() obj = 'object-%s' % uuid4() onode, opart, data_file = self._setup_data_file( container, obj, 'VERIFY') metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] self.assertEquals(odata, 'VERIFY') try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def test_object_run_fast_track_non_zero(self): self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 data = '0' * 1024 etag = md5() with self.disk_file.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': str(normalize_timestamp(time.time())), 'Content-Length': str(os.fstat(writer._fd).st_size), } writer.put(metadata) etag = md5() etag.update('1' + '0' * 1023) etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer._fd, metadata) quarantine_path = os.path.join(self.devices, 'sda', 'quarantined', 'objects') kwargs = {'mode': 'once'} kwargs['zero_byte_fps'] = 50 self.auditor.run_audit(**kwargs) self.assertFalse(os.path.isdir(quarantine_path)) del(kwargs['zero_byte_fps']) self.auditor.run_audit(**kwargs) self.assertTrue(os.path.isdir(quarantine_path))
def run_quarantine_range_etag(self): container = 'container-range-%s' % uuid4() obj = 'object-range-%s' % uuid4() onode, opart, data_file = self._setup_data_file( container, obj, 'RANGE') metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) for header, result in [({ 'Range': 'bytes=0-2' }, 'RAN'), ({ 'Range': 'bytes=1-11' }, 'ANGE'), ({ 'Range': 'bytes=0-11' }, 'RANGE')]: odata = direct_client.direct_get_object(onode, opart, self.account, container, obj, headers=header)[-1] self.assertEquals(odata, result) try: direct_client.direct_get_object(onode, opart, self.account, container, obj) raise Exception("Did not quarantine object") except client.ClientException as err: self.assertEquals(err.http_status, 404)
def setup_bad_zero_byte(self, with_ts=False): self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 ts_file_path = '' if with_ts: name_hash = hash_path('a', 'c', 'o') dir_path = os.path.join( self.devices, 'sda', storage_directory(get_data_dir(0), '0', name_hash)) ts_file_path = os.path.join(dir_path, '99999.ts') if not os.path.exists(dir_path): mkdirs(dir_path) fp = open(ts_file_path, 'w') write_metadata(fp, {'X-Timestamp': '99999', 'name': '/a/c/o'}) fp.close() etag = md5() with self.disk_file.create() as writer: etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': str(normalize_timestamp(time.time())), 'Content-Length': 10, } writer.put(metadata) etag = md5() etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer._fd, metadata) return ts_file_path
def run_quarantine(self): container = 'container-%s' % uuid4() obj = 'object-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'VERIFY') # Stash the on disk data for future comparison - this may not equal # 'VERIFY' if for example the proxy has crypto enabled backend_data = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] self.assertEqual(odata, backend_data) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def run_quarantine_range_etag(self): container = 'container-range-%s' % uuid4() obj = 'object-range-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'RANGE') # Stash the on disk data for future comparison - this may not equal # 'VERIFY' if for example the proxy has crypto enabled backend_data = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx})[-1] metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) base_headers = {'X-Backend-Storage-Policy-Index': self.policy.idx} for header, result in [({'Range': 'bytes=0-2'}, backend_data[0:3]), ({'Range': 'bytes=1-11'}, backend_data[1:]), ({'Range': 'bytes=0-11'}, backend_data)]: req_headers = base_headers.copy() req_headers.update(header) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers=req_headers)[-1] self.assertEqual(odata, result) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={ 'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def _get_disk_file( self, invalid_type=None, obj_name="o", fsize=1024, csize=8, mark_deleted=False, ts=None, iter_hook=None, mount_check=False, extra_metadata=None, ): """returns a DiskFile""" df = diskfile.DiskFile(self.testdir, "sda1", "0", "a", "c", obj_name, FakeLogger()) data = "0" * fsize etag = md5() if ts: timestamp = ts else: timestamp = str(normalize_timestamp(time())) with df.writer() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = {"ETag": etag, "X-Timestamp": timestamp, "Content-Length": str(os.fstat(writer.fd).st_size)} metadata.update(extra_metadata or {}) writer.put(metadata) if invalid_type == "ETag": etag = md5() etag.update("1" + "0" * (fsize - 1)) etag = etag.hexdigest() metadata["ETag"] = etag diskfile.write_metadata(writer.fd, metadata) if invalid_type == "Content-Length": metadata["Content-Length"] = fsize - 1 diskfile.write_metadata(writer.fd, metadata) if mark_deleted: metadata = {"X-Timestamp": timestamp, "deleted": True} df.put_metadata(metadata, tombstone=True) df = diskfile.DiskFile( self.testdir, "sda1", "0", "a", "c", obj_name, FakeLogger(), keep_data_fp=True, disk_chunk_size=csize, iter_hook=iter_hook, mount_check=mount_check, ) if invalid_type == "Zero-Byte": os.remove(df.data_file) fp = open(df.data_file, "w") fp.close() df.unit_test_len = fsize return df
def _get_disk_file(self, invalid_type=None, obj_name='o', fsize=1024, csize=8, mark_deleted=False, ts=None, iter_hook=None, mount_check=False, extra_metadata=None): '''returns a DiskFile''' df = diskfile.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', obj_name, FakeLogger()) data = '0' * fsize etag = md5() if ts: timestamp = ts else: timestamp = str(normalize_timestamp(time())) with df.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp, 'Content-Length': str(os.fstat(writer.fd).st_size), } metadata.update(extra_metadata or {}) writer.put(metadata) if invalid_type == 'ETag': etag = md5() etag.update('1' + '0' * (fsize - 1)) etag = etag.hexdigest() metadata['ETag'] = etag diskfile.write_metadata(writer.fd, metadata) if invalid_type == 'Content-Length': metadata['Content-Length'] = fsize - 1 diskfile.write_metadata(writer.fd, metadata) if mark_deleted: metadata = {'X-Timestamp': timestamp, 'deleted': True} df.put_metadata(metadata, tombstone=True) df = diskfile.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', obj_name, FakeLogger(), disk_chunk_size=csize, iter_hook=iter_hook, mount_check=mount_check) df.open() if invalid_type == 'Zero-Byte': fp = open(df.data_file, 'w') fp.close() df.unit_test_len = fsize return df
def setUp(self): super(TestPrintObj, self).setUp() self.datafile = os.path.join(self.testdir, '1402017432.46642.data') with open(self.datafile, 'wb') as fp: md = {'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream'} write_metadata(fp, md)
def test_invalid_etag(self): with open(self.datafile, 'wb') as fp: md = {'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream', 'ETag': 'badetag', 'Content-Length': 0} write_metadata(fp, md) out = StringIO() with mock.patch('sys.stdout', out): print_obj(self.datafile) self.assertIn('ETag: badetag doesn\'t match file hash', out.getvalue())
def test_invalid_etag(self): with open(self.datafile, 'wb') as fp: md = {'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream', 'ETag': 'badetag', 'Content-Length': 0} write_metadata(fp, md) out = StringIO() with mock.patch('sys.stdout', out): print_obj(self.datafile) self.assertTrue('ETag: badetag doesn\'t match file hash' in out.getvalue())
def test_object_audit_will_not_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file._datadir, timestamp + ".data") mkdirs(self.disk_file._datadir) with open(path, "w") as f: write_metadata(f, {"name": "/a/c/o"}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger, self.rcache, self.devices) def blowup(*args): raise NameError("tpyo") with mock.patch.object(DiskFileManager, "get_diskfile_from_audit_location", blowup): self.assertRaises(NameError, auditor_worker.object_audit, AuditLocation(os.path.dirname(path), "sda", "0"))
def _get_disk_file(self, invalid_type=None, obj_name='o', fsize=1024, csize=8, mark_deleted=False, ts=None, iter_hook=None, mount_check=False, extra_metadata=None): '''returns a DiskFile''' df = diskfile.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', obj_name, FakeLogger()) data = '0' * fsize etag = md5() if ts: timestamp = ts else: timestamp = str(normalize_timestamp(time())) with df.create() as writer: writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp, 'Content-Length': str(os.fstat(writer.fd).st_size), } metadata.update(extra_metadata or {}) writer.put(metadata) if invalid_type == 'ETag': etag = md5() etag.update('1' + '0' * (fsize - 1)) etag = etag.hexdigest() metadata['ETag'] = etag diskfile.write_metadata(writer.fd, metadata) if invalid_type == 'Content-Length': metadata['Content-Length'] = fsize - 1 diskfile.write_metadata(writer.fd, metadata) if mark_deleted: metadata = { 'X-Timestamp': timestamp, 'deleted': True } df.put_metadata(metadata, tombstone=True) df = diskfile.DiskFile(self.testdir, 'sda1', '0', 'a', 'c', obj_name, FakeLogger(), keep_data_fp=True, disk_chunk_size=csize, iter_hook=iter_hook, mount_check=mount_check) if invalid_type == 'Zero-Byte': os.remove(df.data_file) fp = open(df.data_file, 'w') fp.close() df.unit_test_len = fsize return df
def test_failsafe_object_audit_will_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file.datadir, timestamp + '.data') mkdirs(self.disk_file.datadir) with open(path, 'w') as f: write_metadata(f, {'name': '/a/c/o'}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger) def blowup(*args): raise NameError('tpyo') with mock.patch('swift.obj.diskfile.DiskFile', blowup): auditor_worker.failsafe_object_audit(path, 'sda', '0') self.assertEquals(auditor_worker.errors, 1)
def test_object_audit_will_not_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file._datadir, timestamp + '.data') mkdirs(self.disk_file._datadir) with open(path, 'w') as f: write_metadata(f, {'name': '/a/c/o'}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger) def blowup(*args): raise NameError('tpyo') with mock.patch.object(DiskFileManager, 'get_diskfile_from_audit_location', blowup): self.assertRaises(NameError, auditor_worker.object_audit, AuditLocation(os.path.dirname(path), 'sda', '0'))
def setUp(self): super(TestPrintObjFullMeta, self).setUp() self.datafile = os.path.join(self.testdir, 'sda', 'objects-1', '1', 'ea8', 'db4449e025aca992307c7c804a67eea8', '1402017884.18202.data') utils.mkdirs(os.path.dirname(self.datafile)) with open(self.datafile, 'wb') as fp: md = { 'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream', 'ETag': 'd41d8cd98f00b204e9800998ecf8427e', 'Content-Length': 0 } write_metadata(fp, md)
def setup_bad_zero_byte(self, timestamp=None): if timestamp is None: timestamp = Timestamp(time.time()) self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 etag = md5() with self.disk_file.create() as writer: etag = etag.hexdigest() metadata = {"ETag": etag, "X-Timestamp": timestamp.internal, "Content-Length": 10} writer.put(metadata) etag = md5() etag = etag.hexdigest() metadata["ETag"] = etag write_metadata(writer._fd, metadata)
def setUp(self): super(TestPrintObjFullMeta, self).setUp() self.datafile = os.path.join(self.testdir, 'sda', 'objects-1', '1', 'ea8', 'db4449e025aca992307c7c804a67eea8', '1402017884.18202.data') utils.mkdirs(os.path.dirname(self.datafile)) with open(self.datafile, 'wb') as fp: md = {'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream', 'ETag': 'd41d8cd98f00b204e9800998ecf8427e', 'Content-Length': 0} write_metadata(fp, md)
def test_failsafe_object_audit_will_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file._datadir, timestamp + ".data") mkdirs(self.disk_file._datadir) with open(path, "w") as f: write_metadata(f, {"name": "/a/c/o"}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger, self.rcache, self.devices) def blowup(*args): raise NameError("tpyo") with mock.patch("swift.obj.diskfile.DiskFile", blowup): auditor_worker.failsafe_object_audit(AuditLocation(os.path.dirname(path), "sda", "0")) self.assertEquals(auditor_worker.errors, 1)
def test_object_audit_will_not_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file._datadir, timestamp + '.data') mkdirs(self.disk_file._datadir) with open(path, 'w') as f: write_metadata(f, {'name': '/a/c/o'}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger, self.rcache, self.devices) def blowup(*args): raise NameError('tpyo') with mock.patch.object(DiskFileManager, 'get_diskfile_from_audit_location', blowup): self.assertRaises(NameError, auditor_worker.object_audit, AuditLocation(os.path.dirname(path), 'sda', '0'))
def setUp(self): skip_if_no_xattrs() self.logger = FakeLogger() self.testdir = tempfile.mkdtemp() self.devices = os.path.join(self.testdir, 'node') shutil.rmtree(self.testdir, ignore_errors=1) os.mkdir(self.testdir) os.mkdir(self.devices) self.rb = ring.RingBuilder(8, 6.0, 1) for i in range(6): ip = "127.0.0.%s" % i self.rb.add_dev({ 'id': i, 'region': 0, 'zone': 0, 'weight': 1, 'ip': ip, 'port': 10000, 'device': 'sda1' }) self.rb.rebalance(seed=1) self.existing_device = 'sda1' os.mkdir(os.path.join(self.devices, self.existing_device)) self.objects = os.path.join(self.devices, self.existing_device, 'objects') os.mkdir(self.objects) self._hash = utils.hash_path('a/c/o') digest = binascii.unhexlify(self._hash) part = struct.unpack_from('>I', digest)[0] >> 24 self.next_part = struct.unpack_from('>I', digest)[0] >> 23 self.objdir = os.path.join(self.objects, str(part), self._hash[-3:], self._hash) os.makedirs(self.objdir) self.object_fname = "1278553064.00000.data" self.objname = os.path.join(self.objdir, self.object_fname) with open(self.objname, "wb") as dummy: dummy.write(b"Hello World!") write_metadata(dummy, {'name': '/a/c/o', 'Content-Length': '12'}) test_policies = [StoragePolicy(0, 'platin', True)] storage_policy._POLICIES = StoragePolicyCollection(test_policies) self.expected_dir = os.path.join(self.objects, str(self.next_part), self._hash[-3:], self._hash) self.expected_file = os.path.join(self.expected_dir, self.object_fname)
def run_quarantine_zero_byte_head(self): container = 'container-zbyte-%s' % uuid4() obj = 'object-zbyte-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'DATA') metadata = read_metadata(data_file) unlink(data_file) with open(data_file, 'w') as fpointer: write_metadata(fpointer, metadata) try: direct_client.direct_head_object(onode, opart, self.account, container, obj, conn_timeout=1, response_timeout=1) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def run_quarantine_zero_byte_head(self): container = 'container-zbyte-%s' % uuid4() obj = 'object-zbyte-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'DATA') metadata = read_metadata(data_file) unlink(data_file) with open(data_file, 'w') as fpointer: write_metadata(fpointer, metadata) try: direct_client.direct_head_object(onode, opart, self.account, container, obj, conn_timeout=1, response_timeout=1) raise Exception("Did not quarantine object") except client.ClientException as err: self.assertEquals(err.http_status, 404)
def test_with_tombstone_and_data(self): # rsync replication could leave a tombstone and data file in object # dir - verify they are both removed during audit ts_iter = make_timestamp_iter() ts_tomb = ts_iter.next() ts_data = ts_iter.next() self.setup_bad_zero_byte(timestamp=ts_data) tomb_file_path = os.path.join(self.disk_file._datadir, "%s.ts" % ts_tomb.internal) with open(tomb_file_path, "wb") as fd: write_metadata(fd, {"X-Timestamp": ts_tomb.internal}) files = os.listdir(self.disk_file._datadir) self.assertEqual(2, len(files)) self.assertTrue(os.path.basename(tomb_file_path) in files, files) kwargs = {"mode": "once"} self.auditor.run_audit(**kwargs) self.assertFalse(os.path.exists(self.disk_file._datadir))
def test_failsafe_object_audit_will_swallow_errors_in_tests(self): timestamp = str(normalize_timestamp(time.time())) path = os.path.join(self.disk_file._datadir, timestamp + '.data') mkdirs(self.disk_file._datadir) with open(path, 'w') as f: write_metadata(f, {'name': '/a/c/o'}) auditor_worker = auditor.AuditorWorker(self.conf, self.logger, self.rcache, self.devices) def blowup(*args): raise NameError('tpyo') with mock.patch('swift.obj.diskfile.DiskFileManager.diskfile_cls', blowup): auditor_worker.failsafe_object_audit( AuditLocation(os.path.dirname(path), 'sda', '0', policy=POLICIES.legacy)) self.assertEqual(auditor_worker.errors, 1)
def run_quarantine_zero_byte_get(self): container = 'container-zbyte-%s' % uuid4() obj = 'object-zbyte-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'DATA') metadata = read_metadata(data_file) unlink(data_file) with open(data_file, 'w') as fpointer: write_metadata(fpointer, metadata) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, conn_timeout=1, response_timeout=1, headers={'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEqual(err.http_status, 404)
def test_with_tombstone_and_data(self): # rsync replication could leave a tombstone and data file in object # dir - verify they are both removed during audit ts_iter = make_timestamp_iter() ts_tomb = next(ts_iter) ts_data = next(ts_iter) self.setup_bad_zero_byte(timestamp=ts_data) tomb_file_path = os.path.join(self.disk_file._datadir, '%s.ts' % ts_tomb.internal) with open(tomb_file_path, 'wb') as fd: write_metadata(fd, {'X-Timestamp': ts_tomb.internal}) files = os.listdir(self.disk_file._datadir) self.assertEqual(2, len(files)) self.assertTrue(os.path.basename(tomb_file_path) in files, files) kwargs = {'mode': 'once'} self.auditor.run_audit(**kwargs) self.assertFalse(os.path.exists(self.disk_file._datadir))
def run_quarantine(self): container = "container-%s" % uuid4() obj = "object-%s" % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, "VERIFY") with open(data_file) as fpointer: metadata = read_metadata(fpointer) metadata["ETag"] = "badetag" with open(data_file) as fpointer: write_metadata(fpointer, metadata) odata = direct_client.direct_get_object(onode, opart, self.account, container, obj)[-1] self.assertEquals(odata, "VERIFY") try: direct_client.direct_get_object(onode, opart, self.account, container, obj) raise Exception("Did not quarantine object") except client.ClientException as err: self.assertEquals(err.http_status, 404)
def run_quarantine(self): container = 'container-%s' % uuid4() obj = 'object-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'VERIFY') metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj)[-1] self.assertEquals(odata, 'VERIFY') try: direct_client.direct_get_object(onode, opart, self.account, container, obj) raise Exception("Did not quarantine object") except client.ClientException as err: self.assertEquals(err.http_status, 404)
def setup_bad_zero_byte(self, timestamp=None): if timestamp is None: timestamp = Timestamp(time.time()) self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 etag = md5() with self.disk_file.create() as writer: etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp.internal, 'Content-Length': 10, } writer.put(metadata) etag = md5() etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer._fd, metadata)
def _setup_object(self, condition=None): attempts = [] for _ in range(50): account = 'a' container = 'c' obj = 'o-' + str(uuid.uuid4()) self._hash = utils.hash_path(account, container, obj) digest = binascii.unhexlify(self._hash) self.part = struct.unpack_from('>I', digest)[0] >> 24 self.next_part = struct.unpack_from('>I', digest)[0] >> 23 path = os.path.join(os.path.sep, account, container, obj) # There's 1/512 chance that both old and new parts will be 0; # that's not a terribly interesting case, as there's nothing to do attempts.append((self.part, self.next_part, 2**PART_POWER)) if (self.part != self.next_part and (condition(self.part) if condition else True)): break else: self.fail( 'Failed to setup object satisfying test preconditions %s' % attempts) shutil.rmtree(self.objects, ignore_errors=True) os.mkdir(self.objects) self.objdir = os.path.join(self.objects, str(self.part), self._hash[-3:], self._hash) os.makedirs(self.objdir) self.object_fname = utils.Timestamp.now().internal + ".data" self.objname = os.path.join(self.objdir, self.object_fname) with open(self.objname, "wb") as dummy: dummy.write(b"Hello World!") write_metadata(dummy, {'name': path, 'Content-Length': '12'}) self.policy = StoragePolicy(0, 'platinum', True) storage_policy._POLICIES = StoragePolicyCollection([self.policy]) self.part_dir = os.path.join(self.objects, str(self.part)) self.suffix_dir = os.path.join(self.part_dir, self._hash[-3:]) self.next_part_dir = os.path.join(self.objects, str(self.next_part)) self.next_suffix_dir = os.path.join(self.next_part_dir, self._hash[-3:]) self.expected_dir = os.path.join(self.next_suffix_dir, self._hash) self.expected_file = os.path.join(self.expected_dir, self.object_fname)
def run_quarantine(self): container = "container-%s" % uuid4() obj = "object-%s" % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, "VERIFY") metadata = read_metadata(data_file) metadata["ETag"] = "badetag" write_metadata(data_file, metadata) odata = direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={"X-Backend-Storage-Policy-Index": self.policy.idx} )[-1] self.assertEquals(odata, "VERIFY") try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={"X-Backend-Storage-Policy-Index": self.policy.idx} ) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def setup_bad_zero_byte(self, timestamp=None): if timestamp is None: timestamp = Timestamp(time.time()) self.auditor = auditor.ObjectAuditor(self.conf) self.auditor.log_time = 0 etag = md5() with self.disk_file.create() as writer: etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp.internal, 'Content-Length': 10, } writer.put(metadata) writer.commit(Timestamp(timestamp)) etag = md5() etag = etag.hexdigest() metadata['ETag'] = etag write_metadata(writer._fd, metadata)
def run_quarantine(self): container = 'container-%s' % uuid4() obj = 'object-%s' % uuid4() onode, opart, data_file = self._setup_data_file( container, obj, 'VERIFY') with open(data_file) as fpointer: metadata = read_metadata(fpointer) metadata['ETag'] = 'badetag' with open(data_file) as fpointer: write_metadata(fpointer, metadata) odata = direct_client.direct_get_object(onode, opart, self.account, container, obj)[-1] self.assertEquals(odata, 'VERIFY') try: direct_client.direct_get_object(onode, opart, self.account, container, obj) raise Exception("Did not quarantine object") except client.ClientException as err: self.assertEquals(err.http_status, 404)
def _get_open_disk_file(self, invalid_type=None, obj_name='o', fsize=1024, csize=8, mark_deleted=False, ts=None, mount_check=False, extra_metadata=None): '''returns a DiskFile''' df = self.df_mgr.get_diskfile('sda1', '0', 'a', 'c', obj_name) data = '0' * fsize etag = md5() if ts: timestamp = ts else: timestamp = normalize_timestamp(time()) with df.create() as writer: upload_size = writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp, 'Content-Length': str(upload_size), } metadata.update(extra_metadata or {}) writer.put(metadata) if invalid_type == 'ETag': etag = md5() etag.update('1' + '0' * (fsize - 1)) etag = etag.hexdigest() metadata['ETag'] = etag diskfile.write_metadata(writer._fd, metadata) if invalid_type == 'Content-Length': metadata['Content-Length'] = fsize - 1 diskfile.write_metadata(writer._fd, metadata) if invalid_type == 'Bad-Content-Length': metadata['Content-Length'] = 'zero' diskfile.write_metadata(writer._fd, metadata) if invalid_type == 'Missing-Content-Length': del metadata['Content-Length'] diskfile.write_metadata(writer._fd, metadata) if mark_deleted: df.delete(timestamp) self.conf['disk_chunk_size'] = csize self.conf['mount_check'] = mount_check self.df_mgr = diskfile.DiskFileManager(self.conf, FakeLogger()) df = self.df_mgr.get_diskfile('sda1', '0', 'a', 'c', obj_name) df.open() if invalid_type == 'Zero-Byte': fp = open(df._data_file, 'w') fp.close() df.unit_test_len = fsize return df
def setUp(self): skip_if_no_xattrs() self.logger = FakeLogger() self.testdir = tempfile.mkdtemp() self.devices = os.path.join(self.testdir, 'node') shutil.rmtree(self.testdir, ignore_errors=1) os.mkdir(self.testdir) os.mkdir(self.devices) self.rb = ring.RingBuilder(8, 6.0, 1) for i in range(6): ip = "127.0.0.%s" % i self.rb.add_dev({'id': i, 'region': 0, 'zone': 0, 'weight': 1, 'ip': ip, 'port': 10000, 'device': 'sda1'}) self.rb.rebalance(seed=1) self.existing_device = 'sda1' os.mkdir(os.path.join(self.devices, self.existing_device)) self.objects = os.path.join(self.devices, self.existing_device, 'objects') os.mkdir(self.objects) self._hash = utils.hash_path('a/c/o') digest = binascii.unhexlify(self._hash) part = struct.unpack_from('>I', digest)[0] >> 24 self.next_part = struct.unpack_from('>I', digest)[0] >> 23 self.objdir = os.path.join( self.objects, str(part), self._hash[-3:], self._hash) os.makedirs(self.objdir) self.object_fname = "1278553064.00000.data" self.objname = os.path.join(self.objdir, self.object_fname) with open(self.objname, "wb") as dummy: dummy.write(b"Hello World!") write_metadata(dummy, {'name': '/a/c/o', 'Content-Length': '12'}) test_policies = [StoragePolicy(0, 'platin', True)] storage_policy._POLICIES = StoragePolicyCollection(test_policies) self.expected_dir = os.path.join( self.objects, str(self.next_part), self._hash[-3:], self._hash) self.expected_file = os.path.join(self.expected_dir, self.object_fname)
def run_quarantine_zero_byte_post(self): container = 'container-zbyte-%s' % uuid4() obj = 'object-zbyte-%s' % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, 'DATA') metadata = read_metadata(data_file) unlink(data_file) with open(data_file, 'w') as fpointer: write_metadata(fpointer, metadata) try: headers = {'X-Object-Meta-1': 'One', 'X-Object-Meta-Two': 'Two', POLICY_INDEX: self.policy.idx} direct_client.direct_post_object( onode, opart, self.account, container, obj, headers=headers, conn_timeout=1, response_timeout=1) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def run_quarantine_zero_byte_post(self): container = "container-zbyte-%s" % uuid4() obj = "object-zbyte-%s" % uuid4() onode, opart, data_file = self._setup_data_file(container, obj, "DATA") metadata = read_metadata(data_file) unlink(data_file) with open(data_file, "w") as fpointer: write_metadata(fpointer, metadata) try: headers = { "X-Object-Meta-1": "One", "X-Object-Meta-Two": "Two", "X-Backend-Storage-Policy-Index": self.policy.idx, } direct_client.direct_post_object( onode, opart, self.account, container, obj, headers=headers, conn_timeout=1, response_timeout=1 ) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def test_print_obj_curl_command_ipv6(self): # Note: policy 3 has IPv6 addresses in its ring datafile3 = os.path.join( self.testdir, 'sda', 'objects-3', '1', 'ea8', 'db4449e025aca992307c7c804a67eea8', '1402017884.18202.data') utils.mkdirs(os.path.dirname(datafile3)) with open(datafile3, 'wb') as fp: md = {'name': '/AUTH_admin/c/obj', 'Content-Type': 'application/octet-stream', 'ETag': 'd41d8cd98f00b204e9800998ecf8427e', 'Content-Length': 0} write_metadata(fp, md) object_ring = ring.Ring(self.testdir, ring_name='object-3') part, nodes = object_ring.get_nodes('AUTH_admin', 'c', 'obj') node = nodes[0] out = StringIO() hash_dir = os.path.dirname(datafile3) file_name = os.path.basename(datafile3) # Change working directory to object hash dir cwd = os.getcwd() try: os.chdir(hash_dir) with mock.patch('sys.stdout', out): print_obj(file_name, swift_dir=self.testdir) finally: os.chdir(cwd) exp_curl = ( 'curl -g -I -XHEAD ' '"http://[{host}]:{port}' '/{device}/{part}/AUTH_admin/c/obj" ').format( host=node['ip'], port=node['port'], device=node['device'], part=part) self.assertIn(exp_curl, out.getvalue())
def run_quarantine_range_etag(self): container = 'container-range-%s' % uuid4() obj = 'object-range-%s' % uuid4() onode, opart, data_file = self._setup_data_file( container, obj, 'RANGE') metadata = read_metadata(data_file) metadata['ETag'] = 'badetag' write_metadata(data_file, metadata) base_headers = {'X-Backend-Storage-Policy-Index': self.policy.idx} for header, result in [({ 'Range': 'bytes=0-2' }, 'RAN'), ({ 'Range': 'bytes=1-11' }, 'ANGE'), ({ 'Range': 'bytes=0-11' }, 'RANGE')]: req_headers = base_headers.copy() req_headers.update(header) odata = direct_client.direct_get_object(onode, opart, self.account, container, obj, headers=req_headers)[-1] self.assertEquals(odata, result) try: direct_client.direct_get_object( onode, opart, self.account, container, obj, headers={'X-Backend-Storage-Policy-Index': self.policy.idx}) raise Exception("Did not quarantine object") except ClientException as err: self.assertEquals(err.http_status, 404)
def _get_open_disk_file(self, invalid_type=None, obj_name='o', fsize=1024, csize=8, mark_deleted=False, ts=None, mount_check=False, extra_metadata=None): '''returns a DiskFile''' df = self.df_mgr.get_diskfile('sda1', '0', 'a', 'c', obj_name) data = '0' * fsize etag = md5() if ts: timestamp = ts else: timestamp = normalize_timestamp(time()) with df.create() as writer: upload_size = writer.write(data) etag.update(data) etag = etag.hexdigest() metadata = { 'ETag': etag, 'X-Timestamp': timestamp, 'Content-Length': str(upload_size), } metadata.update(extra_metadata or {}) writer.put(metadata) if invalid_type == 'ETag': etag = md5() etag.update('1' + '0' * (fsize - 1)) etag = etag.hexdigest() metadata['ETag'] = etag diskfile.write_metadata(writer._fd, metadata) elif invalid_type == 'Content-Length': metadata['Content-Length'] = fsize - 1 diskfile.write_metadata(writer._fd, metadata) elif invalid_type == 'Bad-Content-Length': metadata['Content-Length'] = 'zero' diskfile.write_metadata(writer._fd, metadata) elif invalid_type == 'Missing-Content-Length': del metadata['Content-Length'] diskfile.write_metadata(writer._fd, metadata) if mark_deleted: df.delete(timestamp) data_files = [ os.path.join(df._datadir, fname) for fname in sorted(os.listdir(df._datadir), reverse=True) if fname.endswith('.data') ] if invalid_type == 'Corrupt-Xattrs': # We have to go below read_metadata/write_metadata to get proper # corruption. meta_xattr = xattr.getxattr(data_files[0], "user.swift.metadata") wrong_byte = 'X' if meta_xattr[0] != 'X' else 'Y' xattr.setxattr(data_files[0], "user.swift.metadata", wrong_byte + meta_xattr[1:]) elif invalid_type == 'Truncated-Xattrs': meta_xattr = xattr.getxattr(data_files[0], "user.swift.metadata") xattr.setxattr(data_files[0], "user.swift.metadata", meta_xattr[:-1]) self.conf['disk_chunk_size'] = csize self.conf['mount_check'] = mount_check self.df_mgr = diskfile.DiskFileManager(self.conf, FakeLogger()) df = self.df_mgr.get_diskfile('sda1', '0', 'a', 'c', obj_name) df.open() if invalid_type == 'Zero-Byte': fp = open(df._data_file, 'w') fp.close() df.unit_test_len = fsize return df