swift/test/unit/obj/test_auditor.py

388 lines
14 KiB
Python
Raw Normal View History

# Copyright (c) 2010-2012 OpenStack, LLC.
2010-07-12 17:03:45 -05:00
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from test import unit
2010-07-12 17:03:45 -05:00
import unittest
2010-12-16 16:20:57 -08:00
import tempfile
import os
import time
from shutil import rmtree
from hashlib import md5
2011-01-19 14:18:37 -06:00
from tempfile import mkdtemp
2011-03-15 22:12:03 -07:00
from test.unit import FakeLogger
2010-07-12 17:03:45 -05:00
from swift.obj import auditor
2011-01-19 14:18:37 -06:00
from swift.obj import server as object_server
2011-02-24 12:27:20 -08:00
from swift.obj.server import DiskFile, write_metadata, DATADIR
from swift.common.utils import hash_path, mkdirs, normalize_timestamp, \
renamer, storage_directory
2010-12-28 14:54:00 -08:00
from swift.obj.replicator import invalidate_hash
2010-12-16 16:20:57 -08:00
from swift.common.exceptions import AuditException
2010-07-12 17:03:45 -05:00
2010-12-28 14:54:00 -08:00
2010-07-12 17:03:45 -05:00
class TestAuditor(unittest.TestCase):
2010-12-16 16:20:57 -08:00
def setUp(self):
2011-03-15 22:12:03 -07:00
self.testdir = os.path.join(mkdtemp(), 'tmp_test_object_auditor')
2010-12-16 16:20:57 -08:00
self.devices = os.path.join(self.testdir, 'node')
2011-03-15 22:12:03 -07:00
self.logger = FakeLogger()
2010-12-16 16:20:57 -08:00
rmtree(self.testdir, ignore_errors=1)
2011-03-15 22:12:03 -07:00
mkdirs(os.path.join(self.devices, 'sda'))
2010-12-16 16:20:57 -08:00
self.objects = os.path.join(self.devices, 'sda', 'objects')
os.mkdir(os.path.join(self.devices, 'sdb'))
self.objects_2 = os.path.join(self.devices, 'sdb', 'objects')
2010-12-16 16:20:57 -08:00
os.mkdir(self.objects)
self.parts = {}
for part in ['0', '1', '2', '3']:
self.parts[part] = os.path.join(self.objects, part)
os.mkdir(os.path.join(self.objects, part))
self.conf = dict(
devices=self.devices,
2010-12-28 14:54:00 -08:00
mount_check='false')
2011-03-15 22:12:03 -07:00
self.disk_file = DiskFile(self.devices, 'sda', '0', 'a', 'c', 'o',
self.logger)
2010-12-16 16:20:57 -08:00
def tearDown(self):
2011-01-24 17:12:38 -08:00
rmtree(os.path.dirname(self.testdir), ignore_errors=1)
unit.xattr_data = {}
2010-12-16 16:20:57 -08:00
def test_object_audit_extra_data(self):
self.auditor = auditor.AuditorWorker(self.conf)
2010-12-16 16:20:57 -08:00
data = '0' * 1024
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
2010-12-16 16:20:57 -08:00
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
timestamp = str(normalize_timestamp(time.time()))
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
2010-12-16 16:20:57 -08:00
pre_quarantines = self.auditor.quarantines
self.auditor.object_audit(
2011-03-15 22:12:03 -07:00
os.path.join(self.disk_file.datadir, timestamp + '.data'),
'sda', '0')
2010-12-16 16:20:57 -08:00
self.assertEquals(self.auditor.quarantines, pre_quarantines)
os.write(fd, 'extra_data')
self.auditor.object_audit(
2011-03-15 22:12:03 -07:00
os.path.join(self.disk_file.datadir, timestamp + '.data'),
'sda', '0')
self.assertEquals(self.auditor.quarantines, pre_quarantines + 1)
2010-12-16 16:20:57 -08:00
def test_object_audit_diff_data(self):
self.auditor = auditor.AuditorWorker(self.conf)
data = '0' * 1024
etag = md5()
timestamp = str(normalize_timestamp(time.time()))
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
pre_quarantines = self.auditor.quarantines
2011-03-16 07:55:07 -07:00
# remake so it will have metadata
2011-03-15 22:12:03 -07:00
self.disk_file = DiskFile(self.devices, 'sda', '0', 'a', 'c', 'o',
self.logger)
self.auditor.object_audit(
2011-03-15 22:12:03 -07:00
os.path.join(self.disk_file.datadir, timestamp + '.data'),
'sda', '0')
self.assertEquals(self.auditor.quarantines, pre_quarantines)
etag = md5()
etag.update('1' + '0' * 1023)
etag = etag.hexdigest()
metadata['ETag'] = etag
write_metadata(fd, metadata)
2010-12-16 16:20:57 -08:00
self.auditor.object_audit(
2011-03-15 22:12:03 -07:00
os.path.join(self.disk_file.datadir, timestamp + '.data'),
'sda', '0')
2010-12-16 16:20:57 -08:00
self.assertEquals(self.auditor.quarantines, pre_quarantines + 1)
2010-07-12 17:03:45 -05:00
2010-12-28 14:54:00 -08:00
def test_object_audit_no_meta(self):
2011-01-24 17:12:38 -08:00
timestamp = str(normalize_timestamp(time.time()))
2011-03-15 22:12:03 -07:00
path = os.path.join(self.disk_file.datadir, timestamp + '.data')
mkdirs(self.disk_file.datadir)
2011-01-24 17:12:38 -08:00
fp = open(path, 'w')
fp.write('0' * 1024)
fp.close()
2011-03-15 22:12:03 -07:00
invalidate_hash(os.path.dirname(self.disk_file.datadir))
self.auditor = auditor.AuditorWorker(self.conf)
2010-12-28 14:54:00 -08:00
pre_quarantines = self.auditor.quarantines
2011-01-24 17:12:38 -08:00
self.auditor.object_audit(
2011-03-15 22:12:03 -07:00
os.path.join(self.disk_file.datadir, timestamp + '.data'),
'sda', '0')
2011-01-24 17:12:38 -08:00
self.assertEquals(self.auditor.quarantines, pre_quarantines + 1)
2010-12-28 14:54:00 -08:00
def test_object_audit_bad_args(self):
self.auditor = auditor.AuditorWorker(self.conf)
2010-12-28 14:54:00 -08:00
pre_errors = self.auditor.errors
self.auditor.object_audit(5, 'sda', '0')
self.assertEquals(self.auditor.errors, pre_errors + 1)
pre_errors = self.auditor.errors
self.auditor.object_audit('badpath', 'sda', '0')
self.assertEquals(self.auditor.errors, pre_errors) # just returns
2010-12-28 14:54:00 -08:00
def test_object_run_once_pass(self):
self.auditor = auditor.AuditorWorker(self.conf)
2010-12-28 14:54:00 -08:00
self.auditor.log_time = 0
timestamp = str(normalize_timestamp(time.time()))
pre_quarantines = self.auditor.quarantines
data = '0' * 1024
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
self.disk_file.close()
self.auditor.audit_all_objects()
self.assertEquals(self.auditor.quarantines, pre_quarantines)
2010-12-28 14:54:00 -08:00
def test_object_run_once_no_sda(self):
self.auditor = auditor.AuditorWorker(self.conf)
timestamp = str(normalize_timestamp(time.time()))
pre_quarantines = self.auditor.quarantines
data = '0' * 1024
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
self.disk_file.close()
os.write(fd, 'extra_data')
self.auditor.audit_all_objects()
self.assertEquals(self.auditor.quarantines, pre_quarantines + 1)
2010-12-28 14:54:00 -08:00
def test_object_run_once_multi_devices(self):
self.auditor = auditor.AuditorWorker(self.conf)
2010-12-28 14:54:00 -08:00
timestamp = str(normalize_timestamp(time.time()))
pre_quarantines = self.auditor.quarantines
data = '0' * 10
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
2010-12-28 14:54:00 -08:00
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
self.disk_file.close()
self.auditor.audit_all_objects()
2011-03-15 22:12:03 -07:00
self.disk_file = DiskFile(self.devices, 'sdb', '0', 'a', 'c',
'ob', self.logger)
2010-12-28 14:54:00 -08:00
data = '1' * 10
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
2010-12-28 14:54:00 -08:00
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': timestamp,
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
self.disk_file.close()
2010-12-28 14:54:00 -08:00
os.write(fd, 'extra_data')
self.auditor.audit_all_objects()
2010-12-28 14:54:00 -08:00
self.assertEquals(self.auditor.quarantines, pre_quarantines + 1)
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()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
os.write(fd, data)
etag.update(data)
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': str(normalize_timestamp(time.time())),
'Content-Length': str(os.fstat(fd).st_size),
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
etag = md5()
etag.update('1' + '0' * 1023)
etag = etag.hexdigest()
metadata['ETag'] = etag
write_metadata(fd, metadata)
quarantine_path = os.path.join(self.devices,
'sda', 'quarantined', 'objects')
2011-02-21 16:37:12 -08:00
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))
2011-02-24 12:27:20 -08:00
def setup_bad_zero_byte(self, with_ts=False):
self.auditor = auditor.ObjectAuditor(self.conf)
self.auditor.log_time = 0
2011-02-24 12:27:20 -08:00
ts_file_path = ''
if with_ts:
name_hash = hash_path('a', 'c', 'o')
dir_path = os.path.join(self.devices, 'sda',
2011-03-15 22:12:03 -07:00
storage_directory(DATADIR, '0', name_hash))
2011-02-24 12:27:20 -08:00
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')
fp.close()
etag = md5()
2011-03-15 22:12:03 -07:00
with self.disk_file.mkstemp() as (fd, tmppath):
etag = etag.hexdigest()
metadata = {
'ETag': etag,
'X-Timestamp': str(normalize_timestamp(time.time())),
'Content-Length': 10,
}
2011-03-15 22:12:03 -07:00
self.disk_file.put(fd, tmppath, metadata)
etag = md5()
etag = etag.hexdigest()
metadata['ETag'] = etag
write_metadata(fd, metadata)
2011-03-15 22:12:03 -07:00
if self.disk_file.data_file:
return self.disk_file.data_file
2011-02-24 12:27:20 -08:00
return ts_file_path
2011-02-21 16:37:12 -08:00
def test_object_run_fast_track_all(self):
self.setup_bad_zero_byte()
self.auditor.run_once()
quarantine_path = os.path.join(self.devices,
'sda', 'quarantined', 'objects')
self.assertTrue(os.path.isdir(quarantine_path))
2011-02-21 16:37:12 -08:00
def test_object_run_fast_track_zero(self):
self.setup_bad_zero_byte()
self.auditor.run_once(zero_byte_fps=50)
quarantine_path = os.path.join(self.devices,
'sda', 'quarantined', 'objects')
self.assertTrue(os.path.isdir(quarantine_path))
2010-07-12 17:03:45 -05:00
2011-02-24 12:27:20 -08:00
def test_with_tombstone(self):
ts_file_path = self.setup_bad_zero_byte(with_ts=True)
self.auditor.run_once()
quarantine_path = os.path.join(self.devices,
'sda', 'quarantined', 'objects')
self.assertTrue(ts_file_path.endswith('ts'))
self.assertTrue(os.path.exists(ts_file_path))
def test_sleeper(self):
auditor.SLEEP_BETWEEN_AUDITS = 0.01
my_auditor = auditor.ObjectAuditor(self.conf)
start = time.time()
my_auditor._sleep()
self.assertEquals(round(time.time() - start, 2), 0.01)
2011-08-30 14:29:19 -07:00
def test_object_run_fast_track_zero_check_closed(self):
rat = [False]
class FakeFile(DiskFile):
def close(self, verify_file=True):
rat[0] = True
DiskFile.close(self, verify_file=verify_file)
self.setup_bad_zero_byte()
was_df = object_server.DiskFile
2011-08-31 07:28:36 -07:00
try:
object_server.DiskFile = FakeFile
self.auditor.run_once(zero_byte_fps=50)
quarantine_path = os.path.join(self.devices,
'sda', 'quarantined', 'objects')
self.assertTrue(os.path.isdir(quarantine_path))
self.assertTrue(rat[0])
finally:
object_server.DiskFile = was_df
2011-08-30 14:29:19 -07:00
2011-02-24 12:27:20 -08:00
def test_run_forever(self):
class StopForever(Exception):
pass
class ObjectAuditorMock(object):
check_args = ()
check_kwargs = {}
fork_called = 0
fork_res = 0
def mock_run(self, *args, **kwargs):
self.check_args = args
self.check_kwargs = kwargs
def mock_sleep(self):
raise StopForever('stop')
def mock_fork(self):
self.fork_called += 1
return self.fork_res
my_auditor = auditor.ObjectAuditor(dict(devices=self.devices,
mount_check='false',
zero_byte_files_per_second=89))
mocker = ObjectAuditorMock()
my_auditor.run_once = mocker.mock_run
my_auditor._sleep = mocker.mock_sleep
was_fork = os.fork
try:
os.fork = mocker.mock_fork
self.assertRaises(StopForever,
my_auditor.run_forever, zero_byte_fps=50)
self.assertEquals(mocker.check_kwargs['zero_byte_fps'], 50)
self.assertEquals(mocker.fork_called, 0)
self.assertRaises(StopForever, my_auditor.run_forever)
self.assertEquals(mocker.fork_called, 1)
self.assertEquals(mocker.check_args, ())
mocker.fork_res = 1
self.assertRaises(StopForever, my_auditor.run_forever)
self.assertEquals(mocker.fork_called, 2)
self.assertEquals(mocker.check_kwargs['zero_byte_fps'], 89)
finally:
os.fork = was_fork
2010-07-12 17:03:45 -05:00
if __name__ == '__main__':
unittest.main()