Skip to content

Commit 9d0b36d

Browse files
neko12583justin
authored andcommitted
feature: 同步 CMDB 主机 cpu 架构及操作系统信息(closed TencentBlueKing#1454)
# Conflicts: # apps/node_man/models.py
1 parent e2bdb96 commit 9d0b36d

4 files changed

Lines changed: 121 additions & 92 deletions

File tree

apps/node_man/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ def get_optional_items(cls) -> List[str]:
117117
OsType = choices_to_namedtuple(OS_CHOICES)
118118
OS_CHN = {os_type: os_type if os_type == OsType.AIX else os_type.capitalize() for os_type in OS_TUPLE}
119119
BK_OS_TYPE = {"LINUX": "1", "WINDOWS": "2", "AIX": "3", "SOLARIS": "5"}
120+
# 操作系统匹配关键词
121+
OS_KEYWORDS = {
122+
OsType.LINUX: ["linux", "ubuntu", "centos", "redhat", "suse", "debian", "fedora"],
123+
OsType.WINDOWS: ["windows", "xserver"],
124+
OsType.AIX: ["aix"]
125+
}
120126

121127
# 操作系统->系统账户映射表
122128
ACCOUNT_MAP = {
@@ -477,6 +483,10 @@ def _get_member__alias_map(cls) -> Dict[Enum, str]:
477483
OsType.AIX: CpuType.powerpc,
478484
OsType.SOLARIS: CpuType.sparc,
479485
}
486+
CMDB_CPU_MAP = {
487+
"x86": CpuType.x86,
488+
"arm": CpuType.aarch64
489+
}
480490

481491
PACKAGE_PATH_RE = re.compile(
482492
f"(?P<is_external>external_)?plugins_(?P<os>({'|'.join(map(str, PLUGIN_OS_TUPLE))}))"
@@ -622,6 +632,7 @@ class BkappRunEnvType(Enum):
622632
"bk_state",
623633
"bk_state_name",
624634
"bk_supplier_account",
635+
"bk_cpu_architecture",
625636
]
626637

627638
# 限流窗口配置,用于控制CMDB订阅触发的变更频率

apps/node_man/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ class KeyEnum(Enum):
114114
ENABLE_PUSH_HOST_IDENTIFIER = "ENABLE_PUSH_HOST_IDENTIFIER"
115115
# 插件配置公共常量支持 issue: https://github.com/TencentBlueKing/bk-nodeman/issues/1500
116116
PLUGIN_COMMON_CONSTANTS = "PLUGIN_COMMON_CONSTANTS"
117+
# GSE 2.0 灰度列表
118+
GSE2_GRAY_SCOPE_LIST = "GSE2_GRAY_SCOPE_LIST"
119+
# 禁用订阅业务列表
120+
DISABLE_SUBSCRIPTION_SCOPE_LIST = "DISABLE_SUBSCRIPTION_SCOPE_LIST"
121+
GSE2_GRAY_AP_MAP = "GSE2_GRAY_AP_MAP"
122+
# 是否同步 cc 的CPU架构
123+
SYNC_CMDB_HOST_APPLY_CPU_ARCH = "SYNC_CMDB_HOST_APPLY_CPU_ARCH"
124+
# 同步 cc 主机操作系统时,是否 bk_os_type 匹配优先与 bk_os_name
125+
SYNC_CMDB_HOST_OS_TYPE_PRIORITY = "SYNC_CMDB_HOST_OS_TYPE_PRIORITY"
117126

118127
key = models.CharField(_("键"), max_length=255, db_index=True, primary_key=True)
119128
v_json = JSONField(_("值"))

apps/node_man/periodic_tasks/sync_cmdb_host.py

Lines changed: 45 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def _list_resource_pool_hosts(start):
9999
def _bulk_update_host(hosts, extra_fields):
100100
update_fields = [
101101
"node_type",
102+
"bk_biz_id",
102103
"bk_cloud_id",
103104
"bk_host_name",
104105
"bk_addressing",
@@ -107,14 +108,16 @@ def _bulk_update_host(hosts, extra_fields):
107108
"inner_ipv6",
108109
"outer_ipv6",
109110
"bk_agent_id",
111+
"os_type",
110112
] + extra_fields
111113
if hosts:
112114
models.Host.objects.bulk_update(hosts, fields=update_fields)
113115

114116

115-
def _generate_host(biz_id, host, ap_id):
116-
os_type = tools.HostV2Tools.get_os_type(host)
117-
cpu_arch = tools.HostV2Tools.get_cpu_arch(host)
117+
def _generate_host(biz_id, host, ap_id, is_os_type_priority=False, is_sync_cmdb_host_apply_cpu_arch=False):
118+
os_type = tools.HostV2Tools.get_os_type(host, is_os_type_priority)
119+
cpu_arch = tools.HostV2Tools.get_cpu_arch(host, is_sync_cmdb_host_apply_cpu_arch, os_type=os_type)
120+
118121
host_data = models.Host(
119122
bk_host_id=host["bk_host_id"],
120123
bk_agent_id=host.get("bk_agent_id"),
@@ -192,16 +195,16 @@ def update_or_create_host_base(biz_id, task_id, cmdb_host_data):
192195
).values_list("bk_host_id", flat=True)
193196
)
194197

195-
need_delete_host_ids: typing.Set[int] = set()
196-
need_create_host_without_biz: typing.List[typing.Dict] = []
198+
is_sync_cmdb_host_apply_cpu_arch = tools.HostV2Tools.is_sync_cmdb_host_apply_cpu_arch()
199+
is_os_type_priority = tools.HostV2Tools.is_os_type_priority()
200+
197201
need_update_hosts: typing.List[models.Host] = []
198-
need_update_hosts_without_biz: typing.List[models.Host] = []
199-
need_update_hosts_without_os: typing.List[models.Host] = []
200-
need_update_hosts_without_biz_os: typing.List[models.Host] = []
202+
need_update_hosts_with_arch: typing.List[models.Host] = []
203+
201204
need_create_hosts: typing.List[models.Host] = []
202-
need_update_host_identity_objs: typing.List[models.IdentityData] = []
203205
need_create_host_identity_objs: typing.List[models.IdentityData] = []
204206
need_create_process_status_objs: typing.List[models.ProcessStatus] = []
207+
need_update_host_identity_objs: typing.List[models.IdentityData] = []
205208

206209
ap_id = constants.DEFAULT_AP_ID if models.AccessPoint.objects.count() > 1 else models.AccessPoint.objects.first().id
207210

@@ -218,6 +221,7 @@ def update_or_create_host_base(biz_id, task_id, cmdb_host_data):
218221
host_params = {
219222
"bk_host_id": host["bk_host_id"],
220223
"bk_agent_id": host.get("bk_agent_id"),
224+
"bk_biz_id": biz_id,
221225
"bk_cloud_id": host["bk_cloud_id"],
222226
"bk_host_name": host.get("bk_host_name"),
223227
"bk_addressing": host.get("bk_addressing") or constants.CmdbAddressingType.STATIC.value,
@@ -226,74 +230,47 @@ def update_or_create_host_base(biz_id, task_id, cmdb_host_data):
226230
"inner_ipv6": (host.get("bk_host_innerip_v6") or "").split(",")[0],
227231
"outer_ipv6": (host.get("bk_host_outerip_v6") or "").split(",")[0],
228232
}
229-
if host["bk_host_id"] in exist_agent_host_ids:
230233

231-
os_type = tools.HostV2Tools.get_os_type(host)
234+
if host["bk_host_id"] in exist_agent_host_ids:
235+
host_params["os_type"] = tools.HostV2Tools.get_os_type(host, is_os_type_priority)
232236
host_params["node_type"] = (constants.NodeType.PAGENT, constants.NodeType.AGENT)[
233237
host["bk_cloud_id"] == constants.DEFAULT_CLOUD
234238
]
235-
236-
if os_type and biz_id:
237-
host_params["bk_biz_id"] = biz_id
238-
host_params["os_type"] = os_type
239-
need_update_hosts.append(models.Host(**host_params))
240-
elif biz_id:
241-
host_params["bk_biz_id"] = biz_id
242-
need_update_hosts_without_os.append(models.Host(**host_params))
243-
elif os_type:
244-
host_params["os_type"] = os_type
245-
need_update_hosts_without_biz.append(models.Host(**host_params))
246-
else:
247-
need_update_hosts_without_biz_os.append(models.Host(**host_params))
248239
elif host["bk_host_id"] in exist_proxy_host_ids:
249240
host_params["os_type"] = constants.OsType.LINUX
250241
host_params["node_type"] = constants.NodeType.PROXY
251-
if biz_id:
252-
host_params["bk_biz_id"] = biz_id
253-
need_update_hosts.append(models.Host(**host_params))
254-
else:
255-
need_update_hosts_without_biz.append(models.Host(**host_params))
256242
else:
257-
# 不是agent不是proxy的主机需要创建
258-
if not biz_id:
259-
need_create_host_without_biz.append(host)
243+
host_data, identify_data, process_status_data = _generate_host(
244+
biz_id,
245+
host,
246+
ap_id,
247+
is_os_type_priority,
248+
is_sync_cmdb_host_apply_cpu_arch,
249+
)
250+
need_create_hosts.append(host_data)
251+
if identify_data.bk_host_id not in host_ids_in_exist_identity_data:
252+
need_create_host_identity_objs.append(identify_data)
260253
else:
261-
host_data, identify_data, process_status_data = _generate_host(biz_id, host, ap_id)
262-
need_create_hosts.append(host_data)
263-
if identify_data.bk_host_id not in host_ids_in_exist_identity_data:
264-
need_create_host_identity_objs.append(identify_data)
265-
else:
266-
need_update_host_identity_objs.append(identify_data)
267-
if process_status_data.bk_host_id not in host_ids_in_exist_proc_statuses:
268-
need_create_process_status_objs.append(process_status_data)
269-
270-
if need_create_host_without_biz:
271-
# 查询业务主机数据进行创建
272-
find_host_biz_ids = [_host["bk_host_id"] for _host in need_create_host_without_biz]
273-
host_biz_relation = find_host_biz_relations(find_host_biz_ids)
274-
# 查询不到业务需要删除
275-
need_delete_host_ids = set(find_host_biz_ids) - set(host_biz_relation.keys())
276-
277-
for need_create_host in need_create_host_without_biz:
278-
if need_create_host["bk_host_id"] not in need_delete_host_ids:
279-
host_data, identify_data, process_status_data = _generate_host(
280-
host_biz_relation[need_create_host["bk_host_id"]],
281-
need_create_host,
282-
ap_id,
283-
)
284-
need_create_hosts.append(host_data)
285-
if identify_data.bk_host_id not in host_ids_in_exist_identity_data:
286-
need_create_host_identity_objs.append(identify_data)
287-
else:
288-
need_update_host_identity_objs.append(identify_data)
289-
if process_status_data.bk_host_id not in host_ids_in_exist_proc_statuses:
290-
need_create_process_status_objs.append(process_status_data)
254+
need_update_host_identity_objs.append(identify_data)
255+
if process_status_data.bk_host_id not in host_ids_in_exist_proc_statuses:
256+
need_create_process_status_objs.append(process_status_data)
257+
continue
258+
259+
cpu_arch = tools.HostV2Tools.get_cpu_arch(
260+
host,
261+
is_sync_cmdb_host_apply_cpu_arch,
262+
get_default=False,
263+
)
264+
if is_sync_cmdb_host_apply_cpu_arch and cpu_arch:
265+
host_params["cpu_arch"] = cpu_arch
266+
need_update_hosts_with_arch.append(models.Host(**host_params))
267+
continue
268+
269+
need_update_hosts.append(models.Host(**host_params))
291270

292271
with transaction.atomic():
293-
_bulk_update_host(need_update_hosts, ["bk_biz_id", "os_type"])
294-
_bulk_update_host(need_update_hosts_without_biz, ["os_type"])
295-
_bulk_update_host(need_update_hosts_without_os, ["bk_biz_id"])
296-
_bulk_update_host(need_update_hosts_without_biz_os, [])
272+
_bulk_update_host(need_update_hosts, [])
273+
_bulk_update_host(need_update_hosts_with_arch, ["cpu_arch"])
297274

298275
if need_create_hosts:
299276
models.Host.objects.bulk_create(need_create_hosts, batch_size=500)
@@ -306,7 +283,7 @@ def update_or_create_host_base(biz_id, task_id, cmdb_host_data):
306283
if need_create_process_status_objs:
307284
models.ProcessStatus.objects.bulk_create(need_create_process_status_objs, batch_size=500)
308285

309-
return bk_host_ids, list(need_delete_host_ids)
286+
return bk_host_ids
310287

311288

312289
def sync_biz_incremental_hosts(bk_biz_id: int, expected_bk_host_ids: typing.Iterable[int]):
@@ -362,7 +339,7 @@ def _update_or_create_host(biz_id, start=0, task_id=None):
362339
f"host_count -> {host_count}, range -> {start}-{start + constants.QUERY_CMDB_LIMIT}"
363340
)
364341

365-
bk_host_ids, _ = update_or_create_host_base(biz_id, task_id, host_data)
342+
bk_host_ids = update_or_create_host_base(biz_id, task_id, host_data)
366343

367344
# 递归
368345
if host_count > start + constants.QUERY_CMDB_LIMIT:

apps/node_man/tools/host_v2.py

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,71 @@
1717

1818
class HostV2Tools:
1919
@classmethod
20-
def get_os_type(cls, host: Dict) -> str:
21-
"""根据CC的主机属性,得到可能的操作系统"""
22-
bk_os_name = host.get("bk_os_name") or "unknown"
23-
bk_os_type = host.get("bk_os_type")
24-
os_name = bk_os_name.lower()
20+
def get_os_type_by_os_type(cls, bk_os_type: str) -> Optional[str]:
21+
"""根据 os_type 获取主机操作系统"""
22+
return constants.OS_TYPE.get(bk_os_type)
23+
24+
@classmethod
25+
def get_os_type_by_os_name(cls, bk_os_name: str) -> Optional[str]:
26+
"""根据 os_name 获取主机操作系统"""
27+
bk_os_name = bk_os_name.lower()
28+
29+
for os_type, keywords in constants.OS_KEYWORDS.items():
30+
for keyword in keywords:
31+
if keyword in bk_os_name:
32+
return os_type
2533

26-
linux_keywords = ["linux", "ubuntu", "centos", "redhat", "suse", "debian", "fedora"]
27-
windows_keywords = ["windows", "xserver"]
28-
aix_keywords = ["aix"]
34+
return None
2935

30-
for linux_keyword in linux_keywords:
31-
if linux_keyword in os_name:
32-
return constants.OsType.LINUX
36+
@classmethod
37+
def is_os_type_priority(cls) -> bool:
38+
return bool(
39+
models.GlobalSettings.get_config(models.GlobalSettings.KeyEnum.SYNC_CMDB_HOST_OS_TYPE_PRIORITY.value)
40+
)
3341

34-
for windows_keyword in windows_keywords:
35-
if windows_keyword in os_name:
36-
return constants.OsType.WINDOWS
42+
@classmethod
43+
def get_os_type(cls, host: Dict, is_os_type_priority: bool = False) -> str:
44+
"""根据CC的主机属性,得到可能的操作系统"""
45+
bk_os_name = host.get("bk_os_name") or "unknown"
46+
bk_os_type = host.get("bk_os_type")
3747

38-
for aix_keyword in aix_keywords:
39-
if aix_keyword in os_name:
40-
return constants.OsType.AIX
48+
os_type = cls.get_os_type_by_os_name(bk_os_name)
4149

42-
if bk_os_type in constants.OS_TYPE:
43-
return constants.OS_TYPE[bk_os_type]
50+
if is_os_type_priority:
51+
os_type = cls.get_os_type_by_os_type(bk_os_type) or os_type
52+
else:
53+
os_type = os_type or cls.get_os_type_by_os_type(bk_os_type)
4454

4555
# 若CMDB中区分不出操作系统,则默认是LINUX
46-
return constants.OsType.LINUX
56+
return os_type or constants.OsType.LINUX
4757

4858
@classmethod
49-
def get_cpu_arch(cls, host: Dict) -> str:
50-
os_type = cls.get_os_type(host)
51-
# 暂时通过操作系统区分CPU架构,后续通过CMDB的CPU架构字段区分
52-
return constants.DEFAULT_OS_CPU_MAP.get(os_type, constants.CpuType.x86_64)
59+
def is_sync_cmdb_host_apply_cpu_arch(cls) -> bool:
60+
sync_cmdb_host_apply_cpu_arch = models.GlobalSettings.get_config(
61+
models.GlobalSettings.KeyEnum.SYNC_CMDB_HOST_APPLY_CPU_ARCH.value
62+
)
63+
return bool(sync_cmdb_host_apply_cpu_arch)
64+
65+
@classmethod
66+
def get_cpu_arch(
67+
cls,
68+
host: Dict,
69+
is_sync_cmdb_host_apply_cpu_arch: bool = False,
70+
get_default: bool = True,
71+
os_type: str = constants.OsType.LINUX
72+
) -> Optional[str]:
73+
if is_sync_cmdb_host_apply_cpu_arch:
74+
cpu_arch = constants.CMDB_CPU_MAP.get(host.get("bk_cpu_architecture"))
75+
if cpu_arch == constants.CpuType.x86 and host.get("bk_os_bit"):
76+
bk_os_bit = host.get("bk_os_bit")
77+
bit_suffix = "" if "32" in bk_os_bit else "_64"
78+
return cpu_arch + bit_suffix
79+
elif cpu_arch:
80+
return cpu_arch
81+
if get_default:
82+
return constants.DEFAULT_OS_CPU_MAP.get(os_type, constants.CpuType.x86_64)
83+
84+
return None
5385

5486
@classmethod
5587
def list_scope_host_ids(cls, scope: Dict) -> List[int]:

0 commit comments

Comments
 (0)