machine: detect virtualized envronment
It isn't valid to run some commands from within containers. Use systmd-detect-virt to detect a virtualized environment and report the type and id via the system_info endpoint. If Moonraker is running from within a container do not allow access to the reboot and shutdown endpoints. Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
7890753d9f
commit
f35bceb309
|
@ -43,6 +43,8 @@ class Machine:
|
||||||
dist_info: Dict[str, Any]
|
dist_info: Dict[str, Any]
|
||||||
dist_info = {'name': distro.name(pretty=True)}
|
dist_info = {'name': distro.name(pretty=True)}
|
||||||
dist_info.update(distro.info())
|
dist_info.update(distro.info())
|
||||||
|
self.virt_type = "none"
|
||||||
|
self.virt_id = "none"
|
||||||
self.system_info: Dict[str, Any] = {
|
self.system_info: Dict[str, Any] = {
|
||||||
'cpu_info': self._get_cpu_info(),
|
'cpu_info': self._get_cpu_info(),
|
||||||
'sd_info': self._get_sdcard_info(),
|
'sd_info': self._get_sdcard_info(),
|
||||||
|
@ -52,8 +54,11 @@ class Machine:
|
||||||
sys_info_msg = "\nSystem Info:"
|
sys_info_msg = "\nSystem Info:"
|
||||||
for header, info in self.system_info.items():
|
for header, info in self.system_info.items():
|
||||||
sys_info_msg += f"\n\n***{header}***"
|
sys_info_msg += f"\n\n***{header}***"
|
||||||
for key, val in info.items():
|
if not isinstance(info, dict):
|
||||||
sys_info_msg += f"\n {key}: {val}"
|
sys_info_msg += f"\n {repr(info)}"
|
||||||
|
else:
|
||||||
|
for key, val in info.items():
|
||||||
|
sys_info_msg += f"\n {key}: {val}"
|
||||||
self.server.add_log_rollover_item('system_info', sys_info_msg)
|
self.server.add_log_rollover_item('system_info', sys_info_msg)
|
||||||
self.available_services: Dict[str, Dict[str, str]] = {}
|
self.available_services: Dict[str, Dict[str, str]] = {}
|
||||||
|
|
||||||
|
@ -85,7 +90,7 @@ class Machine:
|
||||||
# Retreive list of services
|
# Retreive list of services
|
||||||
event_loop = self.server.get_event_loop()
|
event_loop = self.server.get_event_loop()
|
||||||
self.init_evt = asyncio.Event()
|
self.init_evt = asyncio.Event()
|
||||||
event_loop.register_callback(self._find_active_services)
|
event_loop.register_callback(self._initialize)
|
||||||
|
|
||||||
async def wait_for_init(self, timeout: float = None) -> None:
|
async def wait_for_init(self, timeout: float = None) -> None:
|
||||||
try:
|
try:
|
||||||
|
@ -93,8 +98,16 @@ class Machine:
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
async def _initialize(self):
|
||||||
|
await self._check_virt_status()
|
||||||
|
await self._find_active_services()
|
||||||
|
|
||||||
async def _handle_machine_request(self, web_request: WebRequest) -> str:
|
async def _handle_machine_request(self, web_request: WebRequest) -> str:
|
||||||
ep = web_request.get_endpoint()
|
ep = web_request.get_endpoint()
|
||||||
|
if self.virt_type == "container":
|
||||||
|
raise self.server.error(
|
||||||
|
f"Cannot {ep.split('/')[-1]} from within a "
|
||||||
|
f"{self.virt_id} container")
|
||||||
if ep == "/machine/shutdown":
|
if ep == "/machine/shutdown":
|
||||||
await self.shutdown_machine()
|
await self.shutdown_machine()
|
||||||
elif ep == "/machine/reboot":
|
elif ep == "/machine/reboot":
|
||||||
|
@ -281,6 +294,46 @@ class Machine:
|
||||||
await self.update_service_status(notify=False)
|
await self.update_service_status(notify=False)
|
||||||
self.init_evt.set()
|
self.init_evt.set()
|
||||||
|
|
||||||
|
async def _check_virt_status(self) -> None:
|
||||||
|
self.virt_id = self.virt_type = "none"
|
||||||
|
|
||||||
|
shell_cmd: SCMDComp = self.server.lookup_component('shell_command')
|
||||||
|
|
||||||
|
# Check for any form of virtualization. This will report the innermost
|
||||||
|
# virtualization type in the event that nested virtualization is used
|
||||||
|
scmd = shell_cmd.build_shell_command("systemd-detect-virt")
|
||||||
|
try:
|
||||||
|
resp = await scmd.run_with_response()
|
||||||
|
except shell_cmd.error:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.virt_id = resp.strip()
|
||||||
|
|
||||||
|
if self.virt_id != "none":
|
||||||
|
# Check explicitly for container virtualization
|
||||||
|
scmd = shell_cmd.build_shell_command(
|
||||||
|
"systemd-detect-virt --container")
|
||||||
|
try:
|
||||||
|
resp = await scmd.run_with_response()
|
||||||
|
except shell_cmd.error:
|
||||||
|
self.virt_type = "vm"
|
||||||
|
else:
|
||||||
|
if self.virt_id == resp.strip():
|
||||||
|
self.virt_type = "container"
|
||||||
|
else:
|
||||||
|
# Moonraker is run from within a VM inside a container
|
||||||
|
self.virt_type = "vm"
|
||||||
|
logging.info(
|
||||||
|
f"Virtualized Environment Detected, Type: {self.virt_type} "
|
||||||
|
f"id: {self.virt_id}")
|
||||||
|
else:
|
||||||
|
logging.info("No Virtualization Detected")
|
||||||
|
|
||||||
|
self.system_info['virtualization'] = {
|
||||||
|
'virt_type': self.virt_type,
|
||||||
|
'virt_identifier': self.virt_id
|
||||||
|
}
|
||||||
|
|
||||||
async def update_service_status(self, notify: bool = True) -> None:
|
async def update_service_status(self, notify: bool = True) -> None:
|
||||||
shell_cmd: SCMDComp = self.server.lookup_component('shell_command')
|
shell_cmd: SCMDComp = self.server.lookup_component('shell_command')
|
||||||
for svc, state in list(self.available_services.items()):
|
for svc, state in list(self.available_services.items()):
|
||||||
|
|
Loading…
Reference in New Issue