Coverage for /Users/jingyu.wy/git/ansible-module-apsarastack/src/ansible_collections/alibaba/apsarastack/plugins/module_utils/apsarastack_connections.py: 21%

219 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-22 16:06 +0800

1# encoding: utf-8 

2''' 

3Created on 2025年3月4日 

4 

5@author: jingyu.wy 

6''' 

7import json 

8import os 

9import types 

10 

11from aliyunsdkcore.auth.credentials import AccessKeyCredential,\ 

12 StsTokenCredential 

13from aliyunsdkcore.client import AcsClient 

14from aliyunsdkcore.request import CommonRequest 

15from footmark.connection import ACSQueryConnection 

16 

17 

18try: 

19 import footmark 

20 import footmark.ecs 

21 import footmark.slb 

22 import footmark.vpc 

23 import footmark.rds 

24 import footmark.ess 

25 import footmark.sts 

26 import footmark.dns 

27 import footmark.ram 

28 import footmark.ros 

29 import footmark.oos 

30 import footmark.oss 

31 import footmark.market 

32 HAS_FOOTMARK = True 

33except ImportError: 

34 HAS_FOOTMARK = False 

35 

36APSARASTACK_ENDPOINTS = { 

37 "vpc": ("vpc-internal.%(domain)s", "vpc-internal.%(region)s.%(domain)s",), 

38 "ecs": ("ecs-internal.%(domain)s", "ecs-internal.%(region)s.%(domain)s",), 

39 "dns": ("dns-control.pop.%(domain)s", "dns-control.pop.%(region)s.%(domain)s",), 

40 "rds": ("rds.%(domain)s", "rds.%(region)s.%(domain)s",), 

41 "slb": ("slb-vpc.%(domain)s", "slb-vpc.%(region)s.%(domain)s",), 

42 "ascm": ("ascm.%(domain)s", "ascm.%(region)s.%(domain)s",), 

43 "ess": ("ess.%(domain)s", "ess.%(region)s.%(domain)s",), 

44 "ram": ("ascm.%(domain)s", "ascm.%(region)s.%(domain)s",), 

45 } 

46 

47 

48class AnsibleACSError(Exception): 

49 pass 

50 

51 

52def get_acs_connection_info(params): 

53 

54 return dict( 

55 acs_access_key_id=params.get('apsarastack_access_key'), 

56 acs_secret_access_key=params.get('apsarastack_secret_key'), 

57 security_token=params.get('apsarastack_security_token'), 

58 ecs_role_name=params.get('ecs_role_name'), 

59 user_agent='Ansible-Provider-Apsarastack', 

60 ) 

61 

62 

63def get_assume_role(params): 

64 """ Return new params """ 

65 sts_params = get_acs_connection_info(params) 

66 assume_role = {} 

67 if params.get('assume_role'): 

68 assume_role['apsarastack_assume_role_arn'] = params['assume_role'].get('role_arn') 

69 assume_role['apsarastack_assume_role_session_name'] = params['assume_role'].get('session_name') 

70 assume_role['apsarastack_assume_role_session_expiration'] = params['assume_role'].get('session_expiration') 

71 assume_role['apsarastack_assume_role_policy'] = params['assume_role'].get('policy') 

72 

73 assume_role_params = { 

74 'role_arn': params.get('apsarastack_assume_role_arn') if params.get('apsarastack_assume_role_arn') else assume_role.get('apsarastack_assume_role_arn'), 

75 'role_session_name': params.get('apsarastack_assume_role_session_name') if params.get('apsarastack_assume_role_session_name') 

76 else assume_role.get('apsarastack_assume_role_session_name'), 

77 'duration_seconds': params.get('apsarastack_assume_role_session_expiration') if params.get('apsarastack_assume_role_session_expiration') 

78 else assume_role.get('apsarastack_assume_role_session_expiration', 3600), 

79 'policy': assume_role.get('apsarastack_assume_role_policy', {}) 

80 } 

81 

82 try: 

83 sts = connect_to_acs(footmark.sts, params.get('apsarastack_region'), **sts_params).assume_role(**assume_role_params).read() 

84 sts_params['acs_access_key_id'], sts_params['acs_secret_access_key'], sts_params['security_token'] \ 

85 = sts['access_key_id'], sts['access_key_secret'], sts['security_token'] 

86 except AnsibleACSError as e: 

87 params.fail_json(msg=str(e)) 

88 return sts_params 

89 

90 

91def get_profile(params): 

92 if not params['apsarastack_access_key'] and not params['ecs_role_name'] and params['profile']: 

93 path = params['shared_credentials_file'] if params['shared_credentials_file'] else os.getenv('HOME') + '/.apsarastack/config.json' 

94 auth = {} 

95 with open(path, 'r') as f: 

96 for pro in json.load(f)['profiles']: 

97 if params['profile'] == pro['name']: 

98 auth = pro 

99 if auth: 

100 if auth['mode'] == 'AK' and auth.get('access_key_id') and auth.get('access_key_secret'): 

101 params['apsarastack_access_key'] = auth.get('access_key_id') 

102 params['apsarastack_secret_key'] = auth.get('access_key_secret') 

103 params['apsarastack_region'] = auth.get('region_id') 

104 params = get_acs_connection_info(params) 

105 elif auth['mode'] == 'StsToken' and auth.get('access_key_id') and auth.get('access_key_secret') and auth.get('sts_token'): 

106 params['apsarastack_access_key'] = auth.get('access_key_id') 

107 params['apsarastack_secret_key'] = auth.get('access_key_secret') 

108 params['security_token'] = auth.get('sts_token') 

109 params['apsarastack_region'] = auth.get('region_id') 

110 params = get_acs_connection_info(params) 

111 elif params.get('apsarastack_assume_role_arn') or params.get('assume_role'): 

112 params = get_assume_role(params) 

113 else: 

114 params = get_acs_connection_info(params) 

115 return params 

116 

117 

118def get_endpoint(domain:str, popcode:str, region:str, is_center_region:bool) -> str: 

119 index = 0 if is_center_region else 1 

120 endpoint_template = APSARASTACK_ENDPOINTS[popcode][index] 

121 return endpoint_template % {"domain":domain, "region":region} 

122 

123def connect_to_acs(acs_module, modules_params:dict, **params): 

124 conn = acs_module.connect_to_region(modules_params['apsarastack_region'], **params) 

125 popcode = acs_module.__name__.split('.')[-1] 

126 conn._endpoint = get_endpoint( 

127 modules_params['apsarastack_domain'], popcode, 

128 modules_params['apsarastack_region'], modules_params['apsarastack_is_center_region'] 

129 ) 

130 conn._default_headers = { 

131 "x-acs-organizationid": modules_params['apsarastack_department'], 

132 "x-acs-resourcegroupid": modules_params['apsarastack_resourcegroup'], 

133 "x-acs-regionid": modules_params['apsarastack_region'], 

134 "x-acs-request-version": "v1", 

135 # "RegionId": client.RegionId, // ASAPI 

136 # "x-acs-organizationid": client.Department, 

137 # "x-acs-resourcegroupid": client.ResourceGroup, 

138 # "x-acs-regionid": client.RegionId, 

139 # "x-acs-request-version": "v1", 

140 # "x-acs-asapi-product": popcode, 

141 # "x-ascm-product-name": popcode, 

142 } 

143 def import_request(self, action): 

144 request = ACSQueryConnection.import_request(self, action) 

145 request.set_endpoint(conn._endpoint) 

146 request.set_headers(conn._default_headers) 

147 return request 

148 

149 conn.import_request = types.MethodType(import_request, conn) 

150 

151 return conn 

152 

153 

154class OssConn(object): 

155 def __init__(self, modules_params): 

156 self.region = modules_params.get('region') 

157 self.security_token = modules_params.get('security_token') 

158 self.acs_access_key_id = modules_params.get('acs_access_key_id') 

159 self.acs_secret_access_key = modules_params.get('acs_secret_access_key') 

160 self.user_agent = modules_params.get('user_agent') 

161def connect_to_bucket(acs_module, modules_params:dict, **params): 

162 conn = OssConn(params) 

163 popcode = acs_module.__name__.split('.')[-1] 

164 conn._endpoint = get_endpoint( 

165 modules_params['apsarastack_domain'], popcode, 

166 modules_params['apsarastack_region'], modules_params['apsarastack_is_center_region'] 

167 ) 

168 conn._default_headers = { 

169 "x-acs-organizationid": modules_params['apsarastack_department'], 

170 "x-acs-resourcegroupid": modules_params['apsarastack_resourcegroup'], 

171 "x-acs-regionid": modules_params['apsarastack_region'], 

172 "x-acs-request-version": "v1", 

173 } 

174 def import_request(self, action): 

175 request = ACSQueryConnection.import_request(self, action) 

176 request.set_endpoint(conn._endpoint) 

177 request.set_headers(conn._default_headers) 

178 return request 

179 

180 conn.import_request = types.MethodType(import_request, conn) 

181 

182 return conn 

183 

184def connect_to_universal(popcode, modules_params:dict, **params): 

185 conn = ACSQueryConnection(region=modules_params['apsarastack_region'], **params) 

186 popcode = "ascm" 

187 conn._endpoint = get_endpoint( 

188 modules_params['apsarastack_domain'], popcode, 

189 modules_params['apsarastack_region'], modules_params['apsarastack_is_center_region'] 

190 ) 

191 conn._default_headers = { 

192 "x-acs-organizationid": modules_params['apsarastack_department'], 

193 "x-acs-resourcegroupid": modules_params['apsarastack_resourcegroup'], 

194 "x-acs-regionid": modules_params['apsarastack_region'], 

195 "x-acs-request-version": "v1", 

196 } 

197 

198 def import_request(self, action): 

199 request = ACSQueryConnection.import_request(self, action) 

200 request.set_endpoint(conn._endpoint) 

201 request.set_headers(conn._default_headers) 

202 return request 

203 

204 conn.import_request = types.MethodType(import_request, conn) 

205 

206 return conn 

207 

208 

209def do_common_request(conn, method:str, popcode: str, version:str, api_name:str, pattern:str="", headers:dict={}, query:dict={}, body:dict=None) -> dict: 

210 if not conn.security_token: 

211 credentials = AccessKeyCredential(conn.acs_access_key_id, conn.acs_secret_access_key) 

212 else: 

213 credentials = StsTokenCredential(conn.acs_access_key_id, conn.acs_secret_access_key, conn.security_token) 

214 # 创建AcsClient连接,timeout设置请求超时时间(单位:ms) 

215 client = AcsClient(region_id=conn.region, credential=credentials, timeout=10000) 

216 # 创建API请求 

217 request = CommonRequest() 

218 # 产品接口信息参数 

219 request.set_product(popcode) 

220 request.set_version(version) 

221 request.set_action_name(api_name) 

222 if pattern: 

223 request.set_uri_pattern(pattern) 

224 request.add_header("x-acs-asapi-product", popcode) 

225 request.add_header("x-ascm-product-name", popcode) 

226 request.add_header("RegionId", conn.region) 

227 # 云产品的Endpoint地址 

228 request.set_domain(conn._endpoint) 

229 request.set_endpoint(conn._endpoint) 

230 # 设置请求方式 

231 request.set_method(method) 

232 # 设置请求协议类型 

233 request.set_protocol_type('http') 

234 

235 # 阿里云核心库SDK发起API请求时,可以设置四种类型参数(Path/Query/Body/Header) 

236 # Path参数用于对请求Request中设置的UriPattern进行变量替换 

237 # Query参数用于对请求Request中的URL参数进行设置(一般用于GET请求) 

238 # Body参数用于对请求Request中的HTTP Content进行设置(一般用于POST/PUT请求),在设置Body参数时,需要同时设置HTTP Content-Type,目前支持JSON和FORM两种格式 

239 # Header参数用于对请求Request中的HTTP Header进行设置 

240 

241 # 设置Headers 

242 # 设置身份标识,标识调用来源,无实际作用,可随意设置,必填项 

243 for k, v in conn._default_headers.items(): 

244 request.add_header(k ,v) 

245 for k, v in headers.items(): 

246 request.add_header(k ,v) 

247 

248 request.add_header("x-acs-caller-sdk-source", conn.user_agent) 

249 request.set_user_agent(conn.user_agent) 

250 

251 if query: 

252 request.set_query_params(query) 

253 

254 if body: 

255 request.set_content_type('application/x-www-form-urlencoded') 

256 

257 request.set_body_params(body) 

258 

259 response = client.do_action_with_exception(request) 

260 

261 return json.loads(response) 

262 

263 

264def ecs_connect(module): 

265 """ Return an ecs connection""" 

266 ecs_params = get_profile(module.params) 

267 # If we have a region specified, connect to its endpoint. 

268 region = module.params.get('apsarastack_region') 

269 if region: 

270 try: 

271 ecs = connect_to_acs(footmark.ecs, module.params, **ecs_params) 

272 except AnsibleACSError as e: 

273 module.fail_json(msg=str(e)) 

274 # Otherwise, no region so we fallback to the old connection method 

275 return ecs 

276 

277 

278def vpc_connect(module): 

279 """ Return an vpc connection""" 

280 vpc_params = get_profile(module.params) 

281 # If we have a region specified, connect to its endpoint. 

282 try: 

283 vpc = connect_to_acs(footmark.vpc, module.params, **vpc_params) 

284 except AnsibleACSError as e: 

285 module.fail_json(msg=str(e)) 

286 # Otherwise, no region so we fallback to the old connection method 

287 return vpc 

288 

289 

290def dns_connect(module): 

291 """ Return an dns connection""" 

292 dns_params = get_profile(module.params) 

293 try: 

294 dns = connect_to_acs(footmark.dns, module.params, **dns_params) 

295 except AnsibleACSError as e: 

296 module.fail_json(msg=str(e)) 

297 # Otherwise, no region so we fallback to the old connection method 

298 return dns 

299 

300def rds_connect(module): 

301 """ Return an rds connection""" 

302 rds_params = get_profile(module.params) 

303 try: 

304 rds = connect_to_acs(footmark.rds, module.params, **rds_params) 

305 except AnsibleACSError as e: 

306 module.fail_json(msg=str(e)) 

307 # Otherwise, no region so we fallback to the old connection method 

308 return rds 

309 

310 

311def slb_connect(module): 

312 """ Return an slb connection""" 

313 slb_params = get_profile(module.params) 

314 try: 

315 slb = connect_to_acs(footmark.slb, module.params, **slb_params) 

316 except AnsibleACSError as e: 

317 module.fail_json(msg=str(e)) 

318 # Otherwise, no region so we fallback to the old connection method 

319 return slb 

320 

321 

322def ascm_connect(module): 

323 """ Return an ascm connection""" 

324 ascm_params = get_profile(module.params) 

325 try: 

326 ascm = connect_to_universal("ascm", module.params, **ascm_params) 

327 except AnsibleACSError as e: 

328 module.fail_json(msg=str(e)) 

329 # Otherwise, no region so we fallback to the old connection method 

330 return ascm 

331 

332 

333def ossbucket_connect(module): 

334 """ Return an oss bucket connection""" 

335 oss_params = get_profile(module.params) 

336 del oss_params["ecs_role_name"] 

337 try: 

338 oss_bucket = connect_to_bucket(footmark.oss, module.params, **oss_params) 

339 except AnsibleACSError as e: 

340 module.fail_json(msg=str(e)) 

341 # Otherwise, no region so we fallback to the old connection method 

342 return oss_bucket 

343 

344 

345def ossservice_connect(module): 

346 """ Return an oss service connection""" 

347 rds_params = get_profile(module.params) 

348 try: 

349 oss_service = connect_to_acs(footmark.oss, module.params, **rds_params) 

350 except AnsibleACSError as e: 

351 module.fail_json(msg=str(e)) 

352 # Otherwise, no region so we fallback to the old connection method 

353 return oss_service 

354 

355def ess_connect(module): 

356 """ Return an ess service connection""" 

357 ess_params = get_profile(module.params) 

358 try: 

359 ess = connect_to_acs(footmark.ess, module.params, **ess_params) 

360 except AnsibleACSError as e: 

361 module.fail_json(msg=str(e)) 

362 # Otherwise, no region so we fallback to the old connection method 

363 return ess 

364 

365 

366def ram_connect(module): 

367 """ Return an ram service connection""" 

368 ram_params = get_profile(module.params) 

369 try: 

370 ram = connect_to_acs(footmark.ram, module.params, **ram_params) 

371 except AnsibleACSError as e: 

372 module.fail_json(msg=str(e)) 

373 # Otherwise, no region so we fallback to the old connection method 

374 return ram