Никогда не знаешь, где упадет OpenStack(c) 
Я, в процессе очередного дебагга.

Те, кто читает мой твиттер (@e0ne), должны знать, что в последнее время я работаю с OpenStack’ом, а именно занимаюсь(конечно, не один я) попытками его запуска на Red Hat Enterprise Linux (RHEL), CentOS, Scientific Linux, etc. Т.к. все это построено на базе полной и непросветной enterpise в виде RHEL, то сборка нового дистрибутива, как правило, у меня начинается со сборки именно под эту ОС. 

Вот я и хочу поделиться своими впечатлениями от сборки последней версии OpenStack’а под RHEL. Началось все с попытки запустить чуть менее чем полностью поломанную версию essex-1. Потом все продолжилось с версией essex-2. Основные моменты, которые мешали мне радоваться жизни - переделки в glance, связанные и security, которые на время поломали работоспособность EC2 API. 

Проект Glance - это услуги по отбору, регистрации и поиску виртуальных «machine images» (VMI). В рамках Glance используется RESTful API, что позволяет делать запрос метаданных VMI и выполнять поиск фактического образа (VMI). (http://openstack.ru/openstack_glance.html)

И тут я решил попробовать запустить все из последней версии исходников, с master’а...

После небольших усилий инстансы (виртуалки) начали запускаться, но были проблемы с сетью. Команда “killall dnsmasq”, подсказанная моим коллегой, решила часть проблем, а именно - выдачу IP адреса виртуальной машине. Далее в логах при загрузке неворуженым глазом были замечены такие проблемы:

 

Что означало, что запущенный инстанс не может получить данный от Metadata Server’а. Т.к. Metadata Server нормально работал в Diablo, то сразу вспомнились 2 вещи:

 

 

Далее по аналогии с Nova API был создан файл /etc/init.d/openstack-nova-api-metadata, который предназначался для запуске сервиса Metadata Server’а. Metadata Server, на первый взгляд, успешно запустился, то я попытался запустить снова инстанс, что мне привело к предыдущей ошибке. Логи Metadata Server’а немного испугали:

 

Мозг сразу начал представлять кошмары, связанные с выводом strace, linux kernel debugger’ом и так далее. Вовремя опомнившись, я полез в Google. Поиск по “exit code 134” ничего полезного не дал. А вот поиск по “iptables-restore buffer overflow” дал нужный результат в виде двух багов iptables: http://bugzilla.netfilter.org/show_bug.cgi?id=641 иhttps://bugzilla.redhat.com/show_bug.cgi?id=545600. Довольно-таки стандартное, на сколько мне известно, переполнение буфера, вызванное функцией strcpy, которую, к слову, не очень-то и рекомендуют использовать. Подробности в этом комментарии: https://bugzilla.redhat.com/show_bug.cgi?id=545600#c6

 

 

Т.к. обновление iptables в RHEL 6.1 - не самая приоритетная для меня задача, то я решил зайти с другой стороны - посмотреть что же делает OpenStack для получения такого результата.

 

 

https://github.com/openstack/nova/blob/master/bin/nova-api-metadata

Metadata Server запускается таким же способом, как и другие REST-сервисы Nova, поэтому проблему нужно было искать где-то дальше. Об этом же говорили и логи, и ошибка, связанная с iptables.

https://github.com/openstack/nova/blob/master/nova/network/linux_net.py

 

Метод metadata_accept() отрабатывает без ошибок и падает все в iptables_manager.apply().

 

Т.к. данный метод используется далеко не в одном месте

 

 

то ошибка где-то в передаваемых параметрах. В качестве параметров к iptables-restore у меня передавалось такое:

 ip-restore-full.jpg

 

 

Зная о баге в iptables и то, что падало все только при запуске Metadata Server’а, то получилось быстро найти нужную команду, которая все ломала:

iptables-restore <<EOF
*nat
:nova-api-metadata-POSTROUTING - [0:0]
-A POSTROUTING -j nova-api-metadata-POSTROUTING
COMMIT
EOF

len(‘nova-api-metadata-POSTROUTING’)==29, что вместе с символом конца строки в языке С давало нам 30 символов и при копировании их в массив из 29 символов давало нам переполнение буффера (см. ссылки на баги выше). Хорошо, проблема найдена, теперь нужно ее устранить. Для этого находим код, где у нас генерируется имя chain’а:

chain1.jpg, chain2.jpg

 

где:

binary_name = os.path.basename(inspect.stack()[-1][1])

Таким образом проблема была в имени исполняемого файла. Переименовав “/usr/bin/nova-api-metadata” в “/usr/bin/nova-metadata ” все заработало. Вопрос лишь в том, насколько долго оно будет работать с таким “фиксом”? 

Более правильное решение нужно делать исправляя код OpenStack’а и/или обновляя iptables. Также интересно как это себя ведет на других RHEL-based дистрибутивах(версия iptables) и ubuntu, но это уже проверю завтра, а пока поставил качаться нужные образы дистрибутивов...

[Update]

Баг с iptables проверен после установки чистой ОС после установки всех апдейтов с помощью команды "yum update" на следующих ОС:

  • RHEL 6.1 x86_64 - iptables v1.4.7, buffer overflow detected
  • RHEL 6.2 x86_64 - iptables v1.4.7, buffer overflow detected
  • CentOS 6.1 x86_64 - iptables v1.4.7 buffer overflow detected
  • CentOS 6.2 x86_64 - iptables v1.4.7 buffer overflow detected
  • Scientific Linux 6.1 x86_64 - iptables v1.4.7 buffer overflow detected
  • Fedora 15 x86_64 - testing in process
  • Fedora 16 x86_64 - testing in process

 


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

  • подключения специальной версии CSS;
  • подключения нужных JavaScript’ов;
  • создание мобильных шаблонов (templates) с версткой (html).

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

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

{% if request.mobile %}
    Mobile
{% else %}
    Not mobile
{% endif %}

 

Или же наша view поменяет вид на такой:

def index(request):
    if not request.mobile:
        return render_to_response('index.html’)
    else:
        return render_to_response('mobile_index.html’)

Теперь дело за малым - сделать так, чтоб в объекте нашего запроса (request’а) появилось свойство mobile. Один из самых простых и достаточно эффективных способов - посмотреть какой USER_AGENT у браузера, который делает запрос. Для этих целей уже есть небольшой, но удобный компонент minidecector, который анализирует USER_AGENT из запроса и выставляет нужное значение свойства request.mobile.

minidetector можно подключать двумя способами:

  • добавление декоратора detect_mobile к нужной view;
  • добавление уже готового Middleware; в этом случае будут обрабатываться все запросы к нашему приложению.

Небольшой пример использования minidetector лежит на GitHub’e: https://github.com/e0ne/BlogSamples/tree/master/MobileTest

 

Другие ссылки по теме:

Напомню, что протестировать это на встроеном в Django веб-сервере не получится, т.к. он работает только локально и вы не зайдете на него со своего мобильного устройста. Настройка Django+Apache+mod_wsgi описана тут: https://code.djangoproject.com/wiki/django_apache_and_mod_wsgi


 

Рассмотрим задачу сравнения двух инстансов простого класса A в Python. Сам класс A выглядит так:

class A(object):
    def __init__(self, int_param):
        self.int_value = int_param

В данном случае, если мы выполним такой код:

a1 = A(1)
a2 = A(1)

то инстансы этого классы не будут равны между собой:

a1 == a2 - False
a1 is a2 - False

Чтобы понять как это все работает и почему получается такой результат рассмотрим функцию id(object). Функция id() возвращает идентификатор объекта, который будет уникальным и неизменным на протяжении времени жизни объекта. В CPython эта функция возвращает адрес объекта в памяти. В моем случае это:

id(a1)=4299743824
id(a2)=4299743888

Теперь, если мы посмотрим на документацию оператора is, то увидем, что он возвращает True, только в случае, если, в нашем случае a1 и a2, - один и тот же объект. В таком случае, если сделать a3=a1, то получим:

a3 == a1 - True
a3 is a1 - True

Оператор “==” сравнивает объекты с помощью метода __cmp__, который может возвращать одно из 3-х значений:

 

  • -1  - в случае, когда один объект “меньше” (<) другого;
  • 1  - в случае, когда один объект “больше” (>) другого;
  • 0  - объекты равны (==).

 

 

Самая простая реализация этого метода выглядит так:

class B(object):
    def __init__(self, int_param):
        self.int_value = int_param

    def __cmp__(self, other):
        if self.int_value < other:
            return -1
        elif self.int_value > other:
            return 1
        else:
            return 0

После этого получаем такой вывод:

b1 = B()
b2 = B()
b1 == b2 - True
b1 is b2 - False

Примеры кода, традиционно, на GitHub’e: https://github.com/e0ne/BlogSamples/tree/master/PythonEquals

 


Git: создаем branch из tag'а

Published 12/21/2011 by e0ne in Python
Tags: ,

 

Любая source control система (TFS, SVN, Git и т.д.) умеет работать с такими вещами, как branch (ветка) и tag (метка). Ветки нужны для разработки каких-то фич, исправления багов и т.д., что бы в это время не ломать уже работающий код. Тэги, в свою очередь, нужны для заморозки какой-то версии кода без возможности последующих исправлений. Грязные хаки вроде залезть в базу данных source control чтобы поменять файл с каким-то тэгом я не рассматриваю по понятным причинам.

В моем случае, изменения в код с каким-то тэгом было связано с задачей сборки новой версии Openstack essex-2 под Red Hat Enterprise Linux (RHEL). Алгоритм работы был, примерно такой:

 

  • забираем исходники Openstack’а: $ git clone https://github.com/openstack/nova.git
  • переключаемся на нужный тэг: $ git checkout essex-2
  • делаем необходимые изменения в коде и пытаемся запушить в новый бранч: $ git push myrepo essex-2.

 

После данных действий, в моем репозитории, к удивлению, вместо нового бранча с нужными изменениями появился тэг essex-2, который был идентичен такому тэгу с официального репозитория Openstack’а. Чтение Pro Git расставило все на свои места и стало ясно почему так случилось.

Далее, для выполнения нужных мне действий понадобилось выполнить команды: 

 

  • $ git checkout -b branchname tag
  • $ git push myrepo essex-2

 

Что эквивалентно такому:

 

  • $ git branch branchname tag
  • $ git checkout branchname
  • $ git push myrepo essex-2

 

Надеюсь что мой пост не помешает правильному использованию тэгов.

 


Качество кода

Published 12/12/2011 by e0ne in Offtopic

Качественного кода нельзя добиться в случае:

  • нет code review;
  • code review проводит один и только один человек;
  • нету guidelines;
  • проверка кода не происходит на Continius Integration сервере;
  • хотя бы один из членов команды не заинтересован в качественном коде;
  • время на уменьшение технического долга не закладывается при планировании следующей итерации.