Este post cobre os seguintes módulos de loop Ansible: with_items, with_nested, with_subelements, with_dict.
Todos esses com * já estão obsoletos e é recomendado o uso de loop.
Fonte
Uma das minhas funções na Chromatic é como membro da equipe DevOps. Entre outras coisas, isso inclui trabalhar com nossos servidores e os servidores de nossos clientes. Isso, por sua vez, significa que passo muito tempo trabalhando com o Ansible , uma ferramenta popular para provisionar, configurar e implantar servidores e aplicativos.
Para simplificar, a máquina que executa o Ansible executa comandos em outra máquina via SSH. Esses comandos são especificados declarativamente (opcional) usando pequenas seções de YAML chamadas de tarefas. Essas TAREFAS chamam módulos Ansible que se especializam em executar opções em certos componentes, como arquivos, bancos de dados, etc.
Por exemplo, a seguinte tarefa usa o módulo Arquivo ( documentação , código ) para criar um diretório específico se ele ainda não existir e modifica seus atributos se eles ainda não estiverem definidos corretamente:
- file:
path: /home/jenkins/.ssh
state: directory
owner: jenkins
group: jenkins
mode: 700
Várias tarefas relacionadas a uma tarefa são agrupadas em funções, e várias funções podem ser agrupadas em manuais. Você pode então usar o manual para executar exatamente as mesmas etapas de configuração em qualquer número de servidores ao mesmo tempo.
O Ansible é declarativo?
TASKS Ansible , , TASKS. , , , . , Ansible Copy, . Ansible , :
- name: Copy SSH config file into Alice’s .ssh directory.
copy:
src: files/config
dest: /home/alice/.ssh/config
owner: alice
group: alice
mode: 0600
, , bash, scp, chown chmod. Ansible , .
, , — , , .
, Ansible, — TASKS . , Ansible , , — PHP, .
, Ansible. Loops , «loops _ + lookup(), ». (Lookups) — Ansible, « Ansible », Loops Ansible Github, .
Ansible « », , . Ansible, , , .
Ansible
TASKS, , , , , ( : , , , , !)
:
, :
alice,bob,caroldan.
, :
.ssh/loops.
, . , alice :
/home/alice/
├── .ssh/
├── bob/
├── carol/
├── dan/
└── loops/
1. WITH_ITEMS
Ansible , chuck , :
- name: Remove user ‘Chuck’ from the system.
user:
name: chuck
state: absent
remove: yes
— , Chuck Craig — with_items. with_items ( ), ( ):
- name: Remove users ‘Chuck’ and ‘Craig’ from the system.
user:
name: "{{ item }}"
state: absent
remove: yes
with_items:
- chuck
- craig
, with_items , alice bob:
users_with_items:
- name: "alice"
personal_directories:
- "bob"
- "carol"
- "dan"
- name: "bob"
personal_directories:
- "alice"
- "carol"
- "dan"
TASKS
- name: "Loop 1: create users using 'with_items'."
user:
name: "{{ item.name }}"
with_items: "{{ users_with_items }}"
Ansible User users_with_items. , , , , personal_directories ( , personal_directories — ).
Ansible ( Ansible ): TASKS , . , , personal_directories TASKS (. . User, File).
with_items , PHP:
<?php
foreach ($users_with_items as $user) {
// Do something with $user...
}
, , :
• item.name .
• with_items, .
, Ansible item, item.property.
/home/
├── alice/
└── bob/
2: , WITH_NESTED
: 2 , 1. chown failed: failed to look up user
, users_with_items 1, , common_directories, , . , ( PHP), -, :
<?php
foreach ($users_with_items as $user) {
foreach ($common_directories as $directory) {
// Create $directory for $user...
}
}
Ansible with_nested. with_nested , :
users_with_items:
- name: "alice"
personal_directories:
- "bob"
- "carol"
- "dan"
- name: "bob"
personal_directories:
- "alice"
- "carol"
- "dan"
common_directories:
- ".ssh"
- "loops
TASKS
# Note that this does not set correct permissions on /home/{{ item.x.name }}/.ssh!
- name: "Loop 2: create common users' directories using 'with_nested'."
file:
dest: "/home/{{ item.0.name }}/{{ item.1 }}"
owner: "{{ item.0.name }}"
group: "{{ item.0.name }}"
state: directory
with_nested:
- "{{ users_with_items }}"
- "{{ common_directories }}"
, with_nested , item.0 ( users_with_items) item.1 ( common_directories) . , , /home/alice/.ssh .
/home/
├── alice/
│ ├── .ssh/
│ └── loops/
└── bob/
├── .ssh/
└── loops/
3: , WITH_SUBELEMENTS
: 3 , 1. chown failed: failed to look up user
with_subelements , users_with_items 1. PHP :
<?php
foreach ($users_with_items as $user) {
foreach ($user['personal_directories'] as $directory) {
// Create $directory for $user...
}
}
, $users_with_items $user['personal_directories'] .
users_with_items:
- name: "alice"
personal_directories:
- "bob"
- "carol"
- "dan"
- name: "bob"
personal_directories:
- "alice"
- "carol"
- "dan"
TASKS
- name: "Loop 3: create personal users' directories using 'with_subelements'."
file:
dest: "/home/{{ item.0.name }}/{{ item.1 }}"
owner: "{{ item.0.name }}"
group: "{{ item.0.name }}"
state: directory
with_subelements:
- "{{ users_with_items }}"
- personal_directories
with_subelements , with_nested, , , — personal_directories. 2, ( ) /home/alice/bob.
/home/
├── alice/
│ ├── .ssh/
│ ├── bob/
│ ├── carol/
│ ├── dan/
│ └── loops/
└── bob/
├── .ssh/
├── alice/
├── carol/
├── dan/
└── loops/
4: WITH_DICT
3 , alice bob, , , carol dan. users_with_dict Ansible with_dict.
, (dict dictionary — Python ); with_dict , . , Ansible, PHP :
<?php
foreach ($users_with_dict as $user => $properties) {
// Create a user named $user...
}
users_with_dict:
carol:
common_directories: "{{ common_directories }}"
dan:
common_directories: "{{ common_directories }}"
TASKS
- name: "Loop 4: create users using 'with_dict'."
user:
name: "{{ item.key }}"
with_dict: "{{ users_with_dict }}"
with_dict . , , , dict with_dict (, , with_dict ).
/home/
├── alice/
│ ├── .ssh/
│ ├── bob/
│ ├── carol/
│ ├── dan/
│ └── loops/
├── bob/
│ ├── .ssh/
│ ├── alice/
│ ├── carol/
│ ├── dan/
│ └── loops/
├── carol/
└── dan/
5: ,
users_with_dict, Ansible, -. alice, bob, carol dan, with_nested /home/. , , , TASKS:
- Ansible
- Ansible
- Jinja2 ()
- Jinja2 ()
common_directories:
- ".ssh"
- "loops"
TASKS
- name: "Get list of extant users."
shell: "find * -type d -prune | sort"
args:
chdir: "/home"
register: "home_directories"
changed_when: false
- name: "Loop 5: create personal user directories if they don't exist."
file:
dest: "/home/{{ item.0 }}/{{ item.1 }}"
owner: "{{ item.0 }}"
group: "{{ item.0 }}"
state: directory
with_nested:
- "{{ home_directories.stdout_lines }}"
- "{{ home_directories.stdout_lines | union(common_directories) }}"
when: "'{{ item.0 }}' != '{{ item.1 }}'"
TASKS: shell find , file .
/home find \ -type d -prune | sort ( shell) , /home, , , .
home_directories register: "home_directories" . , , :
"stdout_lines": [
"alice",
"bob",
"carol",
"dan",
],
( ) with_nested , :
-
with_nested:
- "{{ home_directories.stdout_lines | union(common_directories) }}"
,
whenTASKS:
when: "'{{ item.0 }}' != '{{ item.1 }}'"
. with_nested Jinja2 TASKS ( home_directories.stdout_lines). Jinja:
- (
home_directories.stdout_lines) - (
|) - , (
union (common_directories))
, home_directories.stdout_lines common_directories :
item:
- .ssh
- alice
- bob
- carol
- dan
- loops
, with_nested home_directories.stdout_lines ( with_nested) , .
, — , , , ! (, /home/alice/alice, /home/bob/bob . .) Ansible — when — :
when: "'{{ item.0 }}' != '{{ item.1 }}'"
, home_directories.stdout_lines home_directories.stdout_lines ( Ansible Loops, «… when with_items ( ), when »). PHP , , :
<?php
$users = ['alice', 'bob', 'carol', 'dan'];
$common_directories = ['.ssh', 'loops'];
$directories = $user + $common_directories;
foreach ($users as $user) {
foreach ($directories as $directory) {
if ($directory != $user) {
// Create the directory…
}
}
}
, , .
/home/
├── alice/
│ ├── .ssh/
│ ├── bob/
│ ├── carol/
│ ├── dan/
│ └── loops/
├── bob/
│ ├── .ssh/
│ ├── alice/
│ ├── carol/
│ ├── dan/
│ └── loops/
├── carol/
│ ├── .ssh/
│ ├── alice/
│ ├── bob/
│ ├── dan/
│ └── loops/
└── dan/
├── .ssh/
├── alice/
├── bob/
├── carol/
└── loops/
Ansible . ( Ansible), , (with_nested? with_subitems?) .
, , TASKS, ( , array_filter, array_reduce, array_map , ). , , — — .
Espero que este post o ajude a sair da minha dificuldade inicial. Para isso, construí uma máquina virtual Vagrant (o Vagrant suporta nativamente o uso de Ansible para provisionamento) e um playbook de Ansible que usei para criar e testar esses exemplos). Basta seguir as instruções no README para executar os exemplos deste post ou tente o seu próprio. Se você tiver dúvidas ou comentários, tweet em @chromaticHQ!