adapto 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- adapto/predictor.py +24 -24
- adapto/scaler.py +128 -112
- adapto/utils.py +4 -4
- {adapto-0.1.0.dist-info → adapto-0.1.2.dist-info}/LICENSE +21 -21
- {adapto-0.1.0.dist-info → adapto-0.1.2.dist-info}/METADATA +21 -19
- adapto-0.1.2.dist-info/RECORD +9 -0
- {adapto-0.1.0.dist-info → adapto-0.1.2.dist-info}/WHEEL +1 -1
- adapto-0.1.0.dist-info/RECORD +0 -9
- {adapto-0.1.0.dist-info → adapto-0.1.2.dist-info}/top_level.txt +0 -0
adapto/predictor.py
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
import numpy as np
|
2
|
-
from sklearn.linear_model import LinearRegression
|
3
|
-
|
4
|
-
|
5
|
-
class Predictor:
|
6
|
-
def __init__(self):
|
7
|
-
pass
|
8
|
-
|
9
|
-
def train_predictor(self, history):
|
10
|
-
if len(history) < 2:
|
11
|
-
return history[-1] if history else 0
|
12
|
-
|
13
|
-
X = np.arange(len(history)).reshape(-1, 1)
|
14
|
-
y = np.array(history)
|
15
|
-
model = LinearRegression().fit(X, y)
|
16
|
-
return model.predict([[len(history)]])[0]
|
17
|
-
|
18
|
-
def predict(self, cpu_history, memory_history, network_sent_history, network_recv_history):
|
19
|
-
return {
|
20
|
-
"predicted_cpu": self.train_predictor(cpu_history),
|
21
|
-
"predicted_memory": self.train_predictor(memory_history),
|
22
|
-
"predicted_network_sent": self.train_predictor(network_sent_history),
|
23
|
-
"predicted_network_recv": self.train_predictor(network_recv_history)
|
24
|
-
}
|
1
|
+
import numpy as np
|
2
|
+
from sklearn.linear_model import LinearRegression
|
3
|
+
|
4
|
+
|
5
|
+
class Predictor:
|
6
|
+
def __init__(self):
|
7
|
+
pass
|
8
|
+
|
9
|
+
def train_predictor(self, history):
|
10
|
+
if len(history) < 2:
|
11
|
+
return history[-1] if history else 0
|
12
|
+
|
13
|
+
X = np.arange(len(history)).reshape(-1, 1)
|
14
|
+
y = np.array(history)
|
15
|
+
model = LinearRegression().fit(X, y)
|
16
|
+
return model.predict([[len(history)]])[0]
|
17
|
+
|
18
|
+
def predict(self, cpu_history, memory_history, network_sent_history, network_recv_history):
|
19
|
+
return {
|
20
|
+
"predicted_cpu": self.train_predictor(cpu_history),
|
21
|
+
"predicted_memory": self.train_predictor(memory_history),
|
22
|
+
"predicted_network_sent": self.train_predictor(network_sent_history),
|
23
|
+
"predicted_network_recv": self.train_predictor(network_recv_history)
|
24
|
+
}
|
adapto/scaler.py
CHANGED
@@ -1,112 +1,128 @@
|
|
1
|
-
import psutil
|
2
|
-
import time
|
3
|
-
import logging
|
4
|
-
from collections import deque
|
5
|
-
from adapto.predictor import Predictor
|
6
|
-
|
7
|
-
# Set up logging
|
8
|
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
9
|
-
|
10
|
-
|
11
|
-
class AutoScaler:
|
12
|
-
def __init__(self, scale_up_threshold=80, scale_down_threshold=30, memory_threshold=75,
|
13
|
-
bandwidth_threshold=100000000, min_instances=1, max_instances=10, history_size=10):
|
14
|
-
self.scale_up_threshold = scale_up_threshold
|
15
|
-
self.scale_down_threshold = scale_down_threshold
|
16
|
-
self.memory_threshold = memory_threshold
|
17
|
-
self.bandwidth_threshold = bandwidth_threshold # in bytes per second
|
18
|
-
self.current_instances = min_instances
|
19
|
-
self.min_instances = min_instances
|
20
|
-
self.max_instances = max_instances
|
21
|
-
self.previous_network = psutil.net_io_counters()
|
22
|
-
|
23
|
-
#
|
24
|
-
self.
|
25
|
-
|
26
|
-
|
27
|
-
self.
|
28
|
-
|
29
|
-
self.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
self.
|
40
|
-
|
41
|
-
|
42
|
-
self.
|
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
|
-
list(self.
|
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
|
-
self.
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
1
|
+
import psutil
|
2
|
+
import time
|
3
|
+
import logging
|
4
|
+
from collections import deque
|
5
|
+
from adapto.predictor import Predictor
|
6
|
+
|
7
|
+
# Set up logging
|
8
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
9
|
+
|
10
|
+
|
11
|
+
class AutoScaler:
|
12
|
+
def __init__(self, scale_up_threshold=80, scale_down_threshold=30, memory_threshold=75,
|
13
|
+
bandwidth_threshold=100000000, min_instances=1, max_instances=10, history_size=10, custom_scaling=None):
|
14
|
+
self.scale_up_threshold = scale_up_threshold
|
15
|
+
self.scale_down_threshold = scale_down_threshold
|
16
|
+
self.memory_threshold = memory_threshold
|
17
|
+
self.bandwidth_threshold = bandwidth_threshold # in bytes per second
|
18
|
+
self.current_instances = min_instances
|
19
|
+
self.min_instances = min_instances
|
20
|
+
self.max_instances = max_instances
|
21
|
+
self.previous_network = psutil.net_io_counters()
|
22
|
+
|
23
|
+
# Optional custom scaling function; should accept (metrics, predictions) and return 'scale_up', 'scale_down', or 'no_change'
|
24
|
+
self.custom_scaling = custom_scaling
|
25
|
+
|
26
|
+
# Data history for prediction
|
27
|
+
self.cpu_history = deque(maxlen=history_size)
|
28
|
+
self.memory_history = deque(maxlen=history_size)
|
29
|
+
self.network_sent_history = deque(maxlen=history_size)
|
30
|
+
self.network_recv_history = deque(maxlen=history_size)
|
31
|
+
|
32
|
+
self.predictor = Predictor()
|
33
|
+
|
34
|
+
def get_system_metrics(self):
|
35
|
+
cpu_usage = psutil.cpu_percent(interval=1)
|
36
|
+
memory_usage = psutil.virtual_memory().percent
|
37
|
+
load_avg = psutil.getloadavg()[0] if hasattr(psutil, "getloadavg") else 0 # Unix-only
|
38
|
+
disk_usage = psutil.disk_usage('/').percent
|
39
|
+
network_metrics = self.get_network_metrics()
|
40
|
+
|
41
|
+
# Store metrics in history
|
42
|
+
self.cpu_history.append(cpu_usage)
|
43
|
+
self.memory_history.append(memory_usage)
|
44
|
+
self.network_sent_history.append(network_metrics['network_sent'])
|
45
|
+
self.network_recv_history.append(network_metrics['network_recv'])
|
46
|
+
|
47
|
+
return {
|
48
|
+
"cpu_usage": cpu_usage,
|
49
|
+
"memory_usage": memory_usage,
|
50
|
+
"load_avg": load_avg,
|
51
|
+
"disk_usage": disk_usage,
|
52
|
+
**network_metrics
|
53
|
+
}
|
54
|
+
|
55
|
+
def get_network_metrics(self):
|
56
|
+
network_io = psutil.net_io_counters()
|
57
|
+
network_sent = network_io.bytes_sent - self.previous_network.bytes_sent
|
58
|
+
network_recv = network_io.bytes_recv - self.previous_network.bytes_recv
|
59
|
+
self.previous_network = network_io
|
60
|
+
|
61
|
+
return {
|
62
|
+
"network_sent": network_sent,
|
63
|
+
"network_recv": network_recv
|
64
|
+
}
|
65
|
+
|
66
|
+
def predict_future_usage(self):
|
67
|
+
return self.predictor.predict(
|
68
|
+
list(self.cpu_history),
|
69
|
+
list(self.memory_history),
|
70
|
+
list(self.network_sent_history),
|
71
|
+
list(self.network_recv_history)
|
72
|
+
)
|
73
|
+
|
74
|
+
def scale_up(self):
|
75
|
+
if self.current_instances < self.max_instances:
|
76
|
+
self.current_instances += 1
|
77
|
+
logging.info(f"Scaling up: New instance count = {self.current_instances}")
|
78
|
+
else:
|
79
|
+
logging.info("Max instances reached. Cannot scale up further.")
|
80
|
+
|
81
|
+
def scale_down(self):
|
82
|
+
if self.current_instances > self.min_instances:
|
83
|
+
self.current_instances -= 1
|
84
|
+
logging.info(f"Scaling down: New instance count = {self.current_instances}")
|
85
|
+
else:
|
86
|
+
logging.info("Min instances reached. Cannot scale down further.")
|
87
|
+
|
88
|
+
def monitor(self, interval=5):
|
89
|
+
while True:
|
90
|
+
metrics = self.get_system_metrics()
|
91
|
+
predictions = self.predict_future_usage()
|
92
|
+
|
93
|
+
logging.info(
|
94
|
+
f"CPU: {metrics['cpu_usage']}% | Memory: {metrics['memory_usage']}% | Load Avg: {metrics['load_avg']} | Disk: {metrics['disk_usage']}% | "
|
95
|
+
f"Network Sent: {metrics['network_sent']} bytes/s | Network Recv: {metrics['network_recv']} bytes/s"
|
96
|
+
)
|
97
|
+
logging.info(
|
98
|
+
f"Predicted CPU: {predictions['predicted_cpu']}% | Predicted Memory: {predictions['predicted_memory']}% | "
|
99
|
+
f"Predicted Network Sent: {predictions['predicted_network_sent']} bytes/s | Predicted Network Recv: {predictions['predicted_network_recv']} bytes/s"
|
100
|
+
)
|
101
|
+
|
102
|
+
# If a custom scaling strategy is provided, use it to decide the action
|
103
|
+
if self.custom_scaling:
|
104
|
+
action = self.custom_scaling(metrics, predictions)
|
105
|
+
if action == 'scale_up':
|
106
|
+
self.scale_up()
|
107
|
+
elif action == 'scale_down':
|
108
|
+
self.scale_down()
|
109
|
+
else:
|
110
|
+
# Default scaling strategy
|
111
|
+
if (predictions['predicted_cpu'] > self.scale_up_threshold or
|
112
|
+
predictions['predicted_memory'] > self.memory_threshold or
|
113
|
+
predictions['predicted_network_sent'] > self.bandwidth_threshold or
|
114
|
+
predictions['predicted_network_recv'] > self.bandwidth_threshold):
|
115
|
+
self.scale_up()
|
116
|
+
elif (predictions['predicted_cpu'] < self.scale_down_threshold and
|
117
|
+
predictions['predicted_memory'] < self.memory_threshold / 2 and
|
118
|
+
predictions['predicted_network_sent'] < self.bandwidth_threshold / 2 and
|
119
|
+
predictions['predicted_network_recv'] < self.bandwidth_threshold / 2):
|
120
|
+
self.scale_down()
|
121
|
+
|
122
|
+
time.sleep(interval)
|
123
|
+
|
124
|
+
|
125
|
+
# Example usage
|
126
|
+
if __name__ == "__main__":
|
127
|
+
scaler = AutoScaler()
|
128
|
+
scaler.monitor()
|
adapto/utils.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import time
|
2
|
-
|
3
|
-
def log_event(message):
|
4
|
-
"""Log an event with a timestamp."""
|
1
|
+
import time
|
2
|
+
|
3
|
+
def log_event(message):
|
4
|
+
"""Log an event with a timestamp."""
|
5
5
|
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {message}")
|
@@ -1,21 +1,21 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2025 Harshal Mehta
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
7
|
-
in the Software without restriction, including without limitation the rights
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
10
|
-
furnished to do so, subject to the following conditions:
|
11
|
-
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
13
|
-
copies or substantial portions of the Software.
|
14
|
-
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Harshal Mehta
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,19 +1,21 @@
|
|
1
|
-
Metadata-Version: 2.
|
2
|
-
Name: adapto
|
3
|
-
Version: 0.1.
|
4
|
-
Summary: AI-driven auto-scaling library for dynamic resource allocation.
|
5
|
-
Home-page: https://github.com/hrshlmeht/adapto
|
6
|
-
Author: Harshal Mehta
|
7
|
-
Author-email: harshalmehta1998@gmail.com
|
8
|
-
|
9
|
-
|
10
|
-
Classifier:
|
11
|
-
|
12
|
-
|
13
|
-
Requires-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: adapto
|
3
|
+
Version: 0.1.2
|
4
|
+
Summary: AI-driven auto-scaling library for dynamic resource allocation.
|
5
|
+
Home-page: https://github.com/hrshlmeht/adapto
|
6
|
+
Author: Harshal Mehta
|
7
|
+
Author-email: harshalmehta1998@gmail.com
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.7
|
12
|
+
License-File: LICENSE
|
13
|
+
Requires-Dist: psutil
|
14
|
+
Requires-Dist: numpy
|
15
|
+
Dynamic: author
|
16
|
+
Dynamic: author-email
|
17
|
+
Dynamic: classifier
|
18
|
+
Dynamic: home-page
|
19
|
+
Dynamic: requires-dist
|
20
|
+
Dynamic: requires-python
|
21
|
+
Dynamic: summary
|
@@ -0,0 +1,9 @@
|
|
1
|
+
adapto/__init__.py,sha256=8SWysOKRVNsD3cOXLOfIdVZx6MxzIqGKEh9Z26QuCyM,30
|
2
|
+
adapto/predictor.py,sha256=ze-cMHdf290o3_9D-PQ7yQ8eMz1Utv3E3qTHRUFQiAI,842
|
3
|
+
adapto/scaler.py,sha256=qVwnjd6YondkJ_vorinmReXoO0TNf0-CiKUMvDgHYrw,5544
|
4
|
+
adapto/utils.py,sha256=6TgDvowlXL__v-OkLSTZF12ZOEqEKCLuNv1LmL70eAY,140
|
5
|
+
adapto-0.1.2.dist-info/LICENSE,sha256=B73NNEiUy-CCs4zrOPlOWR39PfoG4zKtK97OnNctjvg,1070
|
6
|
+
adapto-0.1.2.dist-info/METADATA,sha256=c42fZm-Mw_GOCTHNpZLqQpT6jv8DaNaIxSwrvqWnUV8,609
|
7
|
+
adapto-0.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
8
|
+
adapto-0.1.2.dist-info/top_level.txt,sha256=IYsgAr6fnEC1R1ztYmK2ZpFNNGV0qRaf3Tvf-R8j0cM,7
|
9
|
+
adapto-0.1.2.dist-info/RECORD,,
|
adapto-0.1.0.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
adapto/__init__.py,sha256=8SWysOKRVNsD3cOXLOfIdVZx6MxzIqGKEh9Z26QuCyM,30
|
2
|
-
adapto/predictor.py,sha256=RqPbSWwppyI1PQGzGZMihpX5YQoyWvN_G-ocHOa2H0g,866
|
3
|
-
adapto/scaler.py,sha256=P1f8TDc4mrFpqXffs2FImg9mRRpP0GoYks_3JNyz4O4,4955
|
4
|
-
adapto/utils.py,sha256=8elBvOHytKcqT9TnVYcDU8yN1SibprjhNKrnSPgBR9E,144
|
5
|
-
adapto-0.1.0.dist-info/LICENSE,sha256=SAzpYNgJ4rxFNBFW55imF0XI2fjW7O7yXqajoK1SBmw,1091
|
6
|
-
adapto-0.1.0.dist-info/METADATA,sha256=i2ikB2E6_fVLZgGUmwgC-LCkxr24pEHr2v2lR55vv-c,531
|
7
|
-
adapto-0.1.0.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
8
|
-
adapto-0.1.0.dist-info/top_level.txt,sha256=IYsgAr6fnEC1R1ztYmK2ZpFNNGV0qRaf3Tvf-R8j0cM,7
|
9
|
-
adapto-0.1.0.dist-info/RECORD,,
|
File without changes
|