Azure / azure-cli

Azure Command-Line Interface
MIT License
4.02k stars 2.99k forks source link

az vm image terms: check for missing version in URN #26703

Open jrtknauer opened 1 year ago

jrtknauer commented 1 year ago

The Command

az vm image terms and its subcommands.

The Issue

az vm image terms and its subcommands can be issued with either individual options to specify the marketplace product (--offer, --plan, etc.) - or instead provide the fully qualified URN using --urn. However, when passing a malformed URN, such as one that is missing the version component, the command hard fails:

# Example URN which works as intended
$ az vm image terms show --urn Canonical:0001-com-ubuntu-pro-jammy:pro-22_04-lts:22.04.202305310

# Example URN which hard fails with a less than obvious error message
$ az vm image terms show --urn Canonical:0001-com-ubuntu-pro-jammy:pro-22_04-lts:
The command failed with an unexpected error. Here is the traceback:
(", AttributeError: 'list' object has no attribute 'get'", 'Unable to deserialize to object: type', AttributeError("'list' object has no attribute 'get'"))
Traceback (most recent call last):
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1430, in _deserialize
    found_value = key_extractor(attr, attr_desc, data)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1177, in rest_key_extractor
    return working_data.get(key)
AttributeError: 'list' object has no attribute 'get'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/az/lib/python3.10/site-packages/knack/cli.py", line 233, in invoke
    cmd_result = self.invocation.execute(args)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 663, in execute
    raise ex
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 726, in _run_jobs_serially
    results.append(self._run_job(expanded_arg, cmd_copy))
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 697, in _run_job
    result = cmd_copy(params)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 333, in __call__
    return self.handler(*args, **kwargs)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/command_operation.py", line 363, in handler
    show_exception_handler(ex)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/arm.py", line 429, in show_exception_handler
    raise ex
  File "/opt/az/lib/python3.10/site-packages/azure/cli/core/commands/command_operation.py", line 361, in handler
    return op(**command_args)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/command_modules/vm/custom.py", line 2441, in get_terms
    publisher, offer, plan = _terms_prepare(cmd, urn, publisher, offer, plan)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/command_modules/vm/custom.py", line 2377, in _terms_prepare
    image = show_vm_image(cmd, urn)
  File "/opt/az/lib/python3.10/site-packages/azure/cli/command_modules/vm/custom.py", line 2327, in show_vm_image
    return client.virtual_machine_images.get(location, publisher, offer, sku, version)
  File "/opt/az/lib/python3.10/site-packages/azure/core/tracing/decorator.py", line 78, in wrapper_use_tracer
    return func(*args, **kwargs)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/v2022_11_01/operations/_virtual_machine_images_operations.py", line 320, in get
    deserialized = self._deserialize("VirtualMachineImage", pipeline_response)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1375, in __call__
    return self._deserialize(target_obj, data)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1445, in _deserialize
    raise_with_traceback(DeserializationError, msg, err)
  File "/opt/az/lib/python3.10/site-packages/azure/core/exceptions.py", line 78, in raise_with_traceback
    raise error.with_traceback(exc_traceback)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1430, in _deserialize
    found_value = key_extractor(attr, attr_desc, data)
  File "/opt/az/lib/python3.10/site-packages/azure/mgmt/compute/_serialization.py", line 1177, in rest_key_extractor
    return working_data.get(key)
azure.core.exceptions.DeserializationError: (", AttributeError: 'list' object has no attribute 'get'", 'Unable to deserialize to object: type', AttributeError("'list' object has no attribute 'get'"))
To check existing issues, please visit: https://github.com/Azure/azure-cli/issues

This issue is not to be confused with an URN with an invalid version. The command also correctly handles some incomplete URNs:

# A better error message
$ az vm image terms show --urn Canonical:0001-com-ubuntu-pro-jammy:
usage error: urn should be in the format of publisher:offer:sku:version.

# Not as good as the previous error, but much better than the one which is being reported
$ az vm image terms show --urn Canonical:0001-com-ubuntu-pro-jammy::
(BadRequest) The request URL is not valid.
Code: BadRequest
Message: The request URL is not valid.
Inner error: {
    "internalErrorCode": "RequestUrlInvalid"
}

The Solution

Azure Marketplace URNs are well defined, and Azure CLI should report that the URN is incomplete:

# An error message that tells the user what the URN is missing
$ az vm image terms show --urn Canonical:0001-com-ubuntu-pro-jammy:pro-22_04-lts:
usage error: urn is missing "version" in the publisher:offer:sku:version format

Other Considerations

This is a low impact enhancement. Users should be smart enough to input a valid URN (once again, the documentation is very clear on what an URN is comprised of), but I can attest to this error message being an issue for those who are less-than-familiar with Azure.

yonzhan commented 1 year ago

Thank you for opening this issue, we will look into it.