xenfra 0.1.7__py3-none-any.whl → 0.1.9__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.
- xenfra/api/auth.py +51 -0
- xenfra/api/billing.py +80 -0
- xenfra/api/connections.py +163 -0
- xenfra/api/main.py +175 -0
- xenfra/api/webhooks.py +146 -0
- xenfra/cli/main.py +211 -0
- xenfra/config.py +24 -0
- xenfra/db/models.py +51 -0
- xenfra/db/session.py +17 -0
- xenfra/dependencies.py +35 -0
- xenfra/dockerizer.py +45 -109
- xenfra/engine.py +255 -227
- xenfra/mcp_client.py +149 -0
- xenfra/models.py +54 -0
- xenfra/recipes.py +20 -118
- xenfra/security.py +58 -0
- xenfra/templates/Dockerfile.j2 +25 -0
- xenfra/templates/cloud-init.sh.j2 +72 -0
- xenfra/templates/docker-compose.yml.j2 +33 -0
- {xenfra-0.1.7.dist-info → xenfra-0.1.9.dist-info}/METADATA +30 -63
- xenfra-0.1.9.dist-info/RECORD +25 -0
- xenfra-0.1.9.dist-info/entry_points.txt +3 -0
- xenfra/cli.py +0 -169
- xenfra-0.1.7.dist-info/RECORD +0 -10
- xenfra-0.1.7.dist-info/entry_points.txt +0 -3
- {xenfra-0.1.7.dist-info → xenfra-0.1.9.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
xenfra/__init__.py,sha256=ja0-Vc9T61EXZnPeX84Fi-UOjoGAWu5r90_1t-0WjVw,46
|
|
2
|
+
xenfra/api/auth.py,sha256=WxepMKeF8Xnf9imqYip_EyGT0xFXgKoAhFIYx7uqWvA,1848
|
|
3
|
+
xenfra/api/billing.py,sha256=hoviKgpzjMoWcz0KW7I5HUhwLKPlRov5-3TIqzbdpAs,2871
|
|
4
|
+
xenfra/api/connections.py,sha256=IQfOA9jZV6Gcz0_E69Sgp3poAMQKwGwn19GV84Sn61I,7328
|
|
5
|
+
xenfra/api/main.py,sha256=psdVAOKsSM9vMmTSdZBuGceJNG50mqtJFbfa3UrTpmo,6392
|
|
6
|
+
xenfra/api/webhooks.py,sha256=Ek--AVzzKxvukway-vLt_wprBMaQjuWy7q35BbUKeiA,6367
|
|
7
|
+
xenfra/cli/main.py,sha256=1RiznGbrlaSDw37nD8i7wrpXMQsHnNuqk1YOYzxWdII,7841
|
|
8
|
+
xenfra/config.py,sha256=g7ahyI4kbYITRcliCbzXCRfKJ3uh8E2VMjmpR-n51s8,621
|
|
9
|
+
xenfra/db/models.py,sha256=nRqbG9cbcX8LWz2Jr4inKysAq47yALcxNl3_UYEpSoQ,1305
|
|
10
|
+
xenfra/db/session.py,sha256=Q03RIiPlYBtPD-qVHlTqQtacnOPTZnOy6_f9p6lABPU,510
|
|
11
|
+
xenfra/dependencies.py,sha256=pQ7bFNZHC24chMxRa_69mu2fIqcoc8DG9MD1POSGgjA,1211
|
|
12
|
+
xenfra/dockerizer.py,sha256=5qzgqw2MZrBwI4IFzXPJZ6k3F3IRdFnX-KGIpv5cjXc,3126
|
|
13
|
+
xenfra/engine.py,sha256=ZQOyThord9mEhthBxHSL7_8o_d-DsgyN_4VJ_WHCz-U,12954
|
|
14
|
+
xenfra/mcp_client.py,sha256=IxkTC3NPHvPJn-2dl5BUHQ3d-A9MBiKP9fIftzhmCuA,5756
|
|
15
|
+
xenfra/models.py,sha256=9Dvr1_kb29LJIR0a-uwx_tsCWt3GZeko6FKQtYY8F4g,1852
|
|
16
|
+
xenfra/recipes.py,sha256=q5ilpDzGuUM6GyvlW97pOpPS9nzQAJGI4pgzSU_URik,862
|
|
17
|
+
xenfra/security.py,sha256=w7aIFnHDHOH2zDjYD_LnJnSE01NeGeoAh_V8hC1HipY,2003
|
|
18
|
+
xenfra/templates/Dockerfile.j2,sha256=apWts895OOoUYwj_fOa6OiylFB5m8zFEYvJ1Nki32YM,664
|
|
19
|
+
xenfra/templates/cloud-init.sh.j2,sha256=Ln7XO4rwaHgauevMKfkxAgBFNLHPnWv-TnJl3NJbU8c,2359
|
|
20
|
+
xenfra/templates/docker-compose.yml.j2,sha256=zKUT2cd_FrxXvRxE-vAAjuQk3-nLNQjRe-StkhAWRQA,860
|
|
21
|
+
xenfra/utils.py,sha256=aGXjJm-pwVCHuCn5UBdrxRcYvM8aJwHQ1kihl7gcxiM,2387
|
|
22
|
+
xenfra-0.1.9.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
23
|
+
xenfra-0.1.9.dist-info/entry_points.txt,sha256=O6JNPm-inoMzmW29WPYl6jHHlWCrcs8ShHEo-CXvERs,49
|
|
24
|
+
xenfra-0.1.9.dist-info/METADATA,sha256=qjXKY6vbu_LM2QfJtAo_kC3tL_8V4UBly4dVJ1mn9nA,4128
|
|
25
|
+
xenfra-0.1.9.dist-info/RECORD,,
|
xenfra/cli.py
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
from rich.console import Console
|
|
2
|
-
from rich.table import Table
|
|
3
|
-
from rich.prompt import Prompt, Confirm, IntPrompt
|
|
4
|
-
from rich.panel import Panel
|
|
5
|
-
import importlib.metadata
|
|
6
|
-
|
|
7
|
-
# Import Custom Logic
|
|
8
|
-
from xenfra.engine import InfraEngine
|
|
9
|
-
|
|
10
|
-
console = Console()
|
|
11
|
-
|
|
12
|
-
# --- CONSTANTS ---
|
|
13
|
-
SIZES = {
|
|
14
|
-
"1": ("s-1vcpu-1gb", "$6/mo", "1GB RAM / 1 CPU"),
|
|
15
|
-
"2": ("s-1vcpu-2gb", "$12/mo", "2GB RAM / 1 CPU"),
|
|
16
|
-
"3": ("s-2vcpu-4gb", "$24/mo", "4GB RAM / 2 CPU"),
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
IMAGES = {
|
|
20
|
-
"1": ("ubuntu-24-04-x64", "Ubuntu 24.04 LTS"),
|
|
21
|
-
"2": ("debian-12-x64", "Debian 12"),
|
|
22
|
-
"3": ("fedora-39-x64", "Fedora 39"),
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
def print_header(email):
|
|
26
|
-
try:
|
|
27
|
-
# Get the version of the installed 'xenfra' package
|
|
28
|
-
version = importlib.metadata.version("xenfra")
|
|
29
|
-
except importlib.metadata.PackageNotFoundError:
|
|
30
|
-
version = "dev" # Fallback for local development
|
|
31
|
-
|
|
32
|
-
console.clear()
|
|
33
|
-
grid = Table.grid(expand=True)
|
|
34
|
-
grid.add_column(justify="center", ratio=1)
|
|
35
|
-
grid.add_row(f"[bold cyan]🧘 XENFRA[/bold cyan] [dim]v{version}[/dim]")
|
|
36
|
-
grid.add_row("[italic]Infrastructure in Zen Mode[/italic]")
|
|
37
|
-
console.print(Panel(
|
|
38
|
-
grid,
|
|
39
|
-
style="cyan",
|
|
40
|
-
subtitle=f"👤 {email} | 📧 xenfracloud@gmail.com"
|
|
41
|
-
))
|
|
42
|
-
|
|
43
|
-
def deploy_menu(engine: InfraEngine):
|
|
44
|
-
console.print("\n[bold green]🛠️ CONFIGURE YOUR SERVER[/bold green]")
|
|
45
|
-
|
|
46
|
-
# 1. Name
|
|
47
|
-
name = Prompt.ask(" 🏷️ Server Name", default="xenfra-node-01")
|
|
48
|
-
|
|
49
|
-
# 2. Image Selection
|
|
50
|
-
console.print("\n [bold]Select Operating System:[/bold]")
|
|
51
|
-
for k, v in IMAGES.items():
|
|
52
|
-
console.print(f" [cyan]{k}[/cyan]. {v[1]}")
|
|
53
|
-
img_choice = Prompt.ask(" Choice", choices=list(IMAGES.keys()), default="1")
|
|
54
|
-
selected_image = IMAGES[img_choice][0]
|
|
55
|
-
|
|
56
|
-
# 3. Size Selection
|
|
57
|
-
console.print("\n [bold]Select Power Size:[/bold]")
|
|
58
|
-
for k, v in SIZES.items():
|
|
59
|
-
console.print(f" [cyan]{k}[/cyan]. {v[2]} ({v[1]})")
|
|
60
|
-
size_choice = Prompt.ask(" Choice", choices=list(SIZES.keys()), default="1")
|
|
61
|
-
selected_size = SIZES[size_choice][0]
|
|
62
|
-
|
|
63
|
-
# 4. Final Confirm
|
|
64
|
-
if not Confirm.ask(f"\n🚀 Deploy [cyan]{name}[/cyan]?"):
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
# 5. EXECUTE (Delegate to Engine)
|
|
68
|
-
try:
|
|
69
|
-
# This is now a single, blocking call to the stateful engine.
|
|
70
|
-
# The engine handles all the complexity. The CLI just shows the final result.
|
|
71
|
-
result = engine.deploy_server(
|
|
72
|
-
name=name,
|
|
73
|
-
region="blr1", # region can be prompted for in the future
|
|
74
|
-
size=selected_size,
|
|
75
|
-
image=selected_image,
|
|
76
|
-
logger=console.log
|
|
77
|
-
)
|
|
78
|
-
console.print(Panel(
|
|
79
|
-
f"[bold green]✅ SERVER ONLINE & DEPLOYED![/bold green]\n\n"
|
|
80
|
-
f"🌍 IP Address: [bold cyan]{result['ip']}[/bold cyan]\n"
|
|
81
|
-
f"📂 App Path: [yellow]/root/app[/yellow]\n"
|
|
82
|
-
f"🔑 Login: ssh root@{result['ip']}",
|
|
83
|
-
title="Deployment Success",
|
|
84
|
-
border_style="green"
|
|
85
|
-
))
|
|
86
|
-
except Exception as e:
|
|
87
|
-
console.print(Panel(
|
|
88
|
-
f"[bold red]⚠️ DEPLOYMENT FAILED[/bold red]\n\n"
|
|
89
|
-
f"The engine reported a critical error: {e}\n"
|
|
90
|
-
f"Check logs if available on the server.",
|
|
91
|
-
title="Fatal Error",
|
|
92
|
-
border_style="red"
|
|
93
|
-
))
|
|
94
|
-
|
|
95
|
-
Prompt.ask("\nPress Enter to return to menu")
|
|
96
|
-
|
|
97
|
-
def list_menu(engine: InfraEngine):
|
|
98
|
-
console.print("\n[bold]📡 SCANNING FLEET...[/bold]")
|
|
99
|
-
with console.status("Calling DigitalOcean API..."):
|
|
100
|
-
servers = engine.list_servers()
|
|
101
|
-
|
|
102
|
-
if not servers:
|
|
103
|
-
console.print("[yellow] No active servers found.[/yellow]")
|
|
104
|
-
else:
|
|
105
|
-
table = Table(show_header=True, header_style="bold magenta")
|
|
106
|
-
table.add_column("ID", style="dim", width=12)
|
|
107
|
-
table.add_column("Name", style="cyan")
|
|
108
|
-
table.add_column("IP Address", style="green")
|
|
109
|
-
table.add_column("Status")
|
|
110
|
-
table.add_column("Cost", justify="right")
|
|
111
|
-
for s in servers:
|
|
112
|
-
table.add_row(str(s.id), s.name, s.ip_address, s.status, f"${s.size['price_monthly']}/mo")
|
|
113
|
-
console.print(table)
|
|
114
|
-
Prompt.ask("\nPress Enter to return to menu")
|
|
115
|
-
|
|
116
|
-
def destroy_menu(engine: InfraEngine):
|
|
117
|
-
console.print("\n[bold red]🧨 DESTROY SERVER[/bold red]")
|
|
118
|
-
with console.status("Calling DigitalOcean API..."):
|
|
119
|
-
servers = engine.list_servers()
|
|
120
|
-
|
|
121
|
-
if not servers:
|
|
122
|
-
console.print("[yellow] No servers to destroy.[/yellow]")
|
|
123
|
-
Prompt.ask("\nPress Enter to return")
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
for i, s in enumerate(servers):
|
|
127
|
-
console.print(f" [{i+1}] {s.name} ({s.ip_address})")
|
|
128
|
-
|
|
129
|
-
choice = IntPrompt.ask("\n Select Server to Destroy (0 to cancel)", choices=[str(i) for i in range(len(servers) + 1)], show_choices=False)
|
|
130
|
-
if choice == 0:
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
target = servers[choice-1]
|
|
134
|
-
|
|
135
|
-
if Confirm.ask(f" Are you SURE you want to delete [red]{target.name}[/red]?"):
|
|
136
|
-
with console.status(f"💥 Destroying {target.name}..."):
|
|
137
|
-
engine.destroy_server(target.id)
|
|
138
|
-
console.print(f"[green] Server {target.name} destroyed.[/green]")
|
|
139
|
-
|
|
140
|
-
Prompt.ask("\nPress Enter to return")
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def main():
|
|
144
|
-
try:
|
|
145
|
-
engine = InfraEngine()
|
|
146
|
-
user = engine.get_user_info()
|
|
147
|
-
while True:
|
|
148
|
-
print_header(user['email'])
|
|
149
|
-
console.print("\n[bold]MAIN MENU:[/bold]")
|
|
150
|
-
console.print(" [1] 🚀 Deploy New Server")
|
|
151
|
-
console.print(" [2] 📋 List Active Servers")
|
|
152
|
-
console.print(" [3] 🧨 Destroy a Server")
|
|
153
|
-
console.print(" [4] 🚪 Exit")
|
|
154
|
-
choice = Prompt.ask("\n 👉 Select Option", choices=["1", "2", "3", "4"], default="2")
|
|
155
|
-
|
|
156
|
-
if choice == "1":
|
|
157
|
-
deploy_menu(engine)
|
|
158
|
-
elif choice == "2":
|
|
159
|
-
list_menu(engine)
|
|
160
|
-
elif choice == "3":
|
|
161
|
-
destroy_menu(engine)
|
|
162
|
-
elif choice == "4":
|
|
163
|
-
console.print("[cyan]Goodbye, CEO.[/cyan]")
|
|
164
|
-
break
|
|
165
|
-
except Exception as e:
|
|
166
|
-
console.print(f"[bold red]CRITICAL ERROR:[/bold red] {e}")
|
|
167
|
-
|
|
168
|
-
if __name__ == "__main__":
|
|
169
|
-
main()
|
xenfra-0.1.7.dist-info/RECORD
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
xenfra/__init__.py,sha256=ja0-Vc9T61EXZnPeX84Fi-UOjoGAWu5r90_1t-0WjVw,46
|
|
2
|
-
xenfra/cli.py,sha256=AXCVncZEo3oM0VfZYk0zIIHPrziKQRiwG7OYv6HsaVY,6103
|
|
3
|
-
xenfra/dockerizer.py,sha256=exmmzCHi55FR0PS5TzyK7xKd4FYreaYSPg1cwVkyJj0,4289
|
|
4
|
-
xenfra/engine.py,sha256=wIlVC9krILGY2xmp5CFBPyNsI2ugy1e4cR9YruYLNzI,10636
|
|
5
|
-
xenfra/recipes.py,sha256=KvGu-5f0ycBEZmqwBW3rCF7sz3PI-ZNg8x95jaw2v1U,4047
|
|
6
|
-
xenfra/utils.py,sha256=aGXjJm-pwVCHuCn5UBdrxRcYvM8aJwHQ1kihl7gcxiM,2387
|
|
7
|
-
xenfra-0.1.7.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
8
|
-
xenfra-0.1.7.dist-info/entry_points.txt,sha256=pLGDlV0SH2hWunZJcEY7UkLLleMExFBaxgxRKYhU9mw,44
|
|
9
|
-
xenfra-0.1.7.dist-info/METADATA,sha256=_EuzoqOsAnBorh48O-7CLosKpS4odW-KZxytf7GNsV0,4222
|
|
10
|
-
xenfra-0.1.7.dist-info/RECORD,,
|
|
File without changes
|