суббота, 12 июля 2014 г.

Windows: Поднимаем из бэкапов базы MSSQL на другой машине

Рассмотрим такую гипотетическую ситуацию (которая не далее как сегодня утром реализовалась на практике, но это неважно).

Есть у нас компьютер WinServA, на котором живёт-поживает и добра наживает Microsoft SQL Server 2005, хранящий все свои базы в каталоге E:\MSSQL\Data. И вот в один не очень прекрасный день этот сервер умирает. Скажем, отказали диски. Ага, сразу все. Возникает задача - поднять базу на другом, девственно чистом сервере WinServB, который до этого спокойно управлялся ОС Windows 2008, ни сном, ни духом не ведал о каких-то SQL Server-ах две тысячи пятого затёртого года и вообще, имеет свободное место только на диске D:.

Для этого нам понадобится: 1) бэкапы дорогих нашему сердцу баз, 2) бэкапы системных баз почившего сервера 3) немного валидола.

Шаг первый - поднимаем Microsoft SQL Server 2005 на Windows 2008.

Тут возможны всяческие чудеса. Например, однажды MSSQL отказывался ставиться до тех пор, пока система не притворилась, что у неё один процессор. Сегодня же нас порадовали другой ошибкой - в процессе установки MSSQL Native Client вываливается сообщение Error 1603, а файлы логов в папке C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG содержат примерно такое разъяснение:
An error occurred during the installation of assembly 'Microsoft.VC80.CRT,type="win32",version="8.0.50727.42",publicKeyToken="1fc8b3b9a1e18e3b",processorArchitecture="x86"'. Please refer to Help and Support for more information. HRESULT: 0x80070BC9. assembly interface: IAssemblyCacheItem, function: Commit, component: {98CB24AD-52FB-DB5F-A01F-C8B3B9A1E18E}
Решением оказалось в реестре прописать параметр:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control 
Key: RegistrySizeLimit 
Type: REG_DWORD 
Value: 0xffffff (4294967295)
перезагрузиться и прогнать инсталляцию ещё раз.

Дальше интереснее. Для второго шага требуется, чтобы версии старого и нового SQL Server-ов совпадали. Умерший сервер был версии 9.0.5057. Новый, после установки SP4 - 9.0.5000. Очевидно, на старый сервер накатывались какие-то обновления Центром обновлений. Но какие? Тут приходит на помощь вот эта таблица. В частности, в нашем случае помогает установка kb2494120. И можно переходить к следующему шагу.

Шаг второй - восстанавливаем системные базы из бэкапов.

На самом деле хватает трёх бэкапов: master, msdb и model. Но ситуация осложняется тем, что отличаются пути, по которым жили базы на старом сервере и на новом. Помолясь, поступаем так:
a) Находим в списке сервисов сервис MSSQLSERVER и останавливаем его. В свойствах сервиса прописываем параметр командной строки -m и запускаем сервис снова. После этого СУБД стартует в однопользовательском режиме.
b) Заходим в Microsoft SQL Server Management Studio, оно предложит законнектиться к какой-нибудь базе, мы отказываемся. Нажимаем кнопку "New Query" и пишем следующее:
RESTORE DATABASE master FROM DISK='c:\temp\master.bak' WITH REPLACE
Нажимаем конпку "Execute", указываем наконец, к какой базе прицепиться, и ждём.
Сервер сообщит, что база данных восстановлена, и работа будет продолжена после перезапуска сервиса. Фигушки, с восстановленной базой сервис запускаться откажется, указав примерно такую причину в системном журнале Windows: Could not open file E:\MSSQL\Data\mssqlsystemresource.mdf
c) Тут самое время запустить SQL Server из командной строки примерно такой командой:
"C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe" -f -T3608
Сервер снова станет доступным, и тогда через Microsoft SQL Server Management Studio удастся сменить пути для всех системных баз на их реальное местоположение в новом сервере:
ALTER DATABASE mssqlsystemresource modify file (name=data,filename='D:\MSSQL\Data\mssqlsystemresource.mdf')
ALTER DATABASE mssqlsystemresource modify file (name=log,filename='D:\MSSQL\Data\mssqlsystemresource.ldf')
ALTER DATABASE msdb modify file (name=MSDBData,filename='D:\MSSQL\Data\msdbdata.mdf')
ALTER DATABASE msdb modify file (name=MSDBLog, filename='D:\MSSQL\Data\msdblog.ldf')
ALTER DATABASE model modify file (name=modeldev,filename='D:\MSSQL\Data\model.mdf')
ALTER DATABASE model modify file (name=modellog, filename='D:\MSSQL\Data\modellog.ldf')
ALTER DATABASE tempdb modify file (name=tempdev,filename='D:\MSSQL\Data\tempdb.mdf')
ALTER DATABASE tempdb modify file (name=templog, filename='D:\MSSQL\Data\templog.ldf')
Кстати, есть способ посмотреть, какие пути каким базам назначены, выполнив команду:
SELECT name, physical_name
FROM sys.master_files
d) После этого можно попробовать вновь запустить штатно сервис MSSQLSERVER и восстановить оставшиеся системные базы:
RESTORE DATABASE msdb FROM DISK='C:\temp\msdb.bak' WITH REPLACE
RESTORE DATABASE model FROM DISK='C:\temp\model.bak' WITH REPLACE

По завершении этой процедуры у нас в руках оказывается живой сервер с восстановленными системными базами.

Шаг третий - восстанавливаем из бэкапов интересующие нас базы.

Это уже делается тривиально, со штатным использованием соответствующих пунктов контекстного меню Microsoft SQL Server Management Studio. Единственное - каждую базу придётся перед восстановлением из бэкапа пересоздать.

Шаг четвертый - пытаемся запустить SQL Server Agent.

Если тот не хочет стартовать с ошибкой Error creating a new session, значит, что-то не слава богу с правами. Нам помогло следующее:
a) на сервере выполнили команды:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Agent XPs', 1;
GO
RECONFIGURE
GO
b) В группу пользователей SQLServer2005SQLAgentUser$ServerName добавили учетную запись, под которой сервис этого самого агента у нас запускается. Не знаем точно, что из этого помогло, но больше SQL Server Agent нам не жаловался.

Шаг пятый - выставляем правильное имя сервера в планах обслуживания.

Если были настроены какие-то планы обслуживания, то в них нужно поменять свойства локальных подключений (Local connection). Сделать это можно либо через редактирование планов в Microsoft SQL Server Management Studio (кнопка Manage connections), либо выполнив вот такой скрипт:
use msdb

-- указываем имя старого сервера
DECLARE @oldservername as varchar(max)
SET @oldservername='WinServA'

-- указываем имя нового сервера
declare @newservername as varchar(max)
set @newservername='WinServB'

declare
    @planid      uniqueidentifier,
    @xml         varchar(max),
    @planname    varchar(max)

-- вытаскиваем все планы, в строке подключения которых значится старый сервер
DECLARE PlansToFix LOCAL STATIC CURSOR FOR
SELECT
    id
FROM sysdtspackages90
WHERE (CAST(CAST(packagedata AS varbinary(MAX)) AS varchar(MAX)) LIKE '%server=''' + @oldservername + '%')

OPEN PlansToFix
FETCH NEXT FROM PlansToFix INTO @planid

WHILE (@@fetch_status != -1)
    BEGIN

    if (@@fetch_status != -2)
        begin

        -- получаем имя плана и его содержимое в виде xml-строки
        select
            @xml = cast(cast(packagedata as varbinary(max)) as varchar(max)),
            @planname = name
        from sysdtspackages90
        where id = @planid

        -- печатаем пользователю, какой план патчим
        print 'Changing ' + @planname + ' server from ' + @oldservername + ' to ' + @newservername

        -- меняем упоминания старого сервера на новый
        set @xml = replace(@xml,'server=''' + @oldservername + '''','server=''' + @newservername +'''')

        -- обновляем план
        UPDATE sysdtspackages90
        SET packagedata = cast(@xml as varbinary(max))
        WHERE id = @planid

        end

    FETCH NEXT FROM PlansToFix INTO @planid  

    END

CLOSE PlansToFix
DEALLOCATE PlansToFix

Вот, собственно, и всё.

вторник, 8 июля 2014 г.

понедельник, 7 июля 2014 г.

Windows: настраиваем резервное копирование с помощью rsync

Дано:
1) Компьютер WinSRV под управлением Windows 2008 с установленной на нём СУБД SQL Server 2012 Express и развёрнутой базой MyDatabase. Будем считать, что аккаунт с административными правами называется winuser.
2) Компьютер DebSRV под управлением Debian 6.0, доступный по ssh (порт 12345) с логином debuser, и содержащий папку, предназначенную для резервных копий: /media/backup/.

Задача:
Настроить ежедневное резервное копирование баз с первого компьютера на второй.

Решение:

Выбираем инструментарий. Предлагаем на стороне WinSRV использовать:
1) Архиватор 7-zip, установленный в папке c:\Program Files\7-Zip
2) rsync из пакета cygwin. Этот пакет установлен в папке c:\cygwin64 и помимо rsync содержит, в частности утилиты ssh.exe и ssh-keygen.exe, которые нам понадобятся.

На компьютере WinSRV создаём рабочую папку для задачи архивирования, c:\backup.
В этой папке создаём два вспомогательных файла.
Файл backup.sql:
-- создаём резервную копию базы MyDatabase
BACKUP DATABASE MyDatabase TO DISK='c:\backup\MyDatabase.bak'

-- создаём резервные копии системных баз
BACKUP DATABASE master TO DISK='c:\backup\master.bak'
BACKUP DATABASE model TO DISK='c:\backup\model.bak'
BACKUP DATABASE msdb TO DISK='c:\backup\msdb.bak'
Файл filelist.txt:
c:\backup\MyDatabase.bak
c:\backup\master.bak
c:\backup\model.bak
c:\backup\msdb.bak
Создаём командный файл backup.bat:
rem создаём бэкапы баз
"c:\Program Files\Microsoft SQL Server\110\Binn\SQLCMD.exe" -U (логин к базе) -P (пароль к базе) -S . -i c:\backup\backup.sql -o c:\backup\log.txt

rem архивируем бэкапы в один файл
"c:\Program Files\7-Zip\7z.exe" -a -r -p(пароль к архиву) c:\backup\MSSQL_%date:~10,4%%date:~7,2%%date:~4,2%.7z @c:\backup\filelist.txt -xr!*.log

rem передаём архив на сервер DebSRV при помощи rsync
c:\cygwin64\bin\rsync.exe -e "/bin/ssh.exe -p 12345" -t /cygdrive/c/backup/MSSQL_%date:~10,4%%date:~7,2%%date:~4,2%.7z debuser@DebSRV:/media/backup

rem удаляем лишние файлы
del c:\backup\MSSQL_%date:~10,4%%date:~7,2%%date:~4,2%.7z c:\backup\MyDatabase.bak c:\backup\master.bak c:\backup\model.bak c:\backup\msdb.bak

Настраиваем доступ на сервер DebSRV по ssh без пароля. Мы сделали это так:
1) На сервере WinSRV создали приватный и публичный ключ командой:
c:\cygwin64\bin\ssh-keygen.exe -t dsa -N ''
результатом работы этой утилиты являются два файла, c:\cygwin64\home\winuser\.ssh\id_dsa и c:\cygwin64\home\winuser\.ssh\id_dsa.pub
2) Закинули публичную часть ключа на сервер DebSRV (предполагается, что папка /home/debuser/.ssh/ на этом сервере уже есть):
c:\cygwin64\bin\rsync.exe -e "/bin/ssh.exe -p 12345" -t /home/winuser/.ssh/id_dsa.pub debuser@DebSRV:~
дальше заходим на сервер DebSRV по ssh
ssh debuser@DebSRV -p 12345
и добавляем содержимое файла id_dsa.pub в файл ~/.ssh/authorized_keys2:
cat id_dsa.pub >> ~/.ssh/authorized_keys2
rm id_dsa.pub

После этого на компьютере WinSRV в планировщике задач ставим на выполнение файл c:\backup\backup.bat от имени winuser с нужным расписанием, и всё.

воскресенье, 8 июня 2014 г.

Linux: создаём зашифрованный контейнер

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

В середине весны у меня на служебном компьютере умер очередной винчестер, и стало ясно, что так продолжаться не может. Хоть я потерял и не сильно критичные файлы - какие-то старые бэкапы и пиратские дистрибутивы - но это событие всё равно оказалось, что называется, close call. Поэтому было принято стратегическое решение: упорядочить свои данные и работу с ними. Сделал я это следующим образом.

Во-первых, был выполнен аудит имеющейся в моём распоряжении информации и произведено её разделение на три неравные части:

1) Критически важная: продукты моего труда (исходники программ, какие-то запросы, заметки, уникальные документы и т.п.), логины-пароли и т.д.

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

3) Не важная: дистрибутивы, скачанные с инета, временные файлы и т.д. В общем, всё, что можно восстановить или не сильно жалко потерять.

Во-вторых, принят регламент дальнейшей работы:

1) В качестве операционной системы использовать Linux.

2) Те задачи, которые не могут быть перенесены под линукс и которые нужно решать по долгу службы (в частности, у нас существенно используются .NET приложения, часть из которых разрабатывал я сам), будут жить на виртуальной машине под управлением Oracle VM VirtualBox.

3) Не раскидываться по компьютерам. Не должно быть такого: что-то дома, что-то на работе, что-то вообще непонятно, где. Всё, что я делаю, должно храниться в одном месте.

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

Лучшим решением, наверно, было бы переселиться на ноутбук. Но, во-первых, тупо нет лишних денег, и, во-вторых, лень таскать его с работы домой и обратно. Поэтому в качестве паллиатива был прикуплен внешний жесткий диск (3Q 500Гб USB 2.0) за 1800 рублей. Дальше предполагалось следующее:

1) создать четыре криптоконтейнера (критически важная, важная и не важная информация плюс виртуальная машина)

2) копировать их ежедневно на свой домашний компьютер

3) криптоконтейнер с критически важной информацией закидывать в DropBox (это, кстати, накладывает ограничение на объем этого криптоконтейнера - 2 Гб и служит одной из причин наличия приставки "крипто-" во всей этой истории вообще)

И всё получилось как нельзя лучше, но дальше началась та самая "невезуха". В качестве средства для создания криптоконтейнеров я выбрал знакомый мне с незапамятных виндовских времён TrueCrypt 7.1a. Это было в конце апреля. В конце мая вышеуказанный проект начало как-то подозрительно колбасить, и это заставило меня начать поиск альтернатив.

И тут выяснилась поразительная вещь. Оказывается, всё это время у меня под носом тихо лежало всё необходимое для создания полноценных криптоконтейнеров! Я имею в виду cryptsetup с LUKS. Удивительная всё-таки штука этот линукс. Делается подобное, как я понял, так:

1) Создаётся файл myContainer нужного размера:
dd if=/dev/urandom of=myContainer bs=1M count=2048

2) Этот файл превращается в криптоконтейнер:
sudo cryptsetup luksFormat myContainer

3) Просматривается список занятых loopback-устройств:
sudo losetup -a
и находится первое свободное, скажем, /dev/loop0. Либо это можно сделать сразу командой:
sudo losetup -f

4) Криптоконтейнер ассоциируется с этим свободным устройством:
sudo losetup /dev/loop0 myContainer
либо, опять-таки, минуя п.3 всё это делается сразу:
sudo losetup -f myContainer

5) Открывается криптоконтейнер командой:
sudo cryptsetup luksOpen /dev/loop0 LUKSmyContainer

6) Содержимое криптоконтейнера форматируется командой:
sudo mkfs -t ext4 /dev/mapper/LUKSmyContainer

7) Теперь можно примонтировать криптоконтейнер к заранее созданной точке myMountpoint:
sudo mount /dev/mapper/LUKSmyContainer myMountpoint

То есть в итоге получается такая цепочка:
файл myContainer -> устройство /dev/loop0 -> устройство LUKSmyContainer -> точка монтирования myMountpoint

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

После того, как работа завершена, можно отключить этот криптоконтейнер, выполнив последовательность команд:
sudo umount myMountpoint
sudo cryptsetup luksClose LUKSmyContainer
sudo losetup -d /dev/loop0

Кстати, ещё один приятный момент: cryptsetup всю работу с loopback-устройствами может взять на себя. Так что, если мне потребуется примонтировать криптоконтейнер, я могу воспользоваться более простым вариантом:
sudo cryptsetup luksOpen myContainer LUKSmyContainer
sudo mount /dev/mapper/LUKSmyContainer myMountpoint
(Кстати, в убунте вторая команда не требуется - устройство подхватывается и монтируется автоматически.)

Соответственно, при отключении криптоконтейнера в этом случае понадобятся всего две команды:
sudo umount myMountpoint
sudo cryptsetup luksClose LUKSmyContainer
(И снова кстати - в убунте при отключении тома через файловый менеджер Thunar никаких дополнительных команд не требуется вообще.)

Ну и напоследок: чтобы посмотреть все подключенные в данный момент устройства, включая и криптоконтейнеры, достаточно выполнить команду:
lsblk --fs

вторник, 27 мая 2014 г.

Linux: RDP через SSH

Дано:
1) Сервер my-rdp-server во внешнем инете, доступный по RDP;
2) Домашний компьютер my-ssh-server, доступный по ssh;
3) Корпоративный http-прокси с ntlm-авторизацией;
4) Рабочая станция с линуксом и программой rdesktop.
Проблема следующая: как попасть на сервер my-rdp-server с рабочего компьютера?

Решение:
1) поднимаем cntlm
2) пускаем ssh через этот самый cntlm (как это сделать, см., например, тут)
3) поднимаем ssh-туннель командой:
ssh -N -f -L 3389:my-rdp-server:3389 my-login@my-ssh-server
4) цепляемся к туннелю командой:
rdesktop -g 1024x720 localhost:3389

Литература:
man ssh
http://rus-linux.net/MyLDP/sec/SSH-Tunneling.html

воскресенье, 25 мая 2014 г.

Linux: организуем proxy при помощи SSH

Дано:
1) Корпоративный http-прокси с ntlm-авторизацией;
2) Рабочая станция с линуксом;
3) Домашний компьютер my-ssh-server, доступный по ssh.
Проблема следующая: как гулять по интернету с рабочего компьютера так, чтобы не сильно светиться на корпоративном прокси?

Решение:
1) поднимаем cntlm
2) пускаем ssh через этот самый cntlm (как это сделать, см., например, тут)
3) поднимаем socks-прокси командой:
ssh -N -f -D localhost:12345 my-login@my-ssh-server
4) прописываем localhost:12345 в качестве socks4-сервера в своём браузере.

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

суббота, 24 мая 2014 г.

TrueCrypt: кодировка

В общем, есть некий том (или как его там правильно, криптоконтейнер), который был создан под Windows, содержит файловую систему fat-32 и файлы с папками, названные по-русски. При попытке смонтировать этот том под убунтой вместо кириллических имен получаются знаки вопроса. Чтобы это победить, нужно при подключении в Mount options (это в окне ввода пароля кнопка "Options >") указать:
iocharset=utf8