clonebox 0.1.1__py3-none-any.whl → 0.1.2__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.
- clonebox/cli.py +884 -0
- clonebox/cloner.py +85 -9
- clonebox/detector.py +3 -1
- clonebox-0.1.2.dist-info/METADATA +301 -0
- clonebox-0.1.2.dist-info/RECORD +10 -0
- clonebox-0.1.1.dist-info/METADATA +0 -40
- clonebox-0.1.1.dist-info/RECORD +0 -9
- {clonebox-0.1.1.dist-info → clonebox-0.1.2.dist-info}/WHEEL +0 -0
- {clonebox-0.1.1.dist-info → clonebox-0.1.2.dist-info}/entry_points.txt +0 -0
- {clonebox-0.1.1.dist-info → clonebox-0.1.2.dist-info}/licenses/LICENSE +0 -0
- {clonebox-0.1.1.dist-info → clonebox-0.1.2.dist-info}/top_level.txt +0 -0
clonebox/cloner.py
CHANGED
|
@@ -31,6 +31,7 @@ class VMConfig:
|
|
|
31
31
|
paths: dict = field(default_factory=dict)
|
|
32
32
|
packages: list = field(default_factory=list)
|
|
33
33
|
services: list = field(default_factory=list)
|
|
34
|
+
user_session: bool = False # Use qemu:///session instead of qemu:///system
|
|
34
35
|
|
|
35
36
|
def to_dict(self) -> dict:
|
|
36
37
|
return {
|
|
@@ -46,8 +47,16 @@ class SelectiveVMCloner:
|
|
|
46
47
|
Uses bind mounts instead of full disk cloning.
|
|
47
48
|
"""
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
# Default images directories
|
|
51
|
+
SYSTEM_IMAGES_DIR = Path("/var/lib/libvirt/images")
|
|
52
|
+
USER_IMAGES_DIR = Path.home() / ".local/share/libvirt/images"
|
|
53
|
+
|
|
54
|
+
def __init__(self, conn_uri: str = None, user_session: bool = False):
|
|
55
|
+
self.user_session = user_session
|
|
56
|
+
if conn_uri:
|
|
57
|
+
self.conn_uri = conn_uri
|
|
58
|
+
else:
|
|
59
|
+
self.conn_uri = "qemu:///session" if user_session else "qemu:///system"
|
|
51
60
|
self.conn = None
|
|
52
61
|
self._connect()
|
|
53
62
|
|
|
@@ -59,17 +68,40 @@ class SelectiveVMCloner:
|
|
|
59
68
|
"Also ensure libvirt is installed: sudo apt install libvirt-daemon-system"
|
|
60
69
|
)
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
try:
|
|
72
|
+
self.conn = libvirt.open(self.conn_uri)
|
|
73
|
+
except libvirt.libvirtError as e:
|
|
74
|
+
raise ConnectionError(
|
|
75
|
+
f"Cannot connect to {self.conn_uri}\n"
|
|
76
|
+
f"Error: {e}\n\n"
|
|
77
|
+
f"Troubleshooting:\n"
|
|
78
|
+
f" 1. Check if libvirtd is running: sudo systemctl status libvirtd\n"
|
|
79
|
+
f" 2. Start libvirtd: sudo systemctl start libvirtd\n"
|
|
80
|
+
f" 3. Add user to libvirt group: sudo usermod -aG libvirt $USER\n"
|
|
81
|
+
f" 4. Re-login or run: newgrp libvirt\n"
|
|
82
|
+
f" 5. For user session (no sudo): use --user flag"
|
|
83
|
+
)
|
|
84
|
+
|
|
63
85
|
if self.conn is None:
|
|
64
86
|
raise ConnectionError(f"Cannot connect to {self.conn_uri}")
|
|
65
87
|
|
|
88
|
+
def get_images_dir(self) -> Path:
|
|
89
|
+
"""Get the appropriate images directory based on session type."""
|
|
90
|
+
if self.user_session:
|
|
91
|
+
return self.USER_IMAGES_DIR
|
|
92
|
+
return self.SYSTEM_IMAGES_DIR
|
|
93
|
+
|
|
66
94
|
def check_prerequisites(self) -> dict:
|
|
67
95
|
"""Check system prerequisites for VM creation."""
|
|
96
|
+
images_dir = self.get_images_dir()
|
|
97
|
+
|
|
68
98
|
checks = {
|
|
69
99
|
"libvirt_connected": False,
|
|
70
100
|
"kvm_available": False,
|
|
71
101
|
"default_network": False,
|
|
72
102
|
"images_dir_writable": False,
|
|
103
|
+
"images_dir": str(images_dir),
|
|
104
|
+
"session_type": "user" if self.user_session else "system",
|
|
73
105
|
}
|
|
74
106
|
|
|
75
107
|
# Check libvirt connection
|
|
@@ -77,18 +109,45 @@ class SelectiveVMCloner:
|
|
|
77
109
|
checks["libvirt_connected"] = True
|
|
78
110
|
|
|
79
111
|
# Check KVM
|
|
80
|
-
|
|
112
|
+
kvm_path = Path("/dev/kvm")
|
|
113
|
+
checks["kvm_available"] = kvm_path.exists()
|
|
114
|
+
if not checks["kvm_available"]:
|
|
115
|
+
checks["kvm_error"] = "KVM not available. Enable virtualization in BIOS."
|
|
116
|
+
elif not os.access(kvm_path, os.R_OK | os.W_OK):
|
|
117
|
+
checks["kvm_error"] = f"No access to /dev/kvm. Add user to kvm group: sudo usermod -aG kvm $USER"
|
|
81
118
|
|
|
82
119
|
# Check default network
|
|
83
120
|
try:
|
|
84
121
|
net = self.conn.networkLookupByName("default")
|
|
85
122
|
checks["default_network"] = net.isActive() == 1
|
|
86
123
|
except libvirt.libvirtError:
|
|
87
|
-
|
|
124
|
+
checks["network_error"] = (
|
|
125
|
+
"Default network not found or inactive.\n"
|
|
126
|
+
" Start it with: sudo virsh net-start default\n"
|
|
127
|
+
" Or create it: sudo virsh net-define /usr/share/libvirt/networks/default.xml"
|
|
128
|
+
)
|
|
88
129
|
|
|
89
130
|
# Check images directory
|
|
90
|
-
images_dir
|
|
91
|
-
|
|
131
|
+
if images_dir.exists():
|
|
132
|
+
checks["images_dir_writable"] = os.access(images_dir, os.W_OK)
|
|
133
|
+
if not checks["images_dir_writable"]:
|
|
134
|
+
checks["images_dir_error"] = (
|
|
135
|
+
f"Cannot write to {images_dir}\n"
|
|
136
|
+
f" Option 1: Run with sudo\n"
|
|
137
|
+
f" Option 2: Use --user flag for user session (no root needed)\n"
|
|
138
|
+
f" Option 3: Fix permissions: sudo chown -R $USER:libvirt {images_dir}"
|
|
139
|
+
)
|
|
140
|
+
else:
|
|
141
|
+
# Try to create it
|
|
142
|
+
try:
|
|
143
|
+
images_dir.mkdir(parents=True, exist_ok=True)
|
|
144
|
+
checks["images_dir_writable"] = True
|
|
145
|
+
except PermissionError:
|
|
146
|
+
checks["images_dir_writable"] = False
|
|
147
|
+
checks["images_dir_error"] = (
|
|
148
|
+
f"Cannot create {images_dir}\n"
|
|
149
|
+
f" Use --user flag for user session (stores in ~/.local/share/libvirt/images/)"
|
|
150
|
+
)
|
|
92
151
|
|
|
93
152
|
return checks
|
|
94
153
|
|
|
@@ -109,8 +168,25 @@ class SelectiveVMCloner:
|
|
|
109
168
|
else:
|
|
110
169
|
print(msg)
|
|
111
170
|
|
|
112
|
-
|
|
113
|
-
|
|
171
|
+
# Determine images directory
|
|
172
|
+
images_dir = self.get_images_dir()
|
|
173
|
+
vm_dir = images_dir / config.name
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
vm_dir.mkdir(parents=True, exist_ok=True)
|
|
177
|
+
except PermissionError as e:
|
|
178
|
+
raise PermissionError(
|
|
179
|
+
f"Cannot create VM directory: {vm_dir}\n\n"
|
|
180
|
+
f"🔧 Solutions:\n"
|
|
181
|
+
f" 1. Use --user flag to run in user session (recommended):\n"
|
|
182
|
+
f" clonebox clone . --user\n\n"
|
|
183
|
+
f" 2. Run with sudo (not recommended):\n"
|
|
184
|
+
f" sudo clonebox clone .\n\n"
|
|
185
|
+
f" 3. Fix directory permissions:\n"
|
|
186
|
+
f" sudo mkdir -p {images_dir}\n"
|
|
187
|
+
f" sudo chown -R $USER:libvirt {images_dir}\n\n"
|
|
188
|
+
f"Original error: {e}"
|
|
189
|
+
) from e
|
|
114
190
|
|
|
115
191
|
# Create root disk
|
|
116
192
|
root_disk = vm_dir / "root.qcow2"
|
clonebox/detector.py
CHANGED
|
@@ -276,6 +276,8 @@ class SystemDetector:
|
|
|
276
276
|
def _get_dir_size(self, path: Path, max_depth: int = 2) -> int:
|
|
277
277
|
"""Get approximate directory size in bytes."""
|
|
278
278
|
total = 0
|
|
279
|
+
if not path.exists():
|
|
280
|
+
return 0
|
|
279
281
|
try:
|
|
280
282
|
for item in path.iterdir():
|
|
281
283
|
if item.is_file():
|
|
@@ -285,7 +287,7 @@ class SystemDetector:
|
|
|
285
287
|
pass
|
|
286
288
|
elif item.is_dir() and max_depth > 0 and not item.is_symlink():
|
|
287
289
|
total += self._get_dir_size(item, max_depth - 1)
|
|
288
|
-
except PermissionError:
|
|
290
|
+
except (PermissionError, FileNotFoundError, OSError):
|
|
289
291
|
pass
|
|
290
292
|
return total
|
|
291
293
|
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clonebox
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Clone your workstation environment to an isolated VM with selective apps, paths and services
|
|
5
|
+
Author: CloneBox Team
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/wronai/clonebox
|
|
8
|
+
Project-URL: Repository, https://github.com/wronai/clonebox
|
|
9
|
+
Project-URL: Issues, https://github.com/wronai/clonebox/issues
|
|
10
|
+
Keywords: vm,virtualization,libvirt,clone,workstation,qemu,kvm
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: System Administrators
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: System :: Systems Administration
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: libvirt-python>=9.0.0
|
|
29
|
+
Requires-Dist: rich>=13.0.0
|
|
30
|
+
Requires-Dist: questionary>=2.0.0
|
|
31
|
+
Requires-Dist: psutil>=5.9.0
|
|
32
|
+
Requires-Dist: pyyaml>=6.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# CloneBox 📦
|
|
41
|
+
|
|
42
|
+
```commandline
|
|
43
|
+
╔═══════════════════════════════════════════════════════╗
|
|
44
|
+
║ ____ _ ____ ║
|
|
45
|
+
║ / ___|| | ___ _ __ ___| _ \ ___ __ __ ║
|
|
46
|
+
║ | | | | / _ \ | '_ \ / _ \ |_) |/ _ \\ \/ / ║
|
|
47
|
+
║ | |___ | || (_) || | | | __/ _ <| (_) |> < ║
|
|
48
|
+
║ \____||_| \___/ |_| |_|\___|_| \_\\___//_/\_\ ║
|
|
49
|
+
║ ║
|
|
50
|
+
║ Clone your workstation to an isolated VM ║
|
|
51
|
+
╚═══════════════════════════════════════════════════════╝
|
|
52
|
+
```
|
|
53
|
+
**Clone your workstation environment to an isolated VM with selective apps, paths and services.**
|
|
54
|
+
|
|
55
|
+
CloneBox lets you create isolated virtual machines with only the applications, directories and services you need - using bind mounts instead of full disk cloning. Perfect for development, testing, or creating reproducible environments.
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- 🎯 **Selective cloning** - Choose exactly which paths, services and apps to include
|
|
60
|
+
- 🔍 **Auto-detection** - Automatically detects running services, applications, and project directories
|
|
61
|
+
- 🔗 **Bind mounts** - Share directories with the VM without copying data
|
|
62
|
+
- ☁️ **Cloud-init** - Automatic package installation and service setup
|
|
63
|
+
- 🖥️ **GUI support** - SPICE graphics with virt-viewer integration
|
|
64
|
+
- ⚡ **Fast creation** - No full disk cloning, VMs are ready in seconds
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
### Prerequisites
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Install libvirt and QEMU/KVM
|
|
72
|
+
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager virt-viewer
|
|
73
|
+
|
|
74
|
+
# Enable and start libvirtd
|
|
75
|
+
sudo systemctl enable --now libvirtd
|
|
76
|
+
|
|
77
|
+
# Add user to libvirt group
|
|
78
|
+
sudo usermod -aG libvirt $USER
|
|
79
|
+
newgrp libvirt
|
|
80
|
+
|
|
81
|
+
# Install genisoimage for cloud-init
|
|
82
|
+
sudo apt install genisoimage
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Install CloneBox
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# From source
|
|
89
|
+
git clone https://github.com/wronai/clonebox.git
|
|
90
|
+
cd clonebox
|
|
91
|
+
pip install -e .
|
|
92
|
+
|
|
93
|
+
# Or directly
|
|
94
|
+
pip install clonebox
|
|
95
|
+
```
|
|
96
|
+
lub
|
|
97
|
+
```bash
|
|
98
|
+
# Aktywuj venv
|
|
99
|
+
source .venv/bin/activate
|
|
100
|
+
|
|
101
|
+
# Interaktywny tryb (wizard)
|
|
102
|
+
clonebox
|
|
103
|
+
|
|
104
|
+
# Lub poszczególne komendy
|
|
105
|
+
clonebox detect # Pokaż wykryte usługi/apps/ścieżki
|
|
106
|
+
clonebox list # Lista VM
|
|
107
|
+
clonebox create --config ... # Utwórz VM z JSON config
|
|
108
|
+
clonebox start <name> # Uruchom VM
|
|
109
|
+
clonebox stop <name> # Zatrzymaj VM
|
|
110
|
+
clonebox delete <name> # Usuń VM
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Quick Start
|
|
114
|
+
|
|
115
|
+
### Interactive Mode (Recommended)
|
|
116
|
+
|
|
117
|
+
Simply run `clonebox` to start the interactive wizard:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
clonebox
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The wizard will:
|
|
124
|
+
1. Detect running services (Docker, PostgreSQL, nginx, etc.)
|
|
125
|
+
2. Detect running applications and their working directories
|
|
126
|
+
3. Detect project directories and config files
|
|
127
|
+
4. Let you select what to include in the VM
|
|
128
|
+
5. Create and optionally start the VM
|
|
129
|
+
|
|
130
|
+
### Command Line
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# Create VM with specific config
|
|
134
|
+
clonebox create --name my-dev-vm --config '{
|
|
135
|
+
"paths": {
|
|
136
|
+
"/home/user/projects": "/mnt/projects",
|
|
137
|
+
"/home/user/.config": "/mnt/config"
|
|
138
|
+
},
|
|
139
|
+
"packages": ["python3", "nodejs", "docker.io"],
|
|
140
|
+
"services": ["docker"]
|
|
141
|
+
}' --ram 4096 --vcpus 4 --start
|
|
142
|
+
|
|
143
|
+
# List VMs
|
|
144
|
+
clonebox list
|
|
145
|
+
|
|
146
|
+
# Start/Stop VM
|
|
147
|
+
clonebox start my-dev-vm
|
|
148
|
+
clonebox stop my-dev-vm
|
|
149
|
+
|
|
150
|
+
# Delete VM
|
|
151
|
+
clonebox delete my-dev-vm
|
|
152
|
+
|
|
153
|
+
# Detect system state (useful for scripting)
|
|
154
|
+
clonebox detect --json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Usage Examples
|
|
158
|
+
|
|
159
|
+
### Python Development Environment
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
clonebox create --name python-dev --config '{
|
|
163
|
+
"paths": {
|
|
164
|
+
"/home/user/my-python-project": "/workspace",
|
|
165
|
+
"/home/user/.pyenv": "/root/.pyenv"
|
|
166
|
+
},
|
|
167
|
+
"packages": ["python3", "python3-pip", "python3-venv", "build-essential"],
|
|
168
|
+
"services": []
|
|
169
|
+
}' --ram 2048 --start
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Docker Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
clonebox create --name docker-dev --config '{
|
|
176
|
+
"paths": {
|
|
177
|
+
"/home/user/docker-projects": "/projects",
|
|
178
|
+
"/var/run/docker.sock": "/var/run/docker.sock"
|
|
179
|
+
},
|
|
180
|
+
"packages": ["docker.io", "docker-compose"],
|
|
181
|
+
"services": ["docker"]
|
|
182
|
+
}' --ram 4096 --start
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Full Stack (Node.js + PostgreSQL)
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
clonebox create --name fullstack --config '{
|
|
189
|
+
"paths": {
|
|
190
|
+
"/home/user/my-app": "/app",
|
|
191
|
+
"/home/user/pgdata": "/var/lib/postgresql/data"
|
|
192
|
+
},
|
|
193
|
+
"packages": ["nodejs", "npm", "postgresql"],
|
|
194
|
+
"services": ["postgresql"]
|
|
195
|
+
}' --ram 4096 --vcpus 4 --start
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Inside the VM
|
|
199
|
+
|
|
200
|
+
After the VM boots, mount shared directories:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Mount shared paths (9p filesystem)
|
|
204
|
+
sudo mkdir -p /mnt/projects
|
|
205
|
+
sudo mount -t 9p -o trans=virtio,version=9p2000.L mount0 /mnt/projects
|
|
206
|
+
|
|
207
|
+
# Or add to /etc/fstab for permanent mount
|
|
208
|
+
echo "mount0 /mnt/projects 9p trans=virtio,version=9p2000.L 0 0" | sudo tee -a /etc/fstab
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Architecture
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
┌────────────────────────────────────────────────────────┐
|
|
215
|
+
│ HOST SYSTEM │
|
|
216
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
217
|
+
│ │ /home/user/ │ │ /var/www/ │ │ Docker │ │
|
|
218
|
+
│ │ projects/ │ │ html/ │ │ Socket │ │
|
|
219
|
+
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
220
|
+
│ │ │ │ │
|
|
221
|
+
│ │ 9p/virtio │ │ │
|
|
222
|
+
│ │ bind mounts │ │ │
|
|
223
|
+
│ ┌──────▼─────────────────▼─────────────────▼───────┐ │
|
|
224
|
+
│ │ CloneBox VM │ │
|
|
225
|
+
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
|
|
226
|
+
│ │ │ /mnt/proj │ │ /mnt/www │ │ /var/run/ │ │ │
|
|
227
|
+
│ │ │ │ │ │ │ docker.sock│ │ │
|
|
228
|
+
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
|
|
229
|
+
│ │ │ │
|
|
230
|
+
│ │ cloud-init installed packages & services │ │
|
|
231
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
232
|
+
└────────────────────────────────────────────────────────┘
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Quick Clone (Recommended)
|
|
236
|
+
|
|
237
|
+
The fastest way to clone your current working directory:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Clone current directory - generates .clonebox.yaml and asks to create VM
|
|
241
|
+
clonebox clone .
|
|
242
|
+
|
|
243
|
+
# Clone specific path
|
|
244
|
+
clonebox clone ~/projects/my-app
|
|
245
|
+
|
|
246
|
+
# Clone with custom name and auto-start
|
|
247
|
+
clonebox clone ~/projects/my-app --name my-dev-vm --run
|
|
248
|
+
|
|
249
|
+
# Clone and edit config before creating
|
|
250
|
+
clonebox clone . --edit
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Later, start the VM from any directory with `.clonebox.yaml`:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Start VM from config in current directory
|
|
257
|
+
clonebox start .
|
|
258
|
+
|
|
259
|
+
# Start VM from specific path
|
|
260
|
+
clonebox start ~/projects/my-app
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Export YAML Config
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Export detected state as YAML (with deduplication)
|
|
267
|
+
clonebox detect --yaml --dedupe
|
|
268
|
+
|
|
269
|
+
# Save to file
|
|
270
|
+
clonebox detect --yaml --dedupe -o my-config.yaml
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Commands Reference
|
|
274
|
+
|
|
275
|
+
| Command | Description |
|
|
276
|
+
|---------|-------------|
|
|
277
|
+
| `clonebox` | Interactive VM creation wizard |
|
|
278
|
+
| `clonebox clone <path>` | Generate `.clonebox.yaml` from path + running processes |
|
|
279
|
+
| `clonebox clone . --run` | Clone and immediately start VM |
|
|
280
|
+
| `clonebox clone . --edit` | Clone, edit config, then create |
|
|
281
|
+
| `clonebox start .` | Start VM from `.clonebox.yaml` in current dir |
|
|
282
|
+
| `clonebox start <name>` | Start existing VM by name |
|
|
283
|
+
| `clonebox stop <name>` | Stop a VM (graceful shutdown) |
|
|
284
|
+
| `clonebox stop -f <name>` | Force stop a VM |
|
|
285
|
+
| `clonebox delete <name>` | Delete VM and storage |
|
|
286
|
+
| `clonebox list` | List all VMs |
|
|
287
|
+
| `clonebox detect` | Show detected services/apps/paths |
|
|
288
|
+
| `clonebox detect --yaml` | Output as YAML config |
|
|
289
|
+
| `clonebox detect --yaml --dedupe` | YAML with duplicates removed |
|
|
290
|
+
| `clonebox detect --json` | Output as JSON |
|
|
291
|
+
|
|
292
|
+
## Requirements
|
|
293
|
+
|
|
294
|
+
- Linux with KVM support (`/dev/kvm`)
|
|
295
|
+
- libvirt daemon running
|
|
296
|
+
- Python 3.8+
|
|
297
|
+
- User in `libvirt` group
|
|
298
|
+
|
|
299
|
+
## License
|
|
300
|
+
|
|
301
|
+
MIT License - see [LICENSE](LICENSE) file.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
clonebox/__init__.py,sha256=IOk7G0DiSQ33EGbFC0xbnnFB9aou_6yuyFxvycQEvA0,407
|
|
2
|
+
clonebox/cli.py,sha256=Zk9D99G2Zcaeb0Pw3eNhv0EtLYKPcpE0GyB3QtuhvgQ,31625
|
|
3
|
+
clonebox/cloner.py,sha256=qfMpx7tS5Eozvhi2ZzBc5GY6HLYotncuMakeknHnTwo,18099
|
|
4
|
+
clonebox/detector.py,sha256=Umg4CRJU61yV3a1AvR_0tOfjBMCCIbiQdDAAhlrOL5k,11916
|
|
5
|
+
clonebox-0.1.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
6
|
+
clonebox-0.1.2.dist-info/METADATA,sha256=YtSqXudDO6TrPtAZzbP5fbMvf-PHarUpkY55ZGpHplw,10374
|
|
7
|
+
clonebox-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
clonebox-0.1.2.dist-info/entry_points.txt,sha256=FES95Vi3btfViLEEoHdb8nikNxTqzaooi9ehZw9ZfWI,47
|
|
9
|
+
clonebox-0.1.2.dist-info/top_level.txt,sha256=LdMo2cvCrEcRGH2M8JgQNVsCoszLV0xug6kx1JnaRjo,9
|
|
10
|
+
clonebox-0.1.2.dist-info/RECORD,,
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: clonebox
|
|
3
|
-
Version: 0.1.1
|
|
4
|
-
Summary: Clone your workstation environment to an isolated VM with selective apps, paths and services
|
|
5
|
-
Author: CloneBox Team
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/wronai/clonebox
|
|
8
|
-
Project-URL: Repository, https://github.com/wronai/clonebox
|
|
9
|
-
Project-URL: Issues, https://github.com/wronai/clonebox/issues
|
|
10
|
-
Keywords: vm,virtualization,libvirt,clone,workstation,qemu,kvm
|
|
11
|
-
Classifier: Development Status :: 4 - Beta
|
|
12
|
-
Classifier: Environment :: Console
|
|
13
|
-
Classifier: Intended Audience :: Developers
|
|
14
|
-
Classifier: Intended Audience :: System Administrators
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
-
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
-
Classifier: Topic :: System :: Systems Administration
|
|
24
|
-
Classifier: Topic :: Utilities
|
|
25
|
-
Requires-Python: >=3.8
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
License-File: LICENSE
|
|
28
|
-
Requires-Dist: libvirt-python>=9.0.0
|
|
29
|
-
Requires-Dist: rich>=13.0.0
|
|
30
|
-
Requires-Dist: questionary>=2.0.0
|
|
31
|
-
Requires-Dist: psutil>=5.9.0
|
|
32
|
-
Requires-Dist: pyyaml>=6.0
|
|
33
|
-
Provides-Extra: dev
|
|
34
|
-
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
35
|
-
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
36
|
-
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
37
|
-
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
38
|
-
Dynamic: license-file
|
|
39
|
-
|
|
40
|
-
# clonebox
|
clonebox-0.1.1.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
clonebox/__init__.py,sha256=IOk7G0DiSQ33EGbFC0xbnnFB9aou_6yuyFxvycQEvA0,407
|
|
2
|
-
clonebox/cloner.py,sha256=SamhrCJoJ-k_u4b-yvpNCmr_IHpSrVjlo826lq4fD2M,14523
|
|
3
|
-
clonebox/detector.py,sha256=dwtMg2FybGR79c3xce5PXNfrQgMpH4HK-nEsNfucPms,11835
|
|
4
|
-
clonebox-0.1.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
5
|
-
clonebox-0.1.1.dist-info/METADATA,sha256=NQWcmpWvadnOr-UC3Ge3yYMD5vo7ClIcYUFiAXagxuA,1570
|
|
6
|
-
clonebox-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
7
|
-
clonebox-0.1.1.dist-info/entry_points.txt,sha256=FES95Vi3btfViLEEoHdb8nikNxTqzaooi9ehZw9ZfWI,47
|
|
8
|
-
clonebox-0.1.1.dist-info/top_level.txt,sha256=LdMo2cvCrEcRGH2M8JgQNVsCoszLV0xug6kx1JnaRjo,9
|
|
9
|
-
clonebox-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|