Azureのリソースグループにあるリソースの一覧が欲しい

Azure

azコマンドでザッと見るのはともかく、やっぱりExcelになってないと何かと不便だなぁ、ということで書いた。GitHubに放流しといた。それっぽいツールがあるのかも知れないけど、探すのが面倒。

#!/usr/bin/env python3.11

# built-in modules
import argparse
import configparser
import os
import pathlib
import sys
import warnings

cur_python = f"python{sys.version_info[0]}.{sys.version_info[1]}"

# exit with redden message
def exit_with_error(msg) -> None:
    sys.exit("\033[31m" + msg + "\033[0m")

# external modules
try:
    from azure.identity import DefaultAzureCredential
except ModuleNotFoundError:
    exit_with_error(f"Please install 'azure-ai-translation-text' before executing.\n{cur_python} -m pip install azure-identity")

try:
    from azure.mgmt.resource import ResourceManagementClient
except ModuleNotFoundError:
    exit_with_error(f"Please install 'azure-ai-translation-text' before executing.\n{cur_python} -m pip install azure-mgmt-resource")

try:
    import openpyxl as xl
    from openpyxl.worksheet.table import Table, TableStyleInfo
    from openpyxl.styles import Color, Font, PatternFill, DEFAULT_FONT
except ModuleNotFoundError:
    exit_with_error(f"Please install 'openpyxl' before executing.\n{cur_python} -m pip install openpyxl")

try:
    from azure.mgmt.postgresqlflexibleservers import PostgreSQLManagementClient
except ModuleNotFoundError:
    exit_with_error(f"Please install 'azure-mgmt-postgresqlflexibleservers' before executing.\n{cur_python} -m pip install azure-mgmt-postgresqlflexibleservers")

try:
    from azure.mgmt.mysqlflexibleservers import MySQLManagementClient
except ModuleNotFoundError:
    exit_with_error(f"Please install 'azure-mgmt-mysqlflexibleservers' before executing.\n{cur_python} -m pip install azure-mgmt-mysqlflexibleservers")

# suppress warnings from openpyxl
# "Workbook contains no default style, apply openpyxl's default"
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')

def get_sub_id() -> str:
    try:
        return os.environ["AZURE_SUBSCRIPTION_ID"]
    except KeyError:
        print("Could not find subscription ID in environment variables.\nTrying to read from configuration file...")

    config = configparser.ConfigParser()
    try:
        default_path = "~/.azure/clouds.config"
        config.read(pathlib.Path(default_path).expanduser())
        return config["AzureCloud"]["subscription"]
    except KeyError:
        print(f"Could not find subscription ID in configuration file, '{default_path}'.")
        exit_with_error("Please set 'AZURE_SUBSCRIPTION' environment variable or login with 'az login' first.")

def list_to_excel(rgname: str) -> None:
    client_map = {
        "Microsoft.DBforPostgreSQL/flexibleServers": PostgreSQLManagementClient,
        "Microsoft.DBforMySQL/flexibleServers": MySQLManagementClient
    }

    credential = DefaultAzureCredential()
    sub_id = get_sub_id()
    resource_client = ResourceManagementClient(credential, sub_id)
    resource_list = resource_client.resources.list_by_resource_group(rgname)

    # Create a workbook
    wb = xl.Workbook()
    ws = wb.worksheets[0]
    ws.title = "Resources"

    # Header
    labels = ['id', 'name', 'type', 'location', 'extended_location', 'tags', 'plan', 'properties', 'kind', 'managed_by', 'sku-name', 'sku-tier', 'sku-size', 'sku-family', 'sku-model', 'sku-capacity', 'version', 'identity', 'created_time', 'changed_time', 'provisioning_state', 'systemData-createdBy', 'systemData-createdByType', 'systemData-createdAt', 'systemData-lastModifiedBy', 'systemData-lastModifiedByType']
    for i, label in enumerate(labels, 1):
        ws.cell(row = 1, column = i).value = label
    ws.row_dimensions[1].height = 16

    k_sku = "sku"
    k_version = "version"
    k_systemData = "systemData"
    row_num = 2
    for r in list(resource_list):
        ws.row_dimensions[row_num].height = 16
        for k in labels:
            if k[0:len(k_sku)] == k_sku:
                try:
                    ws.cell(row = row_num, column = labels.index(k) + 1).value = getattr(r.sku, k[len(k_sku) + 1:])
                except AttributeError:
                    pass
            elif k[0:len(k_systemData)] == k_systemData:
                if len(r.additional_properties) == 1:
                    try:
                        ws.cell(row = row_num, column = labels.index(k) + 1).value = r.additional_properties[k_systemData][k[len(k_systemData) + 1:]]
                    except KeyError:
                        pass
            elif k[0:len(k_version)] == k_version:
                client_class = client_map.get(r.type)
                if client_class:
                    flex_client = client_class(credential, sub_id)
                    for item in flex_client.servers.list_by_resource_group(resource_group_name=rgname):
                        try:
                            ws.cell(row = row_num, column = labels.index(k) + 1).value = f"{item.version}.{item.minor_version}"
                        except AttributeError:
                            ws.cell(row = row_num, column = labels.index(k) + 1).value = f"{item.version}"
            else:
                try:
                    ws.cell(row = row_num, column = labels.index(k) + 1).value = getattr(r, k)
                except ValueError:
                    pass
        row_num += 1

    # It's hack to set default font
    _font = Font(name = "Calibri", size = 11)
    {k: setattr(DEFAULT_FONT, k, v) for k, v in _font.__dict__.items()}

    # Set table
    table = Table(displayName = "Table1", ref = f"A1:Z{row_num - 1}")
    table.tableStyleInfo = TableStyleInfo(name = "TableStyleMedium2", showRowStripes = True)
    ws.add_table(table)

    # Save
    import datetime
    today = datetime.datetime.now()
    path = f"All Resources Under '{rgname}' - " + today.strftime("%Y-%m-%d %H-%M-%S") + ".xlsx"
    wb.save(path)

    # On macOS, the workbook will be opened automatically
    if sys.platform == "darwin":
        import subprocess
        coms = ["open", path]
        subprocess.run(coms)

def main() -> None:
    parser = argparse.ArgumentParser(description = "List all the resources in a resource group and put the list in a Excel file.")
    parser.add_argument("resource_group", help = "Resource group name to list the resources")
    args = parser.parse_args()

    list_to_excel(args.resource_group)

if __name__ == "__main__":
    if sys.platform != "darwin":
        print("This script is intended to be run on macOS.")
    main()

こんな感じのExcelに出力される。PostgreSQLとMySQLだけ、バージョンが出るw

タイトルとURLをコピーしました