Location>code7788 >text

Not for the faint of heart - a detailed explanation of the usage of roles in ansible-playbook (II)

Popularity:930 ℃/2024-12-13 22:42:10

preamble

In this article, we'll continue to cover the various uses of roles in ansible-playbook.

environmental preparation

assemblies releases
operating system Ubuntu 22.04.4 LTS
ansible 2.17.6

basic usage

file structure

.
├── 
├── 
└── roles
    └── base
        └── tasks
            └── 

Defining global public variables

Add a new group_vars directory and add new files

.
├── 
├── 
├── group_vars
│   └── 
└── roles
    └── base
        └── tasks
            └── 

▶ cat group_vars/
info: IT paiqiu
▶ cat roles/base/tasks/
- name: first
  debug:
    msg: "hello world {{ info }}"

Running:

▶ ansible-playbook -i  

...
TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world IT paiqiu"
}
...

Defining role-level variables

Can override global variables

In the rolebase The following is a new vars directory and a new file

.
├── 
├── 
├── group_vars
│   └── 
└── roles
    └── base
        ├── tasks
        │   └── 
        └── vars
            └── 
▶ cat roles/base/tasks/
- name: first
  debug:
    msg: "hello world {{ info }}"
▶ cat roles/base/vars/
info:
  name: wilson
  addr: cd

Running:

▶ ansible-playbook -i  

...
TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world {'name': 'wilson', 'addr': 'cd'}"
}
...

Define the static file directory

This is equivalent to defining the root directory at the role level to better manage files that need to be transferred in the rolebaseCreate a directory belowfilesand in thefilesBelow is the file to be transferred

.
├── 
├── 
├── group_vars
│   └── 
└── roles
    └── base
        ├── files
        │   └── 
        ├── tasks
        │   └── 
        └── vars
            └── 

transportTo target machine

- name: first
  copy: src= dest=/tmp/

The default is to go back to roles/base/files, so you don't need to add a path in front of it.

The copy module automatically checks the md5 of the file to be transferred, and if it hasn't changed, then it won't be transferred anymore

Defining a template

Each time a file is transferred it is re-rendered through the input variables before transferring it, in the rolebaseCreate a directory belowtemplatesand create a file

.
├── 
├── 
├── group_vars
│   └── 
└── roles
    └── base
        ├── files
        │   └── 
        ├── tasks
        │   └── 
        ├── templates
        │   └── 
        └── vars
            └── 

There are two variables defined in the template file, a manually set variable called version and the ansible built-in variable called inventory_hostname.

▶ cat roles/base/templates/
{{ version }}
{{ inventory_hostname }}
▶ cat roles/base/tasks/
- name: first
  template: src= dest=/tmp/ mode=0644

Running:

▶ ansible-playbook -i  -e version=2 

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
changed: [10.22.11.166]

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Log in to the target machine to view it:

▶ cat 
2
10.22.11.166

2is the variable passed in for this task.10.22.11.166is the ip address of the target machine

Defining event-driven

Usually used for actions that need to be triggered after certain tasks have been completed, e.g., restarting a service after publishing a configuration file. In the rolebaseCreate a directory underhandlersand create a file

.
├── 
├── 
├── group_vars
│   └── 
└── roles
    └── base
        ├── files
        │   └── 
        ├── handlers
        │   └── 
        ├── tasks
        │   └── 
        ├── templates
        │   └── 
        └── vars
            └── 

Creating Eventsfirst handler

▶ cat roles/base/handlers/
- name: first handler
  debug:
    msg: echo 'hello world'
▶ cat roles/base/tasks/
- name: first
  template: src= dest=/tmp/ mode=0644
  notify: first handler

Running:

▶ ansible-playbook -i  -e version=2 

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
changed: [10.22.11.166]

RUNNING HANDLER [base : first handler] ***************************************************************************
ok: [10.22.11.166] => {
    "msg": "echo 'hello world'"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Similarly, if the event precursor doesn't happen, then the event notification won't happen, for example, if the event precursor is the transfer of a file, and if the file doesn't change, it won't be transferred again, then the event won't happen again either

Add more tasks

Currently onlyIn addition, a task dedicated to the transfer of files is being added.

▶ cat roles/base/tasks/
- name: main
  include_tasks: 
  vars:
    app_version: 0.2
▶ cat roles/base/tasks/
- name: first
  debug:
    msg: "version: {{ app_version }}"

Running:

▶ ansible-playbook -i  

PLAY [deploy] ****************************************************************************************************

TASK [base : main] ***********************************************************************************************
included: /home/wilson/workspace/ansible/roles/base/tasks/ for 10.22.11.166

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "version: 0.2"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

If there are too many files, they can be handled by looping:

- name: main
  include_tasks: "{{ yaml_items }}"
  loop:
    - 
    - 
  loop_control:
    loop_var: yaml_items
  vars:
    app_version: 0.2

To add a few common commands

execute a commandshell

- name: display
  shell: echo 'hello world'

Transmission of documentscopy

The copy module automatically checks the md5 of the file to be transferred, and if it hasn't changed, then it won't be transferred anymore

- name: copy file
  copy: src= dest=/tmp/

Modify the contents of the document (one line)lineinfile

  • path: Specify the path of the file to be operated (required)
  • line: defines the complete line to be inserted or replaced (optional)
  • regexp: Regular expression to match existing lines. Used in conjunction with line, matching lines will be replaced with
  • state:
    • present (default): Ensures that the specified line exists.
    • absent: remove matching rows
  • create: Whether to create the file if it does not exist (default yes)
  • insertafter: specifies the location of the insertion line (default EOF)
    • EOF: End of File
    • BOF: Beginning of File
    • Regular expression: inserts after matching line
      insertbefore: similar to insertafter, but inserted before the matching line

Modify the current line after matching the line with a regular

- name: modify
  lineinfile: dest=/tmp/ regexp='^DC' line="DC=hello" state=present

Modify file contents (multiple lines/blocks)blockinfile

  • path: Specify the path of the file to be manipulated (required)
  • block: defines the content of the text to be inserted (required)
  • marker: Specify the start and end strings of the marker block, default is # {mark} ANSIBLE MANAGED BLOCK
  • state:
    • present (default): ensures that the block exists
    • absent: remove block
  • create: Whether to create the file if it does not exist (default yes)
  • insertafter: specifies the location of the insertion block (default EOF)
    • Available values:
      • EOF: End of File
      • BOF: Beginning of File
      • Regular expression: insert after matching line
  • insertbefore: Similar to insertafter, but inserts before the matching line.

1) Add new content below a line and mark the added content

- name: add new content with markers
  blockinfile:
    path: /tmp/
    marker: "# {mark} by wilson"
    insertafter: '^DC'
    block: |
      name: wilson
      city: cd

View the results after running

▶ cat /tmp/
DC=hello
# BEGIN by wilson
name: wilson
city: cd
# END by wilson

2) Delete marked content

- name: Remove the managed block
  blockinfile:
    marker: "# {mark} by wilson"
    path: /tmp/
    state: absent

Adding blocks of content and marking them up makes it easy to modify and delete them.

Using templates

- name: hostname config
  template: src=etc/hostname dest=/etc/hostname

Setting File Permissionsfile

- name: change file 755
  file:
    path: /tmp/
    owner: wilson
    group: wilson
    state: file
    mode: 755

Using loopswith_items

with_items

Modify permissions for multiple directories

- name: change directory 755
  file:
    path: '{{  }}'
    owner: wilson
    group: wilson
    state: directory
    mode: '{{  }}'
  with_items:
    - { dir: '/tmp/1', mode: '0755'}
    - { dir: '/tmp/2', mode: '0755'}

loop

surelywith_items replace withloopIt's possible.

- name: change directory 755
  file:
    path: '{{  }}'
    owner: wilson
    group: wilson
    state: directory
    mode: '{{  }}'
  with_items:
    - { dir: '/tmp/1', mode: '0755'}
    - { dir: '/tmp/2', mode: '0755'}

nested loopwith_nested

Output each combination, equivalent to the Cartesian product

- name: nested loop
  debug:
    msg: "{{ item[0] }} {{ item[1] }}"
  with_nested:
    - [ "hello1", "hello2"]
    - [ "world1", "world2"]

Output results:

TASK [base : nested loop] ****************************************************************************************
ok: [127.0.0.1] => (item=['hello1', 'world1']) => {
    "msg": "hello1 world1"
}
ok: [127.0.0.1] => (item=['hello1', 'world2']) => {
    "msg": "hello1 world2"
}
ok: [127.0.0.1] => (item=['hello2', 'world1']) => {
    "msg": "hello2 world1"
}
ok: [127.0.0.1] => (item=['hello2', 'world2']) => {
    "msg": "hello2 world2"
}

File Content Loopwith_file

Printing the contents of a file line by line

- name: display file content
  debug:
    msg: "{{ item }}"
  with_file:
    - /tmp/

idempotence (math.)

When using roles to manage multiple devices, scripts should always be written with idempotency in mind, i.e., each execution should be guaranteed to produce the same result.

Contact me

Contact me for an in-depth chat


This concludes this article
I'm not very knowledgeable, so if there is any soup leakage, please do not hesitate to give me advice...