utils.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. import json
  2. import logging
  3. from aliyunsdkcore import client
  4. from aliyunsdkcore.acs_exception.exceptions import ClientException, ServerException
  5. from aliyunsdkecs.request.v20140526.AllocatePublicIpAddressRequest import (
  6. AllocatePublicIpAddressRequest,
  7. )
  8. from aliyunsdkecs.request.v20140526.AuthorizeSecurityGroupRequest import (
  9. AuthorizeSecurityGroupRequest,
  10. )
  11. from aliyunsdkecs.request.v20140526.CreateInstanceRequest import CreateInstanceRequest
  12. from aliyunsdkecs.request.v20140526.CreateKeyPairRequest import CreateKeyPairRequest
  13. from aliyunsdkecs.request.v20140526.CreateSecurityGroupRequest import (
  14. CreateSecurityGroupRequest,
  15. )
  16. from aliyunsdkecs.request.v20140526.CreateVpcRequest import CreateVpcRequest
  17. from aliyunsdkecs.request.v20140526.CreateVSwitchRequest import CreateVSwitchRequest
  18. from aliyunsdkecs.request.v20140526.DeleteInstanceRequest import DeleteInstanceRequest
  19. from aliyunsdkecs.request.v20140526.DeleteInstancesRequest import DeleteInstancesRequest
  20. from aliyunsdkecs.request.v20140526.DeleteKeyPairsRequest import DeleteKeyPairsRequest
  21. from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import (
  22. DescribeInstancesRequest,
  23. )
  24. from aliyunsdkecs.request.v20140526.DescribeKeyPairsRequest import (
  25. DescribeKeyPairsRequest,
  26. )
  27. from aliyunsdkecs.request.v20140526.DescribeSecurityGroupsRequest import (
  28. DescribeSecurityGroupsRequest,
  29. )
  30. from aliyunsdkecs.request.v20140526.DescribeVpcsRequest import DescribeVpcsRequest
  31. from aliyunsdkecs.request.v20140526.DescribeVSwitchesRequest import (
  32. DescribeVSwitchesRequest,
  33. )
  34. from aliyunsdkecs.request.v20140526.ImportKeyPairRequest import ImportKeyPairRequest
  35. from aliyunsdkecs.request.v20140526.RunInstancesRequest import RunInstancesRequest
  36. from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest
  37. from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest
  38. from aliyunsdkecs.request.v20140526.StopInstancesRequest import StopInstancesRequest
  39. from aliyunsdkecs.request.v20140526.TagResourcesRequest import TagResourcesRequest
  40. class AcsClient:
  41. """
  42. A wrapper around Aliyun SDK. We use this wrapper in aliyun node provider.
  43. Parameters:
  44. access_key: The AccessKey ID of your aliyun account.
  45. access_key_secret: The AccessKey secret of your aliyun account.
  46. region_id: A region is a geographic area where a data center resides.
  47. Region_id is the ID of region (e.g., cn-hangzhou,
  48. us-west-1, etc.)
  49. max_retries: The maximum number of retries each connection.
  50. """
  51. def __init__(self, access_key, access_key_secret, region_id, max_retries):
  52. self.cli = client.AcsClient(
  53. ak=access_key,
  54. secret=access_key_secret,
  55. max_retry_time=max_retries,
  56. region_id=region_id,
  57. )
  58. def describe_instances(self, tags=None, instance_ids=None):
  59. """Query the details of one or more Elastic Compute Service (ECS) instances.
  60. :param tags: The tags of the instance.
  61. :param instance_ids: The IDs of ECS instances
  62. :return: ECS instance list
  63. """
  64. request = DescribeInstancesRequest()
  65. if tags is not None:
  66. request.set_Tags(tags)
  67. if instance_ids is not None:
  68. request.set_InstanceIds(instance_ids)
  69. response = self._send_request(request)
  70. if response is not None:
  71. instance_list = response.get("Instances").get("Instance")
  72. return instance_list
  73. return None
  74. def create_instance(
  75. self,
  76. instance_type,
  77. image_id,
  78. tags,
  79. key_pair_name,
  80. optimized="optimized",
  81. instance_charge_type="PostPaid",
  82. spot_strategy="SpotWithPriceLimit",
  83. internet_charge_type="PayByTraffic",
  84. internet_max_bandwidth_out=5,
  85. ):
  86. """Create a subscription or pay-as-you-go ECS instance.
  87. :param instance_type: The instance type of the ECS.
  88. :param image_id: The ID of the image used to create the instance.
  89. :param tags: The tags of the instance.
  90. :param key_pair_name: The name of the key pair to be bound to
  91. the instance.
  92. :param optimized: Specifies whether the instance is I/O optimized
  93. :param instance_charge_type: The billing method of the instance.
  94. Default value: PostPaid.
  95. :param spot_strategy: The preemption policy for the pay-as-you-go
  96. instance.
  97. :param internet_charge_type: The billing method for network usage.
  98. Default value: PayByTraffic.
  99. :param internet_max_bandwidth_out: The maximum inbound public
  100. bandwidth. Unit: Mbit/s.
  101. :return: The created instance ID.
  102. """
  103. request = CreateInstanceRequest()
  104. request.set_InstanceType(instance_type)
  105. request.set_ImageId(image_id)
  106. request.set_IoOptimized(optimized)
  107. request.set_InstanceChargeType(instance_charge_type)
  108. request.set_SpotStrategy(spot_strategy)
  109. request.set_InternetChargeType(internet_charge_type)
  110. request.set_InternetMaxBandwidthOut(internet_max_bandwidth_out)
  111. request.set_KeyPairName(key_pair_name)
  112. request.set_Tags(tags)
  113. response = self._send_request(request)
  114. if response is not None:
  115. instance_id = response.get("InstanceId")
  116. logging.info("instance %s created task submit successfully.", instance_id)
  117. return instance_id
  118. logging.error("instance created failed.")
  119. return None
  120. def run_instances(
  121. self,
  122. instance_type,
  123. image_id,
  124. tags,
  125. security_group_id,
  126. vswitch_id,
  127. key_pair_name,
  128. amount=1,
  129. optimized="optimized",
  130. instance_charge_type="PostPaid",
  131. spot_strategy="SpotWithPriceLimit",
  132. internet_charge_type="PayByTraffic",
  133. internet_max_bandwidth_out=1,
  134. ):
  135. """Create one or more pay-as-you-go or subscription
  136. Elastic Compute Service (ECS) instances
  137. :param instance_type: The instance type of the ECS.
  138. :param image_id: The ID of the image used to create the instance.
  139. :param tags: The tags of the instance.
  140. :param security_group_id: The ID of the security group to which to
  141. assign the instance. Instances in the same
  142. security group can communicate with
  143. each other.
  144. :param vswitch_id: The ID of the vSwitch to which to connect
  145. the instance.
  146. :param key_pair_name: The name of the key pair to be bound to
  147. the instance.
  148. :param amount: The number of instances that you want to create.
  149. :param optimized: Specifies whether the instance is I/O optimized
  150. :param instance_charge_type: The billing method of the instance.
  151. Default value: PostPaid.
  152. :param spot_strategy: The preemption policy for the pay-as-you-go
  153. instance.
  154. :param internet_charge_type: The billing method for network usage.
  155. Default value: PayByTraffic.
  156. :param internet_max_bandwidth_out: The maximum inbound public
  157. bandwidth. Unit: Mbit/s.
  158. :return: The created instance IDs.
  159. """
  160. request = RunInstancesRequest()
  161. request.set_InstanceType(instance_type)
  162. request.set_ImageId(image_id)
  163. request.set_IoOptimized(optimized)
  164. request.set_InstanceChargeType(instance_charge_type)
  165. request.set_SpotStrategy(spot_strategy)
  166. request.set_InternetChargeType(internet_charge_type)
  167. request.set_InternetMaxBandwidthOut(internet_max_bandwidth_out)
  168. request.set_Tags(tags)
  169. request.set_Amount(amount)
  170. request.set_SecurityGroupId(security_group_id)
  171. request.set_VSwitchId(vswitch_id)
  172. request.set_KeyPairName(key_pair_name)
  173. response = self._send_request(request)
  174. if response is not None:
  175. instance_ids = response.get("InstanceIdSets").get("InstanceIdSet")
  176. return instance_ids
  177. logging.error("instance created failed.")
  178. return None
  179. def create_security_group(self, vpc_id):
  180. """Create a security group
  181. :param vpc_id: The ID of the VPC in which to create
  182. the security group.
  183. :return: The created security group ID.
  184. """
  185. request = CreateSecurityGroupRequest()
  186. request.set_VpcId(vpc_id)
  187. response = self._send_request(request)
  188. if response is not None:
  189. security_group_id = response.get("SecurityGroupId")
  190. return security_group_id
  191. return None
  192. def describe_security_groups(self, vpc_id=None, tags=None):
  193. """Query basic information of security groups.
  194. :param vpc_id: The ID of the VPC to which the security group belongs.
  195. :param tags: The tags of the security group.
  196. :return: Security group list.
  197. """
  198. request = DescribeSecurityGroupsRequest()
  199. if vpc_id is not None:
  200. request.set_VpcId(vpc_id)
  201. if tags is not None:
  202. request.set_Tags(tags)
  203. response = self._send_request(request)
  204. if response is not None:
  205. security_groups = response.get("SecurityGroups").get("SecurityGroup")
  206. return security_groups
  207. logging.error("describe security group failed.")
  208. return None
  209. def authorize_security_group(
  210. self, ip_protocol, port_range, security_group_id, source_cidr_ip
  211. ):
  212. """Create an inbound security group rule.
  213. :param ip_protocol: The transport layer protocol.
  214. :param port_range: The range of destination ports relevant to
  215. the transport layer protocol.
  216. :param security_group_id: The ID of the destination security group.
  217. :param source_cidr_ip: The range of source IPv4 addresses.
  218. CIDR blocks and IPv4 addresses are supported.
  219. """
  220. request = AuthorizeSecurityGroupRequest()
  221. request.set_IpProtocol(ip_protocol)
  222. request.set_PortRange(port_range)
  223. request.set_SecurityGroupId(security_group_id)
  224. request.set_SourceCidrIp(source_cidr_ip)
  225. self._send_request(request)
  226. def create_v_switch(self, vpc_id, zone_id, cidr_block):
  227. """Create vSwitches to divide the VPC into one or more subnets
  228. :param vpc_id: The ID of the VPC to which the VSwitch belongs.
  229. :param zone_id: The ID of the zone to which
  230. the target VSwitch belongs.
  231. :param cidr_block: The CIDR block of the VSwitch.
  232. :return:
  233. """
  234. request = CreateVSwitchRequest()
  235. request.set_ZoneId(zone_id)
  236. request.set_VpcId(vpc_id)
  237. request.set_CidrBlock(cidr_block)
  238. response = self._send_request(request)
  239. if response is not None:
  240. return response.get("VSwitchId")
  241. else:
  242. logging.error("create_v_switch vpc_id %s failed.", vpc_id)
  243. return None
  244. def create_vpc(self):
  245. """Creates a virtual private cloud (VPC).
  246. :return: The created VPC ID.
  247. """
  248. request = CreateVpcRequest()
  249. response = self._send_request(request)
  250. if response is not None:
  251. return response.get("VpcId")
  252. return None
  253. def describe_vpcs(self):
  254. """Queries one or more VPCs in a region.
  255. :return: VPC list.
  256. """
  257. request = DescribeVpcsRequest()
  258. response = self._send_request(request)
  259. if response is not None:
  260. return response.get("Vpcs").get("Vpc")
  261. return None
  262. def tag_resource(self, resource_ids, tags, resource_type="instance"):
  263. """Create and bind tags to specified ECS resources.
  264. :param resource_ids: The IDs of N resources.
  265. :param tags: The tags of the resource.
  266. :param resource_type: The type of the resource.
  267. """
  268. request = TagResourcesRequest()
  269. request.set_Tags(tags)
  270. request.set_ResourceType(resource_type)
  271. request.set_ResourceIds(resource_ids)
  272. response = self._send_request(request)
  273. if response is not None:
  274. logging.info("instance %s create tag successfully.", resource_ids)
  275. else:
  276. logging.error("instance %s create tag failed.", resource_ids)
  277. def start_instance(self, instance_id):
  278. """Start an ECS instance.
  279. :param instance_id: The Ecs instance ID.
  280. """
  281. request = StartInstanceRequest()
  282. request.set_InstanceId(instance_id)
  283. response = self._send_request(request)
  284. if response is not None:
  285. logging.info("instance %s start successfully.", instance_id)
  286. else:
  287. logging.error("instance %s start failed.", instance_id)
  288. def stop_instance(self, instance_id, force_stop=False):
  289. """Stop an ECS instance that is in the Running state.
  290. :param instance_id: The Ecs instance ID.
  291. :param force_stop: Specifies whether to forcibly stop the instance.
  292. :return:
  293. """
  294. request = StopInstanceRequest()
  295. request.set_InstanceId(instance_id)
  296. request.set_ForceStop(force_stop)
  297. logging.info("Stop %s command submit successfully.", instance_id)
  298. self._send_request(request)
  299. def stop_instances(self, instance_ids, stopped_mode="StopCharging"):
  300. """Stop one or more ECS instances that are in the Running state.
  301. :param instance_ids: The IDs of instances.
  302. :param stopped_mode: Specifies whether billing for the instance
  303. continues after the instance is stopped.
  304. """
  305. request = StopInstancesRequest()
  306. request.set_InstanceIds(instance_ids)
  307. request.set_StoppedMode(stopped_mode)
  308. response = self._send_request(request)
  309. if response is None:
  310. logging.error("stop_instances failed")
  311. def delete_instance(self, instance_id):
  312. """Release a pay-as-you-go instance or
  313. an expired subscription instance.
  314. :param instance_id: The ID of the instance that you want to release.
  315. """
  316. request = DeleteInstanceRequest()
  317. request.set_InstanceId(instance_id)
  318. request.set_Force(True)
  319. logging.info("Delete %s command submit successfully", instance_id)
  320. self._send_request(request)
  321. def delete_instances(self, instance_ids):
  322. """Release one or more pay-as-you-go instances or
  323. expired subscription instances.
  324. :param instance_ids: The IDs of instances that you want to release.
  325. """
  326. request = DeleteInstancesRequest()
  327. request.set_Force(True)
  328. request.set_InstanceIds(instance_ids)
  329. self._send_request(request)
  330. def allocate_public_address(self, instance_id):
  331. """Assign a public IP address to an ECS instance.
  332. :param instance_id: The ID of the instance to which you want to
  333. assign a public IP address.
  334. :return: The assigned ip.
  335. """
  336. request = AllocatePublicIpAddressRequest()
  337. request.set_InstanceId(instance_id)
  338. response = self._send_request(request)
  339. if response is not None:
  340. return response.get("IpAddress")
  341. def create_key_pair(self, key_pair_name):
  342. """Create an SSH key pair.
  343. :param key_pair_name: The name of the key pair.
  344. :return: The created keypair data.
  345. """
  346. request = CreateKeyPairRequest()
  347. request.set_KeyPairName(key_pair_name)
  348. response = self._send_request(request)
  349. if response is not None:
  350. logging.info("Create Key Pair %s Successfully", response.get("KeyPairId"))
  351. return response
  352. else:
  353. logging.error("Create Key Pair Failed")
  354. return None
  355. def import_key_pair(self, key_pair_name, public_key_body):
  356. """Import the public key of an RSA-encrypted key pair
  357. that is generated by a third-party tool.
  358. :param key_pair_name: The name of the key pair.
  359. :param public_key_body: The public key of the key pair.
  360. """
  361. request = ImportKeyPairRequest()
  362. request.set_KeyPairName(key_pair_name)
  363. request.set_PublicKeyBody(public_key_body)
  364. self._send_request(request)
  365. def delete_key_pairs(self, key_pair_names):
  366. """Delete one or more SSH key pairs.
  367. :param key_pair_names: The name of the key pair.
  368. :return:
  369. """
  370. request = DeleteKeyPairsRequest()
  371. request.set_KeyPairNames(key_pair_names)
  372. self._send_request(request)
  373. def describe_key_pairs(self, key_pair_name=None):
  374. """Query one or more key pairs.
  375. :param key_pair_name: The name of the key pair.
  376. :return:
  377. """
  378. request = DescribeKeyPairsRequest()
  379. if key_pair_name is not None:
  380. request.set_KeyPairName(key_pair_name)
  381. response = self._send_request(request)
  382. if response is not None:
  383. return response.get("KeyPairs").get("KeyPair")
  384. else:
  385. return None
  386. def describe_v_switches(self, vpc_id=None):
  387. """Queries one or more VSwitches.
  388. :param vpc_id: The ID of the VPC to which the VSwitch belongs.
  389. :return: VSwitch list.
  390. """
  391. request = DescribeVSwitchesRequest()
  392. if vpc_id is not None:
  393. request.set_VpcId(vpc_id)
  394. response = self._send_request(request)
  395. if response is not None:
  396. return response.get("VSwitches").get("VSwitch")
  397. else:
  398. logging.error("Describe VSwitches Failed.")
  399. return None
  400. def _send_request(self, request):
  401. """send open api request"""
  402. request.set_accept_format("json")
  403. try:
  404. response_str = self.cli.do_action_with_exception(request)
  405. response_detail = json.loads(response_str)
  406. return response_detail
  407. except (ClientException, ServerException) as e:
  408. logging.error(request.get_action_name())
  409. logging.error(e)
  410. return None