azure icon indicating copy to clipboard operation
azure copied to clipboard

azure_rm_galleryimageversion: delete doesn't catch permission issues

Open achevalet opened this issue 3 years ago • 16 comments

SUMMARY

Delete image version fails silently.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

azure_rm_galleryimageversion

ANSIBLE VERSION
ansible [core 2.11.8] 
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
  jinja version = 2.11.3
  libyaml = True
COLLECTION VERSION
Collection         Version
------------------ -------
azure.azcollection 1.11.0 
OS / ENVIRONMENT

CentOS Linux release 7.9.2009

STEPS TO REPRODUCE
        - name: delete gallery image version
          azure_rm_galleryimageversion:
            state: absent
            resource_group: "{{ resource_group }}"
            gallery_name: "{{ image_gallery }}"
            location: "{{ image_location }}"
            gallery_image_name: "{{ image_name }}"
            name: "{{ image_version }}"
            publishing_profile:
              exclude_from_latest: no
              replica_count: "{{ regional_replica_count }}"
              storage_account_type: "{{ storage_account_type }}"
              target_regions:
                - name: "{{ image_location }}"
                  regional_replica_count: "{{ regional_replica_count }}"
                  storage_account_type: "{{ storage_account_type }}"
            storage_profile:
              source_image: "{{ image_name }}"
EXPECTED RESULTS

Image version is deleted.

ACTUAL RESULTS

Image version is not deleted and result is ok.

TASK [delete gallery image version] *******************************************************************************************************************************************************************************
[WARNING]: Azure API profile latest does not define an entry for GenericRestClient
ok: [localhost]

achevalet avatar Feb 15 '22 14:02 achevalet

Note that the image version to delete produces an error at creation, not sure if both issues are linked.

achevalet avatar Feb 15 '22 14:02 achevalet

just realized that it comes from a permission issue...

tested in same environment with az cli:

        - name: delete gallery image version
          ignore_errors: yes
          ansible.builtin.shell: |
            set -e
            az login --service-principal -u $AZURE_CLIENT_ID -p "$AZURE_SECRET" --tenant $AZURE_TENANT >/dev/null
            az account set --subscription $AZURE_SUBSCRIPTION_ID >/dev/null
            az sig image-version delete \
              --resource-group {{ resource_group }} \
              --gallery-name "{{ image_gallery }}" \
              --gallery-image-definition "{{ image_name }}" \
              --gallery-image-version "{{ image_version }}"

result:

stderr_lines": ["ForbiddenError: The client '...' with object id '...' does not have authorization to perform action 'Microsoft.Compute/galleries/images/versions/delete' over scope '/subscriptions/.../resourceGroups/images/providers/Microsoft.Compute/galleries/images/images/.../versions/1.10.1' or the scope is invalid. If access was recently granted, please refresh your credentials."]

Fixed by adding Microsoft.Compute/galleries/images/versions/delete permission.

achevalet avatar Feb 16 '22 21:02 achevalet

@achevalet Thank you for submitting this question? Could you please provide a complete Playbook and the implementation results? This will go a long way towards solving the problem. Thank you very much!

ansible-playbook ***.yml -vvv

Fred-sun avatar Feb 22 '22 12:02 Fred-sun

@Fred-sun I'm sorry but it would be full of redacted lines.. I think that the required information are listed in this ticket. Basically, if the user does not have the permission Microsoft.Compute/galleries/images/versions/delete, this module is not able to delete an image version (which is normal) but it does not return any error.

achevalet avatar Feb 23 '22 21:02 achevalet

@achevalet If it can't be delete it, I will definitely get an error. I executed YAML as follows and the created resource was deleted. Can you try it on? Thank you very much!

- name: Get a simple gallery Image Version info.
  azure_rm_galleryimageversion_info:
    resource_group: "{{ resource_group }}"
    gallery_name: myGallery{{ rpfx }}
    gallery_image_name: myImage
    name: 10.1.3
- name: Delete gallery image Version.
  azure_rm_galleryimageversion:
    resource_group: "{{ resource_group }}"
    gallery_name: myGallery{{ rpfx }}
    gallery_image_name: myImage
    name: 10.1.3
    state: absent

Fred-sun avatar Mar 02 '22 14:03 Fred-sun

Sorry for late answer. Yes, this code is working fine on my end as long as the Azure user has correct permissions. On Azure side, if you drop only the delete permission on images versions (Microsoft.Compute/galleries/images/versions/delete), keep read and create permissions, this code produces no error but does not actually delete the image version.

achevalet avatar Mar 25 '22 14:03 achevalet

Thank you for your reply, I think there is no problem with my local deletion. Could you do it again? First, use azure_rn_galleryImageversion_info to get related information, then delete, and help provide all -vvvv info and information in the register. Thank you very much!

ansible-playbook ****.yml -vvvv
- name: Get a simple gallery Image Version info.
  azure_rm_galleryimageversion_info:
    resource_group: "{{ resource_group }}"
    gallery_name: myGallery{{ rpfx }}
    gallery_image_name: myImage
    name: 10.1.3
  register: output
- debug:
      var: output

Fred-sun avatar Mar 31 '22 02:03 Fred-sun

Sorry again, I don't have any test environment right now. Basically, to be able to reproduce this bug, az cli must produce this error when you try to delete the image:

stderr_lines": ["ForbiddenError: The client '...' with object id '...' does not have authorization to perform action 'Microsoft.Compute/galleries/images/versions/delete' over scope '/subscriptions/.../resourceGroups/images/providers/Microsoft.Compute/galleries/images/images/.../versions/1.10.1' or the scope is invalid. If access was recently granted, please refresh your credentials."]

It occurs only if you use a service principal with limited access to connect to Azure API. This "user" is defined in the environment variable $AZURE_CLIENT_ID used by the ansible module for authentication. You must set read and write permission but not delete to be able to repoduce.

Please let me know if verbose mode still needed, I could send it later if needed.

achevalet avatar Mar 31 '22 19:03 achevalet

I am seeing a similar issue with collection version 1.13.0, but I am authenticated with an MSI that has contributor role over the whole subscription and using the CLI to delete the gallery image version works.

- name: List all gallery {{ image_name }} versions
  azure.azcollection.azure_rm_galleryimageversion_info:
    gallery_name: "{{ azure.sig_name }}"
    gallery_image_name: "{{ image_name }}"
    resource_group: "{{ azure.sig_resource_group }}"
  register: sig_image

- name: sorting all gallery {{ image_name }} versions
  set_fact:
    sig_image_sorted: "{{ sig_image.versions | sort(attribute='publishing_profile.publishedDate') }}"
  when: sig_image |length > 0

- name: Remove old {{ image_name }} versions
  azure.azcollection.azure_rm_galleryimageversion:
    gallery_name: "{{ azure.sig_name }}"
    gallery_image_name: "{{ image_name }}"
    location: "{{ azure.location }}"
    name: "{{ version_item.name }}*"
    resource_group: "{{ azure.sig_resource_group }}"
    state: absent
  loop: "{{ sig_image_sorted[:-(azure.versions_to_keep|int)] }}"
  loop_control:
    label: "{{ version_item.name }}"
    loop_var: version_item

The task to delete the old versions has this output

TASK [retire-base-images : Remove old com.lgc.windows2012.base versions] *******
Thursday 14 July 2022  10:54:04 +0000 (0:00:00.168)       0:00:09.924 ********* 
ok: [localhost] => (item=21.02.17)

Here's debug output of that task

    83 1657807441.69273:  ^ task is: TASK: retire-base-images : Remove old {{ image_name }} versions
    83 1657807441.69283:  ^ state is: HOST STATE: block=2, task=3, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (HOST STATE: block=0, task=5, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (HOST STATE: block=0, task=1, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (None), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False
    83 1657807441.69288: done building task lists
    83 1657807441.69293: counting tasks in each state of execution
    83 1657807441.69300: done counting tasks in each state of execution:
	num_setups: 0
	num_tasks: 1
	num_rescue: 0
	num_always: 0
    83 1657807441.69306: advancing hosts in ITERATING_TASKS
    83 1657807441.69310: starting to advance hosts
    83 1657807441.69314: getting the next task for host localhost
    83 1657807441.69327: done getting next task for host localhost
    83 1657807441.69334:  ^ task is: TASK: retire-base-images : Remove old {{ image_name }} versions
    83 1657807441.69341:  ^ state is: HOST STATE: block=2, task=3, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (HOST STATE: block=0, task=5, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (HOST STATE: block=0, task=1, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child state? (None), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False
    83 1657807441.69346: done advancing hosts to next task
    83 1657807441.69351: getting variables
    83 1657807441.69355: in VariableManager get_vars()
    83 1657807441.69384: Calling all_inventory to load vars for localhost
    83 1657807441.69395: Calling groups_inventory to load vars for localhost
    83 1657807441.69401: Calling all_plugins_inventory to load vars for localhost
    83 1657807441.70307: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.70712: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.70723: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.70792: Calling all_plugins_play to load vars for localhost
    83 1657807441.71621: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.71960: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.71968: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.72018: Calling groups_plugins_inventory to load vars for localhost
    83 1657807441.72809: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.73169: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.73178: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.73208: Calling groups_plugins_play to load vars for localhost
    83 1657807441.74123: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.74461: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.74470: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.75530: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.75939: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.75948: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.76882: Loading ModuleDocFragment 'vars_plugin_staging' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/vars_plugin_staging.py (found_in_cache=True, class_only=False)
    83 1657807441.77261: Loaded config def from plugin (vars/host_group_vars)
    83 1657807441.77269: Loading VarsModule 'host_group_vars' from /usr/lib/python3.8/site-packages/ansible/plugins/vars/host_group_vars.py (found_in_cache=True, class_only=False)
    83 1657807441.77832: done with get_vars()
    83 1657807441.77860: done getting variables
    83 1657807441.77953: sending task start callback, copying the task so we can template it temporarily
    83 1657807441.77966: done copying, going to template now
    83 1657807441.78122: variable 'image_name' from source: include params
    83 1657807441.78133: variable 'item' from source: include params
    83 1657807441.78213: variable 'item' from source: include params
    83 1657807441.78229: done templating
    83 1657807441.78235: here goes the callback...
TASK [retire-base-images : Remove old com.lgc.windows2012.base versions] *******
Thursday 14 July 2022  14:04:01 +0000 (0:00:00.174)       0:00:10.438 ********* 
    83 1657807441.78272: sending task start callback
    83 1657807441.78278: entering _queue_task() for localhost/azure.azcollection.azure_rm_galleryimageversion
    83 1657807441.78284: Creating lock for azure.azcollection.azure_rm_galleryimageversion
    83 1657807441.78592: worker is 1 (out of 1 available)
    83 1657807441.78658: exiting _queue_task() for localhost/azure.azcollection.azure_rm_galleryimageversion
    83 1657807441.78772: done queuing things up, now waiting for results queue to drain
    83 1657807441.78781: waiting for pending results...
   187 1657807441.78847: running TaskExecutor() for localhost/TASK: retire-base-images : Remove old {{ image_name }} versions
   187 1657807441.78952: in run() - task 0242ac11-0003-677f-a7a8-000000000051
   187 1657807441.78976: variable 'ansible_search_path' from source: unknown
   187 1657807441.78983: variable 'ansible_search_path' from source: unknown
   187 1657807441.81388: Loading FilterModule 'core' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/core.py
   187 1657807441.81449: Loading FilterModule 'encryption' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/encryption.py
   187 1657807441.81508: Loading FilterModule 'mathstuff' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/mathstuff.py
   187 1657807441.81563: Loading FilterModule 'urls' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/urls.py
   187 1657807441.81606: Loading FilterModule 'urlsplit' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/urlsplit.py
   187 1657807441.81872: variable 'sig_image_sorted' from source: set_fact
   187 1657807441.81959: variable 'azure' from source: role '' defaults
   187 1657807441.82296: trying /usr/lib/python3.8/site-packages/ansible/plugins/lookup
   187 1657807441.82955: Loaded config def from plugin (lookup/env)
   187 1657807441.82965: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py
   187 1657807441.83691: Loaded config def from plugin (lookup/env)
   187 1657807441.83706: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.84462: Loaded config def from plugin (lookup/env)
   187 1657807441.84472: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.84825: variable 'ansible_connection' from source: host vars for 'localhost'
   187 1657807441.84850: variable 'omit' from source: magic vars
   187 1657807441.85179: variable 'dry_run' from source: role '' defaults
   187 1657807441.85331: Loading FilterModule 'core' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/core.py (found_in_cache=True, class_only=False)
   187 1657807441.85341: Loading FilterModule 'encryption' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/encryption.py (found_in_cache=True, class_only=False)
   187 1657807441.85354: Loading FilterModule 'mathstuff' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/mathstuff.py (found_in_cache=True, class_only=False)
   187 1657807441.85364: Loading FilterModule 'urls' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/urls.py (found_in_cache=True, class_only=False)
   187 1657807441.85371: Loading FilterModule 'urlsplit' from /usr/lib/python3.8/site-packages/ansible/plugins/filter/urlsplit.py (found_in_cache=True, class_only=False)
   187 1657807441.86030: Loaded config def from plugin (lookup/env)
   187 1657807441.86043: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.86083: Evaluated conditional (not dry_run): True
   187 1657807441.86093: variable 'omit' from source: magic vars
   187 1657807441.86198: variable 'image_name' from source: include params
   187 1657807441.86208: variable 'item' from source: include params
   187 1657807441.86297: variable 'item' from source: include params
   187 1657807441.86351: variable 'omit' from source: magic vars
   187 1657807441.86455: variable 'azure' from source: role '' defaults
   187 1657807441.87111: Loaded config def from plugin (lookup/env)
   187 1657807441.87123: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.87904: Loaded config def from plugin (lookup/env)
   187 1657807441.87924: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.88587: Loaded config def from plugin (lookup/env)
   187 1657807441.88597: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.88641: variable 'image_name' from source: include params
   187 1657807441.88739: variable 'image_name' from source: include params
   187 1657807441.88749: variable 'item' from source: include params
   187 1657807441.88883: variable 'azure' from source: role '' defaults
   187 1657807441.89529: Loaded config def from plugin (lookup/env)
   187 1657807441.89540: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.90180: Loaded config def from plugin (lookup/env)
   187 1657807441.90190: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.90879: Loaded config def from plugin (lookup/env)
   187 1657807441.90889: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.91027: variable 'version_item' from source: unknown
   187 1657807441.91148: variable 'azure' from source: role '' defaults
   187 1657807441.91822: Loaded config def from plugin (lookup/env)
   187 1657807441.91833: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.92498: Loaded config def from plugin (lookup/env)
   187 1657807441.92508: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.93256: Loaded config def from plugin (lookup/env)
   187 1657807441.93267: Loading LookupModule 'env' from /usr/lib/python3.8/site-packages/ansible/plugins/lookup/env.py (found_in_cache=True, class_only=False)
   187 1657807441.93329: variable 'omit' from source: magic vars
   187 1657807441.93475: variable 'image_name' from source: include params
   187 1657807441.93486: variable 'item' from source: include params
   187 1657807441.93549: variable 'ansible_connection' from source: host vars for 'localhost'
   187 1657807441.93556: variable 'ansible_connection' from source: host vars for 'localhost'
   187 1657807441.93580: trying /usr/lib/python3.8/site-packages/ansible/plugins/connection
   187 1657807441.93927: Loading ModuleDocFragment 'connection_pipelining' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/connection_pipelining.py (found_in_cache=True, class_only=False)
   187 1657807441.94438: Loaded config def from plugin (connection/local)
   187 1657807441.94450: Loading Connection 'local' from /usr/lib/python3.8/site-packages/ansible/plugins/connection/local.py (found_in_cache=True, class_only=False)
   187 1657807441.94476: trying /usr/lib/python3.8/site-packages/ansible/plugins/shell
   187 1657807441.94679: Loading ModuleDocFragment 'shell_common' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/shell_common.py (found_in_cache=True, class_only=False)
   187 1657807441.96856: Loaded config def from plugin (shell/sh)
   187 1657807441.96878: Loading ShellModule 'sh' from /usr/lib/python3.8/site-packages/ansible/plugins/shell/sh.py (found_in_cache=True, class_only=False)
   187 1657807441.97070: Loading ModuleDocFragment 'shell_common' from /usr/lib/python3.8/site-packages/ansible/plugins/doc_fragments/shell_common.py (found_in_cache=True, class_only=False)
   187 1657807441.99285: Loaded config def from plugin (shell/sh)
   187 1657807441.99296: Loading ShellModule 'sh' from /usr/lib/python3.8/site-packages/ansible/plugins/shell/sh.py (found_in_cache=True, class_only=False)
   187 1657807441.99325: variable 'ansible_pipelining' from source: unknown
   187 1657807441.99641: Loading ActionModule 'normal' from /usr/lib/python3.8/site-packages/ansible/plugins/action/normal.py (searched paths: /usr/lib/python3.8/site-packages/ansible/plugins/action/__pycache__:/usr/lib/python3.8/site-packages/ansible/plugins/action)
   187 1657807441.99663: variable 'omit' from source: magic vars
   187 1657807441.99683: starting attempt loop
   187 1657807441.99690: running the handler
   187 1657807441.99718: _low_level_execute_command(): starting
   187 1657807441.99732: _low_level_execute_command(): executing: /bin/sh -c 'echo ~root && sleep 0'
   187 1657807441.99751: in local.exec_command()
   187 1657807441.99760: opening command with Popen()
   187 1657807442.00154: done running command with Popen()
   187 1657807442.00174: getting output with communicate()
   187 1657807442.00397: done communicating
   187 1657807442.00408: done with local.exec_command()
   187 1657807442.00424: _low_level_execute_command() done: rc=0, stdout=/root, stderr=
   187 1657807442.00448: _low_level_execute_command(): starting
   187 1657807442.00478: _low_level_execute_command(): executing: /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095 `" && echo ansible-tmp-1657807442.0043871-187-52252793169095="` echo /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095 `" ) && sleep 0'
   187 1657807442.00489: in local.exec_command()
   187 1657807442.00500: opening command with Popen()
   187 1657807442.00745: done running command with Popen()
   187 1657807442.00766: getting output with communicate()
   187 1657807442.01391: done communicating
   187 1657807442.01400: done with local.exec_command()
   187 1657807442.01411: _low_level_execute_command() done: rc=0, stdout=ansible-tmp-1657807442.0043871-187-52252793169095=/root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095, stderr=
   187 1657807442.01651: ANSIBALLZ: Using lock for azure.azcollection.azure_rm_galleryimageversion
   187 1657807442.01660: ANSIBALLZ: Acquiring lock
   187 1657807442.01667: ANSIBALLZ: Lock acquired: 140584859734464
   187 1657807442.01673: ANSIBALLZ: Creating module
   187 1657807442.27952: ANSIBALLZ: Writing module into payload
   187 1657807442.28157: ANSIBALLZ: Writing module
   187 1657807442.28197: ANSIBALLZ: Renaming module
   187 1657807442.28232: ANSIBALLZ: Done creating module
   187 1657807442.28259: variable 'ansible_python_interpreter' from source: host vars for 'localhost'
   187 1657807442.28355: transferring module to remote /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/AnsiballZ_azure_rm_galleryimageversion.py
   187 1657807442.28491: done transferring module to remote
   187 1657807442.28522: _low_level_execute_command(): starting
   187 1657807442.28535: _low_level_execute_command(): executing: /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/ /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/AnsiballZ_azure_rm_galleryimageversion.py && sleep 0'
   187 1657807442.28544: in local.exec_command()
   187 1657807442.28553: opening command with Popen()
   187 1657807442.28916: done running command with Popen()
   187 1657807442.28940: getting output with communicate()
   187 1657807442.29256: done communicating
   187 1657807442.29265: done with local.exec_command()
   187 1657807442.29275: _low_level_execute_command() done: rc=0, stdout=, stderr=
   187 1657807442.29283: _low_level_execute_command(): starting
   187 1657807442.29305: _low_level_execute_command(): executing: /bin/sh -c '/usr/bin/python3 /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/AnsiballZ_azure_rm_galleryimageversion.py && sleep 0'
   187 1657807442.29317: in local.exec_command()
   187 1657807442.29329: opening command with Popen()
   187 1657807442.29606: done running command with Popen()
   187 1657807442.29628: getting output with communicate()
   187 1657807444.09882: done communicating
   187 1657807444.09897: done with local.exec_command()
   187 1657807444.09913: _low_level_execute_command() done: rc=0, stdout={"changed": false, "invocation": {"module_args": {"gallery_name": "BASE_IMAGES", "gallery_image_name": "com.lgc.windows2012.base", "location": "southcentralus", "name": "21.02.17*", "resource_group": "MY-SUBSCRIPTION-SIG", "state": "absent", "auth_source": "msi", "cloud_environment": "AzureCloud", "api_profile": "latest", "append_tags": true, "profile": null, "subscription_id": null, "client_id": null, "secret": null, "tenant": null, "ad_user": null, "password": null, "cert_validation_mode": null, "adfs_authority_url": null, "log_mode": null, "log_path": null, "tags": null, "storage_profile": null, "publishing_profile": null}}, "warnings": ["Azure API profile latest does not define an entry for GenericRestClient"]}, stderr=
   187 1657807444.09976: done with _execute_module (azure.azcollection.azure_rm_galleryimageversion, {'gallery_name': 'BASE_IMAGES', 'gallery_image_name': 'com.lgc.windows2012.base', 'location': 'southcentralus', 'name': '21.02.17*', 'resource_group': 'MY-SUBSCRIPTION-SIG', 'state': 'absent', '_ansible_check_mode': False, '_ansible_no_log': False, '_ansible_debug': True, '_ansible_diff': False, '_ansible_verbosity': 0, '_ansible_version': '2.12.7', '_ansible_module_name': 'azure.azcollection.azure_rm_galleryimageversion', '_ansible_syslog_facility': 'LOG_USER', '_ansible_selinux_special_fs': ['fuse', 'nfs', 'vboxsf', 'ramfs', '9p', 'vfat'], '_ansible_string_conversion_action': 'warn', '_ansible_socket': None, '_ansible_shell_executable': '/bin/sh', '_ansible_keep_remote_files': False, '_ansible_tmpdir': '/root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/', '_ansible_remote_tmp': '~/.ansible/tmp'})
   187 1657807444.10000: _low_level_execute_command(): starting
   187 1657807444.10028: _low_level_execute_command(): executing: /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1657807442.0043871-187-52252793169095/ > /dev/null 2>&1 && sleep 0'
   187 1657807444.10039: in local.exec_command()
   187 1657807444.10052: opening command with Popen()
   187 1657807444.10397: done running command with Popen()
   187 1657807444.10422: getting output with communicate()
   187 1657807444.10834: done communicating
   187 1657807444.10844: done with local.exec_command()
   187 1657807444.10854: _low_level_execute_command() done: rc=0, stdout=, stderr=
   187 1657807444.10866: handler run complete
   187 1657807444.10904: attempt loop complete, returning result
   187 1657807444.11140: variable 'version_item' from source: unknown
   187 1657807444.11281: dumping result to json
   187 1657807444.11388: done dumping result, returning
   187 1657807444.11411: done running TaskExecutor() for localhost/TASK: retire-base-images : Remove old {{ image_name }} versions [0242ac11-0003-677f-a7a8-000000000051]
   187 1657807444.11422: sending task result for task 0242ac11-0003-677f-a7a8-000000000051
   187 1657807444.11438: done sending task result for task 0242ac11-0003-677f-a7a8-000000000051
   187 1657807444.11495: WORKER PROCESS EXITING
ok: [localhost] => (item=21.02.17)

jghal avatar Jul 14 '22 13:07 jghal

@achevalet @jghal Thank you for submitting the problem, but I can remove it after repeated testing locally. 'OK' is returned when the image version number does not exist. Can you check if the resource exists before deleting it? Thank you very much!

Check resource exist or not:
- name: Get a simple gallery Image Version info
  azure_rm_galleryimageversion_info:
    resource_group: "{{ resource_group }}"
    gallery_name: myGallery{{ rpfx }}
    gallery_image_name: myImage
    name: "{{ imageversion_name }}"
  register: output

- name: Print imageverison info
  debug:
    var: output

Fred-sun avatar Jul 15 '22 07:07 Fred-sun

If you review my code snippet you'll see the input to the azure_rm_galleryimageversion to delete image versions is the sorted output of the azure_rm_galleryimageversion_info task, and therefore the version must exist, but the task to delete doesn't delete it or return an error.

$ az sig image-version list -g MY-SUBSCRIPTION-SIG -r BASE_IMAGES -i com.lgc.windows2012.base --query '[].name'
[
  "21.02.17",
  "21.11.16",
  "22.02.10",
  "22.04.18"
]

jghal avatar Jul 15 '22 13:07 jghal

@Fred-sun I was able to move forward by using the uri task to call the Azure gallery-image-version DELETE API.

jghal avatar Jul 28 '22 13:07 jghal

@Now that it has been solved, I cannot copy the current problem. I suggest closing it temporarily and opening it when there is a new problem. Thank you very much!

Fred-sun avatar Sep 21 '22 10:09 Fred-sun

The problem isn't solved, merely avoided by not using the collection's module for that task.

jghal avatar Sep 21 '22 13:09 jghal

@jghal @achevalet However, in my local test, it can be deleted. In addition, after you delete it, wait for 10 minutes and check again, because the service needs some time to complete this operation. Could you try it again? Thank you very much!

Fred-sun avatar Sep 22 '22 01:09 Fred-sun

The problem is not solved and I can't explain my use-case better than above.

achevalet avatar Sep 22 '22 07:09 achevalet

@jghal I got your code snippet to work after removing the "*" after the name from this part: name: "{{ version_item.name }}*" so it became: name: "{{ version_item.name }}"

smirgel avatar Dec 20 '22 12:12 smirgel

@jghal The suggestion of the above comment is correct, your script multiple symbols '*'. Thank you!

Fred-sun avatar Apr 04 '23 02:04 Fred-sun