Категории: Все

по christophe Mias 7 месяца назад

1448

Ansible

Ansible

Ansible

Grande ligne

Langage
JSON
YAML
Usage
Sujet secondaire
CONFIGURATION

Path multiple

DEPLOYEMENT
ORCHESTRATION ET AUTOMATISATION

fonctionnement

Configuration
inventaire/inventory

Résumé:


  1. * inventory = inventaire des machines et de leurs variables
  2. * élément éssentiel car il décrit votre infra :* vos serveurs* vos types de serveurs
  3. * deux types d'instances :* hosts* groupes
  4. * plusieurs formats :* ini = plat* yaml = plus homogène* json = pour manipuler
  5. * possiblité d'utiliser des patterns
  6. * inventory = * fichier d'inventaire* répertoire group_vars* répertoire host_vars

répertoires associés

* variables d'inventaires:- fichier d'inventaire- group_vars (répertoire)- host_vars (répertoire)

├── 00_inventory.yml├── group_vars│   ├── all.yml│   ├── dbserver.yml│   └── webserver│       ├── vault.yml│       └── webserver.yml└── host_vars    ├── srv1    │   └── srv1.yml    └── srv2.yml

host_vars

group_vars

├── dev│   ├── 00_inventory.yml│   ├── group_vars│   │   ├── all.yml│   │   ├── dbserver.yml│   │   └── webserver│   │       ├── vault.yml│   │       └── webserver.yml│   └── host_vars│       ├── srv1│       │   └── srv1.yml│       └── srv2.yml├── prod│   ├── 00_inventory.yml│   ├── group_vars│   │   ├── all.yml│   │   ├── dbserver.yml│   │   └── webserver│   │       ├── vault.yml│   │       └── webserver.yml│   └── host_vars│       ├── srv1│       │   └── srv1.yml│       └── srv2.yml└── stage    ├── 00_inventory.yml    ├── group_vars    │   ├── all.yml    │   ├── dbserver.yml    │   └── webserver    │       ├── vault.yml    │       └── webserver.yml    └── host_vars        ├── srv1        │   └── srv1.yml        └── srv2.yml

on retrouve cette structure dans la sortie de ansible-config, ex:

 

tree

.
├── 00_inventory.yml
├── group_vars
│   └── common
│       └── params.yml
├── host_vars

cat group_vars/common/params.yml

ansible_python_interpreter: /usr/bin/python3
var1: serveurs de test

on retrouve les variables dans l'arborescence:

 cat  00_inventory.yml &&  ansible-inventory -i 00_inventory.yml --list --yaml
all:
  children:
    common:
      hosts:
       node[1:5]:
all:
  children:
    common:
      hosts:
        node1:
          ansible_python_interpreter: /usr/bin/python3
          var1: serveurs de test
        node2:
          ansible_python_interpreter: /usr/bin/python3
          var1: serveurs de test
        node3:
          ansible_python_interpreter: /usr/bin/python3
          var1: serveurs de test
        node4:
          ansible_python_interpreter: /usr/bin/python3
          var1: serveurs de test
        node5:
          ansible_python_interpreter: /usr/bin/python3
          var1: serveurs de test
    ungrouped: {}

ansible -i "node2," all -b -e "var1=xavki" -m debug -a 'msg={{ var1 }}'

détail:

-i "node2," = dans le groupe All , prendre en compte le node2 seul
-b = "become" = élévation des droits
-e = passage de la variable en cli
-m = le module utilisé (ici debug)
-a = l'argument associé au module

ansible -i 00_inventory.yml all -m debug -a 'msg={{ var1 }}'

node4 | SUCCESS => {
    "msg": "serveurs de test"
}
node1 | SUCCESS => {
    "msg": "serveurs de test"
}
node3 | SUCCESS => {
    "msg": "serveurs de test"
}
node2 | SUCCESS => {
    "msg": "serveurs de test"
}
node5 | SUCCESS => {
    "msg": "serveurs de test"
}

Inventaire dynamique

Documentation :

https://docs.ansible.com/ansible/latest/plugins/inventory.html

https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html

https://github.com/ansible-collections/community.general/tree/main/scripts/inventory


ex: nmap.yml

plugin: nmap
strict: false
address: 172.17.0.0/24


récupération de l(inventaire

samik@Abacus:~/ansible_dir(abacustraining⚡) » ansible-inventory -i nmap.yml --list -y --output test.yml
samik@Abacus:~/ansible_dir(abacustraining⚡) » cat test.yml 
all:
 children:
  ungrouped:
   hosts:
    node1:
     ip: 172.17.0.2
     nginx_port: 8888
     ports:
     - port: '22'
      protocol: tcp
      service: ssh
      state: open
     var1: groupvar
    node2:
     ip: 172.17.0.3
     nginx_port: 8888
     ports:
     - port: '22'
      protocol: tcp
      service: ssh
      state: open
     var1: groupvar
    node3:
     ip: 172.17.0.4
     nginx_port: 8888
     ports:
     - port: '22'
      protocol: tcp
      service: ssh
      state: open
     var1: groupvar
    node4:
     ip: 172.17.0.5
     nginx_port: 8888
     ports:
     - port: '22'
      protocol: tcp
      service: ssh
      state: open
     var1: groupvar

ansible -i nmap.yml all -m ping
[WARNING]: Platform linux on host node3 is using the discovered Python interpreter at
/usr/bin/python3.7, but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
node3 | SUCCESS => {
  "ansible_facts": {
    "discovered_interpreter_python": "/usr/bin/python3.7"
  },
  "changed": false,
  "ping": "pong"
}
[WARNING]: Platform linux on host node4 is using the discovered Python interpreter at
/usr/bin/python3.7, but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
node4 | SUCCESS => {
  "ansible_facts": {
    "discovered_interpreter_python": "/usr/bin/python3.7"
  },
  "changed": false,
  "ping": "pong"
}
...

inventory généré

 ansible-inventory -i nmap.yml --list
{
  "_meta": {
    "hostvars": {
      "node1": {
        "ip": "172.17.0.2",
        "nginx_port": 8888,
        "ports": [
          {
            "port": "22",
            "protocol": "tcp",
            "service": "ssh",
            "state": "open"
          }
        ],
        "var1": "groupvar"
      },
      "node2": {
        "ip": "172.17.0.3",
        "nginx_port": 8888,
        "ports": [
          {
            "port": "22",
            "protocol": "tcp",
            "service": "ssh",
            "state": "open"
          }
        ],
        "var1": "groupvar"
      },
      "node3": {
        "ip": "172.17.0.4",
        "nginx_port": 8888,
        "ports": [
          {
            "port": "22",
            "protocol": "tcp",
            "service": "ssh",
            "state": "open"
          }
        ],
...
        "var1": "groupvar"
      },
      "node4": {
        "ip": "172.17.0.5",
        "nginx_port": 8888,
        "ports": [
          {
            "port": "22",
            "protocol": "tcp",
            "service": "ssh",
            "state": "open"
          }
        ],
        "var1": "groupvar"
      }
    }
  },
  "all": {
    "children": [
      "ungrouped"
    ]
  },
  "ungrouped": {
    "hosts": [
      "node1",
      "node2",
      "node3",
      "node4"
    ]

les différents plugins par défaut sont à configurer ici:

* ansible.cfg

[inventory]
# enable inventory plugins, default: 'host_list', 'script', 'auto', 'yaml', 'ini', 'toml'
#enable_plugins = host_list, virtualbox, yaml, constructed

le fichier de base

inventory.json

$ ansible-inventory -i 00_inventory.yml --list

{
    "_meta": {
        "hostvars": {
            "172.17.0.2": {
                "ansible_python_interpreter": "/usr/bin/python3"
            },
            "172.17.0.3": {
                "ansible_python_interpreter": "/usr/bin/python3"
            },
            "172.17.0.4": {
                "ansible_python_interpreter": "/usr/bin/python3"
            },
            "172.17.0.5": {
                "ansible_python_interpreter": "/usr/bin/python3"
            },
            "172.17.0.6": {
                "ansible_python_interpreter": "/usr/bin/python3"
            },
            "172.17.0.7": {
                "ansible_python_interpreter": "/usr/bin/python3"
            }
        }
    },
    "all": {
        "children": [
            "ungrouped"
        ]
    },
    "ungrouped": {
        "hosts": [
            "172.17.0.2",
            "172.17.0.3",
            "172.17.0.4",
            "172.17.0.5",
            "172.17.0.6",
            "172.17.0.7"
        ]
    }
}

Inventory.yml

cat 00_inventory.yml                            

all:
  vars:
    ansible_python_interpreter: /usr/bin/python3
  hosts:
    172.17.0.7:
    172.17.0.6:
    172.17.0.5:
    172.17.0.4:
    172.17.0.3:
    172.17.0.2:

 ansible-inventory -i 00_inventory.yml --list --yaml

all:
  children:
    ungrouped:
      hosts:
        172.17.0.2:
          ansible_python_interpreter: /usr/bin/python3
        172.17.0.3:
          ansible_python_interpreter: /usr/bin/python3
        172.17.0.4:
          ansible_python_interpreter: /usr/bin/python3
        172.17.0.5:
          ansible_python_interpreter: /usr/bin/python3
        172.17.0.6:
          ansible_python_interpreter: /usr/bin/python3
        172.17.0.7:
          ansible_python_interpreter: /usr/bin/python3

hosts

Appelé fichier ini:

[imac]
localhost ansible_connection=local
imacpat
[laptop]
mbp
kaisenlinux
[vm]
abacus
[tab]
nexus
ipadkris



ansible-inventory --list --toml
[imac.hosts.imacpat]

[imac.hosts.localhost]
ansible_connection = "local"

[laptop.hosts.kaisenlinux]

[laptop.hosts.mbp]

[tab.hosts.ipadkris]

[tab.hosts.nexus]

[vm.hosts.abacus]

commande

ansible-inventory

ansible-inventory

usage: ansible-inventory [-h] [--version] [-v] [-i INVENTORY] [--vault-id VAULT_IDS]
                         [--ask-vault-password | --vault-password-file VAULT_PASSWORD_FILES] [--playbook-dir BASEDIR]
                         [--list] [--host HOST] [--graph] [-y] [--toml] [--vars] [--export] [--output OUTPUT_FILE]
                         [host|group]

positional arguments:
  host|group

optional arguments:
  --ask-vault-password, --ask-vault-pass
                        ask for vault password
  --export              When doing an --list, represent in a way that is optimized for export,not as an accurate
                        representation of how Ansible has processed it
  --output OUTPUT_FILE  When doing --list, send the inventory to a file instead of to the screen
  --playbook-dir BASEDIR
                        Since this tool does not use playbooks, use this as a substitute playbook directory.This sets the
                        relative path for many features including roles/ group_vars/ etc.
  --toml                Use TOML format instead of default JSON, ignored for --graph
  --vars                Add vars to graph display, ignored unless used with --graph
  --vault-id VAULT_IDS  the vault identity to use
  --vault-password-file VAULT_PASSWORD_FILES, --vault-pass-file VAULT_PASSWORD_FILES
                        vault password file
  --version             show program's version number, config file location, configured module search path, module location,
                        executable location and exit
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY
                        specify inventory host path or comma separated host list. --inventory-file is deprecated
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable connection debugging)
  -y, --yaml            Use YAML format instead of default JSON, ignored for --graph

Actions:
  One of following must be used on invocation, ONLY ONE!

  --graph               create inventory graph, if supplying pattern it must be a valid group name
  --host HOST           Output specific host info, works as inventory script
  --list                Output all hosts info, works as inventory script

Show Ansible inventory information, by default it uses the inventory script JSON format
ERROR! No action selected, at least one of --host, --graph or --list needs to be specified.

--graph

ansible-inventory   --graph
@all:
  |--@common:
  |  |--@dbserver:
  |  |  |--node4
  |  |  |--node5
  |  |--@webserver:
  |  |  |--node1
  |  |  |--node2
  |  |  |--node3
  |--@monitoring:
  |  |--@dbserver:
  |  |  |--node4
  |  |  |--node5
  |  |--@nocommon:
  |  |  |--node6
  |  |--@webserver:
  |  |  |--node1
  |  |  |--node2
  |  |  |--node3
  |--@ungrouped:
ansible-inventory   -i 00_inventory.yml --graph
@all:
  |--@common:
  |  |--node1
  |  |--node2
  |  |--node3
  |  |--node4
  |  |--node5
  |--@ungrouped:

--list

--toml

ajout de l'option avec:

pip3 install toml

--yaml

ansible-inventory --list --yaml

all:
  children:
    common:
      children:
        dbserver:
          hosts:
            node4:
              var1: gp_dbserver
            node5:
              var1: node5
        webserver:
          hosts:
            node1:
              var1: gp_webserver
            node2:
              var1: node2
            node3:
              var1: gp_webserver
    monitoring:
      children:
        dbserver:
          hosts:
            node4: {}
            node5: {}
        nocommon:
          hosts:
            node6:
              var1: all
        webserver:
          hosts:
            node1: {}
            node2: {}
            node3: {}
    ungrouped: {}
Precedence des variables

ANSIBLE : Precedence des variables


* 23 types / localisation :
        command line values (eg “-u user”)        role defaults [1]        inventory file or script group vars [2]        inventory group_vars/all [3]        playbook group_vars/all [3]        inventory group_vars/* [3]        playbook group_vars/* [3]        inventory file or script host vars [2]        inventory host_vars/* [3]        playbook host_vars/* [3]        host facts / cached set_facts [4]        play vars        play vars_prompt        play vars_files        role vars (defined in role/vars/main.yml)        block vars (only for tasks in block)        task vars (only for the task)        include_vars        set_facts / registered vars        role (and include_role) params        include params        extra vars (always win precedence)

roles
Exemple2

ANSIBLE : Ex - Monitoring > node exporter


Objectif : série de vidéo de mise en pratique autour du monitoring

prometheus / grafana / node-exporter...



* travail sur 4 noeuds

1- un de monitoring (prometheus/grafana)

2- tous monitoré par node exporter


* structure = inventory + playbook + role node exporter


Informations des conteneurs :


  => /samik-debian-4 - 172.17.0.5

  => /samik-debian-3 - 172.17.0.4

  => /samik-debian-2 - 172.17.0.3

  => /samik-debian-1 - 172.17.0.2

- name: Install Nodeexporter
  hosts: all
  become: yes
  roles:
    - node-exporter
- name: Install prometheus grafana
  hosts: monito
  become: yes
  roles:
    - monito
    - grafana


phase3

role grafana

---
# handlers file for roles/grafana
- name: restart_grafana
  systemd:
    name: grafana-server
    state: restarted
    enabled: yes
    daemon_reload: yes


dashboard-node-exporter.yml.j2

apiVersion: 1
providers:
- name: 'node-exporter'
  orgId: 1
  folder: ''
  type: file
  disableDeletion: false
  updateIntervalSeconds: 10 
  options:
    path: /var/lib/grafana/node-exporter.json


---
# tasks file for roles/grafana
- name: install gpg
  apt:
    name: gnupg,software-properties-common
    state: present
    update_cache: yes
    cache_valid_time: 3600
- name: add gpg hey
  apt_key:
    url: "https://packages.grafana.com/gpg.key"
    validate_certs: no
- name: add repository
  apt_repository:
    repo: "deb https://packages.grafana.com/oss/deb stable main"
    state: present
    validate_certs: no
- name: install grafana
  apt:
    name: grafana
    state: latest
    update_cache: yes
    cache_valid_time: 3600
- name: change admin user
  lineinfile:
    path: /etc/grafana/grafana.ini
    regexp: "{{ item.before }}"
    line: "{{ item.after }}"
  with_items:
  - { before: "^;admin_user = admin", after: "admin_user = {{ grafana_admin_user }}"}
  - { before: "^;admin_password = admin", after: "admin_password = {{ grafana_admin_password }}"}
  notify: restart_grafana
- name: start service grafana-server
  systemd:
    name: grafana-server
    state: started
    enabled: yes
- name: wait for service up
  uri:
    url: "http://127.0.0.1:3000"
    status_code: 200
  register: __result
  until: __result.status == 200
  retries: 120
  delay: 1
- name: add prometheus datasource
  grafana_datasource:
    name: "prometheus-local"
    grafana_url: "http://127.0.0.1:3000"
    grafana_user: "{{ grafana_user_admin }}"
    grafana_password: "{{ grafana_admin_password }}"
    org_id: "1"
    ds_type: "prometheus"
    ds_url: "127.0.0.1:9090"
  changed_when: false
- name: install node exporter dashboard
  get_url:
    url: https://raw.githubusercontent.com/rfrail3/grafana-dashboards/master/prometheus/node-exporter-full.json
    dest: /var/lib/grafana/node-exporter.json
    mode: '0755'
- name: activate dashboard for node exporter
  template:
    src: dashboard-node-exporter.yml.j2
    dest: /etc/grafana/provisioning/dashboards/dashboard-node-exporter.yml
    mode: 0755
  notify: restart_grafana

grafana_admin_user: "admin"
grafana_admin_password: "password"

phase2

role monito

prometheus.yml.j2

#jinja2: lstrip_blocks: "True"
{{ prometheus_var_config | to_nice_yaml(indent=2) }}
{% if prometheus_node_exporter_group %}
- job_name: node_exporter
  scrape_interval: 15s
  static_configs:
  - targets:
{% for server in groups[prometheus_node_exporter_group] %}
    - {{ server }}:9100
{% endfor %}
{% endif %}


prometheus.j2

# Set the command-line arguments to pass to the server.
ARGS="--web.enable-lifecycle --storage.tsdb.retention.time={{ prometheus_retention_time }} --web.console.templates=/etc/prometheus/consoles --web.console.libraries=/etc/prometheus/console_libraries

---
# handlers file for roles/monito
- name: restart_prometheus
  systemd:
    name: prometheus
    state: restarted
    enabled: yes
    daemon_reload: yes

- name: reload_prometheus
  uri: 
    url: http://localhost:9090/-/reload
    method: POST
    status_code: 200


---
# tasks file for roles/monito
- name: update and install prometheus
  apt:
    name: prometheus
    state: latest
    update_cache: yes
    cache_valid_time: 3600
- name: prometheus args
  template:
    src: prometheus.j2
    dest: /etc/default/prometheus
    mode: 0644
    owner: root
    group: root
  notify: restart_prometheus
- name: prometheus configuration file
  template:
    src: prometheus.yml.j2
    dest: "{{ prometheus_dir_configuration }}/prometheus.yml"
    mode: 0755
    owner: prometheus
    group: prometheus
  notify: reload_prometheus
- name: start prometheus
  systemd:
    name: prometheus
    state: started
    enabled: yes

- meta: flush_handlers


---
# defaults file for roles/monito
prometheus_dir_configuration: "/etc/prometheus"
prometheus_retention_time: "365d"
prometheus_scrape_interval: "30s"
prometheus_node_exporter: true
prometheus_node_exporter_group: "all"
prometheus_env: "production"
prometheus_var_config: 
  global:
    scrape_interval: "{{ prometheus_scrape_interval }}"
    evaluation_interval: 5s 
    external_labels:
      env: '{{ prometheus_env }}'
  scrape_configs:
    - job_name: prometheus
      scrape_interval: 5m
      static_configs:
        - targets: ['{{ inventory_hostname }}:9090']


phase1

LES TASKS DU ROLE



* vérifier si node exporter est déjà installé

roles node-exporter

node_exporter.service.j2

[Unit]
Description=Node Exporter Version {{node_exporter_version}}
After=network-online.target
Wants=network-online.target


[Service]
User={{ node_exporter_user }}
Group={{ node_exporter_user }}
Type=simple
ExecStart={{ node_exporter_bin }}


[Install]
WantedBy=multi-user.target



handler

---
# handlers file for roles/node-exporter
- name: reload_daemon_and_restart_node_exporter
  systemd:
    name: node_exporter
    state: restarted
    daemon_reload: yes
    enabled: yes


tasks

---
# tasks file for roles/node-exporter
- name: check if node exporter exist
  stat:
    path: "{{ node_exporter_bin }}"
  register: __check_node_exporter_present
- name: create node exporter user
  user:
    name: "{{ node_exporter_user }}"
    append: true
    shell: /usr/sbin/nologin
    system: true
    create_home: false
    home: /
- name: create node exporter config dir
  file:
    path: "{{ node_exporter_dir_conf }}"
    state: directory
    owner: "{{ node_exporter_user }}"
    group: "{{ node_exporter_group }}"


    # on récupère la version via le module shell
- name: if node exporter exist get version
  shell: "cat /etc/systemd/system/node_exporter.service | grep Version | sed s/'.*Version '//g"
  when: __check_node_exporter_present.stat.exists == true
  changed_when: false
  register: __get_node_exporter_version


- name: download and unzip node exporter if not exist
  unarchive:
    #src: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz"
    src: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.{{ node_exporter_platform }}.tar.gz"
    dest: /tmp/
    remote_src: yes
#  when: __check_node_exporter_present.stat.exists == false
  when: __check_node_exporter_present.stat.exists == false or not __get_node_exporter_version.stdout == node_exporter_version
- name: move the binary to the final destination
  copy:
    src: "/tmp/node_exporter-{{ node_exporter_version }}.{{ node_exporter_platform}}/node_exporter"
    dest: "{{ node_exporter_bin }}"
    owner: "{{ node_exporter_user }}"
    group: "{{ node_exporter_group }}"
    mode: 0755
    remote_src: yes
 # when: __check_node_exporter_present.stat.exists == false
  when: __check_node_exporter_present.stat.exists == false or not __get_node_exporter_version.stdout == node_exporter_version
- name: clean
  file:
    path: "/tmp/node_exporter-{{ node_exporter_version }}.{{ node_exporter_platform}}/node_exporter"
    state: absent
- name: install service
  template:
    src: node_exporter.service.j2
    dest: /etc/systemd/system/node_exporter.service
    owner: root
    group: root
    mode: 0755
  notify: reload_daemon_and_restart_node_exporter


- meta: flush_handlers


- name: service always started
  systemd:
    name: node_exporter
    state: started
    enabled: yes


default

---
# defaults file for roles/node-exporter
node_exporter_version: "1.0.1"
node_exporter_bin: /usr/local/bin/node_exporter
node_exporter_user: node-exporter
node_exporter_group: "{{ node_exporter_user }}"
node_exporter_dir_conf: /etc/node_exporter
node_exporter_platform: "linux-arm64"

Exemple1

3 roles

nginx

ROLE NGINX : installation du serveur nginx

                        - name: install nginx    apt:      name: nginx,curl      state: present      cache_valid_time: 3600      update_cache: yes  - name: remove default file    file:      path: "{{ item }}"      state: absent    with_items:    - "/etc/nginx/sites-available/default"    - "/etc/nginx/sites-enabled/default"  - name: install vhost    template:      src: default_vhost.conf.j2      dest: /etc/nginx/sites-available/default_vhost.conf      owner: root      group: root      mode: 0644    notify: reload_nginx  - name: Flush handlers    meta: flush_handlers                    

users

* ROLE USERS : création d'un user et ajout de la clef ssh

                                              
                                          
- name: création du user devops    user:      name: devops      shell: /bin/bash      groups: sudo      append: yes      password: "{{ 'password' | password_hash('sha512') }}"    become: yes  - name: Add devops user to the sudoers    copy:      dest: "/etc/sudoers.d/devops"      content: "devops  ALL=(ALL)  NOPASSWD: ALL"    become: yes  - name: Deploy SSH Key    authorized_key:       user: devops      key: "{{ lookup('file', '/tmp/xavki.pub') }}"      state: present    become: yes

ssh_keygen

* ROLE SSH_KEYGEN : génération d'une clef

                                              
                                          
- name: mon premier playbook  hosts: localhost  connection: local  roles:  - ssh_keygen  - name: generate SSH key"    openssh_keypair:      path: /tmp/xavki      type: rsa      size: 4096      state: present      force: no

initialisation

creer: un dossier roles
executer: ansible-galaxy init monrole
résultat:
 
 
tree -a
.
└── monrole
  ├── defaults
  │  └── main.yml
  ├── files
  ├── handlers
  │  └── main.yml
  ├── meta
  │  └── main.yml
  ├── README.md
  ├── tasks
  │  └── main.yml
  ├── templates
  ├── tests
  │  ├── inventory
  │  └── test.yml
  ├── .travis.yml
  └── vars
    └── main.yml

Playbook

nombreuses options : -i : inventory


Variable d'environnement

Documentation :

https://docs.ansible.com/ansible/latest/user_guide/playbooks_environment.html

Objectifs : Définir des variables d'environnement et utiliser un prompt


* différents endroits pour définir les variables d'environnement

* playbook

* tasks

prompt

* var prompt : interrogation de l'utilisateur

  vars_prompt:
    - name: nom
  tasks:
  - name: echo
    shell: "echo Salut {{ nom }}"
    register: __output
  - name: print
    debug:
      var: __output


* avec phrase et valeur par défaut

  vars_prompt:
  - name: env
    prompt: "Quel est votre environnement ? prod/stage/dev"
    default: dev
  environment:
    ENV: "{{ env }}"
  tasks:
  - name: echo
    shell: "echo Salut $ENV"
    register: __output
  - name: print
    debug:
      var: __output

* exemples:

- name: utilisation du module shell et command
  hosts: all
  environment:
    PATHLIB: "/var/lib/"
    ENV: "{{ env }}"
  vars_prompt: 
    - name: nom
    - name: env
      prompt: "Quel est votre environnement ? prod/stage/dev"
      default: dev
  tasks:
  - name: echo
    shell: echo $PATHLIB
    register: __output
    changed_when: false
  - name: print
    debug:
      var: __output
  - name: echo
    shell: "echo Salut $ENV"
    register: __output
  - name: print
    debug:
      var: __output

environment



- name: utilisation du module shell et command
  hosts: all
  environment:
    PATHLIB: "/var/lib/"
  tasks:
  - name: echo
    shell: echo $PATHLIB
    register: __output
  - name: print
    debug:
      var: __output


* variable d'environnement de la machine ansible

  - name: echo
    shell: "echo {{ lookup('env', 'ENV') | default('stage', True) }}"
    register: __output
  - name: print
    debug:
      var: __output


modules

docker

ANSIBLE : module docker login & docker_image


* Objectif : construction, build et push d'images docker

Documentation :

https://docs.ansible.com/ansible/latest/collections/community/general/docker_image_module.html


Prérequis :

* docker

* python3-docker ou pip3 install docker


PARAMETRES :

* api_version : version de l'api docker (docker info)

* archive_path : cas d'une image en tar, chemin d'accès

* build : pour constuire une image * args : clef/valeur * cache_from : images sources utilisées en cache * container_limits: limite applicable aux conteneurs POUR LE BUILD * cpusetcpus : spécificier le cpu (taskset) * cpushares : poids des cpus * memory : mémoire maximum * memswap : mémoire total (mem + swap) , -1 = disable swap

	* dockerfile : nom du fichier Dockerfile
	* /etc/hosts : utilisé lors du build (liste : ip / adresses)
	* http_timeout : timeout lors du build
	* network : utilisé pour le RUN
	* no_cache: ne pas utiliser de cache
	* path : chemin de contexte pour le build
	* pull : dowload du/des FROM
	* rm : suppression des images intermédiaires après le build
	* target : image finale résultant de plusieurs stage
	* use_config_proxy : utilisation d'un proxy

ANSIBLE : module docker login & docker_image


* buildargs (deprecated) : idem build > args

* ca_cert : vérficiation du serveur par ca (DOCKER_CERT_PATH)

* client_cert : tls client

* client_key : tls client clef

* containers_limit (deprecated) : idem build > container_limits

* debug : activation du mode debug

* docker_hosts : par défaut socket local sinon tcp/ssh

* dockerfile (deprecated) : cf build

* force : à utiliser avec le state absent pour forcer la suppression

* force_source : refaire build, load, pull d'une image qui existe déjà

* force_tag : forcer le tagging d'une image

* http_timeout (deprecated) : cf build ANSIBLE : module docker login & docker_image


* load_path : load une image via son archive tar

* name : nom de l'image url_registry/nom

* nocache : ne pas utiliser le cache au build

* path (deprecated) : cf build

* pull : idem

* push : idem

* repository : chemin vers le dépôt

* rm (deprecated) : cd build

* source : origine de l'image : * build : dockerfile * load : archive tar * pull : pull d'une registry * local : déjà présente dans le cache local ANSIBLE : module docker login & docker_image


* ssl_version : version ssl pour docker

* state : present / build / absent

* tag : tag de l'image

* timeout : délai pour le timeout du daemon docker

* tls : connexion chiffrée vers l'api docker

* tls_hostname : hostname pour le tls

* validate_certs : check tls

login

* cas du build & push

  - include_vars: /home/oki/.vault.yml
  - name: docker login
    docker_login:
      registry_url: registry.gitlab.com
      username: xavki
      password: "{{ vault_token_gitlab }}"
      reauthorize: yes
  - name: build
    docker_image:
      build:
        path: /tmp/build/
        dockerfile: Dockerfile
        pull: yes
        cache_from:
        - alpine:3.9
      source: build
      name: registry.gitlab.com/xavki/testflux
      tag: v1.1


Container

* Objectif : lancement d'image docker

Documentation :

https://docs.ansible.com/ansible/latest/collections/community/general/docker_container_module.html


Prérequis :

* docker

* python3-docker ou pip3 install docker


PARAMETRES :

ANSIBLE : module docker_container


image

* pull simple d'une image

  - name: Pull an image
    docker_image:
      name: alpine
      tag: latest
      source: pull


* retaguer une image

  - name: Pull an image
    docker_image:
      name: alpine
      tag: latest
      repository: myregistry/monimage:v1.0

ANSIBLE : module docker login & docker_image


* import via un tar (docker save)

  - name: copy image
    copy:
      src: image.test.v1.0.tar
      dest: /tmp/
  - name: Pull an image
    docker_image:
      name: archive
      tag: v1.0
      load_path: /tmp/image.test.v1.0.tar
      source: load

Exemple build

* build d'image via Dockerfile

  - name: copy files
    file:
      path: /tmp/build
      state: directory
  - name: copy image
    copy:
      src: app/
      dest: /tmp/build
  - name: build
    docker_image:
      name: imgbuild
      tag: v1.0
      source: build
      build:
        path: /tmp/build/app/
        dockerfile: Dockerfile
        cache_from:
        - alpine:3.9

ANSIBLE : module docker login & docker_image


* cas du build & push

  - include_vars: /home/oki/.vault.yml
  - name: docker login
    docker_login:
      registry_url: registry.gitlab.com
      username: xavki
      password: "{{ vault_token_gitlab }}"
      reauthorize: yes
  - name: build
    docker_image:
      build:
        path: /tmp/build/
        dockerfile: Dockerfile
        pull: yes
        cache_from:
        - alpine:3.9
      source: build
      name: registry.gitlab.com/xavki/testflux
      tag: v1.2
      push: yes 

assemble

ANSIBLE : Module ASSEMBLE


Documentation :

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assemble_module.html


PARAMETRES

* backup : sauvegarde du fichier avant changement

* decrypt : déchiffrer automatiquement par défaut ou pas le vault

* delimiter : séparation entre chaque fichier

* dest : la destination (fichier)

* group : groupe du fichier de destination

* regexp : regular expression de pattern des fichiers sources

* remote_src

* src : répertoire source



* validate : commande de validation ANSIBLE : Module ASSEMBLE


* simple via uniquement le remote

  - name: dir
    file:
      path: /tmp/sources
      state: directory
  - name: copy
    copy:
      src: "files/{{ item }}"
      dest: /tmp/sources/
    with_items:
    - t1
    - t2
    - t3
  - name: test assemble
    assemble:
      src: /tmp/sources
      dest: /tmp/myconf.cfg

ANSIBLE : Module ASSEMBLE


* ajouter un delimiter

delimiter: '### START FRAGMENT ###'


* sans remote src

  - name: test assemble
    assemble:
      src: files/
      dest: /tmp/myconf.cfg
      remote_src: no

Shell/command

Documentation :

https://docs.ansible.com/ansible/2.5/modules/shell_module.html

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html

Objectifs : lancer des commandes shell

Command vs Shell > command : options réduites (lance des commandes simples) shell : utilisation de tout ce qui est dans la CLI (pipe...)


PARAMETRES : COMMAND

* argv : ligne de commande sous forme de liste

* chdir : change de répertoire

* cmd : commande lancée

* creates : la commande n'est pas lancée si le fichier existe

* removes : inverse de creates, si le fichier existe la commande est lancée

* stdin : spécifier une valeur entrante via stdin

* stdin_add_newline : passe une ligne pour le stdin

* strip_empyt_ends : supprimer les lignes vides


* simple :
  - name: test
    command:
      cmd: ls
    register: __output

* changement de directory :
  - name: test
    command:
      cmd: ls
      chdir: /etc/
    register: __output
ANSIBLE : Modules COMMAND & SHELL

* commande en liste :
  - name: test
    command:
      argv:
      - ls
      - -larth
    register: __output

* sous condition si le fichier n'existe pas
  - name: touch
    file:
      path: /tmp/xavki
      state: touch
  - name: test
    command: 
      cmd: ls -lath /tmp
      creates: /tmp/xavki
    register: __output
  - name: debug
    debug:
      var: __output
ANSIBLE : Modules COMMAND & SHELL

* inverse : si il existe
  - name: test
    command: 
      cmd: ls -lath /tmp
      removes: /tmp/xavki
ANSIBLE : Modules COMMAND & SHELL

PARAMTRES : SHELL
* chdir : changement de répertoire d'exécution
* creates : la commande est lancée si le fichier n'existe pas
* executable : choix du shell utilisé
* removes : inverse de creates
* stdin : définir un stdin
* warn : afficher ou non les warn
ANSIBLE : Modules COMMAND & SHELL

* exemple simple :
  - name: test
    shell: cat /etc/hosts | grep 127
    register: __output
  - name: debug
    debug:
      var: __output

* exemple avec un bloc
  - name: test
    shell: |
      cat /etc/hosts
      ls /etc/
    register: __output
  - name: debug
    debug:
      var: __output

* exemple avec des variables d'environnement
  - name: test
    shell: echo "Hello $MAVAR"
    environment:
      MAVAR: "xavki"
    register: __output

uri

Objectifs : passer des requêtes http ou https et interagir avec


PARAMETRES :

* HEADER_ : paramètre header pour passer vos requêtes

* body : si activation du format json récupérer une variable

* body_format : format du body json ou raw

* creates : si le fichier existe la tâche n'est pas lancée

* dest : répertoire de destination

* follow_redirects : suivre les redirections

* force_basic_aut : forcer le basic auth

* headers : ajout de header (format yaml)

* method : GET / POST/ DELETE / PUT / HEAD / PATCH / TRACE...

* others : autre argument pour le file module (fichier créé)

* password : pour le basic auth

* removes : supprime le fichier avant

* return_content : pour récupérer le contenu

* status_code : 200, 301... [200,201...]

* timeout : en seconde

* url : target

* user : pour basic_auth

* validate_certs : stricte tls ou non 

* cas simple
- name: test
  hosts: all
  tasks:
  - name: uri
    uri: 
      url: http://xavki.blog
      method: GET
      validate_certs: False

* vérification du status
- name: test
  hosts: all
  tasks:
  - name: uri
    uri: 
      url: http://xavki.blog
      method: GET
      validate_certs: False
      status_code: 200
ANSIBLE : Module URI

* liste de code retour
  - name: uri
    uri: 
      url: https://httpbin.org/status/500
      method: POST
      status_code: [200,201,301]
      validate_certs: False

* récupération du contenu
- name: test
  hosts: all
  tasks:
  - name: uri
    uri: 
      url: http://httpbin.org/get
      return_content: yes
      method: GET
    register: __content
  - name: debug
    debug:
      var: __content.content
ANSIBLE : Module URI

* utilisation du format json
  - name: uri
    uri: 
      url: https://httpbin.org/get
      method: GET
      return_content: yes
      validate_certs: False
      body_format: json
    register: __body
  - name: debug
    debug:
      var: __body.json.url

* validation du contenu
- name: test
  hosts: all
  tasks:
  - name: uri
    uri: 
      url: http://xavki.blog
      return_content: yes
      method: GET
      validate_certs: False
    register: __content
    failed_when: " 'xavki' not in __content.content"
ANSIBLE : Module URI

* basic auth
   hosts: all
  tasks:
  - name: uri
    uri: 
      url: https://httpbin.org/basic-auth/toto/test
      user: "toto"
      password: "test"
      method: GET
      validate_certs: False
  
  - name: uri2
    uri: 
      url: https://httpbin.org/basic-auth/tot/test
      user: "toto"
      password: "test"
      method: GET
      validate_certs: False



Gather Facts & module Setup

Documentation : * setup : https://docs.ansible.com/ansible/2.3/setup_module.html * gather facts : https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html 
* facts > données relatives aux machines plus ou moins détaillées (réduit, non collectés...) * networks * devices * os * hardware * connexion utilisée * montages/volumes... 
* ansible_facts : dictionnaire contenant tous les facts

set_fact

ANSIBLE : Module SET_FACT


Documentation :

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html


PARAMETRES

* cacheable : ajouté au cache (défaut non)


  - name: set fact
    set_fact:
      mavariable: "Hello tout le monde !!"
  - name: debug
    debug:
      var: mavariable

ANSIBLE : Module SET_FACT


* exemple avec éléments calculés

  vars:
    var1: "hello"
    var2: "je suis"
  tasks:
  - name: get user
    command: "echo $USER"
    register: __user
  - name: date
    set_fact:
      mavariable: "{{ var1 }} {{ var2 }} {{ __user.stdout }} sur {{ ansible_hostname }}"
  - name: debug
    debug:
      var: mavariable

ANSIBLE : Module SET_FACT


* le gather fact datetime :

  - name: date
    debug:
      var: ansible_date_time


* si cache (ansible.cfg)

#cache facts
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/facts_cache
# two hours timeout
fact_caching_timeout = 7200

ANSIBLE : Module SET_FACT


* contourner le cache

  - name: date without cache
    shell: "date +%Y-%m-%d"
    register: shell_date
  - set_fact:
      date: "{{ shell_date.stdout }}"


 ansible-playbook -i 00_inventory.yml -D pbfact.yml 

PLAY [exemple synchro] ********************************************************************************

TASK [Gathering Facts] ********************************************************************************
ok: [172.17.0.5]
ok: [172.17.0.3]
ok: [172.17.0.4]
ok: [172.17.0.2]

TASK [get user] ***************************************************************************************
changed: [172.17.0.2]
changed: [172.17.0.4]
changed: [172.17.0.3]
changed: [172.17.0.5]

TASK [date] *******************************************************************************************
ok: [172.17.0.3]
ok: [172.17.0.4]
ok: [172.17.0.5]
ok: [172.17.0.2]

TASK [debug] ******************************************************************************************
ok: [172.17.0.5] => {
  "mavariable": "hello je suis samik sur samik-debian-4"
}
ok: [172.17.0.3] => {
  "mavariable": "hello je suis samik sur samik-debian-2"
}
ok: [172.17.0.4] => {
  "mavariable": "hello je suis samik sur samik-debian-3"
}
ok: [172.17.0.2] => {
  "mavariable": "hello je suis samik sur samik-debian-1"
}

PLAY RECAP ********************************************************************************************
172.17.0.2         : ok=4  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0  
172.17.0.3         : ok=4  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0  
172.17.0.4         : ok=4  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0  
172.17.0.5         : ok=4  changed=1  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0  


* soit en cli

ansible -i 00_inventory.yml all -m setupansible -i 00_inventory.yml all -m setup -a "filter=ansible_user*"

* soit par la variable
  - name: debug    debug:      var: ansible_facts

apt_key

https://docs.ansible.com/ansible/2.5/modules/apt_key_module.html* apt_repository : https://docs.ansible.com/ansible/2.5/modules/apt_repository_module.html
APT_KEY

PARAMETRES :


* data > directement fournir la clef

Exemple avec docker

ANSIBLE : Installation dépôt APT - ex : docker

Quelques exemples :


* à partir d'un fichier

- name: Add a key from a file on the Ansible server.  apt_key:    data: "{{ lookup('file', 'apt.asc') }}"    state: present

* à partir d'une url
- name: Add an Apt signing key to a specific keyring file  apt_key:    id: 9FED2BCBDCD29CDF762678CBAED4B06F473041FA    url: https://ftp-master.debian.org/keys/archive-key-6.0.asc    keyring: /etc/apt/trusted.gpg.d/debian.gpg

* suppression d'une clef
- name: Remove a Apt specific signing key, leading 0x is valid  apt_key:    id: 0x9FED2BCBDCD29CDF762678CBAED4B06F473041FA    state: absent

linefile

ANSIBLE : Modules LINEINFILE


Documentation : * https://docs.ansible.com/ansible/2.5/modules/lineinfile_module.html
PARAMETRES :
* attributes
* backrefs : pour utiliser des captures via regexp
* backup : réalise un backup avant modification
* create : si le fichier n'existe pas il est créé (default no)
* firstmatch : avec insertafter ou insertbefore s'exécute via la première occurence
* group : groupe propriétaire du fichier
* insertafter : insertion après la ligne recherché (default EOF > regex sans backrefs)
* insertbefore : idem after > mais avant la ligne
* line : ligne à ajouter ou remplacer (éventuellement avec la capture)
* mode : permissions (0755 ou u+rwx,g+rx,o+rx)
* owner : propriétaire du fichier
* path : chemin du fichier
* regexp : expression régulière permettant de rechercher la ligne (et éventuellement faire un capture)
* state : la ligne doit être présente/modifiée ou supprimée
* validate : commande de validation de la ligne

exemples 2

avec regexp sous condition:


- name: change admin user
  lineinfile:
    path: /etc/grafana/grafana.ini
    regexp: "{{ item.before }}"
    line: "{{ item.after }}"
  with_items:
  - { before: "^;admin_user = admin", after: "admin_user = {{ grafana_admin_user }}"}
  - { before: "^;admin_password = admin", after: "admin_password = {{ grafana_admin_password }}"}

ANSIBLE : Modules LINEINFILE


* cas le plus simple mais le moins courant : ajout d'une ligne

```
  - name: lineinfile
    lineinfile: 
      dest: /tmp/test.conf 
      line: "test"
      state: present
      create: True
```


Rq: si changement de line > nlle ligne




* recherche d'une ligne précise et modification

```
    lineinfile:
      dest: /tmp/test.conf
      line: "test 2"
      regexp: "^test$"
      state: present
      create: True
```


<br>


* modification avec capture

```
    lineinfile:
      dest: /tmp/test.conf
      line: 'je suis le nombre : \1'
      regexp: "^test ([0-2])$"
      backrefs: yes
      state: present
      create: True
```


Rq: si 2 runs attention


--------------------------------------------------------------------------------------


# ANSIBLE : Modules LINEINFILE



<br>


* commenter une ligne avec plus ou moins de précision


```
    lineinfile:
      dest: /tmp/test.conf
      line: '# \1'
      regexp: "(^je suis le nombre : [0-2])"
      backrefs: yes
      state: present
      create: True
```


<br>


* ajout avant une ligne

```
    lineinfile:
      dest: /tmp/test.conf
      line: "Ma nouvelle ligne"
      insertbefore: '# je suis le nombre : [0-2]'
      state: present
      create: True
```


Rq : idem after


--------------------------------------------------------------------------------------


# ANSIBLE : Modules LINEINFILE



<br>


* supprimer une ligne soit par regexp ou par line

```
  - name: lineinfile
    lineinfile:
      dest: /tmp/test.conf
      regexp: "^Ma nouvelle ligne"
      #line: "^Ma nouvelle ligne"
      state: absent
```


<br>


* avec backup avant modification


```
  - name: lineinfile
    lineinfile: 
      dest: /tmp/test.conf
      regexp: "^#"
      state: absent
      backup: yes
```


get-url

GET_URL

Documentation : * https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html


PARAMETRES : 
* attributes


* http_agent: spécifier un agent

Exemple27

                        
                          
                        
                        
                        
  - name: dest locale puis dispatch

                        
    get_url:

                        
      url: https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz

                        
      dest: /tmp/

                        
      validate_certs: no

                        
    delegate_to: localhost

                        
    run_once: yes

                        
  - name: dispatch

                        
    unarchive:

                        
      src: /tmp/node_exporter-1.0.1.linux-amd64.tar.gz

                        
      dest: /tmp/
                      

archive


UNARCHIVE

Documentation :* https://docs.ansible.com/ansible/2.5/modules/unarchive_module.html

Prérequis : unzip, tar


PARAMETRES :
* attributes : attributs du fichier
* copy : deprecated > utiliser remote_src
* creates : si un répertoire ou fichier exist la tâche n'est pas lancé
* decrypt : (default yes) déchiffrer les fichiers vaultés
* dest : destination des éléments
* exclude : fichier ou chemin à exclure de unarchive
* extra_opt : options complémentaires
* group : groupe propriétaire
* keep_newer : garder le plus récent
* list_files : retourne la liste des fichiers de l'archive
* mode : permissions (0755, u+rwx,g+rx,o+rx)
* remote_src : passer par le host ansible pour pousser récupérer l'archive
* src : no > copy du fichier vers les cibles, yes > download et pousse
* unsafe_writes : éviter les corruptions de fichiers
* validate_certs : dans le cas de https (default yes)

exemple : https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz

Exemple26


* copy de la machine ansible et dezip sur la machine cible:

  - name: test unarchive    unarchive:      src: /tmp/node_exporter-1.0.1.linux-amd64.tar.gz      dest: /home/oki/


* avec url utilisation de remote_src

  - name: test unarchive    unarchive:      src: https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz      dest: /home/oki/      remote_src: yes


- name: unarchive /get url
  hosts: all
  become: yes
  tasks:
  - name: installation de tar unzip
    apt:
      name: "{{ pkg}}"
      update_cache: yes
      state: present
      cache_valid_time: 3600
    vars: 
      pkg:
      - tar 
      - unzip
  - name: test unarchive local
    unarchive:
      src: /tmp/zip.tgz
      dest: /home/samik/
  - name: test unarchive via https
    unarchive:
      src: https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz
      dest: /home/samik/
      remote_src: yes

  - name: dest locale puis dispatch
    get_url:
      url: https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz
      dest: /tmp/
      validate_certs: no
    delegate_to: localhost
    run_once: yes
  - name: dispatch
    unarchive:
      src: /tmp/node_exporter-1.0.1.linux-amd64.tar.gz
      dest: /tmp/



autre fichier:

- name: test unarchive/geturl
  hosts: all
  become: yes
  tasks:
  - name: test unarchive
    unarchive:
      src: /tmp/node_exporter-1.0.1.linux-amd64.tar.gz
      dest: /home/samik/
  - name: test unarchive
    unarchive:
      src: https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz
      dest: /home/samik/
      remote_src: yes
  - name: start haproxy service
    get_url:
      url: https://downloads.apache.org/tomcat/tomcat-10/v10.0.0-M9/bin/apache-tomcat-10.0.0-M9.tar.gz
      dest: /opt/tomcat8.tar.gz
      mode: 0755
      checksum: sha512:547ae280792b8684d11154f678584d0c4eb5af645cc8145e04da6de6d115b7bca03122191e6447cdb3497b85357181ca3fd9716d8a2dbc86461cf28f3df3ee91
      group: samik
      owner: samik


systemd

Documentation :

Objectifs : gestion des services systemd et reload

Documentation : https://docs.ansible.com/ansible/2.5/modules/systemd_module.html


PARAMETRES :
* daemon_reexec :
* daemon_reload : exécute un reload pour prendre en compte les changements de conf systemd
* enabled : active le démarrage au boot du service
* force : écraser les liens symboliques systemd
* masked : masquer l'unité systemd
* name : nom du service systemd
* no_block : ne pas attendre la fin de l'opération pour continuer
* scope: systemd manager pour un user ou l'ensemble des users
* state : started /stopped / reloaded / restarted
* user : deprecated

Exemple25


* le plus simple :

- name: Make sure a service is running  systemd:    name: haproxy    state: started

* arrêt
- name: Make sure a service is running  systemd:    name: haproxy    state: started

* activation au boot
- name: Make sure a service is running  systemd:    name: haproxy    state: started    enabled: yes


* exécuter avant si nécessaire un daemon-reload
- name: Make sure a service is running  systemd:    name: haproxy    state: started    enabled: yes    daemon-reload: yes

* s'assurer sa présence dans le list-units
- name: Make sure a service is running  systemd:    name: haproxy    state: started    enabled: yes    daemon-reload: yes    masked: no

* juste faire un daemon-reload
- name: Make sure a service is running  systemd:    daemon-reload: yes

handlers

flush des handlers

* attention quand jouer le trigger ? par defaut, il est joué toujours en fin de playbook, le flush permet de resetter en cours de PB.

  - name: Flush handlers    meta: flush_handlers
- name: Check if need to restart  stat:     path: /var/run/reboot.pending  register: __need_reboot  changed_when: __need_reboot.stat.exists  notify: reboot_server

exemple24

- name: premier playbook
  hosts: all
  become: yes
  vars:
   nginx_port: 8888
  tasks:
  - name: install nginx
    apt:
      name: nginx,curl
      state: present
      cache_valid_time: 3600
      update_cache: yes
  - name: remove default file
    file:
      path: "{{ item }}"
      state: absent
    with_items:
    - "/etc/nginx/sites-available/default"
    - "/etc/nginx/sites-enabled/default"

  - name: install vhost
    template:
      src: default_vhost.conf.j2
      dest: /etc/nginx/sites-available/default_vhost.conf
      owner: root
      group: root
      mode: 0644
    notify: reload_nginx ajout du handlers
  - name: activate vhost
    file:
      src: /etc/nginx/sites-available/default_vhost.conf
      dest: /etc/nginx/sites-enabled/default_vhost.conf
      state: link
  - name: start nginx
    systemd:
      name: nginx
      state: started

  handlers:
  - name: reload_nginx
    systemd:
      name: nginx
      state: reloaded

template

permet de creer un modele à déployer, à inclure en début de fichier:

exemple au début du fichier

#{{ template_run_date }} - "{{ ansible_managed }}" via {{ template_uid }}@{{ template_host }}

Sortie

[samik@samik-centos-1 ~]$ ls /tmp
hello.txt  hello_paul.txt  hello_pierre.txt  hello_xavier.txt

[samik@samik-centos-1 ~]$ cat /tmp/hell*
#2020-10-13 11:15:01.882949 - "Ansible managed" via samik@Abacus

hello samik !!!
#2020-10-13 11:25:41.160516 - "Ansible managed" via samik@Abacus
Hello samik !!!
je suis paul
j'ai 22

#2020-10-13 11:25:43.860866 - "Ansible managed" via samik@Abacus
Hello samik !!!
je suis pierre
j'ai 25

#2020-10-13 11:25:37.609008 - "Ansible managed" via samik@Abacus
Hello samik !!!
je suis xavier
j'ai 40
- name: preparation local
  hosts: all
  vars:
    var1: "samik !!!"
    var2:
      - { nom: "xavier", age: "40" }
      - { nom: "paul", age: "22" }
      - { nom: "pierre", age: "25" }
  tasks:
  - name: template
    template:
      src: montemplate.txt.j2
      dest: "/tmp/hello_{{ item.nom }}.txt"
    with_items:
    - "{{ var2 }}"
#{{ template_run_date }} - "{{ ansible_managed }}" via {{ template_uid }}@{{ template_host }}
Hello {{ var1 }}
je suis {{ item.nom }}
j'ai {{ item.age }}

#{{ template_run_date }} - "{{ ansible_managed }}" via {{ template_uid }}@{{{
     template_host }}
  2 Hello {{ var1 }}
  3 {% for personne in var2 %}
  4     je suis {{ personne.nom }}
  5     j'ai {{ personne.age }}
  6 {% endfor %}
  7

Fetch

permet de récupérer un fichier sur hote distant, ici test avec /etc/host

PB

- name: copie
  hosts: all
  become: yes
  tasks:
  - name: fetch
    fetch:
      src: /etc/hosts
      dest: /tmp/hosts_{{ ansible_hostname }}.txt
#      flat: yes

Exemple22

Avec le "flat":

samik@Abacus:~/ansible_dir(master⚡) » tree /tmp
/tmp
├── hosts_samik-centos-1.txt
└── hosts_samik-centos-2.txt

sans le "flat":

samik@Abacus:~/ansible_dir(master⚡) » tree /tmp
/tmp
├── hosts_samik-centos-1.txt
│   └── 172.17.0.2
│       └── etc
│           └── hosts
└── hosts_samik-centos-2.txt
    └── 172.17.0.3
        └── etc
            └── hosts

Exemples avec nginx

- name: preparation local
  connection: local
  hosts: localhost
  become: yes
  tasks:
  - name: install nginx
    apt:
      name: nginx
      state: present
  - name: clean
    file:
      path: "{{ item }}"
      state: absent
    with_fileglob:
    - /var/www/html/*.html
  - name: permission
    file:
      path: /var/www/html
      owner: samik
      recurse: yes
      state: directory

- name: recup des hosts
  become: yes
  hosts: all
  tasks:
  - name: fetch
    fetch:
      src: /etc/hosts
      dest: /var/www/html/hosts_{{ ansible_hostname }}.txt
      flat: yes

COPY

PARAMETRES :
* attributes : attributs du fichier
* backup : réalise une copie datée avant la copie
* checksum : vérification du ficheir via un hash
* content : dans le cas ou la source n'est pas un fichier mais une variable ou un string
* decrypt : déchiffre les fichiers si ils sont vaultés (défaut : yes)
* dest : localisation du fichier sur les serveurs target
* dicrectory_mode : dans le cas d'une recopie en mode récursif
* follow : indiquer le filesytème dans la destination
* force : remplace le fichier si il est différent de la source
* group : group propriétaire
* local_follow : indique le FS  dans la source
* mode : permissions du fichier ou du répertoire (0755, u+rwx,g+rx,o+rx)
* owner : user propriétiare
* remote_src : no > copie du master vers la target, yes > copie de la target vers la target
* src : localisation de la source* attention : roles / dir files / .
* unsafe_writes : éviter la corruption de fichier
validate : commande jouée pour valider le fichier avant de le copier (le fichier se situe %s)

Exemple20

- name: copie
  hosts: all
  become: yes
  tasks:
  - name: copy
    copy:
      src: "{{ item }}"
      dest: /tmp/
      backup: yes
    with_fileglob:
    - samik*

Exemple21

- name: copie
  hosts: all
  become: yes
  tasks:
  - name: copy
    copy:
      content: |
         Salut
         la team !!
         on est sur {{ ansible_hostname }}
      dest: /tmp/hello.txt

crée le fichier mais ne le modifie pas s'il existe ! un exemple avec sudoers
utilisation de validate:

   - name: Add devops user to the sudoers
     copy:
       dest: "/etc/sudoers.d/devops"
       content: "devops ALL=(ALL)  NOPASSWD: ALL"
       owner: root
       group: root
       mode: 0600
       validate: /usr/sbin/visudo -cf %s

Exemple17

- name: copie
  hosts: all
  become: yes
  tasks:
#  - name: copy
#    copy:
#      src: test.txt
#      dest: /tmp/samik.txt
#      force: no
  - name: copy
    copy:
      src: /tmp/
      dest: /tmp/

Exemple18

- name: copie
  hosts: all
  become: yes
  tasks:
#  - name: copy
#    copy:
#      src: test.txt
#      dest: /tmp/samik.txt
#      force: no
#  - name: copy
#    copy:
#      src: /tmp/
#      dest: /tmp/
   - name: copy
     copy:
      dest: /home/samik
      src: /tmp/samik
      remote_src: yes

Exemple19

* combinaison avec with_items

                            vars:    mesfichiers:      - { source: "xavki1.txt", destination: "/tmp/{{ ansible_hostname }}_xavki1.txt", permission: "0755" }      - { source: "xavki2.txt", destination: "/home/oki/{{ ansible_hostname }}_xavki2.txt", permission: "0644" }  tasks:  - name: copy    copy:      src: "{{ item.source }}"      dest: "{{ item.destination }}"      mode: "{{ item.permission }}"    with_items: "{{ mesfichiers }}"                        

Delegate, run_once, local

Exemple16

Objectifs : gérer les run locaux ou déléguer des tâches* primaire/secondaire


* delegate_to : déléguer une tache à un autre serveur identifié

- name: premier playbook  hosts: all  tasks:  - name: création de fichier    file:      state: touch      path: /tmp/xavki.txt    delegate_to: localhost

Rq : attention au nombre d'itération si plusieurs serveurs


* quelles variables ?

- name: premier playbook  hosts: all  tasks:  - name: debug    debug:      var: var1  - name: debug    debug:      var: var1    delegate_to: localhost

ssh

PARAMETRES : openssh_keypair

* attibutes : attributs des fichiers (non supprimable etc)
* comment : commentaire de la clef
* force : regénère la clef si elle existe déjà
* group : group propriétaire des fichiers
* mode : permisssions (cf file, 0600, u+rw)
* owner : propirétaire
* path : localisation des clefs (attention sécurité de la clef privée)
* regenerate : never / fail / partial_idempotence (si non conforme) / full_idempotence (et si non lisible) / always
* size : taille de la clef
* state : present/absent
* type : rsa / dsa / rsa1 / ecdsa / ed25519
* unsafe_writes : prévenir les corruptions de fichiers

Rq : si password / clef cassé > force : yes

exemple15

- name: ajout de clef ssh et de user
  hosts: all
  tasks:
  - name: generate SSH key"
    openssh_keypair:
      path: /tmp/devops
      type: rsa
      size: 4096
      mode: 0600
      state: present
      force: no
    run_once: yes
    delegate_to: localhost
  - name: création du group sudo
    group:
      name: sudo
    become: yes
  - name: création du user devops
    user:
      name: devops
      shell: /bin/bash
      groups: sudo
      append: yes
      password: "{{ 'password' | password_hash('sha512') }}"
    become: yes
  - name: Add devops user to the sudoers
    copy:
      dest: "/etc/sudoers.d/devops"
      content: "devops  ALL=(ALL)  NOPASSWD: ALL"
    become: yes
  - name: Deploy SSH Key
    authorized_key:
      user: devops
      key: "{{ lookup('file', '/tmp/devops.pub') }}"
      state: present
    become: yes

Reboot

l'inventory:


ansible-inventory -i VCS_inventory.yml --graph             2 ↵
@all:
  |--@centos:
  |  |--192.168.100.101
  |  |--192.168.100.102
  |--@ungrouped:

exemple14

- name: ajout de patch & reboot
  hosts: centos
  become: yes
  remote_user: vagrant
  tasks:
  - name: Upgrade all packages, excluding kernel & foo related packages
    yum:
      name: '*'
      update_cache: yes
      state: latest
      exclude: kernel*,foo*
  - name: vérification à partir du fichier reboot_required
    register: reboot_required_file
    stat:
      path: /var/run/reboot-required


  - name: lancement du reboot avec reboot
    reboot:
      msg: "Reboot via ansible"
      connect_timeout: 5
      reboot_timeout: 300
      pre_reboot_delay: 0
      post_reboot_delay: 10
      test_command: uptime
    when: reboot_required_file.stat.exists

exemple13

- name: ajout de patch & reboot
  hosts: centos
  become: yes
  remote_user: vagrant
  tasks:
  - name: create file
    file:
      path: /tmp/samik.txt
      state: touch
  - name: test
    stat:
      path: /tmp/samik.txt
    register: __file_exist


  - name: lancement du reboot avec reboot
    reboot:
      msg: "Reboot via ansible"
      connect_timeout: 5
      reboot_timeout: 300
      pre_reboot_delay: 0
      post_reboot_delay: 10
      test_command: uptime
    when: __file_exist.stat.exists
  - name: create file2
    file:
      path: /tmp/reboot_ok.txt
      state: touch

yum

exemple3

ici, traitement des 2 type d'OS : debian et Centos, l'inventory:



ansible-inventory -i 00_inventory.yml --graph
@all:
  |--@centos:
  |  |--172.17.0.7
  |  |--172.17.0.8
  |--@debian:
  |  |--172.17.0.2
  |  |--172.17.0.3
  |  |--172.17.0.4
  |  |--172.17.0.5
  |  |--172.17.0.6
  |--@gp1:
  |  |--172.17.0.2
  |--@ungrouped:

- name: ajout de pkg dans les cont
  hosts: debian
  become: yes
  tasks:
#  - name: tree
#    apt:
#      name: tree
#      autoclean: yes
#      update_cache: yes
#      cache_valid_time: 3600
#      state: latest
  - name: multi pack
    apt:
      name: "{{ packs }}"
      autoclean: yes
      update_cache: yes
      cache_valid_time: 3600
      state: latest
    vars:
      packs:
      - zsh
      - openssh-server
- name: ajout sur centos
  hosts: centos
  become: yes
  tasks:
  - name: multi pack
    yum:
      name: "{{ packs }}"
      update_cache: yes
      state: latest
    vars:
      packs:
      - zsh
      - tree

exemple12

- name: ajout de pkg dans les cont
  hosts: all
  become: yes
  tasks:
  - name: tree
    apt:
      name: tree
      autoclean: yes
      update_cache: yes
      cache_valid_time: 60
      state: latest
  - name: multi pack
    apt:
      name: "{{ packs }}"
      autoclean: yes
      update_cache: yes
      cache_valid_time: 60
      state: latest
    vars:
      packs:
      - zsh
      - openssh-server

with_items

Conditionner les taches d'Ansible


A noter: le dico est dans group vars:

 » tree
.
├── 00_inventory.yml
├── ansible_dir
│   ├── 00_inventory.yml
│   ├── group_vars
│   └── host_vars
├── group_vars
│   ├── all.yml
│   └── common
│       └── params.yml


» cat group_vars/all.yml
mondico:
- { dir: "xavki1", file: "fichierA"}
- { dir: "xavki2", file: "fichierB"}
- { dir: "xavki3", file: "fichierC"}
- { dir: "xavki4", file: "fichierD"}

Exemple11

ici, on créé un rep aves comme item le nom du serveur appartenant à gp1:
ansible-inventory -i 00_inventory.yml --graph
@all:
  |--@gp1:
  |  |--172.17.0.2
  |--@ungrouped:
  |  |--172.17.0.3
  |  |--172.17.0.4
  |  |--172.17.0.5
  |  |--172.17.0.6

- name: pb avec boucle
  hosts: all
  become: yes
  tasks:
#  - name: ajout de tree
 #   apt:
  #    name: tree
   #   state: present
  - name: modification shell  de samik
    user:
      name: samik
      state: present
      shell: /bin/bash
  - name: boucle création de répertoire
    file:
      path: /tmp/samik/{{ item }}
      state: directory
      recurse: yes
    with_inventory_hostnames:
    - gp1

Exemple10

ANSIBLE : With Item et boucles


* version condensée
  vars:    fichiers:    - { dir: "xavki1", file: "fichierA"}    - { dir: "xavki2", file: "fichierB"}    - { dir: "xavki3", file: "fichierC"}    - { dir: "xavki4", file: "fichierD"}  tasks:  - name: création de fichiers    file:      path: /tmp/xavki/{{ item.dir }}/{{ item.file }}      state: touch    with_items:    - "{{ fichiers }}"

* parcourir une liste de machines de l'inventaire
 with_items:    - "{{ groups['all'] }}"

* en version plus simple :
  - name: création de fichiers    file:      path: /tmp/{{ item }}      state: touch    with_inventory_hostnames:    - all

exemple9


- name: pb avec boucle
  hosts: all
  become: yes
  tasks:
  - name: ajout de tree
    apt:
      name: tree
      state: present
  - name: modification shell  de samik
    user:
      name: samik
      state: present
      shell: /bin/bash
  - name: boucle création de répertoire
    file:
      path: /tmp/samik/{{ item }}
      state: directory
      recurse: yes
    with_items:
    - samik1
    - samik2
    - samik3
    - samik4

  - name: création de fichiers
    file:
      path: /tmp/xavki/{{ item.dir }}/{{ item.file }}
      state: touch
    with_items: "{{ mondico }}"

register & stat

exemple7

* récupération d'une clef

  - name: debug    debug:      var: __fichier_xavki.stat.exists

* utilisation conditionnnel
  - name: création répertoire xavki    file:      path: /tmp/xavki      state: directory    when: __fichier_xavki.stat.exists

* exemple:
  tasks:  - name: création d'un fichier    file:      path: /tmp/xavki.txt      state: touch      owner: root    when: xavki_file is defined  - name: check avec stat    stat:      path: /tmp/xavki.txt    register: __fichier_xavki  - name: debug    debug:      var: __fichier_xavki.stat.exists  - name: création répertoire xavki    file:      path: /tmp/xavki      state: directory    when: __fichier_xavki.stat.exists and xavki_file is defined

exemple8

playbook

 cat   playbook.yml

- name: abacus premier  Playbook
  hosts: all
  become: yes
  tasks:
  - name: creation du fichier
    file:
      path: /tmp/samik.txt
      state: touch
      mode: 0755
  - name: test de stat
    stat:
      path: /tmp/samik.txt
    register: __outdestat
  - name : affiche stat complet
    debug:
      var: __outdestat
  - name : affiche stat
    debug:
      var: __outdestat.stat.exists
  - name: création répertoire samik
    file:
     path: /tmp/samik
     state: directory
    when: __outdestat.stat.exists 

.stat.exists correspond au champ que l'on veut extraire pour la condition, cf le fichier de sortie.

sortie

ansible-playbook -i 00_inventory.yml   playbook.yml



PLAY [abacus premier  Playbook] ***********************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************
ok: [172.17.0.4]
ok: [172.17.0.6]
ok: [172.17.0.3]
ok: [172.17.0.2]
ok: [172.17.0.5]

TASK [creation du fichier] ****************************************************************************************************
changed: [172.17.0.6]
changed: [172.17.0.4]
changed: [172.17.0.2]
changed: [172.17.0.3]
changed: [172.17.0.5]

TASK [test de stat] ***********************************************************************************************************
ok: [172.17.0.6]
ok: [172.17.0.5]
ok: [172.17.0.2]
ok: [172.17.0.3]
ok: [172.17.0.4]

TASK [affiche stat complet] ***************************************************************************************************
ok: [172.17.0.6] => {
    "__outdestat": {
        "changed": false,
        "...


        ...
            "xusr": true
        }
    }
}
ok: [172.17.0.2] => {
    "__outdestat": {
        "changed": false,
        "failed": false,
        "stat": {
            "atime": 1602086939.4785962,
            "attr_flags": "",
            "attributes": [],
            "block_size": 4096,
            "blocks": 0,
            "charset": "unknown",
            "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "ctime": 1602086939.4785962,
            "dev": 48,
            "device_type": 0,
            "executable": true,
            "exists": true,
            "gid": 0,
            "gr_name": "root",
            "inode": 288270,
            "isblk": false,
            "ischr": false,
            "isdir": false,
            "isfifo": false,
            "isgid": false,
            "islnk": false,
            "isreg": true,
            "issock": false,
            "isuid": false,
            "mimetype": "unknown",
            "mode": "0755",
            "mtime": 1602086939.4785962,
            "nlink": 1,
            "path": "/tmp/samik.txt",
            "pw_name": "root",
            "readable": true,
            "rgrp": true,
            "roth": true,
            "rusr": true,
            "size": 0,
            "uid": 0,
            "version": null,
            "wgrp": false,
            "woth": false,
            "writeable": true,
            "wusr": true,
            "xgrp": true,
            "xoth": true,
            "xusr": true
        }
    }
}

TASK [affiche stat] ***********************************************************************************************************
ok: [172.17.0.6] => {
    "__outdestat.stat.exists": true
}
ok: [172.17.0.5] => {
    "__outdestat.stat.exists": true
}
ok: [172.17.0.4] => {
    "__outdestat.stat.exists": true
}
ok: [172.17.0.3] => {
    "__outdestat.stat.exists": true
}
ok: [172.17.0.2] => {
    "__outdestat.stat.exists": true
}

TASK [création répertoire samik] **********************************************************************************************
ok: [172.17.0.6]
ok: [172.17.0.4]
ok: [172.17.0.5]
ok: [172.17.0.3]
ok: [172.17.0.2]

PLAY RECAP ********************************************************************************************************************
172.17.0.2                 : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.17.0.3                 : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.17.0.4                 : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.17.0.5                 : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.17.0.6                 : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

exemple6

* création d'un fichier

  - name: création d'un fichier    file:      path: /tmp/xavki.txt      state: touch      owner: xavki

* utilisation de stat
  - name: check avec stat    stat:      path: /tmp/xavki.txt

* récupération de la variable
  - name: check avec stat    stat:      path: /tmp/xavki.txt    register: __fichier_xavki_exist  - name: debug    debug:      var: __fichier_xavki

user

Equivalence : useradd/adduser/userdel/deluser/luseradd

exemple5

- name: création de xavki
  user:
    name: xavki
    state: present
    uid: 1200
    groups: sudo
    append: yes
    generate_ssh_key: yes
    password: "{{ 'password' | password_hash('sha512') }}"

- name: création du user xavki
  user:
    name: xavki
    state: present
    generate_ssh_key: yes
    uid: 1200
    groups: sudo
    append: yes
    password: "{{ 'password' | password_hash('sha512') }}"
  register: mavar
- name: debug
    debug:
      msg: "{{ mavar }}"

- name: suppression du user xavki
  user:
    name: xavki
    state: absent

examples4

* création d'un user avec password

- name: création de xavki  user:    name: xavki    state: present    password: "{{ 'password' | password_hash('sha512') }}"   

* ajout au groupe sudo
- name: création de xavki  user:    name: xavki    state: present    groups: sudo    append: yes    password: "{{ 'password' | password_hash('sha512') }}"   

file

exemple3:

* touch avec idempotence

  - name: touch idempotent    file:      path: /tmp/xavki.txt      state: touch      mode: 0755      modification_time: preserve      access_time: preserve

* à l'inverse
  - name: touch sans idempotence    file:      path: /tmp/xavki/1/2/3      state: touch      mode: 0755      modification_time: now      access_time: now

exemple2: file


* modification du groupe et des droits (RWX-RX-RX - 0755) | stat

- name: création du répertoire /tmp/xavki  file:    path: /tmp/xavki/    state: directory    owner: root    group: root    mode: 0755  become: yes

* récursivité (pour directory uniquement
  - name: création du répertoire /tmp/xavki    file:      path: /tmp/xavki/1/2/3/4      recurse: yes      state: directory      owner: root      group: root      mode: 0755

  - name: création du répertoire /tmp/xavki    file:      path: /tmp/xavki/1/2/3/4/fichier.txt      state: touch      owner: root      group: root      mode: 0755

suite...

* lien symbolique = lien vers fichier (diff avec hardlink = lien vers inode)

  - name: création du répertoire /tmp/xavki    file:      src: /tmp/xavki/1/2/3/4/      dest: /tmp/symlink      state: link  #hard      owner: root      group: root      mode: 0755

Rq: idempotence


* suppression de fichier

  - name: dir sans idempotence    file:      path: /tmp/xavki.txt      state: absent

* suppression de répertoire récursive
  - name: dir sans idempotence    file:      path: /tmp/xavki/      state: absent

structure

l'indentation est importante (python oblige !)

-name: titre de l'action

hosts: all

-become: yes

 - name: abacus premier  Playbook
   2   │   hosts: all
   3   │   become: yes

tasks:

exemples

- name: Mon Playbook !!  hosts: all  remote_user: vagrant  become_user: yes  tasks:  - name: je debug    debug:      msg: "{{ var1 }}"

Exécution

ansible-playbook exemple_playbook.yml


PLAY [copie du fichier master.gitconfig] *************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************
[WARNING]: Platform linux on host kaisenlinux is using the discovered Python interpreter at /usr/bin/python, but future
installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
ok: [kaisenlinux]
ok: [localhost]

TASK [copy] ******************************************************************************************************************
changed: [kaisenlinux]
ok: [localhost]

PLAY [mise à jour des packets désirés brew] **********************************************************************************

TASK [Gathering Facts] *******************************************************************************************************
[WARNING]: Platform linux on host abacus is using the discovered Python interpreter at /usr/bin/python, but future
installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
ok: [abacus]
ok: [kaisenlinux]
fatal: [nexus]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host nexus port 2222: Operation timed out", "unreachable": true}
fatal: [ipadkris]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host ipadkris port 22: Operation timed out", "unreachable": true}

TASK [homebrew] **************************************************************************************************************
fatal: [abacus]: FAILED! => {"changed": false, "msg": "Failed to find required executable brew in paths: /usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/sbin:/usr/sbin:/usr/local/sbin"}
fatal: [kaisenlinux]: FAILED! => {"changed": false, "msg": "Failed to find required executable brew in paths: /usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/sbin:/usr/sbin:/usr/local/sbin"}

PLAY RECAP *******************************************************************************************************************
abacus                     : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
ipadkris                   : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0
kaisenlinux                : ok=3    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
nexus                      : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0

CLI
gather facts

ansible all -m gather_facts --tree /tmp/facts

# Display facts from all hosts and store them indexed by I(hostname) at C(/tmp/facts).


exemple

ansible all -m gather_facts -a "filter=ansible_distribution"  |head


[WARNING]: Platform linux on host node5 is using the discovered Python interpreter at /usr/bin/python3.7, but future
installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
node5 | SUCCESS => {
    "ansible_facts": {
        "ansible_distribution": "Debian",
        "discovered_interpreter_python": "/usr/bin/python3.7"
    },
    "changed": false,
    "deprecations": []
}

ansible -i "node2," all -m gather_facts -a "filter=ansible_distribution*"

fetch

récupérer un fichier

ansible -i "node2," all -m fetch -a 'src=/tmp/titi.txt dest=xavki.txt flat=yes'

flat = fichier plat


copy

idem scp

ansible -i "node2," all -m copy -a 'src=toto.txt dest=/tmp/titi.txt'

service

ansible -i "node2," all -b -m service -a 'name=nginx state=stopped'

apt

ansible -i "node2," all -b -m apt -a 'name=nginx state=latest'

raw

ansible -i 00_inventory.yml centos -b -m raw -a "yum install python38 -y "

utile lorsque python n'est pas installé sur le serveur/conteneur

ansible -i "node2," all -u vagrant -b -K -m raw -a "apt install -y git"

debug

ansible all -b -e "var1=xavki" -m debug -a 'msg={{ var1 }}'

détail:

-i "node2," = dans le groupe All , prendre en compte le node2 seul
-b = "become" = élévation des droits
-e = passage de la variable en cli
-m = le module utilisé (ici debug)
-a = l'argument associé au module
shell

ansible -i "node2," all -u vagrant -m shell -a "ps aux | grep vagrant | wc -l" --one-line

detail:

-m = module shell 
-a = argument "ps aux | grep vagrant | wc -l" 
--one-line = sortie sur une ligne
command

ansible -i "node2," all -u vagrant -m command -a uptime

ping

ansible all -m ping

(test simple de fonctionnement)

imackris | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname imackris: nodename nor servname provided, or not known",
    "unreachable": true
}
[WARNING]: Platform linux on host abacus is using the discovered Python interpreter at /usr/bin/python,
but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
abacus | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
[WARNING]: Platform linux on host kaisenlinux is using the discovered Python interpreter at
/usr/bin/python, but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
kaisenlinux | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
[WARNING]: Platform darwin on host imacpat is using the discovered Python interpreter at
/usr/bin/python, but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
imacpat | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
mbp | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: connect to host mbp port 22: Operation timed out",
    "unreachable": true
}
nexus | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: connect to host nexus port 2222: Operation timed out",
    "unreachable": true
}
ipadkris | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: ssh: connect to host ipadkris port 22: Operation timed out",
    "unreachable": true
}

Exemple

ansible all -i "localhost," -m debug -a "msg='Hello Ansible'"

-i

inventory

fichier inventaire

defini les nodes impactés,
ex:
[gp_patricia]
mbp
imacpat
[gp_kris]
kaisenlinux
abacus
nexus
ipadkris


Fichiers de configuration

plusieurs lieux possible, défini par ordre de priorité


* exemple :
inventory       = /etc/ansible/hostsforks           = 5sudo_user       = rootask_sudo_pass   = Trueask_pass        = Truegathering       = implicitgather_subset   = allroles_path      = /etc/ansible/roleslog_path        = /var/log/ansible.logvault_password_file = /path/to/vault_password_filefact_caching_connection =/tmppipelining = False
Commande
ansible-config
ansible-config
usage: ansible-config [-h] [--version] [-v] {list,dump,view} ...
ansible-config: error: the following arguments are required: action

usage: ansible-config [-h] [--version] [-v] {list,dump,view} ...

View ansible configuration.

positional arguments:
  {list,dump,view}
    list            Print all config options
    dump            Dump configuration
    view            View configuration file

optional arguments:
  --version         show program's version number, config file location, configured module search path, module location,
                    executable location and exit
  -h, --help        show this help message and exit
  -v, --verbose     verbose mode (-vvv for more, -vvvv to enable connection debugging)

view

ansible-config view|head -20

# Example config file for ansible -- https://ansible.com/
# =======================================================

# Nearly all parameters can be overridden in ansible-playbook
# or with command line flags. Ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory, or /etc/ansible/ansible.cfg, whichever it
# finds first

# For a full list of available options, run ansible-config list or see the
# documentation: https://docs.ansible.com/ansible/latest/reference_appendices/config.html.

[defaults]
inventory       = $HOME/hosts
#library         = ~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
#module_utils    = ~/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils
remote_tmp      = .ansible/tmp
local_tmp       = ~/.ansible/tmp
#forks           = 5
#poll_interval   = 0.001

depend de l'emplacement

astuce pour localiser le fichier config pris en compte:


ansible -v imac -m ping


Using /Users/samik/.ansible.cfg as config file
...

list

ansible-config list|head -20

ACTION_WARNINGS:
  default: true
  description:
  - By default Ansible will issue a warning when received from a task action (module
    or action plugin)
  - These warnings can be silenced by adjusting this setting to False.
  env:
  - name: ANSIBLE_ACTION_WARNINGS
  ini:
  - key: action_warnings
    section: defaults
  name: Toggle action warnings
  type: boolean
  version_added: '2.5'
AGNOSTIC_BECOME_PROMPT:
  default: true
  description: Display an agnostic become prompt instead of displaying a prompt containing
    the command line supplied become method
  env:
  - name: ANSIBLE_AGNOSTIC_BECOME_PROMPT
lieu du playbook
ansible.cfg
/etc/ansible
defini par variable
ANSIBLE_CONFIG
dossier de base USER
~/.ansible/ansible.cfg

.ansible

ll -R $HOME/.ansible*
-rw-r--r--  1 samik  staff    19K  3 mai 11:31 /Users/samik/.ansible.cfg

/Users/samik/.ansible:
total 0
drwx------  2 samik  staff    64B 12 aoû 18:30 cp
drwx------  2 samik  staff    64B 12 aoû 18:29 tmp

/Users/samik/.ansible/cp:

/Users/samik/.ansible/tmp:

.ansible.cfg

egrep -v "#|^$" /Users/samik/.ansible.cfg
[defaults]
inventory       = $HOME/hosts
remote_tmp      = .ansible/tmp
local_tmp       = ~/.ansible/tmp
nocows = 1
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[sudo_become_plugin]
[selinux]
[colors]
[diff]

head -20 /Users/samik/.ansible.cfg
# Example config file for ansible -- https://ansible.com/
# =======================================================

# Nearly all parameters can be overridden in ansible-playbook
# or with command line flags. Ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory, or /etc/ansible/ansible.cfg, whichever it
# finds first

# For a full list of available options, run ansible-config list or see the
# documentation: https://docs.ansible.com/ansible/latest/reference_appendices/config.html.

[defaults]
inventory       = $HOME/hosts
#library         = ~/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
#module_utils    = ~/.ansible/plugins/module_utils:/usr/share/ansible/plugins/module_utils
remote_tmp      = .ansible/tmp
local_tmp       = ~/.ansible/tmp
#forks           = 5
#poll_interval   = 0.001