maqet 0.0.1.4__py3-none-any.whl → 0.0.5__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.
- maqet/__init__.py +50 -6
- maqet/__main__.py +96 -0
- maqet/__version__.py +3 -0
- maqet/api/__init__.py +35 -0
- maqet/api/decorators.py +184 -0
- maqet/api/metadata.py +147 -0
- maqet/api/registry.py +182 -0
- maqet/cli.py +71 -0
- maqet/config/__init__.py +26 -0
- maqet/config/merger.py +237 -0
- maqet/config/parser.py +198 -0
- maqet/config/validators.py +519 -0
- maqet/config_handlers.py +684 -0
- maqet/constants.py +200 -0
- maqet/exceptions.py +226 -0
- maqet/formatters.py +294 -0
- maqet/generators/__init__.py +12 -0
- maqet/generators/base_generator.py +101 -0
- maqet/generators/cli_generator.py +635 -0
- maqet/generators/python_generator.py +247 -0
- maqet/generators/rest_generator.py +58 -0
- maqet/handlers/__init__.py +12 -0
- maqet/handlers/base.py +108 -0
- maqet/handlers/init.py +147 -0
- maqet/handlers/stage.py +196 -0
- maqet/ipc/__init__.py +29 -0
- maqet/ipc/retry.py +265 -0
- maqet/ipc/runner_client.py +285 -0
- maqet/ipc/unix_socket_server.py +239 -0
- maqet/logger.py +160 -55
- maqet/machine.py +884 -0
- maqet/managers/__init__.py +7 -0
- maqet/managers/qmp_manager.py +333 -0
- maqet/managers/snapshot_coordinator.py +327 -0
- maqet/managers/vm_manager.py +683 -0
- maqet/maqet.py +1120 -0
- maqet/os_interactions.py +46 -0
- maqet/process_spawner.py +395 -0
- maqet/qemu_args.py +76 -0
- maqet/qmp/__init__.py +10 -0
- maqet/qmp/commands.py +92 -0
- maqet/qmp/keyboard.py +311 -0
- maqet/qmp/qmp.py +17 -0
- maqet/snapshot.py +473 -0
- maqet/state.py +958 -0
- maqet/storage.py +702 -162
- maqet/validation/__init__.py +9 -0
- maqet/validation/config_validator.py +170 -0
- maqet/vm_runner.py +523 -0
- maqet-0.0.5.dist-info/METADATA +237 -0
- maqet-0.0.5.dist-info/RECORD +55 -0
- {maqet-0.0.1.4.dist-info → maqet-0.0.5.dist-info}/WHEEL +1 -1
- maqet-0.0.5.dist-info/entry_points.txt +2 -0
- maqet-0.0.5.dist-info/licenses/LICENSE +21 -0
- {maqet-0.0.1.4.dist-info → maqet-0.0.5.dist-info}/top_level.txt +0 -1
- maqet/core.py +0 -411
- maqet/functions.py +0 -104
- maqet-0.0.1.4.dist-info/METADATA +0 -6
- maqet-0.0.1.4.dist-info/RECORD +0 -33
- qemu/machine/__init__.py +0 -36
- qemu/machine/console_socket.py +0 -142
- qemu/machine/machine.py +0 -954
- qemu/machine/py.typed +0 -0
- qemu/machine/qtest.py +0 -191
- qemu/qmp/__init__.py +0 -59
- qemu/qmp/error.py +0 -50
- qemu/qmp/events.py +0 -717
- qemu/qmp/legacy.py +0 -319
- qemu/qmp/message.py +0 -209
- qemu/qmp/models.py +0 -146
- qemu/qmp/protocol.py +0 -1057
- qemu/qmp/py.typed +0 -0
- qemu/qmp/qmp_client.py +0 -655
- qemu/qmp/qmp_shell.py +0 -618
- qemu/qmp/qmp_tui.py +0 -655
- qemu/qmp/util.py +0 -219
- qemu/utils/__init__.py +0 -162
- qemu/utils/accel.py +0 -84
- qemu/utils/py.typed +0 -0
- qemu/utils/qemu_ga_client.py +0 -323
- qemu/utils/qom.py +0 -273
- qemu/utils/qom_common.py +0 -175
- qemu/utils/qom_fuse.py +0 -207
maqet/config/parser.py
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
"""
|
2
|
+
Configuration Parser
|
3
|
+
|
4
|
+
Parses YAML configuration files for VM settings only.
|
5
|
+
Does NOT execute API commands - configs are purely for VM configuration.
|
6
|
+
Supports multiple config file deep-merging for flexible VM configuration.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import stat
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import TYPE_CHECKING, Any, Dict
|
13
|
+
|
14
|
+
if TYPE_CHECKING:
|
15
|
+
from ..maqet import Maqet
|
16
|
+
|
17
|
+
from .merger import ConfigError
|
18
|
+
|
19
|
+
|
20
|
+
class ConfigParser:
|
21
|
+
"""
|
22
|
+
Parses and validates VM configuration files.
|
23
|
+
|
24
|
+
This parser handles YAML configuration files for VM settings ONLY.
|
25
|
+
It does NOT execute API commands - those should be handled separately
|
26
|
+
by calling methods on the Maqet instance.
|
27
|
+
|
28
|
+
The parser validates configuration structure and types but does not
|
29
|
+
start VMs or execute commands.
|
30
|
+
|
31
|
+
NOTE: Configuration parsing flow:
|
32
|
+
1. ConfigParser.parse_config() - Loads and validates YAML
|
33
|
+
2. Machine._configure_machine() - Converts config to QEMU args
|
34
|
+
3. ConfigHandlers (config_handlers.py) - Handler-based config processing
|
35
|
+
4. StorageManager.get_qemu_args() - Storage-specific QEMU args
|
36
|
+
|
37
|
+
The old qemu_args.py approach has been replaced with the extensible
|
38
|
+
handler-based system for better maintainability and test coverage.
|
39
|
+
"""
|
40
|
+
|
41
|
+
def __init__(self, maqet_instance: "Maqet"):
|
42
|
+
"""
|
43
|
+
Initialize config parser.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
maqet_instance: Maqet instance for validation context
|
47
|
+
"""
|
48
|
+
self.maqet = maqet_instance
|
49
|
+
|
50
|
+
def parse_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
51
|
+
"""
|
52
|
+
Parse configuration dictionary.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
config_data: Configuration dictionary
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
Normalized configuration data
|
59
|
+
"""
|
60
|
+
if not isinstance(config_data, dict):
|
61
|
+
raise ConfigError("Configuration must be a dictionary")
|
62
|
+
|
63
|
+
return config_data
|
64
|
+
|
65
|
+
def validate_config(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
|
66
|
+
"""
|
67
|
+
Validate VM configuration data.
|
68
|
+
|
69
|
+
This method validates VM configuration settings without executing
|
70
|
+
any API commands. Configuration files are purely for VM settings.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
config_data: Configuration dictionary
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
Validated configuration data
|
77
|
+
|
78
|
+
Example:
|
79
|
+
config = {
|
80
|
+
'binary': '/usr/bin/qemu-system-x86_64',
|
81
|
+
'memory': '4G',
|
82
|
+
'cpu': 2,
|
83
|
+
'storage': [
|
84
|
+
{'name': 'hdd', 'size': '20G', 'type': 'qcow2'}
|
85
|
+
]
|
86
|
+
}
|
87
|
+
validated = parser.validate_config(config)
|
88
|
+
"""
|
89
|
+
|
90
|
+
# Use dynamic validation system with decorators
|
91
|
+
from .validators import ConfigValidationError, validate_config_data
|
92
|
+
|
93
|
+
# File integrity validation implemented in _validate_config_file_security():
|
94
|
+
# - Size limit check (10MB) prevents DoS with huge YAML
|
95
|
+
# - World-writable permission warning for security
|
96
|
+
# - File ownership validation (warns if not owned by current user)
|
97
|
+
# - yaml.safe_load used in merger.py prevents code execution
|
98
|
+
# NOTE: Checksum/signature validation not implemented (would require key management)
|
99
|
+
try:
|
100
|
+
# Unknown keys are silently ignored - no validation needed
|
101
|
+
# This allows forward compatibility and flexibility in config files
|
102
|
+
|
103
|
+
# Early storage validation to fail fast before VM creation
|
104
|
+
if "storage" in config_data:
|
105
|
+
from ..storage import validate_storage_config
|
106
|
+
|
107
|
+
try:
|
108
|
+
validate_storage_config(config_data["storage"])
|
109
|
+
except ValueError as e:
|
110
|
+
raise ConfigError(f"Storage configuration error: {e}")
|
111
|
+
|
112
|
+
# Use dynamic validator system
|
113
|
+
return validate_config_data(config_data)
|
114
|
+
|
115
|
+
except ConfigValidationError as e:
|
116
|
+
raise ConfigError(str(e))
|
117
|
+
|
118
|
+
def _validate_config_file_security(self, config_path: str) -> None:
|
119
|
+
"""
|
120
|
+
Validate configuration file security before loading.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
config_path: Path to YAML configuration file
|
124
|
+
|
125
|
+
Raises:
|
126
|
+
ConfigError: If file has security issues
|
127
|
+
"""
|
128
|
+
|
129
|
+
# Using pathlib for modern path handling
|
130
|
+
# TODO(m4x0n, 2025-10-10): Standardize all path operations to use
|
131
|
+
# pathlib throughout codebase. See CODE_ISSUES_REPORT.md #4.
|
132
|
+
path = Path(config_path)
|
133
|
+
|
134
|
+
# Check if file exists first
|
135
|
+
if not path.exists():
|
136
|
+
# Let load_and_merge_files handle the FileNotFoundError
|
137
|
+
return
|
138
|
+
|
139
|
+
# Check file size to prevent DoS with huge YAML files
|
140
|
+
max_size = 10 * 1024 * 1024 # 10MB limit
|
141
|
+
file_stat = path.stat()
|
142
|
+
file_size = file_stat.st_size
|
143
|
+
if file_size > max_size:
|
144
|
+
raise ConfigError(
|
145
|
+
f"Configuration file too large ({file_size} bytes, max {
|
146
|
+
max_size}). "
|
147
|
+
f"This may indicate a malicious or corrupted file."
|
148
|
+
)
|
149
|
+
|
150
|
+
# Check file permissions - warn if world-writable
|
151
|
+
mode = file_stat.st_mode
|
152
|
+
# FIXME(m4x0n, 2025-10-10): Missing import. Issue #1 in
|
153
|
+
# CODE_ISSUES_REPORT.md - needs `import stat` at module level.
|
154
|
+
if mode & stat.S_IWOTH:
|
155
|
+
from ..logger import LOG
|
156
|
+
|
157
|
+
LOG.warning(
|
158
|
+
f"Configuration file {config_path} is world-writable. "
|
159
|
+
f"This is a security risk as anyone can modify VM settings."
|
160
|
+
)
|
161
|
+
|
162
|
+
# Check if file is owned by current user (Unix only)
|
163
|
+
# FIXME(m4x0n, 2025-10-10): Missing import. Issue #2 in
|
164
|
+
# CODE_ISSUES_REPORT.md - needs `import os` at module level.
|
165
|
+
if hasattr(os, "getuid"):
|
166
|
+
current_uid = os.getuid()
|
167
|
+
if file_stat.st_uid != current_uid:
|
168
|
+
from ..logger import LOG
|
169
|
+
|
170
|
+
LOG.warning(
|
171
|
+
f"Configuration file {
|
172
|
+
config_path} is not owned by current user. "
|
173
|
+
f"Verify the file source before using."
|
174
|
+
)
|
175
|
+
|
176
|
+
def load_and_validate(self, config_path: str) -> Dict[str, Any]:
|
177
|
+
"""
|
178
|
+
Load configuration file and validate it.
|
179
|
+
|
180
|
+
Args:
|
181
|
+
config_path: Path to YAML configuration file
|
182
|
+
|
183
|
+
Returns:
|
184
|
+
Validated configuration data
|
185
|
+
|
186
|
+
Raises:
|
187
|
+
ConfigError: If file cannot be loaded or validation fails
|
188
|
+
"""
|
189
|
+
from .merger import ConfigMerger
|
190
|
+
|
191
|
+
# Validate file security before loading
|
192
|
+
self._validate_config_file_security(config_path)
|
193
|
+
|
194
|
+
# Load single config file (uses yaml.safe_load for security)
|
195
|
+
config_data = ConfigMerger.load_and_merge_files(config_path)
|
196
|
+
|
197
|
+
# Validate the loaded config
|
198
|
+
return self.validate_config(config_data)
|