Coverage for /Users/jingyu.wy/git/ansible-module-apsarastack/src/ansible_collections/alibaba/apsarastack/plugins/modules/ali_vpc.py: 30%

101 statements  

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

1#!/usr/bin/python 

2# -*- coding: utf-8 -*- 

3 

4# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com.com> 

5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 

6# 

7# This file is part of Ansible 

8# 

9# Ansible is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# Ansible is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with Ansible. If not, see http://www.gnu.org/licenses/. 

21 

22from __future__ import (absolute_import, division, print_function) 

23 

24import time 

25 

26from ansible.module_utils.basic import AnsibleModule 

27 

28try: 

29 from ansible_collections.alibaba.apsarastack.plugins.module_utils.apsarastack_common import common_argument_spec 

30 from ansible_collections.alibaba.apsarastack.plugins.module_utils.apsarastack_connections import vpc_connect 

31except ImportError: 

32 from ..module_utils.apsarastack_common import common_argument_spec 

33 from ..module_utils.apsarastack_connections import vpc_connect 

34 

35__metaclass__ = type 

36 

37ANSIBLE_METADATA = {'metadata_version': '1.1', 

38 'status': ['preview'], 

39 'supported_by': 'community'} 

40 

41DOCUMENTATION = """ 

42--- 

43module: ali_vpc 

44short_description: Configure Alibaba Cloud virtual private cloud(VPC) 

45description: 

46 - Create, Delete Apsarastack virtual private cloud(VPC). 

47 It supports updating VPC description. 

48options: 

49 state: 

50 description: 

51 - Whether or not to create, delete VPC. 

52 choices: ['present', 'absent'] 

53 type: str 

54 default: 'present' 

55 name: 

56 description: 

57 - The name to give your VPC, which is a string of 2 to 128 Chinese or English characters. It must begin with an 

58 uppercase/lowercase letter or a Chinese character and can contain numerals, "_" or "-". 

59 It cannot begin with http:// or https://. 

60 This is used in combination with C(cidr_block) to determine if a VPC already exists. 

61 aliases: ['vpc_name'] 

62 type: str 

63 vpc_id: 

64 description: 

65 - The id of VPC, required when operate existing vpc. 

66 type: str 

67 aliases: ['id'] 

68 description: 

69 description: 

70 - The description of VPC, which is a string of 2 to 256 characters. It cannot begin with http:// or https://. 

71 type: str 

72 cidr_block: 

73 description: 

74 - The primary CIDR of the VPC. This is used in conjunction with the C(name) to ensure idempotence. 

75 aliases: ['cidr'] 

76 required: True 

77 type: str 

78 user_cidrs: 

79 description: 

80 - List of user custom cidr in the VPC. It no more than three. 

81 type: list 

82 elements: str 

83 multi_ok: 

84 description: 

85 - By default the module will not create another VPC if there is another VPC with the same name and CIDR block. 

86 Specify this as true if you want duplicate VPCs created. 

87 default: False 

88 type: bool 

89 recent: 

90 description: 

91 - By default the module will not choose the recent one if there is another VPC with the same I(name) and 

92 I(cidr_block). Specify this as true if you want to target the recent VPC. 

93 There will be conflict when I(multi_ok=True) and I(recent=True). 

94 default: False 

95 type: bool 

96 tags: 

97 description: 

98 - A hash/dictionaries of vpc tags. C({"key":"value"}) 

99 type: dict 

100 purge_tags: 

101 description: 

102 - Delete existing tags on the vpc that are not specified in the task. 

103 If True, it means you have to specify all the desired tags on each task affecting a vpc. 

104 default: False 

105 type: bool 

106notes: 

107 - There will be launch a virtual router along with creating a vpc successfully. 

108 - There is only one virtual router in one vpc and one route table in one virtual router. 

109requirements: 

110 - "python >= 3.6" 

111 - "footmark >= 1.14.1" 

112extends_documentation_fragment: 

113 - apsarastack 

114author: 

115 - "Wang Yu (@zshongyi) 

116 - "He Guimin (@xiaozhu36)" 

117""" 

118 

119EXAMPLES = """ 

120# Note: These examples do not set authentication details, see the Alibaba Cloud Guide for details. 

121- name: Create a new vpc 

122 ali_vpc: 

123 cidr_block: '192.168.0.0/16' 

124 name: 'Demo_VPC' 

125 description: 'Demo VPC' 

126 

127- name: Choose the latest VPC as target when there are several vpcs with same name and cidr block 

128 ali_vpc: 

129 cidr_block: '192.168.0.0/16' 

130 name: 'Demo_VPC' 

131 recent: True 

132 

133- name: Delete a vpc 

134 ali_vpc: 

135 state: absent 

136 cidr_block: '192.168.0.0/16' 

137 name: 'Demo_VPC' 

138""" 

139 

140RETURN = ''' 

141vpc: 

142 description: info about the VPC that was created or deleted 

143 returned: always 

144 type: complex 

145 contains: 

146 cidr_block: 

147 description: The CIDR of the VPC 

148 returned: always 

149 type: str 

150 sample: 10.0.0.0/8 

151 creation_time: 

152 description: The time the VPC was created. 

153 returned: always 

154 type: str 

155 sample: '2018-06-24T15:14:45Z' 

156 description: 

157 description: The VPC description. 

158 returned: always 

159 type: str 

160 sample: "my ansible vpc" 

161 id: 

162 description: alias of 'vpc_id'. 

163 returned: always 

164 type: str 

165 sample: vpc-c2e00da5 

166 is_default: 

167 description: indicates whether this is the default VPC 

168 returned: always 

169 type: bool 

170 sample: false 

171 state: 

172 description: state of the VPC 

173 returned: always 

174 type: str 

175 sample: available 

176 tags: 

177 description: tags attached to the VPC, includes name 

178 returned: always 

179 type: dict 

180 sample: 

181 user_cidrs: 

182 description: The custom CIDR of the VPC 

183 returned: always 

184 type: list 

185 sample: [] 

186 vpc_id: 

187 description: VPC resource id 

188 returned: always 

189 type: str 

190 sample: vpc-c2e00da5 

191 vpc_name: 

192 description: Name of the VPC 

193 returned: always 

194 type: str 

195 sample: my-vpc 

196 vrouter_id: 

197 description: The ID of virtual router which in the VPC 

198 returned: always 

199 type: str 

200 sample: available 

201 vswitch_ids: 

202 description: List IDs of virtual switch which in the VPC 

203 returned: always 

204 type: list 

205 sample: [vsw-123cce3, vsw-34cet4v] 

206''' 

207 

208 

209HAS_FOOTMARK = False 

210 

211try: 

212 from footmark.exception import VPCResponseError 

213 HAS_FOOTMARK = True 

214except ImportError: 

215 HAS_FOOTMARK = False 

216 

217 

218def vpc_exists(module, vpc, vpc_id, name, cidr_block, multi, recent): 

219 """Returns None or a vpc object depending on the existence of a VPC. When supplied 

220 with a CIDR and Name, it will check them to determine if it is a match 

221 otherwise it will assume the VPC does not exist and thus return None. 

222 """ 

223 if multi: 

224 return None 

225 matching_vpcs = [] 

226 try: 

227 for v in vpc.describe_vpcs(): 

228 if cidr_block and v.cidr_block != cidr_block: 

229 continue 

230 if name and v.vpc_name != name: 

231 continue 

232 if vpc_id and v.vpc_id != vpc_id: 

233 continue 

234 matching_vpcs.append(v) 

235 

236 except Exception as e: 

237 module.fail_json(msg="Failed to describe VPCs: {0}".format(e)) 

238 

239 if len(matching_vpcs) == 1: 

240 return matching_vpcs[0] 

241 elif len(matching_vpcs) > 1: 

242 if recent: 

243 return matching_vpcs[-1] 

244 module.fail_json(msg='Currently there are {0} VPCs that have the same name and ' 

245 'CIDR block you specified. If you would like to create ' 

246 'the VPC anyway please pass True to the multi_ok param. ' 

247 'Or, please pass True to the recent param to choose the recent one.'.format(len(matching_vpcs))) 

248 return None 

249 

250 

251def main(): 

252 argument_spec = common_argument_spec() 

253 argument_spec.update(dict( 

254 state=dict(default='present', choices=['present', 'absent']), 

255 cidr_block=dict(type='str', required=True, aliases=['cidr']), 

256 user_cidrs=dict(type='list', elements='str'), 

257 name=dict(type='str', aliases=['vpc_name']), 

258 vpc_id=dict(type='str', aliases=['id']), 

259 multi_ok=dict(type='bool', default=False), 

260 description=dict(type='str'), 

261 recent=dict(type='bool', default=False), 

262 tags=dict(type='dict'), 

263 purge_tags=dict(type='bool', default=False) 

264 )) 

265 

266 module = AnsibleModule(argument_spec=argument_spec) 

267 

268 if HAS_FOOTMARK is False: 

269 module.fail_json(msg='footmark required for the module ali_vpc.') 

270 

271 vpc_conn = vpc_connect(module) 

272 

273 # Get values of variable 

274 state = module.params['state'] 

275 vpc_name = module.params['name'] 

276 description = module.params['description'] 

277 vpc_id = module.params['vpc_id'] 

278 

279 if str(description).startswith('http://') or str(description).startswith('https://'): 

280 module.fail_json(msg='description can not start with http:// or https://') 

281 if str(vpc_name).startswith('http://') or str(vpc_name).startswith('https://'): 

282 module.fail_json(msg='vpc_name can not start with http:// or https://') 

283 

284 changed = False 

285 

286 # Check if VPC exists 

287 vpc = vpc_exists(module, vpc_conn, vpc_id, vpc_name, module.params['cidr_block'], module.params['multi_ok'], module.params['recent']) 

288 

289 if state == 'absent': 

290 if not vpc: 

291 module.exit_json(changed=changed, vpc={}) 

292 

293 try: 

294 module.exit_json(changed=vpc.delete(), vpc={}) 

295 except VPCResponseError as ex: 

296 module.fail_json(msg='Unable to delete vpc {0}, error: {1}'.format(vpc.id, ex)) 

297 

298 if not vpc: 

299 params = module.params 

300 params['client_token'] = "Ansible-Apsarastack-%s-%s" % (hash(str(module.params)), str(time.time())) 

301 params['vpc_name'] = vpc_name 

302 try: 

303 vpc = vpc_conn.create_vpc(**params) 

304 module.exit_json(changed=True, vpc=vpc.get().read()) 

305 except VPCResponseError as e: 

306 module.fail_json(msg='Unable to create vpc, error: {0}'.format(e)) 

307 

308 if not description: 

309 description = vpc.description 

310 

311 try: 

312 if vpc.modify(vpc_name, description): 

313 changed = True 

314 except VPCResponseError as e: 

315 module.fail_json(msg='Unable to modify vpc {0}, error: {1}'.format(vpc.id, e)) 

316 

317 tags = module.params['tags'] 

318 if module.params['purge_tags']: 

319 if not tags: 

320 tags = vpc.tags 

321 try: 

322 if vpc.remove_tags(tags): 

323 changed = True 

324 module.exit_json(changed=changed, vpc=vpc.get().read()) 

325 except Exception as e: 

326 module.fail_json(msg="{0}".format(e)) 

327 

328 if tags: 

329 try: 

330 if vpc.add_tags(tags): 

331 changed = True 

332 except Exception as e: 

333 module.fail_json(msg="{0}".format(e)) 

334 module.exit_json(changed=changed, vpc=vpc.get().read()) 

335 

336 

337if __name__ == '__main__': 

338 main()