Ansible: 他のディレクトリキーと一致する配列キー値を更新する方法

Ansible: 他のディレクトリキーと一致する配列キー値を更新する方法

私は次の辞書を持っています:

question:
  first_run:
    app:
      - answer: null
        name: first_name
        question: What is your First name?
      - answer: null
        name: last_name
        question: What is your Last name?
    core:
      - question: question1
      - question: question2
answer:
  first_name: John
  last_name: Smith

次の操作を使用して手動で更新します。回答以下の価値Question.first_run.app良い結果

- name: Update question variable
  set_fact:
    question:
      first_run:
        app:
          - name: first_name
            question: "What is your First name?"
            answer: "{{ answer.first_name }}"
          - name: last_name
            question: "What is your Last name?"
            answer: "{{ answer.last_name }}"

また、次のタスクをテストしました(この場合はこれが望ましいアプローチです)。

- name: "TEST-1"
  set_fact:
    question: "{{ question | combine({'first_run': {'app': question.first_run.app | map('combine', {'answer': update }) | list }}, recursive=True) }}"
  loop: "{{ question.first_run.app }}"
  vars:
    update: "{{ answer[item.name] if item.name in answer.keys() else item.answer }}"

- name: "TEST-2"
  set_fact:
    question: "{{ question | combine({'first_run': {'app': question.first_run.app | map('combine', {'answer': (answer[item.name])})}}, recursive=True) }}"
  loop: "{{ question.first_run.app }}"
  vars:c
    update: "{{ answer | dict2items | selectattr('key', 'in', [item.name]) | map(attribute='value') | first }}"
#    update: "{{ answer[item.name] }}"    # THis also works

ただし、TEST-1とTEST-2の出力は常に次のようになります。

question:
  first_run:
    app:
      - answer: Smith
        name: first_name
        question: What is your First name?
      - answer: Smith
        name: last_name
        question: What is your Last name?
    core:
      - question: question1
      - question: question2

私がテストした最後の作業は次のとおりです。
うまくいきますが、目的の結果は新しいvar app_listの下に保存されます。

- name: "TEST-3"
  set_fact:
    question: "{{ question | combine({'first_run': {'app': app_list}}, recursive=True) }}"
  vars:
    app_list: []
  loop: "{{ question.first_run.app }}"
  set_fact:
    app_list: "{{ app_list + [item | combine({'answer': answer[item.name]})] }}"

質問:

これらのキーをすべて配列に手動で配置する必要がないように、「問題変数の更新」操作を更新する必要があります。Question.first_run.app

ループを使用して一致させる方法Question.first_run.app.nameそして答えそれでは、出力は次のようになりますか? TEST-1、TEST-2、またはTEST-3を調整することをお勧めします。

question:
  first_run:
    app:
      - answer: John
        name: first_name
        question: What is your First name?
      - answer: Smith
        name: last_name
        question: What is your Last name?
    core:
      - question: question1
      - question: question2

ベストアンサー1

作る回答

  answers: "{{ question.first_run.app|
               map(attribute='name')|
               map('extract', answer)|
               map('community.general.dict_kv', 'answer') }}"

与えられた

  answers:
  - answer: John
  - answer: Smith

事前更新アプリ

  app_update: "{{ question.first_run.app|
                  zip(answers)|
                  map('combine') }}"

与えられた

  app_update:
  - answer: John
    name: first_name
    question: What is your First name?
  - answer: Smith
    name: last_name
    question: What is your Last name?

修正する最初の実行

    first_run_update: "{{ question.first_run|
                          combine({'app': app_update}) }}"

与えられた

  first_run_update:
    app:
    - answer: John
      name: first_name
      question: What is your First name?
    - answer: Smith
      name: last_name
      question: What is your Last name?
    core:
    - question: question1
    - question: question2

最後の更新質問

    - set_fact:
        question: "{{ question|
                      combine({'first_run': first_run_update}) }}"

あなたが望むものを与える

  question:
    first_run:
      app:
      - answer: John
        name: first_name
        question: What is your First name?
      - answer: Smith
        name: last_name
        question: What is your Last name?
      core:
      - question: question1
      - question: question2

テストのための完全なプレイブックの例

- name: Substitute attribute *answer* by *name*
  hosts: localhost

  vars:

    question:
      first_run:
        app:
        - answer: null
          name: first_name
          question: What is your First name?
        - answer: null
          name: last_name
          question: What is your Last name?
        core:
        - question: question1
        - question: question2

    answer:
      first_name: John
      last_name: Smith

    answers: "{{ question.first_run.app|
                 map(attribute='name')|
                 map('extract', answer)|
                 map('community.general.dict_kv', 'answer') }}"
    app_update: "{{ question.first_run.app|
                    zip(answers)|
                    map('combine') }}"
    first_run_update: "{{ question.first_run|
                          combine({'app': app_update}) }}"
    

  tasks:

    - debug:
        var: answers
    - debug:
        var: app_update
    - debug:
        var: first_run_update

    - set_fact:
        question: "{{ question|
                      combine({'first_run': first_run_update}) }}"
    - debug:
        var: question

本番では宣言グループ変数

shell> cat group_vars/all/answers.yml 
answers: "{{ question.first_run.app|
             map(attribute='name')|
             map('extract', answer)|
             map('community.general.dict_kv', 'answer') }}"
app_update: "{{ question.first_run.app|
                zip(answers)|
                map('combine') }}"
question_update:
  first_run: "{{ question.first_run|
                 combine({'app': app_update}) }}"

データを入れる変わりやすい。たとえば、ファイルを生成します。

shell> cat qa.yml 
question:
  first_run:
    app:
    - answer: null
      name: first_name
      question: What is your First name?
    - answer: null
      name: last_name
      question: What is your Last name?
    core:
    - question: question1
    - question: question2

answer:
  first_name: John
  last_name: Smith

、スクリプトを簡素化

shell> cat pb.yml 
- hosts: all
  vars_files:
    - qa.yml
  tasks:
    - set_fact:
        question: "{{ question|combine(question_update) }}"
    - debug:
        var: question

スクリプトの実行

shell> ansible-playbook -l localhost pb.yml

おすすめ記事