Add checksum to object extended attributes

Currently, our integrity checking for objects is pretty weak when it
comes to object metadata. If the extended attributes on a .data or
.meta file get corrupted in such a way that we can still unpickle it,
we don't have anything that detects that.

This could be especially bad with encrypted etags; if the encrypted
etag (X-Object-Sysmeta-Crypto-Etag or whatever it is) gets some bits
flipped, then we'll cheerfully decrypt the cipherjunk into plainjunk,
then send it to the client. Net effect is that the client sees a GET
response with an ETag that doesn't match the MD5 of the object *and*
Swift has no way of detecting and quarantining this object.

Note that, with an unencrypted object, if the ETag metadatum gets
mangled, then the object will be quarantined by the object server or
auditor, whichever notices first.

As part of this commit, I also ripped out some mocking of
getxattr/setxattr in tests. It appears to be there to allow unit tests
to run on systems where /tmp doesn't support xattrs. However, since
the mock is keyed off of inode number and inode numbers get re-used,
there's lots of leakage between different test runs. On a real FS,
unlinking a file and then creating a new one of the same name will
also reset the xattrs; this isn't the case with the mock.

The mock was pretty old; Ubuntu 12.04 and up all support xattrs in
/tmp, and recent Red Hat / CentOS releases do too. The xattr mock was
added in 2011; maybe it was to support Ubuntu Lucid Lynx?

Bonus: now you can pause a test with the debugger, inspect its files
in /tmp, and actually see the xattrs along with the data.

Since this patch now uses a real filesystem for testing filesystem
operations, tests are skipped if the underlying filesystem does not
support setting xattrs (eg tmpfs or more than 4k of xattrs on ext4).

References to "/tmp" have been replaced with calls to
tempfile.gettempdir(). This will allow setting the TMPDIR envvar in
test setup and getting an XFS filesystem instead of ext4 or tmpfs.

THIS PATCH SIGNIFICANTLY CHANGES TESTING ENVIRONMENTS

With this patch, every test environment will require TMPDIR to be
using a filesystem that supports at least 4k of extended attributes.
Neither ext4 nor tempfs support this. XFS is recommended.

So why all the SkipTests? Why not simply raise an error? We still need
the tests to run on the base image for OpenStack's CI system. Since
we were previously mocking out xattr, there wasn't a problem, but we
also weren't actually testing anything. This patch adds functionality
to validate xattr data, so we need to drop the mock.

`test.unit.skip_if_no_xattrs()` is also imported into `test.functional`
so that functional tests can import it from the functional test
namespace.

The related OpenStack CI infrastructure changes are made in
https://review.openstack.org/#/c/394600/.

Co-Authored-By: John Dickinson <me@not.mn>

Change-Id: I98a37c0d451f4960b7a12f648e4405c6c6716808
This commit is contained in:
Samuel Merritt 2016-06-30 16:52:58 -07:00 committed by Thiago da Silva
parent feee399840
commit 728b4ba140
31 changed files with 264 additions and 110 deletions

View File

@ -82,6 +82,12 @@ You can run unit tests with ``.unittests``, functional tests with
``.functests``, and probe tests with ``.probetests``. There is an ``.functests``, and probe tests with ``.probetests``. There is an
additional ``.alltests`` script that wraps the other three. additional ``.alltests`` script that wraps the other three.
To fully run the tests, the target environment must use a filesystem that
supports large xattrs. XFS is strongly recommended. For unit tests and in-
process functional tests, either mount ``/tmp`` with XFS or provide another
XFS filesystem via the ``TMPDIR`` environment variable. Without this setting,
tests should still pass, but a very large number will be skipped.
Code Organization Code Organization
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

View File

@ -77,6 +77,9 @@ To execute the tests:
--recreate`` or remove the ``.tox`` directory to force ``tox`` to recreate the --recreate`` or remove the ``.tox`` directory to force ``tox`` to recreate the
dependency list. dependency list.
Swift's tests require having an XFS directory available in ``/tmp`` or
in the ``TMPDIR`` environment variable.
Swift's functional tests may be executed against a :doc:`development_saio` or Swift's functional tests may be executed against a :doc:`development_saio` or
other running Swift cluster using the command:: other running Swift cluster using the command::

View File

@ -201,6 +201,23 @@ On Fedora 19 or later, you need to place these in ``/etc/rc.d/rc.local``.
On OpenSuse you need to place these in ``/etc/init.d/boot.local``. On OpenSuse you need to place these in ``/etc/init.d/boot.local``.
Creating an XFS tmp dir
-----------------------
Tests require having an XFS directory available in ``/tmp`` or in the
``TMPDIR`` environment variable. To set up ``/tmp`` with an XFS filesystem,
do the following::
cd ~
truncate -s 1GB xfs_file # create 1GB fil for XFS in your home directory
mkfs.xfs xfs_file
sudo mount -o loop,noatime,nodiratime xfs_file /tmp
sudo chmod -R 1777 /tmp
To persist this, edit and add the following to ``/etc/fstab``::
/home/swift/xfs_file /tmp xfs rw,noatime,nodiratime,attr2,inode64,noquota 0 0
---------------- ----------------
Getting the code Getting the code
---------------- ----------------

View File

@ -105,6 +105,10 @@ class DiskFileXattrNotSupported(DiskFileError):
pass pass
class DiskFileBadMetadataChecksum(DiskFileError):
pass
class DeviceUnavailable(SwiftException): class DeviceUnavailable(SwiftException):
pass pass

View File

@ -23,6 +23,7 @@ import time
import subprocess import subprocess
import re import re
from swift import gettext_ as _ from swift import gettext_ as _
import tempfile
from swift.common.utils import search_tree, remove_file, write_file from swift.common.utils import search_tree, remove_file, write_file
from swift.common.exceptions import InvalidPidFileException from swift.common.exceptions import InvalidPidFileException
@ -82,7 +83,7 @@ def setup_env():
"Running as non-root?")) "Running as non-root?"))
# Set PYTHON_EGG_CACHE if it isn't already set # Set PYTHON_EGG_CACHE if it isn't already set
os.environ.setdefault('PYTHON_EGG_CACHE', '/tmp') os.environ.setdefault('PYTHON_EGG_CACHE', tempfile.gettempdir())
def command(func): def command(func):

View File

@ -70,7 +70,8 @@ from swift.common.splice import splice, tee
from swift.common.exceptions import DiskFileQuarantined, DiskFileNotExist, \ from swift.common.exceptions import DiskFileQuarantined, DiskFileNotExist, \
DiskFileCollision, DiskFileNoSpace, DiskFileDeviceUnavailable, \ DiskFileCollision, DiskFileNoSpace, DiskFileDeviceUnavailable, \
DiskFileDeleted, DiskFileError, DiskFileNotOpen, PathNotDir, \ DiskFileDeleted, DiskFileError, DiskFileNotOpen, PathNotDir, \
ReplicationLockTimeout, DiskFileExpired, DiskFileXattrNotSupported ReplicationLockTimeout, DiskFileExpired, DiskFileXattrNotSupported, \
DiskFileBadMetadataChecksum
from swift.common.swob import multi_range_iterator from swift.common.swob import multi_range_iterator
from swift.common.storage_policy import ( from swift.common.storage_policy import (
get_policy_string, split_policy_string, PolicyError, POLICIES, get_policy_string, split_policy_string, PolicyError, POLICIES,
@ -83,6 +84,7 @@ DEFAULT_RECLAIM_AGE = timedelta(weeks=1).total_seconds()
HASH_FILE = 'hashes.pkl' HASH_FILE = 'hashes.pkl'
HASH_INVALIDATIONS_FILE = 'hashes.invalid' HASH_INVALIDATIONS_FILE = 'hashes.invalid'
METADATA_KEY = 'user.swift.metadata' METADATA_KEY = 'user.swift.metadata'
METADATA_CHECKSUM_KEY = 'user.swift.metadata_checksum'
DROP_CACHE_WINDOW = 1024 * 1024 DROP_CACHE_WINDOW = 1024 * 1024
# These are system-set metadata keys that cannot be changed with a POST. # These are system-set metadata keys that cannot be changed with a POST.
# They should be lowercase. # They should be lowercase.
@ -145,16 +147,33 @@ def read_metadata(fd):
(key or ''))) (key or '')))
key += 1 key += 1
except (IOError, OSError) as e: except (IOError, OSError) as e:
for err in 'ENOTSUP', 'EOPNOTSUPP': if errno.errorcode.get(e.errno) in ('ENOTSUP', 'EOPNOTSUPP'):
if hasattr(errno, err) and e.errno == getattr(errno, err): msg = "Filesystem at %s does not support xattr"
msg = "Filesystem at %s does not support xattr" % \ logging.exception(msg, _get_filename(fd))
_get_filename(fd)
logging.exception(msg)
raise DiskFileXattrNotSupported(e) raise DiskFileXattrNotSupported(e)
if e.errno == errno.ENOENT: if e.errno == errno.ENOENT:
raise DiskFileNotExist() raise DiskFileNotExist()
# TODO: we might want to re-raise errors that don't denote a missing # TODO: we might want to re-raise errors that don't denote a missing
# xattr here. Seems to be ENODATA on linux and ENOATTR on BSD/OSX. # xattr here. Seems to be ENODATA on linux and ENOATTR on BSD/OSX.
metadata_checksum = None
try:
metadata_checksum = xattr.getxattr(fd, METADATA_CHECKSUM_KEY)
except (IOError, OSError) as e:
# All the interesting errors were handled above; the only thing left
# here is ENODATA / ENOATTR to indicate that this attribute doesn't
# exist. This is fine; it just means that this object predates the
# introduction of metadata checksums.
pass
if metadata_checksum:
computed_checksum = hashlib.md5(metadata).hexdigest()
if metadata_checksum != computed_checksum:
raise DiskFileBadMetadataChecksum(
"Metadata checksum mismatch for %s: "
"stored checksum='%s', computed='%s'" % (
fd, metadata_checksum, computed_checksum))
# strings are utf-8 encoded when written, but have not always been # strings are utf-8 encoded when written, but have not always been
# (see https://bugs.launchpad.net/swift/+bug/1678018) so encode them again # (see https://bugs.launchpad.net/swift/+bug/1678018) so encode them again
# when read # when read
@ -169,21 +188,23 @@ def write_metadata(fd, metadata, xattr_size=65536):
:param metadata: metadata to write :param metadata: metadata to write
""" """
metastr = pickle.dumps(_encode_metadata(metadata), PICKLE_PROTOCOL) metastr = pickle.dumps(_encode_metadata(metadata), PICKLE_PROTOCOL)
metastr_md5 = hashlib.md5(metastr).hexdigest()
key = 0 key = 0
while metastr:
try: try:
while metastr:
xattr.setxattr(fd, '%s%s' % (METADATA_KEY, key or ''), xattr.setxattr(fd, '%s%s' % (METADATA_KEY, key or ''),
metastr[:xattr_size]) metastr[:xattr_size])
metastr = metastr[xattr_size:] metastr = metastr[xattr_size:]
key += 1 key += 1
xattr.setxattr(fd, METADATA_CHECKSUM_KEY, metastr_md5)
except IOError as e: except IOError as e:
for err in 'ENOTSUP', 'EOPNOTSUPP': # errno module doesn't always have both of these, hence the ugly
if hasattr(errno, err) and e.errno == getattr(errno, err): # check
msg = "Filesystem at %s does not support xattr" % \ if errno.errorcode.get(e.errno) in ('ENOTSUP', 'EOPNOTSUPP'):
_get_filename(fd) msg = "Filesystem at %s does not support xattr"
logging.exception(msg) logging.exception(msg, _get_filename(fd))
raise DiskFileXattrNotSupported(e) raise DiskFileXattrNotSupported(e)
if e.errno in (errno.ENOSPC, errno.EDQUOT): elif e.errno in (errno.ENOSPC, errno.EDQUOT):
msg = "No space left on device for %s" % _get_filename(fd) msg = "No space left on device for %s" % _get_filename(fd)
logging.exception(msg) logging.exception(msg)
raise DiskFileNoSpace() raise DiskFileNoSpace()
@ -2389,6 +2410,8 @@ class BaseDiskFile(object):
return read_metadata(source) return read_metadata(source)
except (DiskFileXattrNotSupported, DiskFileNotExist): except (DiskFileXattrNotSupported, DiskFileNotExist):
raise raise
except DiskFileBadMetadataChecksum as err:
raise self._quarantine(quarantine_filename, str(err))
except Exception as err: except Exception as err:
raise self._quarantine( raise self._quarantine(
quarantine_filename, quarantine_filename,

View File

@ -31,7 +31,6 @@ from contextlib import closing
from gzip import GzipFile from gzip import GzipFile
from shutil import rmtree from shutil import rmtree
from tempfile import mkdtemp from tempfile import mkdtemp
from unittest2 import SkipTest
from six.moves.configparser import ConfigParser, NoSectionError from six.moves.configparser import ConfigParser, NoSectionError
from six.moves import http_client from six.moves import http_client
@ -44,10 +43,13 @@ from swift.common.utils import set_swift_dir
from test import get_config, listen_zero from test import get_config, listen_zero
from test.functional.swift_test_client import Account, Connection, Container, \ from test.functional.swift_test_client import Account, Connection, Container, \
ResponseError ResponseError
# This has the side effect of mocking out the xattr module so that unit tests
# (and in this case, when in-process functional tests are called for) can run
# on file systems that don't support extended attributes.
from test.unit import debug_logger, FakeMemcache from test.unit import debug_logger, FakeMemcache
# importing skip_if_no_xattrs so that functional tests can grab it from the
# test.functional namespace. Importing SkipTest so this works under both
# nose and testr test runners.
from test.unit import skip_if_no_xattrs as real_skip_if_no_xattrs
from test.unit import SkipTest
from swift.common import constraints, utils, ring, storage_policy from swift.common import constraints, utils, ring, storage_policy
from swift.common.ring import Ring from swift.common.ring import Ring
@ -110,6 +112,7 @@ insecure = False
in_process = False in_process = False
_testdir = _test_servers = _test_coros = _test_socks = None _testdir = _test_servers = _test_coros = _test_socks = None
policy_specified = None policy_specified = None
skip_if_no_xattrs = None
class FakeMemcacheMiddleware(MemcacheMiddleware): class FakeMemcacheMiddleware(MemcacheMiddleware):
@ -660,6 +663,7 @@ def get_cluster_info():
def setup_package(): def setup_package():
global policy_specified global policy_specified
global skip_if_no_xattrs
policy_specified = os.environ.get('SWIFT_TEST_POLICY') policy_specified = os.environ.get('SWIFT_TEST_POLICY')
in_process_env = os.environ.get('SWIFT_TEST_IN_PROCESS') in_process_env = os.environ.get('SWIFT_TEST_IN_PROCESS')
if in_process_env is not None: if in_process_env is not None:
@ -698,6 +702,7 @@ def setup_package():
if in_process: if in_process:
in_mem_obj_env = os.environ.get('SWIFT_TEST_IN_MEMORY_OBJ') in_mem_obj_env = os.environ.get('SWIFT_TEST_IN_MEMORY_OBJ')
in_mem_obj = utils.config_true_value(in_mem_obj_env) in_mem_obj = utils.config_true_value(in_mem_obj_env)
skip_if_no_xattrs = real_skip_if_no_xattrs
try: try:
in_process_setup(the_object_server=( in_process_setup(the_object_server=(
mem_object_server if in_mem_obj else object_server)) mem_object_server if in_mem_obj else object_server))
@ -705,6 +710,8 @@ def setup_package():
print(('Exception during in-process setup: %s' print(('Exception during in-process setup: %s'
% str(exc)), file=sys.stderr) % str(exc)), file=sys.stderr)
raise raise
else:
skip_if_no_xattrs = lambda: None
global web_front_end global web_front_end
web_front_end = config.get('web_front_end', 'integral') web_front_end = config.get('web_front_end', 'integral')

View File

@ -834,6 +834,9 @@ class TestAccount(unittest2.TestCase):
if tf.skip: if tf.skip:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
def post(url, token, parsed, conn, extra_headers): def post(url, token, parsed, conn, extra_headers):
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
headers.update(extra_headers) headers.update(extra_headers)

View File

@ -438,6 +438,9 @@ class TestContainer(unittest2.TestCase):
if tf.skip: if tf.skip:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
def post(url, token, parsed, conn, extra_headers): def post(url, token, parsed, conn, extra_headers):
headers = {'X-Auth-Token': token} headers = {'X-Auth-Token': token}
headers.update(extra_headers) headers.update(extra_headers)
@ -580,6 +583,9 @@ class TestContainer(unittest2.TestCase):
def test_cross_account_public_container(self): def test_cross_account_public_container(self):
if tf.skip or tf.skip2: if tf.skip or tf.skip2:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
# Obtain the first account's string # Obtain the first account's string
first_account = ['unknown'] first_account = ['unknown']
@ -649,6 +655,9 @@ class TestContainer(unittest2.TestCase):
def test_nonadmin_user(self): def test_nonadmin_user(self):
if tf.skip or tf.skip3: if tf.skip or tf.skip3:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
# Obtain the first account's string # Obtain the first account's string
first_account = ['unknown'] first_account = ['unknown']
@ -1562,6 +1571,9 @@ class TestContainer(unittest2.TestCase):
if 'container_quotas' not in cluster_info: if 'container_quotas' not in cluster_info:
raise SkipTest('Container quotas not enabled') raise SkipTest('Container quotas not enabled')
if tf.in_process:
tf.skip_if_no_xattrs()
def post(url, token, parsed, conn, name, value): def post(url, token, parsed, conn, name, value):
conn.request('POST', parsed.path + '/' + self.name, '', conn.request('POST', parsed.path + '/' + self.name, '',
{'X-Auth-Token': token, name: value}) {'X-Auth-Token': token, name: value})

View File

@ -42,6 +42,9 @@ class TestObject(unittest2.TestCase):
def setUp(self): def setUp(self):
if tf.skip or tf.skip2: if tf.skip or tf.skip2:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
self.container = uuid4().hex self.container = uuid4().hex
self.containers = [] self.containers = []

View File

@ -379,6 +379,9 @@ class TestObjectVersioning(Base):
self.assertNotIn('x-object-manifest', resp_headers) self.assertNotIn('x-object-manifest', resp_headers)
def _test_versioning_dlo_setup(self): def _test_versioning_dlo_setup(self):
if tf.in_process:
tf.skip_if_no_xattrs()
container = self.env.container container = self.env.container
versions_container = self.env.versions_container versions_container = self.env.versions_container
obj_name = Utils.create_name() obj_name = Utils.create_name()
@ -695,6 +698,8 @@ class TestSloWithVersioning(unittest2.TestCase):
def setUp(self): def setUp(self):
if 'slo' not in cluster_info: if 'slo' not in cluster_info:
raise SkipTest("SLO not enabled") raise SkipTest("SLO not enabled")
if tf.in_process:
tf.skip_if_no_xattrs()
self.conn = Connection(tf.config) self.conn = Connection(tf.config)
self.conn.authenticate() self.conn.authenticate()

View File

@ -87,16 +87,19 @@ class BaseEnv(object):
class Base(unittest2.TestCase): class Base(unittest2.TestCase):
# subclasses may override env class
env = BaseEnv env = BaseEnv
@classmethod
def tearDownClass(cls):
cls.env.tearDown()
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.env.setUp() cls.env.setUp()
@classmethod def setUp(self):
def tearDownClass(cls): if tf.in_process:
cls.env.tearDown() tf.skip_if_no_xattrs()
def assert_body(self, body): def assert_body(self, body):
response_body = self.env.conn.response.read() response_body = self.env.conn.response.read()
@ -2721,6 +2724,9 @@ class TestServiceToken(unittest2.TestCase):
if tf.skip_service_tokens: if tf.skip_service_tokens:
raise SkipTest raise SkipTest
if tf.in_process:
tf.skip_if_no_xattrs()
self.SET_TO_USERS_TOKEN = 1 self.SET_TO_USERS_TOKEN = 1
self.SET_TO_SERVICE_TOKEN = 2 self.SET_TO_SERVICE_TOKEN = 2

View File

@ -19,7 +19,6 @@ from __future__ import print_function
import os import os
import copy import copy
import logging import logging
import errno
from six.moves import range from six.moves import range
from six import BytesIO from six import BytesIO
import sys import sys
@ -32,11 +31,14 @@ import time
import eventlet import eventlet
from eventlet import greenpool, debug as eventlet_debug from eventlet import greenpool, debug as eventlet_debug
from eventlet.green import socket from eventlet.green import socket
from tempfile import mkdtemp from tempfile import mkdtemp, mkstemp, gettempdir
from shutil import rmtree from shutil import rmtree
import signal import signal
import json import json
import random import random
import errno
import xattr
from swift.common.utils import Timestamp, NOTICE from swift.common.utils import Timestamp, NOTICE
from test import get_config from test import get_config
@ -57,7 +59,12 @@ import six.moves.cPickle as pickle
from gzip import GzipFile from gzip import GzipFile
import mock as mocklib import mock as mocklib
import inspect import inspect
from nose import SkipTest import unittest
import unittest2
class SkipTest(unittest2.SkipTest, unittest.SkipTest):
pass
EMPTY_ETAG = md5().hexdigest() EMPTY_ETAG = md5().hexdigest()
@ -402,36 +409,6 @@ def tmpfile(content):
finally: finally:
os.unlink(file_name) os.unlink(file_name)
xattr_data = {}
def _get_inode(fd):
if not isinstance(fd, int):
try:
fd = fd.fileno()
except AttributeError:
return os.stat(fd).st_ino
return os.fstat(fd).st_ino
def _setxattr(fd, k, v):
inode = _get_inode(fd)
data = xattr_data.get(inode, {})
data[k] = v
xattr_data[inode] = data
def _getxattr(fd, k):
inode = _get_inode(fd)
data = xattr_data.get(inode, {}).get(k)
if not data:
raise IOError(errno.ENODATA, "Fake IOError")
return data
import xattr
xattr.setxattr = _setxattr
xattr.getxattr = _getxattr
@contextmanager @contextmanager
def temptree(files, contents=''): def temptree(files, contents=''):
@ -1289,3 +1266,51 @@ def fake_ec_node_response(node_frags, policy):
return StubResponse(200, body, headers) return StubResponse(200, body, headers)
return get_response return get_response
supports_xattr_cached_val = None
def xattr_supported_check():
"""
This check simply sets more than 4k of metadata on a tempfile and
returns True if it worked and False if not.
We want to use *more* than 4k of metadata in this check because
some filesystems (eg ext4) only allow one blocksize worth of
metadata. The XFS filesystem doesn't have this limit, and so this
check returns True when TMPDIR is XFS. This check will return
False under ext4 (which supports xattrs <= 4k) and tmpfs (which
doesn't support xattrs at all).
"""
global supports_xattr_cached_val
if supports_xattr_cached_val is not None:
return supports_xattr_cached_val
# assume the worst -- xattrs aren't supported
supports_xattr_cached_val = False
big_val = 'x' * (4096 + 1) # more than 4k of metadata
try:
fd, tmppath = mkstemp()
xattr.setxattr(fd, 'user.swift.testing_key', big_val)
except IOError as e:
if errno.errorcode.get(e.errno) in ('ENOSPC', 'ENOTSUP', 'EOPNOTSUPP'):
# filesystem does not support xattr of this size
return False
raise
else:
supports_xattr_cached_val = True
return True
finally:
# clean up the tmpfile
os.close(fd)
os.unlink(tmppath)
def skip_if_no_xattrs():
if not xattr_supported_check():
raise SkipTest('Large xattrs not supported in `%s`. Skipping test' %
gettempdir())

View File

@ -20,7 +20,7 @@ from shutil import rmtree
from tempfile import mkdtemp from tempfile import mkdtemp
from six.moves import cStringIO as StringIO from six.moves import cStringIO as StringIO
from test.unit import patch_policies, write_fake_ring from test.unit import patch_policies, write_fake_ring, skip_if_no_xattrs
from swift.common import ring, utils from swift.common import ring, utils
from swift.common.swob import Request from swift.common.swob import Request
@ -40,6 +40,7 @@ from swift.obj.diskfile import write_metadata
StoragePolicy(3, 'three', False)]) StoragePolicy(3, 'three', False)])
class TestCliInfoBase(unittest.TestCase): class TestCliInfoBase(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.orig_hp = utils.HASH_PATH_PREFIX, utils.HASH_PATH_SUFFIX self.orig_hp = utils.HASH_PATH_PREFIX, utils.HASH_PATH_SUFFIX
utils.HASH_PATH_PREFIX = 'info' utils.HASH_PATH_PREFIX = 'info'
utils.HASH_PATH_SUFFIX = 'info' utils.HASH_PATH_SUFFIX = 'info'

View File

@ -26,11 +26,12 @@ from swift.common.storage_policy import (
from swift.obj.diskfile import write_metadata from swift.obj.diskfile import write_metadata
from test.unit import FakeLogger from test.unit import FakeLogger, skip_if_no_xattrs
class TestRelinker(unittest.TestCase): class TestRelinker(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.logger = FakeLogger() self.logger = FakeLogger()
self.testdir = tempfile.mkdtemp() self.testdir = tempfile.mkdtemp()
self.devices = os.path.join(self.testdir, 'node') self.devices = os.path.join(self.testdir, 'node')

View File

@ -1425,7 +1425,7 @@ class TestCommands(unittest.TestCase, RunSwiftRingBuilderMixin):
self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv)
def test_validate_non_existent_file(self): def test_validate_non_existent_file(self):
rand_file = '%s/%s' % ('/tmp', str(uuid.uuid4())) rand_file = '%s/%s' % (tempfile.gettempdir(), str(uuid.uuid4()))
argv = ["", rand_file, "validate"] argv = ["", rand_file, "validate"]
self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv) self.assertSystemExit(EXIT_ERROR, ringbuilder.main, argv)

View File

@ -29,7 +29,7 @@ from swift.common.ring import Ring
from swift.common.swob import Request from swift.common.swob import Request
from swift.obj import diskfile from swift.obj import diskfile
from test.unit import FakeLogger from test.unit import FakeLogger, skip_if_no_xattrs
from test.unit.common.middleware.crypto.crypto_helpers import ( from test.unit.common.middleware.crypto.crypto_helpers import (
md5hex, encrypt, TEST_KEYMASTER_CONF) md5hex, encrypt, TEST_KEYMASTER_CONF)
from test.unit.helpers import setup_servers, teardown_servers from test.unit.helpers import setup_servers, teardown_servers
@ -54,6 +54,7 @@ class TestCryptoPipelineChanges(unittest.TestCase):
cls._test_context = None cls._test_context = None
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.plaintext = 'unencrypted body content' self.plaintext = 'unencrypted body content'
self.plaintext_etag = md5hex(self.plaintext) self.plaintext_etag = md5hex(self.plaintext)
self._setup_crypto_app() self._setup_crypto_app()

View File

@ -268,7 +268,8 @@ class TestReconSuccess(TestCase):
return app return app
def _create_ring(self, ringpath, replica_map, devs, part_shift): def _create_ring(self, ringpath, replica_map, devs, part_shift):
ring.RingData(replica_map, devs, part_shift).save(ringpath) ring.RingData(replica_map, devs, part_shift).save(ringpath,
mtime=None)
def _create_rings(self): def _create_rings(self):
# make the rings unique so they have different md5 sums # make the rings unique so they have different md5 sums

View File

@ -20,6 +20,7 @@ import unittest
import os import os
import mock import mock
from uuid import uuid4 from uuid import uuid4
from tempfile import gettempdir
from swift.common.linkat import linkat from swift.common.linkat import linkat
from swift.common.utils import O_TMPFILE from swift.common.utils import O_TMPFILE
@ -42,7 +43,7 @@ class TestLinkat(unittest.TestCase):
with open('/dev/null', 'r') as fd: with open('/dev/null', 'r') as fd:
self.assertRaises(IOError, linkat, self.assertRaises(IOError, linkat,
linkat.AT_FDCWD, "/proc/self/fd/%s" % (fd), linkat.AT_FDCWD, "/proc/self/fd/%s" % (fd),
linkat.AT_FDCWD, "/tmp/testlinkat", linkat.AT_FDCWD, "%s/testlinkat" % gettempdir(),
linkat.AT_SYMLINK_FOLLOW) linkat.AT_SYMLINK_FOLLOW)
self.assertEqual(ctypes.get_errno(), 0) self.assertEqual(ctypes.get_errno(), 0)
@ -83,8 +84,8 @@ class TestLinkat(unittest.TestCase):
path = None path = None
ret = -1 ret = -1
try: try:
fd = os.open('/tmp', O_TMPFILE | os.O_WRONLY) fd = os.open(gettempdir(), O_TMPFILE | os.O_WRONLY)
path = os.path.join('/tmp', uuid4().hex) path = os.path.join(gettempdir(), uuid4().hex)
ret = linkat(linkat.AT_FDCWD, "/proc/self/fd/%d" % (fd), ret = linkat(linkat.AT_FDCWD, "/proc/self/fd/%d" % (fd),
linkat.AT_FDCWD, path, linkat.AT_SYMLINK_FOLLOW) linkat.AT_FDCWD, path, linkat.AT_SYMLINK_FOLLOW)
self.assertEqual(ret, 0) self.assertEqual(ret, 0)

View File

@ -24,6 +24,7 @@ import signal
import errno import errno
from collections import defaultdict from collections import defaultdict
from time import sleep, time from time import sleep, time
import tempfile
from six.moves import reload_module from six.moves import reload_module
@ -115,7 +116,8 @@ class TestManagerModule(unittest.TestCase):
] ]
self.assertEqual(manager.resource.called_with_args, expected) self.assertEqual(manager.resource.called_with_args, expected)
self.assertTrue( self.assertTrue(
manager.os.environ['PYTHON_EGG_CACHE'].startswith('/tmp')) manager.os.environ['PYTHON_EGG_CACHE'].startswith(
tempfile.gettempdir()))
# test error condition # test error condition
manager.resource = MockResource(error=ValueError()) manager.resource = MockResource(error=ValueError())
@ -123,7 +125,8 @@ class TestManagerModule(unittest.TestCase):
manager.setup_env() manager.setup_env()
self.assertEqual(manager.resource.called_with_args, []) self.assertEqual(manager.resource.called_with_args, [])
self.assertTrue( self.assertTrue(
manager.os.environ['PYTHON_EGG_CACHE'].startswith('/tmp')) manager.os.environ['PYTHON_EGG_CACHE'].startswith(
tempfile.gettempdir()))
manager.resource = MockResource(error=OSError()) manager.resource = MockResource(error=OSError())
manager.os.environ = {} manager.os.environ = {}

View File

@ -2018,7 +2018,7 @@ foo = bar
[section2] [section2]
log_name = yarr''' log_name = yarr'''
# setup a real file # setup a real file
fd, temppath = tempfile.mkstemp(dir='/tmp') fd, temppath = tempfile.mkstemp()
with os.fdopen(fd, 'wb') as f: with os.fdopen(fd, 'wb') as f:
f.write(conf) f.write(conf)
make_filename = lambda: temppath make_filename = lambda: temppath
@ -2067,7 +2067,7 @@ foo = bar
[section2] [section2]
log_name = %(yarr)s''' log_name = %(yarr)s'''
# setup a real file # setup a real file
fd, temppath = tempfile.mkstemp(dir='/tmp') fd, temppath = tempfile.mkstemp()
with os.fdopen(fd, 'wb') as f: with os.fdopen(fd, 'wb') as f:
f.write(conf) f.write(conf)
make_filename = lambda: temppath make_filename = lambda: temppath
@ -3275,7 +3275,7 @@ cluster_dfw1 = http://dfw1.host/v1/
tmpdir = mkdtemp() tmpdir = mkdtemp()
try: try:
link = os.path.join(tmpdir, "tmp") link = os.path.join(tmpdir, "tmp")
os.symlink("/tmp", link) os.symlink(tempfile.gettempdir(), link)
self.assertFalse(utils.ismount(link)) self.assertFalse(utils.ismount(link))
finally: finally:
shutil.rmtree(tmpdir) shutil.rmtree(tmpdir)
@ -3580,7 +3580,7 @@ cluster_dfw1 = http://dfw1.host/v1/
tempdir = None tempdir = None
fd = None fd = None
try: try:
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
fd, temppath = tempfile.mkstemp(dir=tempdir) fd, temppath = tempfile.mkstemp(dir=tempdir)
_mock_fsync = mock.Mock() _mock_fsync = mock.Mock()
@ -3618,7 +3618,7 @@ cluster_dfw1 = http://dfw1.host/v1/
def test_renamer_with_fsync_dir(self): def test_renamer_with_fsync_dir(self):
tempdir = None tempdir = None
try: try:
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
# Simulate part of object path already existing # Simulate part of object path already existing
part_dir = os.path.join(tempdir, 'objects/1234/') part_dir = os.path.join(tempdir, 'objects/1234/')
os.makedirs(part_dir) os.makedirs(part_dir)
@ -3665,7 +3665,7 @@ cluster_dfw1 = http://dfw1.host/v1/
tempdir = None tempdir = None
fd = None fd = None
try: try:
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
os.makedirs(os.path.join(tempdir, 'a/b')) os.makedirs(os.path.join(tempdir, 'a/b'))
# 4 new dirs created # 4 new dirs created
dirpath = os.path.join(tempdir, 'a/b/1/2/3/4') dirpath = os.path.join(tempdir, 'a/b/1/2/3/4')
@ -3788,7 +3788,7 @@ cluster_dfw1 = http://dfw1.host/v1/
@requires_o_tmpfile_support @requires_o_tmpfile_support
def test_link_fd_to_path_linkat_success(self): def test_link_fd_to_path_linkat_success(self):
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
fd = os.open(tempdir, utils.O_TMPFILE | os.O_WRONLY) fd = os.open(tempdir, utils.O_TMPFILE | os.O_WRONLY)
data = "I'm whatever Gotham needs me to be" data = "I'm whatever Gotham needs me to be"
_m_fsync_dir = mock.Mock() _m_fsync_dir = mock.Mock()
@ -3808,7 +3808,7 @@ cluster_dfw1 = http://dfw1.host/v1/
@requires_o_tmpfile_support @requires_o_tmpfile_support
def test_link_fd_to_path_target_exists(self): def test_link_fd_to_path_target_exists(self):
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
# Create and write to a file # Create and write to a file
fd, path = tempfile.mkstemp(dir=tempdir) fd, path = tempfile.mkstemp(dir=tempdir)
os.write(fd, "hello world") os.write(fd, "hello world")
@ -3843,7 +3843,7 @@ cluster_dfw1 = http://dfw1.host/v1/
@requires_o_tmpfile_support @requires_o_tmpfile_support
def test_linkat_race_dir_not_exists(self): def test_linkat_race_dir_not_exists(self):
tempdir = mkdtemp(dir='/tmp') tempdir = mkdtemp()
target_dir = os.path.join(tempdir, uuid4().hex) target_dir = os.path.join(tempdir, uuid4().hex)
target_path = os.path.join(target_dir, uuid4().hex) target_path = os.path.join(target_dir, uuid4().hex)
os.mkdir(target_dir) os.mkdir(target_dir)

View File

@ -14,7 +14,6 @@
# limitations under the License. # limitations under the License.
import json import json
from test import unit
import unittest import unittest
import mock import mock
import os import os
@ -26,7 +25,7 @@ from tempfile import mkdtemp
import textwrap import textwrap
from os.path import dirname, basename from os.path import dirname, basename
from test.unit import (debug_logger, patch_policies, make_timestamp_iter, from test.unit import (debug_logger, patch_policies, make_timestamp_iter,
DEFAULT_TEST_EC_TYPE) DEFAULT_TEST_EC_TYPE, skip_if_no_xattrs)
from swift.obj import auditor, replicator from swift.obj import auditor, replicator
from swift.obj.diskfile import ( from swift.obj.diskfile import (
DiskFile, write_metadata, invalidate_hash, get_data_dir, DiskFile, write_metadata, invalidate_hash, get_data_dir,
@ -63,6 +62,7 @@ def works_only_once(callable_thing, exception):
class TestAuditor(unittest.TestCase): class TestAuditor(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.testdir = os.path.join(mkdtemp(), 'tmp_test_object_auditor') self.testdir = os.path.join(mkdtemp(), 'tmp_test_object_auditor')
self.devices = os.path.join(self.testdir, 'node') self.devices = os.path.join(self.testdir, 'node')
self.rcache = os.path.join(self.testdir, 'object.recon') self.rcache = os.path.join(self.testdir, 'object.recon')
@ -118,7 +118,6 @@ class TestAuditor(unittest.TestCase):
def tearDown(self): def tearDown(self):
rmtree(os.path.dirname(self.testdir), ignore_errors=1) rmtree(os.path.dirname(self.testdir), ignore_errors=1)
unit.xattr_data = {}
def test_worker_conf_parms(self): def test_worker_conf_parms(self):
def check_common_defaults(): def check_common_defaults():

View File

@ -44,7 +44,8 @@ from swift.obj.diskfile import MD5_OF_EMPTY_STRING, update_auditor_status
from test.unit import (mock as unit_mock, temptree, mock_check_drive, from test.unit import (mock as unit_mock, temptree, mock_check_drive,
patch_policies, debug_logger, EMPTY_ETAG, patch_policies, debug_logger, EMPTY_ETAG,
make_timestamp_iter, DEFAULT_TEST_EC_TYPE, make_timestamp_iter, DEFAULT_TEST_EC_TYPE,
requires_o_tmpfile_support, encode_frag_archive_bodies) requires_o_tmpfile_support, encode_frag_archive_bodies,
skip_if_no_xattrs)
from nose import SkipTest from nose import SkipTest
from swift.obj import diskfile from swift.obj import diskfile
from swift.common import utils from swift.common import utils
@ -61,6 +62,7 @@ from swift.common.storage_policy import (
BaseStoragePolicy, REPL_POLICY, EC_POLICY) BaseStoragePolicy, REPL_POLICY, EC_POLICY)
from test.unit.obj.common import write_diskfile from test.unit.obj.common import write_diskfile
test_policies = [ test_policies = [
StoragePolicy(0, name='zero', is_default=True), StoragePolicy(0, name='zero', is_default=True),
ECStoragePolicy(1, name='one', is_default=False, ECStoragePolicy(1, name='one', is_default=False,
@ -145,6 +147,7 @@ def _make_metafilename(meta_timestamp, ctype_timestamp=None):
class TestDiskFileModuleMethods(unittest.TestCase): class TestDiskFileModuleMethods(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
utils.HASH_PATH_SUFFIX = 'endcap' utils.HASH_PATH_SUFFIX = 'endcap'
utils.HASH_PATH_PREFIX = '' utils.HASH_PATH_PREFIX = ''
# Setup a test ring per policy (stolen from common/test_ring.py) # Setup a test ring per policy (stolen from common/test_ring.py)
@ -682,6 +685,7 @@ class BaseDiskFileTestMixin(object):
mgr_cls = None mgr_cls = None
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.tmpdir = mkdtemp() self.tmpdir = mkdtemp()
self.testdir = os.path.join( self.testdir = os.path.join(
self.tmpdir, 'tmp_test_obj_server_DiskFile') self.tmpdir, 'tmp_test_obj_server_DiskFile')
@ -3526,6 +3530,13 @@ class DiskFileMixin(BaseDiskFileTestMixin):
wrong_byte = 'X' if meta_xattr[0] != 'X' else 'Y' wrong_byte = 'X' if meta_xattr[0] != 'X' else 'Y'
xattr.setxattr(data_files[0], "user.swift.metadata", xattr.setxattr(data_files[0], "user.swift.metadata",
wrong_byte + meta_xattr[1:]) wrong_byte + meta_xattr[1:])
elif invalid_type == 'Subtly-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_checksum = md5(meta_xattr + "some extra stuff").hexdigest()
xattr.setxattr(data_files[0], "user.swift.metadata_checksum",
wrong_checksum)
elif invalid_type == 'Truncated-Xattrs': elif invalid_type == 'Truncated-Xattrs':
meta_xattr = xattr.getxattr(data_files[0], "user.swift.metadata") meta_xattr = xattr.getxattr(data_files[0], "user.swift.metadata")
xattr.setxattr(data_files[0], "user.swift.metadata", xattr.setxattr(data_files[0], "user.swift.metadata",
@ -3684,6 +3695,11 @@ class DiskFileMixin(BaseDiskFileTestMixin):
def test_quarantine_corrupt_xattrs(self): def test_quarantine_corrupt_xattrs(self):
self.run_quarantine_invalids('Corrupt-Xattrs') self.run_quarantine_invalids('Corrupt-Xattrs')
def test_quarantine_subtly_corrupt_xattrs(self):
# xattrs that unpickle without error, but whose checksum does not
# match
self.run_quarantine_invalids('Subtly-Corrupt-Xattrs')
def test_quarantine_truncated_xattrs(self): def test_quarantine_truncated_xattrs(self):
self.run_quarantine_invalids('Truncated-Xattrs') self.run_quarantine_invalids('Truncated-Xattrs')
@ -3746,18 +3762,7 @@ class DiskFileMixin(BaseDiskFileTestMixin):
invalid_type='Bad-Content-Length') invalid_type='Bad-Content-Length')
def test_quarantine_fstat_oserror(self): def test_quarantine_fstat_oserror(self):
invocations = [0] with mock.patch('os.fstat', side_effect=OSError()):
orig_os_fstat = os.fstat
def bad_fstat(fd):
invocations[0] += 1
if invocations[0] == 4:
# FIXME - yes, this an icky way to get code coverage ... worth
# it?
raise OSError()
return orig_os_fstat(fd)
with mock.patch('os.fstat', bad_fstat):
self.assertRaises( self.assertRaises(
DiskFileQuarantined, DiskFileQuarantined,
self._get_open_disk_file) self._get_open_disk_file)
@ -5957,6 +5962,7 @@ class TestSuffixHashes(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.testdir = tempfile.mkdtemp() self.testdir = tempfile.mkdtemp()
self.logger = debug_logger('suffix-hash-test') self.logger = debug_logger('suffix-hash-test')
self.devices = os.path.join(self.testdir, 'node') self.devices = os.path.join(self.testdir, 'node')

View File

@ -45,7 +45,7 @@ from swift.obj.reconstructor import REVERT
from test.unit import (patch_policies, debug_logger, mocked_http_conn, from test.unit import (patch_policies, debug_logger, mocked_http_conn,
FabricatedRing, make_timestamp_iter, FabricatedRing, make_timestamp_iter,
DEFAULT_TEST_EC_TYPE, encode_frag_archive_bodies, DEFAULT_TEST_EC_TYPE, encode_frag_archive_bodies,
quiet_eventlet_exceptions) quiet_eventlet_exceptions, skip_if_no_xattrs)
from test.unit.obj.common import write_diskfile from test.unit.obj.common import write_diskfile
@ -149,6 +149,7 @@ class TestGlobalSetupObjectReconstructor(unittest.TestCase):
legacy_durable = False legacy_durable = False
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.testdir = tempfile.mkdtemp() self.testdir = tempfile.mkdtemp()
_create_test_rings(self.testdir) _create_test_rings(self.testdir)
POLICIES[0].object_ring = ring.Ring(self.testdir, ring_name='object') POLICIES[0].object_ring = ring.Ring(self.testdir, ring_name='object')
@ -2387,6 +2388,7 @@ class TestWorkerReconstructor(unittest.TestCase):
@patch_policies(with_ec_default=True) @patch_policies(with_ec_default=True)
class BaseTestObjectReconstructor(unittest.TestCase): class BaseTestObjectReconstructor(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.policy = POLICIES.default self.policy = POLICIES.default
self.policy.object_ring._rtime = time.time() + 3600 self.policy.object_ring._rtime = time.time() + 3600
self.testdir = tempfile.mkdtemp() self.testdir = tempfile.mkdtemp()

View File

@ -30,7 +30,8 @@ from eventlet.green import subprocess
from eventlet import Timeout from eventlet import Timeout
from test.unit import (debug_logger, patch_policies, make_timestamp_iter, from test.unit import (debug_logger, patch_policies, make_timestamp_iter,
mocked_http_conn, FakeLogger, mock_check_drive) mocked_http_conn, FakeLogger, mock_check_drive,
skip_if_no_xattrs)
from swift.common import utils from swift.common import utils
from swift.common.utils import (hash_path, mkdirs, normalize_timestamp, from swift.common.utils import (hash_path, mkdirs, normalize_timestamp,
storage_directory) storage_directory)
@ -179,6 +180,7 @@ def _create_test_rings(path, devs=None, next_part_power=None):
class TestObjectReplicator(unittest.TestCase): class TestObjectReplicator(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
utils.HASH_PATH_SUFFIX = 'endcap' utils.HASH_PATH_SUFFIX = 'endcap'
utils.HASH_PATH_PREFIX = '' utils.HASH_PATH_PREFIX = ''
# recon cache path # recon cache path

View File

@ -45,9 +45,9 @@ from swift import __version__ as swift_version
from swift.common.http import is_success from swift.common.http import is_success
from test import listen_zero from test import listen_zero
from test.unit import FakeLogger, debug_logger, mocked_http_conn, \ from test.unit import FakeLogger, debug_logger, mocked_http_conn, \
make_timestamp_iter, DEFAULT_TEST_EC_TYPE, mock_check_drive make_timestamp_iter, DEFAULT_TEST_EC_TYPE, skip_if_no_xattrs, \
from test.unit import connect_tcp, readuntil2crlfs, patch_policies, \ connect_tcp, readuntil2crlfs, patch_policies, encode_frag_archive_bodies, \
encode_frag_archive_bodies mock_check_drive
from swift.obj import server as object_server from swift.obj import server as object_server
from swift.obj import updater from swift.obj import updater
from swift.obj import diskfile from swift.obj import diskfile
@ -140,6 +140,7 @@ class TestObjectController(unittest.TestCase):
def setUp(self): def setUp(self):
"""Set up for testing swift.object.server.ObjectController""" """Set up for testing swift.object.server.ObjectController"""
skip_if_no_xattrs()
utils.HASH_PATH_SUFFIX = 'endcap' utils.HASH_PATH_SUFFIX = 'endcap'
utils.HASH_PATH_PREFIX = 'startcap' utils.HASH_PATH_PREFIX = 'startcap'
self.tmpdir = mkdtemp() self.tmpdir = mkdtemp()
@ -6942,6 +6943,7 @@ class TestObjectController(unittest.TestCase):
class TestObjectServer(unittest.TestCase): class TestObjectServer(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
# dirs # dirs
self.tmpdir = mkdtemp() self.tmpdir = mkdtemp()
self.tempdir = os.path.join(self.tmpdir, 'tmp_test_obj_server') self.tempdir = os.path.join(self.tmpdir, 'tmp_test_obj_server')
@ -7632,6 +7634,7 @@ class TestZeroCopy(unittest.TestCase):
return True return True
def setUp(self): def setUp(self):
skip_if_no_xattrs()
if not self._system_can_zero_copy(): if not self._system_can_zero_copy():
raise SkipTest("zero-copy support is missing") raise SkipTest("zero-copy support is missing")

View File

@ -34,8 +34,9 @@ from swift.obj.reconstructor import RebuildingECDiskFileStream, \
from swift.obj.replicator import ObjectReplicator from swift.obj.replicator import ObjectReplicator
from test import listen_zero from test import listen_zero
from test.unit import patch_policies, debug_logger, encode_frag_archive_bodies
from test.unit.obj.common import BaseTest from test.unit.obj.common import BaseTest
from test.unit import patch_policies, debug_logger, \
encode_frag_archive_bodies, skip_if_no_xattrs
class TestBaseSsync(BaseTest): class TestBaseSsync(BaseTest):
@ -47,6 +48,7 @@ class TestBaseSsync(BaseTest):
about the final state of the sender and receiver diskfiles. about the final state of the sender and receiver diskfiles.
""" """
def setUp(self): def setUp(self):
skip_if_no_xattrs()
super(TestBaseSsync, self).setUp() super(TestBaseSsync, self).setUp()
# rx side setup # rx side setup
self.rx_testdir = os.path.join(self.tmpdir, 'tmp_test_ssync_receiver') self.rx_testdir = os.path.join(self.tmpdir, 'tmp_test_ssync_receiver')

View File

@ -35,7 +35,7 @@ from swift.obj.reconstructor import ObjectReconstructor
from test import listen_zero, unit from test import listen_zero, unit
from test.unit import (debug_logger, patch_policies, make_timestamp_iter, from test.unit import (debug_logger, patch_policies, make_timestamp_iter,
mock_check_drive) mock_check_drive, skip_if_no_xattrs)
from test.unit.obj.common import write_diskfile from test.unit.obj.common import write_diskfile
@ -43,12 +43,11 @@ from test.unit.obj.common import write_diskfile
class TestReceiver(unittest.TestCase): class TestReceiver(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
utils.HASH_PATH_SUFFIX = 'endcap' utils.HASH_PATH_SUFFIX = 'endcap'
utils.HASH_PATH_PREFIX = 'startcap' utils.HASH_PATH_PREFIX = 'startcap'
# Not sure why the test.unit stuff isn't taking effect here; so I'm # Not sure why the test.unit stuff isn't taking effect here; so I'm
# reinforcing it. # reinforcing it.
diskfile.getxattr = unit._getxattr
diskfile.setxattr = unit._setxattr
self.testdir = os.path.join( self.testdir = os.path.join(
tempfile.mkdtemp(), 'tmp_test_ssync_receiver') tempfile.mkdtemp(), 'tmp_test_ssync_receiver')
utils.mkdirs(os.path.join(self.testdir, 'sda1', 'tmp')) utils.mkdirs(os.path.join(self.testdir, 'sda1', 'tmp'))
@ -1963,6 +1962,7 @@ class TestSsyncRxServer(unittest.TestCase):
# server socket. # server socket.
def setUp(self): def setUp(self):
skip_if_no_xattrs()
# dirs # dirs
self.tmpdir = tempfile.mkdtemp() self.tmpdir = tempfile.mkdtemp()
self.tempdir = os.path.join(self.tmpdir, 'tmp_test_obj_server') self.tempdir = os.path.join(self.tmpdir, 'tmp_test_obj_server')

View File

@ -26,8 +26,9 @@ from swift.common.utils import Timestamp
from swift.obj import ssync_sender, diskfile, ssync_receiver from swift.obj import ssync_sender, diskfile, ssync_receiver
from swift.obj.replicator import ObjectReplicator from swift.obj.replicator import ObjectReplicator
from test.unit import patch_policies, make_timestamp_iter, debug_logger
from test.unit.obj.common import BaseTest from test.unit.obj.common import BaseTest
from test.unit import patch_policies, make_timestamp_iter, skip_if_no_xattrs, \
debug_logger
class NullBufferedHTTPConnection(object): class NullBufferedHTTPConnection(object):
@ -84,6 +85,7 @@ class FakeConnection(object):
class TestSender(BaseTest): class TestSender(BaseTest):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
super(TestSender, self).setUp() super(TestSender, self).setUp()
self.daemon = ObjectReplicator(self.daemon_conf, self.daemon = ObjectReplicator(self.daemon_conf,
debug_logger('test-ssync-sender')) debug_logger('test-ssync-sender'))

View File

@ -53,7 +53,8 @@ from test import listen_zero
from test.unit import ( from test.unit import (
connect_tcp, readuntil2crlfs, FakeLogger, fake_http_connect, FakeRing, connect_tcp, readuntil2crlfs, FakeLogger, fake_http_connect, FakeRing,
FakeMemcache, debug_logger, patch_policies, write_fake_ring, FakeMemcache, debug_logger, patch_policies, write_fake_ring,
mocked_http_conn, DEFAULT_TEST_EC_TYPE, make_timestamp_iter) mocked_http_conn, DEFAULT_TEST_EC_TYPE, make_timestamp_iter,
skip_if_no_xattrs)
from test.unit.helpers import setup_servers, teardown_servers from test.unit.helpers import setup_servers, teardown_servers
from swift.proxy import server as proxy_server from swift.proxy import server as proxy_server
from swift.proxy.controllers.obj import ReplicatedObjectController from swift.proxy.controllers.obj import ReplicatedObjectController
@ -237,6 +238,7 @@ def _limit_max_file_size(f):
class TestController(unittest.TestCase): class TestController(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.account_ring = FakeRing() self.account_ring = FakeRing()
self.container_ring = FakeRing() self.container_ring = FakeRing()
self.memcache = FakeMemcache() self.memcache = FakeMemcache()
@ -1288,6 +1290,7 @@ class TestProxyServerLoading(unittest.TestCase):
class TestProxyServerConfigLoading(unittest.TestCase): class TestProxyServerConfigLoading(unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.tempdir = mkdtemp() self.tempdir = mkdtemp()
account_ring_path = os.path.join(self.tempdir, 'account.ring.gz') account_ring_path = os.path.join(self.tempdir, 'account.ring.gz')
write_fake_ring(account_ring_path) write_fake_ring(account_ring_path)
@ -1987,6 +1990,7 @@ class TestReplicatedObjectController(
Test suite for replication policy Test suite for replication policy
""" """
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.app = proxy_server.Application( self.app = proxy_server.Application(
None, FakeMemcache(), None, FakeMemcache(),
logger=debug_logger('proxy-ut'), logger=debug_logger('proxy-ut'),
@ -6383,6 +6387,7 @@ class BaseTestECObjectController(BaseTestObjectController):
class TestECObjectController(BaseTestECObjectController, unittest.TestCase): class TestECObjectController(BaseTestECObjectController, unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.ec_policy = POLICIES[3] self.ec_policy = POLICIES[3]
super(TestECObjectController, self).setUp() super(TestECObjectController, self).setUp()
@ -6390,11 +6395,15 @@ class TestECObjectController(BaseTestECObjectController, unittest.TestCase):
class TestECDuplicationObjectController( class TestECDuplicationObjectController(
BaseTestECObjectController, unittest.TestCase): BaseTestECObjectController, unittest.TestCase):
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.ec_policy = POLICIES[4] self.ec_policy = POLICIES[4]
super(TestECDuplicationObjectController, self).setUp() super(TestECDuplicationObjectController, self).setUp()
class TestECMismatchedFA(unittest.TestCase): class TestECMismatchedFA(unittest.TestCase):
def setUp(self):
skip_if_no_xattrs()
def tearDown(self): def tearDown(self):
prosrv = _test_servers[0] prosrv = _test_servers[0]
# don't leak error limits and poison other tests # don't leak error limits and poison other tests
@ -6581,6 +6590,7 @@ class TestECMismatchedFA(unittest.TestCase):
class TestECGets(unittest.TestCase): class TestECGets(unittest.TestCase):
def setUp(self): def setUp(self):
super(TestECGets, self).setUp() super(TestECGets, self).setUp()
skip_if_no_xattrs()
self.tempdir = mkdtemp() self.tempdir = mkdtemp()
def tearDown(self): def tearDown(self):
@ -6852,6 +6862,7 @@ class TestObjectDisconnectCleanup(unittest.TestCase):
mkdirs(data_path) mkdirs(data_path)
def setUp(self): def setUp(self):
skip_if_no_xattrs()
debug.hub_exceptions(False) debug.hub_exceptions(False)
self._cleanup_devices() self._cleanup_devices()
@ -6960,6 +6971,7 @@ class TestObjectECRangedGET(unittest.TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
skip_if_no_xattrs()
cls.obj_name = 'range-get-test' cls.obj_name = 'range-get-test'
cls.tiny_obj_name = 'range-get-test-tiny' cls.tiny_obj_name = 'range-get-test-tiny'
cls.aligned_obj_name = 'range-get-test-aligned' cls.aligned_obj_name = 'range-get-test-aligned'
@ -9488,6 +9500,7 @@ class TestProxyObjectPerformance(unittest.TestCase):
# This is just a simple test that can be used to verify and debug the # This is just a simple test that can be used to verify and debug the
# various data paths between the proxy server and the object # various data paths between the proxy server and the object
# server. Used as a play ground to debug buffer sizes for sockets. # server. Used as a play ground to debug buffer sizes for sockets.
skip_if_no_xattrs()
prolis = _test_sockets[0] prolis = _test_sockets[0]
sock = connect_tcp(('localhost', prolis.getsockname()[1])) sock = connect_tcp(('localhost', prolis.getsockname()[1]))
# Client is transmitting in 2 MB chunks # Client is transmitting in 2 MB chunks
@ -9601,6 +9614,7 @@ class TestSocketObjectVersions(unittest.TestCase):
def setUp(self): def setUp(self):
global _test_sockets global _test_sockets
skip_if_no_xattrs()
self.prolis = prolis = listen_zero() self.prolis = prolis = listen_zero()
self._orig_prolis = _test_sockets[0] self._orig_prolis = _test_sockets[0]
allowed_headers = ', '.join([ allowed_headers = ', '.join([

View File

@ -30,7 +30,7 @@ from swift.proxy import server as proxy
import swift.proxy.controllers import swift.proxy.controllers
from swift.proxy.controllers.base import get_object_info from swift.proxy.controllers.base import get_object_info
from test.unit import FakeMemcache, debug_logger, FakeRing, \ from test.unit import FakeMemcache, debug_logger, FakeRing, \
fake_http_connect, patch_policies fake_http_connect, patch_policies, skip_if_no_xattrs
class FakeServerConnection(WSGIContext): class FakeServerConnection(WSGIContext):
@ -132,6 +132,7 @@ class TestObjectSysmeta(unittest.TestCase):
% (key, resp.headers)) % (key, resp.headers))
def setUp(self): def setUp(self):
skip_if_no_xattrs()
self.app = proxy.Application(None, FakeMemcache(), self.app = proxy.Application(None, FakeMemcache(),
logger=debug_logger('proxy-ut'), logger=debug_logger('proxy-ut'),
account_ring=FakeRing(replicas=1), account_ring=FakeRing(replicas=1),