Desenvolvimento

20 jan, 2014

Como usar o Vagrant.has_plugin? No Vagrantfile

Publicidade

Olá, pessoal!

Esse artigo é uma continuação do Vagrant e seus plugins e, para falar a verdade, começou a ser escrito antes do original. É que percebi que, sem uma explicação mais básica do que eram os plugins, ia “faltar base” – como dizia um professor do cursinho. Então, mais uma vez, se quiser primeiro saber o que são os plugins no Vagrant, leia o artigo original primeiro, ok?

vagrant-has-plugin

O que é o método Vagrant.has_plugin?

has_plugin? é um método da API do Vagrant, para ser usado no seu Vagrantfile, que verifica se um plugin está disponível no sistema. Com o grande número de plugins disponíveis (confira os listados na wiki oficial), é importante ter uma forma de garantir que quem for usar seu projeto Vagrant tenha os plugins que você definiu/utilizou, e, se não tiver, fazer algo com essa informação.

Vamos ver um exemplo para deixar mais fácil o entendimento:

# Vagrant.configure("2") do |config| ...

  # configs for vagrant-cachier
  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.auto_detect = true
  end

# ...

Nesse trecho acima vemos um Vagrantfile que utiliza oplugin vagrant-cachier para acelerar o vagrant up se o usuário tem o plugin instalado na máquina. Caso não tenha, tudo continua funcionando, apenas sem a aceleração. Sem usar o has_plugin? o Vagrant interromperia o processo com uma mensagem de erro.

Parece bastante com o conceito de progressive enhancement/graceful degradation: forneça ao usuário que tem apenas o requisito básico uma versão funcional do seu projeto, sem traumas. E, para os que tem mais requisitos (no caso o plugin que definimos), entregue também as funções melhoradas (nesse caso, uma camada de cache que vai acelerar o provisionamento das máquinas virtuais. Se você ainda não conhece o vagrant-cachier, do brasileiro Fabio Rehm, ou @fgrehm, é uma boa hora de começar!).

Um outro exemplo segue abaixo:

# Warns to use Bindler
unless Vagrant.has_plugin?("Bindler")
  puts "--- WARNING ---"
  puts "I'm using Bindler, https://github.com/fgrehm/bindler"
  puts "It's for 'Dead easy Vagrant plugins management'"
  puts "If you have not it installed in your system,"
  puts "visit https://github.com/fgrehm/bindler#installation for more information"
end

# Vagrant.configure("2") do |config| ...

Nesse caso, ao contrário do anterior, é feita uma ação quando um plugin não existe no sistema. E quando que isso é útil? Principalmente para os casos em que precisamos avisar para o usuário que um plugin é necessário/recomendável para executar a aplicação, dando algum caminho para que ele possa resolver a situação. No exemplo acima, avisamos que o projeto está usando o plugin vagrant-bindler para fazer a gestão dos plugins e passamos um caminho para que o usuário faça a instalação do mesmo se ele ainda não tiver (plugin também criado pelo @fgrehm).

Há tempos… um problema!

A função Vagrant.has_plugin? foi introduzida no Vagrant na versão 1.3.0com alguns problemas, e na versão 1.3.2 foi realmente consertada – isso tudo em setembro de 2013. Mas por que então, mesmo tendo uma certa idade, essa função ainda não é tão utilizada?

Isso acontece por uma pequena inconsistência na implementação dessa API, que faz com que o nome do plugin internamente para o Vagrant (que vai ser usada na chamada Vagrant.has_plugin?) seja diferente do nome do plugin que é usado na instalação via linha de comando $ vagrant plugin install.

Antes de perceber isso acima, eu mesmo no começo não conseguia entender a lógica, que parecia ser tão simples: fazer uma condição ruby IF ou UNLESS, passando o nome do plugin. Por que não funcionava? Era essa bendita inconsistência de nomes. Ainda bem que não desisti de entender!

Para facilitar, vamos chamar esses nomes da seguinte forma:

  • nome de instalação do plugin: usado no comando $ vagrant plugin install ....
  • nome interno do plugin: usado no Vagrantfile, com o métodohas_plugin?

Com isso em mente, vamos para os  exemplos:

HOW IS LISTED WITH VAGRANT PLUGIN LIST HOW TO USE IN VAGRANT.HAS_PLUGIN? LINK TO PLUGIN.RBIN REPO
bindler Bindler fgrehm/bindler
vagrant-hostmanager HostManager smdahlen/vagrant-hostmanager
vagrant-cachier vagrant-cachier fgrehm/vagrant-cachier
vagrant-aws AWS mitchellh/vagrant-aws
vagrant-rackspace RackSpace Cloud mitchellh/vagrant-rackspace
vagrant-hp HP mohitsethi/vagrant-hp
vagrant-digitalocean DigitalOcean smdahlen/vagrant-digitalocean

Quando acessamos a lista oficial dos plugins disponíveis para Vagrant, não encontramos o nome interno (ainda, estou trabalhando nisso); apenas aparece o nome de instalação. Uma diferença que, às vezes, é apenas de maiúsculas ou minúsculas entre os nomes das duas versões mas que já atrapalha tudo!

Peguemos o Bindler. Para instalá-lo no sistema, é usado o nome daGem (em minúsculas):

$ vagrant plugin install bindler

Já para usar no seu Vagrantfile, com o has_plugin?, tem que ser onome interno do plugin (começando com maíscula):

Vagrant.has_plugin?("Bindler")

É, realmente é complicado. Por não haver um padrão, é possível encontrar todos os tipos de combinações: nomes iguais, totalmente diferentes ou apenas a diferença de capitulares. Mas existe uma solução! Vamos vê-la?

A solução!

E a solução é: aprender a ler o repositório do plugin! Puxa, não é o que você estava esperando, não é mesmo… É, por enquanto, não existe uma solução perfeita, por isso vamos aprender aqui a ler o repositório sempre que você precisar.

Arquivos importantes

O primeiro passo é saber localizar, dentro de um repositório, o nome de instalação do plugin e o nome interno do plugin:

  • /nome-de-instalação-do-plugin.gemspec: é nesse arquivo que temos o nome de instalação. O arquivo fica na pasta raiz do repositório do plugin. Exemplos: bindler.gemspecvagrant-aws.gemspecvagrant-cachier.gemspec etc.
  • /lib/nome-de-instalação-do-plugin/plugin.rb: é nesse arquivo que temos o nome interno. O arquivo fica no terceiro nível do repositório do plugin. Dentro desse arquivo, existe um atributoname, que é o nome interno que você vai usar. Exemplos para os mesmos plugins acima: BindlerAWSvagrant-cachier.

Achar o repositório do plugin

O segundo passo é saber onde está o repositório do plugin. Minha sugestão, comece pela lista oficial, e siga o link de lá. Na maioria das vezes, você vai cair num repositório no GitHub (ou em algum outro serviço de hospedagem de projetos open source).

A partir daí é só navegar buscando os arquivos mostrados ali em cima, que você já terá a informação necessária para trabalhar.

Considerações finais

Vimos que o Vagrant.has_plugin? é um método da API do Vagrant muito útil para utilizar nos seus projetos. Principalmente importante para os projetos compartilhados com muitas pessoas, verificando no tempo de execução a existência ou não de um plugin determinado; permitindo que quem tenha o plugin, aproveite as funcionalidades, mas não impeça que os usuários sem o plugin tenham uma experiência pelo menos básica.

Entendemos também que existem dois nomes para os plugins: onome de instalação e o nome interno, e qual deles deve ser usado junto com o Vagrant.has_plugin?. Aprendemos quando usar cada um deles, e como descobrir o nome lendo o repositório do plugin (fique de olho na wiki da lista oficial de plugins, pois vou fazer um trabalho visando facilitar a pesquisa centralizada desses nomes, seria interessante, certo?).

Quer uma dica de plugins para começar a trabalhar? Dê uma olhada no meu artigo original, Vagrant e seus plugins, que tem algumas opções que já utilizo. Agora é sua vez de montar uma estratégia de uso dos plugins e do has_plugin? nos seus projetos Vagrant e

Fique à vontade para tirar suas dúvidas nos comentários (ou me procure, estou em quase todo lugar na internet como rogeriopradoj, é só chamar!)

Feliz vagrant up!

Referências: