xenfra 0.1.6__py3-none-any.whl → 0.1.8__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/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} | 📧 support@xenfracloud.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()
@@ -1,10 +0,0 @@
1
- xenfra/__init__.py,sha256=ja0-Vc9T61EXZnPeX84Fi-UOjoGAWu5r90_1t-0WjVw,46
2
- xenfra/cli.py,sha256=3c6EFZuiq2ede3S5WKskrFgup769ECXYMLEMWfeaLo8,6105
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.6.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
8
- xenfra-0.1.6.dist-info/entry_points.txt,sha256=pLGDlV0SH2hWunZJcEY7UkLLleMExFBaxgxRKYhU9mw,44
9
- xenfra-0.1.6.dist-info/METADATA,sha256=zbeICHmtktfW-ks2v4nZW8SpctvIdiT6kw6ggGw1oAo,4222
10
- xenfra-0.1.6.dist-info/RECORD,,
@@ -1,3 +0,0 @@
1
- [console_scripts]
2
- xenfra = xenfra.cli:main
3
-
File without changes