I am using ansible 1.9 and want to run two commands. I have tried several variations:
- name: npm build
command: npm run build
args:
chdir: "{{ app_dir }}"
- name: clean up
shell: sed_index.sh
args:
chdir: "{{ app_dir }}"
On running I get the following error:
"stderr": "/bin/sh: 1: npm: not found"
However
npm run build
works fine when I log in to the server and run it in the app_dir.
I also tried:
- name: npm install and clean
command: "{{ item }} chdir={{ app_dir }}"
with_items:
- npm run build
- sed_index.sh
Again I get a npm not found error.
If I comment out the npm run build command I get an error when running the sed_index script on the 'cd dist' command below, saying 'dist' not found.
sed_index.sh
#!/usr/bin/env bash
cd dist
sed -i 's|=static/css/font-awesome.min.css rel=stylesheet>|=/app/static/css/font-awesome.min.css rel=stylesheet>|g' index.html
Any ideas?
The npm executable is probably not in a standard location like /usr/bin/npm. Probably /usr/local/bin/npm, but it's up to you to find where it's installed and use the fully qualified path. From a login that can run the npm command, execute 'which npm'. The output will be what you want to use instead of just npm.
FYI - When I'm doing a one-off or other small task that I don't want to take the time to write a playbook for, if it's not an easy one liner in Ansible I write a small script to execute via the script module. One of the first commands in those scripts is to set the PATH if I know some of the commands are in non-standard locations.
Use full path to the npm executable. Ansible runs commands in non-interactive shell session and your environment set in rc files is not read.
Regarding the second problem: if you get a "'dist' not found" error, it means either dist directory does not exist, or you call it from a wrong directory. It's impossible to tell given the information you provided.
#techraf answer should help you to solve this issue.
For some reason if you look for an alternate way, give a try like below with ansible command:
ansible -m shell -a "/bin/bash -c 'cd {{app_dir}} && npm run build && ./sed_index.sh'" -e "app_dir=/path/to/app_dir" <host/group name>
You should be able to convert it back to your playbook once you get it running.
Related
- name: Go to the folder
command: chdir=/opt/tools/temp
When I run my playbook, I get:
TASK: [Go to the folder] *****************************
failed: [host] => {"failed": true, "rc": 256}
msg: no command given
Any help is much appreciated.
There's no concept of current directory in Ansible. You can specify current directory for specific task, like you did in your playbook. The only missing part was the actual command to execute. Try this:
- name: Go to the folder and execute command
command: chdir=/opt/tools/temp ls
This question was in the results for when I was trying to figure out why 'shell' was not respecting my chdir entries when I had to revert to Ansible 1.9. So I will be posting my solution.
I had
- name: task name
shell:
cmd: touch foobar
creates: foobar
chdir: /usr/lib/foobar
It worked with Ansible > 2, but for 1.9 I had to change it to.
- name: task name
shell: touch foobar
args:
creates: foobar
chdir: /usr/lib/foobar
Just wanted to share.
If you need a login console (like for bundler), then you have to do the command like this.
command: bash -lc "cd /path/to/folder && bundle install"
You can change into a directory before running a command with ansible with chdir.
Here's an example I just setup:
- name: Run a pipenv install
environment:
LANG: "en_GB.UTF-8"
command: "pipenv install --dev"
args:
chdir: "{{ dir }}/proj"
What is the difference between raw, shell and command in the ansible playbook? And when to use which?
command: executes a remote command on the target host, in the same shell of other playbook's tasks.
It can be used for launch scripts (.sh) or for execute simple commands. For example:
- name: Cat a file
command: cat somefile.txt
- name: Execute a script
command: somescript.sh param1 param2
shell: executes a remote command on the target host, opening a new shell (/bin/sh).
It can be used if you want to execute more complex commands, for example, commands concatenated with pipes. For example:
- name: Look for something in a file
shell: cat somefile.txt | grep something
raw: executes low-level commands where the interpreter is missing on the target host, a common use case is for installing python. This module should not be used in all other cases (where command and shell are suggested)
Since I were I stumbling about the same question, I wanted to share my findings here too.
The command and shell module, as well gather_facts (annot.: setup.py) depend on a properly installed Python interpreter on the Remote Node(s). If that requirement isn't fulfilled one may experience errors were it isn't possible to execute
python <ansiblePython.py>
In a Debian 10 (Buster) minimal installation i.e., python3 was installed but the symlink to python missing.
To initialize the system correctly before applying all other roles, I've used an approach with the raw module
ansible/initSrv/main.yml
- hosts: "{{ target_hosts }}"
gather_facts: no # is necessary because setup.py depends on Python too
pre_tasks:
- name: "Make sure remote system is initialized correctly"
raw: 'ln -s /usr/bin/python3 /usr/bin/python'
register: set_symlink
failed_when: set_symlink.rc != 0 and set_symlink.rc != 1
which is doing something like
/bin/sh -c 'ln -s /usr/bin/python3 /usr/bin/python'
on the remote system.
Further Documentation
raw module – Executes a low-down and dirty command
A common case is installing python on a system without python installed by default.
... but not only restricted to that
Playbook Keyword - pre_tasks
A list of tasks to execute before roles.
Set the order of task execution in Ansible
I'm trying to run the following ansible playbook to start the "nexus" service on remote server at path "nexux/bin" it gets failed :
- hosts: nexus
become: yes
become_user: nexus
become_method: sudo
tasks:
- name: changing dir and starting nexus service
shell:
chdir: nexux/bin
executable: ./nexus start
Can someone troubleshoot here to deduce the root cause ?
As the ansible output very clearly told you, in that syntax you did not provide a command. The executable: is designed to be the shell executable, not the "run this thing" argument. It is very clear in the examples section of the fine manual
- shell: cd /opt/nexus/bin && ./nexus start
If you want to use the chdir: option, you must put it under a sibling yaml key to the shell:, like so:
- shell: echo hello world
args:
chdir: /opt/nexus/bin
# I'm omitting the "executable:" key here, because you for sure
# do not want to do that, but if you did, then fine, put it here
Having said all of that, as the docs also indicate, what you really want is to use command: because you are not making use of any special shell characters (redirects, pipes, && phrases, etc), so:
- command: ./nexus start
args:
chdir: /opt/nexus/bin
Try use the shell module, i also recommend to run with nohup and send the output to a file
- shell: |
cd /opt/nexus/bin
nohup ./nexus start > /tmp/nexus.log 2>&1 &
I'm setting up an Ansible role to install Ahsay Offsite Backup Server.
After downloading and extracting the compressed file containing the software, I need to run the install script. I've determined that it's a step early in the script where it checks that your current user has appropriate permissions which is failing to run.
When I run the playbook, the final task never finishes.
The role
- name: Check if OBS install files have already been downloaded
stat:
path: /tmp/obs/version.txt
register: stat_result
- name: Ensures /tmp/obs exists
file: path=/tmp/obs state=directory
- name: Download and extract OBS install files
unarchive:
src: https://ahsay-dn.ahsay.com/v6/obsr/62900/obsr-nix.tar.gz
dest: /tmp/obs
remote_src: true
validate_certs: no
when: stat_result.stat.exists == false
- name: Install OBS
command: bash -lc "/tmp/obs/bin/install.sh > /tmp/install_output.log"
The playbook configuration is for all tasks to become sudo.
If I run the command in a shell on the remote host, it executes successfully.
I've hit similar issues before where commands fail because (in the case of rvm) it requires the bash_profile to load and pull in a bunch of environment variables first. The fix for that was as I've done above, to wrap the command in bash -lc "...", but that hasn't helped this time.
I'd love any suggestions of how I could continue troubleshooting this one.
you are checking for file presence before ensuring the folder.
some applications require tty, and when not on it they ask some stupid question
to really debug while the command is "stuck" connect to the offending machine, and try analyzing what does the script do: look in its /proc/${PID} folder (if you're on linux), maybe connect to it via strace -p ${PID} and maybe dup its stderr to see maybe it prints something that makes sense to you.
Also, you don't really have to run command, you can use shell module, and specify its args to make sure the command runs from specific folder, like so:
- name: Install OBS
shell: |
./bin/install.sh \
1> /tmp/install.output.log \
2> /tmp/install.error.log
args:
executable: /bin/bash
chdir: /tmp/obs
I'm using Ansible to deploy (Git clone, run the install script) a framework to a server. The install step means running the install.sh script like this:
- name: Install Foo Framework
shell: ./install.sh
args:
chdir: ~/foo
How can I determine whether I have executed this step in a previous run of Ansible? I want to add a when condition to this step that only executes if the install.sh script hasn't been run previously.
The install.sh script does a couple of things (replacing some files in the user's home directory), but it's not obvious whether the script was run before from just taking a look at the files. The ~/foo.sh file might have existed before, it's not clear whether it was replaced by the install script or was there before.
Is there a way in Ansible to store a value on the server that let's me determine whether this particular task has been executed before? Or should I just create a marker file in the user's home directory (e.g. ~/foo-installed) that I check in later invocations of the playbook?
I suggest to use the script module instead. This module has a creates parameter:
a filename, when it already exists, this step will not be run. (added in Ansible 1.5)
So your script then could simply touch a file which would prevent execution of the script in subsequent calls.
Here's how I solved it in the end. The pointer to using the creates option helped:
- name: Install Foo Framework
shell: ./install.sh && touch ~/foo_installed
args:
chdir: ~/foo
creates: ~/foo_installed
Using this approach, the ~/foo_installed file is only created when the install script finished without an error.