Skip to content

Commit

Permalink
feature: SaaS 适配动态 IP 安装校验,统一业务逻辑 IPv6 表示法 (closed #926 closed #927 #787
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ZhuoZhuoCrayon committed Jul 18, 2022
1 parent eee8213 commit bb5857b
Show file tree
Hide file tree
Showing 18 changed files with 363 additions and 230 deletions.
27 changes: 8 additions & 19 deletions apps/backend/components/collections/agent_new/query_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,27 +114,16 @@ def _is_auth_info_empty(_sub_inst: models.SubscriptionInstanceRecord, _host_info
identity_data_objs_to_be_created.append(identity_data_obj)
continue

# 更新场景下,传入 `auth_type` 需要提供完整认证信息用于更新,否则使用快照
auth_type: Optional[str] = host_info.get("auth_type")
if not auth_type:
identity_data_objs_to_be_updated.append(identity_data_obj)
continue

# 处理认证信息不完整的情况
if _is_auth_info_empty(sub_inst, host_info):
empty_auth_info_sub_inst_ids.append(sub_inst.id)
continue

# 允许缺省时使用快照
# 更新策略:优先使用传入数据,否则使用历史快照
identity_data_obj.port = host_info.get("port") or identity_data_obj.port
identity_data_obj.account = host_info.get("account") or identity_data_obj.account

# 更新认证信息
identity_data_obj.auth_type = auth_type
identity_data_obj.password = base64.b64decode(host_info.get("password", "")).decode()
identity_data_obj.key = base64.b64decode(host_info.get("key", "")).decode()
identity_data_obj.retention = host_info.get("retention", 1)
identity_data_obj.extra_data = host_info.get("extra_data", {})
identity_data_obj.auth_type = host_info.get("auth_type") or identity_data_obj.auth_type
identity_data_obj.password = (
base64.b64decode(host_info.get("password", "")).decode() or identity_data_obj.password
)
identity_data_obj.key = base64.b64decode(host_info.get("key", "")).decode() or identity_data_obj.key
identity_data_obj.retention = host_info.get("retention", 1) or identity_data_obj.retention
identity_data_obj.extra_data = host_info.get("extra_data", {}) or identity_data_obj.extra_data
identity_data_obj.updated_at = timezone.now()

identity_data_objs_to_be_updated.append(identity_data_obj)
Expand Down
10 changes: 10 additions & 0 deletions apps/backend/subscription/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from apps.node_man import constants, models, tools
from apps.node_man.models import ProcessStatus
from apps.node_man.serializers import policy
from apps.utils import basic


class GatewaySerializer(serializers.Serializer):
Expand All @@ -32,6 +33,15 @@ class ScopeSerializer(serializers.Serializer):
need_register = serializers.BooleanField(required=False, default=False)
nodes = serializers.ListField()

def validate(self, attrs):
for node in attrs["nodes"]:
basic.ipv6_formatter(data=node, ipv6_field_names=["ip"])
basic.ipv6_formatter(
data=node.get("instance_info", {}),
ipv6_field_names=["bk_host_innerip_v6", "bk_host_outerip_v6", "login_ip", "data_ip"],
)
return attrs


class TargetHostSerializer(serializers.Serializer):
bk_host_id = serializers.CharField(required=False, label="目标机器主机ID")
Expand Down
1 change: 1 addition & 0 deletions apps/backend/subscription/steps/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class ReinstallAgent(AgentAction):
def _generate_activities(self, agent_manager: AgentManager):

activities = [
agent_manager.add_or_update_hosts() if settings.BKAPP_ENABLE_DHCP else None,
agent_manager.query_password(),
agent_manager.choose_ap(),
agent_manager.install(),
Expand Down
37 changes: 27 additions & 10 deletions apps/backend/subscription/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""
import copy
import hashlib
import ipaddress
import logging
import math
import os
Expand Down Expand Up @@ -476,16 +477,32 @@ def get_host_detail(host_info_list: list, bk_biz_id: int = None):
host_infos_gby_bk_cloud_id[host_info["bk_cloud_id"]].append(host_info)
rules = []
for bk_cloud_id, host_infos in host_infos_gby_bk_cloud_id.items():
ips = [host_info["ip"] for host_info in host_infos]
rules.append(
{
"condition": "AND",
"rules": [
{"field": "bk_host_innerip", "operator": "in", "value": ips},
{"field": "bk_cloud_id", "operator": "equal", "value": bk_cloud_id},
],
}
)
ipv4s = set()
ipv6s = set()
for host_info in host_infos:
if ipaddress.ip_address(host_info["ip"]).version == constants.CmdbIpVersion.V6.value:
ipv6s.add(host_info["ip"])
else:
ipv4s.add(host_info["ip"])
for ip_field_name, ips in [("bk_host_innerip", ipv4s), ("bk_host_innerip_v6", ipv6s)]:
# 如果为空,
if not ips:
continue
rules.append(
{
"condition": "AND",
"rules": [
# 仅允许静态 IP 通过 ip + 云区域 方式下发订阅
{
"field": "bk_addressing",
"operator": "equal",
"value": constants.CmdbAddressingType.STATIC.value,
},
{"field": ip_field_name, "operator": "in", "value": ips},
{"field": "bk_cloud_id", "operator": "equal", "value": bk_cloud_id},
],
}
)
cond = {"host_property_filter": {"condition": "OR", "rules": rules}}
else:
# 如果不满足 bk_host_id / ip & bk_cloud_id 的传入格式,此时直接返回空列表,表示查询不到任何主机
Expand Down
11 changes: 11 additions & 0 deletions apps/node_man/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,17 @@ def _get_member__alias_map(cls) -> Dict[Enum, str]:
return {cls.STATIC: _("静态"), cls.DYNAMIC: _("动态")}


class CmdbIpVersion(EnhanceEnum):
"""IP 版本"""

V4 = 4
V6 = 6

@classmethod
def _get_member__alias_map(cls) -> Dict[Enum, str]:
return {cls.V4: _("IPv4"), cls.V6: _("IPv6")}


class PolicyRollBackType:
SUPPRESSED = "SUPPRESSED"
LOSE_CONTROL = "LOSE_CONTROL"
Expand Down
98 changes: 59 additions & 39 deletions apps/node_man/handlers/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""
from typing import List
from typing import Iterable, List, Optional

from django.db import transaction
from django.db.models import Count
Expand Down Expand Up @@ -364,9 +364,12 @@ def list(self, params: dict, username: str):
"bk_cloud_id",
"bk_biz_id",
"bk_host_id",
"bk_addressing",
"os_type",
"inner_ip",
"inner_ipv6",
"outer_ip",
"outer_ipv6",
"ap_id",
"install_channel_id",
"login_ip",
Expand Down Expand Up @@ -478,7 +481,9 @@ def proxies(bk_cloud_id: int):
"bk_cloud_id",
"bk_host_id",
"inner_ip",
"inner_ipv6",
"outer_ip",
"outer_ipv6",
"login_ip",
"data_ip",
"bk_biz_id",
Expand Down Expand Up @@ -576,7 +581,15 @@ def biz_proxies(bk_biz_id: int):
# 获得proxy相应数据
proxies = list(
Host.objects.filter(bk_cloud_id__in=bk_cloud_ids, node_type=const.NodeType.PROXY).values(
"bk_cloud_id", "bk_host_id", "inner_ip", "outer_ip", "login_ip", "data_ip", "bk_biz_id"
"bk_cloud_id",
"bk_addressing",
"inner_ip",
"inner_ipv6",
"outer_ip",
"outer_ipv6",
"login_ip",
"data_ip",
"bk_biz_id",
)
)

Expand Down Expand Up @@ -751,10 +764,13 @@ def remove_host(self, params: dict):

return {}

def ip_list(self, ips):
@staticmethod
def ip_list(ips: Iterable[str], ip_version: int, bk_addressing: Optional[str] = None):
"""
返回存在ips的所有云区域-IP的列表
:param ips: IP列表
返回存在
:param ips:
:param ip_version:
:param bk_addressing: 寻址方式
:return:
{
bk_cloud_id+ip: {
Expand All @@ -765,47 +781,51 @@ def ip_list(self, ips):
}
},
"""
ips = set(ips)

if bk_addressing is None:
bk_addressing = const.CmdbAddressingType.STATIC.value

login_ip_field_name = "login_ip"
login_ip_filter_k = "login_ip__in"

# 根据 IP 版本筛选不同的 IP 字段
if ip_version == const.CmdbIpVersion.V6.value:
inner_ip_field_name = "inner_ipv6"
outer_ip_field_name = "outer_ipv6"
inner_ip_filter_k = "inner_ipv6__in"
outer_ip_filter_k = "outer_ipv6__in"
else:
inner_ip_field_name = "inner_ip"
outer_ip_field_name = "outer_ip"
inner_ip_filter_k = "inner_ip__in"
outer_ip_filter_k = "outer_ip__in"

fields: List[str] = [
"inner_ip",
"inner_ipv6",
"outer_ip",
"outer_ipv6",
"login_ip",
"bk_cloud_id",
"bk_biz_id",
"node_type",
"bk_host_id",
]

inner_ip_info = {
f"{host['bk_cloud_id']}-{host['inner_ip']}": {
"inner_ip": host["inner_ip"],
"outer_ip": host["outer_ip"],
"login_ip": host["login_ip"],
"bk_cloud_id": host["bk_cloud_id"],
"bk_biz_id": host["bk_biz_id"],
"node_type": host["node_type"],
"bk_host_id": host["bk_host_id"],
}
for host in Host.objects.filter(inner_ip__in=ips).values(
"inner_ip", "outer_ip", "login_ip", "bk_cloud_id", "bk_biz_id", "node_type", "bk_host_id"
)
f"{host['bk_cloud_id']}-{host[inner_ip_field_name]}": host
for host in Host.objects.filter(bk_addressing=bk_addressing, **{inner_ip_filter_k: ips}).values(*fields)
}

outer_ip_info = {
f"{host['bk_cloud_id']}-{host['outer_ip']}": {
"inner_ip": host["inner_ip"],
"login_ip": host["login_ip"],
"bk_cloud_id": host["bk_cloud_id"],
"bk_biz_id": host["bk_biz_id"],
"node_type": host["node_type"],
"bk_host_id": host["bk_host_id"],
}
for host in Host.objects.filter(outer_ip__in=ips).values(
"inner_ip", "outer_ip", "login_ip", "bk_cloud_id", "bk_biz_id", "node_type", "bk_host_id"
)
f"{host['bk_cloud_id']}-{host[outer_ip_field_name]}": host
for host in Host.objects.filter(bk_addressing=bk_addressing, **{outer_ip_filter_k: ips}).values(*fields)
}

login_ip_info = {
f"{host['bk_cloud_id']}-{host['login_ip']}": {
"inner_ip": host["inner_ip"],
"outer_ip": host["outer_ip"],
"bk_cloud_id": host["bk_cloud_id"],
"bk_biz_id": host["bk_biz_id"],
"node_type": host["node_type"],
"bk_host_id": host["bk_host_id"],
}
for host in Host.objects.filter(login_ip__in=ips).values(
"inner_ip", "outer_ip", "login_ip", "bk_cloud_id", "bk_biz_id", "node_type", "bk_host_id"
)
f"{host['bk_cloud_id']}-{host[login_ip_field_name]}": host
for host in Host.objects.filter(bk_addressing=bk_addressing, **{login_ip_filter_k: ips}).values(*fields)
}

exists_ip_info = {}
Expand Down
Loading

0 comments on commit bb5857b

Please sign in to comment.