Инструменты пользователя

Инструменты сайта


ansible:over

Использование

Созданный на хосте пользователь должен быть судошным без ввода пароля, либо нужно вводить пароль при выполнении заданий

Yaml файл начинается с директивы «—« (три тире), обозначает начало очередного файла

Установка

# apt install ansible
# yum install epel-release && yum install ansible

Общее

Исполнения

:!: Общее

Сука тварь блядь, пидарастический ансибл, тупое хуйло, этому пидару надо точно писать «import_tasks» SSSSSuka, или include_tasks(sssss), если не дай бох этому гандону написать без `s`, эта хуила выйбет весь мозг, будет сыпать кучей невнятных ошибок в которых хуй че разберешь, а проблема в одной пидарской букве, спасибо пидары разработчики за такое хуйло

По умолчанию ансибл выполняет все команды на хостах, указанных в параметре «hosts», со всеми вытекающими, ресурсы/зависимости и т.д.
Выполнение можно делегировать на другой хост в т.ч. на локальный, («delegate_to: localhost» и «local_action» одно и тоже, но синтаксис разный)

При делегировании возможно переменные указывают на делегированный хост, а не на инвентори, хотя тут неясно. Есть еще вариант указания «connection: local», отличий вроде нет

Во всех случаях таска выполнится столько раз сколько хостов указано, можно указать «hosts: 127.0.0.1» тогда выполнится один раз
И кстати нормально, при таком варианте инвентори и все хосты из него доступны, ничего не подменивается

Так же есть директива «run_once» для однократного выполнения на первом хосте из доступных

---
- hosts: webservers
  #connection: local
  tasks:
    - name: Take out of load balancer pool
      ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1
      
    - name: Take out of load balancer pool
      local_action: ansible.builtin.command /usr/bin/take_out_of_pool {{ inventory_hostname }}    

    - name: Send summary mail
      local_action:
        module: community.general.mail
        body: "{{ mail_body }}"
      run_once: True

Инфо о хосте

ansible_facts - содержит множество данных о целевом хосте
Занимает время при каждом выполнении, можно отключить в таске либо в конфиге, «gather_facts: False»

ansible 10.11.193.43 -m setup
ansible 10.11.193.43 -m setup -a 'filter=facter_*'
ansible 10.11.193.43 -m setup -a 'gather_subset=!all,!any,facter'
ansible all -m debug -a "var=hostvars[inventory_hostname]"
- name: Collect only facts returned by facter
  ansible.builtin.setup:
    gather_subset: !all,!facter,!ohai,network
 
{{ ansible_facts['devices']['xvda']['model'] }}
 
{{ hostvars['myHost']['ansible_facts']['os_family'] }}

Манипуляции с текстом

Дока

:!: Вывод/обработка списка

Инвентори или group_vars:

mylist:
  - cl_first
  - cl_second
  - cl_three
  - cl_four

Простой вывод списка, заменяя префикс

---
  - name: Test play
    hosts: 127.0.0.1
    tasks:
      - name: check
        debug:
          msg: 
            - "{{ mylist | replace('cl_', 'GSC ') }}"
            - "{{ list1 | difference(list2) }}"
            - "{{ list | select('match', '^prefix.*') | reject('match', '^bad1$|^bad2$') | list }}"

Работа с группами инвентори

  # Перечень групп (развернут с хостами)
{{ groups }}
 
  # Содержимое конкретной группы
{{ groups['<имя-группы>'] }}
 
  # Перечень без развертывания
{{ groups.keys() }}
 
  # Тоже без развертывания
{{ groups | list }}
 
  # Группы в которые входит хост выполнения
{{ group.names }}

Аргументы/Параметры

  • -b [become] - выполнять с повышенными привилегиями
  • [roles] - список ролей применяемые для плейбука
  • -i - каталог с инвентори
  • -a - аргументы
  • -l (–limit) - группа/хост для выполнения указанного задания

Vault

При использовании пароля в файле, используется только вывод файла т.е. запуск, можно указывать скрипт

# Зашифровать файл
ansible-vault encrypt 'path_file'
 
# Расшифровать файл
ansible-vault decrypt 'path_file'
 
# Зашифровать строку
ansible-vault encrypt_string 'string'
 
Переменная среды: ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt\\
Ключ для запроса в cmd: --ask-vault-pass
Ключ для указания в  cmd: --vault-password-file
 
 
# ask password
--ask-vault-password, --ask-vault-pass
 
# создать, сохранится зашифрованный
ansible-vault create new_file
 
# расшифровать
ansible-vault decrypt file.txt --output file.txt_open
 
# открыть для редактирования, при закрытии снова зашифруется
ansible-vault edit 
 
ansible-vault view
:!: Пример расшифровки в консоли
export chiphertext='$ANSIBLE_VAULT;1.1;AES256
	63363161346637313765383762356535366637653435313436623435666166326338346163303232
	6432313962643561306631303363613334303664666536350a653561613564343236313766646336
	66336363396339353734643732343833333135336662613038326435633831613935326434633865
	6631626366386234620a386332633965613436386337613138353762623566623461353034653832
	62306266396439656533636430643261376331616436656334376430386264656532'
 
printf "%s\n" $chiphertext | ansible-vault decrypt

Ограничения запуска

Указывая хост (или группу) можно ограничить те места, откуда будет выполняться задача, в блоке «hosts» при этом должна быть указана родительская группа, «all» например, иначе ошибка аля «not found target»

ansible-playbook mybook.yml --limit <group[host]_name>
ansible <group[host]_name> -m ping

Работа с файлами

Как минимум три модуля:

  • lineinfile - добавить, заменить или удалить одну строку
  • replace - добавить, заменить или удалить несколько строк
  • blockinfile - добавлять несколько строк, окруженных маркерами
:!: Описание

lineinfile
Дока
Поиск/замена одной строки

- name: Ensure SELinux is set to enforcing mode
  ansible.builtin.lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: SELINUX=enforcing

- name: Make sure group wheel is not in the sudoers configuration
  ansible.builtin.lineinfile:
    path: /etc/sudoers
    state: absent
    regexp: '^%wheel'

replace
Дока
Поинтереснее, но все же заточен на построчную поиск/замену
Указав «любой символ» работает с каждым найденным словом как с отдельным элементом, причем даже пробелы не щадит(
Для замены собсна тоже принимает строку

- name: "Запись в файл"
  ansible.builtin.replace:
    path: /tmp/hosts-test
    after: "# Start gameserver hosts"
    before: "# End gameserver hosts"
    #regexp: '^1.1.(.+)$'
    #replace: '11.11.11.11'
    regexp: '.*'
    replace: '11.11.11.11'

blockinfile
Дока
Вставляет блок текста, соблюдая строки
Можно указать регулярками (либо конец файла) после чего (до чего) вставлять блок, что то одно !!!

Работает прежде всего с блоками текста, сам текст указан в «block», обрамление в «marker» (директива »{mark}« подставляет слова BEGIN/END в метке)
С блоками работает нормально, проверяет наличие, если изменений нет, то пропускается, если есть, то обновляет текст, если указать в block пустую строку, то блок удалится вместе с метками

- name: "Запись в файл hosts"
  ansible.builtin.blockinfile:
    #become: yes
    #become_method: sudo
    #become_user: root
    path: /tmp/hosts-test
    block: |
      2.2.2.2 two
      3.3.3.3 three
      4.4.4.4 four
    marker: "{mark} Gameservers from ansible inventory"

Фильтрация списков словарей

  • selectattr rejectattr - возвращает весь элемент по указанному условию
  • map - вырезает только значения указанных аттрибутов, по одному аттрибуту из всех подходящих элементов
:!: Описание

selectattr rejectattr
Есть нюанс тогда когда указанный для фильтрации ключ есть не во всех элементах. Указанный по ссылке пример в итоге возвратит два списка, один с установленным аттрибутом, второй без аттрибута.

Условия для поиска могут быть разными «equalto match search» и т.д.

  # Так возвращает элемент (весь элемент словаря) у которого установлен аргумент в указанное значение
    # "('origin1', 'none')" - для поиска пустого значения 
"{{ fruit | selectattr('origin1', 'equalto', '21') }}" 
 
  # "selectattr('origin1', 'undefined')" - Для поиска именно неустановленного аттрибута
"{{ fruit | selectattr('origin1', 'undefined') }}" 

map

  # Из общего списка словарей вернет только элементы по регулярке, далее покажем только значение только одного аттрибута, всех этих элементов
"{{ fruit | selectattr('origin1', 'match', '^..$') | map(attribute='origin1') }}"

Block

:!:
 

Преобразования типов данных

Дока
dict2items,items2dict,combine,zip и т.д.

Примеры

Zabbix

Для работы нужен «zabbix-api», плюс ансибл работает со своей версией питона

/usr/bin/python3.8 -m pip install zabbix-api
ansible-galaxy collection install community.zabbix

OverAll

:!: Минимальный стартовый пример

hosts, можно короче

all:
  hosts:
    192.168.0.101

test.yaml

---
- hosts: all
  tasks:
    - name: Test ping
      delegate_to: 127.0.0.1
      ping:

+ в конфиге еще путь к инвентори

:!: Перебор хостов циклом

Инкремент переменной в цикле

---
- hosts: all
  gather_facts: no
  run_once: True
  tasks:
    - name: Get list group
      vars:
        - llist: ''
        - foo: ''
      set_fact:
        foo: "{{ item +' '+ hostvars[item]['ansible_host'] | default('-') }}"
        llist: "{{ llist + foo }}\n\r "
      loop: "{{ groups['remote'] }}"
 
    - name: show
      debug:
        msg: "{{ llist }}"
 
(...)
msg: "{{ hostvars[groups['gameservers_all'][0]]['ansible_winrm_host'] }}"
(...)
(...)
vars:
    - zabbix_gameservers_list: ''
  set_fact:
    zabbix_gameservers_list: "{{ zabbix_gameservers_list
                              + hostvars[item]['openvpn_ip'] | default(hostvars[item]['ansible_winrm_host']) | default('# ip not found :(') +' '
                              + hostvars[item]['inventory_hostname'] }}\n"
  loop: "{{ groups['gameservers_all'] }}"
(...)
:!: Выполнение bash команды и вывод результата
---
- hosts: all
  gather_facts: no
  run_once: True
  tasks:
    - name: Get list group
      shell:
        cmd: "ss -ntlua | grep 8086 | wc"
      register: resultt
      become: yes
    - debug: var=resultt.stdout_lines
:!: Работа в консоли

Есть несколько вариантов/утилит, в зависимости от задачи
Например вывод списка из инвентори команды:
ansible-inventory, ansible-console - по функционалу почти одинаковые, и почти бесполезные, тупые, конечные (или даже конченные)
Можно просто запросом в консоли через debug

ansible localhost -m debug -a 'var=groups["my_group"]'
ansible localhost -m debug -a 'var=hostvars["myHost"].myVariable'
 
ansible-inventory --graph "my_group" --vars --export
 
# Объявление переменной в консоли
ansible-playbook runrole.yml -e "zabbix_status_host='enabled'"
:!: Работа с сервисами
---
- name: "Конфигурация systemd для новой службы"
  systemd:
    daemon_reload: yes
  listen: "reload_systemd"
 
- name: "Запуск службы zookeeper"
  systemd:
    name: zookeeper
    state: restarted
    enabled: true
  listen: "start_restart_zookeeper"
  # рекоммендуют запускать при любых изменениях чтобы убедится в применении пар-ов, в случае yes, запустит reload даже если ничего не запускал/останавливал
daemon_reload: yes
  # Ожидание завершения
no_block: false 
  # start/stopped — это идемпотентные действия, которые не будут запускать команды без необходимости. После restarted устройство всегда будет подпрыгивать. reloaded всегда перезагружается.
state: reloaded # запускает службу в любом случае
state: restarted # перезапускает службу
state: [stopped, started]

Проверка существования и остановка сервиса, несколько попыток с задержкой, пока не остановится, таска упадет если сервис так и не остановится

---
- name: "Получаем информацию о сервисах в системе"
  ansible.builtin.service_facts:
 
- name: "Останавливаем fprofilesac.service если он есть в ОС"
  systemd:
    name: 'fprofilesac.service'
    state: stopped
  register: fprofilesacInfo
  until: fprofilesacInfo.state == "stopped"
  retries: 5
  delay: 10
  when: "'fprofilesac.service' in services"

handlers: запуск/перезапуск/начальная активация службы

- name: "Запуск службы FProfilesAutoAcceleration"
  systemd:
    name: fprofilesac
    state: restarted
    enabled: true
    daemon_reload: yes
  listen: "start_restart_fprofilesac"

Пример шаблона для unit файла

[Unit]
    Description=FProfilesAutoAcceleration service
    After=tank.mount
    After=mnt-update_server_200.mount
    After=network-online.target
 
    #Requires=network-online.target tank.mount mnt-update_server_200.mount
 
[Service]
    ExecStart=java -Dcom.sun.management.jmxremote \
                   -Dcom.sun.management.jmxremote.port=10045 \
                   -Djava.rmi.server.hostname={{ openvpn_ip | default(ansible_host) }} \
                   -Dcom.sun.management.jmxremote.authenticate=false \
                   -Dcom.sun.management.jmxremote.ssl=false \
                   -jar {{ fac_appname }}.jar \
                   -Xmx7G
    WorkingDirectory={{ fac_path }}
    Restart=always
    TimeoutSec=15
    User={{ fac_user }}
 
[Install]
    Alias=fac.service
:!: Работа в ОС
- name: "Создание пользователя"
  user:
    name: fprofilesac
    create_home: false
    system: true
    shell: /bin/false
 
- name: "Создание директорий"
  file:
    path: "{{ item }}"
    state: directory
    owner: fprofilesac
    group: fprofilesac
    mode: '0755'
  loop:
    - "{{ fprofilesac_path }}"
    - "{{ fprofilesac_path }}/logs"
    - "{{ fprofilesac_path }}/backups"
 
- name: "Создание ссылки симлинка"
  file:
    src: "/src/directory"
    dest: "dest/symlink-name"
    state: link
  # become для винды
  become: yes
  become_method: runas
  become_user: "{{ admin_user }}"
:!: Запуск процессов Windows

Есть проблемы с синхронным/ассинхронным выполнением на хостах, бывает что ансиблом запускаешь процесс, все норм он запускается но завершается вместе с плейбуком т.к. плейбук по умолчанию работает в синхронном режиме, надо запускать в ассинхронном

- name: "test"
  win_shell: |
    cd {{ my_path }}
    ./myScript.ps1
  async: 15
  ignore_errors: yes
  register: start_app
  failed_when: start_app.started != 1
 
 
# Еще примеры запуска скриптов/процессов
- name: "Старт приложения"
  win_shell: |
    cd {{ my_path }}
    ./myScript.ps1
 
 
- name: "Старт приложения"
  win_shell: |
    cd {{ my_path }}
    (Start-Process java -ArgumentList "-Xmx4096m -Dapplication.env=PROD Main" -passthru).ID > myScript.pid
 
# Рестарт
Stop-Process -Id $(cat myScript.pid)
./myScript.ps1

Переменная с результатом содержит примерно такой вывод, при условии что консоль продолжила работать
(и started и finished == 1)
Если консоль сразу же корректно завершилась то вывод не отличается, тобишь здесь можно отследить проблему именно при физическом запуске доп процесса, типа если pShell не сможет его запустить, а вот если приложение упадет после запуска, это уже надо другими способами проверять, хотя бы ПИД как минимум

ok: [host_mes_mds_prod] => {
    "msg": {
        "ansible_async_watchdog_pid": 1516,
        "ansible_job_id": "41177545019.4340",
        "changed": true,
        "cmd": "cd C:\\test_mds\\\n./startMDS2.ps1",
        "delta": "0:00:00.437520",
        "end": "2023-12-04 12:59:59.234763",
        "failed": false,
        "failed_when_result": false,
        "finished": 1,
        "rc": 0,
        "results_file": "C:\\Users\\ansible\\.ansible_async\\41177545019.4340",
        "start": "2023-12-04 12:59:58.797243",
        "started": 1,
        "stderr": "",
        "stderr_lines": [],
        "stdout": "",
        "stdout_lines": []
    }
}
:!: Динамические группы инвентори

Смысл в том что можно в рантайме сформировать группу хостов, на основе каких то данных в нем, например факты или хостовые переменные

Динамические группы формируются на все попадаемые значения, указанной переменной, содержатся только в памяти и к сожалению похоже нельзя вывести весь список, что усложняет работу с ними

Так же использовать можно только в текущем плейбуке, «не отходя от кассы» что называется
Например:

# Выполняем на всех хостах, группируем по знаяениям в хостовой переменной
- hosts: all
  gather_facts: no
  tasks:
    - name: Set 'appgrp_mgaimports'
      group_by:
        key: "{{ variable_in_host }}"
 
# Далее запускаем плейбуки с определенными параметрами только для нужной группы
- hosts: value_1
  gather_facts: false
  roles:
    - my_role_for_1

- hosts: value_2
  gather_facts: false
  roles:
    - my_role_for_2

Command & shell

command - работает чуть быстрее но запускается не через оболочку («bin/sh»), поэтому в нем не доступны переменные окружения и прочие плюшки шелла, типа конвейеров, перенаправления вывода и проч

ansible/over.txt · Последнее изменение: 2024/04/22 10:02 — admin