azure-sdk-for-python: Empty repository in container registry causes unexpected SDK issue when trying to list tags
- Package Name: azure-containerregistry
- Package Version: 1.0.0
- Operating System: macOS 13.1
- Python Version: 3.9.6
Describe the bug
When trying to list the tags on an empty container registry repository (all tags have been removed), the SDK produces the unexpected error TypeError: 'NoneType' object is not iterable
. The error is thrown when trying to iterate on a non-none object of type azure.core.paging.ItemPaged
, which is what is unexpected.
To Reproduce Steps to reproduce the behavior:
-
Delete all tags for a container registry’s repository.
-
Try and use the SDK to list tags for the empty repository. The issue will come when try to iterate on the response (even if a check for
None
is done prior):client = ContainerRegistryClient(endpoint=registry_endpoint, credential=credentials, audience="https://management.azure.com") response = client.list_tag_properties(repository=repository_name) if response is not None: for tag in response: # <--- error occurs here - TypeError: 'NoneType' object is not iterable print("\t" + tag.name)
I have created a script which reproduces the issue, which also includes setup of a registry/repository for testing. See below for more detail.
Expected behavior
The SDK should either not throw an issue when trying to iterate on the tag response (ItemPaged
type) OR return a NoneType
response so that appropriate checks can be added by client applications.
Screenshots
Below is a screenshot in Azure portal of a repository which has had all tags removed:
Using the SDK to list tags for “my-test-repository” causes the above issue to occur.
Additional context
I’ve created a script which completely initializes a container registry and and puts it in the desired state, and then reproduces the error.
-
Install required dependencies:
azure-containerregistry==1.0.0 azure-identity==1.12.0 azure-mgmt-containerregistry==10.0.0
-
Create environment variables for test script, and populate with environment-specific values.
export AZURE_SUBSCRIPTION_ID=xxx export AZURE_CLIENT_ID=xxx export AZURE_CLIENT_SECRET=xxx export AZURE_TENANT_ID=xxx export AZURE_RESOURCE_GROUP=xxx export AZURE_REGISTRY_NAME=xxx
-
Run the following script to recreate the issue. The script will autocreate the container registry (and repository) if it doesn’t exist. The script will then try and list tags for the empty repository.
#!/usr/bin/python import os from azure.identity._credentials import client_secret from azure.containerregistry import ContainerRegistryClient from azure.mgmt.containerregistry import ContainerRegistryManagementClient from azure.core.exceptions import ResourceNotFoundError from azure.mgmt.containerregistry.models import (RegistryNameCheckRequest, Registry, Sku, ImportImageParameters, ImportSource) subscription_id = os.environ.get('AZURE_SUBSCRIPTION_ID', 'xxx') credentials = client_secret.ClientSecretCredential( client_id=os.environ.get('AZURE_CLIENT_ID', 'xxx'), client_secret=os.environ.get('AZURE_CLIENT_SECRET', 'xxx'), tenant_id=os.environ.get('AZURE_TENANT_ID', 'xxx'), ) registry_name = os.environ.get('AZURE_REGISTRY_NAME', 'xxx') registry_endpoint = registry_name + ".azurecr.io" repository_name = "my-test-repository" def list_tags(): print(f"listing tags for repository {repository_name} in registry {registry_name}") client = ContainerRegistryClient(endpoint=registry_endpoint, credential=credentials, audience="https://management.azure.com") response = client.list_tag_properties(repository=repository_name) if response is not None: for tag in response: print("\t" + tag.name) else: print('response is none') def initialize_registry(): resource_group = os.environ.get('AZURE_RESOURCE_GROUP', 'xxx') mgmt_client = ContainerRegistryManagementClient(credential=credentials, subscription_id=subscription_id) print(f"checking for registry '{registry_name}' in resource group '{resource_group}'") try: registry = mgmt_client.registries.get(resource_group_name=resource_group, registry_name=registry_name) except ResourceNotFoundError: registry = None if registry is None: print(f"registry '{registry_name}' does not exist; checking for name availability") status = mgmt_client.registries.check_name_availability(registry_name_check_request=RegistryNameCheckRequest(name=registry_name)) if status.name_available: print(f"creating registry '{registry_name}'") poller = mgmt_client.registries.begin_create(resource_group_name=resource_group, registry_name=registry_name, registry= Registry(location="eastus", sku=Sku(name="Basic")) ) while not poller.done(): poller.wait(timeout=5) registry = poller.result() print(f"registry '{registry_name}' created!") else: print(f"name '{registry_name}' is unavailable, please use a different one!") exit(1) print(f"registry '{registry_name}' exists, checking for repository '{repository_name}'") client = ContainerRegistryClient(endpoint=registry_endpoint, credential=credentials, audience="https://management.azure.com") try: repository = client.get_repository_properties(repository=repository_name) except ResourceNotFoundError: repository = None test_image = "hello-world:latest" if repository is None: print(f"creating repository '{repository_name}' by importing test image '{test_image}'") params = ImportImageParameters( target_tags=[repository_name + ":latest"], source=ImportSource( registry_uri="docker.io", source_image="library/" + test_image, ) ) poller = mgmt_client.registries.begin_import_image(resource_group_name=resource_group, registry_name=registry_name, parameters=params) while not poller.done(): poller.wait(timeout=5) print(f"test image {test_image} successfully imported to '{repository_name}'") print(f"ensuring test image '{test_image}' is removed from repository '{repository_name}'") client.delete_tag(repository=repository_name, tag="latest") print(f"repository '{repository_name}' is empty and ready for recreating the issue!\n") initialize_registry() list_tags()
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 15 (6 by maintainers)
Sorry I didn’t respond sooner, but I have tested the beta version and can confirm it is working! Thank you!!
When will a stable release occur with the same?
/unresolve
Hi @l3ender , we are working on it. You can expect it get fix in our next preview release.