Привет всем интересующимся. В этой небольшой статье расскажу как менять владельца файла в linux скриптом на python. Сразу предупреждаю, что предисловие будет долгим, но познавательным. А код коротким, но, тоже, познавательным.
Недавно я столкнулся с идиотской ситуацией на сервере заказчика:
- Администратор сервера создал директорию /www/sitename.ru и пользователя sitename с правами чтения записи только в этой директории. Это разумно. Это безопасно и респектабельно.
- Администрирует он сервер удаленно и, как и полагается, считает себя "самым умным" ( я с ним лично не общался, т.к. контакт через четвертое лицо ). Прям зачат был исходным кодом ядра Линукса.
- nginx и uwsgi работают от nobody. Вот тут проблема, т.к. проект ( django ) пишет огромное количество файлов данных ( можно было бы хранить все в NoSQL базах, но - это медленнее, - это несет накладные расходы, - никто не собирается устанавливать mongo на сервер ).
- Эти файлы, соответственно, принадлежат nobody. Из этого следует, что после тестирования по SSH / FTP ни удалить файлы, ни перенести.
- На сервере настроен планировщик ( cron ), запускающий раз в N минут скрипт генератора. Генератор, соответственно создает файлы, которые пишутся от пользователя sitename.
- Все это периодически необходимо проверять на актуальность и вычищать
Что мы имеем?
- Файлы пользователя nobody, которые я могу удалять только запустив процесс из web интерфейса.
- Файлы пользователя sitename, которые я могу удалять только под SSH etc.
- Огромное желание сделать один раз и забыть.
План действий: написать скрипт, который через web будет переназначать пользователя ( CHOWN ). Удалять из под консоли, т.к. там по крону запускается скрипт, проверяющий файлы на актуальность и удаляющий их. Дальше код.
- Напишем функцию _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)
здесь мы рекурсивно пытаемся назначать пользователя файлам. естественно, если не получается, то пропускаем. - Ну и для 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()
Вот и все.