Managing remote machines direcly using ansible commands

From Notes_Wiki
Revision as of 16:45, 19 February 2015 by Saurabh (talk | contribs)

<yambe:breadcrumb>Ansible|Ansible</yambe:breadcrumb>

Managing remote machines directly using ansible commands

Running simple shell command on all remote machines

Steps for managing remote machine are:

  1. Add all remote node FQDN or IPs in a text file (one on each line).
    echo <machine IP or FQDN> >> ansible_hosts
  2. Then setup trust based ssh to all hosts mentioned in ansible_hosts file using:
    ssh-copy-id root@<machine IP or FQDN>
  3. Finally to "/bin/echo hello" command on all remote machines use:
    ansible all -i ansible_hosts -a "/bin/echo hello"

Note that without no_log option the commands are recorded in remote systems syslog and can be seen at /var/log/messages. A better way to run commands is to use shell module as follows:

    ansible all -i ansible_hosts -m shell -a "echo hello"

with a very big advantage of not having to type full absolute path for the executable.

When running any command with the Ansible ad-hoc CLI, pay particular attention to shell quoting rules, so the local shell doesn’t eat a variable before it gets passed to Ansible. For example, using double vs single quotes as shown below:

    ansible all -i ansible_hosts -m shell -a "echo $HOSTNAME"

or

    ansible all -i ansible_hosts -m shell -a 'echo $HOSTNAME'

would evaluate the variable on the box where command is run vs evaluation of varilables on remote machine.


Disabling remote ssh host key checking

Running ansible to manage remote hosts when their public keys are not present in '~/.ssh/known_hosts' does not works. To solve this either manually those keys can be added by doing ssh to every node being managed. Or checking of remote host public ssh keys can be disabled by editing ansible configuration. System wide ansible configuration goes in '/etc/ansible/ansible.cfg'. A local user specific override can be done in '~/.ansible.cfg'. To disable ssh key checks use:

    [defaults]
    host_key_checking = False

in one of these two configuration file locations.

The same can also be done for current shell temporarily using:

    export ANSIBLE_HOST_KEY_CHECKING=False

Warning: Please note that disabling checks for remote ssh keys will make system vulnerable to Man-In-The-Middle (MITM) attacks.


Ansible command options

Various ansible command options are:

Host name

First a required argument is host where the ansible command should operate. We can use keyword 'all' or '*' to run the ansible command on all hosts. We can specify group name, where group is properly defined in hosts file to run command on all hosts in the group. Finally we can specify pattern or individual host name to run command only on hosts which satisfy the pattern (192.168.122.*). More than one host or pattern can be specified separated by colon(:).

It is also possible to specify a pattern or a group and then exclude specific hosts or other groups from overall selection using ! operator. Example

 192.168*:!192.168.122.101  

On shell remember to escape ! by using \     Further if no hosts match then ansible shows "No hosts match" message.

It is also possible to get intersection of two groups using & operator as follows:

 webservers:&staging 
Please note that even when we use pattern only hosts which are present in hosts file can be contacted or managed.
Hosts file
We can specicy custom hosts file using '-i'. Default is '/etc/ansible/hosts'. All hosts specified at top of file are treated as uncategorized hosts. After such hosts we can specify a group name such as '[dns]', '[test_dns]' etc and set of hosts under given group. These group names can be used to specify hosts to operate on in ansible command or playbook.
Module
We can specify which module to invoke using '-m'. Default is command
Arguments
Arguments to the module being invoked can be passed using -a
Fork
To configure multiple machines in parallel we can use '-f' option with an integer argument.
Ask-pass
To configure ansible to ask ssh root password for remote machine we can use --ask-pass or -l


Ansible modules basics

To learn any ansible module first read its syntax and purpose from ansible docs at http://docs.ansible.com/list_of_all_modules.html For example read information on copy module and try commands mentioned in this article to understand its purpose.

Copy module

To copy a file from ansible server to specified remote hosts use:

     ansible dns_hosts -i dns_hosts -m copy -a "src=/etc/hosts dest=/etc/hosts"

Note that output would look similar to:

192.168.122.103 | success >> {
    "changed": true, 
    "checksum": "ab27c9b77077dd2a9f15246324ca0f8d31436b2f", 
    "dest": "/etc/hosts", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "8cff70896b6b562833d9b14bd8d7bbb9", 
    "mode": "0644", 
    "owner": "root", 
    "size": 308, 
    "src": "/root/.ansible/tmp/ansible-tmp-1423134324.77-50906221386053/source", 
    "state": "file", 
    "uid": 0
}

192.168.122.102 | success >> {
    "changed": true, 
    "checksum": "ab27c9b77077dd2a9f15246324ca0f8d31436b2f", 
    "dest": "/etc/hosts", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "8cff70896b6b562833d9b14bd8d7bbb9", 
    "mode": "0644", 
    "owner": "root", 
    "size": 308, 
    "src": "/root/.ansible/tmp/ansible-tmp-1423134324.76-153401053249562/source", 
    "state": "file", 
    "uid": 0
}

On running the same copy command again, value of changed in output would change from true to false. Example output on running same copy command is:

192.168.122.103 | success >> {
    "changed": false, 
    "checksum": "ab27c9b77077dd2a9f15246324ca0f8d31436b2f", 
    "dest": "/etc/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/etc/hosts", 
    "size": 308, 
    "state": "file", 
    "uid": 0
}

192.168.122.102 | success >> {
    "changed": false, 
    "checksum": "ab27c9b77077dd2a9f15246324ca0f8d31436b2f", 
    "dest": "/etc/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/etc/hosts", 
    "size": 308, 
    "state": "file", 
    "uid": 0
}

For further information on copy module visit http://docs.ansible.com/copy_module.html


yum module

Use

     ansible dns_hosts -i dns_hosts -m yum -a "name=bind-utils" -f 10

to install bind-utils on all dns_hosts or

     ansible dns_hosts -i dns_hosts -m yum -a "name=bind-chroot state=absent" -f 10

to remove bind-chroot from all dns_hosts

In yum module state option can be specified to be absent, present or latest depending upon whether given package should be removed (if present), should be present (even if current version is older than latest available via yum), or should be latest possible package available via yum. Other options can be learned from http://docs.ansible.com/yum_module.html


file module

To ensure file has specific permission and owernhip

    ansible webservers -m file -a "dest=/home/saurabh/.ssh/authorized_keys mode=400 owner=saurabh group=saurabh"

For creating directories with given permission and ownership:

    ansible webservers -m file -a "dest=/home/saurabh/.ssh/ mode=700 owner=saurabh group=saurabh state=directory"

For deleting files or directories (recursively, if needed):

    ansible webservers -m file -a "dest=/tmp/delete_me state=absent"


user module

To create or ensure user exists use:

    ansible all -m user -a "name=foo password=<crypted password here>"

For example

ansible servers -m user -i hosts_file -a 'name=saurabh password=$6$sN4rhde4Wv$F7cH7b4ZG.lmEYy.U334LQvZ0d7EIntlrOxahoh70w/nBKgspJ9AWrlA9RFnZ1Tv0Gi.7TH.bmw4k71A3ct79/'

Here crypted password can be generated using following method:

[root@barjatiyarklp ~]# mkpasswd -l 10 -s 0
mv0iSwy8zC
[root@barjatiyarklp ~]# python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import crypt
>>> crypt.crypt("<password>", "$6$<salt>")
'$6$<salt>$SrPXyEZ1bOhORDPvsFH.5Z5W9VHWYBXUE3rnYhfdboAc.BBhQT7Nwe3BgTSShA4ykP.keRw8.AmbC2uN/QnvN0'
>>> crypt.crypt("rekall123", "$6$mv0iSwy8zC")
'$6$mv0iSwy8zC$Jrg0uunksVqAtHRhE0ik6LRJNTEIzTNMiCzNMkkmvTdMYLdr.3Wau/5DBV9RYp2bzL9M53bxF/u7d432CN8rj0'
>>> 
[root@barjatiyarklp ~]#

This can also be done using one single command as:

python -c "import crypt; print crypt.crypt('iiit123','\$6\$$(mkpasswd -l 10 -s 0)')"


Similarly users can be deleted or it can be ensured that given user does not exists using:

ansible all -m user -a "name=foo state=absent"


service module

To ensure that a given service is running and also enabled on startup use:

ansible webservers -m service -a "name=httpd state=started enabled=yes"



Time limited background operations

To run a command in background use:

ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"

To check on the job status later, use async_status module by passing it the job id that is returned when original job is run in the background, as follows:

   ansible web1.example.com -m async_status -a "jid=488359678239.2844"


Gathering facts or setup module

To simply get facts for specific machines use:

ansible all -m setup



<yambe:breadcrumb>Ansible|Ansible</yambe:breadcrumb>