request-vm-on-golem 0.1.24__py3-none-any.whl → 0.1.26__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {request_vm_on_golem-0.1.24.dist-info → request_vm_on_golem-0.1.26.dist-info}/METADATA +11 -9
- request_vm_on_golem-0.1.26.dist-info/RECORD +24 -0
- {request_vm_on_golem-0.1.24.dist-info → request_vm_on_golem-0.1.26.dist-info}/WHEEL +1 -1
- requestor/api/main.py +59 -0
- requestor/cli/commands.py +213 -256
- requestor/config.py +36 -2
- requestor/db/sqlite.py +33 -41
- requestor/run.py +4 -2
- requestor/services/__init__.py +6 -0
- requestor/services/database_service.py +91 -0
- requestor/services/provider_service.py +265 -0
- requestor/services/ssh_service.py +121 -0
- requestor/services/vm_service.py +209 -0
- request_vm_on_golem-0.1.24.dist-info/RECORD +0 -18
- {request_vm_on_golem-0.1.24.dist-info → request_vm_on_golem-0.1.26.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,209 @@
|
|
1
|
+
"""VM management service."""
|
2
|
+
from typing import Dict, List, Optional
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
from ..provider.client import ProviderClient
|
6
|
+
from ..errors import RequestorError, VMError
|
7
|
+
from .database_service import DatabaseService
|
8
|
+
from .ssh_service import SSHService
|
9
|
+
|
10
|
+
class VMService:
|
11
|
+
"""Service for VM operations."""
|
12
|
+
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
db_service: DatabaseService,
|
16
|
+
ssh_service: SSHService,
|
17
|
+
provider_client: Optional[ProviderClient] = None
|
18
|
+
):
|
19
|
+
self.db = db_service
|
20
|
+
self.ssh_service = ssh_service
|
21
|
+
self.provider_client = provider_client
|
22
|
+
|
23
|
+
async def create_vm(
|
24
|
+
self,
|
25
|
+
name: str,
|
26
|
+
cpu: int,
|
27
|
+
memory: int,
|
28
|
+
storage: int,
|
29
|
+
provider_ip: str,
|
30
|
+
ssh_key: str
|
31
|
+
) -> Dict:
|
32
|
+
"""Create a new VM with validation and error handling."""
|
33
|
+
try:
|
34
|
+
# Check if VM name already exists
|
35
|
+
existing_vm = await self.db.get_vm(name)
|
36
|
+
if existing_vm:
|
37
|
+
raise VMError(f"VM with name '{name}' already exists")
|
38
|
+
|
39
|
+
# Create VM on provider
|
40
|
+
vm = await self.provider_client.create_vm(
|
41
|
+
name=name,
|
42
|
+
cpu=cpu,
|
43
|
+
memory=memory,
|
44
|
+
storage=storage,
|
45
|
+
ssh_key=ssh_key
|
46
|
+
)
|
47
|
+
|
48
|
+
# Get VM access info
|
49
|
+
access_info = await self.provider_client.get_vm_access(vm['id'])
|
50
|
+
|
51
|
+
# Save VM details to database
|
52
|
+
config = {
|
53
|
+
'cpu': cpu,
|
54
|
+
'memory': memory,
|
55
|
+
'storage': storage,
|
56
|
+
'ssh_port': access_info['ssh_port']
|
57
|
+
}
|
58
|
+
await self.db.save_vm(
|
59
|
+
name=name,
|
60
|
+
provider_ip=provider_ip,
|
61
|
+
vm_id=access_info['vm_id'],
|
62
|
+
config=config
|
63
|
+
)
|
64
|
+
|
65
|
+
return {
|
66
|
+
'name': name,
|
67
|
+
'provider_ip': provider_ip,
|
68
|
+
'vm_id': access_info['vm_id'],
|
69
|
+
'config': config,
|
70
|
+
'status': 'running'
|
71
|
+
}
|
72
|
+
|
73
|
+
except Exception as e:
|
74
|
+
raise VMError(f"Failed to create VM: {str(e)}")
|
75
|
+
|
76
|
+
async def destroy_vm(self, name: str) -> None:
|
77
|
+
"""Destroy a VM and clean up resources."""
|
78
|
+
try:
|
79
|
+
# Get VM details
|
80
|
+
vm = await self.db.get_vm(name)
|
81
|
+
if not vm:
|
82
|
+
raise VMError(f"VM '{name}' not found")
|
83
|
+
|
84
|
+
try:
|
85
|
+
# Destroy VM on provider
|
86
|
+
await self.provider_client.destroy_vm(vm['vm_id'])
|
87
|
+
except Exception as e:
|
88
|
+
if "Not Found" not in str(e):
|
89
|
+
raise
|
90
|
+
|
91
|
+
# Remove from database
|
92
|
+
await self.db.delete_vm(name)
|
93
|
+
|
94
|
+
except Exception as e:
|
95
|
+
raise VMError(f"Failed to destroy VM: {str(e)}")
|
96
|
+
|
97
|
+
async def start_vm(self, name: str) -> None:
|
98
|
+
"""Start a stopped VM."""
|
99
|
+
try:
|
100
|
+
# Get VM details
|
101
|
+
vm = await self.db.get_vm(name)
|
102
|
+
if not vm:
|
103
|
+
raise VMError(f"VM '{name}' not found")
|
104
|
+
|
105
|
+
# Start VM on provider
|
106
|
+
await self.provider_client.start_vm(vm['vm_id'])
|
107
|
+
|
108
|
+
# Update status in database
|
109
|
+
await self.db.update_vm_status(name, "running")
|
110
|
+
|
111
|
+
except Exception as e:
|
112
|
+
raise VMError(f"Failed to start VM: {str(e)}")
|
113
|
+
|
114
|
+
async def stop_vm(self, name: str) -> None:
|
115
|
+
"""Stop a running VM."""
|
116
|
+
try:
|
117
|
+
# Get VM details
|
118
|
+
vm = await self.db.get_vm(name)
|
119
|
+
if not vm:
|
120
|
+
raise VMError(f"VM '{name}' not found")
|
121
|
+
|
122
|
+
# Stop VM on provider
|
123
|
+
await self.provider_client.stop_vm(vm['vm_id'])
|
124
|
+
|
125
|
+
# Update status in database
|
126
|
+
await self.db.update_vm_status(name, "stopped")
|
127
|
+
|
128
|
+
except Exception as e:
|
129
|
+
raise VMError(f"Failed to stop VM: {str(e)}")
|
130
|
+
|
131
|
+
async def list_vms(self) -> List[Dict]:
|
132
|
+
"""List all VMs with their current status."""
|
133
|
+
try:
|
134
|
+
return await self.db.list_vms()
|
135
|
+
except Exception as e:
|
136
|
+
raise VMError(f"Failed to list VMs: {str(e)}")
|
137
|
+
|
138
|
+
async def get_vm(self, name: str) -> Optional[Dict]:
|
139
|
+
"""Get VM details by name."""
|
140
|
+
try:
|
141
|
+
vm = await self.db.get_vm(name)
|
142
|
+
if not vm:
|
143
|
+
return None
|
144
|
+
return vm
|
145
|
+
except Exception as e:
|
146
|
+
raise VMError(f"Failed to get VM details: {str(e)}")
|
147
|
+
|
148
|
+
def format_vm_row(self, vm: Dict, colorize: bool = False) -> List:
|
149
|
+
"""Format VM information for display."""
|
150
|
+
from click import style
|
151
|
+
|
152
|
+
row = [
|
153
|
+
vm['name'],
|
154
|
+
vm['status'],
|
155
|
+
vm['provider_ip'],
|
156
|
+
vm['config'].get('ssh_port', 'N/A'),
|
157
|
+
vm['config']['cpu'],
|
158
|
+
vm['config']['memory'],
|
159
|
+
vm['config']['storage'],
|
160
|
+
vm['created_at']
|
161
|
+
]
|
162
|
+
|
163
|
+
if colorize:
|
164
|
+
# Format status with color and icon
|
165
|
+
status = row[1]
|
166
|
+
if status == "running":
|
167
|
+
row[1] = style("● " + status, fg="green", bold=True)
|
168
|
+
elif status == "stopped":
|
169
|
+
row[1] = style("● " + status, fg="yellow", bold=True)
|
170
|
+
else:
|
171
|
+
row[1] = style("● " + status, fg="red", bold=True)
|
172
|
+
|
173
|
+
# Format other columns
|
174
|
+
row[0] = style(row[0], fg="cyan") # Name
|
175
|
+
row[2] = style(row[2], fg="cyan") # IP
|
176
|
+
row[3] = style(str(row[3]), fg="cyan") # Port
|
177
|
+
|
178
|
+
return row
|
179
|
+
|
180
|
+
@property
|
181
|
+
def vm_headers(self) -> List[str]:
|
182
|
+
"""Get headers for VM display."""
|
183
|
+
return [
|
184
|
+
"Name",
|
185
|
+
"Status",
|
186
|
+
"IP Address",
|
187
|
+
"SSH Port",
|
188
|
+
"CPU",
|
189
|
+
"Memory (GB)",
|
190
|
+
"Storage (GB)",
|
191
|
+
"Created"
|
192
|
+
]
|
193
|
+
|
194
|
+
async def get_vm_stats(self, name: str) -> Dict:
|
195
|
+
"""Get VM stats by name."""
|
196
|
+
try:
|
197
|
+
vm = await self.db.get_vm(name)
|
198
|
+
if not vm:
|
199
|
+
raise VMError(f"VM '{name}' not found")
|
200
|
+
|
201
|
+
key_pair = await self.ssh_service.get_key_pair()
|
202
|
+
|
203
|
+
return self.ssh_service.get_vm_stats(
|
204
|
+
host=vm['provider_ip'],
|
205
|
+
port=vm['config']['ssh_port'],
|
206
|
+
private_key_path=key_pair.private_key
|
207
|
+
)
|
208
|
+
except Exception as e:
|
209
|
+
raise VMError(f"Failed to get VM stats: {str(e)}")
|
@@ -1,18 +0,0 @@
|
|
1
|
-
requestor/__init__.py,sha256=OqSUAh1uZBMx7GW0MoSMg967PVdmT8XdPJx3QYjwkak,116
|
2
|
-
requestor/cli/__init__.py,sha256=e3E4oEGxmGj-STPtFkQwg_qIWhR0JAiAQdw3G1hXciU,37
|
3
|
-
requestor/cli/commands.py,sha256=deW4HxJGJvWQCOEvkuPEzkIfSDOSYa2npO4i_4sesCo,24283
|
4
|
-
requestor/config.py,sha256=3e0xAuteZ3JiE6uWHipQLQQklGN59hiqdqZUT2mUutM,2146
|
5
|
-
requestor/db/__init__.py,sha256=Gm5DfWls6uvCZZ3HGGnyRHswbUQdeA5OGN8yPwH0hc8,88
|
6
|
-
requestor/db/sqlite.py,sha256=kqutQMs3srcZHa5kI1cbHvOYr66cCfQCb2xuioNAbLc,4638
|
7
|
-
requestor/errors.py,sha256=wVpHBuYgQx5pTe_SamugfK-k768noikY1RxvPOjQGko,665
|
8
|
-
requestor/provider/__init__.py,sha256=fmW23aYUVciF8-gmBZkG-PLhn22upmcDzdPfAOLHG6g,103
|
9
|
-
requestor/provider/client.py,sha256=OUP7CoOCCtKD6DB9eqFkOXK6A2BLFdM4DWSkoulJQxg,3213
|
10
|
-
requestor/run.py,sha256=mFqoP93KuRpQZ8pmzP5pHvByaDjHJ9xRYRjYC77s6bg,1386
|
11
|
-
requestor/ssh/__init__.py,sha256=hNgSqJ5s1_AwwxVRyFjUqh_LTBpI4Hmzq0F-f_wXN9g,119
|
12
|
-
requestor/ssh/manager.py,sha256=h-93AXFJqzGo2lNTG2u-q4ivU9cCFeNDhYN55skPLBo,6566
|
13
|
-
requestor/utils/logging.py,sha256=oFNpO8pJboYM8Wp7g3HOU4HFyBTKypVdY15lUiz1a4I,3721
|
14
|
-
requestor/utils/spinner.py,sha256=PUHJdTD9jpUHur__01_qxXy87WFfNmjQbD_sLG-KlGo,2459
|
15
|
-
request_vm_on_golem-0.1.24.dist-info/METADATA,sha256=969OAj0KxwHXeI6BWZkfiLbjyO-sYdBPxlDyEP9QyTE,9060
|
16
|
-
request_vm_on_golem-0.1.24.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
17
|
-
request_vm_on_golem-0.1.24.dist-info/entry_points.txt,sha256=Z-skRNpJ8aZcIl_En9mEm1ygkp9FKy0bzQoL3zO52-0,44
|
18
|
-
request_vm_on_golem-0.1.24.dist-info/RECORD,,
|
{request_vm_on_golem-0.1.24.dist-info → request_vm_on_golem-0.1.26.dist-info}/entry_points.txt
RENAMED
File without changes
|