Ansible command with become and chdir - ansible

I have this:
- name: composer install in includes
become: yes
become_user: git
become_method: sudo
become_flags: '-s'
chdir: /var/www/html/includes
command: php /usr/local/bin/composer install
creates: /var/www/html/includes/vendor
When I run it, I get an error 'Composer could not find a composer.json file in /home/git'. But note that I specified a chdir to /var/www/html/includes which DOES have a composer.json. Note also that, while trying things out, I added become_method and become_flags. -s should tell sudo not to change directories or load environments.
Does anybody know what I am doing wrong?
Thanks, Ed

I think the task should be written this way:
- name: composer install in includes
become: yes
become_user: git
become_method: sudo
become_flags: '-s'
command: php /usr/local/bin/composer install
args:
chdir: /var/www/html/includes
creates: /var/www/html/includes/vendor
For more information you can run:
$ ansible-doc command

Related

Changing user and installing ruby

My Ansible server is communicating as root user with agent but I need to install ruby as different user i.e deploy. So I am trying to switch the user to deploy using 'become' to install ruby but I am facing issue. Its seems that when i am trying to switch the user and running the command its unable to use .bashrc file of deploy user. Below is my YML file
---
- hosts: test1
become: true
tasks:
- name: adding node.js repository
shell: curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
- name: adding yarn pubkey
shell: curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
- name: adding yarn repo
shell: echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
- name: update cache
apt: update_cache=true
- name: install all the below list of packages
apt: name={{ item }} update_cache=true
with_items:
- git-core
- curl
- zlib1g-dev
- build-essential
- libssl-dev
- libreadline-dev
- libyaml-dev
- libsqlite3-dev
- sqlite3
- libxml2-dev
- libxslt1-dev
- libcurl4-openssl-dev
- software-properties-common
- libffi-dev
- nodejs
- yarn
- name: change to deploy home directory
shell: cd
become: true
become_user: deploy
- name: getting repo from git
shell: git clone https://github.com/rbenv/rbenv.git ~/.rbenv
become: true
become_user: deploy
- name: copy path
shell: echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
become: true
become_user: deploy
- name: copy eval
shell: echo 'eval "$(rbenv init -)"' >> ~/.bashrc
become: true
become_user: deploy
- name: execute shell
shell: exec $SHELL
become: true
become_user: deploy
- name: ruby repo
shell: git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
become: true
become_user: deploy
- name: copy paths
shell: echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
become: true
become_user: deploy
- name: shell execute
shell: exec $SHELL
become: true
become_user: deploy
- name: install ruby
shell: rbenv install 2.4.4
become: true
become_user: deploy
- name: set global
shell: rbenv global 2.4.4
become: true
become_user: deploy
I am getting the below error:
TASK [install ruby] ***************
fatal: [host1]: FAILED! => {"changed": true, "cmd": "rbenv install
2.4.4", "delta": "0:00:00.003186", "end": "2018-09-25 15:43:23.224716", "msg": "non-zero return code", "rc": 127, "start":
"2018-09-25 15:43:23.221530", "stderr": "/bin/sh: 1: rbenv: not
found", "stderr_lines": ["/bin/sh: 1: rbenv: not found"], "stdout":
"", "stdout_lines": []}
But when I am providing the path manually in command for rbenv its working fine. As shown below:
- name: install ruby
shell: /home/deploy/.rbenv/bin/rbenv install 2.4.4
become: true
become_user: deploy
Can you please tell me why its behaving like this?
I need to install bundler also using gem. I am switching to user 'deploy' but its going to check the root user directory instead of deploy user and giving error. Please refer the below YML part for gem and error:
- name: install bundler
shell: gem install bundler
become: true
become_user: deploy
Below is the error for bundler:
TASK [install bundler] *********
fatal: [host1]: FAILED! => {"changed": true, "cmd": "gem install
bundler", "delta": "0:00:02.396195", "end": "2018-09-25
16:21:18.703899", "msg": "non-zero return code", "rc": 1, "start":
"2018-09-25 16:21:16.307704", "stderr": "ERROR: While executing gem
... (Gem::FilePermissionError)\n You don't have write permissions
for the /var/lib/gems/2.3.0 directory.", "stderr_lines": ["ERROR:
While executing gem ... (Gem::FilePermissionError)", " You don't
have write permissions for the /var/lib/gems/2.3.0 directory."],
"stdout": "", "stdout_lines": []}
Please help me to fix the issue.
Thanks.
That playbook does not do what you think it does, because every one of those tasks is effectively its own ssh connection. So, this:
- name: change to deploy home directory
shell: cd
become: true
become_user: deploy
- name: execute shell
shell: exec $SHELL
... is equivalent to ssh root#the-host "su deploy -c 'cd; exit'"; ssh root#the-host "su deploy -c 'exec $SHELL; exit'" and so forth.
You'll very like also want to move all of those tasks that run as deploy into their own playbook or role, and include them with those become: true and become: deploy at the include or role level to keep from repeating that text all over the tasks.
But even if you don't do that, the shortest path to success is to collapse all 10 of those steps into just one shell: | block to rescue your sanity and reinforce that they all need to happen in the same shell session
- name: install ruby using rbenv
become: true
become_user: deploy
shell: |
set -e # <-- stop running this script if something fails
cd $HOME
export ... # etc etc
args:
creates: /home/deploy/.rbenv/versions/2.4.4/bin/ruby
Optionally including that args: creates: business will give ansible a fighting chance to skip that step if it has already provisioned rbenv. You will, of course, likely want to update that to guard the step in a way that is more relevant to what you're trying to do.

How to run apt update and upgrade via Ansible shell

I'm trying to use Ansible to run the following two commands:
sudo apt-get update && sudo apt-get upgrade -y
I know with ansible you can use:
ansible all -m shell -u user -K -a "uptime"
Would running the following command do it? Or do I have to use some sort of raw command
ansible all -m shell -u user -K -a "sudo apt-get update && sudo apt-get upgrade -y"
I wouldn't recommend using shell for this, as Ansible has the apt module designed for just this purpose. I've detailed using apt below.
In a playbook, you can update and upgrade like so:
- name: Update and upgrade apt packages
become: true
apt:
upgrade: yes
update_cache: yes
cache_valid_time: 86400 #One day
The cache_valid_time value can be omitted. Its purpose from the docs:
Update the apt cache if its older than the cache_valid_time. This
option is set in seconds.
So it's good to include if you don't want to update the cache when it has only recently been updated.
To do this as an ad-hoc command you can run:
$ ansible all -m apt -a "upgrade=yes update_cache=yes cache_valid_time=86400" --become
ad-hoc commands are described in detail here
Note that I am using --become and become: true. This is an example of typical privilege escalation through Ansible. You use -u user and -K (ask for privilege escalation password). Use whichever works for you, this is just to show you the most common form.
Just to add a flavour on the answer. This one is an executable playbook in all the hosts specified in your inventory file.
- hosts: all
become: true
tasks:
- name: Update and upgrade apt packages
apt:
upgrade: yes
update_cache: yes
cache_valid_time: 86400
Using Ubuntu 16.04, I did a little adjustement:
- name: Update and upgrade apt packages
become: true
apt:
update_cache: yes
upgrade: 'yes'
I juste put the upgrade yes between apostrophe to avoid un annoying warning:
[WARNING]: The value True (type bool) in a string field was converted to u'True' (type string). If this does
not look like what you expect, quote the entire value to ensure it does not change.
At 2020, I would like just to comment into the original answer, but no enough reputation at that time...
Ref:
The value True (type bool) in a string field was converted to u'True' (type string)
We use the following command to update and upgrade all packages :
ansible all -m apt -a "name='*' state=latest update_cache=yes upgrade=yes" -b --become-user root

Ansible non-root sudo user and "become" privilege escalation

I've set up a box with a user david who has sudo privileges. I can ssh into the box and perform sudo operations like apt-get install. When I try to do the same thing using Ansible's "become privilege escalation", I get a permission denied error. So a simple playbook might look like this:
simple_playbook.yml:
---
- name: Testing...
hosts: all
become: true
become_user: david
become_method: sudo
tasks:
- name: Just want to install sqlite3 for example...
apt: name=sqlite3 state=present
I run this playbook with the following command:
ansible-playbook -i inventory simple_playbook.yml --ask-become-pass
This gives me a prompt for a password, which I give, and I get the following error (abbreviated):
fatal: [123.45.67.89]: FAILED! => {...
failed: E: Could not open lock file /var/lib/dpkg/lock - open (13:
Permission denied)\nE: Unable to lock the administration directory
(/var/lib/dpkg/), are you root?\n", ...}
Why am I getting permission denied?
Additional information
I'm running Ansible 2.1.1.0 and am targeting a Ubuntu 16.04 box. If I use remote_user and sudo options as per Ansible < v1.9, it works fine, like this:
remote_user: david
sudo: yes
Update
The local and remote usernames are the same. To get this working, I just needed to specify become: yes (see #techraf's answer):
Why am I getting permission denied?
Because APT requires root permissions (see the error: are you root?) and you are running the tasks as david.
Per these settings:
become: true
become_user: david
become_method: sudo
Ansible becomes david using sudo method. It basically runs its Python script with sudo david in front.
the user 'david' on the remote box has sudo privileges.
It means david can execute commands (some or all) using sudo-executable to change the effective user for the child process (the command). If no username is given, this process runs as the root account.
Compare the results of these two commands:
$ sudo whoami
root
$ sudo david whoami
david
Back to the APT problem, you (from CLI) as well as Ansible (connecting with SSH using your account) need to run:
sudo apt-get install sqlite3
not:
sudo david apt-get install sqlite3
which will fail with the very exact message Ansible displayed.
The following playbook will escalate by default to the root user:
---
- name: Testing...
hosts: all
become: true
tasks:
- name: Just want to install sqlite3 for example...
apt: name=sqlite3 state=present
remote_user is david. Call the script with --ask-pass and give password for david. If david doesn't have passwordless sudo, then you should also call it with --ask-become-pass.
- name: Testing...
hosts: all
remote_user: david
become: true
become_method: sudo
tasks:
- name: Just want to install sqlite3 for example...
apt: name=sqlite3 state=present
I have the same issue.
The issue is solved by using root and --ask-become-pass --ask-pass command together.
- name: Testing...
hosts: all
remote_user: root
become: true
become_method: sudo
tasks:
- name: Just want to install sqlite3 for example...
apt: name=sqlite3 state=present
ansible-playbook playbook.yml --ask-become-pass --ask-pass

Can't find the syntax issue with this Ansible playbook

I'm attempting to run an Ansible playbook and I can't find out, through documentation or by looking at examples, what is wrong with my playbook.
---
- hosts: all
sudo: yes
pre_tasks:
ignore_errors: True
tasks:
command: sudo apt-get install build-essential libssl-dev libffi-dev python-dev python-pip
command: sudo pip install caravel
command: fabmanager create-admin --app caravel
command: caravel db upgrade
command: caravel init
command: caravel runserver -p 8088
- copy: src=../zika.db dest=zika.db
failed_when: false
I've been chasing my tail and I don't understand this error:
The offending line appears to be:
---
- hosts: all
^ here
command is a task, and tasks is a list, so you should prefix every task with a dash.
tasks:
- command: ....
- command: ....
....

Using Ansible, how can I install PythonBrew system-wide?

I'm trying to create a playbook with Ansible (v 1.3.3) to install Pythonbrew system-wide on a Debian server following the instructions in the Pythonbrew readme file.
I am able to get Pythonbrew installed but I cannot install the specific version of Python that I want with it. I suspect the issue has to do with the shell environment Ansible is running under.
Here's my playbook script:
- name: Install and configure PythonBrew
hosts: dev
user: root
vars_files:
- vars.yml
gather_facts: false
tasks:
- name: Install PythonBrew Debian packages
apt: pkg=${item} state=installed update-cache=yes
with_items: ${pythonbrew_packages}
- name: Install PythonBrew system-wide
shell: curl -kL http://xrl.us/pythonbrewinstall | bash creates=/usr/local/pythonbrew executable=/bin/bash
- name: Update bashrc for PythonBrew
lineinfile:
dest=~/.bashrc
regexp='^'
line='[[ -s $HOME/.pythonbrew/etc/bashrc ]] && source $HOME/.pythonbrew/etc/bashrc'
state=present
create=True
- name: Install python binary
shell: pythonbrew install -v ${python_version} executable=/bin/bash
When I run this playbook, it fails with the following output
failed: [devserver] => {"changed": true, "cmd": "pythonbrew
install -v 2.7.3 ", "delta": "0:00:00.016639", "end": "2013-10-11
15:21:40.989677", "rc": 127, "start": "2013-10-11 15:21:40.973038"}
stderr: /bin/bash: pythonbrew: command not found
I've been tweaking things for the last hour or so to no avail. Does anybody have any suggestions for fixing this?
By peeking at the PythonBrew install script, I was able to figure this out. (And just in time for the deprecation of PythonBrew!)
Here's the playbook that installs PythonBrew without manual intervention. This may be of interest to anyone trying to script PythonBrew to install automatically.
vars.yml
#
# Python/PythonBrew Settings
# TODO: replace old-style Ansible ${vars} with jinja-style {{ vars }}
#
project_name: MY_PROJECT
python:
version: 2.7.3
pythonbrew:
root: /usr/local/pythonbrew
bashrc_path: $HOME/.pythonbrew/etc/bashrc
packages:
- curl
- zlib1g-dev
- libsqlite3-dev
- libssl-dev
- libxml2
- libxml2-dev
- libxslt1-dev
- libmysqlclient-dev
- libbz2-dev
pythonbrew.yml
---
#
# Install and Configure PythonBrew
#
- name: Install and configure PythonBrew
hosts: MY_HOST
user: root
vars_files:
- vars.yml
gather_facts: false
tasks:
- name: Install PythonBrew Debian packages
apt: pkg=${item} state=installed update-cache=yes
with_items: ${pythonbrew.packages}
- name: Install PythonBrew system-wide
shell: curl -kL http://xrl.us/pythonbrewinstall | bash
executable=/bin/bash
creates=${pythonbrew.root}
- name: Update bashrc for PythonBrew
lineinfile:
dest=/root/.bashrc
regexp='^'
line='[[ -s ${pythonbrew.bashrc_path} ]] && source ${pythonbrew.bashrc_path}'
state=present
create=True
# This step allows install to continue without new shell. Pulled from:
# https://github.com/utahta/pythonbrew/blob/master/pythonbrew/installer/pythonbrewinstaller.py#L91
- name: Install python binary
shell: export PYTHONBREW_ROOT=${pythonbrew.root}; source ${pythonbrew.root}/etc/bashrc; pythonbrew install ${python.version}
executable=/bin/bash
- name: Switch to python version
shell: export PYTHONBREW_ROOT=${pythonbrew.root}; source ${pythonbrew.root}/etc/bashrc; pythonbrew switch ${python.version}
executable=/bin/bash

Resources