Search code examples
azureazure-sdk-for-java

io.netty.channel.ChannelInitializer exceptionCaught accessing cost management api with azure java sdk to a csp account. Has anyone solve this before?


Thanks in advance. I'm trying to access programmatically the costs of each azure subscription to represent it in an app. I used the following code, but it gives this netty error that seems to deal with invalid access. Have you solve this before? I have three hypotheses:

  • I don't have enough access with the credentials I now have. Regarding the first hypothesis, I think is wrong, as the credentials were created with Billing Administrator. And I thought it will give an error relating to this.

  • As I found in [1] that it seems it's not possible accessing costs in a csp account. I found this [2], so does this mean this cost can't be accessed with azure java SDK but I will have to perform the specific gets? But it is strange it does not give the error "cost management data is not available for this subscription" [3]

  • Because some credentials are not introduced. As following [4] AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_CLIENT_SECRET variables are exported (if not it appears another error that azure credentials cannot be authenticated). But if you look at the sample query there an id relating to customer that I don't know how to find.

import com.azure.core.credential.TokenCredential;
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.management.AzureEnvironment;
import com.azure.core.management.Region;
import com.azure.core.management.profile.AzureProfile;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.core.util.Context;
import com.azure.resourcemanager.billing.BillingManager;
import com.azure.resourcemanager.costmanagement.CostManagementManager;
import com.azure.resourcemanager.costmanagement.models.ExportType;
import com.azure.resourcemanager.costmanagement.models.FunctionType;
import com.azure.resourcemanager.costmanagement.models.GranularityType;
import com.azure.resourcemanager.costmanagement.models.OperatorType;
import com.azure.resourcemanager.costmanagement.models.QueryAggregation;
import com.azure.resourcemanager.costmanagement.models.QueryColumnType;
import com.azure.resourcemanager.costmanagement.models.QueryComparisonExpression;
import com.azure.resourcemanager.costmanagement.models.QueryDataset;
import com.azure.resourcemanager.costmanagement.models.QueryDefinition;
import com.azure.resourcemanager.costmanagement.models.QueryFilter;
import com.azure.resourcemanager.costmanagement.models.QueryGrouping;
import com.azure.resourcemanager.costmanagement.models.TimeframeType;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

// Sample to query in a table
public class Query {

  public static void main(String[] args) {

    AzureProfile profile = new AzureProfile(AzureEnvironment.AZURE);
    TokenCredential credential = new DefaultAzureCredentialBuilder()
            .authorityHost(profile.getEnvironment().getActiveDirectoryEndpoint())
            .build();
    // System.out.println(profile.getTenantId());
    CostManagementManager manager = CostManagementManager
            .authenticate(credential, profile);
    System.out.println(System.getenv("AZURE_TENANT_ID"));
    System.out.println(System.getenv("AZURE_CLIENT_ID"));
    System.out.println(System.getenv("AZURE_CLIENT_SECRET"));

    try{
        customerQueryGroupingModern(manager);
    }
     catch (final Exception e) {
        System.out.println(e);
    }
  }


  //https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/costmanagement/azure-resourcemanager-costmanagement/src/samples/java/com/azure/resourcemanager/costmanagement/QueryUsageSamples.java
      /**
     * Sample code: CustomerQueryGrouping-Modern.
     *
     * @param costManagementManager Entry point to CostManagementManager.
     */
    public static void customerQueryGroupingModern(
        com.azure.resourcemanager.costmanagement.CostManagementManager costManagementManager) {
        costManagementManager
            .queries()
            .usageWithResponse(
                "providers/Microsoft.Billing/billingAccounts/xxxxxxxx/customers/5678",
                new QueryDefinition()
                    .withType(ExportType.USAGE)
                    .withTimeframe(TimeframeType.THE_LAST_MONTH)
                    .withDataset(
                        new QueryDataset()
                            .withGranularity(GranularityType.fromString("None"))
                            .withAggregation(
                                mapOf(
                                    "totalCost",
                                    new QueryAggregation().withName("PreTaxCost").withFunction(FunctionType.SUM)))
                            .withGrouping(
                                Arrays
                                    .asList(
                                        new QueryGrouping()
                                            .withType(QueryColumnType.DIMENSION)
                                            .withName("ResourceGroup")))),
                Context.NONE);
    }

    @SuppressWarnings("unchecked")
    private static <T> Map<String, T> mapOf(Object... inputs) {
        Map<String, T> map = new HashMap<>();
        for (int i = 0; i < inputs.length; i += 2) {
            String key = (String) inputs[i];
            T value = (T) inputs[i + 1];
            map.put(key, value);
        }
        return map;
    }

}

Solution

  • I looked for similar errors in google and it was said this issue was relating to a netty package not included. In the readme it was described to use netty for authentication but no package was written. Finally, I found one in the resource manager part of the sdk and included it in the pom.xml:

        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-core-http-netty</artifactId>
            <version>1.12.4</version>
        </dependency>