Azure API Cost Management

API AZURE Cost Management

Aperçu d’Azure Cost Management

A l’instar des autres « Cloud Providers », Azure propose sa solution intégrée de gestion des coûts et de la facturation, disponible depuis le portail de gestion. Ce portail offre toute l’ergonomie et toutes les fonctionnalités que nous sommes en droit d’attendre et dont nous avons classiquement besoin. Néanmoins, dès lors que nous sommes dans un contexte multi-Cloud, que nous souhaitons nous affranchir des outils et portails dédiés, et que nous voulons pouvoir centraliser, consolider et retraiter les coûts, le choix de recourir à l’API pour collecter les informations de coûts s’impose comme une bonne solution. Pour simplifier au maximum la démarche ici, nous sommes partis d’un abonnement gratuit Azure. Nous allons tâcher, dans la suite de cet article, de récupérer programmatiquement la même vision des coûts que celle présentée ci-dessous.

Installation du SDK Azure pour Python

Dans la continuité des articles précédents, nous allons commencer par installer les modules Python relatifs à Azure. Faisant cohabiter plusieurs versions de Python sur ma machine, j’utilise la commande « pip3 » en lieu et place de « pip » pour l’installation des modules. Notre futur script sera exécuté en version 3.x de Python.

pip3 install azure
pip3 install azure-cli-core
pip3 install azure-core

Aperçu de l’Azure SDK for Python

L’Azure SDK for Python embarque une multitudes de services qui couvrent l’ensemble des fonctionnalités offertes au travers d’Azure ou presque (je ne suis pas allé vérifier l’exhaustivité !!!). Dans notre cas nous allons nous focaliser sur 2 services offerts par cette API que sont le « Billing » et la « Consumption ». Vous l’avez deviné ou traduit, il s’agit de la facturation et de la consommation.

La documentation publique et didactique pour les développeurs est disponible ici. Elle est un peu plus agréable à lire que la précédente sur GitHub, et assortie de quelques exemples pour faciliter la prise en mains. Néanmoins on peut regretter la faible quantité d’exemples pratiques et surtout une documentation qui reste peu lisible. C’est pourquoi, j’espère que vous apprécierez d’autant plus cet article et que vous ne manquerez pas de le « liker » et de le recommander.

Dans la conception du script, nous allons procéder en 2 étapes successives, une première pour récupérer les périodes de facturation qui nous intéresse, puis une deuxième pour récupérer les informations de consommation et de coûts dans ces mêmes périodes de facturation. En effet, ce mécanisme nous est imposé par le modèle même de données au sein de l’API, ce qui se différencie de celui des API AWS par exemple (pour plus de détails je vous renvoie à l’article correspondant ici).

Création des credentials pour l’authentification

A l’instar des articles précédents pour AWS, nous allons capitaliser sur l’installation locale de la CLI (Command Line Interface) mais cette fois celle d’Azure. Cela nous évitera notamment d’avoir à stocker les credentials au sein même du script, et d’appuyer l’authentification du script sur celle de la CLI. Si l’Azure CLI n’est pas installée, je vous invite à suivre les instructions présentées dans la documentation disponible sur le site de Microsoft.

Il vous faut ensuite configurer l’authentification en exécutant les deux commandes suivantes :

La première pour s’authentifier :

laptop:~$ az login
Ouverture dans une session de navigateur existante.
You have logged in. Now let us find all the subscriptions to which you have access...
[
  {
    "cloudName": "AzureCloud",
    "id": "########-86ec-470f-8bf6-############",
    "isDefault": true,
    "name": "Essai gratuit",
    "state": "Enabled",
    "tenantId": "########-c994-4eb3-8b95-############",
    "user": {
      "name": "#######@######.com",
      "type": "user"
    }
  }
]

La suivante pour créer un « principal de service » selon une des méthodes proposées dans la documentation « Authenticate with the Azure management libraries for Python » :

laptop:~$ az ad sp create-for-rbac --sdk-auth > mycredentials.json
Creating a role assignment under the scope of "/subscriptions/########-86ec-470f-8bf6-############"
  Retrying role assignment creation: 1/36
  Retrying role assignment creation: 2/36

Exemple de script basique en Python

Dans cet exemple, nous vous proposons un script qui se contente de récupérer toutes les périodes de facturation (« BillingPeriods ») dans lesquelles sont comprises les dates passées en argument. Pour obtenir les périodes de facturation, il faut utiliser la classe BillingPeriodsOperations avec la méthode « list ». Puis nous récupérons toutes les informations détaillées de facturation liées à l’usage dans les périodes de facturation correspondantes. Pour cela nous avons recours à la classe « UsageDetails » et la méthode « list ».

import sys
from azure.common.client_factory import get_client_from_cli_profile
from azure.mgmt.consumption import ConsumptionManagementClient
from azure.mgmt.billing import BillingManagementClient
import argparse
from datetime import datetime
from datetime import timezone
import dateutil.parser

parser = argparse.ArgumentParser(description='Tracking Azure Costs.')
parser.add_argument('--start', help='start date : YYYY-MM-dd')
parser.add_argument('--end', help='end date : YYYY-MM-dd')

args = parser.parse_args()
if args.start and args.end is not None :

    b_client = get_client_from_cli_profile(BillingManagementClient)

    periods = b_client.billing_periods.list()

    #print(periods)
    startDate = datetime.strptime(args.start, "%Y-%m-%d")
    endDate = datetime.strptime(args.end, "%Y-%m-%d")
    periods_to_retain = []
    for period in periods :
        obj_period = period.as_dict()
        #print(obj_period['id'], obj_period['billing_period_start_date'], obj_period['billing_period_end_date'])
        period_start = datetime.strptime(obj_period['billing_period_start_date'], "%Y-%m-%d")
        period_end = datetime.strptime(obj_period['billing_period_end_date'], "%Y-%m-%d")
        if period_start <= startDate <= period_end or period_start <= endDate <= period_end :
            periods_to_retain.append(obj_period['id'])


    c_client = get_client_from_cli_profile(ConsumptionManagementClient)

    for billing_period in periods_to_retain:
    
        result = c_client.usage_details.list(billing_period)

        if result is not None :
            print(';'.join(['subscription', 'service', 'type', 'tags', 'startDate', 'startTime', 'endDate', 'endTime', 'instance','location', 'quantity', 'cost', 'currency', 'estimated']))
            for page in result :
                obj = page.as_dict()
                start_date = dateutil.parser.parse(obj['usage_start']).strftime('%x')
                end_date = dateutil.parser.parse(obj['usage_end']).strftime('%x')
                start_time = dateutil.parser.parse(obj['usage_start']).strftime('%X')
                end_time = dateutil.parser.parse(obj['usage_end']).strftime('%X')
                print(';'.join([obj['subscription_name'], obj['consumed_service'], obj['type'], str(obj['tags']), start_date, start_time, end_date, end_time, obj['instance_name'], obj['instance_location'], str(obj['usage_quantity']), str(obj['pretax_cost']), obj['currency'], str(obj['is_estimated'])]))
else:
    parser.print_help()

J’ai déjà expérimenté quelques problèmes de comportement dans le chargement des modules Python pour Azure. Je vous invite donc, en cas d’erreur sur le chargement des modules Python Azure, à procéder à une ré-installation propre. Cela peut potentiellement résoudre le problème. Je vous propose de procéder comme suit :

sudo pip3 uninstall -y $(pip3 freeze | grep azure)
sudo pip3 install azure

Aperçu des résultats

Passons maintenant à l’exécution du script qui doit nous permettre de récupérer les informations de coûts comprises dans la ou les périodes de facturation comprises dans l’intervalle de dates que nous avons passé en paramètres :

sgautier@laptop:~/Nextcloud/DIGITNEOS/Scripting/Azure/Tracking$ python3 ./azure_tracking.py --start 2020-02-01 --end 2020-02-29 > azure.csv

Les résultats redirigés dans un fichier CSV, vont nous permettre une nouvelle fois de donner une représentation tabulaire et graphique au sein d’un simple fichier Excel ou Calc dans notre cas, mais auraient tout aussi bien pu alimenter notre solution de BI. Une fois retraitées dans un tableau croisé dynamique, nous retrouvons bien les mêmes informations que celles obtenues depuis le portail, ce qui est une bonne base, avant de procéder à l’enrichissement, au retraitement et à l’imputation de ces coûts par exemple.

Conclusions

Vous l’avez compris cet article présente la démarche basique qui consiste à collecter les informations de coûts depuis Azure de manière programmatique. Ce qui nous permet ensuite de réserver à ces données toutes sortes de traitement de manière totalement indépendante. C’est particulièrement utile dans un contexte multi-Cloud et dans le cadre d’une démarche FinOps, qui consiste à se donner les moyens de visualiser, d’optimiser et d’améliorer sa gestion des coûts dans le Cloud. Digitneos se propose de vous accompagner dans la mise en oeuvre et l’outillage de cette démarche FinOps, pour vous permettre de maîtriser vos coûts, de les imputer dans une logique de « showback » ou de « chargeback » et de réaliser des économies. Contactez-nous !

Laisser un commentaire