Myhro Blog

O dia em que perdi cinco mil dólares

No final de fevereiro foi aberta a chamada no Projeto Debian para os interessados em participar da edição de 2014 do Google Summer of Code. Pra quem não conhece o GSOC, trata-se de um programa do Google, qual existe desde 2005, que consiste basicamente em fornecer bolsas de estudo para alunos interessados em contribuir com projetos de Software Livre, durante os 2-3 meses das férias de verão na América do Norte e Europa, quais ocorrem no meio do ano. Conheço o programa há algum tempo, mas somente neste ano me senti maduro o suficiente para participar.

Dando uma olhada na lista de projetos propostos pelo Debian, encontrei um que particularmente me identifiquei muito, o bootstrap-vz. A ideia do mesmo é proporcionar um conjunto de ferramentas, escritas em Python, para gerar máquinas virtuais do Debian GNU/Linux a partir de uma configuração previamente determinada. Ou seja, você não precisa se dar ao trabalho de criar uma máquina virtual no VirtualBox, instalar o sistema, realizar as configurações e instalação de pacotes necessários, depois gerar uma máquina virtual para ser utilizada com o Vagrant. Basta rodar um comando para que tudo fique pronto magicamente.

Visto que me interesso por virtualização há algum tempo, utilizo o Debian em meu desktop há quase dois anos (em servidores há mais tempo ainda) e passei o ano passado inteiro programando em Python (sendo que tenho contato com a linguagem há muito mais tempo), foi natural a escolha do projeto. Sendo assim, entrei em contato com o Olivier Sallou, desenvolvedor Debian francês, comunicando sobre meu interesse em participar. Ele me respondeu rapidamente, dizendo que a seleção dos estudantes consistiria em desenvolver um plugin para configuração do NTP nas máquinas criadas.

Até aí estava tudo bem, bastava que eu brincasse um pouco com o código, após dar uma lida na documentação sobre desenvolvimento, para descobrir como prosseguir. Foi justamente neste momento que meus problemas começaram: não conseguia criar a máquina virtual do Vagrant de exemplo e o processo demorava de 20 a 30 minutos antes de apresentar qualquer erro. Ciente de que perdendo tanto tempo apenas para começar eu jamais sairia do lugar, decidi deixar isso pra lá. Pensei comigo mesmo que haveriam outros estudantes interessados em participar e o projeto não seria prejudicado.

No penúltimo dia das inscrições, o Olivier me enviou uma mensagem de e-mail dizendo que eu deveria realizar minha inscrição formal caso quisesse realmente participar. Expliquei a ele sobre os problemas quais estava passando (coisa que deveria ter feito semanas antes) e ele me colocou em contato com o Anders Ingemann, dinamarquês criador do bootstrap-vz. Foi somente a partir deste momento que obtive algum progresso e, no dia seguinte, último do prazo estipulado, decidi por realmente realizar minha inscrição.

Fui para a universidade e, por volta das 13h, comecei a redigir minha aplicação na Wiki do Debian, primeira etapa do processo de inscrição. Levei um certo tempo para finalizá-la, terminando por volta das 16h30m, pois não o fiz com muita pressa. Havia pensado comigo mesmo que o prazo seria encerrado por volta da meia-noite UTC, o que me daria até pelo menos as 21h no horário de Brasília. Foi somente quando acessei a página do Google Melange que descobri que o prazo havia se encerrado às 19h UTC, 16h do horário de Brasília.

Como era de se esperar, fiquei triste por ter perdido a chance de participar do processo de seleção para uma bolsa de US$ 5000,00 por causa de meia hora. A situação ainda piorou quando percebi que era o único inscrito no projeto e, consequentemente, não haveria concorrência, bastaria aceitarem minha participação. Desta forma, não pude deixar de contribuir com o projeto mesmo não recebendo compensação financeira por isto. O Anders é uma pessoas mais atenciosas e pacientes que já conheci, respondendo meus e-mails mesmo nas noites de sábado ou manhãs de domingo, independente do quão urgente sejam.

De lá pra cá, realizei diversas contribuições, corrigindo bugs, criando plugins e redigindo a documentação correspondente. Estas foram tantas e com tamanha qualidade (palavras do Anders, não minhas) que, em menos de um mês, fui adicionado como colaborador do projeto, tendo permissão para enviar modificações diretamente, sem a necessidade de abrir pull requests. Hoje minha maior preocupação é zelar pela diminuição de issues abertas no projeto, corrigindo os problemas reportados e auxiliando novos contribuidores.

Carregando um kernel manualmente com o kexec

Conheci o kexec por um acaso. É o tipo de ferramenta que, se alguém tivesse me mostrado sem exemplificar com um caso de uso específico, não enxergaria a menor utilidade. A ideia é muito simples, como seu próprio nome sugere: executar (carregar) um kernel. Você pode se perguntar porque alguém precisaria de uma ferramenta para realizar um processo que normalmente é executado por um gerenciador de boot, como o GRUB. Uma das respostas possíveis é: nem sempre você tem a possibilidade de alterar as configurações de inicialização da máquina.

Este é o caso da DigitalOcean, uma empresa nova-iorquina que oferece servidores virtuais a preços extremamente acessíveis. O painel de administração das máquinas virtuais é muito bem feito, possuindo uma interface extremamente simples, que ao mesmo tempo oferece todas as opções necessárias para configurá-las. Entretanto, há um problema: só é possível inicializar as máquinas Linux (únicas oferecidas até o momento) com os kerneis pré-definidos por eles. Não é possível, por exemplo, recompilar seu próprio kernel ou mesmo trocá-lo por uma versão atualizada com novas correções de segurança.

Isto normalmente não é um problema, pois eles oferecem uma quantidade até razoável de kerneis diferentes no painel de administração. O problema é quando você precisa de uma combinação menos convencional, como atualizar o Debian para a versão testing ou unstable, utilizando um kernel qual não está disponível. E isto era justamente o que eu precisava para rodar o Docker no Debian, ou pelo menos atualizar o kernel, se não fosse fazer isto com todo o sistema.

A solução para esta situação é carregar um kernel “na mão”, utilizando o comando kexec, que no Debian está disponível no pacote kexec-tools. Partindo do pressuposto que você já tenha instalado (via apt-get, compilado, etc.) o kernel qual deseja carregar, basta executar o comando kexec -l [arquivo-kernel] --initrd=[arquivo-initrd]. Por exemplo:

[root@debian-docker:~]# uname -a
Linux debian-docker 3.2.0-4-amd64 #1 SMP Debian 3.2.41-2+deb7u2 x86_64 GNU/Linux
[root@debian-docker:~]# ls -lh /boot/
total 33M
-rw-r--r-- 1 root root 148K Mar 26 05:11 config-3.13-1-amd64
-rw-r--r-- 1 root root 127K Mar 26  2013 config-3.2.0-4-amd64
drwxr-xr-x 2 root root 4.0K Apr  6 19:42 grub
-rw-r--r-- 1 root root  13M Apr  6 19:50 initrd.img-3.13-1-amd64
-rw-r--r-- 1 root root 9.8M May  3  2013 initrd.img-3.2.0-4-amd64
-rw-r--r-- 1 root root 2.3M Mar 26 05:11 System.map-3.13-1-amd64
-rw-r--r-- 1 root root 2.1M Mar 26  2013 System.map-3.2.0-4-amd64
-rw-r--r-- 1 root root 2.8M Mar 26 05:08 vmlinuz-3.13-1-amd64
-rw-r--r-- 1 root root 2.8M Mar 26  2013 vmlinuz-3.2.0-4-amd64
[root@debian-docker:~]# kexec -l /boot/vmlinuz-3.13-1-amd64 --initrd=/boot/initrd.img-3.13-1-amd64

Neste momento, o normal seria executar o kernel previamente carregado com o comando kexec -e. Entretanto, não obtive sucesso quando tentei fazer isso e em todas as vezes a máquina simplesmente travava. O que resolveu meu problema foi executar o comando dpkg-reconfigure kexec-tools, respondendo Yes na pergunta ”Should kexec-tools handle reboots?” e No na pergunta ”Read GRUB configuration file to load the kernel?”. Isto faz com que o kernel a ser inicializado passe a ser o que foi carregado no kexec, sem influência do que estiver configurado no GRUB.

A partir disto, basta reiniciar a máquina, seja pelo painel de administração ou através do comando reboot. Na próxima vez que você se conectar, verifique a versão do kernel, para confirmar se tudo ocorreu como esperado:

[root@debian-docker:~]# uname -a
Linux debian-docker 3.13-1-amd64 #1 SMP Debian 3.13.7-1 (2014-03-25) x86_64 GNU/Linux

Minicurso: Introdução ao Python/Django

Estarei ministrando um minicurso de Introdução ao Python/Django nos dias 02 (quarta-feira) e 04 (sexta-feira) de Abril, com possibilidade de mais uma aula no dia 09 (quarta-feira) de Abril de 2014, dependendo de como as coisas fluirem. O local de realização do mesmo será o Laboratório II (o primeiro à direita do corredor) do Centro de Ciências Exatas e Tecnológicas, prédio 03, do Campus Universitário Prof. Darcy Ribeiro da Unimontes, localizado na cidade de Montes Claros. O horário previsto é das 19h às 22h30m.

A ideia surgiu a partir desta postagem feita pelo meu prezado colega de curso Jader Gabriel no grupo do Curso de Sistemas de Informação da Unimontes no Facebook, sugerindo um curso de Python e/ou Django, provavelmente pago. É importante destacar que este minicurso é gratuito e aberto a todos os acadêmicos do CCET, não sendo de forma alguma restrito ao Curso de Sistemas de Informação ou aos cursos ligados ao Departamento de Ciências da Computação (DCC) - embora estes sejam os principais interessados. O único pré-requisito é saber o básico de lógica de programação, embora ter noções de orientação a objetos fosse interessante.

Caso deseje se inscrever, por favor utilize este formulário do Google Drive. Estão previstas 22 (vinte e duas) vagas, para evitar que alguém fique sem computador caso ocorra algum problema com as máquinas durante o andamento do minicurso. O Google Drive não limita o número de inscrições, portanto, caso você consiga se inscrever, não quer dizer necessariamente que sua vaga está garantida. Farei o possível para encerrá-las assim que o limite for atingido, de forma a evitar que isto aconteça. As vagas serão distribuídas por ordem cronológica de inscrição e as mesmas serão posteriormente confirmadas via e-mail.

Atualização: a última vaga foi preenchida às 21h17m do dia 26/03/2014 (quarta-feira) e com isto as inscrições foram encerradas.

Atualização: estão disponíveis para download os slides utilizados no minicurso e o projeto de exemplo gerado.

Vim + Plugins = Pathogen

A escolha de um editor decente e universal não é fácil. Antes de começar a utilizar o Vim corriqueiramente, passei por diversos outros como:

  • Bloco de notas: Um editor sincero. Não espere nada além de realmente editar textos.
  • Joe: Muito bacana. Já havia decorado boa parte dos seus milhares de atalhos.
  • nano: É sério que alguém ainda usa isso? Já implementaram o ”undo”, pelo menos?
  • Notepad++: Um editor acima da média, mas Windows-only.

Todos eles tinham pelo menos um ou vários desses problemas:

  • Não funcionava sem ambiente gráfico (modo texto).
  • Não possuía syntax highlighting.
  • Não sabia lidar com quebras de linha de diferentes sistemas operacionais (CR+LF vs. LF).
  • Não salvava em UTF-8.
  • Não trocava TAB por n espaços.

E ainda havia o mais grave de todos: não estavam disponíveis em todas as máquinas quais utilizo. Foi somente a partir deste momento, que não deve ter acontecido há muito mais do que dois anos atrás, que decidi de vez por utilizar o Vim sempre que fosse necessário editar qualquer arquivo texto que fosse. Sempre que logo em uma máquina qual não estou familiarizado, tenho a certeza (se é que podemos ter certeza de algo nessa vida) de que pelo menos o comando vi (que na verdade faz parte do pacote vim-tiny, sendo uma versão menor e simplificada do Vim) estará disponível.

Acontece que utilizar apenas o editor puro nem sempre é o suficiente. Uma parte considerável das surpresas no estilo ”Wow! O Vim faz isso?!” é proporcionada pelos plugins desenvolvidos por terceiros. Entretanto, além de muitos deles possuírem passos de instalação crípticos, é complicado manter todos devidamente atualizados. Foi a partir daí que passei a usar o Tim Pope’s pathogen.vim, em um daqueles momentos onde sempre me pergunto: ”Por que é que não fiz isso antes?!”.

Após instalar o Pathogen, o que consiste basicamente em salvar o script em ~/.vim/autoload/pathogen.vim e adicionar a linha execute pathogen#infect() ao seu ~/.vimrc, basta criar o diretório ~/.vim/bundle/ e simplesmente clonar lá o repositório (muitos estão no GitHub) do plugin qual deseja utilizar. A grande maioria dos plugins estará disponível a partir deste processo, mas alguns, mais complexos, podem exigir a adição de algumas informações no arquivo ~/.vimrc.

Por exemplo, para instalar o Syntastic, um plugin que verifica seu código a cada vez que o arquivo é salvo, indicando possíveis erros quais serão encontrados na compilação ou quando for interpretado, suportando dezenas de linguagens de programação, basta realizar os seguintes passos:

[myhro@wheezy:~]$ cd ~/.vim/bundle/
[myhro@wheezy:~/.vim/bundle]$ git clone https://github.com/scrooloose/syntastic.git
Cloning into 'syntastic'...
remote: Reusing existing pack: 9852, done.
remote: Counting objects: 40, done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 9892 (delta 15), reused 0 (delta 0)
Receiving objects: 100% (9892/9892), 2.48 MiB | 247 KiB/s, done.
Resolving deltas: 100% (4773/4773), done.
[myhro@wheezy:~/.vim/bundle]$ ls
syntastic
[myhro@wheezy:~/.vim/bundle]$ 

E pronto. O Syntastic está instalado. Para atualizá-lo, bastará entrar em seu diretório e rodar um git fetch seguido de git merge origin/master ou simplesmente um git pull origin.

Vagrant: Introdução

O Vagrant é uma ferramenta criada originalmente para o VirtualBox, mas que hoje suporta uma grande variedade de sistemas de virtualização, qual fornece uma fina camada para facilitar a criação, gerenciamento e utilização de ambientes de desenvolvimento virtuais. O velho problema conhecido como “na minha máquina funciona” é sanado pela raiz, visto que através de pouquíssimos passos, todos os desenvolvedores tem acesso a um ambiente praticamente idêntico, onde as únicas diferenças residem na versão do VirtualBox instalada ou nas modificações realizadas no sistema operacional da máquina virtual utilizada.

Para começar a utilizar o Vagrant, são necessários basicamente três componentes:

  • O VirtualBox, que além de ser o provider padrão, é uma excelente ferramenta de virtualização, gratuita e largamente utilizada.
  • O próprio Vagrant, que é responsável por fornecer os comandos e ler os arquivos de configuração para gerenciamento das máquinas virtuais.
  • Uma box, que nada mais é do que uma máquina virtual criada no VirtualBox ou outro provider cujas configurações e imagem de disco foram exportadas e compactadas em um único arquivo.

O processo de instalação de ambos VirtualBox e Vagrant varia de acordo com o sistema operacional utilizado, podendo ser Windows, Linux ou Mac OS X, mas ainda assim é muito simples. Vale ressaltar que o VirtualBox também suporta Solaris, mas o Vagrant não. O que importa é que ao final você terá o comando vagrant, através do qual realizará todo o processo de adicionar/criar/inicializar/desligar máquinas virtuais, sem precisar utilizar a interface do VirtualBox diretamente para isto.

Após realizar a instalação de ambos, é necessário adicionar pelo menos uma nova box. Há uma página com diversas boxes de várias distribuições Linux ou BSD, mas neste exemplo utilizaremos uma que criei a partir de uma instalação mínima do Debian “Wheezy” 7.0. A sintaxe do comando é vagrant box add {nome} {url}, onde o nome escolhido será utilizado para se referir à mesma em outros comandos. A URL não precissa ser necessariamente um link HTTP, podendo ser também o caminho de um arquivo em outro diretório, por exemplo.

[myhro@wheezy:~]$ vagrant box list
There are no installed boxes! Use `vagrant box add` to add some.
[myhro@wheezy:~]$ vagrant box add wheezy32 http://myhro.info/dl/wheezy32.box 
Downloading or copying the box...
Extracting box...te: 2.6M/s, Estimated time remaining: 0:00:01)
Successfully added box 'wheezy32' with provider 'virtualbox'!
[myhro@wheezy:~]$ vagrant box list
wheezy32 (virtualbox)

Após a box ser copiada, basta, na pasta do projeto qual irá utilizar esta máquina virtual, utilizar o comando vagrant init {nome}. É importante que se faça isso na pasta correta por dois motivos: o primeiro é que a pasta atual será compartilhada no diretório /vagrant/ da máquina virtual, não necessitando copiar seus arquivos por outros meios para acessá-los. O segundo motivo é que será criado um arquivo chamado VagrantFile, que é um simples arquivo-texto onde todas as configurações necessárias para adaptação da máquina estarão presentes. Desta forma, este arquivo pode ser compartilhado com os demais membros do projeto, tornando o ambiente ainda mais homogêneo.

[myhro@wheezy:~]$ cd project/
[myhro@wheezy:~/project]$ vagrant init wheezy32
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Em seguida, basta colocar a máquina pra rodar com o comando vagrant up:

[myhro@wheezy:~/project]$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'wheezy32'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for machine to boot. This may take a few minutes...
[default] Machine booted and ready!
[default] Mounting shared folders...
[default] -- /vagrant

Caso neste momento a máquina virtual não seja inicializada e apareça uma mensagem de erro dizendo que a mesma entrou no estado “gurumeditation”, pode ser que as instruções de virtualização do processador da máquina física estejam desabilitadas, ou mesmo não estejam disponíveis. É interessante verificar no setup da BIOS/UEFI se é possível habilitá-las.

A partir daí, é possível, por exemplo, logar na máquina com o comando vagrant ssh e instalar/configurar/executar o que for necessário. Os exemplos contidos no arquivo VagrantFile ensinam como redirecionar outras portas, fazendo com que um servidor web rodando na máquina virtual se torne acessível a partir do browser na máquina físical qual a está rodando.

myhro@wheezy:~/project]$ vagrant ssh
Linux wheezy32 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Jun 19 15:19:38 2013
[vagrant@wheezy32:~]$ df -h
Filesystem      Size  Used Avail Use% Mounted on
rootfs          4.0G 1022M  2.8G  27% /
udev             10M     0   10M   0% /dev
tmpfs            51M  196K   51M   1% /run
/dev/sda1       4.0G 1022M  2.8G  27% /
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           101M     0  101M   0% /run/shm
none            257G  120G  138G  47% /vagrant
[vagrant@wheezy32:~]$ free -m
total       used       free     shared    buffers     cached
Mem:           502        103        398          0         11         62
-/+ buffers/cache:         29        472
Swap:            0          0          0
[vagrant@wheezy32:~]$ logout
Connection to 127.0.0.1 closed.
[myhro@wheezy:~/project]$ 

E após utilizar a máquina, basta colocá-la para “dormir” com o comando vagrant suspend ou desligá-la com vagrant halt. Mas o comando mais legal mesmo é o salva-vidas vagrant destroy:

[myhro@wheezy:~/project]$ vagrant destroy
Are you sure you want to destroy the 'default' VM? [y/N] y
[default] Forcing shutdown of VM...
[default] Destroying VM and associated drives...

Este comando, como o próprio nome sugere, destrói completamente a máquina virtual. A princípio pode parecer algo exagerado, mas é a coisa mais rápida e prática a se fazer quando algo der errado, como quando a máquina não iniciar mais depois de alguma modificação realizada. Depois disso, basta iniciá-la novamente, recriando-a do zero, com comando vagrant up, que também serve para quando a mesma está desligada ou suspensa.