Skip to content

Commit

Permalink
feat: 切换云上API (closed TencentBlueKing#2515)
Browse files Browse the repository at this point in the history
  • Loading branch information
wyyalt committed Dec 18, 2024
1 parent c9e28ad commit 5a4a9a6
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 4 deletions.
6 changes: 6 additions & 0 deletions apps/node_man/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,9 @@ class YunTiPolicyConfigNotExistsError(NodeManBaseException):
MESSAGE = _("云梯策略配置不存在")
MESSAGE_TPL = _("云梯策略配置不存在")
ERROR_CODE = 43


class TXYPolicyConfigNotExistsError(NodeManBaseException):
MESSAGE = _("腾讯云策略配置不存在")
MESSAGE_TPL = _("腾讯云策略配置不存在")
ERROR_CODE = 44
111 changes: 111 additions & 0 deletions apps/node_man/handlers/security_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
from typing import Any, Dict, List, Optional

from django.conf import settings
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile

from apps.backend.utils.dataclass import asdict
from apps.node_man.exceptions import (
ConfigurationPolicyError,
TXYPolicyConfigNotExistsError,
YunTiPolicyConfigNotExistsError,
)
from apps.node_man.models import GlobalSettings
Expand Down Expand Up @@ -38,6 +41,25 @@ class YunTiPolicyConfig:
protocol: str


@dataclass
class TXYPolicyConfig:
region: str
sid: str
port: str
action: str
protocol: str


@dataclass
class TXYPolicyData:
Protocol: str
CidrBlock: str
Port: str
Action: str
PolicyDescription: Optional[str] = None
Ipv6CidrBlock: Optional[str] = None


class BaseSecurityGroupFactory(abc.ABC):
SECURITY_GROUP_TYPE = None

Expand Down Expand Up @@ -259,6 +281,95 @@ def check_result(self, add_ip_output: Dict) -> bool:
return is_success


class TXYSecurityGroupFactory(BaseSecurityGroupFactory):
SECURITY_GROUP_TYPE: str = "TXY"

def __init__(self) -> None:
"""
policies_config: example
[
{
"region": "ap-xxx",
"sid": "xxxx",
"port": "ALL",
"action": "ACCEPT",
"protocol": "ALL"
}
]
"""
self.policy_configs: List[Dict[str, Any]] = GlobalSettings.get_config(
key=GlobalSettings.KeyEnum.TXY_POLICY_CONFIGS.value, default=[]
)
if not self.policy_configs:
raise TXYPolicyConfigNotExistsError()

self.endpoint = settings.TXY_ENDPOINT

@property
def profile(self):
httpProfile = HttpProfile()
httpProfile.endpoint = self.endpoint

# 设置客户端相关配置
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
return clientProfile

def describe_security_group_address(self, client: VpcClient, sid: str) -> List[str]:
is_ok, result = client.DescribeSecurityGroupPolicies(sid)
if not is_ok:
raise ConfigurationPolicyError(result)

current_policies: List[Dict[str, Any]] = result["SecurityGroupPolicySet"]["Ingress"]
current_ip_list = [policy["CidrBlock"] for policy in current_policies]
return current_ip_list

def add_ips_to_security_group(self, ip_list: List[str], creator: str = None):
for policy_config in self.policy_configs:
config = TXYPolicyConfig(**policy_config)
new_in_gress: Dict[str, List[Dict[str, Any]]] = []
client = VpcClient(config.region, self.profile)
current_ip_list: List[str] = self.describe_security_group_address(client, config.sid)
need_add_ip_list: set = set(ip_list) - set(current_ip_list)
if need_add_ip_list:
for ip in need_add_ip_list:
new_in_gress.append(
asdict(
TXYPolicyData(
Protocol=config.protocol,
CidrBlock=ip,
Port=config.port,
Action=config.action,
PolicyDescription=f"Add by {creator}",
Ipv6CidrBlock="",
)
)
)
is_ok, message = client.CreateSecurityGroupPolicies(
sg_id=config.sid, policies={"Ingress": new_in_gress}
)
if not is_ok:
raise ConfigurationPolicyError(message)

return {"ip_list": ip_list}

def check_result(self, add_ip_output: Dict) -> bool:
"""检查IP列表是否已添加到安全组中"""
is_success: bool = True
for policy_config in self.policy_configs:
config = TXYPolicyConfig(**policy_config)
client = VpcClient(config.region, self.profile)
current_ip_list: List[str] = self.describe_security_group_address(client, config.sid)
logger.info(
f"check_result: Add proxy whitelist to Shangyun security group security. "
f"sid: {config.sid} ip_list: {add_ip_output['ip_list']}"
)
# 需添加的IP列表是已有IP的子集,则认为已添加成功
is_success: bool = is_success and set(add_ip_output["ip_list"]).issubset(set(current_ip_list))

return is_success


def get_security_group_factory(security_group_type: Optional[str]) -> BaseSecurityGroupFactory:
"""获取安全组工厂,返回None表示无需配置安全组"""
factory_map = {factory.SECURITY_GROUP_TYPE: factory for factory in BaseSecurityGroupFactory.__subclasses__()}
Expand Down
2 changes: 2 additions & 0 deletions apps/node_man/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class KeyEnum(Enum):
INSTALL_CHANNEL_ID_NETWORK_SEGMENT = "INSTALL_CHANNEL_ID_NETWORK_SEGMENT"
# 需要执行清理订阅的APP_CODE
NEED_CLEAN_SUBSCRIPTION_APP_CODE = "NEED_CLEAN_SUBSCRIPTION_APP_CODE"
# 腾讯云安全组策略配置
TXY_POLICY_CONFIGS = "TXY_POLICY_CONFIGS"

key = models.CharField(_("键"), max_length=255, db_index=True, primary_key=True)
v_json = JSONField(_("值"))
Expand Down
38 changes: 34 additions & 4 deletions apps/node_man/policy/tencent_vpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@


class VpcClient(object):
def __init__(self, region="ap-guangzhou"):
def __init__(self, region="ap-guangzhou", profile=None):
self.region = region
self.client = None
self.tencent_secret_id = os.getenv("TXY_SECRETID")
self.tencent_secret_key = os.getenv("TXY_SECRETKEY")
self.ip_templates = os.getenv("TXY_IP_TEMPLATES")
self.ip_templates = os.getenv("TXY_IP_TEMPLATES", "")

# 配置文件包含敏感信息,不需要的环境需要注意去掉
if not all([self.tencent_secret_id, self.tencent_secret_key, self.ip_templates]):
if not all([self.tencent_secret_id, self.tencent_secret_key]):
raise ConfigurationPolicyError("Please contact maintenaner to check Tencent cloud configuration.")

# 将字符串变量转换为列表
self.ip_templates = self.ip_templates.split(",")
cred = credential.Credential(self.tencent_secret_id, self.tencent_secret_key)
self.client = vpc_client.VpcClient(cred, self.region)
self.client = vpc_client.VpcClient(cred, self.region, profile)

def describe_address_templates(self, template_name):
req = models.DescribeAddressTemplatesRequest()
Expand Down Expand Up @@ -64,3 +64,33 @@ def add_ip_to_template(self, template_name, ip_list):
if err.code == "InvalidParameterValue.Duplicate":
return True, err.message
return False, err

def CreateSecurityGroupPolicies(self, sg_id, policies):
"""本接口(CreateSecurityGroupPolicies)用于创建安全组规则(SecurityGroupPolicy)。"""
try:
req = models.CreateSecurityGroupPoliciesRequest()
params = {"SecurityGroupId": sg_id, "SecurityGroupPolicySet": policies}
req.from_json_string(json.dumps(params))
resp = self.client.CreateSecurityGroupPolicies(req)
result = json.loads(resp.to_json_string())
logger.info(f"create_security_group_policies: {result}")
return True, f"request_id: {result.get('RequestId')}"
except TencentCloudSDKException as err:
if err.code == "InvalidParameterValue.Duplicate":
return True, err.message
return False, err

def DescribeSecurityGroupPolicies(self, sg_id):
"""本接口(DescribeSecurityGroupPolicies)用于查询安全组规则(SecurityGroupPolicy)。"""
try:
req = models.DescribeSecurityGroupPoliciesRequest()
params = {"SecurityGroupId": sg_id}
req.from_json_string(json.dumps(params))
resp = self.client.DescribeSecurityGroupPolicies(req)
result = json.loads(resp.to_json_string())
logger.info(f"describe_security_group_policies: {result}")
return True, result
except TencentCloudSDKException as err:
if err.code == "InvalidParameterValue.Duplicate":
return True, err.message
return False, err
3 changes: 3 additions & 0 deletions config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,9 @@ def get_standard_redis_mode(cls, config_redis_mode: str, default: Optional[str]

VERSION_LOG = {"MD_FILES_DIR": os.path.join(PROJECT_ROOT, "release"), "LANGUAGE_MAPPINGS": {"en": "en"}}

# 腾讯云endpoint
TXY_ENDPOINT = env.TXY_ENDPOINT

# ==============================================================================
# 可观测
# ==============================================================================
Expand Down
2 changes: 2 additions & 0 deletions env/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
# 自动选择安装通道相关配置
"BKAPP_DEFAULT_INSTALL_CHANNEL_ID",
"BKAPP_AUTOMATIC_CHOICE_CLOUD_ID",
"TXY_ENDPOINT",
]

# ===============================================================================
Expand Down Expand Up @@ -200,3 +201,4 @@
BKPAAS_SHARED_RES_URL = get_type_env(key="BKPAAS_SHARED_RES_URL", default="", _type=str)
BKAPP_LEGACY_AUTH = get_type_env(key="BKAPP_LEGACY_AUTH", default=False, _type=bool)
BK_NOTICE_ENABLED = get_type_env(key="BK_NOTICE_ENABLED", default=False, _type=bool)
TXY_ENDPOINT = get_type_env(key="TXY_ENDPOINT", default="", _type=str)
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,6 @@ data:
BKAPP_IEOD_ACTIVE_FIREWALL_POLICY_SCRIPT_INFO: '{{ .Values.config.bkAppIEODActiveFirewallPolicyScriptInfo }}'
BKAPP_DEFAULT_INSTALL_CHANNEL_ID: "{{ .Values.config.bkAppDefaultInstallChannelId}}"
BKAPP_AUTOMATIC_CHOICE_CLOUD_ID: "{{ .Values.config.bkAppAutomaticChoiceCloudId}}"
TXY_ENDPOINT: "{{ .Values.config.TXYEndpoint }}"
TXY_SECRETID: "{{ .Values.config.TXYSecretId }}"
TXY_SECRETKEY: "{{ .Values.config.TXYSecretKey }}"

0 comments on commit 5a4a9a6

Please sign in to comment.