<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2russianfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>e0ne's comments</title>
    <description>A Web Developer's Blog!</description>
    <link>http://blog.e0ne.info/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.5.0.7</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://blog.e0ne.info/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://blog.e0ne.info/syndication.axd</blogChannel:blink>
    <dc:creator>e0ne</dc:creator>
    <dc:title>e0ne's comments</dc:title>
    <geo:lat>0.000000</geo:lat>
    <geo:long>0.000000</geo:long>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/e0nesComments" /><feedburner:info uri="e0nescomments" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>e0nesComments</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/e0nesComments" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://lenta.yandex.ru/settings.xml?name=feed&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://lenta.yandex.ru/i/addfeed.gif">?????? ? ??????.?????</feedburner:feedFlare><feedburner:feedFlare href="http://www.flurry.com/pushRssFeed.do?r=fb&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fe0nesComments" src="http://www.flurry.com/images/flurry_rss_logo2.gif">Subscribe with Flurry</feedburner:feedFlare><item>
      <title>Конфигурация сетевых интерфейсов в RHEL-based операционных системах</title>
      <description>&lt;p style="text-align: right;"&gt;Еще один пост из серии "чтоб не забыть и знать где искать".&lt;/p&gt;
&lt;p style="text-align: left;"&gt;По умолчанию, RHEL 6.x и любой другой, основанный на нём (CentOS, Scientific Linux), кроме Fedora, дистрибутив в минимальной установки (в других не проверял) после запуска не поднимает&amp;nbsp;доступные ему сетевые интерфейсы. Для их работоспособности необходимо сделать следующее:&lt;/p&gt;
&lt;p style="text-align: left; padding-left: 30px;"&gt;# ifup eht0&lt;br /&gt;# dhclient eth0&lt;/p&gt;
&lt;p style="text-align: left;"&gt;Первая команда включает сетевой интерфейс eth0, вторая - запускает DHCP Client.&amp;nbsp;&lt;/p&gt;
&lt;p style="text-align: left;"&gt;Рабочую сеть мы получили, но теперь прийдется выполнять данные команды после каждой перезагрузки, что не есть хорошо. Для устранения этого нгедостатка меняем конфиг&lt;/p&gt;
&lt;p style="text-align: left; padding-left: 30px;"&gt;/etc/sysconfig/network-scripts/ifcfg-eth0&lt;/p&gt;
&lt;p style="text-align: left;"&gt;следующим образом:&lt;/p&gt;
&lt;p style="text-align: left; padding-left: 30px;"&gt;ONBOOT="yes"&lt;br /&gt;BOOTPROTO="dhcp"&lt;/p&gt;
&lt;p style="text-align: left;"&gt;Остальные параметры можно оставить без изменений.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=X0dVneJTcNA:dFMd-94kzZ0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=X0dVneJTcNA:dFMd-94kzZ0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=X0dVneJTcNA:dFMd-94kzZ0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=X0dVneJTcNA:dFMd-94kzZ0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/X0dVneJTcNA" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/X0dVneJTcNA/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/network-interface-on-rhel-bases-os.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=5ec66de7-d27b-4421-9586-0b48db8799eb</guid>
      <pubDate>Wed, 15 Feb 2012 20:25:00 +0300</pubDate>
      <category>Linux</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=5ec66de7-d27b-4421-9586-0b48db8799eb</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=5ec66de7-d27b-4421-9586-0b48db8799eb</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/network-interface-on-rhel-bases-os.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=5ec66de7-d27b-4421-9586-0b48db8799eb</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=5ec66de7-d27b-4421-9586-0b48db8799eb</feedburner:origLink></item>
    <item>
      <title>Избавляемся от ошибки "socket.error: [Errno 98] Address already in use" в python</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Время от времени, при разработке очередного API, которое работает поверх HTTP или создается Socket-сервер после остановки и попытки запуска сервера получаю ошибку:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;socket.error: [Errno 98] Address already in use&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Проблема заключается в том, что при аварийном (Ctrl+Z) завершении сервера в операционной системе остается запущенным процесс, который слушает нужный мне порт. В разных ОС время жизни такого процесса разное: в RHEL это около двух минут, в Ubuntu - больше.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Решение достаточно простое. Т.к. при нажатии клавиш Ctrl+Z процесс получает команду &amp;ldquo;keyboard interrupt&amp;rdquo;, то достаточно обработать нужное исключение и корректно завершить процесс:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2012%2f2%2ftry-except.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Надеюсь теперь не буду забывать писать нужный try-except...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Пример кода на GitHub:&amp;nbsp;&lt;a href="https://github.com/e0ne/BlogSamples/tree/master/SocketError"&gt;https://github.com/e0ne/BlogSamples/tree/master/SocketError&lt;/a&gt;. Для его запуска необходимо наличие утановленного пакета SOAPPy.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=QajH1c6y5Zw:Bt9GhzddJS4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=QajH1c6y5Zw:Bt9GhzddJS4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=QajH1c6y5Zw:Bt9GhzddJS4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=QajH1c6y5Zw:Bt9GhzddJS4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/QajH1c6y5Zw" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/QajH1c6y5Zw/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/socket-error-Errno-98-Address-already-in-use-in-python.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=4c968f27-4ebb-43c3-af82-180f9fedd5c6</guid>
      <pubDate>Wed, 08 Feb 2012 13:45:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=4c968f27-4ebb-43c3-af82-180f9fedd5c6</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=4c968f27-4ebb-43c3-af82-180f9fedd5c6</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/socket-error-Errno-98-Address-already-in-use-in-python.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=4c968f27-4ebb-43c3-af82-180f9fedd5c6</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=4c968f27-4ebb-43c3-af82-180f9fedd5c6</feedburner:origLink></item>
    <item>
      <title>Переквалификация программиста - так ли это просто?</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Так как периодически сталкиваюсь с этой темой решил высказать свое мнение и заодно поспорить на тему &amp;ldquo;Насколько легко программисту выучить новый язык и писать на нем&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Я неоднократно слышал утверждения о том, что хорошему программисту выучить новый язык и писать на нем качественный софт/код не составит труда. Со своей стороны, я уже второй раз поменял основной язык, на котором пишу/зарабатываю на хлеб с маслом. Сначала был C#/.NET, как правило, это был веб, ASP.NET/ASP.NET MVC. Часто приходилось писать на JavaScript, потом практически полностью ушел от серверной части и писал Front-end на JS. Переход на JavaScript был для меня безболезненным, даже не смотря на поддержку IE6 :). Тем временем познакомился с Python и через какое-то время перешел полностью на него. Исходя из такого, пусть и небольшого, программерского опыта утверждаю что переход на другой язык программирования - это почти всегда обучение с нуля, переход, грубо говоря, от Senior (которым я себя никогда не считал) к Junior.&lt;/p&gt;
&lt;p&gt;Почему так? Почему нельзя &amp;ldquo;научиться писать на другом языке за две недели/месяц/два месяца&amp;rdquo;? Потому что не все так просто. Даже если взять похожие, на первый взгляд Java и C# то трудностей будет много. Да, синтаксис во много похожий, но знаний только его не достаточно для разработки ПО. Ведь если кто-то выучит 100-200-1000 слов другого языка нельзя же сказать, что человек теперь знает другой язык и может свободно писать/читать/говорить на нем? Почему тогда отношения к программистам и языкам программирования другое? Кроме синтаксиса, есть еще понимание платформы, фреймворков, технологического стека и т.д. Да, синтаксис похож, да, веб-фреймворки, реализующие, например, MVC паттерн чем-то похожи по своей структуре и принципам работы, но все-таки отличия есть.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Смотря на свой код, который писал после прочтения книги что-то вроде &amp;ldquo;Django для чайников&amp;rdquo; мне хочется плакать, выкинуть его и никогда не вспоминать. А ведь код-то рабочий. И делает то, что от него нужно. Но... но стиль мышления у меня тогда был как у asp.net разработчика и многие вещи из python/django мне были не понятны. Тогда я знал синтаксис, но не знал python. IMHO, тут есть очень важный психологический барьер, который не всегда бывает просто преодолеть. Когда нужно признаться себе что ты снова ничего не знаешь и нужно учиться заново, проходить путь от &amp;ldquo;hello world&amp;rdquo; до каких-то сложных приложений. И только когда снова появятся знания и понимания того языка/платформы/фреймворка, на котором пишете, тогда можно будет сказать что вы что-то знаете, а не лезете каждый раз в документацию или ищете похожие примеры.&lt;/p&gt;
&lt;p&gt;Разработку программного обеспечения часто сравнивают со строительством домов. Тут же более удачный, на мой взгляд пример, это категории водителей. Если у вас есть категория В и вы можете водить легковую машину, то насколько легко будет сеть за руль трактора или мотоцикла? А если пустить такого водителя к штурвалу самолета? Никто не пустит... так почему с программистами все иначе? Не знаю, вряд ли на этот риторический вопрос есть достойный ответ...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=w9h3cbj7EWI:Zi8Ktavdn8o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=w9h3cbj7EWI:Zi8Ktavdn8o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=w9h3cbj7EWI:Zi8Ktavdn8o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=w9h3cbj7EWI:Zi8Ktavdn8o:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/w9h3cbj7EWI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/w9h3cbj7EWI/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/decelopers-skills-conversion-does-it-esay.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=6feecb1a-1172-4fc3-94da-0eeded3a3e58</guid>
      <pubDate>Wed, 25 Jan 2012 16:48:00 +0300</pubDate>
      <category>Offtopic</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=6feecb1a-1172-4fc3-94da-0eeded3a3e58</pingback:target>
      <slash:comments>7</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=6feecb1a-1172-4fc3-94da-0eeded3a3e58</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/decelopers-skills-conversion-does-it-esay.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=6feecb1a-1172-4fc3-94da-0eeded3a3e58</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=6feecb1a-1172-4fc3-94da-0eeded3a3e58</feedburner:origLink></item>
    <item>
      <title>virtualenv + pip как альтернатива buildout</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Мне всегда казалось, что для небольших проектов использование buildout - это как с пушки по воробьям: долго, сложно и неудобно. Хотелось чего-то более простого и понятного. И таким оказалась связка virtualenv + pip.&lt;/p&gt;
&lt;p&gt;Про virtualenv я уже писал &lt;a href="http://blog.e0ne.info/post/Python-and-virtualenv.aspx"&gt;тут&lt;/a&gt;. &lt;a href="http://www.pip-installer.org/"&gt;pip&lt;/a&gt; - это замена &lt;a href="http://peak.telecommunity.com/DevCenter/EasyInstall"&gt;easy_install&lt;/a&gt;, менеджер пакетов для python, который позволяет быстро и удобно устанавливать, обновлять и удалять пакеты. Более подробно можно почитать на официальном сайте. Сейчас же меня интересует возможность быстрого развертывания необходимого окружения для запуска проекта. В двух словах, задача выглядит так:&lt;/p&gt;
&lt;p&gt;Нужно запустить проект, который для работы требует следующие пакеты:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Django;&lt;/li&gt;
&lt;li&gt;SQL Alchemy;&lt;/li&gt;
&lt;li&gt;pep8 &amp;amp; pylint для проверки кода.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Стандартный алгоритм решения - создать новое окружение с помощью virtualenv и установить нужные пакеты. Но ведь не делать же это каждый раз каждому разработчику руками? А на build-сервере? Пришедшая мне первая мысль (написание нужного bash-скрипта) к счастью, оказалась не совсем правильной. Т.е. для полной автоматизации небольшой bash-скрипт будет не лишним, но вот устанавливать пакеты проще и правильнее через pip. Итак, как же нам установить все необходимые пакеты?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Шаг 1. Создаем virtual environment&lt;/p&gt;
&lt;p style="padding-left: 30px; "&gt;&lt;em&gt;$ virtualenv ./pip-test/ --no-site-packages&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ключ &lt;em&gt;--no-site-packages&lt;/em&gt; указывает на то, что в нашем окружении не будет доступа к пакетам, установленных в операционной системе. Такая себе чистая, ничем не испачканная песочница.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Шаг 2. Устанавливаем нужные пакеты&lt;/p&gt;
&lt;p&gt;Первый раз все-таки будет необходимо установить все пакеты вручную, т.к. список нужных пакетов на данном этапе бывает далеко не всегда.&lt;/p&gt;
&lt;p style="padding-left: 30px; "&gt;&lt;em&gt;$ pip install Django&lt;br /&gt;$ pip install SQLAlchemy&lt;br /&gt;$ pip install pep8&lt;br /&gt;$ pip install pylint&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Шаг 3. Автоматизируем установку пакетов&lt;/p&gt;
&lt;p&gt;После установки нужных пакетов можно выполнить команду &lt;em&gt;pip freeze -l&lt;/em&gt;, которая выведет на экран список установленных пакетов с их версиями. В моем случае, это выглядит так:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;$ pip freeze -l&lt;br /&gt;Django==1.3.1&lt;br /&gt;SQLAlchemy==0.7.4&lt;br /&gt;logilab-astng==0.23.1&lt;br /&gt;logilab-common==0.57.1&lt;br /&gt;pep8==0.6.1&lt;br /&gt;pylint==0.25.1&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ключ -l выводит пакеты установленный только внутри virtualenv, что при создании окружения с ключем --no-site-packages теряет всякий смысл.&lt;/p&gt;
&lt;p&gt;Далее этот список нужно сохранить:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;$ pip freeze -l &amp;gt; pip-requirements&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Тепреь в файле pip-requirements лежит список всех необходимых для запуска пакетов. Этот нужно положить в вашу source control и при необходимости обновлять.&lt;/p&gt;
&lt;p&gt;Чтобы установить все необходимые пакеты, необходимо выполнить команду:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;$ pip install -r pip-requirements&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Несколько рускоязычных статей про buildout можно найту тут:&amp;nbsp;&lt;a href="http://www.vurt.ru/tag/buildout"&gt;http://www.vurt.ru/tag/buildout&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Ngm1xatCXtM:ih2mL0bRLKs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Ngm1xatCXtM:ih2mL0bRLKs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=Ngm1xatCXtM:ih2mL0bRLKs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Ngm1xatCXtM:ih2mL0bRLKs:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/Ngm1xatCXtM" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/Ngm1xatCXtM/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/virtualenv-and-pip-instead-of-buildout.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=67de7185-31ed-4c73-a95a-7cfa099971f3</guid>
      <pubDate>Wed, 04 Jan 2012 14:01:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=67de7185-31ed-4c73-a95a-7cfa099971f3</pingback:target>
      <slash:comments>8</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=67de7185-31ed-4c73-a95a-7cfa099971f3</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/virtualenv-and-pip-instead-of-buildout.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=67de7185-31ed-4c73-a95a-7cfa099971f3</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=67de7185-31ed-4c73-a95a-7cfa099971f3</feedburner:origLink></item>
    <item>
      <title>Мысли в влух о модульности Django</title>
      <description>&lt;p&gt;
&lt;p&gt;&lt;strong&gt;Все сказанное ниже является личным мнением автора и не является объективной точкой зрения и/или истиной последней инстанции.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Я всегда считал и продолжаю это делать, что Django - не очень-то и модульный фреймворк. Он расширяемый, но не модульный, IMHO. В моем понимании модульный фреймворк, это фреймворк, который состоит из ядра (core), и каких-то модулей, которые можно к нему подключать при желании/необходимости. Но и без них будет доступна минимальная функциональность. В случае же Django - выкинуть из него некоторые модули (e.g. models, template engine) достаточно сложно. Что-бы сделать что-то подобное, необходимо самостоятельно удалять ненужные куски кода, что тянет за собой проверку работоспособности оставшихся частей и прочие неприятности в виде сложной поддержки полученного кода и обновление фреймворка.&lt;/p&gt;
&lt;p&gt;Django - легко расширяемый фреймворк. Это видно по django.contrib и многочисленных сторонних дополнений и приложений. Но при добавлении нового, все-равно есть возможность пользоваться &lt;span style="text-decoration: line-through;"&gt;старыми&lt;/span&gt; стандартными модулями Django.&lt;/p&gt;
&lt;p&gt;Т.к. этот вопрос интересует меня давно, я его задавал одному из Django Core Developers, Andrew Goodwin&amp;rsquo;уб на прошедшем в октябре UA Pycon. Далее в вольном пересказе пишу &lt;strong&gt;его слова так, как я их понял&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Мы знаем об этой проблеме и у нас есть в планах заняться этой задачей. Но есть еще масса более важных задач, которые нужно делать. Поэтому я не могу сказать, когда мы начнем это реализовывать. Также по идеологии Django нужно совместимость версий: код, написанный для текущей версии, должен без изменений работать на следующей.&lt;/p&gt;
&lt;p&gt;И есть еще одна проблема: community хочет не только модульность самого Django, но и возможность использование его компонентов, например models, вне Django. В данной это невозможно, но мы хотим когда-нибудь это сделать&amp;rdquo;&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Несколько ссылок по теме из википедии:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Extensibility"&gt;http://en.wikipedia.org/wiki/Extensibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Modularity_(programming)"&gt;http://en.wikipedia.org/wiki/Modularity_(programming)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=60NgOImyStk:DhsHVp8-gt8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=60NgOImyStk:DhsHVp8-gt8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=60NgOImyStk:DhsHVp8-gt8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=60NgOImyStk:DhsHVp8-gt8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/60NgOImyStk" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/60NgOImyStk/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Thoughts-about-django-modularity.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=ac852116-f5e8-4c34-8333-c583da94dcf3</guid>
      <pubDate>Tue, 03 Jan 2012 15:10:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=ac852116-f5e8-4c34-8333-c583da94dcf3</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=ac852116-f5e8-4c34-8333-c583da94dcf3</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Thoughts-about-django-modularity.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=ac852116-f5e8-4c34-8333-c583da94dcf3</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=ac852116-f5e8-4c34-8333-c583da94dcf3</feedburner:origLink></item>
    <item>
      <title>2012-й: успеть до конца света</title>
      <description>&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2012%2f1%2fkonec_sveta.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Небольшой список того, что хотелось бы сделать в этом году:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;дочитать книги&amp;nbsp;&lt;a href="http://www.amazon.com/Learning-Python-Powerful-Object-Oriented-Programming/dp/0596158068/"&gt;Learning Python&lt;/a&gt;&amp;nbsp;&amp;amp;&amp;nbsp;&lt;a href="http://www.amazon.com/Programming-Python-Mark-Lutz/dp/0596158106/"&gt;Prorgamming Python&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;опрделиться до конца с форматом блога;&lt;/li&gt;
&lt;li&gt;вывести со статуса beta&amp;nbsp;&lt;a href="http://notacash.com"&gt;notacash.com&lt;/a&gt;&amp;nbsp;и доделать там всё, что планировал;&lt;/li&gt;
&lt;li&gt;разобраться с CQRS и дописать брошенное django-cqrs;&lt;/li&gt;
&lt;li&gt;ещё больше перейти на лицензионный контент (в первую очередь софт, книги, музыка);&lt;/li&gt;
&lt;li&gt;прочитать всё из&amp;nbsp;&amp;nbsp;&lt;a href="http://www.etnogenez.ru/book/marusya-3/"&gt;http://www.etnogenez.ru/&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;сделать регулярными встречи &lt;a href="http://kharkivpy.org.ua/"&gt;KharkivPy&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;закончить начатое в 2011-м.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;Как-то так.&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;С Новым годом!&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=2bgZkUMFhN8:bF-M8ViyAoc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=2bgZkUMFhN8:bF-M8ViyAoc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=2bgZkUMFhN8:bF-M8ViyAoc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=2bgZkUMFhN8:bF-M8ViyAoc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/2bgZkUMFhN8" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/2bgZkUMFhN8/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/2012-before-the-end-of-the-world.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=3fac9d23-819b-4d75-8da5-7063b2c59b6b</guid>
      <pubDate>Sun, 01 Jan 2012 23:58:00 +0300</pubDate>
      <category>Offtopic</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=3fac9d23-819b-4d75-8da5-7063b2c59b6b</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=3fac9d23-819b-4d75-8da5-7063b2c59b6b</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/2012-before-the-end-of-the-world.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=3fac9d23-819b-4d75-8da5-7063b2c59b6b</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=3fac9d23-819b-4d75-8da5-7063b2c59b6b</feedburner:origLink></item>
    <item>
      <title>OpenStack + RHEL + iptables = buffer overflow detected</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style="text-align: right; "&gt;&lt;em&gt;Никогда не знаешь, где упадет OpenStack(c)&amp;nbsp;&lt;/em&gt;&lt;br /&gt;Я, в процессе очередного дебагга.&lt;/p&gt;
&lt;p&gt;Те, кто читает мой твиттер (&lt;a href="http://twitter.com/e0ne"&gt;@e0ne&lt;/a&gt;), должны знать, что в последнее время я работаю с &lt;a href="http://openstack.org"&gt;OpenStack&lt;/a&gt;&amp;rsquo;ом, а именно занимаюсь(конечно, не один я) попытками его запуска на Red Hat Enterprise Linux (RHEL), CentOS, Scientific Linux, etc. Т.к. все это построено на базе полной и непросветной enterpise в виде RHEL, то сборка нового дистрибутива, как правило, у меня начинается со сборки именно под эту ОС.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Вот я и хочу поделиться своими впечатлениями от сборки последней версии OpenStack&amp;rsquo;а под RHEL. Началось все с попытки запустить чуть менее чем полностью поломанную версию essex-1. Потом все продолжилось с версией essex-2. Основные моменты, которые мешали мне радоваться жизни - переделки в glance, связанные и security, которые на время поломали работоспособность EC2 API.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Проект Glance - это услуги по отбору, регистрации и поиску виртуальных &amp;laquo;machine images&amp;raquo; (VMI). В рамках Glance используется RESTful API, что позволяет делать запрос метаданных VMI и выполнять поиск фактического образа (VMI). (&lt;a href="http://openstack.ru/openstack_glance.html"&gt;http://openstack.ru/openstack_glance.html&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;И тут я решил попробовать запустить все из последней версии исходников, с master&amp;rsquo;а...&lt;/p&gt;
&lt;p&gt;После небольших усилий инстансы (виртуалки) начали запускаться, но были проблемы с сетью. Команда &amp;ldquo;&lt;em&gt;killall dnsmasq&lt;/em&gt;&amp;rdquo;, подсказанная моим коллегой, решила часть проблем, а именно - выдачу IP адреса виртуальной машине. Далее в логах при загрузке неворуженым глазом были замечены такие проблемы:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fmetadata_error.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Что означало, что запущенный инстанс не может получить данный от&amp;nbsp;&lt;a href="https://blueprints.launchpad.net/nova/+spec/openstack-api-metadata"&gt;Metadata Server&amp;rsquo;а&lt;/a&gt;. Т.к. Metadata Server нормально работал в&amp;nbsp;&lt;a href="http://wiki.openstack.org/ReleaseNotes/Diablo"&gt;Diablo&lt;/a&gt;, то сразу вспомнились 2 вещи:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;файл nova-api-metadata, который помешал успешно собрать RPM с essex-2 используя&amp;nbsp;&lt;a href="http://www.rpm.org/max-rpm/ch-rpm-inside.html"&gt;spec-файл&lt;/a&gt;&amp;nbsp;из Diablo&lt;/li&gt;
&lt;li&gt;и то, что в essex-2 Metadata Server теперь существует отдельно от Nova API (&lt;a href="http://fnords.wordpress.com/2011/12/20/ending-the-year-well-openstack-essex-2-milestone/"&gt;http://fnords.wordpress.com/2011/12/20/ending-the-year-well-openstack-essex-2-milestone/&lt;/a&gt;,&amp;nbsp;&lt;a href="https://blueprints.launchpad.net/nova/+spec/separate-nova-metadata"&gt;https://blueprints.launchpad.net/nova/+spec/separate-nova-metadata&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Далее по аналогии с Nova API был создан файл /etc/init.d/openstack-nova-api-metadata, который предназначался для запуске сервиса Metadata Server&amp;rsquo;а. Metadata Server, на первый взгляд, успешно запустился, то я попытался запустить снова инстанс, что мне привело к предыдущей ошибке. Логи Metadata Server&amp;rsquo;а немного испугали:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fiptables_error.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Мозг сразу начал представлять кошмары, связанные с выводом&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Strace"&gt;strace&lt;/a&gt;, linux kernel debugger&amp;rsquo;ом и так далее. Вовремя опомнившись, я полез в Google. Поиск по &amp;ldquo;&lt;em&gt;exit code 134&lt;/em&gt;&amp;rdquo; ничего полезного не дал. А вот поиск по &amp;ldquo;&lt;em&gt;iptables-restore buffer overflow&lt;/em&gt;&amp;rdquo; дал нужный результат в виде двух багов iptables:&amp;nbsp;&lt;a href="http://bugzilla.netfilter.org/show_bug.cgi?id=641"&gt;http://bugzilla.netfilter.org/show_bug.cgi?id=641&lt;/a&gt;&amp;nbsp;и&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=545600"&gt;https://bugzilla.redhat.com/show_bug.cgi?id=545600&lt;/a&gt;. Довольно-таки стандартное, на сколько мне известно, переполнение буфера, вызванное функцией strcpy, которую, к слову, не очень-то и рекомендуют использовать. Подробности в этом комментарии:&amp;nbsp;&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=545600#c6"&gt;https://bugzilla.redhat.com/show_bug.cgi?id=545600#c6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fiptables_version.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Т.к. обновление iptables в RHEL 6.1 - не самая приоритетная для меня задача, то я решил зайти с другой стороны - посмотреть что же делает OpenStack для получения такого результата.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fmd1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/openstack/nova/blob/master/bin/nova-api-metadata"&gt;https://github.com/openstack/nova/blob/master/bin/nova-api-metadata&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Metadata Server запускается таким же способом, как и другие REST-сервисы Nova, поэтому проблему нужно было искать где-то дальше. Об этом же говорили и логи, и ошибка, связанная с iptables.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/openstack/nova/blob/master/nova/network/linux_net.py"&gt;https://github.com/openstack/nova/blob/master/nova/network/linux_net.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fmd2.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Метод&amp;nbsp;&lt;em&gt;metadata_accept()&lt;/em&gt;&amp;nbsp;отрабатывает без ошибок и падает все в&amp;nbsp;&lt;em&gt;iptables_manager.apply()&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fmd3.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Т.к. данный метод используется далеко не в одном месте&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fmd4.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;то ошибка где-то в передаваемых параметрах. В качестве параметров к&amp;nbsp;&lt;em&gt;iptables-restore&lt;/em&gt;&amp;nbsp;у меня передавалось такое:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;ip-restore-full.jpg&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fip-restore-full.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Зная о баге в iptables и то, что падало все только при запуске Metadata Server&amp;rsquo;а, то получилось быстро найти нужную команду, которая все ломала:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;iptables-restore &amp;lt;&amp;lt;EOF&lt;br /&gt;*nat&lt;br /&gt;:nova-api-metadata-POSTROUTING - [0:0]&lt;br /&gt;-A POSTROUTING -j nova-api-metadata-POSTROUTING&lt;br /&gt;COMMIT&lt;br /&gt;EOF&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;len(&amp;lsquo;nova-api-metadata-POSTROUTING&amp;rsquo;)==29, что вместе с символом конца строки в языке С давало нам 30 символов и при копировании их в массив из 29 символов давало нам переполнение буффера (см. ссылки на баги выше). Хорошо, проблема найдена, теперь нужно ее устранить. Для этого находим код, где у нас генерируется имя chain&amp;rsquo;а:&lt;/p&gt;
&lt;p&gt;chain1.jpg, chain2.jpg&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fchain1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.e0ne.info/image.axd?picture=2011%2f12%2fchain2.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;где:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;binary_name = os.path.basename(inspect.stack()[-1][1])&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Таким образом проблема была в имени исполняемого файла. Переименовав &amp;ldquo;&lt;em&gt;/usr/bin/nova-api-metadata&lt;/em&gt;&amp;rdquo; в &amp;ldquo;&lt;em&gt;/usr/bin/nova-metadata&amp;nbsp;&lt;/em&gt;&amp;rdquo; все заработало. Вопрос лишь в том, насколько долго оно будет работать с таким &amp;ldquo;фиксом&amp;rdquo;?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Более правильное решение нужно делать исправляя код OpenStack&amp;rsquo;а и/или обновляя iptables. Также интересно как это себя ведет на других RHEL-based дистрибутивах(версия iptables) и ubuntu, но это уже проверю завтра, а пока поставил качаться нужные образы дистрибутивов...&lt;/p&gt;
&lt;h3&gt;[Update]&lt;/h3&gt;
&lt;p&gt;Баг с iptables проверен после установки чистой ОС после установки всех апдейтов с помощью команды "&lt;em&gt;yum update&lt;/em&gt;" на следующих ОС:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RHEL 6.1 x86_64 - iptables v1.4.7, buffer overflow detected&lt;/li&gt;
&lt;li&gt;RHEL 6.2 x86_64 -&amp;nbsp;iptables v1.4.7, buffer overflow detected&lt;/li&gt;
&lt;li&gt;CentOS 6.1 x86_64 -&amp;nbsp;iptables v1.4.7&amp;nbsp;buffer overflow detected&lt;/li&gt;
&lt;li&gt;CentOS 6.2 x86_64 -&amp;nbsp;iptables v1.4.7&amp;nbsp;buffer overflow detected&lt;/li&gt;
&lt;li&gt;Scientific Linux&amp;nbsp;6.1 x86_64 -&amp;nbsp;iptables v1.4.7&amp;nbsp;buffer overflow detected&lt;/li&gt;
&lt;li&gt;Fedora 15 x86_64 -&amp;nbsp;testing in process&lt;/li&gt;
&lt;li&gt;Fedora 16 x86_64 -&amp;nbsp;testing in process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=wuH-PGcob0o:uKgZ4-0J24Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=wuH-PGcob0o:uKgZ4-0J24Q:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=wuH-PGcob0o:uKgZ4-0J24Q:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=wuH-PGcob0o:uKgZ4-0J24Q:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/wuH-PGcob0o" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/wuH-PGcob0o/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/OpenStack-and-RHEL-and-iptables-and-buffer-overflow-detected.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=ad30d1e4-3b7e-4db6-a62b-6fbef3af7a5c</guid>
      <pubDate>Fri, 30 Dec 2011 02:42:00 +0300</pubDate>
      <category>Offtopic</category>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=ad30d1e4-3b7e-4db6-a62b-6fbef3af7a5c</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=ad30d1e4-3b7e-4db6-a62b-6fbef3af7a5c</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/OpenStack-and-RHEL-and-iptables-and-buffer-overflow-detected.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=ad30d1e4-3b7e-4db6-a62b-6fbef3af7a5c</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=ad30d1e4-3b7e-4db6-a62b-6fbef3af7a5c</feedburner:origLink></item>
    <item>
      <title>Мобильные сайты на Django</title>
      <description>&lt;p&gt;
&lt;p&gt;Как правило, адаптация сайтов под мобильные устройства заключается в выполнении одного или нескольких пунктов из следующего списка:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;подключения специальной версии CSS;&lt;/li&gt;
&lt;li&gt;подключения нужных JavaScript&amp;rsquo;ов;&lt;/li&gt;
&lt;li&gt;создание мобильных шаблонов (templates) с версткой (html).&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;Сразу оговорюсь, что вопрос мобильной верстки сейчас затрагивать не буду.&lt;/p&gt;
&lt;p&gt;Исходя из этого списка, шаблоны, которые предназначенные для мобильных устройст будут выглядеть, примерно, так:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;{% if request.mobile %}&lt;br /&gt;&amp;nbsp; &amp;nbsp; Mobile&lt;br /&gt;{% else %}&lt;br /&gt;&amp;nbsp; &amp;nbsp; Not mobile&lt;br /&gt;{% endif %}&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Или же наша view поменяет вид на такой:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;def index(request):&lt;br /&gt;&amp;nbsp; &amp;nbsp; if not request.mobile:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return render_to_response('index.html&amp;rsquo;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; else:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return render_to_response('mobile_index.html&amp;rsquo;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Теперь дело за малым - сделать так, чтоб в объекте нашего запроса (request&amp;rsquo;а) появилось свойство mobile. Один из самых простых и достаточно эффективных способов - посмотреть какой &lt;a href="http://en.wikipedia.org/wiki/User_agent"&gt;USER_AGENT&lt;/a&gt; у браузера, который делает запрос. Для этих целей уже есть небольшой, но удобный компонент &lt;a href="http://code.google.com/p/minidetector/"&gt;minidecector&lt;/a&gt;, который анализирует USER_AGENT из запроса и выставляет нужное значение свойства request.mobile.&lt;/p&gt;
&lt;p&gt;minidetector можно подключать двумя способами:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;добавление декоратора detect_mobile к нужной view;&lt;/li&gt;
&lt;li&gt;добавление уже готового Middleware; в этом случае будут обрабатываться все запросы к нашему приложению.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;Небольшой пример использования minidetector лежит на GitHub&amp;rsquo;e: &lt;a href="https://github.com/e0ne/BlogSamples/tree/master/MobileTest"&gt;https://github.com/e0ne/BlogSamples/tree/master/MobileTest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Другие ссылки по теме:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/164427/change-django-templates-based-on-user-agent"&gt;http://stackoverflow.com/questions/164427/change-django-templates-based-on-user-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/minidetector/"&gt;http://code.google.com/p/minidetector/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/2321172/detect-mobile-browser-not-just-iphone-in-python-view"&gt;http://stackoverflow.com/questions/2321172/detect-mobile-browser-not-just-iphone-in-python-view&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;Напомню, что протестировать это на встроеном в Django веб-сервере не получится, т.к. он работает только локально и вы не зайдете на него со своего мобильного устройста. Настройка Django+Apache+mod_wsgi описана тут:&amp;nbsp;&lt;a href="https://code.djangoproject.com/wiki/django_apache_and_mod_wsgi"&gt;https://code.djangoproject.com/wiki/django_apache_and_mod_wsgi&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=zUALS4swIPE:PQHHWBkl1pM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=zUALS4swIPE:PQHHWBkl1pM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=zUALS4swIPE:PQHHWBkl1pM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=zUALS4swIPE:PQHHWBkl1pM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/zUALS4swIPE" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/zUALS4swIPE/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Mobile-sites-on-django.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=d81cc805-42ee-474e-abe3-05ede0516de2</guid>
      <pubDate>Tue, 27 Dec 2011 15:53:00 +0300</pubDate>
      <category>Python</category>
      <category>Web Development</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=d81cc805-42ee-474e-abe3-05ede0516de2</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=d81cc805-42ee-474e-abe3-05ede0516de2</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Mobile-sites-on-django.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=d81cc805-42ee-474e-abe3-05ede0516de2</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=d81cc805-42ee-474e-abe3-05ede0516de2</feedburner:origLink></item>
    <item>
      <title>Объекты в Python: equals or not equals</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Рассмотрим задачу сравнения двух инстансов простого класса A в Python. Сам класс A выглядит так:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;class A(object):&lt;br /&gt;&amp;nbsp; &amp;nbsp; def __init__(self, int_param):&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.int_value = int_param&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;В данном случае, если мы выполним такой код:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;a1 = A(1)&lt;br /&gt;a2 = A(1)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;то инстансы этого классы не будут равны между собой:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;a1 == a2 - False&lt;br /&gt;a1 is a2 - False&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Чтобы понять как это все работает и почему получается такой результат рассмотрим функцию &lt;a href="http://docs.python.org/library/functions.html#id"&gt;id(object)&lt;/a&gt;. Функция id() возвращает идентификатор объекта, который будет уникальным и неизменным на протяжении времени жизни объекта. В CPython эта функция возвращает адрес объекта в памяти. В моем случае это:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;id(a1)=4299743824&lt;br /&gt;id(a2)=4299743888&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Теперь, если мы посмотрим на документацию оператора &lt;a href="http://docs.python.org/reference/expressions.html#notin"&gt;is&lt;/a&gt;, то увидем, что он возвращает True, только в случае, если, в нашем случае a1 и a2, - один и тот же объект. В таком случае, если сделать a3=a1, то получим:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;a3 == a1 - True&lt;br /&gt;a3 is a1 - True&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Оператор &amp;ldquo;==&amp;rdquo; сравнивает объекты с помощью метода &lt;a href="http://docs.python.org/reference/datamodel.html#object.__cmp__"&gt;__cmp__&lt;/a&gt;, который может возвращать одно из 3-х значений:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-1 &amp;nbsp;- в случае, когда один объект &amp;ldquo;меньше&amp;rdquo; (&amp;lt;) другого;&lt;/li&gt;
&lt;li&gt;1 &amp;nbsp;- в случае, когда один объект &amp;ldquo;больше&amp;rdquo; (&amp;gt;) другого;&lt;/li&gt;
&lt;li&gt;0 &amp;nbsp;- объекты равны (==).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Самая простая реализация этого метода выглядит так:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;class B(object):&lt;br /&gt;&amp;nbsp; &amp;nbsp; def __init__(self, int_param):&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; self.int_value = int_param&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; def __cmp__(self, other):&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if self.int_value &amp;lt; other:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return -1&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; elif self.int_value &amp;gt; other:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return 1&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return 0&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;После этого получаем такой вывод:&lt;/p&gt;
&lt;p style="padding-left: 30px;"&gt;&lt;em&gt;b1 = B()&lt;br /&gt;b2 = B()&lt;br /&gt;b1 == b2 - True&lt;br /&gt;b1 is b2 - False&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Примеры кода, традиционно, на GitHub&amp;rsquo;e: &lt;a href="https://github.com/e0ne/BlogSamples/tree/master/PythonEquals"&gt;https://github.com/e0ne/BlogSamples/tree/master/PythonEquals&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=coJBluybxDI:Fhc3gFBYFH8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=coJBluybxDI:Fhc3gFBYFH8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=coJBluybxDI:Fhc3gFBYFH8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=coJBluybxDI:Fhc3gFBYFH8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/coJBluybxDI" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/coJBluybxDI/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Python-objects-equals-or-not-equals.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=f9457c73-1b56-4d6e-b473-77a9ef42ceea</guid>
      <pubDate>Thu, 22 Dec 2011 15:15:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=f9457c73-1b56-4d6e-b473-77a9ef42ceea</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=f9457c73-1b56-4d6e-b473-77a9ef42ceea</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Python-objects-equals-or-not-equals.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=f9457c73-1b56-4d6e-b473-77a9ef42ceea</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=f9457c73-1b56-4d6e-b473-77a9ef42ceea</feedburner:origLink></item>
    <item>
      <title>Git: создаем branch из tag'а</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; margin: 8px;"&gt;
&lt;p&gt;Любая source control система (TFS, SVN, Git и т.д.) умеет работать с такими вещами, как branch (ветка) и tag (метка). Ветки нужны для разработки каких-то фич, исправления багов и т.д., что бы в это время не ломать уже работающий код. Тэги, в свою очередь, нужны для заморозки какой-то версии кода без возможности последующих исправлений. Грязные хаки вроде залезть в базу данных source control чтобы поменять файл с каким-то тэгом я не рассматриваю по понятным причинам.&lt;/p&gt;
&lt;p&gt;В моем случае, изменения в код с каким-то тэгом было связано с задачей сборки новой версии&amp;nbsp;&lt;a href="http://openstack.org/"&gt;Openstack&lt;/a&gt;&amp;nbsp;essex-2 под Red Hat Enterprise Linux (RHEL). Алгоритм работы был, примерно такой:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;забираем исходники Openstack&amp;rsquo;а:&amp;nbsp;&lt;em&gt;$ git clone https://github.com/openstack/nova.git&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;переключаемся на нужный тэг:&amp;nbsp;&lt;em&gt;$ git checkout essex-2&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;делаем необходимые изменения в коде и пытаемся запушить в новый бранч:&amp;nbsp;&lt;em&gt;$ git push myrepo essex-2.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;После данных действий, в моем репозитории, к удивлению, вместо нового бранча с нужными изменениями появился тэг essex-2, который был идентичен такому тэгу с официального репозитория Openstack&amp;rsquo;а. Чтение&amp;nbsp;&lt;a href="http://progit.org/book/ch2-6.html"&gt;Pro Git&lt;/a&gt;&amp;nbsp;расставило все на свои места и стало ясно почему так случилось.&lt;/p&gt;
&lt;p&gt;Далее, для выполнения нужных мне действий понадобилось выполнить команды:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;$ git checkout -b branchname tag&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;$ git push myrepo essex-2&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Что эквивалентно такому:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;$ git branch branchname tag&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;$ git checkout branchname&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;$ git push myrepo essex-2&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Надеюсь что мой пост не помешает правильному использованию тэгов.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=eg6dYwFRXiY:JEuLSxe2a48:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=eg6dYwFRXiY:JEuLSxe2a48:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=eg6dYwFRXiY:JEuLSxe2a48:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=eg6dYwFRXiY:JEuLSxe2a48:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/eg6dYwFRXiY" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/eg6dYwFRXiY/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Git-create-branch-from-tag.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=b90d2587-86cb-4ea5-8c93-5676648bf912</guid>
      <pubDate>Wed, 21 Dec 2011 15:27:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=b90d2587-86cb-4ea5-8c93-5676648bf912</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=b90d2587-86cb-4ea5-8c93-5676648bf912</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Git-create-branch-from-tag.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=b90d2587-86cb-4ea5-8c93-5676648bf912</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=b90d2587-86cb-4ea5-8c93-5676648bf912</feedburner:origLink></item>
    <item>
      <title>Качество кода</title>
      <description>&lt;p&gt;Качественного кода нельзя добиться в случае:&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;нет code review;&lt;/li&gt;
&lt;li&gt;code review проводит один и только один человек;&lt;/li&gt;
&lt;li&gt;нету guidelines;&lt;/li&gt;
&lt;li&gt;проверка кода не происходит на Continius Integration сервере;&lt;/li&gt;
&lt;li&gt;хотя бы один из членов команды не заинтересован в качественном коде;&lt;/li&gt;
&lt;li&gt;время на уменьшение технического долга не закладывается при планировании следующей итерации.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=DClF3Ygajug:ank85jj6v74:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=DClF3Ygajug:ank85jj6v74:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=DClF3Ygajug:ank85jj6v74:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=DClF3Ygajug:ank85jj6v74:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/DClF3Ygajug" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/DClF3Ygajug/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Code-quality.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=6a63d835-e808-49a9-b536-55998a3f87dc</guid>
      <pubDate>Mon, 12 Dec 2011 02:25:00 +0300</pubDate>
      <category>Offtopic</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=6a63d835-e808-49a9-b536-55998a3f87dc</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=6a63d835-e808-49a9-b536-55998a3f87dc</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Code-quality.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=6a63d835-e808-49a9-b536-55998a3f87dc</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=6a63d835-e808-49a9-b536-55998a3f87dc</feedburner:origLink></item>
    <item>
      <title>Form submit: что может быть проще? Часть 1</title>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Казалось бы, отправить (засабмитить) HTML форму на сервер - стандартная задача, которая не должна вызывать никаких проблем и/или вопросов. Но так, как мы не занимаемся сферическим программированием в вакууме, то время от времени появляются трудности, вопросы, проблемы.&lt;/p&gt;
&lt;p&gt;Сегодня на повестки для такая задача:&lt;/p&gt;
&lt;p&gt;Есть страница для бронирования мест в театре/кино и т.д. Выглядит она, примерно, так: &lt;/p&gt;
&lt;img src="http://cabinet.kinocentr.com.ua/cache/hall-scheme/df05a3b48c20677bc945bb7411fdf954dfeff134.png" alt="map"/&gt;
&lt;p&gt;Можно выбрать несколько мест и нажать кнопку &amp;ldquo;Зарезервировать&amp;rdquo;. При этом данные на странице постоянно обновляются (ajax) для отображения актуальной информации о свободных местах. Еще одна проблема - процесс брони места является достаточно долгим, например, 5-10-15 секунд.&lt;/p&gt;
&lt;p&gt;Понятно, что реализация такой задачи полностью зависит от выбранной технологи, но общих подхода тут, как мне кажется, два: делать async form submit (ajax) или обычную синхронную отправку формы на сервер. Ниже я приведу алгоритмы для каждого из случая, которые, на мой взгляд, являются оптимальными для данной задачи.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Синхронный сабмит формы:&lt;/p&gt;
&lt;p&gt;+ Самый простой способ сделать это как на клиенте, так и обработать на сервере.&lt;br /&gt;+ Понятный жизненный цикл страницы.&lt;br /&gt;+ Легко отследить момент завершения запроса и получение ответа от сервера.&lt;br /&gt;- При асинхронном обновлении страницы, необходимо это останавливать, чтобы в POST пошли только нужные данные.&lt;br /&gt;- Необходимо учитывать, что при долгой обработке запроса весь UI &amp;ldquo;замирает&amp;rdquo;.&lt;br /&gt;- При сабмите формы асинхронные запросы, посылаемые в этот момент, могут завершиться с ошибкой и есть шансы получить javascript error (при правильном подходе и использовании jQuery такое бывает не часто).&lt;br /&gt;- Ну и напоследок, не модно как-то, не &amp;ldquo;вебдванольно&amp;rdquo; когда весь UI замирает на 10-15 секунд.&lt;/p&gt;
&lt;p&gt;Плюсов и минусов в этом подходе одинаково (не считая последний минус), но обработка ситуаций, связанных с первыми двумя &amp;ldquo;-&amp;rdquo; может потратить много времени и нервов. &amp;nbsp;Описание алгоритма такого обработчика - не имеет смысла, т.к. все достаточно стандартно. Единственное, что стоит отметить, так это то, что долговременные операции можно выполнять в отдельном потоке (не забывая про ограничения среды выполнения и веб-сервера), а еще лучше - запускать это в каком-то application server/service, но тогда теряется вся простота реализации.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Асинхронный сабмит формы:&lt;/p&gt;
&lt;p&gt;+ Весь UI остается, в общем случае, полностью работоспособен.&lt;br /&gt;+ Пользователь не видит никаких тормозов страницы.&lt;br /&gt;- Сложнее реализовывать, чем первый вариант.&lt;br /&gt;- Баги, связанные с асинхронностью никто не отменял.&lt;/p&gt;
&lt;p&gt;Стандартный алгоритм такого решения выглядит так (не рассматриваю ситуацию, когда пользователь уходит со страницы):&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;делается асинхронный(ajax) POST формы на сервер;&lt;/li&gt;
&lt;li&gt;пока ждем ответа от сервера где-то на UI сообщаем пользователю что &amp;ldquo;запрос выполняется, подождите немного&amp;rdquo;;&lt;/li&gt;
&lt;li&gt;в случае успешного запроса показываем пользователю сообщение с ссылкой на страницу с более детальной информацией;&lt;/li&gt;
&lt;li&gt;в случае ошибки (500-я или тайм-аут) показываем сообщение и предлагаем попробовать еще раз&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;В этом подходе получается больше логики на клиентской стороне, но при этом в любой момент времени у нас остается полностью рабочий UI.&lt;/p&gt;
&lt;p&gt;На этом все. В следующий раз я покажу на примерах, как реализовывать тот или иной способ.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=HgA6UbIffsQ:8z_1qr-kwOg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=HgA6UbIffsQ:8z_1qr-kwOg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=HgA6UbIffsQ:8z_1qr-kwOg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=HgA6UbIffsQ:8z_1qr-kwOg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/HgA6UbIffsQ" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/HgA6UbIffsQ/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Form-submit-what-could-be-easier-part-1.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=4efa001f-2f12-4733-abd7-c8e609f5f8e3</guid>
      <pubDate>Tue, 22 Nov 2011 13:36:00 +0300</pubDate>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=4efa001f-2f12-4733-abd7-c8e609f5f8e3</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=4efa001f-2f12-4733-abd7-c8e609f5f8e3</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Form-submit-what-could-be-easier-part-1.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=4efa001f-2f12-4733-abd7-c8e609f5f8e3</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=4efa001f-2f12-4733-abd7-c8e609f5f8e3</feedburner:origLink></item>
    <item>
      <title>Первая встреча харьковского Python Community Kharkiv.Py</title>
      <description>&lt;p&gt;В Киеве ежегодно проходит PyCon, переодически собираются встречи Kyiv.Py - жизнь python community по немного идет своим ходом. А вот в Харькове, к сожалению, ничего подобного не было (не считая DevTime прошедшей весной). Вот мне и хахотелось собрать харькоское python community для общения, обменом знаниями и опытом.&lt;/p&gt;
&lt;p&gt;Подробности на&amp;nbsp;&lt;a href="http://kharkivpy.org.ua/"&gt;http://kharkivpy.org.ua/&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=b51Zm9cI70I:Dw2JAGi4cSU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=b51Zm9cI70I:Dw2JAGi4cSU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=b51Zm9cI70I:Dw2JAGi4cSU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=b51Zm9cI70I:Dw2JAGi4cSU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/b51Zm9cI70I" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/b51Zm9cI70I/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/KharkivPy-1.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=f5fc4459-3a0f-49f3-bbfe-e996f0632547</guid>
      <pubDate>Wed, 09 Nov 2011 13:06:00 +0300</pubDate>
      <category>Events</category>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=f5fc4459-3a0f-49f3-bbfe-e996f0632547</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=f5fc4459-3a0f-49f3-bbfe-e996f0632547</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/KharkivPy-1.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=f5fc4459-3a0f-49f3-bbfe-e996f0632547</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=f5fc4459-3a0f-49f3-bbfe-e996f0632547</feedburner:origLink></item>
    <item>
      <title>Установка компилятора gcc на Mac OS Lion</title>
      <description>&lt;p&gt;При установке пакетов psycopg2 и lxml easy_install радостно падал с криками:&lt;/p&gt;
&lt;p&gt;
&lt;p&gt;unable to execute gcc-4.2: No such file or directory&lt;br /&gt;error: command 'gcc-4.2' failed with exit status 1&lt;/p&gt;
&lt;/p&gt;
&lt;p&gt;Вполне логично, т.к. gcc у меня не стоял :(. Странно только что в Snow Leopard все работало. Немного полазив по инету нашел, что gcc ставится вместе с XCode, который ставится бесплатно из Mac App Store. Но и это не сразу помогло. Ниже привожу список шагов, которые понадобились для установки gcc и&amp;nbsp;psycopg2 после этого.&lt;/p&gt;
&lt;p&gt;&lt;ol&gt;
&lt;li&gt;Из Mac App Store устанавливаем XCode.&lt;/li&gt;
&lt;li&gt;Добавляем в переменную PATH путь к gcc:&amp;nbsp;export PATH=$PATH:/Developer/usr/bin&lt;/li&gt;
&lt;li&gt;Чтобы работало после перезагрузки и для всех пользователей прописываем этот путь и в&amp;nbsp;/etc/paths&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=KizL8wkVio4:lnozGNqj8NQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=KizL8wkVio4:lnozGNqj8NQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=KizL8wkVio4:lnozGNqj8NQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=KizL8wkVio4:lnozGNqj8NQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/KizL8wkVio4" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/KizL8wkVio4/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Install-gcc-on-Mac-OS-Lion.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=e14b55b6-4d4b-42ea-adcf-59d84ccfba17</guid>
      <pubDate>Fri, 28 Oct 2011 14:47:00 +0300</pubDate>
      <category>Python</category>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=e14b55b6-4d4b-42ea-adcf-59d84ccfba17</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=e14b55b6-4d4b-42ea-adcf-59d84ccfba17</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Install-gcc-on-Mac-OS-Lion.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=e14b55b6-4d4b-42ea-adcf-59d84ccfba17</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=e14b55b6-4d4b-42ea-adcf-59d84ccfba17</feedburner:origLink></item>
    <item>
      <title>Тестирование проекта: должны ли все тесты проходить успешно</title>
      <description>&lt;p&gt;&lt;img src="http://lettuce.it/_images/screenshot1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Хорошо когда код покрыт тестами. Хорошо когда кроме модульных тестов есть еще интеграционные, функциональные, UI-тесты и другие. Но должны ли тесты _всегда_ проходить успешно? Казалось бы, очевидный ответ - да. Но не все так просто...&lt;/p&gt;
&lt;p&gt;Хороший тест должен выполняться успешно, когда все работает и показывать ошибку если где-то что-то не так. Он должен тестировать только то, что задумывалось и кричать(зчк) сообщать если ожидаемый результат (expetced result) отличается от того, что мы получили при выполнении нашей программы. Но и из этого правила есть исключения.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;К примеру, при написании когда, мы используем методологию TDD (Test Driven Development). В таком случае, только что написанные тесты никогда не выполнятся успешно, так как кода и функциональности, которую мы тестируем еще нет. Соответственно, если мы напишем n-е количество тестов, то наш билд нашего проекта всегда будет &amp;ldquo;failed&amp;rdquo;. Но при данном подходе это не должно мешать коммитить код в репозиторий и запускать все тесты автоматически на сервере &lt;a href="http://blog.e0ne.info/post/Continuous-integration-(CI)-what-is-it.aspx"&gt;CI&lt;/a&gt;. Вначале билд будет валиться, но с каждой реализованной фичей все больше тестов будет проходить успешно и ваш проект вскоре снова начнет собираться успешно.&lt;/p&gt;
&lt;p&gt;Еще более интересная ситуация с тестами получается когда наше приложение использует сторонние библиотеки. Тут нам приходится работать с чужим кодом и/или со сторонней программой/API, исходников которой(го) у нас нет. Но тестировать-то надо. При этом у нас получаются интеграционные тесты, которые проверяют взаимодействие нашего кода с чужим.&lt;/p&gt;
&lt;p&gt;В таком случае мы не можем контролировать работоспособность некоторых компонентов системы. Логично предположить, что тут тесты будут падать и это будет нормальным поведением. В большинстве случаев так и есть. Но бывают и другие ситуации:&lt;/p&gt;
&lt;p&gt;Мы используем какой-то компонент SomeUsfulComponent, у которого должны быть две функции: FeatureA и FeatureB. И если хотя бы одна из них не работает, то тесты, которые проверяют взаимодействие нашей программы с этими функциями будут падать. А так как неработающие тесты на билд сервере - это поломанный билд, то дальше мы ничего делать уже не можем. Эта ситуация тоже вполне логичная. Вот только, например, мы в нашей программе можем обойтись без функции FeatureB. Как нам быть?&lt;/p&gt;
&lt;p&gt;Тут, на мой взгляд, есть несколько решений данной проблемы. Привожу их в порядве &amp;ldquo;возрастания правильности&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;ol&gt;
&lt;li&gt;Отключить тесты, которые падают из-за сторонних компонентов. Главный минус такого подхода - нужно помнить, что нужно когда-то проверить что эти тесты уже работают правильно и снова их включить.&lt;/li&gt;
&lt;li&gt;В процессе сборки проекта никак не реагировать на провалившиеся тесты. Если вы используете &lt;a href="http://jenkins-ci.org/"&gt;Jenkins&lt;/a&gt;, то на время можно сказать что при падении тестов продолжать дальше собирать билд. Минусы такого подхода - можно не увидеть, что упали другие тесты и продолжать спокойно работать.&lt;/li&gt;
&lt;li&gt;Учитывать в тестах, что FeatureB из SomeUsfulComponent бросает исключение NotImplementedException и в случае такого исключения говорить что тест выполнен успешно. В таком случае, как только FeatureB заработает корректно, наши тесты снова начнут падать и мы сможем быстро их исправить путем выкидывания ненужного уже кода.&lt;/li&gt;
&lt;li&gt;Сделать так, чтоб FeatureB работала :). Если это opensource проект, то тут все легче. Если исходников нет, но есть платная поддержка - получить рабочую версию как можно быстрее тоже можно, но не всегда. Иначе, скорее всего, ждать получится достаточно долго и обходится без нужной нам функциональности.&lt;/li&gt;
&lt;/ol&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Mpm4bsDFo50:fRxkBVccYjA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Mpm4bsDFo50:fRxkBVccYjA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?i=Mpm4bsDFo50:fRxkBVccYjA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/e0nesComments?a=Mpm4bsDFo50:fRxkBVccYjA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/e0nesComments?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/e0nesComments/~4/Mpm4bsDFo50" height="1" width="1"/&gt;</description>
      <link>http://feedproxy.google.com/~r/e0nesComments/~3/Mpm4bsDFo50/post.aspx</link>
      <author>e0ne</author>
      <comments>http://blog.e0ne.info/post/Project-testing-should-test-always-be-successful.aspx#comment</comments>
      <guid isPermaLink="false">http://blog.e0ne.info/post.aspx?id=e723736b-8701-4a09-9a25-9c26fcaf3340</guid>
      <pubDate>Thu, 27 Oct 2011 16:00:00 +0300</pubDate>
      <dc:publisher>e0ne</dc:publisher>
      <pingback:server>http://blog.e0ne.info/pingback.axd</pingback:server>
      <pingback:target>http://blog.e0ne.info/post.aspx?id=e723736b-8701-4a09-9a25-9c26fcaf3340</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://blog.e0ne.info/trackback.axd?id=e723736b-8701-4a09-9a25-9c26fcaf3340</trackback:ping>
      <wfw:comment>http://blog.e0ne.info/post/Project-testing-should-test-always-be-successful.aspx#comment</wfw:comment>
      <wfw:commentRss>http://blog.e0ne.info/syndication.axd?post=e723736b-8701-4a09-9a25-9c26fcaf3340</wfw:commentRss>
    <feedburner:origLink>http://blog.e0ne.info/post.aspx?id=e723736b-8701-4a09-9a25-9c26fcaf3340</feedburner:origLink></item>
  </channel>
</rss>

