Для взаимодействия с облачной инфраструктурой 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 каждого сервера.
