Gluster to handle ENOSPC (Error 28) correctly
A gluster volume could yield an ENOSPC condition seeing that a volume is full. This needed to handled correctly. Added error handling. BUG: 985253 https://bugzilla.redhat.com/show_bug.cgi?id=985253 Change-Id: I85472c0a81a354a2796327fead606da3a938d4bf Signed-off-by: Chetan Risbud <crisbud@redhat.com> Reviewed-on: http://review.gluster.org/5362 Reviewed-by: Peter Portante <pportant@redhat.com> Reviewed-by: Luis Pabon <lpabon@redhat.com> Tested-by: Luis Pabon <lpabon@redhat.com>
This commit is contained in:
parent
e367372f8b
commit
027951c102
@ -24,7 +24,9 @@ from eventlet import sleep
|
||||
from contextlib import contextmanager
|
||||
from swift.common.utils import TRUE_VALUES, fallocate
|
||||
from swift.common.exceptions import DiskFileNotExist, DiskFileError
|
||||
from gluster.swift.common.exceptions import GlusterFileSystemOSError
|
||||
|
||||
from gluster.swift.common.exceptions import GlusterFileSystemOSError, \
|
||||
DiskFileNoSpace
|
||||
from gluster.swift.common.fs_utils import do_fstat, do_open, do_close, \
|
||||
do_unlink, do_chown, os_path, do_fsync, do_fchown, do_stat
|
||||
from gluster.swift.common.utils import read_metadata, write_metadata, \
|
||||
@ -702,6 +704,11 @@ class Gluster_DiskFile(DiskFile):
|
||||
fd = do_open(tmppath,
|
||||
os.O_WRONLY | os.O_CREAT | os.O_EXCL | O_CLOEXEC)
|
||||
except GlusterFileSystemOSError as gerr:
|
||||
if gerr.errno == errno.ENOSPC:
|
||||
# Raise DiskFileNoSpace to be handled by upper layers
|
||||
excp = DiskFileNoSpace()
|
||||
excp.drive = os.path.basename(self.device_path)
|
||||
raise excp
|
||||
if gerr.errno == errno.EEXIST:
|
||||
# Retry with a different random number.
|
||||
continue
|
||||
|
@ -44,3 +44,7 @@ class AlreadyExistsAsDir(GlusterfsException):
|
||||
|
||||
class AlreadyExistsAsFile(GlusterfsException):
|
||||
pass
|
||||
|
||||
|
||||
class DiskFileNoSpace(GlusterfsException):
|
||||
pass
|
||||
|
@ -17,11 +17,13 @@
|
||||
|
||||
# Simply importing this monkey patches the constraint handling to fit our
|
||||
# needs
|
||||
import gluster.swift.common.constraints # noqa
|
||||
import gluster.swift.common.utils # noqa
|
||||
|
||||
from swift.obj import server
|
||||
import gluster.swift.common.utils # noqa
|
||||
import gluster.swift.common.constraints # noqa
|
||||
from swift.common.utils import public, timing_stats
|
||||
from gluster.swift.common.DiskFile import Gluster_DiskFile
|
||||
from gluster.swift.common.exceptions import DiskFileNoSpace
|
||||
from swift.common.swob import HTTPInsufficientStorage
|
||||
|
||||
# Monkey patch the object server module to use Gluster's DiskFile definition
|
||||
server.DiskFile = Gluster_DiskFile
|
||||
@ -54,6 +56,15 @@ class ObjectController(server.ObjectController):
|
||||
"""
|
||||
return
|
||||
|
||||
@public
|
||||
@timing_stats()
|
||||
def PUT(self, request):
|
||||
try:
|
||||
return server.ObjectController.PUT(self, request)
|
||||
except DiskFileNoSpace as err:
|
||||
drive = err.drive
|
||||
return HTTPInsufficientStorage(drive=drive, request=request)
|
||||
|
||||
|
||||
def app_factory(global_conf, **local_conf):
|
||||
"""paste.deploy app factory for creating WSGI object server apps"""
|
||||
|
@ -21,18 +21,21 @@ import errno
|
||||
import unittest
|
||||
import tempfile
|
||||
import shutil
|
||||
import mock
|
||||
from mock import patch
|
||||
from hashlib import md5
|
||||
from swift.common.utils import normalize_timestamp
|
||||
from swift.common.exceptions import DiskFileNotExist, DiskFileError
|
||||
import gluster.swift.common.DiskFile
|
||||
|
||||
import gluster.swift.common.utils
|
||||
import gluster.swift.common.DiskFile
|
||||
from swift.common.utils import normalize_timestamp
|
||||
from gluster.swift.common.DiskFile import Gluster_DiskFile
|
||||
from swift.common.exceptions import DiskFileNotExist, DiskFileError
|
||||
from gluster.swift.common.utils import DEFAULT_UID, DEFAULT_GID, X_TYPE, \
|
||||
X_OBJECT_TYPE, DIR_OBJECT
|
||||
from test_utils import _initxattr, _destroyxattr
|
||||
from test.unit import FakeLogger
|
||||
|
||||
from gluster.swift.common.exceptions import *
|
||||
|
||||
_metadata = {}
|
||||
|
||||
@ -569,6 +572,45 @@ class TestDiskFile(unittest.TestCase):
|
||||
finally:
|
||||
shutil.rmtree(td)
|
||||
|
||||
|
||||
def test_put_ENOSPC(self):
|
||||
td = tempfile.mkdtemp()
|
||||
the_cont = os.path.join(td, "vol0", "bar")
|
||||
try:
|
||||
os.makedirs(the_cont)
|
||||
gdf = Gluster_DiskFile(td, "vol0", "p57", "ufo47", "bar",
|
||||
"z", self.lg)
|
||||
assert gdf._obj == "z"
|
||||
assert gdf._obj_path == ""
|
||||
assert gdf.name == "bar"
|
||||
assert gdf.datadir == the_cont
|
||||
assert gdf.data_file is None
|
||||
|
||||
body = '1234\n'
|
||||
etag = md5()
|
||||
etag.update(body)
|
||||
etag = etag.hexdigest()
|
||||
metadata = {
|
||||
'X-Timestamp': '1234',
|
||||
'Content-Type': 'file',
|
||||
'ETag': etag,
|
||||
'Content-Length': '5',
|
||||
}
|
||||
def mock_open(*args, **kwargs):
|
||||
raise OSError(errno.ENOSPC, os.strerror(errno.ENOSPC))
|
||||
|
||||
with mock.patch("os.open", mock_open):
|
||||
try:
|
||||
with gdf.mkstemp() as fd:
|
||||
assert gdf.tmppath is not None
|
||||
tmppath = gdf.tmppath
|
||||
os.write(fd, body)
|
||||
gdf.put(fd, metadata)
|
||||
except DiskFileNoSpace:
|
||||
pass
|
||||
finally:
|
||||
shutil.rmtree(td)
|
||||
|
||||
def test_put_obj_path(self):
|
||||
the_obj_path = os.path.join("b", "a")
|
||||
the_file = os.path.join(the_obj_path, "z")
|
||||
|
Loading…
x
Reference in New Issue
Block a user