Local execution
If you want to run a specific task locally on the control host, you can use the local action statement.
Suppose that the remote host we need to configure has just started. If we run the playbook directly, it may fail because the sshd service has not started listening. We can use the following example on the control host to wait for the controlled end to listen to the sshd port:
- name: wait for ssh server to be running wait_for port: 22 host: "{{ inventory_hostname }}" search_regex: OpenSSH connection: local
Task delegation
Sometimes, we want to run the task associated with the selected host or host group, but this task does not need to be executed on the selected host or host group, but on another server.
This feature applies to the following scenarios:
- Enable host based alarm in alarm system
- Add or remove a host to the load balancer
- Add or modify resolution for a host on dns
- Create a storage on the storage node for host mount
- Use an external program to check whether the service on the host is normal
You can use the delegate to statement to run task s on another host:
- name: enable alerts for web servers hosts: webservers tasks: - name: enable alerts nagios: action=enable_alerts service=web host="{{ inventory_hostname }}" delegate_to: nagios.example.com
If delegate to: 127.0.0.1, it is equivalent to local action
Task pause
In some cases, some tasks need to wait for the recovery of some states. For example, a host or application has just been restarted. We need to wait for a port on it to open. At this time, we need to pause the running tasks until their states meet the requirements.
Ansible provides the wait for module to implement the requirement of task pause
Common parameters of wait for module:
- Connect Ou timeout: the timeout to wait for a connection before the next task is executed
- delay: when waiting for a port or file or connecting to a specified state, the default timeout is 300 seconds. During the 300 seconds of waiting, the wait for module will always poll whether the specified object reaches the specified state. delay is how often to poll the state.
- Host: wait for the address of the host the module is waiting for. The default is 127.0.0.1
- Port: wait for the port of the host the module is waiting for
- Path: file path. Only when the file exists, the next task starts to execute, that is, wait for the file to be created
- State: the waiting state, that is, when the waiting file or port or connection state reaches the specified state, the next task begins to execute. When the waiting object is a port, the status is started, stopped, that is, the port has been monitored or the port has been closed; when the waiting object is a file, the status is present, started, or absent, that is, the file has been created or deleted; when the waiting object is a connection, the status is drawn, that is, the connection has been established. The default is started
- Timeout: the timeout of wait for, which is 300 seconds by default
Example:
#Wait for port 8080 to listen normally before starting the next task until timeout - wait_for: port: 8080 state: started #Wait for 8000 port to monitor normally, and check every 10s until waiting timeout - wait_for: port: 8000 delay: 10 #Wait for port 8000 until a connection is established - wait_for: host: 0.0.0.0 port: 8000 delay: 10 state: drained #Wait for 8000 port to have connection established, if the connection comes from 10.2.1.2 or 10.2.1.3, ignore. - wait_for: host: 0.0.0.0 port: 8000 state: drained exclude_hosts: 10.2.1.2,10.2.1.3 #Wait for / tmp/foo file to be created - wait_for: path: /tmp/foo #Wait for the / tmp/foo file to be created, and it needs to contain the completed string - wait_for: path: /tmp/foo search_regex: completed #Wait for / var/lock/file.lock to be deleted - wait_for: path: /var/lock/file.lock state: absent #Wait for the specified process to be destroyed - wait_for: path: /proc/3466/status state: absent #Wait for openssh to start, check once in 10s - wait_for: port: 22 host: "{{ ansible_ssh_host | default(inventory_hostname) }}" search_regex: OpenSSH delay: 10
Scroll execution
By default, ansible performs each task on all selected hosts or host groups in parallel, but sometimes we want to be able to run one by one. The most typical example is when updating the application server behind the load balancer. Generally speaking, we will remove the application server from the load balancer one by one, update it, and then add it back. We can use the serial statement in play to tell ansible to limit the number of hosts executing play in parallel.
Here is an example of how to remove the host, update the software package and add it back to the load balancer of amazon EC2:
- name: upgrade pkgs on servers behind load balancer hosts: myhosts serial: 1 tasks: - name: get the ec2 instance id and elastic load balancer id ec2_facts: - name: take the host out of the elastic load balancer id local_action: ec2_elb args: instance_id: "{{ ansible_ec2_instance_id }}" state: absent - name: upgrade pkgs apt: update_cache: yes upgrade: yes - name: put the host back n the elastic load balancer local_action: ec2_elb args: instance_id: "{{ ansible_ec2_instance_id }}" state: present ec2_elbs: "{{ items }}" with_items: ec2_elbs
In the above example, the value of serial is 1, which means that play is only executed on one host in a certain period of time. If it is 2, there are 2 hosts running play at the same time.
Generally speaking, when a task fails, ansible will stop executing the task on the failed host, but continue to execute it on other hosts. In the scenario of load balancing, we would prefer ansible to stop play before all hosts fail to execute. Otherwise, we are likely to face the scenario where all hosts are removed from the load balancer and the execution fails, resulting in service unavailability. At this time, we can use the serial statement with the max fail percentage statement. Max fail percentage indicates that when the proportion of the largest failed hosts reaches, ansible will fail the whole play. An example is as follows:
- name: upgrade pkgs on fservers behind load balancer hosts: myhosts serial: 1 max_fail_percentage: 25 tasks: ......
If there are four hosts behind load balancing and one fails to execute, ansible will continue to run. To stop Play, it must be more than 25%. So if you want to stop execution if you want to fail, we can set the value of Max fail percentage to 24. If we want to give up execution whenever it fails, we can set the value of Max fail percentage to 0.
Only once
Sometimes, we want a task to be executed only once, even if it is bound to multiple hosts. For example, there are multiple application servers behind a load balancer. If we want to perform a database migration, we only need to perform operations on one application server.
You can use the run Hou once statement to handle:
- name: run the database migrateions command: /opt/run_migrateions run_once: true
It can also be used with local action as follows:
- name: run the task locally, only once command: /opt/my-custom-command connection: local run_once: true
It can also be used in conjunction with delegate to to make this one-time task run on the specified machine:
- name: run the task locally, only once command: /opt/my-custom-command run_once: true delegate_to: app.a1-61-105.dev.unp
Setting environment variables
When we execute some commands at the command line, they may need to rely on environment variables. For example, when installing some packages, you may need to use an agent to complete the installation. Or a script may need to call an environment variable to run.
ansible supports defining some environment variables through the environment keyword.
Environment variables may be required in the following scenarios:
- When you run the shell, you need to set the path variable
- Some libraries need to be loaded, which are not in the standard library path of the system
Here is a simple example:
--- - name: upload a remote file to aws s3 hosts: test tasks: - name: install pip yum: name: python-pip state: installed - name: install the aws tools pip: name: awscli state: present - name upload file to s3 shell aws s3 put-object --bucket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu-west-1 environment: AWS_ACCESS_KEY_ID: xxxxxx AWS_SECRET_ACCESS_KEY: xxxxxx
In fact, environment can also be stored in variables:
- hosts: all remote_user: root vars: proxy_env: http_proxy: http://proxy.example.com:8080 https_proxy: http://proxy.bos.example.com:8080 tasks: - apt: name=cobbler state=installed environment: proxy_env
interactive prompt
In a few cases, the ansible task needs users to input some data in the process of running. These data are either relatively secret and inconvenient, or the data is dynamic. Different users have different requirements, such as entering users' own accounts and passwords or entering different version numbers will trigger different subsequent operations. Ansible's vars'u prompt keyword is used to deal with the above-mentioned interaction with users.
- hosts: all remote_user: root vars_prompt: - name: share_user prompt: "what is your network username?" private: yes - name: share_pass prompt: "what is your network password" private: yes tasks: - debug: var: share_user - debug: var: share_pass
Vars? Prompt common options Description:
- private: yes by default, indicating that the value entered by the user is not visible on the command line
- Default: defines the default value, which is used when the user has not entered it
- confirm: if it is set to yes, the user will be required to enter it twice, which is suitable for entering the password