Общая сетевая папка NFS+SAMBA с правами для всех

Цель: расшарить директорию через NFS и CIFS так, чтобы для обоих протоколов был общий доступ и файлы, залитые через один протокол, были доступны на чтение и запись через второй.

Метод, до которого дошел я (возможно не единственный), реализуется через дополнительного пользователя на сервере, с которого шарится директория. В моем случае это пользователь «user» с UID 1000 (входит в одноименную группу с GID 1000).

Файл /etc/exports выглядит так

/etc/exports
 
  1. "/share/Public" *(rw,nohide,async,no_subtree_check,crossmnt,all_squash,anonuid=1000,anongid=1000)

ключевыми параметрами являются:

  1. all_squash — опция говорит что все подключения будут считаться анонимными
  2. anonuid=1000 — определяет UID пользователя от имени которого будет осуществляться доступ для анонимных подключений
  3. anongid=1000 — аналогично определяет GID

Таким образом все файлы и папки, создаваемые на сервере через NFS будут иметь владельца «user»

 
 
  1. ls -la /share/Public/test_dir/
 
 
  1. total 12
  2. drwxr-xr-x  3 user user 4096 Jan 14 16:18  .
  3. drwxrwxrwx 14 user user 4096 Jan 14 16:18  ..
  4. drwxr-xr-x  2 user user 4096 Jan 14 16:18 'nfs dir'
  5. -rw-r--r--  1 user user    0 Jun 19  2020 'nfs file.txt'

Теперь можно переходить к настройке самбы. Приведу весь свой конфиг /etc/samba/smb.conf

/etc/samba/smb.conf
 
  1. [global]
  2.     workgroup = WORKGROUP
  3.     dns proxy = no
  4.     log file = /var/log/samba/log.%m
  5.     max log size = 200
  6.     panic action = /usr/share/samba/panic-action %d
  7.     server role = standalone server
  8.     passdb backend = tdbsam
  9.     obey pam restrictions = yes
  10.     unix password sync = yes
  11.     passwd program = /usr/bin/passwd %u
  12.     passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
  13.     pam password change = yes
  14.     map to guest = bad user
  15.     security = user
  16.     usershare allow guests = yes
  17.     acl allow execute always = true
  18.     allow insecure wide links = yes
  19.     # WinXP/Android X-Plore compatibility:
  20.     ntlm auth = yes
  21.     server min protocol = NT1
  22. [Public]
  23.     path = /share/Public
  24.     mangled names = no
  25.     writeable = yes
  26.     follow symlinks = yes
  27.     wide links = yes
  28.     browsable = yes
  29.     guest ok = yes
  30.     guest only = yes
  31.     force user = user
  32.     force group = user
  33.     create mask = 666
  34.     directory mask = 777
  35.     #recycle
  36.     vfs objects = recycle
  37.     recycle:repository = /share/Public/.Trash-1000/files/%U
  38.     recycle:keeptree = Yes
  39.     recycle:versions = Yes
  40.     recycle:touch = Yes

Здесь ключевыми являются опции директории:

  1. guest ok = yes — пускать юзера без аутентификации
  2. guest only = yes — пускать только анонимусов
  3. force user = user — работа с файлами ведется от имени указанного юзера «user» (аналог nfs-ного «anonuid=1000»)
  4. force group = user — аналогично для группы (аналог nfs-ного «anongid=1000»)

Корзина

Отдельно прокомментирую вот это кусок

 
 
  1. #recycle
  2.     vfs objects = recycle
  3.     recycle:repository = /share/Public/.Trash-1000/files/%U
  4.     recycle:keeptree = Yes
  5.     recycle:versions = Yes
  6.     recycle:touch = Yes

Дело в том, что при удалении файлов из директории, смонтированной через NFS, скорее всего (это зависит от файлового менеджера)  в точке монтирования будет создана директория корзины «.Trash-1000». В то же время клиенты Windows для сетевых путей корзину не используют, но именно для этого существуют опции самбы, которые включают сетевую корзину и позволяют указать — в какой именно директории хранить удаляемые файлы. В моем случае опция «recycle:repository» указывает правило хранения, которое соответствует правилам удалению в корзину в линуксе. То есть, при такой настройке, файлы что удаленные в линуксе через NFS, что в виндусе через SMB — попадут в один каталог. В винде, конечно, они не появятся в виндовой «корзине», но как минимум их можно будет достать из папки «.Trash-1000».

Однако при этом возникает парадоксальная ситуация, что в винде данную «корзину» очистить не получится, так как она лежит в той же шаре. То есть удаляемые файлы будут валиться в нее же. Воркэраундом является создание дополнительной отдельной шары под эту директорию, чтобы через нее удалять ненужные файлы.

/etc/samba/smb.conf
 
  1. [Trash]
  2.     path = /share/Public/.Trash-1000
  3.     mangled names = no
  4.     writeable = yes
  5.     follow symlinks = yes
  6.     wide links = yes
  7.     browsable = yes
  8.     guest ok = yes
  9.     guest only = yes
  10.     force user = user
  11.     force group = user
  12.     create mask = 666
  13.     directory mask = 777

Коды счетчиков Perfmon Windows (для использования с Zabbix и не только)

Список кодов монитора производительности, для использования с заббиксом наподобие

Average disk read queue length — perf_counter[\234(_Total)\1402]

Windows Server 2016 Perfmon Counters and Codes

Get-MailboxDatabaseCopyStatus: «Status.value__» to «Status»

Понадобилось для мониторинга баз. Не все, но наиболее распространенные значения. Взято с MSExchange 2010

 
 
  1. Get-MailboxDatabaseCopyStatus -Identity * | ForEach-Object {$_.Status.value__}
  2. Get-MailboxDatabaseCopyStatus -Identity * | ForEach-Object {$_.Status}
 
 
  1. 3 ⇒ Failed
  2. 4 ⇒ Seeding
  3. 5 ⇒ Suspended
  4. 6 ⇒ Healthy
  5. 7 ⇒ ServiceDown
  6. 8 ⇒ Initializing
  7. 9 ⇒ Resynchronizing
  8. 11 ⇒ Mounted
  9. 12 ⇒ Dismounted
  10. 13 ⇒ Mounting
  11. 15 ⇒ DisconnectedAndHealthy
  12. 16 ⇒ FailedAndSuspended
  13. 17 ⇒ DisconnectedAndResynchronizing

Как отредактировать текстовый файл на 40Gb??

Поимел тут дамп базы данных — текстовик на 40 гигов.

Для понимания проблемы: дамп состоит из двух основных блоков
[блок команд создания таблиц]
[блок команд вставки строк]

Первый блок небольшой, на 150 строк. Второй – все остальные гиги, которые выглядят как

 
 
  1. INSERT INTO tablename VALUES (val1, val2… valN);
  2. INSERT INTO tablename VALUES (val1, val2… valN);
  3. ...
  4. INSERT INTO tablename VALUES (val1, val2… valN);

Импортируется обычно все командой

 
 
  1. cat dump.sql | mysql basename

то есть файл просто читается в пайп и mysql выполняет команды из него.

И в чем подстава.
Во-первых у дампа в начале не хватало пары команд — это выяснилось сразу при попытке импорта и легко выгуглилось. Во-вторых — в блоке импорта строк, ВО ВСЕХ строках отсутствовало начало: «INSERT INTO tablename VALUES»

Я не нашел такой чудо-редактор, который смог бы на редактирование хотя бы открыть этот мегадамп, поэтому к сути.

Сделал два вспомогательных файла:
1.sql – с недостающими командами,
2.sql – с первыми 150 строками, которые про создание таблиц, и первым недостающим «INSERT INTO tablename VALUES» — для начала блока импорта — который я добавил вручную.

Свел задачу к:
— как бы в один поток прочитать сначала эти два файла,
— а потом третий – только в нем пропустить первые строки, а во оставшихся — заменять концы строк с «);» на «); INSERT INTO tablename VALUES», чтобы каждая новая строка начиналась с корректной команды,
— и все это точно также запихать в пайп и отдать mysql.

Оказывается есть такая магия!

 
 
  1. {cat 1.sql 2.sql; sed -n -e 's/);/); INSERT INTO tablename VALUES /g;151,$ p' dump.sql;} | mysql basename
 
 
  1. конструкция команд внутри {} дает общий вывод, который можно направить в пайп и в mysql.
  2. cat 1.sql 2.sql - просто читает два файла подряд
  3. чтение основного файла отдаем седу, с двумя его командами
  4. sed -n -e 's/);/); INSERT INTO tablename VALUES /g;152,$ p' dump.sql;
  5. здесь      ^-- меняем ";)" на "); INSERT..."   --^ ^-- --^ - выводим файл со 151 строки

SimpliVity VM Data Access Not Optimized

Долго не мог понять почему возникает сабжевая ошибка. В норме, при включенном vSphere DRS виртуальные машины должны автоматически перекидываться на хосты, на которых непосредственно лежат их файлы (если точнее, симпливити дублирует каждую виртуалку, так чтобы 2 хоста имели полный локальный доступ к ней). В моем же случае виртуалки балансировались классически — по загруженности хостов, то есть vmotion работал, но по какой-то причине игнорировал симпливитийную привязку к хранилищу.

Оказалось, причина была в установленной галке «For availability, distribute a more even number of virtual machines across hosts» в настройках vSphere DRS. Вероятно задача равномерного распределения оказалась приоритетнее и полностью отрубила балансировку по доступу к хранилищу. Вывод: если возникла подобная проблема — стоит начать с того чтобы выставить дефолтные настройки DRS

Также могу порекомендовать цикл постов о принципах работы Simplivity:

 

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 1 – Data creation and storage

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 2 – Automatic Management

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 3 – Provisioning Options

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 4 – Automatic capacity management

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 5 -Analyzing Cluster Utilization

How Virtual Machine data is stored and managed within a HPE SimpliVity Cluster – Part 6 – Calculating backup capacity

 

Thunderbird, Dovecot и сертификат Let’s Encrypt

Ошибка: «Неустранимая ошибка TLS. Произошла ошибка рукопожатия или, возможно, версия TLS или сертификат, используемые сервером, несовместимы»

Решение: в настройках пролистать до конца, открыть редактор настроек, изменить параметр
security.ssl.enable_ocsp_must_staple = false

Nvidia Optimus: включить ускорение для всего сеанса на постоянку

Долгое время на своем ноуте (Dell Vostro 5470) не мог заставить по-человечески работать  видюху NVIDIA  GK208M [GeForce GT 740M], которая по уму должна включаться по запросу приложений, в остальное время уступая работу по отрисовке графики интегрированной интеловской карточке. Все эти Bumblebee нифига не захотели работать, но на вики дебиана (внезапно) нашлась инструкция — как заставить нвидиевский чип работать постоянно (а почему бы, собственно, и нет — энергосбережение мне нафиг не уперлось).

Коротенько как это сделать при использовании SDDM.

Дрова и xorg

Сначала накатываются дрова

 
 
  1. wajig install  nvidia-driver

Выясняются ID шины для обеих видюх

 
 
  1. lspci
 
 
  1. ...
  2. 00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 09)
  3. ...
  4. 09:00.0 3D controller: NVIDIA Corporation GK208M [GeForce GT 740M] (rev a1)
  5. ...

Теперь создаем файл /etc/X11/xorg.conf (обратите внимание, что запись ID в нем отличается от вывода lspci)

/etc/X11/xorg.conf
 
  1. Section "ServerLayout"
  2.     Identifier "layout"
  3.     Screen 0 "nvidia"
  4.     Inactive "intel"
  5. EndSection
  6. Section "Device"
  7.     Identifier "nvidia"
  8.     Driver "nvidia"
  9.     BusID "PCI:9:0:0"
  10. EndSection
  11. Section "Screen"
  12.     Identifier "nvidia"
  13.     Device "nvidia"
  14.     Option "AllowEmptyInitialConfiguration"
  15. EndSection
  16. Section "Device"
  17.     Identifier "intel"
  18.     Driver "modesetting"
  19.     BusID "PCI:0:2:0"
  20. EndSection
  21. Section "Screen"
  22.     Identifier "intel"
  23.     Device "intel"
  24. EndSection

SDDM

Так как я использую SDDM в качестве дисплей-менеджера, то для него в файл /usr/share/sddm/scripts/Xsetup дописываются строки:

 
 
  1. xrandr --setprovideroutputsource modesetting NVIDIA-0
  2. xrandr --auto
  3. xrandr --dpi 96

Тиринг

Ну и чтобы не было тиринга, в конец файла /etc/modprobe.d/nvidia.conf дописывается строка

 
 
  1. options nvidia-drm modeset=1

после чего выполняется команда

 
 
  1. update-initramfs -u

Теперь после перезагрузки ускорение работает.

Источник: https://wiki.debian.org/NVIDIA%20Optimus#Using_NVIDIA_GPU_as_the_primary_GPU

Отказоустойчивая установка Debian с EFI на зеркало mdadm-рейда

Данный пост возник в результате моей собственной попытки понять, как именно можно добиться отказоустойчивости в конфигурации с EFI-загрузчиком и корнем системы на RAID-массиве. Базовая проблема заключается в том, что разделы с файлами EFI не могут быть расположены на рейде, что приводит к курьезной ситуации, когда сам линукс установлен на рейд, но загрузчик оказывается только на одном диске. Как оказалось, выход конечно есть, но требует дополнительных манипуляций. Я пошел длинным путем и решил описать установку дебиана через Live-CD при помощи debootstrap, что позволяет акцентировать внимание на момент установки загрузчика.

В самом низу будет видео, демонстрирующее все описанные ниже шаги.

Исходная позиция: система с двумя неразмеченными дисками, загруженная с Live-CD

Действия в консоли Live-CD

Размечаем первый диск.
Следующий набор команд создаст на диске GPT-таблицу c двумя разделами: 1 — EFI-раздел на 100 Мб, 2 — раздел под будущее зеркало, размером в 10 Гб

 
 
  1. fdisk /dev/sda
  2. g
  3. n
  4. 1
  5. [default]
  6. +100M
  7. t
  8. 1
  9. n
  10. 2
  11. [default]
  12. +10G
  13. w

Скопируем конфигурацию разделов на второй диск, чтобы они были идентичны

 
 
  1. sfdisk -d /dev/sda | sfdisk /dev/sdb

Отформатируем первые разделы дисков в FAT32

 
 
  1. mkfs.fat -F32 /dev/sda1
  2. mkfs.fat -F32 /dev/sdb1

Создадим зеркало md0 из вторых разделов дисков sda и sdb

 
 
  1. mdadm --create --metadata=0.90 /dev/md0 -l 1 -n 2 /dev/sda2 /dev/sdb2

Форматируем и монтируем рейд

 
 
  1. mkfs.ext4 /dev/md0
  2. mount /dev/md0 /mnt

При помощи утилиты debootstrap скачиваем и разворачиваем на смонтированном рейде основу дебиана

 
 
  1. debootstrap --arch amd64 stable /mnt https://deb.debian.org/debian

Переходим в свежую систему при помощи chroot

 
 
  1. mount --bind /dev /mnt/dev
  2. mount --bind /proc /mnt/proc
  3. mount --bind /sys /mnt/sys
  4. chroot /mnt

Действия в chroot-окружении

Устанавливаем пароль root

 
 
  1. passwd

Создаем директорию под файлы EFI

 
 
  1. mkdir /boot/efi

Выясняем ID рейда и прописываем содержимое fstab

 
 
  1. blkid /dev/md0
  2. vi /etc/fstab
 
 
  1. UUID="..."    /           ext4    errors=remount-ro    1 1
  2. /dev/sda1       /boot/efi       vfat    umask=0077           0 1

Важно: рейд указываем через ID, EFI-раздел — по имени.

Монтируем согласно fstab (рейд уже смонтирован, то есть по факту домонтируем EFI)

 
 
  1. mount -a

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

 
 
  1. apt update
  2. apt install mdadm

Опционально настроим локали и часовой пояс

 
 
  1. apt install locales
  2. dpkg-reconfigure locales
  3. dpkg-reconfigure tzdata

Установим ядро

 
 
  1. apt install linux-image-amd64

Установим и настроим загрузчик

 
 
  1. apt install grub-efi
  2. update-grub2

Проинсталлируем GRUB на диски

 
 
  1. grub-install /dev/sda
  2. grub-install /dev/sdb

В момент инсталляции загрузчика на sda каталог /boot/efi/ заполняется файлами. Для отказоустойчивости необходимо скопировать эти файлы с sda1 на sdb1…

 
 
  1. mkdir /boot/efi2
  2. mount /dev/sdb1 /boot/efi2
  3. cp -RT /boot/efi /boot/efi2

… и добавить второй диск в список UEFI, чтобы система знала, что на нем тоже есть все необходимые файлы

 
 
  1. efibootmgr  -c -g -d /dev/sdb -p 1 -L "debian 2" -l '\EFI\debian\shimx64.efi'

Таким образом у нас оба диска будут в списке загрузчика и при смерти любого из них система будет способна загрузиться.
Используя утилиту efibootmgr в дальнейшем можно удалить из списка замененные диски, а для добавленных дисков нужно будет повторить шаги второго диска:
1. скопировать таблицу разделов,
2. отформатировать первый раздел и скопировать на него файлы EFI,
3. добавить второй раздел в существующий рейд,
4. заинсталлировать на диск grub,
5. добавить этот диск в UEFI.

Выходим из chroot

 
 
  1. exit

Действия в консоли Live-CD

Перезагружаемся

 
 
  1. reboot

Вывод

Обеспечить отказоустойчивость системы на рейд-массиве можно путем создания EFI-раздела на каждом диске, копировании на него файлов EFI и добавлении в список загрузчика при помощи утилиты efibootmgr.

Видео, в котором я последовательно показываю весь процесс с момента создания виртуальной машины:

 

Использованные материалы

См. также

Debian 10 Buster + openbox (установка и настройка)

WordPress: как убрать &nbsp в конце постов.

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

Для лечения уже существующих постов без изменения базы данных, добавляем в functions.php вашей темы следующий код

Загрузчик Загрузка...
Логотип EAD Слишком долго?

Перезагрузка Перезагрузить документ
| Открыть Открыть в новой вкладке

Download

Вторая часть — обработка поста при сохранении. Почти тот же кусок кода

Загрузчик Загрузка...
Логотип EAD Слишком долго?

Перезагрузка Перезагрузить документ
| Открыть Открыть в новой вкладке

Download

Обратите внимание, что смайлик тут используется как символ, заведомо неиспользуемый в постах — в процессе он будет заменен на неразрывный пробел. Это нужно учитывать, если такой символ может появиться в посте «легально».

Чтобы лишний раз не ковырять дефолтный functions.php, можно установить плагин Functionality. Он создаст дополнительный файл с таким же названием и установит его как плагин с именем блога (да, установив этот плагин вы автоматом получите второй — не забудьте активировать и его тоже).

Классный скрипт для конвертации в utf8

Запарило пересохранять субтитры, которые часто выкладывают в вин-кодировке. Нашел клевый скрипт на питоне (а значит и под виндой можно юзать) для конвертации из любой кодировки (исходная автоопределяется) в UTF8. Навесил его как кастомную команду для *.srt в Double Commander, который также юзаю в обеих системах — стало совсем хорошо =)

 
 
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. from chardet import detect
  5. srcfile = sys.argv[1]
  6. tmpfile = sys.argv[1] + '.tmp'
  7. bakfile = sys.argv[1] + '.bak'
  8. # get file encoding type
  9. def get_encoding_type(file):
  10.     with open(file, 'rb') as f:
  11.         rawdata = f.read()
  12.     return detect(rawdata)['encoding']
  13. from_codec = get_encoding_type(srcfile)
  14. # add try: except block for reliability
  15. try:
  16.     with open(srcfile, 'r', encoding=from_codec) as f, open(tmpfile, 'w', encoding='utf-8') as e:
  17.         text = f.read() # for small files, for big use chunks
  18.         e.write(text)
  19.     os.rename(srcfile, bakfile) # backup old encoding file
  20.     os.rename(tmpfile, srcfile) # rename new encoding
  21.    
  22. except UnicodeDecodeError:
  23.     print('Decode Error')
  24. except UnicodeEncodeError:
  25.     print('Encode Error')