Для взаимодействия с облачной инфраструктурой Microsoft Azure компания Майкрософт поддерживает открытый проект на GitHub, который реализует Python SDK. С помощью библиотек из этого проекта можно реализовать взаимодействие с облачной инфраструктурой посредством скриптов или даже написать собственный облегченный веб-сервис для Azure.
В своей работе я использую такие модули, как
- azure.core
- azure.mgmt.compute
- azure.mgmt.network
- azure.mgmt.monitor
Чтобы установить эти модули для использования в своем проекте, необходимо перейти в папку проекта и выполнить команду
pipenv install "azure-identity==1.5.0" "azure-mgmt-compute==18.1.0" "azure-mgmt-network==17.1.0" "azure.mgmt.monitor==2.0.0"
Если эти модули необходимо установить для всей системы, то нужно выполнить команду
pip install "azure-identity==1.5.0" "azure-mgmt-compute==18.1.0" "azure-mgmt-network==17.1.0" "azure.mgmt.monitor==2.0.0"
Примечание. Версия модулей важна, так как от версии к версии некоторые функции внутри модулей меняются, поэтому проект с новыми, а тем более старыми версиями может вести себя некорректно или вообще не работать.
На основе этих модулей я написал несколько функций, которые я объединил в файл module_azu.py:
- создание объекта с параметрами подключения,
- получение свойств сервера из локального json-файла, который заранее был сформирован другой процедурой,
- получение свойств сервера из локального json-файла, который заранее был сформирован другой процедурой, и дополнение этих данных свежими данными из портала,
- запуск сервера,
- остановка сервера,
- получение метрик сервера.
print('--- importing module_azu.py ---') from azure.identity import ClientSecretCredential from azure.mgmt.compute import ComputeManagementClient from azure.mgmt.network import NetworkManagementClient from azure.mgmt.monitor import MonitorManagementClient from azure.core.pipeline.policies import ProxyPolicy from re import findall as re_findall from datetime import datetime, timedelta from os import path as os_path from os import getcwd as os_getcwd from os import environ as os_environ from sys import path as sys_path # импортирование модулей из проекта # два метода импортирования необходимо для реализации разных типов запуска модуля: # - из веб-сервера с Django-проектом # - прямым запуском, но и использованием переменных из Django try: # попытка импортировать модули по относительным путям print(' trying to import modules with relative paths') from .module_core import instances_json_read from django.conf import settings print(' relative import is OK') except ImportError: # импортирование модулей по абсолютным путям print('Relative import failed') print('Trying to import modules with absolute paths') try: # получение текущей дирректории, откуда запущен скрипт - должен быть корень проекта current_directory = os_getcwd() # добавление пути к папке проекта в переменные среды sys_path.append(current_directory) # подключение настроек проекта os_environ.setdefault('DJANGO_SETTINGS_MODULE', 'webconsole.settings') # импортирование переменных Django в текущую среду from django.conf import settings from module_core import instances_json_read print('Absolute import is OK') except ModuleNotFoundError: print('Absolute import failed') exit() print() # функция для создания объекта с параметрами подключения def get_credentials(): from os import environ # установка переменных среды, так как клиент Azure игнорирует аргумент с настройками прокси for item in settings.PROXY_SETTINGS['proxies'].keys(): environ[item + '_proxy'] = settings.PROXY_SETTINGS['proxies'][item] # установка параметров прокси подключения для клиента !!! не работает, закомментировано #azu_proxy_policy = ProxyPolicy() #azu_proxy_policy.proxies = settings.COMPANY_PROXIES # создание объекта с параметрами подключения credentials = ClientSecretCredential( tenant_id = settings.AZU_TENANT_ID, client_id = settings.AZU_CLIENT_ID, client_secret = settings.AZU_SECRET_KEY, use_env_settings = True, # !!! этот аргумент игнорируется функцией, закомментирован #proxies = COMPANY_PROXIES, ) # !!! этот параметр игнорируется функцией, закомментирован #credentials.proxy_policy = azu_proxy_policy # получение AZU_SUBSCRIPTION_ID из настроек Django subscription_id = settings.AZU_SUBSCRIPTION_ID # возврат объектов с параметрами подключения return credentials, subscription_id # функция получения параметров сервера из локального json-файла, который подготовлен заранее другим модулем def azu_instance_properties_local(vm_name): # путь к json-файлу составляется из настроек Django instances_filepath = os_path.join(settings.BASE_DIR, settings.PROJECT_INSTANCES_JSON_FILEPATH) # запрос данных из json-файла try: # чтение таблицы из json-файла instances_table = instances_json_read(instances_filepath)['azu_vm_table'] # поиск сервера в полученной таблице instance_line = instances_table.loc[vm_name.lower()].to_dict() except: instance_line = '' # возврат строки с параметрами сервера return instance_line # функция получения параметров сервера из локального json-файла, дополнение свежими данными из портала def azu_instance_properties_mixed(vm_name): # получение локальных данных из файла vm_properties = azu_instance_properties_local(vm_name) # получение облачных данных credentials, subscription_id = get_credentials() compute_client = ComputeManagementClient(credentials, subscription_id) vm_item = compute_client.virtual_machines.get(vm_properties['rgroup'], vm_name, expand='instanceView') # установка id сервера как его имя в нижнем регистре i_id = vm_item.name.lower() # сохранение тэгов в отдельный словарь tags = {} for item in vm_item.tags.keys(): tags.update({item: vm_item.tags[item]}) # считывание текущего состояния сервера i_state = 'unknown' for item in vm_item.instance_view.statuses: if 'ProvisioningState/failed'.lower() in item.code.lower(): i_state = 'failed' break if 'PowerState'.lower() in item.code.lower(): i_state = item.display_status.replace('VM ','') # список доступа к управлению питанием i_start_stop_access = '' if 'Start-Stop access' in tags: i_start_stop_access = tags['Start-Stop access'].lower() # составление данных о бэкапе if vm_properties['backup_description'] != '': i_backup = 'Take a snapshot ' + vm_properties['backup_description'] else: i_backup = '' if vm_properties['backup_latest'] != '': i_backup_latest = vm_properties['backup_latest'] i_backup_latest = int(re_findall(r'\d+', i_backup_latest)[0])/1000 + 3600 # convert string, from milliseconds to seconds, from UTC to CET i_backup_latest = datetime.fromtimestamp(i_backup_latest).strftime("%d.%m.%Y %H:%M") + ' CET' else: i_backup_latest = '' # составление данных о времени работы if vm_properties['schedule_description'] != '': i_schedule = 'Running ' + vm_properties['schedule_description'] else: i_schedule = '' # составление словаря с данными о сервера curValues = { 'id': i_id, 'name': vm_properties['name'], 'type': vm_properties['type'], 'description': vm_properties['description'], 'zone': vm_properties['vnt_description'], 'ip_address': vm_properties['ip_address'], 'responsible': vm_properties['responsible'], 'project': vm_properties['project'], 'purpose': vm_properties['purpose'], 'rgroup': vm_properties['rgroup'], 'state': i_state, 'backup': i_backup, 'backup_latest': i_backup_latest, 'schedule': i_schedule, 'start_stop_access': i_start_stop_access, } # возврат словаря с данными о сервере return curValues # запуск виртуальной машины def azu_instance_start(vm_name): # получение облачных данных credentials, subscription_id = get_credentials() compute_client = ComputeManagementClient(credentials, subscription_id) vm_collection = compute_client.virtual_machines.list_all() # поиск нужной виртуальной машины for item in vm_collection: if item.name.lower() == vm_name.lower(): vm_rgp = "".join(item.id.split('/')[4]) break # запуск виртуальной машины result = compute_client.virtual_machines._start_initial(vm_rgp, vm_name) return result # остановка виртуальной машины def azu_instance_stop(vm_name): # получение облачных данных credentials, subscription_id = get_credentials() compute_client = ComputeManagementClient(credentials, subscription_id) vm_collection = compute_client.virtual_machines.list_all() # поиск нужной виртуальной машины for item in vm_collection: if item.name.lower() == vm_name.lower(): vm_rgp = "".join(item.id.split('/')[4]) break # остановка виртуальной машины result = compute_client.virtual_machines._deallocate_initial(vm_rgp, vm_name) return result # получение метрик сервера def azu_instance_metrics(vm_name): import pandas as pd # составление временного интервала, за который нужно получить данные time_start = datetime.utcnow() - timedelta(hours=8) time_stop = datetime.utcnow() # получение локальных данных из файла vm_properties = azu_instance_properties_local(vm_name) # получение облачных данных credentials, subscription_id = get_credentials() monitor_client = MonitorManagementClient(credentials, subscription_id) # получение списка всех возможных метрик сервера !!! не используется, закомментировано #for metric in monitor_client.metric_definitions.list(vm_properties['path']): # print("{}: id={}, unit={}".format( # metric.name.localized_value, # metric.name.value, # metric.unit # )) # получение метрики процессора metrics_data = monitor_client.metrics.list( resource_uri=vm_properties['path'], timespan="{}/{}".format(time_start, time_stop), interval='PT5M', metricnames='Percentage CPU', aggregation='Total' ) # конвертация данных в формат googlecharts result = [] for item in metrics_data.value: print("{} ({})".format(item.name.localized_value, item.unit)) for timeserie in item.timeseries: for data in timeserie.data: if data.total == None: result.append([(data.time_stamp + timedelta(hours=1)).strftime('%H:%M'), 0, 0]) else: result.append([(data.time_stamp + timedelta(hours=1)).strftime('%H:%M'), data.total, 0]) return result # функция сохранения меток для виртуальной машины def azu_instance_save(vm_name, startstopaccess): credentials, subscription_id = get_credentials() compute_client = ComputeManagementClient(credentials, subscription_id) vm_collection = compute_client.virtual_machines.list_all() for item in vm_collection: if item.name.lower() == vm_name.lower(): vm_rgp = "".join(item.id.split('/')[4]) break vm_item = compute_client.virtual_machines.get(vm_rgp, vm_name) print(vm_item.tags) vm_item.tags = { 'Start-Stop access': startstopaccess, } result = compute_client.virtual_machines._update_initial( vm_rgp, vm_name, vm_item, ) return result if __name__ == '__main__': i_item = azu_instance_save('wsAAA001', 'Python-test') print(i_item) #for i_keys, i_values in i_item.items(): # print(f'{i_keys}={i_values}')
Данный модуль я использую в проекте облегченного веб-сервиса для просмотра и управления облачными серверами, к которому имеют доступ многие сотрудники компании. Эти сотрудники не имеют доступа непосредственно к порталу Azure, но облегченная версия портала позволяет им выполнять нужные функции с серверами, сверяя доступ к серверам в группах Active Directory и в тегах Start-Stop access каждого сервера.