<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Destaquenet blog &#187; django</title>
	<atom:link href="http://weblog.destaquenet.com/tag/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://weblog.destaquenet.com</link>
	<description>O Blog da equipe Destaquenet</description>
	<pubDate>Wed, 03 Dec 2008 11:08:11 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Deployment de aplicações Python com Fabric</title>
		<link>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/</link>
		<comments>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/#comments</comments>
		<pubDate>Sun, 05 Oct 2008 10:00:05 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
		
		<category><![CDATA[Programação]]></category>

		<category><![CDATA[capistrano]]></category>

		<category><![CDATA[deployment]]></category>

		<category><![CDATA[dicas]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[fabric]]></category>

		<category><![CDATA[ferramenta]]></category>

		<category><![CDATA[python]]></category>

		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=101</guid>
		<description><![CDATA[Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos frameworks utilizados no projeto. Não há o que discutir.
Na verdade, ninguém parecia se importar em automatizar tarefas &#8220;mecânicas&#8221; como o deployment, coisa que mudou de figura [...]]]></description>
			<content:encoded><![CDATA[<p>Uma coisa é fato: subir uma nova versão de uma aplicação é um procedimento que, se feito manualmente, costuma demandar tempo precioso, independente do tamanho da aplicação e dos <em>frameworks</em> utilizados no projeto. Não há o que discutir.</p>
<p>Na verdade, ninguém parecia se importar em automatizar tarefas &#8220;mecânicas&#8221; como o <em>deployment</em>, coisa que mudou de figura ao passo que <a href="http://en.wikipedia.org/wiki/Agile_software_development">metodologias ágeis</a> &#8212; juntamente com técnicas como <a href="http://martinfowler.com/articles/continuousIntegration.html">Integração Contínua</a> &#8212; passaram a se tornar populares. Desde então, algum esforço vem sendo investido para criar ferramentas para automatização de muitas dessas tarefas. <span id="more-101"></span></p>
<h3>Fabric: ferramenta Python para deployment</h3>
<p>Apesar de já ter utilizado algumas dessas <a href="http://maven.apache.org/">ferramentas</a> no desenvolvimento de projetos em <a href="http://java.sun.com/">Java</a>, plataforma na qual eu possuo uma experiência maior, eu ainda não conhecia nenhuma ferramenta em <a href="http://python.org/">Python</a> que me permitisse automatizar o <em>deployment</em> de uma aplicação.</p>
<p>Como eu estava começando a ficar de saco cheio de ter que atualizar os arquivos de uma aplicação <a href="http://djangoproject.org/">Django</a> via SCP, eu resolvi que já era hora de ir atrás de alguma ferramenta que me ajudasse a automatizar esse processo. Finalmente, depois de muita procura, eu encontrei <a href="http://www.nongnu.org/fab/index.html">Fabric</a>, uma ferramenta mais ou menos parecida com um <a href="http://www.capify.org/">Capistrano</a> &#8220;capado&#8221;.</p>
<p>A instalação do Fabric é bem simples para quem costuma usar o <a href="http://peak.telecommunity.com/DevCenter/EasyInstall">easy_install</a>:</p>
<pre>daniel ~ $ sudo easy_install Fabric</pre>
<p>Basta executar esse comando para que os fontes da última versão do Fabric (0.0.9 no momento da publicação deste texto) sejam baixados e instalados.</p>
<p><strong>Atenção</strong>: Quem utiliza máquinas Windows, provavelmente precisará do <a href="http://www.cygwin.com/">Cygwin</a>, já que o Fabric assume o uso de ambientes Unix.</p>
<h3>Fabric a 3.000 pés</h3>
<p>Neste momento você já deve conseguir executar o comando <code>fab</code> no terminal. Se tudo correu bem até aqui, estamos prontos continuar.</p>
<p>Vamos começar criando o arquivo <code>fabfile.py</code> no diretório-raíz da aplicação. Coloque o seguinte conteúdo neste arquivo:</p>

<div class="wp_syntax"><div class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #008000;">set</span><span style="color: black;">&#40;</span>
    project = <span style="color: #483d8b;">'project_name'</span>,
&nbsp;
    package     = <span style="color: #483d8b;">'$(project).zip'</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Remote servers</span>
    fab_user    = <span style="color: #483d8b;">'usuario_ssh'</span>,
    fab_hosts   = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'servidor1.com'</span>, <span style="color: #483d8b;">'servidor2.com'</span><span style="color: black;">&#93;</span>,
<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Deploy the application to the production servers.&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Build the application.&quot;</span>
    prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Prepare the build directory.&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Remove the build directory.&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Cada método definido no arquivo é equivalente a uma <em>task</em> do Capistrano. No início temos o método <code>set</code> que nos permite configurar as variáveis necessárias para o <em>script</em>. Veja que, neste método <code>set</code>, indicamos na variável <code>fab_hosts</code> os servidores nos quais os comandos remotos devem ser executados.</p>
<p>Ok, tente executar o comando <code>fab</code> no terminal, no mesmo diretório onde se encontra o arquivo <code>fabfile.py</code>. Se tudo correr bem, você receberá a seguinte saída:</p>
<pre>daniel ~  $  fab
   Fabric v. 0.0.9, Copyright (C) 2008 Christian Vest Hansen.
   Fabric comes with ABSOLUTELY NO WARRANTY; for details type `fab warranty'.
   This is free software, and you are welcome to redistribute it
   under certain conditions; type `fab license' for details.

No commands given.
Available commands are:
   build    : Build the application.
   clean    : Remove the build directory.
   deploy   : Deploy the application to the production servers.
   help     : Display Fabric usage help, or help for a given command.
   license  : Display the Fabric distribution license text.
   list     : Display a list of commands with descriptions.
   prepare  : Prepare the build directory.
   set      : Set a Fabric variable.
   shell    : Start an interactive shell connection to the specified hosts.
   warranty : Display warranty information for the Fabric software.
Done.</pre>
<p>Veja que as <em>tasks</em> que criamos estão disponíveis para serem executadas via linha de comando. Para executar as <em>tasks</em> <code>clean</code> e <code>deploy</code>, por exemplo, utilizaríamos o seguinte comando:</p>
<pre>daniel ~  $  fab clean deploy</pre>
<p>Simples, não é? Antes de vermos um exemplo de script completo, vamos conhecer os três principais métodos utilizados em <em>scripts</em> Fabric: <code>local</code>, <code>run</code> e <code>put</code>:</p>
<ul>
<li><code>local</code>: Serve para executar comandos na máquina local. Ex: <code>local('mkdir build')</code>;</li>
<li><code>run</code>: Igual ao <code>local</code>, mas executa os comandos nas máquinas remotas (indicadas na variável <code>fab_hosts</code>);</li>
<li><code>put</code>: Envia um arquivo para as máquinas remotas. Ex: <code>put('arquivo.zip', '/home/user/app.zip')</code>.</li>
</ul>
<p>Antes de prosseguirmos, vamos voltar a olhar a chamada ao método <code>set</code>, no início do código. Nele, eu usei um recurso do Fabric conhecido como <em>lazy evaluation</em>. No caso, temos a variável <code>package</code> que recebe o valor <code>'$(project).zip'</code>. Esse <code>$(project)</code> indica que queremos que o valor da variável <code>project</code> substitua o <em>placeholder</em>. Isso permite que variáveis sejam interpoladas umas dentro das outras.</p>
<p>Por exemplo, se dentro de uma <em>task</em> executarmos o comando <code>local('rm $(package)')</code>, isso significa que o Fabric irá parsear a string, transformando-a em <code>'rm project_name'</code> para só então executar tal comando na máquina local.</p>
<p>Como veremos a seguir, eu utilizei este recurso exaustivamente no meu <em>script</em>. Em caso de dúvidas, consulte a <a href="http://www.nongnu.org/fab/user_guide.html">documentação</a> do Fabric.</p>
<h3>Finalmente, o script completo!</h3>
<p>Antes de mostrar o <em>script</em> que eu venho utilizando para fazer o deployment <a href="http://www.destaquenet.com/">de uma aplicação</a> Django, veja como seus arquivos e diretórios estão organizados: (isso deve ajudar a entender melhor o <em>script</em>)</p>
<div id="attachment_131" class="wp-caption aligncenter" style="width: 214px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/destaqueweb_structure-204x300.png" alt="Estrutura do projeto" title="Estrutura do projeto" width="204" height="300" class="size-medium wp-image-131" /></a><p class="wp-caption-text">Estrutura do projeto</p></div>
<p>E, finalmente, o <em>script</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #008000;">set</span><span style="color: black;">&#40;</span>
    project = <span style="color: #483d8b;">'destaqueweb'</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Build output directory</span>
    build_path  = <span style="color: #483d8b;">'build'</span>,
    package     = <span style="color: #483d8b;">'$(project).zip'</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Media</span>
    media_src   = <span style="color: #483d8b;">'media'</span>,
    media_root  = <span style="color: #483d8b;">'public_html'</span>,
    media_path  = <span style="color: #483d8b;">'$(media_root)/$(project)/$(media_src)'</span>,
    media_build = <span style="color: #483d8b;">'$(build_path)/$(media_path)'</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Application code</span>
    app_root  = <span style="color: #483d8b;">'wsgi_apps'</span>,
    app_path  = <span style="color: #483d8b;">'$(app_root)/$(project)'</span>,
    app_build = <span style="color: #483d8b;">'$(build_path)/$(app_path)'</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Remote servers</span>
    fab_user    = <span style="color: #483d8b;">'destaquenet'</span>,
    fab_hosts   = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'destaquenet.com'</span><span style="color: black;">&#93;</span>,
&nbsp;
    destination = <span style="color: #483d8b;">'/home/destaquenet'</span>,
    touch       = <span style="color: #483d8b;">'$(destination)/$(media_root)/$(project)/index.wsgi'</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> deploy<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Deploy the application to the production server.&quot;</span>
    build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Upload the zip file</span>
    put<span style="color: black;">&#40;</span><span style="color: #483d8b;">'$(build_path)/$(package)'</span>, <span style="color: #483d8b;">'$(destination)/$(package)'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Extract the zip file</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd $(destination); unzip -uo $(package); rm $(package)'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Reload the application</span>
    run<span style="color: black;">&#40;</span><span style="color: #483d8b;">'touch $(touch)'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> build<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Build the application.&quot;</span>
    prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Copy application files to the build directory</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R $(project)/* $(build_path)/$(app_path)'</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cp -R $(media_src)/* $(build_path)/$(media_path)'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Remove unecessary files</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find $(build_path) -name *.pyc -delete'</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find $(build_path) -path *upload* -delete'</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'find $(build_path) -path *fixtures* -delete'</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Create the zip file</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'cd $(build_path);zip -r $(package) $(media_root) $(app_root)'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> prepare<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Prepare the build directory.&quot;</span>
    clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p $(media_build)'</span><span style="color: black;">&#41;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'mkdir -p $(app_build)'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> clean<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;Remove the build directory.&quot;</span>
    local<span style="color: black;">&#40;</span><span style="color: #483d8b;">'rm -fR $(build_path)'</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Este código deve ser facilmente entendido por quem tem trabalha com uma certa facilidade no terminal.</p>
<p>Basicamente o que o código faz é organizar os arquivos da aplicação para que estes fiquem dispostos da mesma forma utilizada pelo servidor de produção, enviar os arquivos dentro de um pacote ZIP para os servidores e descompactá-los no local correto, além de executar um <code>touch</code> no <em>script</em> <acronym title="Web Server Gateway Interface">WSGI</acronym> para que o <a href="http://apache.org/">Apache</a> recarregue a aplicação.</p>
<p>Tudo pronto. Agora basta executar <code>fab deploy</code> no terminal para subir a aplicação para o(s) servidor(es) desejado(s).</p>
<h3>Fabric e ambiente de homologação</h3>
<p>Uma coisa que vem se tornando comum é o uso de diferentes ambientes onde uma aplicação costuma ser implantada (ex: ambiente de homologação). Se sua empresa costuma trabalhar dessa forma, o Fabric ainda pode te ajudar.</p>
<p>Por exemplo, vamos supor que sua empresa possua um servidor de produção e um servidor de homologação. Podemos, então, adequar o <em>script</em> para que ele possa trabalhar com ambos os ambientes:</p>

<div class="wp_syntax"><div class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #008000;">set</span><span style="color: black;">&#40;</span>
    <span style="color: #808080; font-style: italic;"># ...</span>
    fab_user = <span style="color: #483d8b;">'production'</span>,
    fab_hosts = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'app.com'</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> staging<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># deploy to staging servers</span>
    <span style="color: #008000;">set</span><span style="color: black;">&#40;</span>fab_user = <span style="color: #483d8b;">'staging'</span>, fab_hosts = <span style="color: black;">&#91;</span><span style="color: #483d8b;">'staging.app.com'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># other tasks...</span></pre></div></div>

<p>Fazendo as mudanças mostradas acima, para executar o <em>deployment</em> no ambiente de homologação basta rodar o comando <code>fab staging deploy</code>; o deployment em ambiente de produção continua disponível através do comando <code>fab deploy</code>.</p>
<p>Isso é possível pois podemos substituir o valor de uma variável (ou configurar novas variáveis) a qualquer momento, através do método <code>set</code>. Então, quando executamos o comando <code>fab staging deploy</code>, o Fabric executa a <em>task</em> <code>staging</code>, substituindo o valor das variáveis <code>fab_user</code> e <code>fab_hosts</code>, fazendo com que os comandos contidos na <em>task</em> <code>deploy</code> sejam executados nos servidores de homologação em vez de nos servidores de produção.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
