一、注意事项
1.1 注意替换资产模板中nodes值,可以通过数据库assets_node表中获取,或者使用jumpserver 脚本获取资产信息查看
1.2 requirements.txt
aliyun-python-sdk-core==2.13.36 aliyun-python-sdk-ecs==4.24.30 aliyunsdkcore==1.0.3 requests==2.28.2 urllib3==1.26.14 PyMySQL~=1.0.2
二、相关脚本文件
aliyun_ecs.py
# -*- coding: utf-8 -*- """ @Time : 2023/2/27 @Author : Bowen @File : aliyun_ecs @Description : """ # pip install requests drf-httpsig import json from aliyunsdkcore.client import AcsClient from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest from aliyunsdkecs.request.v20140526.DescribeDisksRequest import DescribeDisksRequest class ecs_api(object): def __init__(self, region="cn-hangzhou"): self.region = region # 设置阿里云的AccessKeyID和AccessKeySecret self.AK = "xxxxxxx" self.AS = "xxxxxxx" self.client = AcsClient(self.AK, self.AS, self.region) def get_ecs_all(self): """ 获取所有ECS实例信息 :return: list,包含当前AK用户当前地域下所有可查询ECS实例信息列表 """ request = DescribeInstancesRequest() request.set_accept_format('json') # 设置参数,每页返回的数量为10 request.set_PageSize(10) # 设置页码,从第一页开始 page_number = 1 ecs_list = [] while True: # 设置当前页码 request.set_PageNumber(page_number) # 发送请求,获取响应 response = self.client.do_action_with_exception(request) res = json.loads(str(response, encoding='utf-8')) res = res['Instances']['Instance'] # 如果返回的数据为空,则退出循环 if not res: break # 处理响应数据 for ecs in res: ecs_list.append(ecs) # 增加页码 page_number += 1 return ecs_list def get_ecs_disk_size(self, instance_id): """ 阿里云ECS相关操作 :param instance_id: ECS实例ID :return: int,返回当前实例系统盘容量大小,主要由于jumpserver 磁盘仅有容量字段,无法区分磁盘 """ system_disk_size = 0 request = DescribeDisksRequest() request.set_accept_format('json') request.set_InstanceId('i-bp1bjhiosovwnd16u2tf') response = self.client.do_action_with_exception(request) res = json.loads(str(response, encoding='utf-8')) for disk in res['Disks']['Disk']: if disk['Device'] == "/dev/xvda": system_disk_size = disk['Size'] return system_disk_size if __name__ == '__main__': obj = ecs_api() obj.get_ecs_all()
jms_api.py
# -*- coding: utf-8 -*- """ @Time : 2023/2/27 @Author : Bowen @File : jumpserver @Description : """ import requests import json from jms_mysql import get_asset_id from aliyun_ecs import ecs_api class jumpserver(object): def __init__(self): self.jms_url = 'http://192.168.1.136' self.token = '012cddf58f6f89f32631c9a7d49e8991b34a8c71' self.headers = { "Authorization": 'Token ' + self.token, 'X-JMS-ORG': '00000000-0000-0000-0000-000000000002', 'accept': 'application/json' } self.assets_url = self.jms_url + '/api/v1/assets/assets/' self.ecs_api = ecs_api() def get_assets_all(self): """ 获取jumpserver所有资产信息 :return: List 包含jumpserver所有资产信息列表 """ req = requests.get(url=self.assets_url, headers=self.headers) assets_list = json.loads(req.content.decode()) return assets_list @staticmethod def judge_ecs_in_jms(assets_list, ecs_list): """ 判断哪些阿里云ECS实例存在jumpserver中 :param assets_list: List,jumpserver所有资产信息 :param ecs_list: 阿里云所有ECS实例信息 :return: List,List 分别返回阿里云实例已经存在和不存在jumpserver资产中的实例列表 """ jms_ip_set = set() ecs_ip_set = set() for assets in assets_list: jms_ip_set.add(assets['ip']) for ecs in ecs_list: ecs_ip = ecs['NetworkInterfaces']['NetworkInterface'][0]['PrimaryIpAddress'] ecs_ip_set.add(ecs_ip) in_jmp_for_ecs = ecs_ip_set & jms_ip_set not_in_jump_for_ecs = ecs_ip_set - jms_ip_set not_in_ecs_for_jms = jms_ip_set - ecs_ip_set return in_jmp_for_ecs, not_in_jump_for_ecs, not_in_ecs_for_jms def create_assets(self, ecs_list, ip_list): """ 判断阿里云主机是否存在jumpserver中,不存在则创建jumpserver资产 :param ecs_list: 所有ECS实例列表 :param ip_list: 不存在jumpserver资产中的ECS实例ip :return: None 应当返回则创建的资产条目及摘要信息,懒得写了 """ assets_temp = {'id': '', 'hostname': '', 'ip': '', 'platform': 'Linux', 'protocols': ['ssh/34518'], 'is_active': True, 'public_ip': None, 'number': None, 'comment': '', 'vendor': None, 'model': None, 'sn': None, 'cpu_model': None, 'cpu_count': None, 'cpu_cores': None, 'cpu_vcpus': None, 'memory': None, 'disk_total': None, 'disk_info': None, 'os': None, 'os_version': None, 'os_arch': None, 'hostname_raw': None, 'cpu_info': '', 'hardware_info': '', 'domain': None, 'admin_user': None, 'admin_user_display': '', 'nodes': ['b0506981-d3e0-4e28-ba83-968c2521df6b'], 'nodes_display': ['/Default'], 'labels': [], 'labels_display': [], 'connectivity': 'failed', 'date_verified': '', 'created_by': '', 'date_created': '', 'org_id': '00000000-0000-0000-0000-000000000002', 'org_name': 'Default'} add_assets_list = [] for ecs in ecs_list: ecs_ip = ecs['NetworkInterfaces']['NetworkInterface'][0]['PrimaryIpAddress'] # 如果当前ECS实例IP不在jumpserver当前的资产中,则为该ECS创建对应的jumpserver资产 if ecs_ip in ip_list: assets_temp['hostname'] = ecs['InstanceName'] + '-' + ecs_ip assets_temp['ip'] = ecs_ip assets_temp['memory'] = str(ecs['Memory'] / 1024) + 'GB' assets_temp['cpu_vcpus'] = ecs['Cpu'] assets_temp['platform'] = ecs['OSType'].capitalize() assets_temp['os'] = ecs['OSName'] assets_temp['cpu_count'] = ecs['CpuOptions']['ThreadsPerCore'] assets_temp['cpu_cores'] = ecs['CpuOptions']['CoreCount'] assets_temp['disk_total'] = str(self.ecs_api.get_ecs_disk_size(ecs['InstanceId'])) + 'GB' response = requests.post(self.assets_url, headers=self.headers, data=assets_temp) if response.status_code != 201: print("新增资产失败") print("失败资产信息:%s" % assets_temp) print("失败原因:%s" % response.text) break else: add_assets_list.append(ecs_ip) if add_assets_list: print("新增资产条目:%s" % len(add_assets_list)) print("新增资产IP:" + ' '.join(add_assets_list)) else: print("无新增资产") def patch_assets(self, ecs_list, assets_list, exist_ip_list): """ 同步ECS信息到jumpserver :param ecs_list: 所有ECS实例列表 :param assets_list: 所有jumpserver资产信息列表 :param exist_ip_list: 已存在jumpserver中的ECS IP :return: None 应当返回发生变更的资产条目个数及具体信息,懒得写了 """ patch_list = [] patch_ip_list = [] # 循环jumpserver和阿里云并集的IP for exist_ip in exist_ip_list: flag = False # 找到jumpserver和阿里云相同的条目,获取相关条目信息,并对比相关条目信息,如主机名称 内存 磁盘等 for ecs in ecs_list: if ecs['NetworkInterfaces']['NetworkInterface'][0]['PrimaryIpAddress'] == exist_ip: ecs_info = ecs break for assets in assets_list: if assets['ip'] == exist_ip: assets_info = assets break if assets_info['hostname'] != (ecs_info['InstanceName'] + '-' + exist_ip): assets_info['hostname'] = ecs_info['InstanceName'] + '-' + exist_ip flag = True if assets_info['memory'] != (str(ecs_info['Memory'] / 1024) + 'GB'): assets_info['memory'] = (str(ecs_info['Memory'] / 1024) + 'GB') flag = True if assets_info['cpu_vcpus'] != ecs_info['Cpu']: assets_info['cpu_vcpus'] = ecs_info['Cpu'] flag = True if assets_info['cpu_count'] != ecs_info['CpuOptions']['ThreadsPerCore']: assets_info['cpu_count'] = ecs_info['CpuOptions']['ThreadsPerCore'] flag = True if assets_info['cpu_cores'] != ecs_info['CpuOptions']['CoreCount']: assets_info['cpu_cores'] = ecs_info['CpuOptions']['CoreCount'] flag = True if assets_info['disk_total'] != str(self.ecs_api.get_ecs_disk_size(ecs_info['InstanceId'])) + 'GB': assets_info['disk_total'] = str(self.ecs_api.get_ecs_disk_size(ecs_info['InstanceId'])) + 'GB' flag = True if flag: patch_list.append(assets_info) patch_ip_list.append(exist_ip) if patch_list: response = requests.put(self.assets_url, headers=self.headers, json=patch_list) if response.status_code != 200: print("更新资产失败") print("失败资产信息:%s" % assets_info) print("失败原因:%s" % response.text) else: print("更新资产条目:%s" % len(patch_list)) print("更新资产IP:" + ' '.join(patch_ip_list)) else: print("没有需要变更的资产") def delete_asset(self, ip_list): delete_ip_list = [] for ip in ip_list: asset_id = get_asset_id(ip) url = self.assets_url + asset_id + '/' response = requests.delete(url, headers=self.headers) if response.status_code == 204: delete_ip_list.append(ip) else: print("删除资产失败") print("失败资产ip:%s" % ip) print("失败原因:%s" % response.text) if delete_ip_list: print("删除 %s 个条目" % len(delete_ip_list)) print("删除资产IP:" + ' '.join(delete_ip_list)) else: print("没有需要删除的资产")
jms_mysql.py
# -*- coding: utf-8 -*- """ @Time : 2023/2/28 @Author : Bowen @File : jms_mysql @Description : """ import pymysql def get_asset_id(ip): conn = pymysql.connect( host='192.168.1.135', # 数据库地址 port=3306, # 数据库端口 user='root', # 数据库用户名 password='Qwer@123', # 数据库密码 database='jumpserver' # 数据库名称 ) # 创建游标对象 cursor = conn.cursor() # 执行查询操作 sql = "SELECT id FROM assets_asset WHERE ip = '%s'" % ip cursor.execute(sql) # 获取查询结果 result = cursor.fetchone()[0] # 关闭游标和连接 cursor.close() conn.close() return result
main.py
# -*- coding: utf-8 -*- """ @Time : 2023/2/8 @Author : Bowen @File : main @Description : """ from aliyun_ecs import ecs_api from jms_api import jumpserver if __name__ == '__main__': # 实例化aliyun及jumpserver对象 aliyun_obj = ecs_api() jms_obj = jumpserver() # 获取所有ECS及jumpserver对象 ecs_all = aliyun_obj.get_ecs_all() assets_all = jms_obj.get_assets_all() # 分别获取存在jumpserver及不存在jumpserver中的阿里云ECS机器列表 exist_jms_list, not_exist_jms_list, not_exist_ecs_list = jumpserver.judge_ecs_in_jms(assets_list=assets_all, ecs_list=ecs_all) # 如果不存在jumpserver中,则在jumpserver中创建该资产 if not_exist_jms_list: jms_obj.create_assets(ecs_all, not_exist_jms_list) # 如果存在jumpserver中,则校验ECS当前信息与jumpserver信息是否一致,如果不一致则参考ECS进行修改 if exist_jms_list: jms_obj.patch_assets(ecs_list=ecs_all, assets_list=assets_all, exist_ip_list=exist_jms_list) # 如果jumpserver中的资产不存在阿里云上,则删除 if not_exist_ecs_list: jms_obj.delete_asset(not_exist_ecs_list)
直接运行main文件,执行结果如下,更详细信息懒得写