共计 8404 个字符,预计需要花费 22 分钟才能阅读完成。
之前博主在使用ansible +阿里云ecs 标签实现主机信息过滤和生成,但是每台ecs绑定的标签数量有限(20个),遂想要自己扩展下,干脆建个简陋的cmdb(只有db:mongodb)o( ̄┰ ̄*)ゞ
大致逻辑
获取 ECS 信息
创建RAM用户和AK/SK
安装SDK依赖
需要用到的api: DescribeInstances,安装依赖:
pip install alibabacloud_ecs20140526==2.1.1
简单样例,获取单挑数据
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import sys
from typing import List
from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_ecs20140526 import models as ecs_20140526_models
class Sample:
def __init__(self):
pass
@staticmethod
def create_client(
access_key_id: str,
access_key_secret: str,
) -> Ecs20140526Client:
"""
使用AK&SK初始化账号Client
@param access_key_id:
@param access_key_secret:
@return: Client
@throws Exception
"""
config = open_api_models.Config(
# 您的AccessKey ID,
access_key_id="access_key_id",
# 您的AccessKey Secret,
access_key_secret="access_key_secret"
)
# 访问的域名
config.endpoint = f'ecs-cn-hangzhou.aliyuncs.com'
return Ecs20140526Client(config)
@staticmethod
def main(
args: List[str],
) -> None:
client = Sample.create_client('accessKeyId', 'accessKeySecret')
describe_instances_request = ecs_20140526_models.DescribeInstancesRequest(
region_id='cn-shenzhen',
page_number=1,
page_size=1
)
# 复制代码运行请自行打印 API 的返回值
res = client.describe_instances(describe_instances_request).body.to_map()
print(json.dumps(res))
if __name__ == '__main__':
Sample.main(sys.argv[1:])
测试结果
{
"Instances":{
"Instance":[
{
"AutoReleaseTime":"",
"ClusterId":"",
"Cpu":8,
"CpuOptions":{
"CoreCount":4,
"Numa":"",
"ThreadsPerCore":2
},
"CreationTime":"2020-05-03T05:11Z",
"CreditSpecification":"",
"DedicatedHostAttribute":{
"DedicatedHostClusterId":"",
"DedicatedHostId":"",
"DedicatedHostName":""
},
"DedicatedInstanceAttribute":{
"Affinity":"",
"Tenancy":""
},
"DeletionProtection":false,
"DeploymentSetId":"",
"Description":"",
"DeviceAvailable":true,
"EcsCapacityReservationAttr":{
"CapacityReservationId":"",
"CapacityReservationPreference":""
},
"EipAddress":{
"AllocationId":"",
"InternetChargeType":"",
"IpAddress":""
},
"ExpiredTime":"2020-06-03T16:00Z",
"GPUAmount":0,
"GPUSpec":"",
"HibernationOptions":{
"Configured":false
},
"HostName":"iZz56sxxxxxzkZ",
"ImageId":"win2016_1607_x64_dtc_zh-cn_40G_alibase_20200311.vhd",
"ImageOptions":{
},
"InnerIpAddress":{
"IpAddress":[
]
},
"InstanceChargeType":"PrePaid",
"InstanceId":"i-iZz56sxxxxxzkZ",
"InstanceName":"launch-advisor-20200503",
"InstanceNetworkType":"vpc",
"InstanceType":"ecs.c7.2xlarge",
"InstanceTypeFamily":"ecs.c7",
"InternetChargeType":"PayByBandwidth",
"InternetMaxBandwidthIn":5000,
"InternetMaxBandwidthOut":20,
"IoOptimized":true,
"Memory":16384,
"MetadataOptions":{
"HttpEndpoint":"",
"HttpTokens":""
},
"NetworkInterfaces":{
"NetworkInterface":[
{
"MacAddress":"00:16:3e:12:a4:1b",
"NetworkInterfaceId":"eni-wz9xxx19imewia",
"PrimaryIpAddress":"10.200.1.144",
"PrivateIpSets":{
"PrivateIpSet":[
{
"Primary":true,
"PrivateIpAddress":"10.200.1.144"
}
]
},
"Type":"Primary"
}
]
},
"OSName":"Windows Server 2016 \u6570\u636e\u4e2d\u5fc3\u7248 64\u4f4d\u4e2d\u6587\u7248",
"OSNameEn":"Windows Server 2016 Data Center Edition 64bit Chinese Edition",
"OSType":"windows",
"OperationLocks":{
"LockReason":[
]
},
"PublicIpAddress":{
"IpAddress":[
"xxxxxxxxxxxxx"
]
},
"Recyclable":false,
"RegionId":"cn-shenzhen",
"ResourceGroupId":"",
"SaleCycle":"",
"SecurityGroupIds":{
"SecurityGroupId":[
"sg-wz9d0xxxt4i9fg36y3"
]
},
"SerialNumber":"00159a9c-74b2-4541-a02xxx29266ca",
"SpotPriceLimit":0,
"SpotStrategy":"NoSpot",
"StartTime":"2020-05-03T05:11Z",
"Status":"Running",
"StoppedMode":"Not-applicable",
"VlanId":"",
"VpcAttributes":{
"NatIpAddress":"",
"PrivateIpAddress":{
"IpAddress":[
"10.200.1.144"
]
},
"VSwitchId":"vsw-wz9cpxxln62ws0kmw0",
"VpcId":"vpc-wz95lwxxtg6pjctear"
},
"ZoneId":"cn-shenzhen-e"
}
]
},
"NextToken":"4f1d7cc9f51e189029a6ac20e03a54ba666795b580cac90be0b5e8707e68181f",
"PageNumber":1,
"PageSize":1,
"RequestId":"4E4E86B0-D344-5D25-A2D5-54AFCEB0FDE2",
"TotalCount":357
}
获取单个地域所有样例
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import sys
import time
from typing import List
import json
from alibabacloud_ecs20140526.client import Client as Ecs20140526Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_ecs20140526 import models as ecs_20140526_models
class EcsInfo:
def __init__(self):
pass
@staticmethod
def create_client(
access_key_id: str,
access_key_secret: str,
) -> Ecs20140526Client:
"""
使用AK&SK初始化账号Client
@param access_key_id:
@param access_key_secret:
@return: Client
@throws Exception
"""
config = open_api_models.Config(
# 您的AccessKey ID,
access_key_id="access_key_id",
# 您的AccessKey Secret,
access_key_secret="access_key_secret"
)
# 访问的域名
config.endpoint = f'ecs.cn-shenzhen.aliyuncs.com'
return Ecs20140526Client(config)
@staticmethod
def main(
args: List[str],
) -> list:
client = EcsInfo.create_client('accessKeyId', 'accessKeySecret')
# tag_0 = ecs_20140526_models.DescribeInstancesRequestTag(
# key='os',
# value='windows'
# )
# tag_1 = ecs_20140526_models.DescribeInstancesRequestTag(
# key='owner',
# value='zhangke'
# )
next_token = ''
describe_instances_request = ecs_20140526_models.DescribeInstancesRequest(
region_id='cn-shenzhen',
max_results=10,
next_token=next_token
# tag=[
# tag_0,
# tag_1
# ]
)
res = client.describe_instances(describe_instances_request).body.to_map()
next_token = res['NextToken']
# print(next_token)
instances_list = res['Instances']['Instance']
while next_token:
time.sleep(0.5)
# next_token = res['NextToken']
describe_instances_request = ecs_20140526_models.DescribeInstancesRequest(
region_id='cn-shenzhen',
max_results=10,
next_token=next_token
)
res = client.describe_instances(describe_instances_request).body.to_map()
next_token = res['NextToken']
instances_list.extend(res['Instances']['Instance'])
return instances_list
if __name__ == '__main__':
#print(sys.argv)
#print(sys.argv[1:])
instances = EcsInfo.main(sys.argv[1:])
print(len(instances))
for instance in instances:
print(instance)
测试结果
将数据写入mongodb
# 创建一个Cmdb类
class Cmdb:
def __init__(self):
pass
@staticmethod
def create_db_client(
db_user: str,
db_pass: str,
db_host: str,
db_port: str,
db_name: str
) -> object:
DbClient = pymongo.MongoClient("mongodb://"+ db_user + ':' + db_pass + '@' + db_host + ':' +db_port + "/")
return DbClient
@staticmethod
def update_ecs_info(instances: list) -> None:
db_client = Cmdb.create_db_client(
db_user="cmdbadminxxxx",
db_pass="123456xxxx",
db_host="192.168.174.132",
db_port="27017",
db_name="cmdb"
)
mydb = db_client["cmdb"]
mycol = mydb["ecsinfo2"]
for doc in instances:
# 根据实例id唯一进行查找判断是更新还是新增
query = {'InstanceId': doc['InstanceId']}
res = mycol.find_one(query)
# 后期新增自定义的字段EcsTag,需要保留
if res and 'EcsTag' in res:
doc['EcsTag'] = res['EcsTag']
print("==[update]==",doc)
mycol.update_one(query,{"$set": doc})
else:
doc['EcsTag'] = []
print("==[insert]==",doc)
x = mycol.insert_one(doc)
测试更新或新增
从Mongodb获取ecs信息
# 在Cmdb类中创建查询方法
@staticmethod
def get_ecs_info(
query: dict,
) -> None:
db_client = Cmdb.create_db_client(
db_user="cmdbadminxxxx",
db_pass="123456xxxx",
db_host="192.168.174.132",
db_port="27017",
db_name="cmdb"
)
mydb = db_client["cmdb"]
mycol = mydb["ecsinfo2"]
# print(query)
query_lists = list(mycol.find(query))
return query_lists
测试查询结果
新增自定义字段
在原有的数据中已存在Tag字段,该字段是从阿里云ECS openapi获取的ecs 标签,想了想还是新建一个字段EcsTag吧~
# 扩展字段如下,可以自行再扩展如:增加用户信息,创建时间等
{
"EcsTag": [
{
'ProjectName': 'demo_project1',
'ProjectService': 'demo_service1',
'BuildVersion': '#1254',
'env': 'test',
'status': 'running'
},
{
'ProjectName': 'demo_project2',
'ProjectService': 'demo_service2',
'BuildVersion': '#1254',
'env': 'test',
'status': 'running'
}
]
}
新增打标方法
# 再原有的Cmdb类中新增一个打标方法,一次只更新一台ecs的一个或多个标签
@staticmethod
def update_ecs_info_ecstag(query:dict,data:list)->None:
db_client = Cmdb.create_db_client(
db_user="cmdbadminxxxx",
db_pass="123456xxxx",
db_host="192.168.174.132",
db_port="27017",
db_name="cmdb"
)
mydb = db_client["cmdb"]
mycol = mydb["ecsinfo2"]
query = query
data = data
# 先获取已有标签
res = mycol.find_one(query,{'_id':0,"EcsTag":1})
res_list = res['EcsTag']
print(len(res_list),res_list)
# 处理已有标签的更新或新增数据的合并
if res_list:
datatmp = data[:]
for i in data:
for j in res_list:
if i['ProjectName'] == j['ProjectName'] and i['ProjectService'] == j['ProjectService']:
# print(res_list.index(j))
print("==[update]==",i)
update_query = {
'$and': [
query,
{
'EcsTag.ProjectName': j['ProjectName'],
'EcsTag.ProjectService': j['ProjectService']
}
]
}
mycol.update_one(update_query ,{
'$set': {
'EcsTag.$': i
}
})
datatmp.remove(i)
print("==[insert]==", datatmp)
mycol.update_one(query, {'$addToSet': {'EcsTag': {'$each': datatmp}}})
else:
print("==[insert]==",data)
mycol.update_one(query, {'$set': {'EcsTag': data }})
db_client.close()
测试更新
调用get_ecs_info()查询项目所在服务器
# 先自行打标~
if __name__ == '__main__':
tagkey_query = {'EcsTag.ProjectName': 'demo_project2','EcsTag.ProjectService': 'demo_service2'}
tagkey_option = {'_id':0,'InstanceId':1,'VpcAttributes.PrivateIpAddress':1}
ecs_infos = Cmdb.get_ecs_info(tagkey_query,tagkey_option)
print(len(ecs_infos))
for i in ecs_infos:
print(i)
正文完