官术网_书友最值得收藏!

  • Practical Ansible 2
  • Daniel Oh James Freeman Fabio Alessandro Locati
  • 1281字
  • 2021-06-24 16:06:49

Understanding ad hoc commands

We have already seen a handful of ad hoc commands so far in this book, but to recap, they are single commands you can run with Ansible, making use of Ansible modules without the need to create or save playbooks. They are very useful for performing quick, one-off tasks on a number of remote machines or for testing and understanding the behavior of the Ansible modules that you intend to use in your playbooks. They are both a great learning tool and a quick and dirty (because you never document your work with a playbook!) automation solution.

As with every Ansible example, we need an inventory to run against. Let's reuse our production-inventory file from before:

[frontends_na_zone]
frontend1-na.example.com
frontend2-na.example.com

[frontends_emea_zone]
frontend1-emea.example.com
frontend2-emea.example.com

[appservers_na_zone]
appserver1-na.example.com
appserver2-na.example.com


[appservers_emea_zone]
appserver1-emea.example.com
appserver2-emea.example.com

Now, let's start with perhaps the quickest and dirtiest of ad hoc commands—running a raw shell command on a group of remote machines. Suppose that you want to check that the date and time of all the frontend servers in EMEA are in sync—you could do this by using a monitoring tool or by manually logging into each server in turn and checking the date and time. However, you can also use an Ansible ad hoc command:

  1. Run the following ad hoc command to retrieve the current date and time from all of the frontends_emea_zone servers:
$ ansible -i production-inventory frontends_emea_zone -a /usr/bin/date

You will see that Ansible faithfully logs in to each machine in turn and runs the date command, returning the current date and time. Your output will look something as follows:

$ ansible -i production-inventory frontends_emea_zone -a /usr/bin/date
frontend1-emea.example.com | CHANGED | rc=0 >>
Sun 5 Apr 18:55:30 BST 2020
frontend2-emea.example.com | CHANGED | rc=0 >>
Sun 5 Apr 18:55:30 BST 2020
  1. This command is run with the user account you are logged in to when the command is run. You can use a command-line argument (discussed in the previous section) to run as a different user:
$ ansible -i production-inventory frontends_emea_zone -a /usr/sbin/pvs -u danieloh

frontend2-emea.example.com | FAILED | rc=5 >>
WARNING: Running as a non-root user. Functionality may be unavailable.
/run/lvm/lvmetad.socket: access failed: Permission denied
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
/run/lock/lvm/P_global:aux: open failed: Permission denied
Unable to obtain global lock.non-zero return code
frontend1-emea.example.com | FAILED | rc=5 >>
WARNING: Running as a non-root user. Functionality may be unavailable.
/run/lvm/lvmetad.socket: access failed: Permission denied
WARNING: Failed to connect to lvmetad. Falling back to device scanning.
/run/lock/lvm/P_global:aux: open failed: Permission denied
Unable to obtain global lock.non-zero return code
  1. Here, we can see that the danieloh user account does not have the privileges required to successfully run the pvs command. However, we can fix this by adding the --become command-line argument, which tells Ansible to become root on the remote systems:
$ ansible -i production-inventory frontends_emea_zone -a /usr/sbin/pvs -u danieloh --become

frontend2-emea.example.com | FAILED | rc=-1 >>
Missing sudo password
frontend1-emea.example.com | FAILED | rc=-1 >>
Missing sudo password
  1. We can see that the command still fails because although danieloh is in /etc/sudoers, it is not allowed to run commands as root without entering a sudo password. Luckily, there's a switch to get Ansible to prompt us for this at run time, meaning we don't need to edit our /etc/sudoers file:
$ ansible -i production-inventory frontends_emea_zone -a /usr/sbin/pvs -u danieloh --become --ask-become-pass
BECOME password:

frontend1-emea.example.com | CHANGED | rc=0 >>
PV VG Fmt Attr PSize PFree
/dev/sda2 centos lvm2 a-- <19.00g 0
frontend2-emea.example.com | CHANGED | rc=0 >>
PV VG Fmt Attr PSize PFree
/dev/sda2 centos lvm2 a-- <19.00g 0
  1. By default, if you don't specify a module using the -m command-line argument, Ansible assumes you want to use the command module (see https://docs.ansible.com/ansible/latest/modules/command_module.html). If you wish to use a specific module, you can add the -m switch to the command-line arguments and then specify the module arguments under the -a switch, as in the following example:
$ ansible -i production-inventory frontends_emea_zone -m copy -a "src=/etc/yum.conf dest=/tmp/yum.conf"
frontend1-emea.example.com | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "e0637e631f4ab0aaebef1a6b8822a36f031f332e",
"dest": "/tmp/yum.conf",
"gid": 0,
"group": "root",
"md5sum": "a7dc0d7b8902e9c8c096c93eb431d19e",
"mode": "0644",
"owner": "root",
"size": 970,
"src": "/root/.ansible/tmp/ansible-tmp-1586110004.75-208447517347027/source",
"state": "file",
"uid": 0
}
frontend2-emea.example.com | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "e0637e631f4ab0aaebef1a6b8822a36f031f332e",
"dest": "/tmp/yum.conf",
"gid": 0,
"group": "root",
"md5sum": "a7dc0d7b8902e9c8c096c93eb431d19e",
"mode": "0644",
"owner": "root",
"size": 970,
"src": "/root/.ansible/tmp/ansible-tmp-1586110004.75-208447517347027/source",
"state": "file",
"uid": 0
}

The preceding output not only shows that the copy was performed successfully to both hosts but also all the output values from the copy module. This, again, can be very helpful later when you are developing playbooks as it enables you to understand exactly how the module works and what output it produces in cases where you need to perform further work with that output. This is a more advanced topic, however, that is beyond the scope of this introductory chapter.

You will also note that all arguments passed to the module must be enclosed in quotation marks ("). All arguments are specified as key=value pairs and no spaces should be added between key and value (for example, key = value is not acceptable). If you need to place quotation marks around one of your argument values, you can escape them using the backslash character (for example, -a "src=/etc/yum.conf dest=\"/tmp/yum file.conf\"")

All examples we have performed so far are very quick to execute and run, but this is not always the case with computing tasks. When you have to run an operation for a long time, say more than two hours, you should consider running it as a background process. In this instance, you can run the command asynchronously and confirm the result of that execution later. 

For example, to execute sleep 2h asynchronously in the background with a timeout of 7,200 seconds (-B) and without polling (-P), use this command:

$ ansible -i production-inventory frontends_emea_zone -B 7200 -P 0 -a "sleep 2h"
frontend1-emea.example.com | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"ansible_job_id": "537978889103.8857",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/537978889103.8857",
"started": 1
}
frontend2-emea.example.com | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"ansible_job_id": "651461662130.8858",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/651461662130.8858",
"started": 1
}

Note that the output from this command gives a unique job ID for each task on each host. Let's now say that we want to see how this task proceeds on the second frontend server. Simply issue the following command from your Ansible control machine:

$ ansible -i production-inventory frontend2-emea.example.com -m async_status -a "jid=651461662130.8858"
frontend2-emea.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"ansible_job_id": "651461662130.8858",
"changed": false,
"finished": 0,
"started": 1
}

Here, we can see that the job has started but not finished. If we now kill the sleep command that we issued and check on the status again, we can see the following:

$ ansible -i production-inventory frontend2-emea.example.com -m async_status -a "jid=651461662130.8858"
frontend2-emea.example.com | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"ansible_job_id": "651461662130.8858",
"changed": true,
"cmd": [
"sleep",
"2h"
],
"delta": "0:03:16.534212",
"end": "2020-04-05 19:18:08.431258",
"finished": 1,
"msg": "non-zero return code",
"rc": -15,
"start": "2020-04-05 19:14:51.897046",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}

Here, we see a FAILED status result because the sleep command was killed; it did not exit cleanly and returned a -15 code (see the rc parameter). When it was killed, no output was sent to either stdout or stderr, but if it had been, Ansible would have captured it and displayed it in the preceding code, which would aid you in debugging the failure. Lots of other useful information is included, including how long the task actually ran for, the end time, and so on. Similarly, the useful output is returned when the task exits cleanly.

That concludes our look at ad hoc commands in Ansible. By now, you should have a fairly solid grasp of the fundamentals of Ansible, but there's one important thing we haven't looked at yet, even though we briefly touched on it—variables and how to define them. We'll proceed to look at this in the next section.

主站蜘蛛池模板: 同仁县| 晋州市| 剑阁县| 星座| 新郑市| 雅江县| 定日县| 且末县| 安多县| 彭水| 平乡县| 黄骅市| 东丽区| 拜城县| 潼关县| 防城港市| 大足县| 贵州省| 大埔区| 旺苍县| 绩溪县| 屏东市| 安国市| 鱼台县| 兴仁县| 库伦旗| 平果县| 鄂托克前旗| 枣阳市| 东辽县| 荣成市| 西宁市| 乳山市| 浦北县| 南靖县| 剑川县| 临汾市| 孝感市| 墨竹工卡县| 石门县| 吴桥县|