234 lines
8.7 KiB
Python
234 lines
8.7 KiB
Python
from azure.identity import ClientSecretCredential
|
||
from azure.mgmt.compute import ComputeManagementClient
|
||
from azure.mgmt.rdbms import MySQLManagementClient
|
||
from azure.mgmt.redis import RedisManagementClient
|
||
from azure.core.exceptions import AzureError
|
||
|
||
import sys, datetime, hashlib, math, traceback
|
||
from units import consul_kv, consul_svc
|
||
from units.cloud import sync_ecs, sync_rds, sync_redis, notify
|
||
from units.config_log import *
|
||
|
||
def exp(account,collect_days,notify_days,notify_amount):
|
||
pass
|
||
|
||
def group(account):
|
||
"""同步Azure资源组信息"""
|
||
try:
|
||
now = datetime.datetime.now().strftime('%m.%d/%H:%M')
|
||
# 获取Azure认证信息
|
||
tenant_id, client_id, client_secret = consul_kv.get_azure_credentials(account)
|
||
|
||
# 创建认证客户端
|
||
credential = ClientSecretCredential(
|
||
tenant_id=tenant_id,
|
||
client_id=client_id,
|
||
client_secret=client_secret
|
||
)
|
||
|
||
# 获取资源组信息
|
||
from azure.mgmt.resource import ResourceManagementClient
|
||
resource_client = ResourceManagementClient(credential, subscription_id)
|
||
|
||
group_dict = {}
|
||
for group in resource_client.resource_groups.list():
|
||
group_dict[group.name] = {
|
||
'name': group.name,
|
||
'location': group.location,
|
||
'tags': group.tags or {}
|
||
}
|
||
|
||
# 保存到consul
|
||
consul_kv.put_kv(f'ConsulManager/assets/azure/group/{account}', group_dict)
|
||
count = len(group_dict)
|
||
data = {
|
||
'count': count,
|
||
'update': now,
|
||
'status': 20000,
|
||
'msg': f'同步资源组成功!总数:{count}'
|
||
}
|
||
consul_kv.put_kv(f'ConsulManager/record/jobs/azure/{account}/group', data)
|
||
logger.info(f'【JOB】===>azure_group {account} {data}')
|
||
|
||
except AzureError as e:
|
||
handle_azure_error(e, account, 'group')
|
||
except Exception as e:
|
||
handle_general_error(e, account, 'group')
|
||
|
||
def vm(account, region, isextip=False):
|
||
"""同步Azure虚拟机信息"""
|
||
try:
|
||
now = datetime.datetime.now().strftime('%m.%d/%H:%M')
|
||
# 获取认证信息
|
||
tenant_id, client_id, client_secret = consul_kv.get_azure_credentials(account)
|
||
subscription_id = consul_kv.get_azure_subscription(account)
|
||
|
||
# 创建认证客户端
|
||
credential = ClientSecretCredential(
|
||
tenant_id=tenant_id,
|
||
client_id=client_id,
|
||
client_secret=client_secret
|
||
)
|
||
|
||
# 创建计算管理客户端
|
||
compute_client = ComputeManagementClient(credential, subscription_id)
|
||
|
||
ecs_dict = {}
|
||
# 获取虚拟机列表
|
||
for vm in compute_client.virtual_machines.list_all():
|
||
vm_id = vm.id.split('/')[-1]
|
||
vm_info = compute_client.virtual_machines.get(
|
||
vm.id.split('/')[4], # 资源组名称
|
||
vm.name,
|
||
expand='instanceView'
|
||
)
|
||
|
||
ecs_dict_temp = {vm_id: {}}
|
||
ecs_dict_temp[vm_id].update({
|
||
'name': vm.name,
|
||
'group': vm.id.split('/')[4], # 资源组名称
|
||
'ostype': 'windows' if vm.os_profile.windows_configuration else 'linux',
|
||
'status': vm_info.instance_view.statuses[-1].display_status,
|
||
'region': vm.location,
|
||
'ip': get_vm_ip(vm, isextip),
|
||
'cpu': f"{vm.hardware_profile.vm_size.split('_')[1]}核",
|
||
'mem': get_vm_memory(vm.hardware_profile.vm_size),
|
||
'exp': get_vm_billing_type(vm)
|
||
})
|
||
ecs_dict.update(ecs_dict_temp)
|
||
|
||
# 同步到consul
|
||
count = len(ecs_dict)
|
||
off, on = sync_ecs.w2consul('azure', account, region, ecs_dict)
|
||
data = {
|
||
'count': count,
|
||
'update': now,
|
||
'status': 20000,
|
||
'on': on,
|
||
'off': off,
|
||
'msg': f'VM同步成功!总数:{count},开机:{on},关机:{off}'
|
||
}
|
||
consul_kv.put_kv(f'ConsulManager/record/jobs/azure/{account}/vm/{region}', data)
|
||
logger.info(f'【JOB】===>azure_vm {account} {region} {data}')
|
||
|
||
except AzureError as e:
|
||
handle_azure_error(e, account, 'vm', region)
|
||
except Exception as e:
|
||
handle_general_error(e, account, 'vm', region)
|
||
|
||
def redis(account, region):
|
||
"""同步Azure Redis缓存信息"""
|
||
try:
|
||
now = datetime.datetime.now().strftime('%m.%d/%H:%M')
|
||
# 获取认证信息
|
||
tenant_id, client_id, client_secret = consul_kv.get_azure_credentials(account)
|
||
subscription_id = consul_kv.get_azure_subscription(account)
|
||
|
||
# 创建Redis管理客户端
|
||
credential = ClientSecretCredential(
|
||
tenant_id=tenant_id,
|
||
client_id=client_id,
|
||
client_secret=client_secret
|
||
)
|
||
redis_client = RedisManagementClient(credential, subscription_id)
|
||
|
||
redis_dict = {}
|
||
# 获取Redis实例列表
|
||
for redis_cache in redis_client.redis.list():
|
||
cache_id = redis_cache.id.split('/')[-1]
|
||
redis_dict_temp = {cache_id: {}}
|
||
redis_dict_temp[cache_id].update({
|
||
'name': redis_cache.name,
|
||
'domain': redis_cache.host_name,
|
||
'ip': redis_cache.host_name,
|
||
'port': redis_cache.port,
|
||
'region': redis_cache.location,
|
||
'group': redis_cache.id.split('/')[4], # 资源组名称
|
||
'status': redis_cache.provisioning_state,
|
||
'itype': 'redis',
|
||
'ver': redis_cache.redis_version,
|
||
'mem': f"{redis_cache.sku.capacity}GB",
|
||
'exp': get_redis_billing_type(redis_cache)
|
||
})
|
||
redis_dict.update(redis_dict_temp)
|
||
|
||
# 同步到consul
|
||
count = len(redis_dict)
|
||
off, on = sync_redis.w2consul('azure', account, region, redis_dict)
|
||
data = {
|
||
'count': count,
|
||
'update': now,
|
||
'status': 20000,
|
||
'on': on,
|
||
'off': off,
|
||
'msg': f'Redis同步成功!总数:{count},开机:{on},关机:{off}'
|
||
}
|
||
consul_kv.put_kv(f'ConsulManager/record/jobs/azure/{account}/redis/{region}', data)
|
||
logger.info(f'【JOB】===>azure_redis {account} {region} {data}')
|
||
|
||
except AzureError as e:
|
||
handle_azure_error(e, account, 'redis', region)
|
||
except Exception as e:
|
||
handle_general_error(e, account, 'redis', region)
|
||
|
||
# 辅助函数
|
||
def handle_azure_error(e: AzureError, account: str, resource_type: str, region: str = None):
|
||
"""处理Azure API错误"""
|
||
emsg = str(e)
|
||
logger.error(f"【Azure Error】\n【message:】{emsg}\n{traceback.format_exc()}")
|
||
|
||
# 构建错误路径
|
||
error_path = f'ConsulManager/record/jobs/azure/{account}/{resource_type}'
|
||
if region:
|
||
error_path = f'{error_path}/{region}'
|
||
|
||
# 获取现有数据
|
||
data = consul_kv.get_value(error_path)
|
||
if data == {}:
|
||
data = {'count': '无', 'update': '失败', 'status': 50000, 'msg': emsg}
|
||
else:
|
||
data['update'] = '失败'
|
||
data['msg'] = emsg
|
||
|
||
consul_kv.put_kv(error_path, data)
|
||
|
||
def handle_general_error(e: Exception, account: str, resource_type: str, region: str = None):
|
||
"""处理一般错误"""
|
||
logger.error(f'{e}\n{traceback.format_exc()}')
|
||
|
||
# 构建错误路径
|
||
error_path = f'ConsulManager/record/jobs/azure/{account}/{resource_type}'
|
||
if region:
|
||
error_path = f'{error_path}/{region}'
|
||
|
||
data = {'count': '无', 'update': '失败', 'status': 50000, 'msg': str(e)}
|
||
consul_kv.put_kv(error_path, data)
|
||
|
||
def get_vm_ip(vm, isextip=False):
|
||
"""获取虚拟机IP地址"""
|
||
if isextip:
|
||
# 获取公网IP
|
||
return vm.network_profile.network_interfaces[0].ip_configurations[0].public_ip_address.ip_address
|
||
else:
|
||
# 获取私网IP
|
||
return vm.network_profile.network_interfaces[0].ip_configurations[0].private_ip_address
|
||
|
||
def get_vm_memory(vm_size):
|
||
"""根据VM规格获取内存大小"""
|
||
# 这里需要实现VM规格到内存大小的映射
|
||
size_memory_map = {
|
||
'Standard_DS1_v2': '3.5GB',
|
||
'Standard_DS2_v2': '7GB',
|
||
# ... 其他规格映射
|
||
}
|
||
return size_memory_map.get(vm_size, '0')
|
||
|
||
def get_vm_billing_type(vm):
|
||
"""获取虚拟机计费类型"""
|
||
# 根据Azure虚拟机的计费属性判断
|
||
return '按量' if vm.billing_profile.max_price is None else '包年包月'
|
||
|
||
def get_redis_billing_type(redis_cache):
|
||
"""获取Redis实例计费类型"""
|
||
# 根据Redis实例的计费属性判断
|
||
return '按量' # 或根据实际情况判断 |