Однажды в студеную зимнюю пору, пришли ко мне как обычно с паяльником.
Задача: есть у нас сервер в Rackspace, на полном фарше. На сервере неонка крутится база на MS SQL Web Edition. И вот внезапно ребятки спохватились — а куда еженощный бэкап девать? А то превышать он стал все разумные пределы, а пользы от его хранения на диске того же инстанса — чуть.
Как та мудрая сова из анекдота, я им предложил настроить средства облака из консольки. И был жестоко истыкан горячими острыми предметами — оказывается, сервер там не просто стар, а очень стар, висит он там на древнючем каком-то плане, у которого и нет ничего доступного, одни Cloud Files. И поменять — это надо идти к большому боссу уважаемой конторы, которая 200 лет на рынке. А большой босс им зарплату платит не за то чтобы они к нему за такими вещами ходили.
Я страшно удивился и спросил — а что, это так сложно — на коленке скрипт изваять? И запускать его аккурат после того как БД отбэкапится?
Мне снова популярно объяснили, с применением зеленых изображений дохлых президентов, что у них уважаемая контора, им 200 лет, не царское это дело скрипты рисовать. А поскольку у меня с ними много чего по вполне серьезным поводам пересекается, пришлось помочь.
Мало ли, вдруг кому-то еще будет полезно, поэтому про эти скрипты подробнее расскажу.
Подготовка
Изучение мануала нам подсказывает, что для работы с облаком достаточно установить Curl. Однако мы им не поверим и поставим весь MSYS, который идет в комплекте с MinGW.
И заполним файлик про логин:
<?xml version="1.0" encoding="UTF-8"?>
<credentials xmlns="http://docs.rackspacecloud.com/auth/api/v1.1" username="LOGIN" key="RS API KEY"/>
Этот файлик мы будем скармливать рэкспейсу, чтобы получить токен. Без такого токена мы дальше не продвинемся.
Также, для остроты ощущений, писать мы будем досовские бат-файлы, чтобы враг не догадался. На самом деле, изобретать что-то более сложное просто нет смысла, они все в 5 строк получаются. Структура каждого из них вот такая
@echo off
setlocal
set PATH="%PATH%;C:MinGWmsys1.0bin
...
endlocal
поэтому приведу ее один раз.
Login
Токен, который действует аж 24 часа, мы получим вот так:
curl -k -X POST -d @mylogin.xml -H "Content-Type: application/xml" -H "Accept: application/xml" https://auth.api.rackspacecloud.com/v1.1/auth > auth-token.xml
cat auth-token.xml | sed -e 's/.*token id=.//' | sed -e 's/..expires=.*//g' > token
Суровое смешение стилей — но зато у нас есть первый скрипт, он же login.bat. И — токен как результат его работы. Токен мы в дальнейшем можем использовать вот так
set /p TOKEN=<token
Создаем контейнер для бэкапов
Теперь нам надо определиться — куда мы будем складывать бэкапы и как именно. Схемы могут быть разные и и достаточно вычурные, но мы возьмем простейший случай. Представим на минутку что у нас есть обычный дифференциальный бэкап, и все что нам надо — это его раз в сутки заливать в определенное место.
set /p TOKEN=<token
curl -k -X PUT -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup
И мы определили это место, контейнер называется Backup. Свои именования — по вкусу.
Заливаем — первая попытка
А теперь попробуем залить туда что-нибудь:
set /p TOKEN=<token
curl -# -k -X PUT -T %1 -H "Content-Type: application/octet-stream" -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1
А что там лежит?
Отвлечемся на минутку, а как мы увидим — что там вообще есть?
set /p TOKEN=<token
curl -# -k -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1
После запуска, мы увидим список того что есть в контейнере, например вот так
4.0.327-RC1.rar
5.0.709-RELENG-spfix.rar
5.5.907-spfix.rar
foo.bak
Что успели залить на прошлом шаге, то и лежит, логично.
Скачаем обратно
Это в общем-то очевидно — просто урл с токеном.
set /p TOKEN=<token
curl -# -o %1 -k -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1
Передаем параметром имя файла — работает!..
А теперь — горбатый!
Если бы дело было только в этом, я бы пост не писал.
Внедряем это в продакшен, то есть копируем скрипт на сервер, и… ба-бам! превышен размер пост-запроса. Логично — мы же для тестов заливали файлы небольшие, а дамп БД превышает 50 гигабайт.
Заливка больших файлов — попытка номер два
Значит ли это, что целиком дамп БД мы залить не можем?
И да и нет.
Одним запросом залить мы его не можем, это факт. Но получить на сервере один файл в 50+ гигабайт — можем. Заливать можно по частям, а затем эти части объединить в один файл.
Для этого, я приведу весь фрагмент, а затем разберем его подробнее.
set /p TOKEN=<token
split -d --bytes=500m %1 %1.parts.
ls %1.parts.* | awk 'BEGIN{x=0; print "@echo off"; }{ ++x; print "echo Uploading part " x "...ncurl -# -k -X PUT -T " $1 " -H "Content-Type: application/octet-stream" -H "X-Auth-Token: TOKEN" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/FNN/" x " --data-binary '" x "'" }' | sed -e s/FNN/%1/g | sed -e s/TOKEN/%TOKEN%/g > _1.bat
echo curl -# -k -X PUT -H "X-Auth-Token: TOKEN" -H "X-Object-Manifest: Backup/%1/" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1 --data-binary '' | sed -e s/TOKEN/%TOKEN%/g >> _1.bat
call _1.bat
echo Clearing...
rm -f _1.bat %1.parts.*
Итак, сначала нам надо порезать большой файл на кусочки:
split -d --bytes=500m %1 %1.parts.
После чего мы займемся кодоложеством в тяжелой форме, а именно — построим из нашего скрипта второй скрипт, который и сделает всю работу.
ls %1.parts.* | awk 'BEGIN{x=0; print "@echo off"; }{ ++x; print "echo Uploading part " x "...ncurl -# -k -X PUT -T " $1 " -H "Content-Type: application/octet-stream" -H "X-Auth-Token: TOKEN" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/FNN/" x " --data-binary '" x "'" }' | sed -e s/FNN/%1/g | sed -e s/TOKEN/%TOKEN%/g > _1.bat
Простым трюком ls %1.parts.* | awk мы на каждый кусочек получим свою команду. Вот такую
curl -# -k -X PUT -T foo.parts.0 -H "Content-Type: application/octet-stream" -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/foo.0 --data-binary 0
curl -# -k -X PUT -T foo.parts.1 -H "Content-Type: application/octet-stream" -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/foo.1 --data-binary 1
curl -# -k -X PUT -T foo.parts.2 -H "Content-Type: application/octet-stream" -H "X-Auth-Token: %TOKEN%" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/foo.2 --data-binary 2
...
где foo — имя переданного нам файла в комстроке.
Остался последний штрих — склеить это все воедино:
echo curl -# -k -X PUT -H "X-Auth-Token: TOKEN" -H "X-Object-Manifest: Backup/%1/" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1 --data-binary '' | sed -e s/TOKEN/%TOKEN%/g >> _1.bat
что нам даст в свежегенерированном батнике вот такое последней строчкой:
curl -# -k -X PUT -H "X-Auth-Token: %TOKEN%" -H "X-Object-Manifest: Backup/foo/" https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_d3125ab9-8601-45ba-a432-edf3728673bb/Backup/%1 --data-binary
Профит! Мы таки научились заливать большие файлы в облако и доставать их оттуда.
Надеюсь, этот поток индусского кода окажется кому-то полезным.
Автор: viklequick