title: ansible updating a YAML file using set_fact/update_fact
body: <p>My ansible project consists of 6 roles (app, db, init, ror, tick, web). Each role represents the installation of one component of the system. Each device keeps track of which roles have been installed using the file &quot;/etc/ansible/ansible-install-state.yml&quot;. It's initial contents are:</p>
  <pre><code># ansible-install-state.yml
  #
  #
  # This file is maintained by Ansible
  # Please leave it alone, or accept the consequences!
  #
  
  roles:
    app:
      installed: false
    db:
      installed: false
    init:
      installed: false
    ror:
      installed: false
    tick:
      installed: false
    web:        
      installed: false
  </code></pre>
  <p>At the completion of the 'init' role, I want to process the file to update the installed state to 'true'. I do that with the following call. (For testing, I'm also setting 'ror: true' and adding a new role 'new: unknown'</p>
  <pre><code>  - name: System Init | Process ansible_install_state
      ansible.builtin.include_tasks:  process_ansible_install_state.yml
      with_items:
        - role: { key: init, value: true }
        - role: { key: ror, value: true }
        - role: { key: new, value: unknown}
   
  </code></pre>
  <p>Updating existing roles went fairly smoothly, but adding a new role did not. I finally got it to work by first adding the role itself, essentially 'new: {}', then modifying it again to add the 'installed: unknown' part.  Although this does work, I can't help but believe there's a better way - a way to do it all at once. Following is the process_enable_install_state.yml file.</p>
  <pre><code>---
  # process_ansible_install_state.yml
  
  #
  #------------------------- Process Ansible Install State File
  #
  
  - name: display variable
    debug: 
      var: item
  
  # See https://stackoverflow.com/questions/32994002/is-there-a-yaml-editing-module-for-ansible
  - name: Ansible Install State | Read ansible-install-state.yml  
    ansible.builtin.slurp: 
      path: &quot;/etc/ansible/ansible-install-state.yml&quot;
    register: install_state
  
  - name: Ansible Install State | Decode and save yaml as fact
    ansible.builtin.set_fact:
      my_roles: &quot;{{ install_state['content'] | b64decode | from_yaml }}&quot;
    register: its_a_fact
  
  - name: Ansible Install State | Save the new ROLE block
    block: 
   
    - name: Ansible Install State |  Save the new role
      ansible.utils.update_fact:
        updates:
        - path: my_roles.roles.{{ item.role.key }}
          value: {}
      register: updated
  
    # Update_fact does not update 'in place', so we need to save it as a fact
    - name: Ansible Install State | Update the saved 'fact'
      ansible.builtin.set_fact:
        my_roles: &quot;{{ updated.my_roles}}&quot;
  
    when: my_roles.roles[item.role.key] is undefined
  
  - name: debug
    debug: 
      var: updated
  
  - name: Ansible Install State | Update the role's installed state
    ansible.utils.update_fact:
      updates:
      - path: my_roles.roles.{{ item.role.key }}.installed
        value: &quot;{{item.role.value}}&quot;
    register: updated
  
  - name: debug
    debug: 
      var: updated
  
  # Update_fact does not update 'in place', so we need to save it as a fact
  - name: Ansible Install State | Save modified as 'fact'
    ansible.builtin.set_fact:
      my_roles: &quot;{{ updated.my_roles}}&quot;
  
  - name: Ansible Install State | Write Yaml File
    ansible.builtin.copy:    
      content: '{{ my_roles | to_nice_yaml }}'
      dest: &quot;/etc/ansible/ansible-install-state.yml&quot; 
  
  - name: Ansible Install State | Insert Header Comments
    ansible.builtin.blockinfile:
      path: &quot;/etc/ansible/ansible-install-state.yml&quot;
      insertbefore: BOF
      marker: &quot;#{mark}&quot;
      marker_begin: &quot;-------------------------------------------&quot;
      marker_end:   &quot;-------------------------------------------&quot;
      block: |
        # ansible-install-state.yml
        #
        #
        # This file is maintained by Ansible
        # Please leave it alone, or accept the consequences!
        #
        #
  
  
  </code></pre>
  <p>This successfully produced...</p>
  <pre><code># ansible-install-state.yml
  #
  #
  # This file is maintained by Ansible
  # Please leave it alone, or accept the consequences!
  #
  #
  #-------------------------------------------
  roles:
      app:
          installed: false
      db:
          installed: false
      init:
          installed: true
      new:
          installed: unknown
      ror:
          installed: true
      tick:
          installed: false
      web:
          installed: false
  deploy@rpi-tick2:/etc/ansible $ 
  
  </code></pre>