коллективный.xsendfile, большие двоичные объекты ZODB и права доступа к файлам UNIX

#blob #plone #zope #zodb #x-sendfile

#большой двоичный объект #plone #zope #zodb #x-sendfile

Вопрос:

В настоящее время я пытаюсь настроить коллективный.xsendfile, Apache mod_xsendfile и Plone 4.

По-видимому, процесс Apache не видит файлы blobstrage в файловой системе, поскольку они содержат разрешения:

ls -lh var/blobstorage/0x00/0x00/0x00/0x00/0x18/0xd5/0x19/0x038ea09d0eddc611.blob -r——— 1 plone plone 1006K 28 мая 15:30 var/blobstorage/0x00/0x00/0x00/0x00/0x18/0xd5/0x19/0x038ea09d0eddc611.blob

Как мне настроить blobstorage для предоставления дополнительных разрешений, чтобы Apache мог получить доступ к этим файлам?

Ответ №1:

Режимы, с помощью которых blobstorage записывает свои каталоги и файлы, жестко запрограммированы в ZODB.blob . В частности, стандартный ZODB.blob.FileSystemHelper класс создает защищенные каталоги (доступные для чтения и записи только для текущего пользователя) по умолчанию.

Вы могли бы предоставить свою собственную реализацию FileSystemHelper , которая либо сделала бы это настраиваемым, либо просто установила бы режимы каталога на 0750 , а затем исправила ZODB.blob.BlobStorageMixin , чтобы использовать ваш класс вместо класса по умолчанию:

 import os
from ZODB import utils
from ZODB.blob import FilesystemHelper, BlobStorageMixin
from ZODB.blob import log, LAYOUT_MARKER

class GroupReadableFilesystemHelper(FilesystemHelper):
    def create(self):
        if not os.path.exists(self.base_dir):
            os.makedirs(self.base_dir, 0750)
            log("Blob directory '%s' does not exist. "
                "Created new directory." % self.base_dir)
        if not os.path.exists(self.temp_dir):
            os.makedirs(self.temp_dir, 0750)
            log("Blob temporary directory '%s' does not exist. "
                "Created new directory." % self.temp_dir)

        if not os.path.exists(os.path.join(self.base_dir, LAYOUT_MARKER)):
            layout_marker = open(
                os.path.join(self.base_dir, LAYOUT_MARKER), 'wb')
            layout_marker.write(self.layout_name)
        else:
            layout = open(os.path.join(self.base_dir, LAYOUT_MARKER), 'rb'
                          ).read().strip()
            if layout != self.layout_name:
                raise ValueError(
                    "Directory layout `%s` selected for blob directory %s, but "
                    "marker found for layout `%s`" %
                    (self.layout_name, self.base_dir, layout))

    def isSecure(self, path):
        """Ensure that (POSIX) path mode bits are 0750."""
        return (os.stat(path).st_mode amp; 027) == 0

    def getPathForOID(self, oid, create=False):
        """Given an OID, return the path on the filesystem where
        the blob data relating to that OID is stored.

        If the create flag is given, the path is also created if it didn't
        exist already.

        """
        # OIDs are numbers and sometimes passed around as integers. For our
        # computations we rely on the 64-bit packed string representation.
        if isinstance(oid, int):
            oid = utils.p64(oid)

        path = self.layout.oid_to_path(oid)
        path = os.path.join(self.base_dir, path)

        if create and not os.path.exists(path):
            try:
                os.makedirs(path, 0750)
            except OSError:
                # We might have lost a race.  If so, the directory
                # must exist now
                assert os.path.exists(path)
        return path


def _blob_init_groupread(self, blob_dir, layout='automatic'):
    self.fshelper = GroupReadableFilesystemHelper(blob_dir, layout)
    self.fshelper.create()
    self.fshelper.checkSecure()
    self.dirty_oids = []

BlobStorageMixin._blob_init = _blob_init_groupread
  

Возможно, вы захотите сделать это запросом функции для ZODB3 🙂

Комментарии:

1. При настройке ZEO я должен исправить ZEO server, верно? Провел некоторое тестирование с сервером и клиентом и похоже, что monkey-patch на стороне клиента не был запущен (попытался загрузить файл, и ничего не произошло).

2. @Mikko: При настройке ZEO вы действительно хотите исправить как сервер ZEO, так и клиентов. Предположительно, вы shared-blob-dir установили значение True, и в этом случае и клиенты, и сервер будут работать с каталогом данных больших двоичных объектов. В любом случае, вы можете сначала протестировать это на автономной установке. Кроме того, для существующей структуры datadir больших двоичных объектов необходимо обновить права доступа (chmod -R g r), поскольку этот патч не изменит существующие каталоги, только вновь созданные каталоги.

3. Спасибо Martjin. Вот незавершенная работа: github.com/miohtama/collective.xsendfile

4. @Mikko: Я хотел бы увидеть тесты, чтобы показать, что X-SendFile действительно будет быстрее. Я несколько скептически настроен, поскольку обслуживание файла больших двоичных объектов очень, очень эффективно в Zope. Исходный поток запроса закрыт, и потоковая передача файлов полностью обрабатывается базовой реализацией асинхронного опроса, Zope / Plone больше ничего не нужно делать, как только файл большого двоичного объекта найден. Apache и nginx будут делать то же самое.

5. @Mikko: в трекере ZODB уже есть открытая заявка на это: ошибки. launchpad.net/zodb/ bug/683751

Ответ №2:

При настройке процедуры резервного копирования для установки ZOPE / ZEO я столкнулся с той же проблемой с разрешениями для больших двоичных объектов.

После попытки применить патч monkey, который написал Микко (что не так просто), я придумал «настоящий» патч для решения проблемы.

Исправление, предложенное Martijn, не завершено, оно по-прежнему не устанавливает правильный режим для файлов больших двоичных объектов.

Итак, вот мое решение:

1.) Создайте патч, содержащий:

 Index: ZODB/blob.py
===================================================================
--- ZODB/blob.py    (Revision 121959)
    ZODB/blob.py    (Arbeitskopie)
@@ -337,11  337,11 @@

     def create(self):
         if not os.path.exists(self.base_dir):
-            os.makedirs(self.base_dir, 0700)
             os.makedirs(self.base_dir, 0750)
             log("Blob directory '%s' does not exist. "
                 "Created new directory." % self.base_dir)
         if not os.path.exists(self.temp_dir):
-            os.makedirs(self.temp_dir, 0700)
             os.makedirs(self.temp_dir, 0750)
             log("Blob temporary directory '%s' does not exist. "
                 "Created new directory." % self.temp_dir)

@@ -359,8  359,8 @@
                     (self.layout_name, self.base_dir, layout))

     def isSecure(self, path):
-        """Ensure that (POSIX) path mode bits are 0700."""
-        return (os.stat(path).st_mode amp; 077) == 0
         """Ensure that (POSIX) path mode bits are 0750."""
         return (os.stat(path).st_mode amp; 027) == 0

     def checkSecure(self):
         if not self.isSecure(self.base_dir):
@@ -385,7  385,7 @@

         if create and not os.path.exists(path):
             try:
-                os.makedirs(path, 0700)
                 os.makedirs(path, 0750)
             except OSError:
                 # We might have lost a race.  If so, the directory
                 # must exist now
@@ -891,7  891,7 @@
             file2.close()
         remove_committed(f1)
     if chmod:
-        os.chmod(f2, stat.S_IREAD)
         os.chmod(f2, stat.S_IRUSR | stat.S_IRGRP)

 if sys.platform == 'win32':
     # On Windows, you can't remove read-only files, so make the
  

Вы также можете взглянуть на исправление здесь -> http://pastebin.com/wNLYyXvw

2.) Сохраните исправление под именем ‘blob.patch’ в корневом каталоге вашей сборки

3.) Расширьте конфигурацию сборки:

 parts  = 
    patchblob
    postinstall

[patchblob]
recipe = collective.recipe.patch
egg = ZODB3
patches = blob.patch

[postinstall]
recipe = plone.recipe.command
command = 
    chmod -R g r ${buildout:directory}/var
    find ${buildout:directory}/var -type d | xargs chmod g x
update-command = ${:command}
  

Разделы после установки устанавливают желаемые групповые разрешения на чтение для уже существующих больших двоичных объектов. Обратите внимание, что также разрешение на выполнение должно быть предоставлено папкам больших двоичных объектов, эта группа может входить в каталоги.

Я протестировал этот патч с ZODB 3.10.2 и 3.10.3.

Как предположил Мартиджн, это должно быть настраиваемым и входить непосредственно в ZODB.

Комментарии:

1. Вы действительно не хотите делать прямое исправление для egg. Вместо этого используйте monkeypatch.