Ansible: получить значение первой пары на основе значения значения второй пары

У меня есть этот файл, и я знаю значение LOC, например /oracle/19.0.0. Хотите получить значение HOME NAME=, соответствующее значение будет OraDB19Home1.

Посмотрел поиск, но не смог заставить его полностью работать. Цените любую помощь.

<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<!-- Copyright (c) 1999, 2022, Oracle. All rights reserved. -->
<!-- Do not modify the contents of this file by hand. -->
<INVENTORY>
   <VERSION_INFO>
      <SAVED_WITH>13.9.4.0.0</SAVED_WITH>
      <MINIMUM_VER>2.1.0.6.0</MINIMUM_VER>
   </VERSION_INFO>
   <HOME_LIST>
      <HOME NAME = "OraHome1" LOC = "/oracle/agent/agent13.4" TYPE = "O" IDX = "3"/>
      <HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>
   </HOME_LIST>
</INVENTORY>
Введение в Ansible Roles
Введение в Ansible Roles
Ansible - это отличный инструмент управления конфигурацией, который можно использовать для автоматизации настройки или развертывания на большом...
1
0
119
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Это почти тривиально сделать с awk:

Форматируется как файл сценария:

/<HOME NAME=.*TYPE=.*IDX=/ {
    if ($3 == "LOC=\"/oracle/19.0.0\"") {
        split($2, a, /"/);
        print a[2];
        exit;
    }
}'

Командная строка:

cat your_input_file | awk '/<HOME NAME=.*TYPE=.*IDX=/{ if ($3 == "LOC=\"/oracle/19.0.0\"") { split($2, a, /"/); print a[2]; exit }  }'

Вероятно, вы можете относительно легко преобразовать это во что-то подобное в python.

Спасибо! Да, в настоящее время я использую что-то похожее в существующем сценарии оболочки, который я пытаюсь написать как доступную книгу. Поэтому искал что-то доступное решение.

calsaint 08.02.2023 15:48
awk -v loc='LOC = "/oracle/19.0.0"' '
    index($0,loc){
        print gensub(/^.*NAME = "([^"]*)".*$/,"\\1",1)
    }
' inputfile

или

awk -F'=|"' -v loc='LOC = "/oracle/19.0.0"' 'index($0,loc){print $3}' inputfile
awk -F'=|"' -v loc = "/oracle/19.0.0" '/ LOC = "[^"]*" / && $6 == loc {print $3}' inputfile

Выход

OraDB19Home1

Для меня вариант использования выглядит как

Похожие вопросы и ответы

Предполагается, что неблагоприятная структура данных в вашем файле примера конфигурации остается прежней, и вы ищете grep подход в Ansible.

- name: Gather home directory
  shell:
    cmd: "grep '{{ VERSION }}' inventory.xml | cut -d '=' -f 2 | cut -d ' ' -f 1 | tr -d '"'"
  register: home_dir

Как действовать дальше?

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

Если установка ansible.utils.collection и библиотеки Python xmltodict возможна или уже доступна, вам обязательно следует воспользоваться рекомендуемым решением от Владимира Ботки фильтра from_xml — преобразовать заданную строку XML в собственный словарь Python путем преобразования XML в YAML перед дальнейшей обработкой.

В противном случае вы можете попробовать

Примеры пользовательских модулей

Спасибо! Цените помощь. Пытался избежать cmd/shell и сделать это изначально в ansbile.

calsaint 08.02.2023 15:47
Ответ принят как подходящий

Given the XML

shell> cat inventory.xml 
<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<!-- Copyright (c) 1999, 2022, Oracle. All rights reserved. -->
<!-- Do not modify the contents of this file by hand. -->
<INVENTORY>
  <VERSION_INFO>
    <SAVED_WITH>13.9.4.0.0</SAVED_WITH>
    <MINIMUM_VER>2.1.0.6.0</MINIMUM_VER>
  </VERSION_INFO>
  <HOME_LIST>
    <HOME NAME = "OraHome1" LOC = "/oracle/agent/agent13.4" TYPE = "O" IDX = "3"/>
    <HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>
  </HOME_LIST>
</INVENTORY>

Прочитайте файл и конвертируйте XML в YAML

  inv_xml: "{{ lookup('file', 'inventory.xml') }}"
  inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"

дает

  inv_yml:
    INVENTORY:
      HOME_LIST:
        HOME:
        - '@IDX': '3'
          '@LOC': /oracle/agent/agent13.4
          '@NAME': OraHome1
          '@TYPE': O
        - '@IDX': '2'
          '@LOC': /oracle/19.0.0
          '@NAME': OraDB19Home1
          '@TYPE': O
      VERSION_INFO:
        MINIMUM_VER: 2.1.0.6.0
        SAVED_WITH: 13.9.4.0.0

Создайте словарь LOC и NAME

  loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
                items2dict(key_name='@LOC',
                           value_name='@NAME') }}"

дает

  loc_name:
    /oracle/19.0.0: OraDB19Home1
    /oracle/agent/agent13.4: OraHome1

Тогда поиск тривиален

  loc: '/oracle/19.0.0'
  name_of_loc: "{{ loc_name[loc] }}"

дает

  name_of_loc: OraDB19Home1

, или в цикле

    - debug:
        msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
      loop:
        - '/oracle/19.0.0'
        - '/oracle/agent/agent13.4'

дает (сокращенно)

  msg: The name of LOC /oracle/19.0.0 is OraDB19Home1
  msg: The name of LOC /oracle/agent/agent13.4 is OraHome1

Example of a complete playbook for testing

shell> cat pb.yml
- hosts: localhost

  vars:

    inv_xml: "{{ lookup('file', 'inventory.xml') }}"
    inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"
    loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
                  items2dict(key_name='@LOC',
                             value_name='@NAME') }}"
    loc: '/oracle/19.0.0'
    name_of_loc: "{{ loc_name[loc] }}"

  tasks:

    - debug:
        var: inv_xml
    - debug:
        var: inv_yml
    - debug:
        var: loc_name
    - debug:
        var: name_of_loc

    - debug:
        msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
      loop:
        - '/oracle/19.0.0'
        - '/oracle/agent/agent13.4'

Example of the project

shell> tree .
.
├── ansible.cfg
├── hosts
├── inventory.xml
└── pb.yml

0 directories, 4 files
shell> cat ansible.cfg 
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
remote_tmp = ~/.ansible/tmp
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts 
localhost

Q: "Дайте альтернативу ansible.utils"

О: Установите jc и используйте его в пайпе. Объявление ниже расширяется до того же YAML, что и раньше.

  inv_yml: "{{ lookup('pipe', 'cat inventory.xml | jc --xml') }}"

Q: "Используя возможное регулярное выражение?"

A: Сначала выберите строку

  inv_xml: "{{ lookup('file', 'inventory.xml') }}"

  loc: '/oracle/19.0.0'
  home_loc_regex: '^\s*<HOME .*? LOC = "{{ loc }}" .*$'
  home: "{{ inv_xml.splitlines()|
            select('regex', home_loc_regex)|
            first|
            trim }}"

дает

  home: <HOME NAME = "OraDB19Home1" LOC = "/oracle/19.0.0" TYPE = "O" IDX = "2"/>

Разобрать атрибуты

  home_dict: "{{ dict(home[6:-2]|
                      replace('\"', '')|
                      split(' ')|
                      map('split', '=')) }}"

дает

  home_dict:
    IDX: '2'
    LOC: /oracle/19.0.0
    NAME: OraDB19Home1
    TYPE: O

В: «Нет фильтра с названием «разделить»»

О: Фильтр сплит доступен с 2.11. Для более ранних версий доступен только метод «.split». В этом случае используйте Jinja и создайте структуру YAML. Объявления ниже дают тот же словарь home_dict, что и раньше.

  home_dict_str: |
    {% for i in home[6:-2].split(' ') %}
    {% set arr = i.split('=') %}
    {{ arr.0 }}: {{ arr.1 }}
    {% endfor %}
  home_dict: "{{ home_dict_str|from_yaml }}"

Большое спасибо. Я смотрел на них, чтобы импровизировать, stackoverflow.com/questions/72022134/… и следующее, на что вы ответили в другой теме, потеряло ссылку для этого. - set_fact: MQSFILEPARSED: "{{ lookup('file', FILE).splitlines()| select('match', '^(.*) LOC=(.*)$')| map('regex_replace', my_regex , my_replace)| список }}"

calsaint 08.02.2023 15:36

Получение ansible.utils оказалось сложной задачей. Цените, если вы можете дать альтернативу, используя возможное регулярное выражение? Еще раз спасибо.

calsaint 08.02.2023 17:37

Вместо этого используйте jc. Я добавил пример. Что сложного в ansible.utils?

Vladimir Botka 08.02.2023 17:53

Я добавил опцию «regex».

Vladimir Botka 08.02.2023 18:23

Большое спасибо еще раз! Администраторы нашего сервера не хотят добавлять эти утилиты. Вот где я разрабатываю playbooks. В конечном итоге они попадут в Башню. И в Tower env эти утилиты не установлены. Когда я связался с администратором башни, он сказал, что у меня должна быть пользовательская оболочка exec. Не был уверен, сколько из этого я хотел баловаться с ограниченным временем и т. д. Всегда ценю вашу помощь. Я набираю пива для вас здесь, в Хьюстоне :)

calsaint 08.02.2023 20:29

Полезно знать :) Посмотрите, доступен ли вам Community.General . Здесь добавляются и обновляются новые материалы. Например, вы можете использовать jc также в качестве фильтра.

Vladimir Botka 08.02.2023 21:19

Давайте продолжим обсуждение в чате.

calsaint 08.02.2023 21:45

Другие вопросы по теме