【问题标题】:Not possible to source .bashrc with Ansible无法使用 Ansible 获取 .bashrc
【发布时间】:2014-03-07 17:34:49
【问题描述】:

我可以通过 ssh 连接到远程主机并执行 source /home/username/.bashrc - 一切正常。 但是,如果我这样做:

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

我明白了:

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

我不知道我做错了什么......

【问题讨论】:

  • source 仅在您在现有 shell 中运行时才有意义 - 它在该 shell 中运行命令 ,因此只有在存在现有 shell 时才有用/有帮助您要更改其状态或配置。当您运行一个 ansible 操作时,that 创建一个全新的 shell,并在 that shell 中运行一个命令——因此您不会在任何其他地方更新环境变量上下文,所以它实际上不会有任何有用/持久的效果,即使你让它运行没有错误。
  • @CharlesDuffy 如果您想执行一个需要定义环境变量的命令,那么尝试使用 .bashrc 或 .bash_profile 之类的东西来定义这些变量是一个有效的用例,不是吗?
  • @htellez,运行source 只定义变量在它运行的shell 期间。并且在 ansible 命令退出并且下一个命令开始时,该 shell 已经退出(并且它定义的变量已丢失)。
  • @htellez, ...因此,这里唯一真正有用的答案是the one by Steve Midgley,因为它让您在之前运行source的同一个shell中做其他事情它退出了。
  • 这正是我试图描述的用例,如果我不清楚,我很抱歉。我试图描述一个场景,在这个场景中,您想要运行一些需要定义特定环境的东西。我来到这个线程是因为我遇到了同样的错误,通过阅读Steve's answer,我意识到 ansible 的 shell 任务默认使用 sh 而不是 bash。将命令显式设为 bash 命令会使 source 以您最可能习惯的方式工作。

标签: ansible


【解决方案1】:

您有两个选项可以将源代码与 ansible 一起使用。一种是使用“shell:”命令和 /bin/sh(ansible 默认值)。 “源”称为“。”在 /bin/sh 中。所以你的命令是:

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

请注意,您必须在采购 .bashrc b/c 之后运行命令,每个 ssh 会话都是不同的 - 每个 ansible 命令都在单独的 ssh 事务中运行。

您的第二个选项是强制 Ansible shell 使用 bash,然后您可以使用“source”命令:

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

最后,我要指出的是,如果您使用的是 Ubuntu 或类似系统,您可能希望实际获取“/etc/profile”,这更完全地模拟了本地登录。

【讨论】:

  • 另请注意,此问题已作为 Ansible 核心中的错误/功能请求提交(并由我评论)。但 Ansible 关闭它并说“写一个插件”。呸。 github.com/ansible/ansible/issues/4854
  • 你在读我的心吗?你在 3 个月前回答了这个问题,我正在考虑编辑这个 . -> source - 你马上就这样做了 :)
  • 我试过source "/etc/profile" - 它对我不起作用。这有效:source "~/.profile"
  • 我在 .bashrc 中定义了一些 bash 函数,并且在获取 .bashrc 之后。如何执行/调用这些函数?我正在尝试shell: . ~/.bashrc && nvm install {{ node_version }},它说的是nvm command not found。我该如何解决这个问题?
  • @RaviTezu:我的问题是由于 .bashrc 中的以下几行: ;; *) 返回;; esac 这至少是 ubuntu-16.04 xenial64 上的一个问题,其中 .bashrc 不在非交互式 shell 上运行,这是通过 ssh 运行命令时的情况。要尝试一下,请在 ~/.bashrc 中设置一些 PATH 并运行(假设您已在来宾操作系统上将端口 2222 转发到 22): ssh -p 2222 ubuntu@127.0.0.1 'echo $PATH' 如果上述命令没有' t 显示您在 .bashrc 中设置的 PATH 然后修复 .bashrc
【解决方案2】:

所以command 只会运行可执行文件。 source 本身不是可执行文件。 (这是一个内置的 shell 命令)。 你有什么理由要source 一个完整的环境变量吗?

还有其他方法可以在 Ansible 中包含环境变量。例如,environment 指令:

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

另一种方法是使用shell Ansible 模块:

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

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

在这些情况下,一旦运行 Ansible 步骤,shell 实例/环境就会终止。

【讨论】:

  • 差不多好了,不幸的是 /bin/sh 没有 source commmand only 。所以shell source /home/username/.bashrc 变成了shell . /home/username/.bashrc
  • shell 任务采用这样的参数:executable=/usr/bin/bash,如果可用,它将在 bash 中运行它。
【解决方案3】:

我知道这个答案来得太晚了,但我已经看到足够多的代码,你可以使用 sudo 选项-i 所以:

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

如文档中所述

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.

【讨论】:

    【解决方案4】:

    我在尝试让 virtualenvwrapper 在 Ubuntu 服务器上工作时遇到了同样的问题。我是这样使用 Ansible 的:

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

    但源命令不起作用。

    最终我发现 .bashrc 文件在文件顶部有几行阻止源在被 Ansible 调用时工作:

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

    我在 .bashrc 中注释掉了这些行,之后一切正常。

    【讨论】:

    • 对于大多数.bashrc 文件来说,这是完全合理且标准的标题。您可能想要获取不同的 shell 文件,或使用 bash 文档中讨论的 BASH_ENV
    【解决方案5】:

    许多回复建议使用 ~/.bashrc,但主要问题是 ansible shell 不是交互式的,并且 ~/.bashrc 实现默认忽略非交互式 shell(检查它的开头)。

    我发现在 ssh 交互式登录后以用户身份执行命令的最佳解决方案是:

    - 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' 表示交互式 shell,所以 .bashrc 不会被忽略 '-l' 表示登录 shell,它获取完整的用户配置文件

    【讨论】:

      【解决方案6】:

      好吧,我尝试了列出的答案,但在通过rbenv 安装 ruby​​ 时这些答案对我不起作用。我必须从/root/.bash_profile 获取以下行来源

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

      最后,我想出了这个

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

      任何命令都可以使用它。

      - shell: sudo su - root -c 'your command'
      

      【讨论】:

      • 这种经典方法适用于 Ansible 2.2.0.0。但是,我应该使用becomebecome_methodbecome_user 来代替...我无法弄清楚这些“方法”参数的组合无论如何都可以工作。
      【解决方案7】:

      我发现成为最佳解决方案:

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

      您可以通过添加更改用户(默认:root):

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

      更多信息在这里:Ansible become

      【讨论】:

        【解决方案8】:

        我已经用 ansible 2.4.1.0 尝试了上述所有选项,直到另外两个选项都没有工作,这里是重新生成案例的详细信息。

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

        这就是 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
        

        结果如下:

        $ 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  
        

        有两种选择:

        • shell: /bin/bash -ic 'ta'
        • shell: ssh -tt localhost /bin/bash -ci 'ta' 但是这个需要在本地输入密码。

        【讨论】:

          【解决方案9】:

          我的 2 美分,我将问题源 ~/.nvm/nvm.sh 转为 ~/.profile,然后按照另一个答案中的建议使用 sudo -iu

          在 2018 年 1 月与 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    
          

          【讨论】:

            【解决方案10】:

            正确的方法应该是:

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

            注意:在ansible 2.0.2版本中测试

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2020-10-20
              • 2023-01-30
              • 2017-03-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多