Автоматизация монтирования samba-разделов в Mac OS

от автора

Третьего дня поднял сервер для файлопомойки, бэкапов, торрентов и прочих домашних нужд. Там развернулась samba с множеством шар, в частности с личнми данными и местом под бэкапы ноутбука через TimeMachime. Сразу же не понравилось постоянное ручное монтирование шары и образа для бэкапа. Ниже хочу поделиться с сообществом скриптами по автоматизации этого процесса.

Причины неудобств

Каждый раз для подключения к самбе надо изрядно потыкать мышкой: Finder -> Подключение к серверу -> ввод имени сервера (-> первый раз ещё и пароль спросят) -> выбор папок, которые нужно подключить -> Ok. Потом, если захочется делать бэкап в примонтированную по самбе директорию, прийдётся ещё и образ .sparsebundle создавать, и монтировать ещё и его. Всё это, возможно, и не сильно напрягает, если делать раз в пару недель на стационарном ПК, который постоянно находится в одной и той же сети и не выключается так же, как и сервер. Но когда это надо делать после каждого включения/пробуждения ноутбука — это ни в какие ворота не лезет. Плюс к этому выяснилось, что если не отмонтировать разделы и сменить сеть (скажем прийти к соседу в гости), то система изрядно виснет после выхода из сна, ибо не находит сервер с шарами, а, в редких случаях, ещё и в kernel panic случается. Всё это сильно омрачило радость поднятия сервера и мечты о том что больше я даже вспоминать не буду о бэкапах, пока они мне не понадобятся (тьфу тьфу тьфу). Было решено, что процесс нужно автоматизировать.

На первых порах

В попыхах были нагуглены способы монтирования самбы и тут же родился маленький скрипт из парочки идентичных команд следующего вида:

mkdir -p /mount/point 

Так же было найдено как сделать аттач образа для TimeMachine:

hdiutil attach -mountpoint /mount/point /path/to/image.sparsebundle/ 

hdutil оказался более смышлёным и создание папок не потреловал.
Первая версия скрипта была готова.

Безопасность

Очень напрягало указание пароля в явном виде при монтировании. Почитав ман для mount_smbfs узнал про nsmb.conf. Но идея так же не шибко понравилась, так как всё равно пароль хранится где-то в файле в открытом виде. Тут же вспомнил, что через GUI пароль спрашивают единожды, а далее вытаскивают из keychain. Захотелось использовать её. Оказалось автоматически, как если бы взял nsmb.conf и дописал ключик -N к mount_smbfs, пароль подставляться не будет (чуда не произошло). Прийдёся его сначала получать через security и затем передавать в нужное место. Для сих целей была нагуглена и переделана под свои нужды функция:

get_inet_pwd () {   security 2>&1 >/dev/null find-internet-password -gl $1 \   |ruby -e 'print $1 if STDIN.gets =~ /^password: "(.*)"$/' } 

После этого явное указание пароля было заменено на:

mount -t smbfs //user:"$(get_inet_pwd server-pc)"@server-pc/shara_name /mount/point 

Паранойя отступила, но любознательность и перфекционизм остались, поэтому дело продолжилось.

Улучшения и расширение

Захотелось сделать один скрипт для монтирование всего и сразу, да так сделать, чтобы он расширяемый было и повторять код много раз не пришлось, плюс чтобы смотрел что уже в системе примонтировано и второй раз монтировать не пытался. Сказано — сделано. Опишу всё по-порядку.

Для определения примонтированости, на первом этапе, был использован самый «топорный» метод

if [ ! -d /mount/point/ ]; then   mkdir -p /mount/point   mount … fi 

Но сразу же стало понятно, что директория может и присутствовать, но не являться точкой монтирования для чего-либо. Поэтому сделал функцию для проверки:

is_volume_mounted() {   volume_name=$1   mount | awk -v volume_name=$volume_name '$3 == volume_name {print $3}' } 

Метод тоже не идеален, но уже гораздо лучше, нежели простая проверка наличия директории.

То же самое было сделано и для проверки образа бэкапа:

is_image_attached() {   img_path=$1   df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}' } 

После некоторых раздумий и чтения форумов метод раздулся и стал сразу проверять примонтирован ли образ, и, если нет, то монтировать его.

try_attach_fs_image() {   img_path=$1   mnt_pnt_path=$2   # check existance of image file   if [ -d $img_path ]; then     # check if image alredy attached in system     if [[ $(df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}') != "" ]]; then       echo image $img_path alredy attached     else       hdiutil attach -mountpoint $mnt_pnt_path $img_path     fi   fi } 

Далее нужна была функция для выполнения проверок и автоматизации по монтированию любого количества шар с сервера. Вот какой она получилась:

try_mount_server_samba() {   smb_vol_name=$1   mnt_pnt_path=$2   # check if samba share exist in network   if [[ $( is_samba_exist $smb_vol_name ) != "" ]]; then     # check if samba alredy mounted     if [[ $( is_volume_mounted $mnt_pnt_path ) != "" ]]; then       # show message about that       echo volume $mnt_pnt_path alredy mounted     else       # check if moint point directory not exist       if [ ! -d $mnt_pnt_path ]; then         mkdir -p $mnt_pnt_path       fi       # otherwise - mount volume       mount -t smbfs //user:"$(get_inet_pwd server-pc)"@server-pc/$smb_vol_name $mnt_pnt_path     fi   fi } 

Внимательный читатель заметит, что во-первых: можно и имя сервера передавать в параметрах к функции, а не хардкодить его, а во-вторых: в скрипте встречается неизвестная функция is_samba_exist.

Отвечаю по-порядку: 3-й параметр для функции было делать лень, ибо пока второго сервра с самбой не планируется; функция is_samba_exist имеет следующий вид:

is_samba_exist() {   smb_vol_name=$1   smbutil view //user:"$(get_inet_pwd server-pc)"@server-pc/ | awk -v smb_vol_name=$smb_vol_name '$1 == smb_vol_name {print $1}' } 

Несложно догадаться, что функция проверяет наличие шары с указанным именем в текущей сети.

Таким образом основная часть скрипта стала простой, понятной и расширяемой:

try_mount_server_samba "shara_name" "/mount/point" try_attach_fs_image "/path/to/image.sparsebundle" "/mount/point" 

На последок, по образу и подобию вышеописанного скрипта, был создан ещё один, но уже для отмонтирования сразу всего:

#!/bin/sh  # unmount volume if it mounted # syntax: umount_volume "/path/to/volume" umount_volume() {   vol_path=$1   if [[ $(mount | awk -v vol_path=$vol_path '$3 == vol_path {print $3}') != "" ]]; then     umount $vol_path     echo $vol_path is unmounted   fi }  # detach filesystem image if it attached # syntax: detach_fs_image "/path/to/fs/image" detach_fs_image() {   img_path=$1   if [[ $(df -Hl | awk -v img_path=$img_path '$9 == img_path {print $9}') != "" ]]; then     hdiutil detach $img_path     echo $img_path is detched   fi }  # main part  # umnount data volume umount_volume "/data/mount/point"  # firstly detach image from backup volume detach_fs_image "/backup/image/mount/point" # secondary unmount backup volume umount_volume "/backup/volume/mount/point" 

Вот и всё. Дальше скрипты были унесены к своим собратьям в ~/.script. Получили короткие алиасы в .bash_profile и стали помогать мне с самбой.

Перспективы

В будущем, когда дойдут руки, хочется подружить скрипты со SleepWatcher, дабы выполнялись они после выхода из сна и перед уходом в него же. То есть, чтобы совсем ничего не надо было делать руками и автоматизация стала полной.

ссылка на оригинал статьи http://habrahabr.ru/post/232087/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *