diff --git a/gluster/swift/container/server.py b/gluster/swift/container/server.py index ee284c9..36632a6 100644 --- a/gluster/swift/container/server.py +++ b/gluster/swift/container/server.py @@ -24,6 +24,15 @@ from gluster.swift.common.DiskDir import DiskDir class ContainerController(server.ContainerController): + """ + Subclass of the container server's ContainerController which replaces the + _get_container_broker() method so that we can use Gluster's DiskDir + duck-type of the container DatabaseBroker object, and make the + account_update() method a no-op (information is simply stored on disk and + already updated by virtue of performaing the file system operations + directly). + """ + def _get_container_broker(self, drive, part, account, container): """ Overriden to provide the GlusterFS specific broker that talks to @@ -34,10 +43,25 @@ class ContainerController(server.ContainerController): :param part: partition the container is in :param account: account name :param container: container name - :returns: DiskDir object + :returns: DiskDir object, a duck-type of DatabaseBroker """ return DiskDir(self.root, drive, account, container, self.logger) + def account_update(self, req, account, container, broker): + """ + Update the account server(s) with latest container info. + + For Gluster, this is just a no-op, since an account is just the + directory holding all the container directories. + + :param req: swob.Request object + :param account: account name + :param container: container name + :param broker: container DB broker object + :returns: None. + """ + return None + def app_factory(global_conf, **local_conf): """paste.deploy app factory for creating WSGI container server apps.""" diff --git a/gluster/swift/obj/server.py b/gluster/swift/obj/server.py index 1223036..084346a 100644 --- a/gluster/swift/obj/server.py +++ b/gluster/swift/obj/server.py @@ -27,8 +27,36 @@ from gluster.swift.common.DiskFile import Gluster_DiskFile server.DiskFile = Gluster_DiskFile +class ObjectController(server.ObjectController): + """ + Subclass of the object server's ObjectController which replaces the + container_update method with one that is a no-op (information is simply + stored on disk and already updated by virtue of performing the file system + operations directly). + """ + + def container_update(self, op, account, container, obj, request, + headers_out, objdevice): + """ + Update the container when objects are updated. + + For Gluster, this is just a no-op, since a container is just the + directory holding all the objects (sub-directory hierarchy of files). + + :param op: operation performed (ex: 'PUT', or 'DELETE') + :param account: account name for the object + :param container: container name for the object + :param obj: object name + :param request: the original request object driving the update + :param headers_out: dictionary of headers to send in the container + request(s) + :param objdevice: device name that the object is in + """ + return + + def app_factory(global_conf, **local_conf): """paste.deploy app factory for creating WSGI object server apps""" conf = global_conf.copy() conf.update(local_conf) - return server.ObjectController(conf) + return ObjectController(conf) diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py index 4e288d6..a04380d 100644 --- a/test/unit/proxy/test_server.py +++ b/test/unit/proxy/test_server.py @@ -40,7 +40,7 @@ gfs.RUN_DIR = mkdtemp() from test.unit import connect_tcp, readuntil2crlfs, FakeLogger, fake_http_connect from gluster.swift.proxy.server import server as proxy_server -from gluster.swift.obj.server import server as object_server +from gluster.swift.obj import server as object_server from gluster.swift.account import server as account_server from gluster.swift.container import server as container_server from swift.common import ring @@ -2782,6 +2782,53 @@ class TestObjectController(unittest.TestCase): body = fd.read() self.assertEquals(body, 'oh hai123456789abcdef') + def test_put_put(self): + (prolis, acc1lis, acc2lis, con1lis, con2lis, obj1lis, + obj2lis) = _test_sockets + sock = connect_tcp(('localhost', prolis.getsockname()[1])) + fd = sock.makefile() + fd.write('PUT /v1/a/c/o/putput HTTP/1.1\r\nHost: localhost\r\n' + 'Connection: close\r\nX-Auth-Token: t\r\n' + 'Content-Length:27\r\n\r\n' + 'abcdefghijklmnopqrstuvwxyz\n\r\n\r\n') + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 201' + self.assertEquals(headers[:len(exp)], exp) + # Ensure we get what we put + sock = connect_tcp(('localhost', prolis.getsockname()[1])) + fd = sock.makefile() + fd.write('GET /v1/a/c/o/putput HTTP/1.1\r\nHost: localhost\r\n' + 'Connection: close\r\nX-Auth-Token: t\r\n\r\n') + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 200' + self.assertEquals(headers[:len(exp)], exp) + body = fd.read() + self.assertEquals(body, 'abcdefghijklmnopqrstuvwxyz\n') + + sock = connect_tcp(('localhost', prolis.getsockname()[1])) + fd = sock.makefile() + fd.write('PUT /v1/a/c/o/putput HTTP/1.1\r\nHost: localhost\r\n' + 'Connection: close\r\nX-Auth-Token: t\r\n' + 'Content-Length:27\r\n\r\n' + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n\r\n\r\n') + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 201' + self.assertEquals(headers[:len(exp)], exp) + # Ensure we get what we put + sock = connect_tcp(('localhost', prolis.getsockname()[1])) + fd = sock.makefile() + fd.write('GET /v1/a/c/o/putput HTTP/1.1\r\nHost: localhost\r\n' + 'Connection: close\r\nX-Auth-Token: t\r\n\r\n') + fd.flush() + headers = readuntil2crlfs(fd) + exp = 'HTTP/1.1 200' + self.assertEquals(headers[:len(exp)], exp) + body = fd.read() + self.assertEquals(body, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n') + def test_version_manifest(self): raise SkipTest("Not until we support versioned objects") versions_to_create = 3