I have 3 VM's for ansible as follows:
master
host1
host2
ansible is installed and configured correctly. no issue with that part.
So I have this command I need to run. Before going to execute this command using ansible, I will show you how to do this without ansible :
I want to install update the packages first, so I am logged into the VM as a normal user (ubuntut) and execute like this:
sudo apt-get update -y
As you can see, I have executed a sudo command when I am logged in as the ubuntu user but not as a root user.
So above command is executed with sudo but user is ubuntu
I want this scenario to be done using ansible.
My Question: How to execute a command that contains sudo using ansible but when logged in as a different user
So my playbook will look like this:
- hosts: all
tasks:
- name: Update and upgrade apt packages
become: ubuntu
apt:
upgrade: yes
update_cache: yes
But where can I add the sudo part in above playbook ? does it add automatically?
What if I want to execute a command like this, logged in user as ubuntu:
sudo apt-get install docker
How can I do this sudo part in ansible while become: ubuntu
To invoke a command as sudo, You can do something like this :
- hosts: all
tasks:
- name: Update and upgrade apt packages
become: ubuntu
# this will fail because /opt needs permissions
# shell: echo hello > /opt/testfile
# this will work
shell: "sudo sh -c 'echo hello > /opt/testfile'"
# use this to verify output
register: out
- debug:
msg: "{{ out }}"
NOTE: you will get this warning:
"Consider using 'become', 'become_method', and 'become_user' rather
than running sudo"
The following will work, you can find a detailed explanation and examples in ansible documentation.
[1]https://docs.ansible.com/ansible/latest/user_guide/become.html
- hosts: all
tasks:
- name: Update and upgrade apt packages
become: true
become_user: ubuntu
shell: echo hello > /opt/testfile
# use this to verify output
register: out
- debug:
msg: "{{ out }}"
Related
I'm using Ansible to clone a repository to a remote host and install the software there:
---
- hosts: ubuntu-16.04
become: yes
tasks:
- name: Install aptitude
apt:
name: aptitude
state: latest
update_cache: yes
- name: Update apt cache and upgrade packages
apt:
update_cache: yes
upgrade: full
autoclean: yes
autoremove: yes
- name: Clone <name of repository> repository
git:
repo: <link to repository>
dest: /home/test/Downloads/<new directory>
clone: yes
- name: Install <name of repository>
command: chdir=/home/test/Downloads/<new directory> {{ item }}
with_items:
- make
- make install
become_user: root
become_method: sudo
- name: Remove <name of repository> directory
file:
path: /home/test/Downloads/<new directory>
state: absent
This works fine if the software isn't already installed on the system. However, if it is and I run the playbook again, then it gets stuck at the "Install ..." task, saying that it failed to create symlinks as files already exist.
The first problem is that several tasks after this one (not shown here) are not executed due to the play exiting there. I could solve this by simply reordering my tasks, but what I really would like to know, please:
How do I make Ansible overwrite existing files?
Would you even solve this that way, or would you say that this behavior is fine as the software is already installed? But what if the repository contains newer code the second time it is cloned?
I don't think the problem is related to Ansible, rather to the Makefile. Nevertheless, you could simply skip the installation step when the software is already installed.
First you could check if the binary already exists, and based on the output you can skip the installation:
name: Check if software exists
stat:
path: <path to binary>
register: stat_result
name: Install <name of repository>
command: chdir=/home/test/Downloads/<new directory> {{ item }}
with_items:
- make
- make install
become_user: root
become_method: sudo
when: stat_result.stat.exists == False
testuser is a sudo user,
sudo cat /etc/sudoers.d/90-cloud-init-testuser
testuser ALL=(ALL) NOPASSWD:ALL
I can login testuser manually and run following without password:
sudo -H apt-get update
sudo -H apt-get upgrade
but if I run following ansible code, although I saw whoami command return testuser, then the code stops with fatal error (see code and error below).
Must I set become_user as root in order to run (see the line I comment out)? Note I CAN login testuser manually and run sudo command, can't I use become_user=testuser to Install apt? Note I think remote_user does not matter because whoami command only depends on become_user.in fact I feel remote_user is useless, it just log me in. if become_user is unset. then whoami become root, if become_user is set as testuser, then whoami become testuser.
- hosts: all
remote_user: ubuntu
become: yes
become_user: testuser
gather_facts: yes
become_method: sudo
tasks:
- name: test which user I am
shell: whomami
register: hello
- debug: msg="{{ hello.stdout }}"
- name: Update and upgrade apt.
# become_user: root
# become: yes
apt: update_cache=yes upgrade=dist cache_valid_time=3600
TASK [Update and upgrade apt.]
********************************
fatal: [XX.XX.XX.XX]: FAILED! => {"changed": false, "msg":
"'/usr/bin/apt-get dist-upgrade' 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", "rc":
100, "stdout": "", "stdout_lines": []}
You need to connect with an account which has sudo permissions ― in your case testuser ― and then run play/task with elevated permissions (become: true, and become: root which is default), so:
either add sudo permissions to ubuntu,
or connect with testuser.
sudo does not work the way you imply in the question.
Any command runs in a context of a specific user ― either testuser, or ubuntu, or root. There is no such thing as running a command as a "sudo testuser".
sudo executes a command as a different user (root by default). User executing sudo must have appropriate permissions.
If you log in as testuser and execute sudo -H apt-get update it is (almost*) the same as if you logged in as root and ran apt-get update.
If you log in as ubuntu and run sudo -u testuser apt-get update (which is a shell counterpart to the Ansible tasks in the question) ― it is (almost*) the same as if you logged on with testuser and ran apt-get update.
testuser running apt-get update will get an error ― and this is what you get.
* "almost", because it depends on settings regarding environment variables ― not relevant to the problem here.
I'm trying to install java on several hosts with Ansible.
I looked for some examples of expect module to provide answers to the prompts.
I think this syntax is quite fine:
- hosts: datanode
sudo: yes
sudo_user: root
tasks:
- expect:
name: install java jdk 7
command: apt-get install openjdk-7-jdk
responses:
Question:
'Do you want to continue? [Y/n]': 'Y'
But when I try to execute ansible-playbook file.yml I receive the error:
ERROR! conflicting action statements (expect, command)
The error appears to have been in '/root/scp.yml': line 5, column 5, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- expect:
^ here
Where is the problem?
(I have installed ansible 2.0.1.0, pexpect, python)
Thanks!
NOTE that Ansible works with yaml files, and this kind of files are indented. This means that the spaces you put before each statement are important to let Ansible to understand how are they nested. More info about yaml.
Corrected task:
- hosts: datanode
sudo: yes
sudo_user: root
tasks:
- name: install java jdk 7
expect:
command: apt-get install openjdk-7-jdk
responses:
Question:
- 'Y'
- 'n'
This will avoid your syntax error.
Source: http://docs.ansible.com/ansible/expect_module.html
Alternatively, if you always want to say "yes" to your apt-get install commands, you can add the -y argument:
apt-get install -y openjdk-7-jdk
Or even better, use the apt Ansible module.
The issue: When I try to install a package ansible does not proceed. The CLI just sits there idle.
SSH is cofigured to connect with out prompting for a password. I have created a user called "test" and my sudoers file has the following configuration:
test ALL=(ALL) NOPASSWD:ALL
Also in /etc/ansible/ansible.cfg
inventory = /etc/ansible/hosts
#library = /usr/share/my_modules/
remote_tmp = $HOME/.ansible/tmp
pattern = *
forks = 5
poll_interval = 15
sudo_user = root
#ask_sudo_pass = True
#ask_pass = True
transport = smart
#remote_port = 22 module_lang = C
When as user "test" I do
yum install lynx
the package specified gets installed.
But if I do
ansible local -s -m shell -a 'yum install lynx'
Nothing happens.
I am not sure what is going on :(
Try using the yum module instead:
ansible local -s -m yum -a 'name=lynx state=present'
You have to say "yes" to yum:
Try this instead:
ansible local -s -m shell -a 'yum install lynx -y'
You should be using either the yum module or even better, the package module which is OS generic.
On the other hand, you other option is the raw module which runs an SSH-dirty command against your nodes!
This is an example for using the package module in a task:
----
- hosts: <hosts_names>
sudo: yes
tasks:
- name: install lynx
register: result
package: name=lynx state=latest
become: yes
become_user: root
become_method: sudo
ignore_errors: True
Using the above playbook, hopefully helps you to install you desired package and even if it did not do that, you'll be able to easy go through the result variable and see what's going wrong.
And of course before all these, you should've made sure that your YUM repository/ies work propeprly!
I'm using Ansible to set up Ubuntu-based Vagrant and DigitalOcean boxes, and want to use pyenv to manage environments for a few different websites.
I'm having a problem with permissions when trying to install a version of python using the pyenv I've installed, which is probably down to my lack of basic *nix knowledge.
I have a deploy user and group, who I've installed pyenv for, but obviously something's up with which user's doing things as the final task below fails (all variables replaced with strings for clarity):
- name: Install pyenv
git:
repo: https://github.com/yyuu/pyenv.git
dest: "/home/deploy/.pyenv"
- name: Install pyenv-virtualenv plugin
git:
repo: https://github.com/yyuu/pyenv-virtualenv.git
dest: "/home/deploy/.pyenv/plugins/pyenv-virtualenv"
- name: Add path etc to .bashrc.
lineinfile:
dest: "/home/deploy/.bashrc"
state: present
create: yes
line: "{{ item }}"
with_items:
- 'export PYENV_ROOT="$HOME/.pyenv"'
- 'export PATH="$PYENV_ROOT/bin:$PATH"'
- 'eval "$(pyenv init -)"'
- 'eval "$(pyenv virtualenv-init -)"'
- name: Ensure .pyenv permissions are set properly
file: path=/home/deploy/.pyenv
recurse=yes
owner=deploy
group=deploy
state=directory
- name: Install default python version
become: yes
become_user: 'deploy'
shell: . /home/deploy/.bashrc && pyenv install 3.5.1
creates="/home/deploy/.pyenv/versions/3.5.1"
When doing vagrant up it goes fine until:
TASK [python : Install default python version] *********************************
fatal: [192.168.33.15]: FAILED! => {"changed": true, "cmd": ". /home/deploy/.bashrc && pyenv install 3.5.1", "delta": "0:00:00.002111", "end": "2016-02-16 11:48:26.930971", "failed": true, "rc": 127, "start": "2016-02-16 11:48:26.928860", "stderr": "/bin/sh: 1: pyenv: not found", "stdout": "", "stdout_lines": [], "warnings": []}
UPDATE: In case it's important, in this instance (the Vagrant box) my vagrant.yml playbook is setting remote_user to vagrant:
- name: Create a virtual machine via vagrant
hosts: all
become: yes
become_method: sudo
remote_user: vagrant
...
UPDATE 2: If I ssh into the Vagrant VM as the deploy user then I can use pyenv OK. If I ssh in as vagrant and then sudo -u deploy bash -i I get pyenv: command not found...
UPDATE 3: The root of the problem might be that neither /home/deploy/.bashrc or /home/deploy/.profile are sourced when switching to the deploy user with sudo (tested by echoing from each file), but are when logging in as deploy. But, I think /home/deploy/.bashrc is being sourced by the failing task - echo'd text appears in stdout.
As your error is:
pyenv: not found
just try simply to use absoulute path to pyenv in your task. This is a recommended way to handle shell tasks anyway:
Log in to your machine and find out the path to pyenv
which pyenv
then change your task to
# /path/to/pyenv is the result of the previous command
...
shell: . /home/deploy/.bashrc && /path/to/pyenv install 3.5.1
...