azure-sdk-for-python: The resource type 'Query' could not be found in the namespace 'Microsoft.CostManagement' for api version '2020-06-01'

  • Package Name: azure-mgmt-costmanagement
  • Package Version: 1.0.0b1
  • Operating System: WSL Ubuntu 18.04
  • Python Version: 3.6.9

Describe the bug Getting the following error : azure.core.exceptions.ResourceNotFoundError: (InvalidResourceType) The resource type 'Query' could not be found in the namespace 'Microsoft.CostManagement' for api version '2020-06-01'. The supported api-versions are '2018-05-31,2018-08-31,2018-08-01-preview,2018-10-01-preview,2018-12-01-preview,2019-01-01,2019-03-01-preview,2019-04-01-preview,2019-05-01-preview,2019-10-01,2019-11-01'.

To Reproduce Steps to reproduce the behavior:

  1. pip3 install azure-mgmt-costmanagement==1.0.0b1
  2. call query.usage method
client = CostManagementClient(credential, "https://management.azure.com")
client.query.usage(scope=sub_id,parameters=parameters) 

Expected behavior Query should work and produce data

Additional context API version seems hardcoded here : https://github.com/Azure/azure-sdk-for-python/blob/739b24a25158a471159bae887ab8f6907f347727/sdk/costmanagement/azure-mgmt-costmanagement/azure/mgmt/costmanagement/operations/_operations.py#L65 I downloaded the sources, and changed the api_version = "2020-06-01" value to "2019-11-01". It solves my issue locally.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 3
  • Comments: 16 (6 by maintainers)

Most upvoted comments

Since I found no way to set the api version from outside I did some hacky things:

"""A ugly hack to get a workaround for https://github.com/Azure/azure-sdk-for-python/issues/16102
"""
from azure.mgmt.costmanagement.operations import QueryOperations
from azure.core.exceptions import (
    ClientAuthenticationError,
    HttpResponseError,
    ResourceExistsError,
    ResourceNotFoundError,
    map_error,
)


class FixedQueryOperations(QueryOperations):
    def __init__(self, client):
        self._client = client._client
        self._serialize = client._serialize
        self._deserialize = client._deserialize
        self._config = client._config

    # took from https://github.com/Azure/azure-sdk-for-python/blob/739b24a25158a471159bae887ab8f6907f347727/sdk/costmanagement/azure-mgmt-costmanagement/azure/mgmt/costmanagement/operations/_query_operations.py#L47
    def usage(
        self,
        scope,  # type: str
        parameters,  # type: "_models.QueryDefinition"
        **kwargs  # type: Any
    ):
        # type: (...) -> "_models.QueryResult"
        """Query the usage data for scope defined.
        :param scope: The scope associated with query and export operations. This includes
            '/subscriptions/{subscriptionId}/' for subscription scope,
            '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}' for resourceGroup scope,
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}' for Billing Account scope and
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}/departments/{departmentId}'
            for Department scope,
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}/enrollmentAccounts/{enrollmentAccountId}'
            for EnrollmentAccount scope,
            '/providers/Microsoft.Management/managementGroups/{managementGroupId} for Management Group
            scope,
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}/billingProfiles/{billingProfileId}'
            for billingProfile scope,
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}/billingProfiles/{billingProfileId}/invoiceSections/{invoiceSectionId}'
            for invoiceSection scope, and
            '/providers/Microsoft.Billing/billingAccounts/{billingAccountId}/customers/{customerId}'
            specific for partners.
        :type scope: str
        :param parameters: Parameters supplied to the CreateOrUpdate Query Config operation.
        :type parameters: ~azure.mgmt.costmanagement.models.QueryDefinition
        :keyword callable cls: A custom type or function that will be passed the direct response
        :return: QueryResult, or the result of cls(response)
        :rtype: ~azure.mgmt.costmanagement.models.QueryResult
        :raises: ~azure.core.exceptions.HttpResponseError
        """
        cls = kwargs.pop("cls", None)  # type: ClsType["_models.QueryResult"]
        error_map = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
        }
        error_map.update(kwargs.pop("error_map", {}))
        api_version = "2019-11-01"
        content_type = kwargs.pop("content_type", "application/json")
        accept = "application/json"

        # Construct URL
        url = self.usage.metadata["url"]  # type: ignore
        path_format_arguments = {
            "scope": self._serialize.url("scope", scope, "str", skip_quote=True),
        }
        url = self._client.format_url(url, **path_format_arguments)

        # Construct parameters
        query_parameters = {}  # type: Dict[str, Any]
        query_parameters["api-version"] = self._serialize.query(
            "api_version", api_version, "str"
        )

        # Construct headers
        header_parameters = {}  # type: Dict[str, Any]
        header_parameters["Content-Type"] = self._serialize.header(
            "content_type", content_type, "str"
        )
        header_parameters["Accept"] = self._serialize.header("accept", accept, "str")

        body_content_kwargs = {}  # type: Dict[str, Any]
        body_content = self._serialize.body(parameters, "QueryDefinition")
        body_content_kwargs["content"] = body_content
        request = self._client.post(
            url, query_parameters, header_parameters, **body_content_kwargs
        )
        pipeline_response = self._client._pipeline.run(request, stream=False, **kwargs)
        response = pipeline_response.http_response

        if response.status_code not in [200]:
            map_error(
                status_code=response.status_code, response=response, error_map=error_map
            )
            error = self._deserialize(_models.ErrorResponse, response)
            raise HttpResponseError(
                response=response, model=error, error_format=ARMErrorFormat
            )

        deserialized = self._deserialize("QueryResult", pipeline_response)

        if cls:
            return cls(pipeline_response, deserialized, {})

        return deserialized

    usage.metadata = {"url": "/{scope}/providers/Microsoft.CostManagement/query"}  # type: ignore