Ansible automatic operation and maintenance learning III: yaml syntax and playbook writing

Keywords: Linux Nginx ansible MySQL Python

Note: part of the code of the article case will be misaligned. Please pay attention to the format alignment when using!!

Chapter 3 yaml syntax and playbook writing

Ansible's playbook adopts yaml syntax, so before learning ansible playbook, it is necessary to understand and master the grammar format of yaml. Only by practicing and mastering the writing method of playbook can ansible be used smoothly.

3.1 yaml syntax

Here is an example of playbook to illustrate the syntax of yaml:

---
- name: Install Mysql package
  yum: name={{ item }} state=present
  with_items:
   - mysql-server
   - MySQL-python
   - libselinux-python
   - libsemanage-python
#Install mysql service
- name: Configure SELinux to start mysql on any port
  seboolean: name=mysql_connect_any state=true persistent=yes
  when: ansible_selinux.status == "enabled"

- name: Create Mysql configuration file
  template: src=my.cnf.j2 dest=/etc/my.cnf
  notify:
  - restart mysql   #Configure my.cnf and restart mysql service

- name: Start Mysql Service
  service: name=mysqld state=started enabled=yes

1. Yaml files start with - -- to indicate that this is a yaml file;
2. In yaml, the character "ා" is used as the comment character. It can comment the whole line or the content after the character "ා" in the line;
3. Strings in yaml usually don't need to be quoted, even if they contain some special characters. However, in some cases, quotation marks must be added to avoid errors in yaml reading. The most common is to use quotation marks when referencing variables;
4. Finally, it is about the writing format of Boolean value, that is, the expression of true/false. The boolean type in playbook is very flexible, which can be divided into the following two situations:
A: Module parameters: the Boolean value is parsed as a string by ansible.
It accepts the following options: yes/on/1/true/no/off/0/false, which is parsed by ansible.
B: Non module parameters: the Boolean value is parsed by the yaml interpreter. Accepts case insensitive true/yes/on/y/false/no/off/n. For example, enabled=yes above.

For the use of Boolean values in playbook, it is recommended to follow the official specification of ansible:
The Boolean parameter of the module is yes/no, and the Boolean parameter of the non module is True/False
playbook basic components
Hosts: the target host to run the task
Remote user: the user who performs tasks on a remote host
tasks: task list
handlers: tasks, unlike tasks, are triggered only when the notification is received
templates: text files using the template language, using jinja2 syntax.
Variables: variables, variable replacement {{variable_name}}}

3.2 list

The use of lists in playbook is very important. It uses "-" (minus sign plus one or more spaces) as list items, that is, arrays in json. For example, the above example:

  • mariadb-server
  • mariadb
  • MySQL-python
  • libselinux-python
  • libsemanage-python
    The above list is equivalent to the following json list:
    [
    "mariadb-server",
    "mariadb",
    "MySQL-python",
    "libselinux-python",
    "libsemanage-python"
    ]
    It is also equivalent to the following inline forms:
    [mariadb-server,mariadb,MySQL-python,libselinux-python,libsemanage-python]
    Specifically, in ansible playbook, a list describes a local environment. It does not have to have a name or start from the same attribute. As long as you use "-", it means that you define a range, and the items in the range belong to the list.

    3.3 dictionary

    In playbook, virtual content can be written in the form of dictionary, while physical, action and object content should be defined as list
    The writing mode of dictionary is as follows: nginx? Port: 80
    If it can't be written in key/value format and is an entity file, it should be written as a list, such as: - nginx_port.yml

    3.4 branch writing

    There are three ways to continue lines in playbook:
    (1) Use the greater than sign after key:.
    (2) Use a vertical bar after "key:". This way you can write many lines like a script.
    (3) Multi indent.
    For example:

---     #Identification
    - hosts: localhost
      tasks: 
        - shell: echo 2 >>/tmp/test.txt
            creates=/tmp/haha.txt          # More indents than module shell
        - shell: >                         # Use the greater than sign after "key:"
            echo 2 >>/tmp/test.txt
            creates=/tmp/haha.txt
        - shell: |                         # Specify multiline commands
            echo 2 >>/tmp/test.txt
            echo 3 >>/tmp/test.txt
          args:
            creates: /tmp/haha.txt

3.5 transfer parameters to modules

Generally speaking, the parameters of the module are in the format of key=value. There are three ways to pass them:
(1) After writing directly to the module, the format "key=value" is required at this time.
(2) It is written as a dictionary, i.e. "key: value". Writing requires multiple indents.
(3) Use the built-in property args, and then indent multiple levels to define the parameter list.
For example:

---   #Identification
    - hosts: localhost
      tasks: 
        - yum: name=unix2dos state=installed    # key=value passed directly
        - yum: 
            name: unxi2dos
            state: installed            # "key: value" dictionary format transfer
        - yum: 
          args:                               # Pass using args
            name: unix2dos
            state:installed

3.6 relationship between playbook and play

A playbook can contain multiple plays. Each play contains at least two items: tasks and hosts.
It should be noted that in some cases, role is used in play, and the content of playbook does not seem to have tasks. In fact, the role itself has integrated playbook. At this time, no task is not a syntax error. But if you don't use role, the playbook must contain hosts and tasks.

3.7 when to use quotation marks in Playbook

Most of the definitions in playbook are list and dictionary contents. In most cases, you don't need to use quotation marks, but there are two special cases where you need to consider using quotation marks.
(1) When the brace "{}" appears;
(2) ':' when colons and spaces appear.
The reason why curly braces are surrounded by quotation marks is that when they are not used, they will be parsed into an inline dictionary by yaml, resulting in incorrect parsing or not executed according to the actual logic.

    ---   #Identification
        - hosts: localhost
          tasks:
            - shell: 'echo "{{inventory_hostname}}: haha"'
              register: hello
            - debug: 'msg="{{hello.stdout}}: heihei"'

3.8 use of template in Playbook

3.8.1 template

The variables in the module often use the built-in variables of the server itself. We can use the setup module to find the variable names we need:

#To find the remote server host name:
[root@centos130 lnmp]# ansible 192.168.8.131 -m setup  -a 'filter="ansible_fqdn"'
192.168.8.131 | SUCCESS => {
    "ansible_facts": {
        "ansible_fqdn": "centos131"
    }, 
    "changed": false
}

#Find the number of cpu cores for the remote server:
[root@centos130 lnmp]# ansible 192.168.8.131 -m setup  |grep "cpu"
        "ansible_processor_vcpus": 1,

#To view the operating system type of a remote server:
[root@centos130 lnmp]# ansible 192.168.8.131 -m setup  |grep "ansible_os_family"
        "ansible_os_family": "RedHat",

Introduction to module templates:
1. Modules are files, files and can be nested with scripts;
2. The module uses Jinja2 language and has the following forms:
(1) String: use single or double quotes
(2) Number: integer, floating point
(3) List: [item1,item2,...]
(4) No group: (item1,item2,...)
(5) Dictionary: {key1:value1,key2:value2,...}
(6) Boolean: true/false
3. Arithmetic operation: +, -, *, /, / / (rounding),% (rounding), * * (power)
4. Comparison operation: = =,! =, < and < =, > and >=
5. Logical operation: and, or, not
6. Expression: for, if, when

Note: the template module can only be used in ANSI ble playbook.

For example, the default worker process of nginx is auto, which is modified to the second power of the cpu core number of the server. At the same time, the port of nginx is obtained from the hosts list:

#Modify nginx.conf module file
[root@centos130 ansible]# cat template/nginx.conf.j2
....
user nginx;
worker_processes {{ ansible_processor_vcpus**2 }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
....
    server {
        listen       {{ nginx_port }} default_server;
        listen       [::]:{{ nginx_port }} default_server;
.....

#Modify the hosts list configuration
[root@centos130 ansible]# cat hosts
[web]
192.168.8.131 nginx_port

#Write ansible Playbook
[root@centos130 ansible]# cat testtemp.yml
--- #Identification

- hosts: web
  remote_user: root

  tasks:
  - name: install package
     yum: name=nginx

    - name:copy template
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
        notify: restart service

    - name: start service
      service: name=nginx state=started enabled=yes

  handlers:
  - name: restart service
    service: name=nginx state=restarted

#Test execution:
[root@centos130 ansible]# ansible-playbook -i hosts -C testtemp.yml
#You can also add variables directly from the - e parameter command line:
[root@centos130 ansible]# ansible-playbook -i hosts -e "http_port=99" testtemp.yml

3.8.2 use of when

1. Conditional test: if you need to use conditional test as the precondition of whether a task is executed or not according to variables, facts or the execution results of previous tasks, use the syntax format of jinja2 through when statement and task
2. When statement, add when clause after task to use conditional test

#For example:
tasks:
- name: shutdown RedHat flavored system
  command: /sbin/shutdown -h now
    when: ansible_os_family == "RedHat"

For example, the configuration file of nginx is introduced. According to different operating system versions, different nginx.conf module files are used:

#Modify nginx.conf module file
[root@centos130 ansible]# ls template/
nginx.conf6.j2 nginx.conf7.j2

#Write ansible Playbook
[root@centos130 ansible]# cat testwhen.yml
--- #Identification

- hosts: all
  remote_user: root

  tasks:
  - name: install package
     yum: name=nginx

    - name:copy template for centos7
      template: src=nginx.conf7.j2 dest=/etc/nginx/nginx.conf
        when: ansible_distribution_major_version == "7"
        notify: restart service

    - name:copy template for centos6
      template: src=nginx.conf6.j2 dest=/etc/nginx/nginx.conf
        when: ansible_distribution_major_version == "6"
        notify: restart service

    - name: start service
      service: name=nginx state=started enabled=yes

  handlers:
  - name: restart service
    service: name=nginx state=restarted

#Test execution:
[root@centos130 ansible]# ansible-playbook -i hosts -C testwhen.yml

Posted by JDcrack on Fri, 28 Feb 2020 02:22:44 -0800