Executar script na máquina host durante o vagrant up


40

Eu gostaria de executar um script bash na máquina host quando vagrantes provisionam o servidor.

Qual seria o melhor método para conseguir isso?

Respostas:


29

Pelo menos dois plugins que devem ajudar:

Se você não se importa que o script seja executado em (quase) todos os vagrantcomandos, você também pode usar (ou usar o que for ruby ​​magic) no Vagrantfile:

system('./myscript.sh')

Vagrant.configure('2') do |config|
  # ...
end

2
Os gatilhos do Vagrant se parecem exatamente com o que eu preciso.
digital de

Onde você encontrou essa função system ()? Não consigo encontrar qualquer documentação sobre isso em qualquer lugar ...
Cristiano Fontes

11
@CristianoFontes, está no Kernelmódulo, documentado aqui . O Kernelmódulo está incluído na Objectclasse, portanto, seus métodos estão disponíveis em todos os escopos.
2141515 Tmatilai

11
Eu sou estúpido. Eu estava procurando em documentação vagante. Obrigado!
Cristiano Fontes

26

Solução simples (e completa)

(Digo completo porque a resposta aceita não verifica se o usuário está usando o vagrant up. Portanto, o script é executado em cada comando, que não é o que o OP deseja.)

Existe, no entanto, uma solução simples para isso.

ARGV[0]é o primeiro argumento do comando inserido e pode ser up, down, status, etc .. Basta verificar o valor ARGV[0]em sua Vagrantfile.


Algo assim fará:

system("
    if [ #{ARGV[0]} = 'up' ]; then
        echo 'You are doing vagrant up and can execute your script'
        ./myscript.sh
    fi
")

Vagrant.configure('2') do |config|
  # ...
end

11
Olá, Mick ... Boa resposta, obrigado por isso. Mas não consigo entender se [# {ARGV [0]} = 'up']; para trabalhar no windows. Ele nunca encontra o argumento
Cristiano Fontes

11
Isso executa o script antes de qualquer outra coisa, independentemente da sua posição no Vagrantfile. Pode ser suficiente para o que você está fazendo, mas vagabundo-gatilhos plug-in foi o que eu precisava ...
Vigintas Labakojis

3
@CristianoFontes, você pode fazer o teste argv em ruby ​​fora da chamada do sistema e ele funcionará no Windows e no * nix. Eu uso isso para definir uma variável global ruby ​​indicando que o provisionamento está acontecendo, procurando o comando up ou provision na linha de comando: se ARGV [0] = ~ / ^ up | provisionamento $ / i e não ARGV.include? (" --no-provision ") $ provisioning = true else $ provisioning = false end #
Rhubarb

Na verdade, essa é uma prática ruim, conforme recomendado pelo Vagrant; você deve escrever um plug-in para conectar-se ao comando "up"; pode especificar um dos seguintes: antes, depois e em torno da execução.
SilentICE

11
@ Rick é apenas nos documentos do Vagrant ( docs.vagrantup.com/v2/plugins/commands.html ). Ele também cria um script frágil, pois você não pode ter certeza de que, em casos de chamada, argv [0] está 'ativo' em vez de dizer um sinalizador. Além disso, se você está adotando o rubi bruto, está meio que quebrando o encapsulamento que o framework deveria estar fornecendo. Existem mecanismos expostos para fazer isso corretamente, então IMHO você deve usá-los sempre que possível #
SilentICE

9

Coloque isso perto do topo do seu arquivo Vagrant:

module LocalCommand
    class Config < Vagrant.plugin("2", :config)
        attr_accessor :command
    end

    class Plugin < Vagrant.plugin("2")
        name "local_shell"

        config(:local_shell, :provisioner) do
            Config
        end

        provisioner(:local_shell) do
            Provisioner
        end
    end

    class Provisioner < Vagrant.plugin("2", :provisioner)
        def provision
            result = system "#{config.command}"
        end
    end
end

Em seguida, basta chamar no seu Vagrantfile assim:

config.vm.provision "list-files", type: "local_shell", command: "ls"

E através da linha de comando como esta:

vagrant provision --provision-with list-files

Isso é meio que um hack, pois parece um plug-in, mas na verdade não é (não será exibido quando você aparecer vagrant plugin list). Eu não recomendo fazê-lo dessa maneira, exceto que ele tem a vantagem de não precisar instalar um plug-in, portanto, o seu Vagrantfile funcionará em qualquer máquina que suporte a versão mais recente da configuração (versão 2, neste momento). Embora isso pareça prometidamente portátil, também há toda a questão de plataforma cruzada do comando real que você está emitindo. Você precisará levar em consideração se deseja que o seu Vagrantfile seja portátil, mas isso deve ajudá-lo a começar.


11
Boa resposta, vou usar isso para configurar o encaminhamento de porta baixa.
poindexter

6

Com base na resposta de @ tmatilai, mas atualizada para 2019, o vagrant-triggers foi fundido no Vagrant. Agora você pode fazer algo assim:

node.trigger.before [:up, :provision] do |trigger|
  trigger.info = "Running ./myscript.sh locally..."
  trigger.run = {path: "./myscript.sh"}
end

Este bloco vai para dentro config.vm.define. Mais documentação: https://www.vagrantup.com/docs/triggers/


Esta é a resposta mais elegante até hoje. Devo acrescentar que a inserção de trechos deste e de outros similares config.vm.definenão é um requisito; eles podem ser colocados dentro Vagrant.configure("2") do |config| ... endtambém. Como observação final, nos hosts do Windows, o Vagrant executará com prazer os scripts do Powershell que também possuem a .ps1extensão.
Ben Johnson

4

De acordo com o que @tmatilai disse sobre o uso

system('./myscript.sh')

Eu achei bastante útil para comandos de uma só vez, como instalar comandos vagrantes ou algum provisionador que pode não estar instalado no sistema. Eu apenas evito que ele seja executado novamente toda vez que chamo os vagrantcomandos adicionando um sed para comentar automaticamente o Vagrantfile.

Por exemplo:

system('vagrant plugin install vagrant-fabric && (pip install fabric jinja2 || sudo pip install fabric jinja2) && sed -i -e "s/^system/#system/g" Vagrantfile')

E eu faço isso a primeira linha do meu arquivo Vagrant. Desta forma, ele irá primeiro instalar o plugin vagabundo-tecido, tecido e Jinja (vai tentar primeiro sem sudopara virtualenvse com sudose isso falhar) e então o próprio comentários de linha.


Seria mais fácil simplesmente exibir a lista de plugins vagrantes, em vez de descomentar o arquivo Vagrant, o que poderia causar problemas para outras pessoas da sua equipe. if [[ $(vagrant plugin list | grep -c vagrant-host-shell) == "0" ]] then vagrant plugin install vagrant-host-shell fi
Jordânia

O problema com isso é que ele será acionado em outros comandos, o que se você executar vagrant statusantes vagrant up...
Mick
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.