golem-vm-provider 0.1.17__py3-none-any.whl → 0.1.18__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.
- {golem_vm_provider-0.1.17.dist-info → golem_vm_provider-0.1.18.dist-info}/METADATA +1 -1
- {golem_vm_provider-0.1.17.dist-info → golem_vm_provider-0.1.18.dist-info}/RECORD +6 -5
- provider/config.py +21 -3
- provider/utils/setup.py +100 -0
- {golem_vm_provider-0.1.17.dist-info → golem_vm_provider-0.1.18.dist-info}/WHEEL +0 -0
- {golem_vm_provider-0.1.17.dist-info → golem_vm_provider-0.1.18.dist-info}/entry_points.txt +0 -0
@@ -2,7 +2,7 @@ provider/__init__.py,sha256=HO1fkPpZqPO3z8O8-eVIyx8xXSMIVuTR_b1YF0RtXOg,45
|
|
2
2
|
provider/api/__init__.py,sha256=ssX1ugDqEPt8Fn04IymgmG-Ev8PiXLsCSaiZVvHQnec,344
|
3
3
|
provider/api/models.py,sha256=JOzoNf1oE5N97UqTN5xuIrTkqn2tCHqPDaIzGA3jUyo,3513
|
4
4
|
provider/api/routes.py,sha256=P27RQvNqFWn6PacRwr1PaVz-yv5KAWsp9KeORejkXSI,6452
|
5
|
-
provider/config.py,sha256
|
5
|
+
provider/config.py,sha256=-Cu05ebOjUbhnh5iv3raQ7Z79HMhZ9EcRIRrZVW3Ino,14513
|
6
6
|
provider/discovery/__init__.py,sha256=VR3NRoQtZRH5Vs8FG7jnGLR7p7wn7XeZdLaBb3t8e1g,123
|
7
7
|
provider/discovery/advertiser.py,sha256=yv7RbRf1K43qOLAEa2Olj9hhN8etl2qsBuoHok0xoVs,6784
|
8
8
|
provider/discovery/resource_tracker.py,sha256=8dYhJxoe_jLRwisHoA0jr575YhUKmLIqSXfW88KshcQ,6000
|
@@ -13,6 +13,7 @@ provider/utils/ascii_art.py,sha256=ykBFsztk57GIiz1NJ-EII5UvN74iECqQL4h9VmiW6Z8,3
|
|
13
13
|
provider/utils/logging.py,sha256=C_elr0sJROHKQgErYpHJQvfujgh0k4Zf2gg8ZKfrmVk,2590
|
14
14
|
provider/utils/port_display.py,sha256=5d_604Eo-82dqx_yV2ZScq7bKQ8IsXacc-yXC_KAz3A,11031
|
15
15
|
provider/utils/retry.py,sha256=ekP2ucaSJNN-lBcrIvyHa4QYPKNITMl1a5V1X6BBvsw,1560
|
16
|
+
provider/utils/setup.py,sha256=Z5dLuBQkb5vdoQsu1HJZwXmu9NWsiBYJ7Vq9-C-_tY8,2932
|
16
17
|
provider/vm/__init__.py,sha256=JGs50tUmzOR1rQ_w4fMY_3XWylmiA1G7KKWZkVw51mY,501
|
17
18
|
provider/vm/cloud_init.py,sha256=E5dDH7dqStRcJNDfbarBBe83-c9N63W8B5ycIrHI8eU,4627
|
18
19
|
provider/vm/models.py,sha256=zkfvP5Z50SPDNajwZTt9NTDIMRQIsZLvSOsuirHEcJM,6256
|
@@ -20,7 +21,7 @@ provider/vm/multipass.py,sha256=FOcsfcJ-NrgBg_fvq_CKOKsQ0xOmk7Z34KXi3ag_Vl8,1660
|
|
20
21
|
provider/vm/name_mapper.py,sha256=MrshNeJ4Dw-WBsyiIVcn9N5xyOxaBKX4Yqhyh_m5IFg,4103
|
21
22
|
provider/vm/port_manager.py,sha256=d03uwU76vx6LgADMN8ffBT9t400XQ3vtYlXr6cLIFN0,9831
|
22
23
|
provider/vm/proxy_manager.py,sha256=cu0FPPbeCc3CR6NRE_CnLjiRg7xVdSFUylVUOL1g1sI,10154
|
23
|
-
golem_vm_provider-0.1.
|
24
|
-
golem_vm_provider-0.1.
|
25
|
-
golem_vm_provider-0.1.
|
26
|
-
golem_vm_provider-0.1.
|
24
|
+
golem_vm_provider-0.1.18.dist-info/METADATA,sha256=8YfU5Z2xOi0URBANotJQK27x2zJvUz5o2rzVl5hRHt0,10594
|
25
|
+
golem_vm_provider-0.1.18.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
26
|
+
golem_vm_provider-0.1.18.dist-info/entry_points.txt,sha256=E4rCWo_Do_2zCG_GewNuftfVlHF_8b_OvioZre0dfeA,54
|
27
|
+
golem_vm_provider-0.1.18.dist-info/RECORD,,
|
provider/config.py
CHANGED
@@ -64,6 +64,7 @@ class Settings(BaseSettings):
|
|
64
64
|
"""Resolve and create cloud-init directory path."""
|
65
65
|
import platform
|
66
66
|
import tempfile
|
67
|
+
from .utils.setup import setup_cloud_init_dir, check_setup_needed, mark_setup_complete
|
67
68
|
|
68
69
|
def verify_dir_permissions(path: Path) -> bool:
|
69
70
|
"""Verify directory has correct permissions and is accessible."""
|
@@ -86,15 +87,32 @@ class Settings(BaseSettings):
|
|
86
87
|
if system == "linux" and Path("/snap/bin/multipass").exists():
|
87
88
|
# Linux with snap
|
88
89
|
path = Path("/var/snap/multipass/common/cloud-init")
|
90
|
+
|
91
|
+
# Check if we need to set up permissions
|
92
|
+
if check_setup_needed():
|
93
|
+
logger.info("First run detected, setting up cloud-init directory...")
|
94
|
+
success, error = setup_cloud_init_dir(path)
|
95
|
+
if success:
|
96
|
+
logger.info("✓ Cloud-init directory setup complete")
|
97
|
+
mark_setup_complete()
|
98
|
+
else:
|
99
|
+
logger.error(f"Failed to set up cloud-init directory: {error}")
|
100
|
+
logger.error("\nTo fix this manually, run these commands:")
|
101
|
+
logger.error(" sudo mkdir -p /var/snap/multipass/common/cloud-init")
|
102
|
+
logger.error(" sudo chown -R $USER:$USER /var/snap/multipass/common/cloud-init")
|
103
|
+
logger.error(" sudo chmod -R 755 /var/snap/multipass/common/cloud-init\n")
|
104
|
+
# Fall back to user's home directory
|
105
|
+
path = Path.home() / ".local" / "share" / "golem" / "provider" / "cloud-init"
|
106
|
+
|
89
107
|
elif system == "linux":
|
90
108
|
# Linux without snap
|
91
|
-
path = Path("/
|
109
|
+
path = Path.home() / ".local" / "share" / "golem" / "provider" / "cloud-init"
|
92
110
|
elif system == "darwin":
|
93
111
|
# macOS
|
94
|
-
path = Path("
|
112
|
+
path = Path.home() / "Library" / "Application Support" / "golem" / "provider" / "cloud-init"
|
95
113
|
elif system == "windows":
|
96
114
|
# Windows
|
97
|
-
path = Path(os.path.expandvars("%
|
115
|
+
path = Path(os.path.expandvars("%LOCALAPPDATA%")) / "golem" / "provider" / "cloud-init"
|
98
116
|
else:
|
99
117
|
path = Path.home() / ".golem" / "provider" / "cloud-init"
|
100
118
|
|
provider/utils/setup.py
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
import os
|
2
|
+
import subprocess
|
3
|
+
import platform
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Tuple
|
6
|
+
|
7
|
+
from .logging import setup_logger
|
8
|
+
|
9
|
+
logger = setup_logger(__name__)
|
10
|
+
|
11
|
+
def run_sudo_command(cmd: str) -> Tuple[bool, str]:
|
12
|
+
"""Run a command with sudo.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
cmd: Command to run
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
Tuple of (success, error_message)
|
19
|
+
"""
|
20
|
+
try:
|
21
|
+
# Try non-interactive sudo first
|
22
|
+
result = subprocess.run(
|
23
|
+
f"sudo -n {cmd}",
|
24
|
+
shell=True,
|
25
|
+
capture_output=True,
|
26
|
+
text=True
|
27
|
+
)
|
28
|
+
if result.returncode == 0:
|
29
|
+
return True, ""
|
30
|
+
|
31
|
+
# If that fails, try interactive sudo
|
32
|
+
logger.warning("Non-interactive sudo failed, will prompt for password")
|
33
|
+
result = subprocess.run(
|
34
|
+
f"sudo {cmd}",
|
35
|
+
shell=True,
|
36
|
+
capture_output=True,
|
37
|
+
text=True
|
38
|
+
)
|
39
|
+
if result.returncode == 0:
|
40
|
+
return True, ""
|
41
|
+
|
42
|
+
return False, result.stderr
|
43
|
+
|
44
|
+
except Exception as e:
|
45
|
+
return False, str(e)
|
46
|
+
|
47
|
+
def setup_cloud_init_dir(path: Path) -> Tuple[bool, str]:
|
48
|
+
"""Set up cloud-init directory with correct permissions.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
path: Path to cloud-init directory
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
Tuple of (success, error_message)
|
55
|
+
"""
|
56
|
+
if platform.system().lower() != "linux" or not Path("/snap/bin/multipass").exists():
|
57
|
+
# Only needed for Linux with snap
|
58
|
+
return True, ""
|
59
|
+
|
60
|
+
try:
|
61
|
+
# Create directory
|
62
|
+
success, error = run_sudo_command(f"mkdir -p {path}")
|
63
|
+
if not success:
|
64
|
+
return False, f"Failed to create directory: {error}"
|
65
|
+
|
66
|
+
# Set ownership
|
67
|
+
user = os.environ.get("USER", os.environ.get("USERNAME"))
|
68
|
+
success, error = run_sudo_command(f"chown -R {user}:{user} {path}")
|
69
|
+
if not success:
|
70
|
+
return False, f"Failed to set ownership: {error}"
|
71
|
+
|
72
|
+
# Set permissions
|
73
|
+
success, error = run_sudo_command(f"chmod -R 755 {path}")
|
74
|
+
if not success:
|
75
|
+
return False, f"Failed to set permissions: {error}"
|
76
|
+
|
77
|
+
return True, ""
|
78
|
+
|
79
|
+
except Exception as e:
|
80
|
+
return False, str(e)
|
81
|
+
|
82
|
+
def check_setup_needed() -> bool:
|
83
|
+
"""Check if setup is needed.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
True if setup is needed, False otherwise
|
87
|
+
"""
|
88
|
+
# Only needed for Linux with snap
|
89
|
+
if platform.system().lower() != "linux" or not Path("/snap/bin/multipass").exists():
|
90
|
+
return False
|
91
|
+
|
92
|
+
# Check if setup has already been completed
|
93
|
+
setup_flag = Path.home() / ".golem" / "provider" / ".setup-complete"
|
94
|
+
return not setup_flag.exists()
|
95
|
+
|
96
|
+
def mark_setup_complete() -> None:
|
97
|
+
"""Mark setup as complete."""
|
98
|
+
setup_flag = Path.home() / ".golem" / "provider" / ".setup-complete"
|
99
|
+
setup_flag.parent.mkdir(parents=True, exist_ok=True)
|
100
|
+
setup_flag.touch()
|
File without changes
|
File without changes
|