skyplatform-iam 1.0.1__py3-none-any.whl → 1.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skyplatform_iam/__init__.py +77 -17
- skyplatform_iam/api.py +366 -0
- skyplatform_iam/config.py +173 -18
- skyplatform_iam/connect_agenterra_iam.py +291 -12
- skyplatform_iam/global_manager.py +272 -0
- skyplatform_iam/middleware.py +363 -24
- skyplatform_iam-1.0.5.dist-info/METADATA +461 -0
- skyplatform_iam-1.0.5.dist-info/RECORD +10 -0
- skyplatform_iam/auth_middleware.py +0 -201
- skyplatform_iam-1.0.1.dist-info/METADATA +0 -262
- skyplatform_iam-1.0.1.dist-info/RECORD +0 -9
- {skyplatform_iam-1.0.1.dist-info → skyplatform_iam-1.0.5.dist-info}/WHEEL +0 -0
skyplatform_iam/config.py
CHANGED
|
@@ -3,18 +3,21 @@ SkyPlatform IAM SDK 配置模块
|
|
|
3
3
|
"""
|
|
4
4
|
import os
|
|
5
5
|
import fnmatch
|
|
6
|
-
|
|
7
|
-
from
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Optional, List, Dict, Any
|
|
8
|
+
from pydantic import BaseModel, Field, validator
|
|
8
9
|
from dotenv import load_dotenv
|
|
9
10
|
|
|
10
11
|
# 加载环境变量
|
|
11
12
|
load_dotenv()
|
|
12
13
|
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
13
16
|
|
|
14
17
|
class AuthConfig(BaseModel):
|
|
15
18
|
"""
|
|
16
19
|
认证配置类
|
|
17
|
-
|
|
20
|
+
支持环境变量和代码配置,增强配置验证和管理功能
|
|
18
21
|
"""
|
|
19
22
|
# IAM服务配置
|
|
20
23
|
agenterra_iam_host: str
|
|
@@ -30,32 +33,184 @@ class AuthConfig(BaseModel):
|
|
|
30
33
|
|
|
31
34
|
# 白名单路径配置(实例变量)
|
|
32
35
|
whitelist_paths: List[str] = Field(default_factory=list)
|
|
36
|
+
|
|
37
|
+
# 连接配置
|
|
38
|
+
timeout: int = 30
|
|
39
|
+
max_retries: int = 3
|
|
40
|
+
|
|
41
|
+
# 缓存配置
|
|
42
|
+
enable_cache: bool = True
|
|
43
|
+
cache_ttl: int = 300 # 5分钟
|
|
33
44
|
|
|
34
45
|
class Config:
|
|
35
|
-
env_prefix = "
|
|
46
|
+
env_prefix = "SKYPLATFORM_"
|
|
47
|
+
validate_assignment = True
|
|
48
|
+
|
|
49
|
+
@validator('agenterra_iam_host')
|
|
50
|
+
def validate_iam_host(cls, v):
|
|
51
|
+
"""验证IAM主机地址"""
|
|
52
|
+
if not v:
|
|
53
|
+
raise ValueError("agenterra_iam_host不能为空")
|
|
54
|
+
if not (v.startswith('http://') or v.startswith('https://')):
|
|
55
|
+
raise ValueError("agenterra_iam_host必须以http://或https://开头")
|
|
56
|
+
return v.rstrip('/') # 移除末尾的斜杠
|
|
57
|
+
|
|
58
|
+
@validator('server_name')
|
|
59
|
+
def validate_server_name(cls, v):
|
|
60
|
+
"""验证服务名称"""
|
|
61
|
+
if not v or not v.strip():
|
|
62
|
+
raise ValueError("server_name不能为空")
|
|
63
|
+
return v.strip()
|
|
64
|
+
|
|
65
|
+
@validator('access_key')
|
|
66
|
+
def validate_access_key(cls, v):
|
|
67
|
+
"""验证访问密钥"""
|
|
68
|
+
if not v or not v.strip():
|
|
69
|
+
raise ValueError("access_key不能为空")
|
|
70
|
+
if len(v.strip()) < 8:
|
|
71
|
+
raise ValueError("access_key长度不能少于8个字符")
|
|
72
|
+
return v.strip()
|
|
73
|
+
|
|
74
|
+
@validator('timeout')
|
|
75
|
+
def validate_timeout(cls, v):
|
|
76
|
+
"""验证超时时间"""
|
|
77
|
+
if v <= 0:
|
|
78
|
+
raise ValueError("timeout必须大于0")
|
|
79
|
+
return v
|
|
80
|
+
|
|
81
|
+
@validator('max_retries')
|
|
82
|
+
def validate_max_retries(cls, v):
|
|
83
|
+
"""验证最大重试次数"""
|
|
84
|
+
if v < 0:
|
|
85
|
+
raise ValueError("max_retries不能小于0")
|
|
86
|
+
return v
|
|
87
|
+
|
|
88
|
+
@validator('cache_ttl')
|
|
89
|
+
def validate_cache_ttl(cls, v):
|
|
90
|
+
"""验证缓存TTL"""
|
|
91
|
+
if v <= 0:
|
|
92
|
+
raise ValueError("cache_ttl必须大于0")
|
|
93
|
+
return v
|
|
36
94
|
|
|
37
95
|
@classmethod
|
|
38
|
-
def from_env(cls) -> "AuthConfig":
|
|
96
|
+
def from_env(cls, prefix: str = "SKYPLATFORM_") -> "AuthConfig":
|
|
39
97
|
"""
|
|
40
98
|
从环境变量创建配置
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
prefix: 环境变量前缀,默认为SKYPLATFORM_
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
AuthConfig: 配置实例
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
ValueError: 配置验证失败
|
|
41
108
|
"""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
109
|
+
logger.info(f"从环境变量加载配置,前缀: {prefix}")
|
|
110
|
+
|
|
111
|
+
# 支持多种环境变量前缀(向后兼容)
|
|
112
|
+
def get_env_value(key: str, default: str = '') -> str:
|
|
113
|
+
# 优先使用新前缀
|
|
114
|
+
value = os.environ.get(f"{prefix}{key}", '')
|
|
115
|
+
if not value:
|
|
116
|
+
# 回退到旧前缀
|
|
117
|
+
value = os.environ.get(f"AGENTERRA_{key}", default)
|
|
118
|
+
return value
|
|
119
|
+
|
|
120
|
+
# 解析白名单路径
|
|
121
|
+
whitelist_paths_str = get_env_value('WHITELIST_PATHS', '')
|
|
122
|
+
whitelist_paths = []
|
|
123
|
+
if whitelist_paths_str:
|
|
124
|
+
whitelist_paths = [path.strip() for path in whitelist_paths_str.split(',') if path.strip()]
|
|
125
|
+
|
|
126
|
+
config = cls(
|
|
127
|
+
agenterra_iam_host=get_env_value('IAM_HOST'),
|
|
128
|
+
server_name=get_env_value('SERVER_NAME'),
|
|
129
|
+
access_key=get_env_value('ACCESS_KEY'),
|
|
130
|
+
enable_debug=get_env_value('ENABLE_DEBUG', 'false').lower() == 'true',
|
|
131
|
+
whitelist_paths=whitelist_paths,
|
|
132
|
+
timeout=int(get_env_value('TIMEOUT', '30')),
|
|
133
|
+
max_retries=int(get_env_value('MAX_RETRIES', '3')),
|
|
134
|
+
enable_cache=get_env_value('ENABLE_CACHE', 'true').lower() == 'true',
|
|
135
|
+
cache_ttl=int(get_env_value('CACHE_TTL', '300'))
|
|
48
136
|
)
|
|
137
|
+
|
|
138
|
+
logger.info(f"配置加载完成: server_name={config.server_name}, "
|
|
139
|
+
f"iam_host={config.agenterra_iam_host}, "
|
|
140
|
+
f"whitelist_paths_count={len(config.whitelist_paths)}")
|
|
141
|
+
|
|
142
|
+
return config
|
|
143
|
+
|
|
144
|
+
def validate_config(self) -> None:
|
|
145
|
+
"""
|
|
146
|
+
验证配置完整性
|
|
147
|
+
|
|
148
|
+
Raises:
|
|
149
|
+
ValueError: 配置验证失败
|
|
150
|
+
"""
|
|
151
|
+
logger.debug("开始验证配置完整性")
|
|
152
|
+
|
|
153
|
+
# Pydantic会自动调用validator,这里只需要检查业务逻辑
|
|
154
|
+
if not self.agenterra_iam_host:
|
|
155
|
+
raise ValueError("agenterra_iam_host不能为空")
|
|
156
|
+
if not self.server_name:
|
|
157
|
+
raise ValueError("server_name不能为空")
|
|
158
|
+
if not self.access_key:
|
|
159
|
+
raise ValueError("access_key不能为空")
|
|
160
|
+
|
|
161
|
+
logger.info("配置验证通过")
|
|
49
162
|
|
|
50
|
-
def
|
|
163
|
+
def merge_config(self, other: "AuthConfig") -> "AuthConfig":
|
|
164
|
+
"""
|
|
165
|
+
合并配置,other的非空值会覆盖当前配置
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
other: 要合并的配置
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
AuthConfig: 合并后的新配置实例
|
|
51
172
|
"""
|
|
52
|
-
|
|
173
|
+
logger.debug("开始合并配置")
|
|
174
|
+
|
|
175
|
+
# 获取当前配置的字典表示
|
|
176
|
+
current_dict = self.dict()
|
|
177
|
+
other_dict = other.dict()
|
|
178
|
+
|
|
179
|
+
# 合并配置
|
|
180
|
+
merged_dict = current_dict.copy()
|
|
181
|
+
for key, value in other_dict.items():
|
|
182
|
+
if key == 'whitelist_paths':
|
|
183
|
+
# 白名单路径需要合并而不是覆盖
|
|
184
|
+
merged_paths = list(set(current_dict[key] + value))
|
|
185
|
+
merged_dict[key] = merged_paths
|
|
186
|
+
elif value: # 只有非空值才覆盖
|
|
187
|
+
merged_dict[key] = value
|
|
188
|
+
|
|
189
|
+
logger.debug(f"配置合并完成,合并后的配置: {merged_dict}")
|
|
190
|
+
return AuthConfig(**merged_dict)
|
|
191
|
+
|
|
192
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
193
|
+
"""
|
|
194
|
+
转换为字典格式
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Dict: 配置字典
|
|
198
|
+
"""
|
|
199
|
+
return self.dict()
|
|
200
|
+
|
|
201
|
+
def copy_with_updates(self, **updates) -> "AuthConfig":
|
|
202
|
+
"""
|
|
203
|
+
创建配置副本并更新指定字段
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
**updates: 要更新的字段
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
AuthConfig: 更新后的配置副本
|
|
53
210
|
"""
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
raise ValueError(f"配置项 {field} 不能为空")
|
|
58
|
-
return True
|
|
211
|
+
config_dict = self.dict()
|
|
212
|
+
config_dict.update(updates)
|
|
213
|
+
return AuthConfig(**config_dict)
|
|
59
214
|
|
|
60
215
|
def _normalize_path(self, path: str) -> str:
|
|
61
216
|
"""
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import requests
|
|
3
2
|
import logging
|
|
4
3
|
import traceback
|
|
5
4
|
import copy
|
|
6
|
-
from dotenv import load_dotenv
|
|
7
5
|
from enum import Enum
|
|
8
|
-
|
|
9
|
-
# 加载环境变量
|
|
10
|
-
load_dotenv()
|
|
6
|
+
from fastapi import HTTPException, status
|
|
11
7
|
|
|
12
8
|
|
|
13
9
|
class CredentialTypeEnum(str, Enum):
|
|
@@ -19,14 +15,31 @@ class CredentialTypeEnum(str, Enum):
|
|
|
19
15
|
|
|
20
16
|
|
|
21
17
|
class ConnectAgenterraIam(object):
|
|
22
|
-
|
|
18
|
+
_instance = None
|
|
19
|
+
_initialized = False
|
|
20
|
+
|
|
21
|
+
def __new__(cls, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
|
|
22
|
+
"""
|
|
23
|
+
单例模式实现
|
|
24
|
+
确保整个应用中只有一个ConnectAgenterraIam实例
|
|
25
|
+
"""
|
|
26
|
+
if cls._instance is None:
|
|
27
|
+
cls._instance = super(ConnectAgenterraIam, cls).__new__(cls)
|
|
28
|
+
return cls._instance
|
|
29
|
+
|
|
30
|
+
def __init__(self, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
|
|
23
31
|
"""
|
|
24
32
|
初始化AgenterraIAM连接器
|
|
25
33
|
|
|
26
34
|
参数:
|
|
35
|
+
- config: AuthConfig配置对象,如果为None则从环境变量读取
|
|
27
36
|
- logger_name: 日志记录器名称
|
|
28
37
|
- log_level: 日志级别
|
|
29
38
|
"""
|
|
39
|
+
# 防止重复初始化
|
|
40
|
+
if self._initialized:
|
|
41
|
+
return
|
|
42
|
+
|
|
30
43
|
# 配置日志记录器
|
|
31
44
|
self.logger = logging.getLogger(logger_name)
|
|
32
45
|
if not self.logger.handlers:
|
|
@@ -38,10 +51,22 @@ class ConnectAgenterraIam(object):
|
|
|
38
51
|
self.logger.addHandler(handler)
|
|
39
52
|
self.logger.setLevel(log_level)
|
|
40
53
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
# 必须传入config参数,不再支持从环境变量读取
|
|
55
|
+
if config is None:
|
|
56
|
+
raise ValueError("必须传入AuthConfig配置对象,不再支持从环境变量读取配置")
|
|
57
|
+
|
|
58
|
+
self.agenterra_iam_host = config.agenterra_iam_host
|
|
59
|
+
self.server_name = config.server_name
|
|
60
|
+
self.access_key = config.access_key
|
|
61
|
+
self.logger.info("使用传入的AuthConfig配置")
|
|
62
|
+
|
|
63
|
+
# 验证必要的配置
|
|
64
|
+
if not self.agenterra_iam_host:
|
|
65
|
+
self.logger.warning("AGENTERRA_IAM_HOST 配置未设置")
|
|
66
|
+
if not self.server_name:
|
|
67
|
+
self.logger.warning("AGENTERRA_SERVER_NAME 配置未设置")
|
|
68
|
+
if not self.access_key:
|
|
69
|
+
self.logger.warning("AGENTERRA_ACCESS_KEY 配置未设置")
|
|
45
70
|
|
|
46
71
|
self.logger.info(f"初始化AgenterraIAM连接器 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
|
|
47
72
|
|
|
@@ -54,6 +79,95 @@ class ConnectAgenterraIam(object):
|
|
|
54
79
|
"server_name": self.server_name,
|
|
55
80
|
"access_key": self.access_key
|
|
56
81
|
}
|
|
82
|
+
|
|
83
|
+
# 标记为已初始化
|
|
84
|
+
self._initialized = True
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def get_instance(cls):
|
|
88
|
+
"""
|
|
89
|
+
获取已初始化的ConnectAgenterraIam单例实例
|
|
90
|
+
|
|
91
|
+
如果实例尚未初始化,会抛出异常提示用户先进行配置
|
|
92
|
+
这个方法通常在用户已经通过setup_auth()进行配置后使用
|
|
93
|
+
|
|
94
|
+
返回:
|
|
95
|
+
- ConnectAgenterraIam: 已初始化的单例实例
|
|
96
|
+
|
|
97
|
+
异常:
|
|
98
|
+
- RuntimeError: 当实例未初始化时抛出
|
|
99
|
+
"""
|
|
100
|
+
if cls._instance is None or not cls._initialized:
|
|
101
|
+
raise RuntimeError(
|
|
102
|
+
"ConnectAgenterraIam实例尚未初始化。请先使用以下方式之一进行配置:\n"
|
|
103
|
+
"1. 使用setup_auth()进行一键配置\n"
|
|
104
|
+
"2. 手动创建ConnectAgenterraIam实例:ConnectAgenterraIam(config=your_config)"
|
|
105
|
+
)
|
|
106
|
+
return cls._instance
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def get_instance_lazy(cls):
|
|
110
|
+
"""
|
|
111
|
+
获取已初始化的单例实例(延迟模式)
|
|
112
|
+
|
|
113
|
+
此方法支持延迟初始化,当实例未初始化时返回 None 而不是抛出异常。
|
|
114
|
+
适用于在模块导入时需要获取实例但可能尚未初始化的场景。
|
|
115
|
+
|
|
116
|
+
返回:
|
|
117
|
+
- ConnectAgenterraIam: 已初始化的单例实例,如果未初始化则返回 None
|
|
118
|
+
"""
|
|
119
|
+
if cls._instance is None or not cls._initialized:
|
|
120
|
+
return None
|
|
121
|
+
return cls._instance
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def is_initialized(cls):
|
|
125
|
+
"""
|
|
126
|
+
检查单例实例是否已初始化
|
|
127
|
+
|
|
128
|
+
返回:
|
|
129
|
+
- bool: 如果实例已初始化返回 True,否则返回 False
|
|
130
|
+
"""
|
|
131
|
+
return cls._instance is not None and cls._initialized
|
|
132
|
+
|
|
133
|
+
def reload_config(self, config):
|
|
134
|
+
"""
|
|
135
|
+
重新加载配置
|
|
136
|
+
用于在运行时更新配置
|
|
137
|
+
|
|
138
|
+
参数:
|
|
139
|
+
- config: AuthConfig配置对象
|
|
140
|
+
"""
|
|
141
|
+
if config is None:
|
|
142
|
+
raise ValueError("必须传入AuthConfig配置对象")
|
|
143
|
+
|
|
144
|
+
self.logger.info("重新加载配置")
|
|
145
|
+
|
|
146
|
+
# 更新配置
|
|
147
|
+
self.agenterra_iam_host = config.agenterra_iam_host
|
|
148
|
+
self.server_name = config.server_name
|
|
149
|
+
self.access_key = config.access_key
|
|
150
|
+
|
|
151
|
+
# 验证必要的配置
|
|
152
|
+
if not self.agenterra_iam_host:
|
|
153
|
+
self.logger.warning("AGENTERRA_IAM_HOST 配置未设置")
|
|
154
|
+
if not self.server_name:
|
|
155
|
+
self.logger.warning("AGENTERRA_SERVER_NAME 配置未设置")
|
|
156
|
+
if not self.access_key:
|
|
157
|
+
self.logger.warning("AGENTERRA_ACCESS_KEY 配置未设置")
|
|
158
|
+
|
|
159
|
+
# 更新headers和body
|
|
160
|
+
self.headers = {
|
|
161
|
+
"Content-Type": "application/json",
|
|
162
|
+
"SERVER-AK": self.server_name,
|
|
163
|
+
"SERVER-SK": self.access_key
|
|
164
|
+
}
|
|
165
|
+
self.body = {
|
|
166
|
+
"server_name": self.server_name,
|
|
167
|
+
"access_key": self.access_key
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
self.logger.info(f"配置重新加载完成 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
|
|
57
171
|
|
|
58
172
|
def _mask_sensitive(self, value, mask_char="*", show_chars=4):
|
|
59
173
|
"""
|
|
@@ -430,6 +544,11 @@ class ConnectAgenterraIam(object):
|
|
|
430
544
|
"server_sk": server_sk,
|
|
431
545
|
}
|
|
432
546
|
uri = "/api/v2/service/verify"
|
|
547
|
+
|
|
548
|
+
# 检查agenterra_iam_host是否为None
|
|
549
|
+
if self.agenterra_iam_host is None:
|
|
550
|
+
raise ValueError("AGENTERRA_IAM_HOST 配置未设置或为空,请确保传入正确的AuthConfig对象")
|
|
551
|
+
|
|
433
552
|
url = self.agenterra_iam_host + uri
|
|
434
553
|
|
|
435
554
|
# 记录请求信息
|
|
@@ -463,7 +582,6 @@ class ConnectAgenterraIam(object):
|
|
|
463
582
|
else:
|
|
464
583
|
# token有效但无权限,抛出403异常
|
|
465
584
|
self.logger.warning(f"[{method_name}] token有效但用户无权限访问API: {api}")
|
|
466
|
-
from fastapi import HTTPException, status
|
|
467
585
|
raise HTTPException(
|
|
468
586
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
469
587
|
detail=result.get("message", "用户无权限访问此API")
|
|
@@ -475,7 +593,6 @@ class ConnectAgenterraIam(object):
|
|
|
475
593
|
result = response.json()
|
|
476
594
|
# 处理403响应
|
|
477
595
|
self.logger.warning(f"[{method_name}] 收到403响应 - {result.get('message', '用户无权限访问此API')}")
|
|
478
|
-
from fastapi import HTTPException, status
|
|
479
596
|
raise HTTPException(
|
|
480
597
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
481
598
|
detail=result.get("message", "用户无权限访问此API")
|
|
@@ -690,6 +807,168 @@ class ConnectAgenterraIam(object):
|
|
|
690
807
|
self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
|
|
691
808
|
return False
|
|
692
809
|
|
|
810
|
+
def add_custom_config(self, user_id, config_name, config_value=None):
|
|
811
|
+
"""
|
|
812
|
+
机机接口:添加用户自定义配置
|
|
813
|
+
|
|
814
|
+
为指定用户添加或更新自定义属性配置。
|
|
815
|
+
|
|
816
|
+
参数:
|
|
817
|
+
- user_id: 用户ID
|
|
818
|
+
- config_name: 配置项名称
|
|
819
|
+
- config_value: 配置项值(可选)
|
|
820
|
+
|
|
821
|
+
返回:
|
|
822
|
+
- 成功: 返回响应对象
|
|
823
|
+
- 失败: 返回False
|
|
824
|
+
"""
|
|
825
|
+
method_name = "add_custom_config"
|
|
826
|
+
self.logger.info(f"[{method_name}] 开始添加用户自定义配置 - user_id: {user_id}, config_name: {config_name}")
|
|
827
|
+
|
|
828
|
+
try:
|
|
829
|
+
body = {
|
|
830
|
+
"server_name": self.server_name,
|
|
831
|
+
"access_key": self.access_key,
|
|
832
|
+
"user_id": user_id,
|
|
833
|
+
"config_name": config_name
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
# 添加可选参数
|
|
837
|
+
if config_value is not None:
|
|
838
|
+
body["config_value"] = config_value
|
|
839
|
+
|
|
840
|
+
uri = "/api/v2/service/add_custom_config"
|
|
841
|
+
url = self.agenterra_iam_host + uri
|
|
842
|
+
|
|
843
|
+
# 记录请求信息
|
|
844
|
+
self._log_request(method_name, url, self.headers, body)
|
|
845
|
+
|
|
846
|
+
response = requests.post(
|
|
847
|
+
url=url,
|
|
848
|
+
headers=self.headers,
|
|
849
|
+
json=body,
|
|
850
|
+
verify=False
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
# 记录响应信息
|
|
854
|
+
self._log_response(method_name, response)
|
|
855
|
+
|
|
856
|
+
if response.status_code == 200:
|
|
857
|
+
self.logger.info(f"[{method_name}] 添加用户自定义配置成功")
|
|
858
|
+
return response
|
|
859
|
+
else:
|
|
860
|
+
self.logger.warning(f"[{method_name}] 添加用户自定义配置失败 - 状态码: {response.status_code}")
|
|
861
|
+
|
|
862
|
+
return False
|
|
863
|
+
except Exception as e:
|
|
864
|
+
self.logger.error(f"[{method_name}] 添加用户自定义配置请求异常: {str(e)}")
|
|
865
|
+
self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
|
|
866
|
+
return False
|
|
867
|
+
|
|
868
|
+
def get_custom_configs(self, user_id):
|
|
869
|
+
"""
|
|
870
|
+
机机接口:获取用户自定义配置
|
|
871
|
+
|
|
872
|
+
获取指定用户的所有自定义属性配置。
|
|
873
|
+
|
|
874
|
+
参数:
|
|
875
|
+
- user_id: 用户ID
|
|
876
|
+
|
|
877
|
+
返回:
|
|
878
|
+
- 成功: 返回响应对象
|
|
879
|
+
- 失败: 返回False
|
|
880
|
+
"""
|
|
881
|
+
method_name = "get_custom_configs"
|
|
882
|
+
self.logger.info(f"[{method_name}] 开始获取用户自定义配置 - user_id: {user_id}")
|
|
883
|
+
|
|
884
|
+
try:
|
|
885
|
+
body = {
|
|
886
|
+
"server_name": self.server_name,
|
|
887
|
+
"access_key": self.access_key,
|
|
888
|
+
"user_id": user_id
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
uri = "/api/v2/service/get_custom_configs"
|
|
892
|
+
url = self.agenterra_iam_host + uri
|
|
893
|
+
|
|
894
|
+
# 记录请求信息
|
|
895
|
+
self._log_request(method_name, url, self.headers, body)
|
|
896
|
+
|
|
897
|
+
response = requests.post(
|
|
898
|
+
url=url,
|
|
899
|
+
headers=self.headers,
|
|
900
|
+
json=body,
|
|
901
|
+
verify=False
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
# 记录响应信息
|
|
905
|
+
self._log_response(method_name, response)
|
|
906
|
+
|
|
907
|
+
if response.status_code == 200:
|
|
908
|
+
self.logger.info(f"[{method_name}] 获取用户自定义配置成功")
|
|
909
|
+
return response
|
|
910
|
+
else:
|
|
911
|
+
self.logger.warning(f"[{method_name}] 获取用户自定义配置失败 - 状态码: {response.status_code}")
|
|
912
|
+
|
|
913
|
+
return False
|
|
914
|
+
except Exception as e:
|
|
915
|
+
self.logger.error(f"[{method_name}] 获取用户自定义配置请求异常: {str(e)}")
|
|
916
|
+
self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
|
|
917
|
+
return False
|
|
918
|
+
|
|
919
|
+
def delete_custom_config(self, user_id, config_name):
|
|
920
|
+
"""
|
|
921
|
+
机机接口:删除用户自定义配置
|
|
922
|
+
|
|
923
|
+
删除指定用户的指定自定义属性配置。
|
|
924
|
+
|
|
925
|
+
参数:
|
|
926
|
+
- user_id: 用户ID
|
|
927
|
+
- config_name: 配置项名称
|
|
928
|
+
|
|
929
|
+
返回:
|
|
930
|
+
- 成功: 返回响应对象
|
|
931
|
+
- 失败: 返回False
|
|
932
|
+
"""
|
|
933
|
+
method_name = "delete_custom_config"
|
|
934
|
+
self.logger.info(f"[{method_name}] 开始删除用户自定义配置 - user_id: {user_id}, config_name: {config_name}")
|
|
935
|
+
|
|
936
|
+
try:
|
|
937
|
+
body = {
|
|
938
|
+
"server_name": self.server_name,
|
|
939
|
+
"access_key": self.access_key,
|
|
940
|
+
"user_id": user_id,
|
|
941
|
+
"config_name": config_name
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
uri = "/api/v2/service/delete_custom_config"
|
|
945
|
+
url = self.agenterra_iam_host + uri
|
|
946
|
+
|
|
947
|
+
# 记录请求信息
|
|
948
|
+
self._log_request(method_name, url, self.headers, body)
|
|
949
|
+
|
|
950
|
+
response = requests.post(
|
|
951
|
+
url=url,
|
|
952
|
+
headers=self.headers,
|
|
953
|
+
json=body,
|
|
954
|
+
verify=False
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
# 记录响应信息
|
|
958
|
+
self._log_response(method_name, response)
|
|
959
|
+
|
|
960
|
+
if response.status_code == 200:
|
|
961
|
+
self.logger.info(f"[{method_name}] 删除用户自定义配置成功")
|
|
962
|
+
return response
|
|
963
|
+
else:
|
|
964
|
+
self.logger.warning(f"[{method_name}] 删除用户自定义配置失败 - 状态码: {response.status_code}")
|
|
965
|
+
|
|
966
|
+
return False
|
|
967
|
+
except Exception as e:
|
|
968
|
+
self.logger.error(f"[{method_name}] 删除用户自定义配置请求异常: {str(e)}")
|
|
969
|
+
self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
|
|
970
|
+
return False
|
|
971
|
+
|
|
693
972
|
def merge_credential(self, target_user_id, cred_type, cred_value, merge_reason=None):
|
|
694
973
|
"""
|
|
695
974
|
机机接口:凭证合并
|