LINUX.ORG.RU

проблема со слэшами в ansible

 


0

1

Всем добрый день. неделю как изучаю ансамбль и напоролся на совершенно непонятную мне проблему. предыстория - нужно получить с железок информацию о размещении файла на диске и вывести ее в файл. вот такого вида - c:\directory\config.cfg. получаем, парсим с помощью textFSM (\S+), в переменной видим c:\\directory\\config.cfg (как так-то???). отправляем через shell на вывод в файл и там видим c:directoryconfig.cfg. пробовал делать вывод через copy - на выходе получаем c:\\directory\\config.cfg. нет, решить проблему я решил с помощью sed - но как-то это некрасиво. в доках ничего не нашел (плохо искал?). пробовал разные варианты кавычек, пробовал разбивать вывод на части - слэш пропадает и все… может кто чего умного подскажет или хотя бы в нужном направлении пошлет?

ансамбль

что простите?)

c:\directory\

топик на linux.org.ru, вопрос про форточки, лучше спросить на тематическом ресурсе

а теперь по теме:

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

модуль lineinfile позволит писать строки в файл (можно с регулярками), или через модуль copy с параметром content записать целиком генерированный тобою файл

и забудь про shell, sed, grep и т.п., в ansible есть модули и фильтры на любой чих и готовые решения, иначе чем же твоя роль будет отличатся от обычной bash портянки?

WoozyMasta ()
Последнее исправление: WoozyMasta (всего исправлений: 1)

и про слеши еще, \\ - это один слеш, экранированный, а это \\\\ - два слеша, каждый экранированный.

printf '\\\\\\\\\\'
\\\\\
WoozyMasta ()
Ответ на: комментарий от WoozyMasta

уважаемый, вы делаете неверный далекоидущий вывод на основе совершенно не тех данных. покажите мне - где я написал про форточки?

andy77 ()
Ответ на: комментарий от Demacr

сделаем проще. есть вот такой сайт http://textfsm.nornir.tech/ строка для обработки config c:\config.cfg шаблон Value SysT (\S+\s+) Value Type (\S+)

Start ^${SysT} ${Type} вывод [ { «SysT»: "config ", «Type»: «c:\config.cfg» } ] вопрос - как добиться вывода в переменную Type строку с одним слэшем?

andy77 ()
Ответ на: комментарий от WoozyMasta

по теме модуль stat предназначен для линукса/юникса. мои железки не попадают в этот перечень. в виндовый тоже. модуль lineinfile - тут сложнее. пока из описания я вижу что он позволяет изменить или найти строку в существующем на железке файле. но это не то что мне надо. возможно, пока я просто не разобрался с этим модулем. модуль copy - все хорошо, но итог опять лишние слэши в собранной информации. в ansible модули далеко не на любой чих. есть очень много специфического железа и решений, уж поверьте.

andy77 ()
Ответ на: комментарий от andy77

Тогда давайте опишем вопрос конкретно, и не будем заставлять людей ванговать. Что за железо, литсинг тасков из вашей роли, в ответ вы получите более вменяемые советы.

А так вы получаете то, что спросили.

WoozyMasta ()
Ответ на: комментарий от FireFighter

И причем тут шаблоны? Осведомлен, что jinja2 используется как в copy, lineinfile так и в template?

А со слешами там всё просто же:

$ set_fact lol=c:\lol
localhost | SUCCESS => {
    "ansible_facts": {
        "lol": "c:\\lol"
    },
    "changed": false
}

$ echo '{{ lol }}'
localhost | CHANGED | rc=0 >>
c:\lol

$ echo {{ lol }}
localhost | CHANGED | rc=0 >>
c:lol

$ set_fact lol=c:\\\\\\lol
localhost | SUCCESS => {
    "ansible_facts": {
        "lol": "c:\\\\\\lol"
    },
    "changed": false
}

$ echo '{{ lol }}'
localhost | CHANGED | rc=0 >>
c:\\lol

$ echo {{ lol }}
localhost | CHANGED | rc=0 >>
c:\lol

WoozyMasta ()
Ответ на: комментарий от WoozyMasta

и забудь про shell, sed, grep и т.п., в ansible есть модули и фильтры на любой чих и готовые решения, иначе чем же твоя роль будет отличатся от обычной bash портянки?

Тем, что теоретически будет проще для понимания, чем jinja-портянка и быстрее работать, чем ограниченные по возможностям ансибль-питон-портянки.

AnDoR ★★★★★ ()
Ответ на: комментарий от AnDoR

bash-лапша вида '\\\\\\\\\\'

проще для понимания

/0

Он всё правильно сказал – баш-лапшу на помойку и использовать нормальные средства для решения задач, а не говно.

А вообще все эти проблемы из-за ограниченности и убогости Bash’а и прочих UNIX-овых Shell’ов.


Как зайти на хост a@a, с него — на b@b, с него — на c@c, с него — на d@d, а с него удалить файл /foo? Ну, это легко:

ssh a@a "ssh b@b \"ssh c@c \\\"ssh d@d \\\\\\\"rm /foo\\\\\\\"\\\"\""

Слишком много бекслешей, да? Ну, не нравится так, давайте чередовать одинарные и двойные кавычки, будет не так скучно:

ssh a@a 'ssh b@b "ssh c@c '\''ssh d@d \"rm /foo\"'\''"'

А между прочим, если бы вместо shell’а был Lisp, и там функция ssh передавала бы на удалённую сторону не строку (вот она, повёрнутость UNIX на тексте!), а уже распарсенный AST (abstract syntax tree), то такого ада бекслешей не было бы:

(ssh "a@a" '(ssh "b@b" '(ssh "c@c" '(ssh "d@d" '(rm "foo")))))

(c) https://habrahabr.ru/post/321652/

EXL ★★★★★ ()
Ответ на: комментарий от WoozyMasta

При том, что надо писать роль, которую можно использовать и для других хостов. А не затачивать всё под конкретный кейс.

FireFighter ★★★ ()
Ответ на: комментарий от EXL

bash-лапша вида ‘\\\\\’

А теперь вспомним, что в ансиболи надо экранировать для yaml’я и ещё иногда для jinja. Дважды. Ничем не лучше.

Он всё правильно сказал – баш-лапшу на помойку и использовать нормальные средства для решения задач, а не говно.

На баше можно писать не лапшу. На ансиболи это сложнее.

Как зайти на хост a@a, с него — на b@b, с него — на c@c, с него — на d@d, а с него удалить файл /foo? Ну, это легко: ssh a@a «ssh b@b "ssh c@c \"ssh d@d \\\"rm /foo\\\"\""»

ssh -J a@a,b@b,c@c d@d 'rm /foo'
AnDoR ★★★★★ ()
Последнее исправление: AnDoR (всего исправлений: 1)
Ответ на: комментарий от FireFighter

Какие такие ограничения возможностей?

Сходу вот тебе две задачки:

  1. Удали чистой ансиболью все файлы из директории, но не саму директорию.
  2. Сделай явную распаковку тарболла, без траты лишнего времени на бесполезный запуск с --list перед непосредственно распаковкой.

И вам шашечки или ехать? Мне ехать, поэтому я сделал вышестоящие задачи шелл-скриптами, которые запускаются из ансиболи.

AnDoR ★★★★★ ()
Ответ на: комментарий от AnDoR
  1. Тут согласен, что делается данная задачка не тривиально как rm -rf /tmp/lol/*, но и трудностей я не вижу. Или удаляем после создаем директорию, если нужно четко по ТЗ, то find собираем список, и его потом удаляем. Но данный факт не гласит, что ansible пора на свалку, просто нужно как-то соблюдать идемпотентность и разработчики это видят так.

На крайний случай если это столь частая задача на практике, всегда можно написать свой модуль.

  1. Этой проблемы нет сейчас, list_files для unarchive по умолчанию false.
$ unarchive src=/tmp/lol.tar.xz dest=/tmp/lol
localhost | CHANGED => {
    "changed": true,
    "extract_results": {
        "cmd": [
            "/usr/bin/tar",
            "--extract",
            "-C",
            "/tmp/lol",
            "-f",
            "/tmp/.ansible/ansible-tmp-1595681915.8811967-102253595934965/source"
        ]
    }
}

А shell вызывать можно но не нужно всю роль писать на нем, при условии, что есть модуль полностью решающий задачу. Оно конечно прекрасно работает пока ты админ локалхоста, но попав в зоопарк дистрибутивов и версий глаза устанут и руки опустятся отлаживать эту портянку.

WoozyMasta ()
Ответ на: комментарий от WoozyMasta

Или удаляем после создаем директорию

Это первый вариант в гуглах. В моём случае это была точка монтирования ФС, она не удаляется.

если нужно четко по ТЗ, то find собираем список, и его потом удаляем.

Это второй вариант в гуглах и первый вариант, который я попробовал. Представь, что у тебя там тыща файлов и каждый таск это минимум 100мс туда-обратно. Тупо трата времени, ради бессмысленного «сделать ансиболью, а не башем».

Я в итоге сделал так:

- name: remove files in directory
  shell:
    cmd: >-
      find "{{ datadir }}" -maxdepth 1 -mindepth 1 -print -exec rm -rf {} +
  register: _remove_data
  changed_when: _remove_data.stdout | length > 0

Но данный факт не гласит, что ansible пора на свалку

Я не говорил, что ему пора на свалку, но и культ из него делать не стоит.

просто нужно как-то соблюдать идемпотентность и разработчики это видят так.

Для того чтобы ансиболь был идемпотентный, надо специально плясать вприсядку. Но если воспринимать его как pssh или gnu/parallel на стероидах и не ожидать от него, что на голом ансибле можно внятную логику запрограммировать, то волосы становятся шелковистыми. Ансиболь, правда, не становится удобнее, когда без подобной логики никак.

На крайний случай если это столь частая задача на практике, всегда можно написать свой модуль.

А можно сделать быстрое, простое и понятное решение через shell/command не залезая в кишки ансиболи.

Этой проблемы нет сейчас, list_files для unarchive по умолчанию false.

А вот и не угадал. Даже если указано list_files: no, то оно всё равно делает --list, но не возвращает полученный вывод.

Вероятно, это баг, но я свою задачу сделал и забил.

AnDoR ★★★★★ ()
Ответ на: комментарий от AnDoR

Удали чистой ансиболью все файлы из директории, но не саму директорию.

Ну например так:

- name: polkit | Find exists polkit policy's
  find:
    paths: "{{ hostvars[inventory_hostname]['polkit_conf_dest'] +
      '/localauthority.conf.d' }}"
    recurse: "no"
    file_type: "file"
    patterns: "*.conf"
  register: "polkit_policy_find_result"
  when:
  - "hostvars[inventory_hostname]['polkit'] is defined"
  - "hostvars[inventory_hostname]['polkit'] != ''"
  - "hostvars[inventory_hostname]['polkit'] |
     json_query(vars['polkit_drop_exists']) is defined"
  - "hostvars[inventory_hostname]['polkit'] |
     json_query(vars['polkit_drop_exists']) == 'true'"
  vars:
    polkit_drop_exists: "[] | map(&drop_exists || 'false', @) | [0]"

- name: polkit | Delete exists polkit policy's
  file:
    path: "{{ item.path }}"
    state: "absent"
  loop: "{{ vars['polkit_policy_find_result']['files'] | flatten(levels=1) }}"
  loop_control:
    label: "{{ item.path }}"
  when:
  - "vars['polkit_policy_find_result']['files'] is defined"

Сделай явную распаковку тарболла

Что такое «явная распаковка» и зачем это может понадобится делать через оркестратора?

FireFighter ★★★ ()
Ответ на: комментарий от FireFighter

Ну например так:

Это правда лучше выглядит и понятнее, чем shell: find? Также посмотри в текст следующего комментария.

Что такое «явная распаковка»

Имеется в виду распаковка через command/shell + tar вместо unarchive из-за проблем указанных в том же самом комментарии.

зачем это может понадобится делать через оркестратора?

Затем.

AnDoR ★★★★★ ()
Последнее исправление: AnDoR (всего исправлений: 3)
Ответ на: комментарий от FireFighter

Ну не пользуйся этим, используй шелл.

Ну!

AnDoR ★★★★★ ()

да, неплохо я накинул :) проблему решил в лоб - заменой слэша. благо железяке пофиг в какую сторону смотрит слэш...

config_facts: '{{ sh_ver.stdout_lines[0] | parse_cli_textfsm("~/.ansible/parse/sh_config.textFSM" | expanduser ) | replace("\\", "/") }}'
еще можно накинуть? :) есть задачка снятия состояния цископодобной железки до выполнения определенных действий на ней и после с выводом в файл. то есть даем команду вида show system info и ее вывод в stdout_lines в цикле тупо копируем в файл. засада в том что команд много, вывод обьемный, в итоге минут 40 на каждой железке сидим и пялимся в монитор пока пройдет весь этот вывод. железок много. как ускорить? вот кусок кода
  - include: log_system.yml
    vars:
      show_command: "{{ item }}"
    loop:
      '{{ array_commands }}'
----
  ---
  - name: System log
    cli_command:
      command: "{{ show_command }}"
    register: logger
    ignore_errors: true

  - name: copy log to file
    shell: echo '{{ next_item }}' >>~/.ansible/log/{{ inventory_hostname }}
    delegate_to: 127.0.0.1
    loop:
      '{{ logger.stdout_lines }}'
    loop_control:
      loop_var: next_item
    ignore_errors: true
    when: logger.stdout_lines is defined
no_log не предлагать.

andy77 ()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.