Разные примеры

:!: Inventory

hosts.yml

all:
  children:
    app_myApp:
      hosts:
        host_myApp_master:
          ansible_host: 10.10.40.204

hosts/myApp

---
myApp_path: "/tank/secure/test_myApp/"
myApp_appname: "test_myApp.jar"

group/all.yml

#ansible_connection: winrm
#ansible_port: 5985
#ansible_winrm_transport: basic
#ansible_winrm_server_cert_validation: ignore

ansible_connection: ssh
ansible_ssh_port: 22

ansible_user: ansible
ansible_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  31323664336536.......

nexus_base_url: 'https://mysite.ru/repository'
nexus_username: jenkins
nexus_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  3534534534......
:!: CICD Работа с приложением

Backup.yml

---
- name: "Удаляем старый архив"
  file:
    path: '{{ myService_path }}/../{{ myService_appname }}.tar.gz'
    state: absent
  register: remove_backup

- name: "Архивируем папку приложения"
  shell:
    cmd: 'tar -czvf {{ myService_path }}/../{{ myService_appname }}.tar.gz --exclude={logs,properties} -C {{ myService_path }} . && echo OK'
    warn: false
  register: result
  failed_when: '"OK" not in result.stdout'
  changed_when: '"OK" in result.stdout'
  when: remove_backup is not failed
  any_errors_fatal: true

Stop_service.yml

---
- name: "Получаем информацию о сервисах в системе"
  ansible.builtin.service_facts:

- name: "Останавливаем myService.service если он есть в ОС"
  systemd:
    name: 'myService.service'
    state: stopped
  register: myServiceInfo
  until: myServiceInfo.state == "stopped"
  retries: 5
  delay: 10
  when: "'myService.service' in services"

Download.yml

---
- name: "Скачиваем jar из Nexus"
  maven_artifact:
    group_id: 'com.gmware.applications'
    artifact_id: 'myService_group'
    version: '{{ myService_version | default(omit) }}'
    repository_url: '{{ "%s/myService-snapshots" | format(nexus_base_url) }}'
    username: '{{ nexus_username }}'
    password: '{{ nexus_password }}'
    dest: '{{ "%s/%s.jar" | format(myService_path, myService_appname) }}'
    owner: '{{ myService_user }}'
    group: '{{ myService_group }}'
    mode: '640'
    verify_checksum: 'always'

handler/main.yml

---
- name: "Запуск службы myService"
  systemd:
    name: myService
    state: restarted
    enabled: true
    daemon_reload: yes
  listen: "start_restart_myService"
:!: Вариант с откатом

Restart_and_check.yml
При запуске скрипта лучше сменить директорию, потом запустить, т.к. могут быть вские косяки из за системного каталога

---
- name: "Рестарт приложения"
  win_shell: |
    cd {{ myapp_path }}
    ./restartMyApp.ps1
  async: 5
  ignore_errors: yes
  register: start_app
  failed_when: start_app.started != 1

- name: "Ожидаем 5 сек"
  pause:
    seconds: 5

- name: "Проверяем запущен ли процесс"
  win_shell: "Get-Process -Id $(cat {{ myapp_path }}MyApp.pid) -ErrorAction SilentlyContinue | Format-Table -Property ProcessName
  register: check_pid
  failed_when: check_pid.rc < 0
 
- block:
    - name: "Процесс отсутствует, откат обновления"
      import_tasks: 70-rollback.yml
 
  when: check_pid.stdout == ''
---
- name: "Восстановливаем из бекапа"
  shell:
    cmd: "tar -xzvf {{ myService_path }}/backups/{{ myService_appname }}.tar.gz -C {{ myService_path }} && echo OK"
    warn: false
  register: result
  changed_when: '"OK" in result.stdout'
  failed_when: '"OK" not in result.stdout'

Бекап на винде

---
- name: "Создаем бекап"
  win_shell: |
    "Get-ChildItem -Path {{ myService_path }} -Exclude @('backups', 'logs') | 
    Compress-Archive -Force -DestinationPath {{ myService_path }}'backups\\prev_version.zip'"
:!: Виндовый пример

плейбук:

---
- hosts: myapp_group
  gather_facts: no
  become: yes
  become_method: runas
  become_user: "{{ ansible_user }}"
  roles:
    - myapp_deploy

main

---
- name: "Подготовка окружения"
  import_tasks: 10-prepare_host.yml

- name: "Создаем бекап"
  import_tasks: 20-backup.yml

- name: "Скачиваем новый jar-файл"
  import_tasks: 30-download.yml

- name: "Обновляем конфиги"
  import_tasks: 40-config.yml

- name: "Перезапускаем приложения"
  import_tasks: 50-restart_and_check.yml

- block:
    - name: "Разворачиваем бекап"
      win_shell: "Expand-Archive -Force -LiteralPath {{ myapp_path }}'backups\\prev_version.zip' -DestinationPath {{ myapp_path }}"

    - name: "Перезапускаем приложения"
      import_tasks: 50-restart_and_check.yml
  when: not process_running

prepare

---
- name: "Создание директорий"
  win_file:
    path: '{{ item }}'
    state: directory
  loop:
    - '{{ myapp_path }}'
    - '{{ myapp_path }}logs'
    - '{{ myapp_path }}backups'
    - '{{ myapp_path }}conf'

backup

---
- name: "Создаем бекап"
  win_shell: "Get-ChildItem -Path {{ myapp_path }} -Exclude @('backups', 'logs') |
    Compress-Archive -Force -DestinationPath {{ myapp_path }}backups\\prev_version.zip"

download

---

- name: "Скачиваем jar из Nexus"
  maven_artifact:
    group_id: 'ru.myapp'
    artifact_id: 'myapp_id'
    version: '{{ myapp_version | default(omit) }}'
    repository_url: '{{ "%s/myapp-snapshots" | format(nexs_base_url) }}'
    username: '{{ nexs_username }}'
    password: '{{ nexs_password }}'
    dest: '{{ myapp_name }}'
    verify_checksum: 'always'
  delegate_to: localhost

- name: "Копируем на целевой хост"
  copy:
    src: '{{ myapp_name }}'
    dest: '{{ "%s/%s" | format(myapp_path, myapp_name) }}'

configs

---
- name: "Скрипты запуска"
  win_template:
    src: '{{ item }}.j2'
    dest: '{{ "%s%s" | format(myapp_path, item) }}'
  loop:
    - start.ps1
    - restart.ps1

- name: "Конфигурация приложения"
  win_template:
    src: '{{ item }}.j2'
    dest: '{{ "%s\conf\%s" | format(myapp_path, item) }}'
  loop:
    - config.toml

- name: "Сертификаты"
  win_copy:
    src: '{{ item }}'
    dest: '{{ "%s%s" | format(myapp_path, item) }}'
  loop:
    - cacerts
    - cert.jks
    - _certs

restart and check

---
- name: "Перезапускаем приложение"
  win_shell: "{{ myapp_path }}restartmyApp.ps1"
  async: 5
  register: start_app
  failed_when: start_app.started != 1
  ignore_errors: true

- name: "Пауза перед проверкой состояния"
  pause:
    seconds: 10

- name: "Инициализация переменной"
  set_fact: process_running=false

- name: "Проверяем запущен ли процесс"
  win_shell: "Get-Process -Id $(cat {{ myapp_path }}myapp.pid) -ErrorAction SilentlyContinue | Format-Table -Property ProcessName"
  register: check_pid
  failed_when: check_pid.rc < 0
  ignore_errors: true

- name: "Флаг работающего процесса"
  set_fact: process_running=true
  when: check_pid.stdout != ''

start.ps1.j2

cd {{ myApp_path}}
(Start-Process java -ArgumentList "-Xmx4096m -Dapplication.env=PROD -jar {{ myapp_name }}" -passthru).ID > myApp.pid
:!: Работа с переменными в плейбуке

Проверка существования
Встречал вариант «when: item is not defined», но он очевидно не работает, проверка спокойно проходит
Хотя «is not defined» довольно распространено, оно похоже в цикле не применимо, она проверяет существование «item» а не то что в нее передаем, точно
А вариант с «in vars» работает даже с экстра переменными

---
- name: "10-check_vars | Проверка переменных"
  ansible.builtin.fail:
    msg: "{{ item }} is not defined"
  when: item not in vars
  loop:
    - my_var1
    - my_var2
    - my_var3

Развертывание словаря в шаблоне джинджи
В инвентори например такой словарь, точнее это список словарей

my_dict_dests:
  - name: "dest_1"
    destDir: "/mytank/DEST/dest_1"
    transferType: "sftp"
    host: "10.10.10.40"
    user: "---"
    pass: "---"

  - name: "dest_2"
    destDir: "/mytank/DEST/dest_2"

Перечисляем все имеющиеся параметры в файле шаблона j2
т.к. фактически это список словарей, поэтому нужен вложенный цикл

{% for dest in my_dict_dests%}
[[DestDir]]
{% for item in dest.items() %}
    {{ item[0] }} = "{{ item[1] }}"
{% endfor %}
{% endfor %}
 
:!: