AutoMount (Python)

Среда, Июль 13, 2011 г.
Давольно часто приходится работать с файлами и каталогами на удалённых серверах. Задачи разнообразные, но зачастую сводятся к обычной работе с файловой системой. Создание, удаление, редактирование и тд... Для удобства в такой работе я монтирую (Linux на десктопе) файловую систему удалённого сервера локально, это позволяет использовать уже привычные для работы инструменты: редакторы, файловые менеджеры.
Монтирую с помощью sshfs и curlftpfs, в зависимости от типа доступа. Всё хорошо, да вот только аккаунтов накопилась целая куча из которых постоянно используемых чуть больше десятка.

Ручное монтирование стало утомлять. Это необходимо каждый раз создать точку, вспомнить или отыскать реквизиты доступа, набить команду... Ничто так не отравляет позитивный настрой к работе как самая обыденная рутина. И вот однажды когда в очередной раз я забыл где у меня записаны доступы к нужному аккаунту, я твёрдо решил навести порядок. А точнее автоматизировать это безобразие. Решил написать программу которая будет управлять подключениями, создавать точки, монтировать, отмонтировать, помнить реквизиты. Для начала я определился с задачами:
  1. программа будет консольная, ну лень было с gui заморачивться, хотя не исключено что в будущем напишу морду.
  2. язык python, потому как надо было быстрее, да и нравится он мне :)
  3. данные об аккаунтах и прочие опции будут храниться в конфигурационном файле.
  4. при запуске без аргументов, программа должна вывести список аккаунтов с пометками какой из них уже примонтирован.
  5. при запуске программы с именем аккаунта в качестве параметра, создаётся точка монтирования и монтируется аккаунт или же наоборот отмонтируется если он уже примонтирован.

Вот и всё, спартанский минимум для начала, без пыхтелок и рюшечек.
Конфигурационный файл я решил сделать в стиле виндовского ini, но обозвал его .netmount.conf и поместил в домашнюю директорию. Выглядит он примерно так:
[options]
path = /mnt
comm_umount = fusermount -u -z
comm_ssh_mount = sshfs
comm_ftp_mount = curlftpfs

[akk1]
type = ssh
url = bla1.ru
user = root
passwd = q7EVNrCpNR

[akk2]
type = ssh
url = bla2.ru
user = root
passwd = 7lnlBzhYh3

[akk3]
type = ftp
url = bla3.ru
user = root
passwd = 

В секции [options] настройки самой прграммы, думаю там всё понятно. Далее секции соответствуют аккаунтам. Все поля обязательны для заполнения, единственное необязательное это пароль, его ведь может и не быть. Заголовок секции — имя аккаунта. Из этих имён будет состоять список при запуске без аргументов. Также одно из этих имён необходимо передать для монтирования в качестве аргумента. Точка монтирования будет создана с таким же именем.
Вот программа :
#!/usr/bin/python2
# -*- coding: utf-8 -*-

import sys
import os
from ConfigParser import ConfigParser
from subprocess import Popen, PIPE

config = ConfigParser()
config.read(os.path.expanduser("~")+"/.netmount.conf")

sections = config.sections()
try:
    sections.remove("options")
except:
    print "Конфигурационный файл не валиден\n[options]"
    sys.exit(1)

f = open("/etc/mtab")
mtab = f.read()
f.close()

def is_mount(mp):
    "примонтирован ли путь"
    if mp in mtab:
        return True
    return False

# основные опции
options = {}
try:
    options["path"] = config.get("options", "path").strip()
    options["comm_umount"] = config.get("options", "comm_umount").strip()
    options["comm_ssh_mount"] = config.get("options", "comm_ssh_mount").strip()
    options["comm_ftp_mount"] = config.get("options", "comm_ftp_mount").strip()
    if len(filter(lambda x: len(x)==0, options.values())) > 0:
        raise ValueError
except:
    print "Конфигурационный файл не валиден\n[options]"
    sys.exit(1)

# аргументы
if len(sys.argv) < 2:
    for s in sections:
        if is_mount(options["path"]+"/"+s):
            print "+"+s
        else:
            print "-"+s
    sys.exit(0)
elif not sys.argv[1] in sections:
    print "Для '"+sys.argv[1]+"' правило не задано"
    sys.exit(1)

p = sys.argv[1]

# опции для точки монтирования
point = {}
try:
    point["name"] = p
    point["path"] = options["path"]+"/"+p
    point["type"] = config.get(p, "type").strip()
    point["url"] = config.get(p, "url").strip()
    point["user"] = config.get(p, "user").strip()
    point["passwd"] = config.get(p, "passwd").strip()
    if len(point["type"]) == 0 or len(point["url"]) == 0 or len(point["user"]) == 0:
        raise ValueError
except:
    print "Конфигурационный файл не валиден\n["+p+"]"
    sys.exit(1)

if point["type"] != "ftp" and point["type"] != "ssh":
    print "Конфигурационный файл не валиден\n["+p+"] 'type' должен быть ftp или ssh"
    sys.exit(1)

################################################
# ну вроде с конфигом всё как надо, едем дальше
################################################

# существует ли точка монтирования и примонтирована ли?
if os.path.isdir(point["path"]):
    if is_mount(point["path"]):
        if os.system(options["comm_umount"]+" "+point["path"]) > 0:
            print p+" существует и примонтирован\nошибка при попытке отмонтировать."
            sys.exit(1)
        else:
            os.rmdir(point["path"])
            print p+" отмонтирован"
            sys.exit(0)
    os.rmdir(point["path"])

# создаём и монтируем
os.makedirs(point["path"], mode=0775)
if point["type"] == "ftp":
    cmd = options["comm_ftp_mount"]+" ftp://"+point["user"]
    if len(point["passwd"]) > 0:
        cmd += ":"+point["passwd"]
    cmd += "@"+point["url"]+" "+point["path"]
    if os.system(cmd) == 0:
        print p+" примонтирован"
elif point["type"] == "ssh":
    cmd = options["comm_ssh_mount"]+" "+point["user"]+"@"+point["url"]+":/ "+point["path"]
    if len(point["passwd"]) == 0:
        if os.system(cmd) == 0:
            print p+" примонтирован"
    else:
        cmd += " -o password_stdin"
        proc = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
        ans = proc.communicate(point["passwd"])
        if ans[1] != None:
            print ans[0]
        else:
            print p+" примонтирован"


Если что не понятно спрашивайте — разжую. Как по мне, так она простая.
Возможно кто-то скажет что хранить доступы к разным серверам в открытом виде и одном месте не секьюрно. Да это не совсем хорошо. Как вариант пароли или даже сам конфиг можно закриптовать. Можно воспользоваться каким либо менеджером паролей, Kwallet, GNOME Keyring или же другим аналогом в зависимости от предпочтений. При наличии прямых рук и желания, доработать будет не сложно.
Если пригодится, пользуйтесь на здоровье :)
Теги: PythonLinux
 
   
Оставить коментарий
Оставить комментарий   Нажмите, чтобы отменить ответ.
Доступен html впределах разумного. Для цитирования используйте <blockquote></blockquote>, для отрисовки программного кода [code][/code].
Для всяких хакеров и прочих: комментарии проходят санитизацию, всё лишнее будет вырезано. Так что не тратьте своё драгоценное время.
Имя (обязательно)
E-Mail (Не будет опубликован , обязательно)
Сайт (необязательно)