HOW-TO по миграции файловых серверов

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

В моем случае речь ведется о переносе шар с исходного сервера в одном домене на целевой сервер в другом домене, размер шар достигает сотен гигабайт (в некоторых случаях больше терабайта), шара на целевом сервере подключается к серверу DFS.

Итак, первым делом на целевом сервере я создаю папку work, например на диске E:, и расшариваю ее под именем «workE$». Права доступа: полный доступ для SYSTEM, OLDDOMAIN\Domain Admins, NEWDOMAIN\Domain Admins — это позволит копировать конкретные расшареные папки со старого сервера по сети внутрь work с сохранением исходных прав доступа.

Аналогичные права доступа будет очень нелишним добавить и на исходную расшареную папку и ее содержимое, потому что эти права будут копироваться как есть на целевой сервер и возможны ситуации, когда вы, будучи администратором, или не можете получить полные права доступа на файлы на исходном сервере, или, уже скопировав их на целевой, — не имеете прав на изменений атрибутов скопированных файлов. Отдельно нужно следить за папками внутри исходной, на которых отключено наследованием прав — это, к сожалению, вполне распространенная практика в моем случае — на них также нужно проставить полный доступ админам домена(-ов).

Далее, на исходный сервер устанавливается утилита robocopy и изготавливается вот такой скрипт:

rcopy.cmd
 
  1. chcp 1251
  2. robocopy "d:\MyShare" "\\fs-new.local\worke$\MyShare" /MIR /SEC /NS /NC /NDL /R:1 /W:1  /UNILOG:"\\fs-new.local\worke$\MyShare.txt" /TEE
  3. pause

(первая строка нужна на случай, если исходная папка называется по-русски — без этого у меня ломалась кодировка и все файлы копировались с кракозябрами. )

Запускаете cmd с повышенными правами и стартуете скрипт. Он полностью копирует исходную папку на целевой сервер. Что важно — робокопи с этими ключами делает копию директории, а при повторном запуске — актуализирует ее (обновляет измененные файлы, добавляет новые, удаляет те которые были удалены из исходной папки). Поэтому даже если исходная шара была очень большой и копировалась несколько суток, то путем второго-третьего запуска можно уже довольно быстро актуализировать состояние на целевом сервере и пользователи не потеряют те изменения, которые были сделаны во время копирования.
Отдельно замечу что robocopy пишет в лог все ошибки копирования (строго говоря при первом запуске в лог улетают все копируемые файлы, так что лог может быть большим, но при повторном запуске туда попадают только изменения и ошибки, что довольно удобно — как раз видно, например, что на какую-то папку нет прав доступа)

Я так и делаю. Во время копирования или актуализации, пока выполняется скрипт, уже можно на целевом сервере расшарить папку и назначить права доступа к шаре, если они были настроены каким-то специфическим образом. Как только файлы актуализированы (обычно, конечно, актуализацию приходится проводить в нерабочее время) — на старом сервере шара отключается, и поднимается с тем же именем, правами только на чтение, и с двумя файликами: текстовым файлом с содержанием «уважаемые пользователи, файловые ресурс смигрирован на новый адрес: \\новый\адрес, пожалуйста запомните его или скопируйте себе ярлык»,  и ярлыком на новое место, то есть на шару на целевом сервере. Таким образом пользователи, заходя по старому адресу, обнаруживают что ничего не работает, но у них есть подсказка. Из своего опыта могу сказать что даже если у пользователей есть ярлыки куда-то вглубь, то все равно так или иначе они добираются до корня старой шары с подсказкой и вопросов возникает минимум, так что этот метод вполне стрессоустойчив для администратора =)

В моем случае я дополнительно собираю целевые шары на сервере DFS (рекомендую прочитать отдельный пост на тему настройки DFS: Перенастройка DFS для использования DNS-резолвинга), постольку поскольку целевых серверов в моем случае много и хочется дать пользователям единую точку входа. Комментарием тут может быть разве что рекомендация скрывать шару на целевом сервере, то есть реализовывать такую схему:

исходный сервер: \\old-srv\myshare
целевой сервер: \\new-srv\myshare$
dfs-сервер: \\dfs\rootname\myshare

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

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

 

RussianFIO2AD — генератор учеток для Active Directory

По работе регулярно сталкиваюсь с присланными списками ФИО, которые нужно сконвертировать в учетки AD с шаблонными логинами и паролями. Для этих целей еще с год назад написал небольшую прожку, которую все это время тестировал, а сейчас немного допилил и могу поделиться.

Выглядит незамысловато

Вставляем из буфера список ФИО — поддерживается вставка из текстового файла или таблицы (с некоторыми оговорками, но как правило работает) — потом генерируем логины и пароли, проверяем чтобы в AD не было дублей и создаем учетки. Процесс коротенько можно увидеть на ютубе.

Скачать прожку можно на гитхабе: https://github.com/qiwichupa/RussianFIO2AD

Как всегда в таких случаях: нормальная работа не гарантируется, используйте на свой страх и риск, то, что у меня AD не сломалось — ничего не значит, может быть мне повезло )

 

py-subsrenamer: массовое переименование субтитров

Решил переписать на питоне башевый скрипт для переименования субтитров (согласно именам видеофайлов), чтобы можно было его использовать под виндой. Заодно оформил вариант с простеньким графическим интерфейсом (и немножко ознакомился с wxPython)

Скачать можно тут: https://github.com/qiwichupa/py-subsrenamer (экзешники смотреть тут)

Пример использования

 

 

Шифрованный SOCKS5-прокси на своем сервере

Я уже писал как поднять шифрованный прокси средствами ssh, и до сих пор я сам использовал именно этот метод. Однако при всех его плюсах, таких как проверенность протоколов и механизмов, и «изкоробочность» (при условии, конечно, наличия под рукой своего сервера), есть и довольно большой минус: задача проксирования для ssh не первоочередная и справляется он с ней не лучшим образом.

Поэтому я в очередной раз загуглил и нашел более адаптированное решение предназначенное именно для проксирования с шифрованием — shadowsocks.

Это клиент-серверная штука, изначально написанная на питоне, но существующая и в переписанном, если память не изменяет, на C варианте.

Установка сервера (debian/ubuntu)

Ставим софт

 
 
  1. apt install shadowsocks-libev rng-tools

Настраиваем

/etc/default/rng-tools
 
  1. HRNGDEVICE=/dev/urandom
/etc/shadowsocks-libev/config.json
 
  1. {
  2. "server":"SERVER_IP",
  3. "server_port":PORT,
  4. "local_port":1080,
  5. "password":"PA$$W0RD",
  6. "timeout":60,
  7. "method":"aes-128-gcm"
  8. }

Установка клиента

Клиенты для всяческих платформ указаны на официальном сайте. Лично я для винды использовал shadowsocks-windows (портативная версия), а для линукса — shadowsocks-qt5, доступный в штатном репозитории дебиана.

Настраиваются клиенты максимально похоже — все что нужно указать: ip и порт сервера, алгоритм шифрования и пароль, указанные при настройке сервера; а также локальный порт на клиенте, к которому будут подключаться наши приложения (браузер и т.д.)

В самом приложении указываем настройки прокси:

SOCKS5
IP: 127.0.0.1
PORT: 3128 (ну или какой вы укажите при настройке клиента)

Например в файрфоксе это будет выглядеть так:

Ну и все, должно работать.

Безопасность сервера (настройка fail2ban)

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

/etc/fail2ban/filter.d/shadowsocks-libev.conf
 
  1. [INCLUDES]
  2. before = common.conf
  3. [Definition]
  4. _daemon = ss-server
  5. failregex = ^\w+\s+\d+ \d+:\d+:\d+\s+%(__prefix_line)sERROR:\s+failed to handshake with <HOST>: authentication error$
  6. ignoreregex =
  7. datepattern = %%Y-%%m-%%d %%H:%%M:%%S

и

/etc/fail2ban/jail.d/shadowsocks-libev.conf
 
  1. [shadowsocks-libev]
  2. enabled = true
  3. filter = shadowsocks-libev
  4. port = PORT
  5. logpath = /var/log/syslog
  6. maxretry = 3
  7. findtime = 3600
  8. bantime = 3600

(PORT — порт подключения к серверу, указанный нами в конфиге сервера)

Таким образом буквально минут за 5-10 можно сделать для себя адекватный прокси с шифрованным каналом.

Перенастройка DFS для использования DNS-резолвинга

По умолчанию сервис DFS использует короткие NetBIOS-имена для публикации своих неймспейсов (Namespace). Это может привести к недоступности неймспейса \\dfs.mycompany.local\dfsroot\, если вы хотите предоставить доступ кому-то за пределами вашей организации. При попытке захода в dfsroot, даже если пользователь попытается открыть его по полному имени (\\dfs.mycompany.local\dfsroot\), запрос переформулируется в \\dfs\dfsroot\ и возникнет проблема разрешения имени. При этом у вас может быть корректно настроена служба DNS между вашими сетями, и даже все шары внутри этого корня, добавленные с указанием полных имен серверов, могли бы быть доступны. Убедиться в том, что неймспейс резолвится по короткому имени, можно, выбрав его в списке Namespace в оснастке управления DFS на вкладке Namespace Servers: в графе Path будет указано \\dfs\dfsroot. Что делать в этой ситуации?

У DFS нет возможности переключить режим работы на DNS-резолвинг на лету, более того — потребуется удаление всех ранее созданных неймспейсов со всем содержимым. К счастью, текущие настройки неймспейсов можно экспортировать в xml-файл и использовать его для восстановления списка шар после пересоздания неймспейса.

Итак, представим что у нас есть сервер «dfs.mycompany.local», с корнем «dfsroot» и каким-то набором шар внутри него. Шаги для перевода сервера на лыжи DNS будут такими:

(В оснастке управления неймспейс может отображаться как \\dfs\dfsroot или как \\dfs.mycompany.local\dfsroot — это не влияет на резолвинг, но это важно при выполнении нижеприведенных команд. Я привожу их для варианта  \\dfs\dfsroot, в случае если у вас имя прописано полностью — в командах с dfsutil используйте его)

    1. Бэкапим настройки неймспейса:
       
       
      1. dfsutil /root:\\dfs\dfsroot /export:c:\dfsroot.xml
    2. Открываем файл бэкапа в блокноте, убеждаемся что он содержит описание всех шар неймспейса. Вид примерно такой:
       
       
      1. <?xml version="1.0"?>
      2. <Root Name="\\dfs\dfsroot" State="1" Timeout="300" >
      3.       <Target Server="dfs" Folder="dfsroot" State="2" />
      4.       <Link Name="Temp" State="1" Timeout="1800" >
      5.             <Target Server="fileserver" Folder="Temp" State="2" />
      6.       </Link>
      7.       <Link Name="Public" State="1" Timeout="1800" >
      8.            <Target Server="fileserver.mycompany.local" Folder="Public" State="2" />
      9.       </Link>
      10.       <Link Name="SecFiles" State="1" Timeout="1800" >
      11.            <Target Server="newfs.mycompany.local" Folder="SecFiles" State="2" />
      12.       </Link>
      13. </Root>
    3. Удаляем корень dfsroot
    4. Переводим DFS на работу с DNS:
       
       
      1. dfsutil.exe server registry dfsdnsconfig set
    5. Перезапускаем службу DFS:
       
       
      1. net stop dfs; net start dfs
  1. Заново создаем корень dfsroot, указывая в мастере полное имя сервера: dfs.mycompany.local
  2. Перезапускаем консоль управления DFS (это важно!), выбираем созданный неймспейс, и на вкладке Namespace Servers убеждаемся, что в графе Path прописан полный путь
  3. Редактируем файл бэкапа:
    1. Меняем, если надо
       
       
      1. Root Name="\\dfs\dfsroot"

      на

       
       
      1. Root Name="\\dfs.mycompany.local\dfsroot"
    2. Меняем
       
       
      1. Target Server="dfs"

      на

       
       
      1. Target Server="dfs.mycompany.local"
    3. Меняем, если надо, параметры «Target Server» для шар, если сервера прописаны короткими NetBIOS-именами (как в примере из п.2 для шары «Temp» указан сервер «fileserver» вместо «fileserver.mycompany.local»)
  4. Восстанавливаем из бэкапа корень (обратите внимание, что теперь в команде мы используем Namespace, содержащий полное имя — dfs.mycompany.local,  так как при его создании в п.6 мы прописали имя сервера полностью. Важно чтобы в файле бэкапа на текущий момент было указано оно же.)
     
     
    1. dfsutil /root:\\dfs.mycompany.local\dfsroot /import:c:\dfsroot.xml /set
  5. Проверяем в оснастке управления, что неймспейс заполнился нашими шарами.

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

Статья на сайте MS: https://support.microsoft.com/en-us/help/244380/how-to-configure-dfs-to-use-fully-qualified-domain-names-in-referrals

 

Написал поисковик для файлопомоек — pyFileSearcher

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

В общем, я решил что было бы прикольно написать что-то свое. Эту мысль я вынашивал наверное больше года, так как яжнепрограммист ну абсолютно, но вот прошел курс по гуям в питоне и подумал что надо бы попробовать че получится.

Получилось портабельное приложение, которое не обладает горой функционала, но во-первых умеет сожрать в себя 20 миллионов файлов, во-вторых — умеет искать по нужным в быту параметрам, таким как размер файла, тип, и — это важно — дате добавления в индекс. Строго говоря я не видел тулзов, которые бы сами запоминали время, когда файл был обнаружен. Да, у файла есть время создания и время модификации — и казалось бы их должно хватать для отфильтровывания новых файлов, когда мы хотим их найти. Но хрен там был, эти атрибуты ведут себя черт знает как — например файл притащенный с плеера может показать какой-нить 1700й год до нашей эры.

В общем ладно, это все лирика, вот что вышло:

Аскетично, но работает. Прожка может запускаться с ключом, который стартует сканирование, так что можно запускать его раз в сутки по шедулеру и потом смотреть — что же пользователи накидали за прошедшую неделю, нет ли свежих релизов с рутрекера ))

При скролле результатов отсутствующие файлы подсвечиваются красным, список можно сохранить в csv чтобы предъявить владельцу каталога на сервере или его начальнику =) Фильтры поиска можно сохранять (обычно мне нужны медиафайлы размером не менее, список расширений прилагается, в индексе появились за неделю)

Вся эта балалайка разумеется умеет работать под виндой, но и линукс не забыл (была бы макось под рукой, тестил бы код еще и под маком). В качестве базы данных можно использовать или sqlite, базы которого можно рожать прямо из проги, или подключиться к MySQL — мой случай, 20 лямов записей sqlite тупо не вывозит (собственно это проблема большинства несложных индексаторов, какие можно найти в инете)

В общем получилось такое промежуточное решение — простенькое и на скорую руку, не требующее воскуривания мануалов перед использованием, но и не умирающее от большого файлсервера. Да, поиск внутри файлов не умеет, как и кучу других плюшек, так что для домашнего использования скорее всего не пригодится, но мою задачу решает лучше чем что-то похожее, что я использовал (Locate32 — от его интерфейса и возможностей я отталкивался, но он с некоторой периодичностью терял конфиг, жрал под гиг оперативки из-за использования локальных баз, и был виндуз-онли. Хотя в целом прога более чем годная). Так что вот он, первый релиз: https://github.com/qiwichupa/pyFileSearcher/releases также залил на сурсфордж.

Думаю еще пару фишек потом добавить, типа поиска по файлам которые были удалены, потому что оно бывает нужно. Но это как будет время и желание — базовые мои хотелки оно уже удовлетворяет, может кому пригодится тоже =)

 

Папка windows\temp забивается файлами cab_xxxx

Данная проблема вызвана сбоем службы автоматического обновления Windows, в частности при работе с серверами обновлений WSUS.

Пошаговое решение проблемы выглядит так:

  1. Остановка службы обновлений (wuauserv)
  2. Остановка службы trustedinstaller
  3. Удаление содержимого папки c:\windows\temp
  4. Удаление cab-файлов из папки c:\windows\logs\CBS
  5. Удаление папки  C:\windows\softwaredistribution
  6. Запуск сервиса trustedinstaller
  7. Запуск службы обновления

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

fix_winupdate_tmp_cab.ps1
 
  1. $Machine = read-host "Type in the Computer Name"
  2. $windowsUpdateService = 'wuauserv'
  3. $trustedInstallerService = 'trustedinstaller'
  4. function Set-ServiceState
  5. {
  6.     [CmdletBinding()]
  7.     param(
  8.         [string]$ComputerName,
  9.         [string]$ServiceName
  10.     )
  11.     Write-Verbose "Evaluating $ServiceName on $ComputerName."
  12.     [string]$WaitForIt = ""
  13.     [string]$Verb = ""
  14.     [string]$Result = "FAILED"
  15.     $svc = Get-Service -computername $ComputerName -name $ServiceName
  16.     Switch ($svc.status) {
  17.         'Stopped' {
  18.             Write-Verbose "[$ServiceName] is currently Stopped. Starting."
  19.             $Verb = "start"
  20.             $WaitForIt = 'Running'
  21.             $svc.Start()
  22.         }
  23.         'Running' {
  24.             Write-Verbose "[$ServiceName] is Running. Stopping."
  25.             $Verb = "stop"
  26.             $WaitForIt = 'Stopped'
  27.             $svc.Stop()
  28.         }
  29.         default {
  30.             Write-Verbose "$ServiceName is $($svc.status). Taking no action."
  31.         }
  32.     }
  33.     if ($WaitForIt -ne "") {
  34.         Try { # For some reason, we cannot use -ErrorAction after the next statement:
  35.             $svc.WaitForStatus($WaitForIt,'00:02:00')
  36.         } Catch {
  37.             Write-Warning "After waiting for 2 minutes, $ServiceName failed to $Verb."
  38.         }
  39.         $svc = (get-service -computername $ComputerName -name $ServiceName)
  40.         if ($svc.status -eq $WaitForIt) {
  41.             $Result = 'SUCCESS'
  42.         }
  43.         Write-Verbose "$Result - $ServiceName on $ComputerName is $($svc.status)"
  44.         Write-Verbose ("{0} - {1} on {2} is {4}" -f $Result, $ServiceName, $ComputerName, $svc.status)
  45.     }
  46. }
  47. # stop update service
  48. Write-Host "stop update service"
  49. Set-ServiceState -ComputerName $Machine -ServiceName $windowsUpdateService -Verbose
  50. #removes temp files and renames software distribution folder
  51. Write-Host "removes temp files and renames software distribution folder"
  52. Remove-Item \\$Machine\c$\windows\temp\* -recurse
  53. Rename-Item \\$Machine\c$\windows\SoftwareDistribution SoftwareDistribution.old
  54. #restarts update service
  55. Write-Host "restarts update service"
  56. Set-ServiceState -ComputerName $Machine -ServiceName $windowsUpdateService
  57. #removes software distribution.old
  58. Write-Host "removes software distribution.old"
  59. Remove-Item \\$Machine\c$\windows\SoftwareDistribution.old -recurse
  60. #stops trustedinstaller service
  61. Write-Host "stops trustedinstaller service"
  62. Set-ServiceState -ComputerName $Machine -ServiceName $trustedInstallerService
  63. #removes cab files from trustedinstaller
  64. Write-Host "removes cab files from trustedinstaller"
  65. remove-item \\$Machine\c$\windows\Logs\CBS\* -recurse
  66. #restarts trustedinstaller service
  67. Write-Host "restarts trustedinstaller service"
  68. Set-ServiceState -ComputerName $Machine -ServiceName $trustedInstallerService
  69. #rebuilds cab files from WSUS
  70. Write-Host "rebuilds cab files from WSUS"
  71. invoke-command -ComputerName $Machine -ScriptBlock { & cmd.exe "c:\windows\system32\wuauclt.exe /detectnow" }

Источник: https://community.spiceworks.com/topic/495234-windows-temp-file-is-full-of-cab_xxxx-files-on-windows-server-2008-r2