xenfra 0.1.8__tar.gz → 0.2.0__tar.gz

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.
Files changed (24) hide show
  1. {xenfra-0.1.8 → xenfra-0.2.0}/PKG-INFO +1 -1
  2. {xenfra-0.1.8 → xenfra-0.2.0}/pyproject.toml +1 -1
  3. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/engine.py +33 -4
  4. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/templates/cloud-init.sh.j2 +6 -10
  5. {xenfra-0.1.8 → xenfra-0.2.0}/README.md +0 -0
  6. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/__init__.py +0 -0
  7. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/api/auth.py +0 -0
  8. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/api/billing.py +0 -0
  9. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/api/connections.py +0 -0
  10. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/api/main.py +0 -0
  11. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/api/webhooks.py +0 -0
  12. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/cli/main.py +0 -0
  13. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/config.py +0 -0
  14. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/db/models.py +0 -0
  15. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/db/session.py +0 -0
  16. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/dependencies.py +0 -0
  17. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/dockerizer.py +0 -0
  18. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/mcp_client.py +0 -0
  19. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/models.py +0 -0
  20. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/recipes.py +0 -0
  21. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/security.py +0 -0
  22. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/templates/Dockerfile.j2 +0 -0
  23. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/templates/docker-compose.yml.j2 +0 -0
  24. {xenfra-0.1.8 → xenfra-0.2.0}/src/xenfra/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: xenfra
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: A 'Zen Mode' infrastructure engine for Python developers.
5
5
  Author: xenfra-cloud
6
6
  Author-email: xenfra-cloud <xenfracloud@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xenfra"
3
- version = "0.1.8"
3
+ version = "0.2.0"
4
4
  description = "A 'Zen Mode' infrastructure engine for Python developers."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -44,7 +44,15 @@ class InfraEngine:
44
44
 
45
45
  def _get_connection(self, ip_address: str):
46
46
  """Establishes a Fabric connection to the server."""
47
- return fabric.Connection(host=ip_address, user="root", connect_kwargs={"password": None}) # Assumes SSH key auth
47
+ private_key_path = str(Path.home() / ".ssh" / "id_rsa")
48
+ if not Path(private_key_path).exists():
49
+ raise DeploymentError("No private SSH key found at ~/.ssh/id_rsa.", stage="Setup")
50
+
51
+ return fabric.Connection(
52
+ host=ip_address,
53
+ user="root",
54
+ connect_kwargs={"key_filename": [private_key_path]},
55
+ )
48
56
 
49
57
  def get_user_info(self):
50
58
  """Retrieves user account information."""
@@ -189,12 +197,33 @@ class InfraEngine:
189
197
  while True:
190
198
  droplet.load()
191
199
  if droplet.status == 'active':
192
- logger(" - Droplet is active. Waiting for cloud-init to complete...")
200
+ logger(" - Droplet is active. Waiting for SSH to be available...")
193
201
  break
194
202
  time.sleep(10)
195
-
203
+
196
204
  ip_address = droplet.ip_address
197
- with self._get_connection(ip_address) as conn:
205
+
206
+ # Retry SSH connection
207
+ conn = None
208
+ max_retries = 12 # 2-minute timeout for SSH
209
+ for i in range(max_retries):
210
+ try:
211
+ logger(f" - Attempting SSH connection ({i+1}/{max_retries})...")
212
+ conn = self._get_connection(ip_address)
213
+ conn.open() # Explicitly open the connection
214
+ logger(" - SSH connection established.")
215
+ break
216
+ except Exception as e:
217
+ if i < max_retries - 1:
218
+ logger(f" - SSH connection failed. Retrying in 10s...")
219
+ time.sleep(10)
220
+ else:
221
+ raise DeploymentError(f"Failed to establish SSH connection: {e}", stage="Polling")
222
+
223
+ if not conn or not conn.is_connected:
224
+ raise DeploymentError("Could not establish SSH connection.", stage="Polling")
225
+
226
+ with conn:
198
227
  for i in range(30): # 5-minute timeout for cloud-init
199
228
  if conn.run("test -f /root/setup_complete", warn=True).ok:
200
229
  logger(" - Cloud-init setup complete.")
@@ -27,18 +27,18 @@ dpkg --configure -a || true
27
27
  # -----------------------------------------------
28
28
 
29
29
  # 1. System Updates
30
- echo "🔄 [1/6] Refreshing Package Lists..." >> $LOG
30
+ echo "🔄 [1/5] Refreshing Package Lists..." >> $LOG
31
31
  apt-get update
32
32
  apt-get install -y python3-pip git curl
33
33
 
34
34
  # 2. Install Docker & Compose
35
- echo "🐳 [2/6] Installing Docker..." >> $LOG
35
+ echo "🐳 [2/5] Installing Docker..." >> $LOG
36
36
  apt-get install -y docker.io || (curl -fsSL https://get.docker.com | sh)
37
- echo "🎶 [3/6] Installing Docker Compose..." >> $LOG
37
+ echo "🎶 [3/5] Installing Docker Compose..." >> $LOG
38
38
  apt-get install -y docker-compose-v2
39
39
 
40
40
  # --- DOCKERIZED DEPLOYMENT ---
41
- echo "📦 [4/6] Installing Caddy..." >> $LOG
41
+ echo "📦 [4/5] Installing Caddy..." >> $LOG
42
42
  apt-get install -y debian-keyring debian-archive-keyring apt-transport-https
43
43
  curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
44
44
  curl -LsSf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
@@ -56,15 +56,11 @@ cat << EOF > /etc/caddy/Caddyfile
56
56
  EOF
57
57
  {% endif %}
58
58
 
59
- echo "🚀 [5/6] Starting application with Docker Compose..." >> $LOG
60
- cd /root/app
61
- docker-compose -f /root/app/docker-compose.yml up -d
62
-
63
59
  {% if domain %}
64
- echo "🔒 [6/6] Starting Caddy..." >> $LOG
60
+ echo "🚀 [5/5] Starting Caddy..." >> $LOG
65
61
  systemctl restart caddy
66
62
  {% else %}
67
- echo "✅ [6/6] Skipping Caddy start (no domain specified)." >> $LOG
63
+ echo "✅ [5/5] Skipping Caddy start (no domain specified)." >> $LOG
68
64
  {% endif %}
69
65
 
70
66
  # Finish
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes