Não é possível obter .bashrc com Ansible

85

Posso ssh para o host remoto e fazer um source /home/username/.bashrc- tudo funciona bem. No entanto, se eu fizer:

- name: source bashrc
  sudo: no
  action: command source /home/username/.bashrc

Eu recebo:

failed: [hostname] => {"cmd": ["source", "/home/username/.bashrc"], "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory

Não tenho ideia do que estou fazendo de errado ...

pldimitrov
fonte
sourcesó faz sentido quando você o executa dentro de um shell existente - ele executa comandos nesse shell e, portanto, só é útil / útil quando há um shell existente cujo estado ou configuração você deseja alterar. Quando você executa uma ação ansible, isso cria um novo shell , e executa um comando dentro desse shell - então você não estaria atualizando as variáveis ​​de ambiente em qualquer outro contexto, então não teria nenhum efeito útil / duradouro , mesmo que funcione sem erros.
Charles Duffy
@CharlesDuffy Se você deseja executar um comando que espera que as variáveis ​​de ambiente sejam definidas, tentar obter algo como .bashrc ou .bash_profile para definir tais variáveis ​​é um caso de uso válido, não é?
htellez
@htellez, a execução sourcesó define variáveis para a duração do shell em que é executado . E esse shell saiu (e as variáveis ​​que ele define foram perdidas) no momento em que o comando ansible sai e o próximo começa.
Charles Duffy
@htellez, ... portanto, a única resposta aqui que é realmente útil de alguma forma significativa é a de Steve Midgley , uma vez que você faz outra coisa no mesmo shell que foi executado source, antes de sair.
Charles Duffy
Esse é exatamente o caso de uso que tentei descrever, desculpe se não fui claro. Tentei descrever um cenário em que você deseja executar algo que espera um determinado ambiente definido. Cheguei a este tópico porque recebo o mesmo erro e, ao ler a resposta de Steve, percebi que a tarefa do shell do ansible usa sh por padrão em vez de bash. Tornar o comando um comando bash explicitamente faz com que sourcefuncione da maneira que você provavelmente está acostumado.
htellez

Respostas:

88

Você tem duas opções para usar a fonte com ansible. Uma é com o comando "shell:" e / bin / sh (o padrão ansible). "fonte" é chamada de "." em / bin / sh. Portanto, seu comando seria:

- name: source bashrc
  sudo: no   
  shell: . /home/username/.bashrc && [the actual command you want run]

Observe que você deve executar um comando após obter .bashrc b / c. Cada sessão ssh é distinta - cada comando ansible é executado em uma transação ssh separada.

Sua segunda opção é forçar o shell Ansible a usar o bash e então você pode usar o comando "source":

- name: source bashrc
  sudo: no   
  shell: source /home/username/.bashrc && [the actual command you want run]
  args:
     executable: /bin/bash

Finalmente, observarei que você pode querer realmente fornecer "/ etc / profile" se estiver no Ubuntu ou similar, que simula mais completamente um login local.

Steve Midgley
fonte
3
Observe também que esse problema foi registrado (e comentado por mim) como uma solicitação de bug / recurso no núcleo do Ansible. Mas Ansible fechou e disse "escreva um plugin". Bah. github.com/ansible/ansible/issues/4854
Steve Midgley
1
Você está lendo minha mente? Você respondeu a 3 meses atrás, e eu estava pensando em editar .-> source- e você imediatamente fez isso :)
warvariuc
Eu tentei source "/etc/profile"- não funcionou para mim. Funcionou:source "~/.profile"
warvariuc
5
Tenho algumas funções bash definidas dentro de .bashrc e depois de buscar o .bashrc. como posso executar / chamar essas funções? Estou tentando shell: . ~/.bashrc && nvm install {{ node_version }}e está dizendo nvm command not found,. Como posso resolver isso?
RaviTezu
1
@RaviTezu: O problema no meu caso era devido às seguintes linhas em .bashrc: # Se não estiver executando interativamente, não faça nada caso $ - em i ) ;; *) Retorna;; esac Este é pelo menos um problema no ubuntu-16.04 xenial64 onde .bashrc não é executado em shells não interativos que é o caso ao executar comandos via ssh. Para experimentá-lo, defina algum PATH em ~ / .bashrc e execute (assumindo que você definiu a porta 2222 encaminhada para 22 no sistema operacional convidado): ssh -p 2222 [email protected] 'echo $ PATH' Se o comando acima não ' para mostrar o PATH que você definiu em .bashrc e corrigir .bashrc
Divick
24

Portanto command, só executará executáveis. sourceper se não é um executável. (É um comando de shell embutido). Existe algum motivo pelo qual você deseja sourceuma variável de ambiente completa?

Existem outras maneiras de incluir variáveis ​​de ambiente no Ansible. Por exemplo, a environmentdiretiva:

- name: My Great Playbook
  hosts: all
  tasks:
    - name: Run my command
      sudo: no
      action: command <your-command>
      environment:
          HOME: /home/myhome

Outra forma é usar o shellmódulo Ansible:

- name: source bashrc
  sudo: no
  action: shell source /home/username/.bashrc && <your-command>

ou

- name: source bashrc
  sudo: no   
  shell: source /home/username/.bashrc && <your-command>

Nesses casos, a instância / ambiente do shell será encerrado assim que a etapa Ansible for executada.

Rico
fonte
2
quase bom, infelizmente / bin / sh não tem comando de origem apenas. assim shell source /home/username/.bashrcse tornashell . /home/username/.bashrc
b1r3k
A tarefa do shell recebe um parâmetro como tal: executable=/usr/bin/bashque irá então executá-la no bash se estiver disponível como tal.
fgysin reintegrar Monica
16

Sei que esta resposta veio tarde demais, mas vi em código suficiente que você pode usar a opção sudo -i para:

- name: source bashrc
  shell: sudo -iu {{ansible_user_id}} [the actual command you want run]

Como dito na documentação

The -i (simulate initial login) option runs the shell specified by the password database entry of the target user as a login shell.  This means that login-specific
               resource files such as .profile or .login will be read by the shell.  If a command is specified, it is passed to the shell for execution via the shell's -c option.
               If no command is specified, an interactive shell is executed.  sudo attempts to change to that user's home directory before running the shell.  It also initializes
               the environment to a minimal set of variables, similar to what is present when a user logs in.  The Command environment section below documents in detail how the -i
               option affects the environment in which a command is run.
Clempat
fonte
5

Eu estava tendo esse mesmo problema ao tentar fazer o virtualenvwrapper funcionar em um servidor Ubuntu. Eu estava usando o Ansible assim:

- name: Make virtual environment
  shell: source /home/username/.bashrc && makevirtualenv virenvname
  args:
    executable: /bin/bash

mas o comando de origem não estava funcionando.

Por fim, descobri que o arquivo .bashrc tem algumas linhas na parte superior do arquivo que impedem que o código-fonte funcione quando chamado por Ansible:

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Comentei essas linhas em .bashrc e tudo funcionou conforme o esperado depois disso.

Gwerner
fonte
Isso é um cabeçalho perfeitamente razoável e padrão para a maioria dos .bashrcarquivos. Você provavelmente deseja criar um arquivo de shell diferente ou usar BASH_ENVconforme discutido nos documentos do bash.
2

Bem, eu tentei as respostas listadas, mas elas não funcionaram para mim durante a instalação do Ruby através do rbenv . Tive que fornecer as linhas abaixo de/root/.bash_profile

PATH=$PATH:$HOME/bin:$HOME/.rbenv/bin:$HOME/.rbenv/plugins/ruby-build/bin
export PATH
eval "$(rbenv init -)"

Finalmente, eu vim com isso

- shell: sudo su - root -c 'rbenv install -v {{ ruby_version }}'

Pode-se usar isso com qualquer comando.

- shell: sudo su - root -c 'your command'
vikas027
fonte
1
Essa abordagem clássica funciona com o Ansible 2.2.0.0. No entanto, isso me incomoda e become, em vez disso ... Não consegui descobrir uma combinação desses parâmetros de "método" que funcionasse de qualquer maneira. become_methodbecome_user
Yuri
2

Eu descobri que se tornou a melhor solução:

- name: Source .bashrc
  shell: . .bashrc
  become: true

Você pode alterar o usuário adicionando (padrão: root):

- name: Source .bashrc
  shell: . .bashrc
  become: true
  become-user: {your_remote_user}

Mais informações aqui: Ansible se tornou

Zlopez
fonte
2

Muitas respostas recomendam fonte ~ / .bashrc, mas o problema principal é que o shell ansible não é interativo e a implementação de ~ / .bashrc por padrão ignora o shell não interativo (verifique seu início).

A melhor solução para executar comandos como usuário após seu login interativo SSH que encontrei é:

- hosts: all
  tasks:
    - name: source user profile file
      #become: yes
      #become_user: my_user  # in case you want to become different user (make sure acl package is installed)
      shell: bash -ilc 'which python' # example command which prints
      register: which_python
    - debug:
      var: which_python

bash: '-i' significa shell interativo, então .bashrc não será ignorado '-l' significa shell de login que fornece o perfil completo do usuário

Juraj Michalak
fonte
0

Eu tentei todas as opções acima com ansible 2.4.1.0 e ninguém funciona até as outras duas e aqui está o detalhe para reproduzir o case.

$ cat ~/.bash_aliases 
alias ta="echo 'this is test for ansible interactive shell'";

E este é o teste ansible :

- name: Check the basic string operations
  hosts: 127.0.0.1 
  connection: local

  tasks:
  - name: Test Interactive Bash Failure
    shell: ta
    ignore_errors: True

  - name: Test Interactive Bash Using Source
    shell: source ~/.bash_aliases && ta
    args:
      executable: /bin/bash
    ignore_errors: yes

  - name: Test Interactive Bash Using .
    shell: . ~/.bash_aliases && ta
    ignore_errors: yes

  - name: Test Interactive Bash Using /bin/bash -ci
    shell: /bin/bash -ic 'ta'
    register: result
    ignore_errors: yes

  - debug: msg="{{ result }}"

  - name: Test Interactive Bash Using sudo -ui
    shell: sudo -ui hearen ta
    register: result
    ignore_errors: yes

  - name: Test Interactive Bash Using ssh -tt localhost /bin/bash -ci
    shell: ssh -tt localhost /bin/bash -ci 'ta'
    register: result
    ignore_errors: yes

E este é o resultado:

$ ansible-playbook testInteractiveBash.yml 
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available


PLAY [Check the basic string operations] ************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************
ok: [127.0.0.1]

TASK [Test Interactive Bash Failure] ****************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "ta", "delta": "0:00:00.001341", "end": "2018-10-31 10:11:39.485897", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.484556", "stderr": "/bin/sh: 1: ta: not found", "stderr_lines": ["/bin/sh: 1: ta: not found"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Test Interactive Bash Using Source] ***********************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "source ~/.bash_aliases && ta", "delta": "0:00:00.002769", "end": "2018-10-31 10:11:39.588352", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.585583", "stderr": "/bin/bash: ta: command not found", "stderr_lines": ["/bin/bash: ta: command not found"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Test Interactive Bash Using .] ****************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": ". ~/.bash_aliases && ta", "delta": "0:00:00.001425", "end": "2018-10-31 10:11:39.682609", "failed": true, "msg": "non-zero return code", "rc": 127, "start": "2018-10-31 10:11:39.681184", "stderr": "/bin/sh: 1: ta: not found", "stderr_lines": ["/bin/sh: 1: ta: not found"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Test Interactive Bash Using /bin/bash -ci] ****************************************************************************************************************************************
changed: [127.0.0.1]

TASK [debug] ****************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
    "msg": {
        "changed": true, 
        "cmd": "/bin/bash -ic 'ta'", 
        "delta": "0:00:00.414534", 
        "end": "2018-10-31 10:11:40.189365", 
        "failed": false, 
        "rc": 0, 
        "start": "2018-10-31 10:11:39.774831", 
        "stderr": "", 
        "stderr_lines": [], 
        "stdout": "this is test for ansible interactive shell", 
        "stdout_lines": [
            "this is test for ansible interactive shell"
        ]
    }
}

TASK [Test Interactive Bash Using sudo -ui] *********************************************************************************************************************************************
 [WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo

fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "sudo -ui hearen ta", "delta": "0:00:00.007906", "end": "2018-10-31 10:11:40.306128", "failed": true, "msg": "non-zero return code", "rc": 1, "start": "2018-10-31 10:11:40.298222", "stderr": "sudo: unknown user: i\nsudo: unable to initialize policy plugin", "stderr_lines": ["sudo: unknown user: i", "sudo: unable to initialize policy plugin"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Test Interactive Bash Using ssh -tt localhost /bin/bash -ci] **********************************************************************************************************************
hearen@localhost's password: 
changed: [127.0.0.1]

PLAY RECAP ******************************************************************************************************************************************************************************
127.0.0.1                  : ok=8    changed=6    unreachable=0    failed=0  

Existem duas opções funcionadas:

  • shell: /bin/bash -ic 'ta'
  • shell: ssh -tt localhost /bin/bash -ci 'ta' mas este requer a entrada de senha localmente.
Hearen
fonte
0

Meus 2 centavos, eu circumnavigated o problema abastecimento ~/.nvm/nvm.shem ~/.profilee em seguida, usando sudo -iucomo sugerido em outra resposta.

Julgado em janeiro de 2018 vs Ubuntu 16.04.5

- name: Installing Nvm 
  shell: >
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
  args:
    creates: "/home/{{ ansible_user }}/.nvm/nvm.sh"
  tags:
    - nodejs    

- name: Source nvm in ~/.profile
  sudo: yes
  sudo_user: "{{ ansible_user }}"
  lineinfile: >
    dest=~/.profile
    line="source ~/.nvm/nvm.sh"
    create=yes
  tags: 
    - nodejs
  register: output    

- name: Installing node 
  command: sudo -iu {{ ansible_user }} nvm install --lts
  args:
     executable: /bin/bash
  tags:
    - nodejs    
Realtebo
fonte
-3

O caminho certo deve ser:

- hosts: all
  tasks:
    - name: source bashrc file
      shell: "{{ item }}"
      with_items:
         - source ~/.bashrc
         - your other command

Nota: é um teste na ansible 2.0.2versão

kwin wng
fonte