Haikson

[ Everything is possible. Everything takes time. ]

Chown в python и django

Привет всем интересующимся. В этой небольшой статье расскажу как менять владельца файла в linux скриптом на python. Сразу предупреждаю, что предисловие будет долгим, но познавательным. А код коротким, но, тоже, познавательным.

Недавно я столкнулся с идиотской ситуацией на сервере заказчика:

  1. Администратор сервера создал директорию /www/sitename.ru и пользователя sitename с правами чтения записи только в этой директории. Это разумно. Это безопасно и респектабельно.
  2. Администрирует он сервер удаленно и, как и полагается, считает себя "самым умным" ( я с ним лично не общался, т.к. контакт через четвертое лицо ). Прям зачат был исходным кодом ядра Линукса.
  3. nginx и uwsgi работают от nobody. Вот тут проблема, т.к. проект ( django ) пишет огромное количество файлов данных ( можно было бы хранить все в NoSQL базах, но - это медленнее, - это несет накладные расходы, - никто не собирается устанавливать mongo на сервер ).
  4. Эти файлы, соответственно, принадлежат nobody. Из этого следует, что после тестирования по SSH / FTP ни удалить файлы, ни перенести.
  5. На сервере настроен планировщик ( cron ), запускающий раз в N минут скрипт генератора. Генератор, соответственно создает файлы, которые пишутся от пользователя sitename.
  6. Все это периодически необходимо проверять на актуальность и вычищать

Что мы имеем?

  1. Файлы пользователя nobody, которые я могу удалять только запустив процесс из web интерфейса.
  2. Файлы пользователя sitename, которые я могу удалять только под SSH etc.
  3. Огромное желание сделать один раз и забыть.

План действий: написать скрипт, который через web будет переназначать пользователя ( CHOWN ). Удалять из под консоли, т.к. там по крону запускается скрипт, проверяющий файлы на актуальность и удаляющий их. Дальше код.

  1. Напишем функцию _chown, которая меняет владельца:
    def _chown(path, uid, gid):
        os.chown(path, uid, gid)
        for item in os.listdir(path):
            itempath = os.path.join(path, item)
            if os.path.isfile(itempath):
                try:
                    os.chown(itempath, uid, gid)
                except:
                    pass
            elif os.path.isdir(itempath):
                try:
                    os.chown(itempath, uid, gid)
                except:
                    pass
                _chown(itempath, uid, gid)
    здесь мы рекурсивно пытаемся назначать пользователя файлам. естественно, если не получается, то пропускаем.
  2. Ну и для django делаем следующее:
    def chown(request):
        if request.user.is_staff():
            path = settings.MEDIA_ROOT
            uid = "user_name"
            gid = "group_name"
            _chown(path, uid, gid)
        return redirect("/")
    здесь же мы указываем где искать и какому пользователю передать власть над файлами. Но для начала проверяем, не левый ли чувак пытается проделать "ЭТО" с нами?
    request.user.is_staff()

Вот и все.