/
c3mc-bpm-action-aws-ec2-operation
executable file
·115 lines (89 loc) · 4.1 KB
/
c3mc-bpm-action-aws-ec2-operation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env /data/Software/mydan/python3/bin/python3
# -*- coding: utf-8 -*-
import sys
import json
import random
import subprocess
import time
sys.path.append("/data/Software/mydan/Connector/lib/pp")
from c3mc_cloud_aws_ec2 import LIB_EC2
from c3mc_utils import retry_network_request
def exponential_backoff(attempt, max_delay):
delay = min(max_delay, (2**attempt) + random.uniform(0, 1))
time.sleep(delay)
class OperateEc2:
def __init__(self, access_id, access_key, region):
self.lib_client = LIB_EC2(access_id, access_key, region)
def run(self, operation_type, instance_id):
instance_info = self.lib_client.describe_instances([instance_id])["Reservations"][0]["Instances"][0]
timeout = 900
if operation_type == "start":
if instance_info["State"]["Name"] == "running":
print(f"LOG. ec2实例: {instance_id} 已经处于 running 状态, 跳过操作")
return
resp = retry_network_request(self.lib_client.start_instances, ([instance_id],))
print(f"调用完启动接口, 等待实例启动。接口响应: {json.dumps(resp)}")
self.lib_client.wait_ec2_until_status(instance_id, "running", timeout)
print(f"LOG. 成功启动ec2实例: {instance_id}")
# C3TODO 230814 启动完一个实例后休眠一段时间,尝试避免aws接口出现资源容量不足的错误
time.sleep(20)
elif operation_type == "stop":
if instance_info["State"]["Name"] == "stopped":
print(f"LOG. ec2实例: {instance_id} 已经处于 stopped 状态, 跳过操作")
return
resp = retry_network_request(self.lib_client.stop_instances, ([instance_id],))
print(f"调用完停止接口, 等待实例停止。接口响应: {json.dumps(resp)}")
self.lib_client.wait_ec2_until_status(instance_id, "stopped", timeout)
print(f"LOG. 成功停止ec2实例: {instance_id}")
else:
raise RuntimeError(f"LOG. 不支持的操作类型: {operation_type}")
def get_instance_uuid(instance_maybe_identifier):
command = f"c3mc-device-find-uuid {instance_maybe_identifier}"
result = subprocess.check_output(command, shell=True)
parts = result.decode("utf-8").strip().split()
if len(parts) > 1:
print(f"通过命令 {command} 查询到了多个uuid {parts}", file=sys.stderr)
exit(1)
return parts[0]
def main(params):
print("params = ", json.dumps(params))
field_name_list = subprocess.getoutput(
"c3mc-cloud-get-real-field compute aws-ec2 InstanceId account RegionId"
).split()
operation_type = params["operation_type"]
instance_identifier_list = [
item.strip()
for item in params["instance_ids"].split(",") if item.strip() != ""
]
record_err = {}
for instance_identifier in instance_identifier_list:
try:
instance_uuid = get_instance_uuid(instance_identifier)
data = json.loads(
subprocess.getoutput(
f"c3mc-device-cat curr compute aws-ec2 {instance_uuid} | c3mc-base-tab2json"
)
)
key_info = json.loads(
subprocess.getoutput(
f"c3mc-get-account-info aws {data[field_name_list[1]]}"
)
)
OperateEc2(
key_info["access_id"],
key_info["access_key"],
data[field_name_list[2]],
).run(operation_type, instance_uuid)
except Exception as e:
record_err = {
"instance_identifier": instance_identifier,
"error": str(e)
}
if len(record_err):
print(f"操作过程出现错误, 实例标识: {record_err['instance_identifier']}, 错误信息: {record_err['error']}")
exit(1)
if __name__ == "__main__":
input_list = list(sys.stdin)
if not input_list or len(input_list) > 1:
raise type("WrongInputData", (Exception,), {})('数据格式不对, 需要一行json字符串"')
main(json.loads(input_list[0]))