Search code examples
ansiblepodman

Ansible Compare registered variables and set fact


I'm rather newish to ansible and podman, and don't have a full grasp of python. So, I came up to a bit of a block on how to gather a list of container images on a system, and remove them. However only remove the image if no running container is using that image.

My initial tasks, which does work, looks like this:

- name: Gather facts about all container images
  containers.podman.podman_image_info:
  register: image_info

- name: remove images no longer used
  containers.podman.podman_image:
    name: "{{ item.Id }}"
    state: absent
  loop: "{{ image_info.images }}"
  loop_control:
    label: "{{ item.Id }}"
  ignore_errors: true

However, This is not perfect, as the task will fail once it gets to an image that is in use, this is why ignore_errors: true is set. I also do not want the large block of error output (about 200+ lines) this provides when it does fail. Overall this does what I intended it to.

My next step in this "evolution" of code is how to remove the large error output without using no_log: true or anything similar, if possible. My thought is to compare a list of the image IDs I'm all ready gathering, to that of the running containers images. I updated the code to gather information on the containers on the system.

- name: Gather facts about all container images
  containers.podman.podman_image_info:
  register: image_info

- name: gather container info
  containers.podman.podman_container_info:
  register: container_info

- name: remove images no longer used
  containers.podman.podman_image:
    name: "{{ item.Id }}"
    state: absent
  loop: "{{ image_info.images }}"
  loop_control:
    label: "{{ item.Id }}"
  ignore_errors: true

Then debugging the output of the container_info variable I do see the image ID, which ends up something like container_info.containers[0].Image as a variable I can use. My thought now is that I can use this to remove the image IDs that are in use from the list of images I have.

Here is my block, I'm not sure how I can, create this new image list with the info I have. I know I'll have to use set_facts for this, but is it possible to loop though two different lists in a task? Or am I overthinking this and a simpler way exists that I'm not aware of. All I really want to do is avoid needing to use ignore_errors in my code.

Update: I have setting the facts down. which looks like the following in my playbook:

- name: Setting facts for image IDs
  set_fact:
    image_id: "{{ image_info.images | json_query('[].Id') }}"

- name: Setting fact for Container image ID
  set_fact:
    container_id: "{{ container_info.containers | json_query('[].Image') }}"

This ends up giving me the following info when debuged.

TASK [docker-host : debug image_id] ***********************************************************************************************************************************************************************
ok: [dtest05] =>
  image_id:
  - 4bc0467496b6c7a60543069c570ef0e1be4565d25cb2bc7d524600a5fe0d3b8f
  - c223664c734cbbc7213a4312af596b37a5bf5e55f93526bcb34e527efc9c4d5b
  - dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
  - e911c149c0ca46a11a8b6eb604439e972685ec25abfde07eb1cdb272a9c0d1a9
  - eb40451959b6c5f4aebb2b687a589a58370faab9b15faa43c0aea8d711155b9e

TASK [docker-host : debug container_id] *******************************************************************************************************************************************************************
ok: [dtest05] =>
  container_id:
  - dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6

I think I just need to set another fact that will remove duplicates.

Update2: Created another fact to "merge" the two other facts. Full playbook looks like this:

- name: Gather facts about all container images
  containers.podman.podman_image_info:
  register: image_info

- name: gather container info
  containers.podman.podman_container_info:
  register: container_info

- name: Setting Facts for Image IDs
  set_fact:
    image_id: "{{ image_info.images | json_query('[].Id') }}"
    container_id: "{{ container_info.containers | json_query('[].Image') }}"

- name: Merging facts
  set_fact:
    merged_ids: "{{ image_id }} + {{ container_id }}"

Then the merged_id variable outputs the following:

  merged_ids:
  - 4bc0467496b6c7a60543069c570ef0e1be4565d25cb2bc7d524600a5fe0d3b8f
  - c223664c734cbbc7213a4312af596b37a5bf5e55f93526bcb34e527efc9c4d5b
  - dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6
  - e911c149c0ca46a11a8b6eb604439e972685ec25abfde07eb1cdb272a9c0d1a9
  - eb40451959b6c5f4aebb2b687a589a58370faab9b15faa43c0aea8d711155b9e
  - dbcefaa52e7009f5d9b6179a256e70890d29148add0f77741ca4550ba2e2ffa6

I can see the duplicate IDs in the list. How do I remove the duplicate IDs from the merged_ids variable list?


Solution

  • There's a problem with your "Merging facts" tasks. You're not creating a merged list of values; you are in fact concatenating two strings. You want:

    - name: Merging facts
      set_fact:
        merged_ids: "{{ image_id + container_id }}"
    

    There is a unique filter you can use to unique-ify a list:

    - name: Merging facts
      set_fact:
        merged_ids: "{{ image_id + container_id | unique }}"