アンシブルループの解明

この投稿では、次のAnsibleループモジュールについて説明します:with_items、with_nested、with_subelements、with_dict。



*が付いたこれらはすべてすでに非推奨であり、ループを使用することをお勧めします。



ソース



Chromaticでの私の役割の1つは、DevOpsチームのメンバーです。特に、これにはサーバーとクライアントのサーバーの操作が含まれます。つまり、サーバーとアプリケーションのプロビジョニング、構成、および展開のための一般的なツールであるAnsibleでの作業に多くの時間を費やすことになります。



簡単に言うと、Ansibleを実行しているマシンは、SSHを介して別のマシンでコマンドを実行します。これらのコマンドは、タスクと呼ばれるYAMLの小さなセクションを使用して宣言的に(オプションで)指定されますこれらのタスクは、ファイル、データベースなどの特定のコンポーネントでオプションを実行することに特化したAnsibleモジュール呼び出します。



たとえば、次のタスクでは、Fileモジュール(ドキュメントコード)を使用して、特定のディレクトリがまだ存在しない場合は作成し、正しく設定されていない場合はその属性を変更します。



- file:
    path: /home/jenkins/.ssh
    state: directory
    owner: jenkins
    group: jenkins
    mode: 700


1つのタスクに関連する複数のタスクはロールにグループ化され、複数のロールをプレイブックにグループ化できます。その後、プレイブックを使用して、任意の数のサーバーで同時にまったく同じ構成手順を実行できます。



Ansibleは宣言的ですか?



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, , , , , ( : , , , , !)



:



  1. , : alice, bob, carol dan.



  2. , : .ssh/ loops.



  3. , . , 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 Craigwith_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 , :



  1. with_nested :


- "{{ home_directories.stdout_lines | union(common_directories) }}"


  1. , when TASKS:



    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 , ). , , — — .



うまくいけば、この投稿が私の最初の困難を取り除くのに役立つでしょう。この目的のために、Vagrant仮想マシン(VagrantはプロビジョニングにAnsibleを使用することをネイティブにサポートします)と、これらの例を作成およびテストするために使用したAnsibleプレイブックを作成しました。READMEの指示に従って、この投稿の例を実行するか、独自の例を試してください。ご質問やご意見がございましたら、@ chronousHQまでツイートしてください!




All Articles