-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcpx_server.py
172 lines (141 loc) · 5.35 KB
/
cpx_server.py
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env python3
import argparse
import hashlib
import json
import random
import re
import socket
from typing import Dict
from http.server import HTTPServer, SimpleHTTPRequestHandler
from tabulate import tabulate
import pandas as pd
from collections import defaultdict
NUM_SERVERS = 150
SERVER_SET = ['10.58.1.%d' % i for i in range(1, NUM_SERVERS + 1)]
IP_REGEX = r'/10\.58\.1\.[0-9]{1,3}$'
SERVICES = [
'PermissionsService',
'AuthService',
'MLService',
'StorageService',
'TimeService',
'GeoService',
'TicketService',
'RoleService',
'IdService',
'UserService',
'RoleService',
]
def _server_stats(ip: str) -> Dict[str, str]:
ip_u = ip.encode('utf-8')
service_idx = int(hashlib.md5(ip_u).hexdigest(), 16) % len(SERVICES)
service_name = SERVICES[service_idx]
stats= {
'ip': ip,
'service': service_name,
#'cpu': f'{random.randint(0, 100)}%',
#'memory': f'{random.randint(0, 100)}%',
}
"""if stats['cpu'] > '75%' or stats['memory'] > '75%':
stats['status'] = 'Unhealthy'
return stats
stats['status'] = 'Healthy'
"""
return stats
def _all_server_stats():
all_stats = [_server_stats(server) for server in SERVER_SET]
df = pd.DataFrame(all_stats)
table = tabulate(df, headers='keys', tablefmt='psql')
return table
def calculate_average_server_stats():
all_stats = [_server_stats(server) for server in SERVER_SET]
service_stats = defaultdict(list)
# collect cpu and memory usage for each service
for server in all_stats:
service_name = server['service']
cpu_usage = int(server['cpu'].rstrip('%'))
memory_usage = int(server['memory'].rstrip('%'))
service_stats[service_name].append((cpu_usage, memory_usage))
# calculate the average for each service
averages = []
for service_name, stats in service_stats.items():
cpu_average = sum([s[0] for s in stats]) / len(stats)
memory_average = sum([s[1] for s in stats]) / len(stats)
averages.append({'service': service_name, 'cpu_average': f'{cpu_average:.2f}%', 'memory_average': f'{memory_average:.2f}%' })
df = pd.DataFrame(averages)
table = tabulate(df, headers='keys', tablefmt='psql')
return table
def services_with_few_health_instances():
status_data = [_server_stats(server) for server in SERVER_SET]
service_stats = {}
for stat in status_data:
if stat['status'] == 'Unhealthy':
continue
service_name = stat['service']
if service_name not in service_stats:
service_stats[service_name] = []
service_stats[service_name].append(stat['ip'])
services_with_few_health = {}
for service_name, ips in service_stats.items():
healthy_instances = len(ips)
if healthy_instances <= 2:
services_with_few_health[service_name] = ips
df = pd.DataFrame(services_with_few_health)
table = tabulate(df, headers='keys', tablefmt='psql')
return table
class HTTPServerV6(HTTPServer):
address_family = socket.AF_INET6
class CPXHandler(SimpleHTTPRequestHandler):
def _invalid_endpoint(self):
self.send_response(400)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(json.dumps({'error': 'Invalid IP'}), 'utf-8'))
def _json(self, data: str):
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(json.dumps(data), 'utf-8'))
def do_GET(self):
ip_match = re.match(IP_REGEX, self.path)
if self.path == '/servers':
self._json(SERVER_SET)
elif self.path == '/status':
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(_all_server_stats(), 'utf-8'))
elif self.path == '/services':
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(calculate_average_server_stats(), 'utf-8'))
elif self.path == '/service-health':
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(services_with_few_health_instances(), 'utf-8'))
elif ip_match:
ip = ip_match.group().replace('/', '')
if ip not in SERVER_SET:
self._invalid_endpoint()
else:
self._json(_server_stats(ip))
else:
self._invalid_endpoint()
def main(port: int, protocol: int):
if protocol == 6 and not socket.has_ipv6:
print("Falling back to IPv4")
if protocol == 6 and socket.has_ipv6:
httpd = HTTPServerV6(('::', port), CPXHandler)
httpd.serve_forever()
else:
httpd = HTTPServer(('0.0.0.0', port), CPXHandler)
httpd.serve_forever()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("port", help="the port on which to run", type=int)
parser.add_argument("--protocol", help="which IP version to use, 4 for IPv4, 6 for IPv6",
type=int, choices=[4, 6], default=6)
args = parser.parse_args()
main(args.port, args.protocol)