Сегодня ночью завершилась первая игра отборочного тура Yandex.Root — олимпиады для Unix-инженеров и системных администраторов. В ней приняло участие 456 человек из 229 команд, 194 из которых выполнили хотя бы одно задание. Со всеми девятью справилось 38 команд.
Мы проводим Root её в четвёртый раз, но впервые решили опубликовать на Хабре разбор тасков. Задачи, которые мы даём на олимпиаде, сопоставимы с теми, что регулярно решают наши системные администраторы. В Яндексе почти каждый день что-то выкатывается и, когда что-то идёт не так, нужно оперативно распознать это и эффективно отреагировать.
Вообще, соревнования для сисадминов – намного более редкий жанр, чем конкурсы программистов, так что в некотором роде нам приходится здесь быть первопроходцами. Мы очень старались, чтобы задания получились интересными, а также такими, которые действительно проявляли бы в участниках качества, важные в реальной работе. Насколько это у нас получилось, судить вам.
Мы будем благодарны, если вы нам об этом расскажете и поделитесь своим именем, как сделать лучше. Кстати, если хотите, то можете и попробовать себя в реальной игре. Вторая часть первого тура пройдёт через четыре дня — во вторник 14 апреля, и на неё ещё можно зарегистрироваться.
Игра Shannon
Мы решили назвать все игры в память о людях, которые внесли вклад в современные технологии, которые используются в нашей работе. Эта посвящена Клоду Шеннону, инженеру и математику, который среди прочего подарил нам слово «бит». Кстати, сам сервис root.yandex.ru запущен на compute узлах private cloud Яндекса.
Цель отборочной игры — решить несколько проблем на виртуальной машине, изменив конфигурацию установленной ОС: например, запустить службу или скорректировать работу программы. Задачи могут быть как связанными, так и независимыми. Необходимо «зачистить мониторинг», то есть решить проблемы со статусом Critical (отмечены красным цветом) внутри виртуальной машины. Ее образ можно скачать заранее, образ зашифрован — ключ для расшифровки публикуется и рассылается всем участникам по электронной почте в начале игры.
После расшифровки образа необходимо установить соединение с игровым VPN. Для этого всем участникам выдается config-файл: капитан получает его по почте в момент одобрения заявки, члены команды — когда принимают приглашение капитана. В случае утраты файл можно скачать повторно командой «download». Каждый игрок может подключиться к VPN со своей виртуальной машины, поэтому задачи можно распределять внутри команды и решать их параллельно.
Base
В качестве операционной системы в этой игре используется ArchLinux. После загрузки ОС пользователь видит приглашение «shannon login:». Никаких подсказок относительно реквизитов доступа у игрока нет. Как правило, в таких случаях нужно воспользоваться наличием «физического» доступа к машине и сбросить пароль суперпользователя:
- перезагружаемся, останавливаем таймер обратного отсчёта в загрузчике Grub;
- нажимаем 'e', находим строчку linux …, дописываем в конец init=/bin/bash;
- нажимаем Ctrl-X, ждём загрузки;
- вводим команду
passwd
, устанавливаем новый пароль; - вводим команду
exec /sbin/init
, загрузка продолжается.
После выполнения этой процедуры можно войти в систему с новым паролем.
Для решения задач потребуется установить некоторые пакеты, значит, нужно подготовить пакетный менеджер к работе:
- синхронизируемся с внешним зеркалом:
pacman-Sy
,pacman-key --populate
; - обновляем пакетный менеджер:
pacman -S pacman
,pacman-db-upgrade;
- для решения некоторых заданий нам понадобится tcpdump и strace:
pacman -S tcpdump strace.
Внутри игрового образа находится программа game, которая запускает проверочные скрипты (далее — проверки) на удалённом сервере. В случае успешного выполнения проверки, игра засчитывает выполнение задания.
Чтобы обеспечить связность с удалённым сервером, нужно настроить OpenVPN. Организаторы уже подготовили всё необходимое — достаточно скопировать файл конфигурации (он прикреплён к письму от Yandex.Root) в /etc/openvpn/openvpn.conf и выполнить команду systemctl start openvpn@openvpn
.
1.SSL
Это задание было решено первым из всех. Справилась с ним команда SudariLudari. В задаче требуется сгенерировать сертификат, подписанный заданным сертификатом удостоверяющего центра.
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCjKwGnBHUwQtTzLb5uhrh+eRRAQyQwGzCg+n4XWzt8M+iX/OGx
4QCG4GjKhi9Nqzhm41+AjPB5cndU3Oe5j1LrcvWvxe2n15FG7hPSLG5dHe97pzpj
KVma8OkcrUc6WWIccZ48FlV21ZCeUFukthtqEDDEEw1CxEnwHgIydnynlwIDAQAB
AoGADTAfrREmK6VrMtCCsMpAxTAiG+ORXDYGYyx73oVoNGy5ovc0gr0N3tjqf1wD
HML3BxHfmTNLCHXhAUHtlMjpya7kkJELurrFgEQ9gkcdogcf8Iw/J6GjBpJG2WlX
vVL4zEiYw0T5TULGI54Iest0ZQx88EX8r+6x1jI668RHCtECQQDYUPLf2K/0FUyk
csXoKq1ECseSVpfhG5NITqsLOc93jh3xAQFYtSuM7E3CeHkP+ZoKY/SGd9QkWrhd
QQFoGL5vAkEAwRoCwNqlUWwTVayGdgw/D/mxtFelKRYl8kj50MeMraBqHM/ijXZt
+wF5exUmuPio+nF64UIqLA1VCYhnqJ49WQJAL3DJY0hdhnVpYqN9PeamK0cF79Un
6AmpKnF+V67tDjZP4LwstGy/SV/FygGr41IFc4Pqa9c54mM3DdSk31SV5wJAHW9f
mBI8PQsib17bKEd5nW/MfNcXYAn2QtaI7iBc+2KGilnOCQ5SeX6iC/cPbgbJi1Od
DZVOZGSr38YhNvzYEQJBALoFJQEg6Xj44ClcJFIjbA+xyipk4h5JcmGvpUeKfaKF
EBSJMECLR8wIa5XUkeRuM30JhTkd0s3WPUFaoBAvcvs=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDHzCCAoigAwIBAgIJALEwbIlKhnreMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV
BAYTAlJVMQ8wDQYDVQQIEwZNb3Njb3cxDzANBgNVBAcTBk1vc2NvdzEPMA0GA1UE
ChMGWWFuZGV4MQ0wCwYDVQQLEwRSb290MRgwFgYDVQQDEw9yb290LnlhbmRleC5j
b20wHhcNMTUwNDA2MTY0MzA5WhcNMTYwNDA1MTY0MzA5WjBpMQswCQYDVQQGEwJS
VTEPMA0GA1UECBMGTW9zY293MQ8wDQYDVQQHEwZNb3Njb3cxDzANBgNVBAoTBllh
bmRleDENMAsGA1UECxMEUm9vdDEYMBYGA1UEAxMPcm9vdC55YW5kZXguY29tMIGf
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjKwGnBHUwQtTzLb5uhrh+eRRAQyQw
GzCg+n4XWzt8M+iX/OGx4QCG4GjKhi9Nqzhm41+AjPB5cndU3Oe5j1LrcvWvxe2n
15FG7hPSLG5dHe97pzpjKVma8OkcrUc6WWIccZ48FlV21ZCeUFukthtqEDDEEw1C
xEnwHgIydnynlwIDAQABo4HOMIHLMB0GA1UdDgQWBBQG+ykV13EVW9XxCTncLjLV
YVX83TCBmwYDVR0jBIGTMIGQgBQG+ykV13EVW9XxCTncLjLVYVX83aFtpGswaTEL
MAkGA1UEBhMCUlUxDzANBgNVBAgTBk1vc2NvdzEPMA0GA1UEBxMGTW9zY293MQ8w
DQYDVQQKEwZZYW5kZXgxDTALBgNVBAsTBFJvb3QxGDAWBgNVBAMTD3Jvb3QueWFu
ZGV4LmNvbYIJALEwbIlKhnreMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
gYEAmvNk8iAbV4+YMq/9oxkMeB6RxLs9m6jhYyAPuAI/dUhWSX+D+BnRcbsHWK4r
a9G/riM1zerb5BD1apMz3faON2ydFJGB0thjlgr/KXfgaUXjp15QslEhsyhZIgEB
Tak+0BQkkh5+cFAvJhGCZqajr6m2I8Dix3mF3Ey7nSx1GDU=
-----END CERTIFICATE-----
Запишем данные из задания в файлы ca.crt и ca.key соответственно. Теперь посмотрим на сертификат удостоверяющего центра:
# openssl x509 -in ca.crt -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 12767824280512002782 (0xb1306c894a867ade)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=RU, ST=Moscow, L=Moscow, O=Yandex, OU=Root, CN=root.yandex.com
Validity
Not Before: Apr 6 16:43:09 2015 GMT
Not After : Apr 5 16:43:09 2016 GMT
Subject: C=RU, ST=Moscow, L=Moscow, O=Yandex, OU=Root, CN=root.yandex.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:a3:2b:01:a7:04:75:30:42:d4:f3:2d:be:6e:86:
b8:7e:79:14:40:43:24:30:1b:30:a0:fa:7e:17:5b:
3b:7c:33:e8:97:fc:e1:b1:e1:00:86:e0:68:ca:86:
2f:4d:ab:38:66:e3:5f:80:8c:f0:79:72:77:54:dc:
e7:b9:8f:52:eb:72:f5:af:c5:ed:a7:d7:91:46:ee:
13:d2:2c:6e:5d:1d:ef:7b:a7:3a:63:29:59:9a:f0:
e9:1c:ad:47:3a:59:62:1c:71:9e:3c:16:55:76:d5:
90:9e:50:5b:a4:b6:1b:6a:10:30:c4:13:0d:42:c4:
49:f0:1e:02:32:76:7c:a7:97
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
06:FB:29:15:D7:71:15:5B:D5:F1:09:39:DC:2E:32:D5:61:55:FC:DD
X509v3 Authority Key Identifier:
keyid:06:FB:29:15:D7:71:15:5B:D5:F1:09:39:DC:2E:32:D5:61:55:FC:DD
DirName:/C=RU/ST=Moscow/L=Moscow/O=Yandex/OU=Root/CN=root.yandex.com
serial:B1:30:6C:89:4A:86:7A:DE
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
9a:f3:64:f2:20:1b:57:8f:98:32:af:fd:a3:19:0c:78:1e:91:
c4:bb:3d:9b:a8:e1:63:20:0f:b8:02:3f:75:48:56:49:7f:83:
f8:19:d1:71:bb:07:58:ae:2b:6b:d1:bf:ae:23:35:cd:ea:db:
e4:10:f5:6a:93:33:dd:f6:8e:37:6c:9d:14:91:81:d2:d8:63:
96:0a:ff:29:77:e0:69:45:e3:a7:5e:50:b2:51:21:b3:28:59:
22:01:01:4d:a9:3e:d0:14:24:92:1e:7e:70:50:2f:26:11:82:
66:a6:a3:af:a9:b6:23:c0:e2:c7:79:85:dc:4c:bb:9d:2c:75:
18:35
Запросим новый сертификат с теми же значениями:
# openssl req -out cert.csr -new -nodes
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:Moscow
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Yandex
Organizational Unit Name (eg, section) []:Root
Common Name (e.g. server FQDN or YOUR name) []:10.0.0.15
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Подготовим структуру для работы удостоверяющего центра:
# mkdir /etc/ssl/newcerts
# echo 01 > /etc/ssl/serial
# touch /etc/ssl/index.txt
Следующая команда вернёт ошибку, текст которой не столь очевиден:
# openssl ca -cert ca.crt -keyfile ca.key -in cert.csr -out cert.crt
Using configuration from /etc/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
The stateOrProvinceName field needed to be the same in the
CA certificate (Moscow) and the request (Moscow)
На самом деле, проблема заключается в том, что строки в сертификате
удостоверяющего центра и запросе написаны в разных кодировках. Чтобы обойти эту проблему, следует отредактировать файл /etc/ssl/openssl.cnf и изменить значение параметра string_mask
в секции [req]
на pkix
.
Осталось подготовить файлы для веб-сервера:
# mv privkey.pem cert.key
# cat ca.crt >> cert.crt
Теперь установим веб-сервер (pacman -S nginx)
и включим SSL в /etc/nginx/nginx.conf%, раскомментировав соответствующую секцию server{}.
Проверяем:
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# systemctl restart nginx
Но решение не принимается проверяющей системой с диагностикой «SSLv3 is weak». Изменим конфигурацию на рекомендуемую Mozilla:
- отметим опции Nginx и Modern, вставим конфигурацию в nginx.conf;
- сгенерируем параметры Диффи-Хеллмана:
openssl dhparam -out dhparam.pem -outform PEM -2 2048
; - перезапустим nginx:
systemctl restart nginx.
2.MariaDB repair
В этом задании требуется восстановить работу базы данных.
There is a MariaDB database in /var/lib/mysql. We had access there with login 'checker' and password 'masterkey', but something went wrong.
BTW, the `data` table structure was: +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | name | text | YES | | NULL | | | hits | int(11) | YES | | NULL | | | size | int(11) | YES | | NULL | | +-------+---------+------+-----+---------+-------+
Из названия очевидно, что используется база данных MariaDB, известный форк MySQL.
Установим СУБД: pacman -S mariadb
и попробуем запустить systemctl start mysqld
. Из логов видно, что mysqld ищет файлы в неправильном месте. Из файла конфигурации /etc/mysql/my.cnf
видно, что работа системы в сетевом режиме нарушена — добавлены параметры skip-networking, bind-address, указано неправильное значение datadir. Чтобы сэкономить время, не будем пытаться чинить файл конфигурации; вместо этого заменим его на заведомо рабочий:
[mysqld]
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
tmpdir = '/var/tmp'
Поправим владельца файлов — chown -R mysql:mysql /var/lib/mysql
, и попробуем запустить базу данных ещё раз — systemctl restart mysqld
.
Ура, mysqld работает. Попробуем подключиться:
# mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
Видим, что установлена парольная защита, а пароль нам неизвестен/ Значит, как и в случае с операционной системой, придётся сбросить его:
- останавливаем
mysqld: systemctl stop mysqld
; - подготавливаем файл с инструкцией сброса:
echo "UPDATE mysql.user SET password = PASSWORD('root') where user = 'root';" > /tmp/reset.sql
; - запускаем mysqld с загрузкой нашего файла:
mysqld --user=mysql --init-file=/tmp/reset.sql
; - теперь остановим mysqld штатным образом, для этого следует нажать
Ctrl-
; - запустим unit снова —
systemctl start mysqld
После выполнения этой процедуры мы уже можем подключиться к базе данных с паролем root
. Попробуем: mysql -ppassword -uroot
. Из вывода команды show databases
видим факт существования базы db
, но в ней нет таблицы data
. Однако же, эта таблица есть на диске (/var/lib/mysql/db/data.ibd)
. Не хватает table definition (data.frm).
К счастью, задание содержит подсказку, как выглядит таблица, что позволяет реконструировать frm без анализа системных таблиц. Выполним запрос:
create table data2 (name text, hits int(11), size int(11));
Создать таблицу с именем data не получится, так как системные таблицы всё ещё содержат её упоминание. Теперь подключим файл данных к нашей новой таблице. Для этого отключим «пустой» ibd-файл от таблицы: alter table data2 discard tablespace;
, подменим его заполненным mv data.ibd data2.ibd
и подключим обратно alter table data2 import tablespace;
.
Так как db.data до сих пор числится в системных таблицах, то drop table db.data
мы сделать не сможем. Придётся создать временную базу данных, перенести в неё новую таблицу, удалить старую, а затем создать заново:
rename table db.data2 to db2.data;
drop database db;
create database db character set utf8;
rename table db2.data to db.data;
alter table db.data engine = innodb;
Осталось лишь выдать доступ пользователю: grant all privileges on db.* to 'checker'@'%' identified by 'masterkey';
. К сожалению, проверка так и не проходит из-за ошибки подключения. Проверка с помощью tcpdump показывает, что mysqld не отвечает. Проверим фаервол с помощью iptables-save
и обнаружим проблему, оставленную злодеем, — в таблицу nat добавлены ошибочные правила. Однако, их удаление ненадолго восстанавливает работу сети — правила появляются снова.
Как правило, периодические действия вызваны работой crontab. Проверим (crontab -l, cat /etc/cron.* /etc/crontab /etc/cron.d/*)
и удалим все задания текущего пользователя (crontab -r)
.
3.Binary
Run 1.exe
В данном задании нужно запустить «необычную» программу. Из задания нам известно имя файла — «1.exe». Найдём файл на файловой системе и проверим его содержимое:
# find / -iname 1.exe
/root/1/1.exe
# file /root/1/1.exe
/root/1/1.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows
Для запуска .NET-приложений под GNU/Linux существует среда mono. Установим её (pacman -S mono)
и попробуем запустить нашу программу:
# cd /root/1
# mono 1.exe
Но это задание не такое простое, как кажется. В ответ, game вернёт:
Name: Binary
Status: uncompleted
Output: bad program
Попробуем понять, что же делает программа 1.exe. Запуск mono под strace покажет, что программа слушает TCP-сокет и выполняет команды, переданные проверкой. Поверхностный анализ трафика с помощью tcpdump показывает, что программа умеет читать файлы, обращаться к встроенной базе данных и выполнять вычисления. Проверка заканчивает работу после выполнения вычислений, значит, проблема скорее всего заключается в них.
Часто можно извлечь дополнительную информацию, поискав текстовые строки внутри исполняемых файлов. Попробуем воспользоваться этим приёмом — установим пакет программ binutils
и применим программу strings на файл 1.exe. Один фрагмент вывода похож на список библиотек, используемых программой:
System.Core
mscorlib
System.Xml
dnAnalytics
Все эти библиотеки, кроме dnAnalytics, входят в состав mono — это несложно проверить с помощью пакетного менеджера (pacman -Ql mono)
.
4.Mongo
В этом задании нужно развернуть шардированное хранилище MongoDB, записав в него данные, предложенные организаторами.
There is a database in /var/lib/db.tar.gz.
Make a root.features collection with 2 shards and make it available on the standard port.
Для начала установим mongodb: pacman -S mongodb
. Организаторы оставили архив с базой, распакуем его и сделаем архивную копию:
cd /var/lib/mongodb
tar jxf /var/lib/db.tar.bz2
mongod --dbpath db
mongodump
rm -rf db
Для шардирования понадобится специальная служебная база, называемая configdb. Создадим её:
mkdir -p /data/configdb
mongod --configsvr &
Теперь запустим «шардировщик» mongos: mongos --configdb localhost &
. В задании требуется поднять два шарда, поэтому подготовим два экземпляра mongod:
mkdir /var/lib/mongodb/s1 /var/lib/mongodb/s2
mongod --dbpath /var/lib/mongodb/s1 --port 30001 --nojournal &
mongod --dbpath /var/lib/mongodb/s1 --port 30002 --nojournal &
И подключим их к mongos:
# mongo
mongos> sh.addShard("localhost:30001")
mongos> sh.addShard("localhost:30002")
mongos> sh.enableSharding("root")
Теперь осталось загрузить дамп обратно: mognorestore --port 30001 dump/
.
Однако этого недостаточно для решения задачи — коллекция root.features не будет равномерно расшардирована между двумя шардами. Решим эту проблему, создав индекс по идентификатору документа и включив балансировщик:
# mongo root
mongos> db.features.ensureIndex({"_id":"hashed"})
mongos> sh.shardCollection("root.features", {"_id":"hashed"})
mongos> sh.enableBalancing("root.features")
Подождав, пока коллекция перераспределится между шардами, запустим проверку повторно.
5.Strange protocol
Это задание оказалось самым сложным. Собственно, как мы и сами предсказывали.
Set up an echo server on port 13000.
На этот раз нам нужно запустить эхо-сервер на порту 13000.
Это задание кажется простым — действительно, простейшая реализация эхо-сервера уже встроена, например, в xinetd. Запуск tcpdump port 13000 показывает, что обмен происходит по протоколу UDP, но настройка echo-dgram в xinetd не даёт ожидаемого результата.
Посмотрим на трафик внимательнее — снова запустим tcpdump, но уже с параметром -X. Последний пакет кажется интересным:
0x0010: 0a00 000f ebee 32c8 0012 ffd6 656e 6574 ......2.....enet
0x0020: 2065 7272 6f72 .error
Поиск по слову enet
приводит к сайту, описывающему реализацию протокола enet, который позволяет передавать потоки данных через UDP, не заботясь о потере пакетов (как в TCP).
Дальнейший поиск приводит к библиотеке pyenet
, привязке к enet для языка Python, который как раз подойдёт для нашей задачи. Напишем несложную программу:
import enet
import sys
host = enet.Host(enet.Address(b'0.0.0.0', 13000), 100, 0, 0)
while True:
evt = host.service(0)
if evt.type == enet.EVENT_TYPE_RECEIVE:
data = evt.packet.data
evt.peer.send(0, enet.Packet(data))
Осталось установить эти библиотеки:
pacman -S git
git clone git://github.com/aresch/pyenet
cd pyenet
git clone git://github.com/lsalzman/enet
pacman -S cython base-devel
python setup.py build
python setup.py install
Запускаем нашу программу, и проверка на этот раз выполняется успешно.
6.File
Организаторы спрятали root.txt где-то внутри /root/file.
There is a /root/file inside your image. Find a good root.txt file and make it available via image_ip/root.txt.
Попробуем понять, чем же является /root/file:
# file /root/file
/root/file: LVM2 PV (Linux Logical Volume Manager), UUID: XT6zLL-YAUv-nmA9-BSrw-2pBV-CTi2-vqKe35, size: 31457280
Похоже на образ диска. В Linux есть модуль ядра loop, который позволяет превращать файлы в блочные устройства. Воспользуемся им:
losetup /dev/loop0 /root/file
Так как внутри образа диска находится том LVM, подключим его штатными средствами:
# vgchange -ay
1 logical volume(s) in volume group "VolGroup00" now active
Посмотрим, что внутри:
mount /dev/mapper/VolGroup00-lv0 /mnt
ls /mnt
Видим root.txt.gz, распаковываем: gunzip /mnt/root.txt.gz
.
Так как мы уже установили nginx для задания SSL, воспользуемся им для раздачи файла по HTTP:
umount /mnt
mount /dev/mapper/VolGroup00-lv0 /usr/share/nginx/html/
К сожалению, проверка не проходит — мы нашли не тот root.txt. Будем смотреть дальше. Посмотрим, какая у нас файловая система:
# file -s /dev/dm-0
/dev/dm-0: BTRFS Filesystem sectorsize 4096, nodesize 4096, leafsize 4096)
Поскольку в btrfs есть понятние subvolume, посмотрим на их список:
# pacman -S btrfs-progs
# btrfs subvolume list /usr/share/nginx/html/
ID 256 gen 14 top level 5 path root
ID 257 gen 11 top level 5 path root_1
Оказывается, есть ещё один subvolume — root_1. Смонтируем именно его:
umount /usr/share/nginx/html
mount -t btrfs -o subvol=root_1 /dev/mapper/VolGroup00-lv0 /usr/share/nginx/html/
Теперь мы нашли другой файл root.txt.gz. Распакуем его: gunzip/usr/share/nginx/html/root.txt.gz
.
Это и будет решением задачи.
7.MariaDB Tuning
Во время решения задачи MariaDB repair мы починили базу данных, но она работает слишком медленно. Настало время исправить это.
The repaired MariaDB is slow. Tune it up.
Посмотрим, где тормозит наша база. Включим slow query log, куда будут попадать все запросы, выполняющиеся дольше секунды:
mysql -u root -ppassword db
mysql> set global slow_query_log = ON;
mysql> set global long_query_time = 1;
Запускаем проверку и смотрим в лог: tail /var/lib/mysql/shannon-slow.log
.
Видим запрос SELECT COUNT(*) FROM db.data WHERE size < 10;
.
Посмотрим на план запроса:
mysql> explain SELECT COUNT(*) FROM db.data WHERE size < 10 G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: data
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 25061163
Extra: Using where
1 row in set (0.00 sec)
Конечно же, такой запрос выполяется слишком медленно — у нас нет индексов для этого поля. Добавим индекс: mysql> create index data_size on data(size);
.
Повторный запуск проверки покажет нам ту же проблему для data(hits), которую мы решаем аналогичным образом.
8.HG
В /root/repo лежит mercurial
репозиторий, для которого нам надо поправить историю и сделать его доступным через http.
There is a HG repository in /root/repo.
Drop all .gz files in all revisions and make it available via ip:8000/
Первым делом, установим mercurial: pacman -S mercurial
. Изменить историю можно с помощью модуля convert, который по умолчанию отключён. Включим его:
# cat <<EOF > ~/.hgrc
[extensions]
hgext.convert=
EOF
Этот модуль умеет применять правила сопоставления файлов в исходном и целевом репозитории. Такие правила называются filemap
. Напишем и применим правило, которое выкинет файл 2.osm.gz:
echo 'exclude "2.osm.gz"' > /root/fmap
hg convert --filemap ~/fmap /root/repo /root/repo1
После выполнения команды, получим репозиторий /root/repo1, который лишён файла 2.osm.gz во всех ревизиях. Осталось сделать его доступным снаружи. В mercurial есть встроенный веб-сервер, которым мы и воспользуемся:
cd /root/repo1
hg serve
9.Strange File
С этим заданием справилось самое большое количество команд — 151. На файловой системе находится странный файл tester/file, который никто не может изменить.
We got a strange file in ~tester/file. No one can change it. Fix it.
И действительно, файл изменить не получается — даже из-под рута:
# echo test >> ~tester/file
-bash: /home/tester/file: Permission denied
Для начала посмотрим, что у нас за файловая система такая:
# mount | grep ' on / '
/dev/sda2 on / type ext4 (rw,relatime,data=ordered)
Из руководства по ext4 (man 5 ext4)
можно узнать, что файлы на этой ФС могут иметь
следующие атрибуты:
Linux systems using the chattr(1) utility:
a — append only
A — no atime updates
d — no dump
D — synchronous directory updates
i — immutable
S — synchronous updates
u — undeletable
In addition, the ext3 and ext4 filesystems support the following flag:
j — data journaling
Finally, the ext4 filesystem also supports the following flag:
e — extents format
For descriptions of these attribute flags, please refer to the chattr(1) man page.
Посмотрим на страницу chattr(1), где подробно описывается поведение системы для файлов с установленым атрибутом immutable:
Ответ очевиден — нужно снять этот атрибут с файла: chattr -i ~tester/file
. Задача решена.
Автор: kmeaw