machine: validation fixes

Protect the sudo request with a lock.  Add retries to the sudo
commands.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2022-10-15 08:37:45 -04:00
parent f0e4678fab
commit 00c4846d11
No known key found for this signature in database
GPG Key ID: 5A1EB336DFB4C71B
1 changed files with 61 additions and 50 deletions

View File

@ -86,6 +86,7 @@ class Machine:
dist_info['release_info'] = distro.distro_release_info()
self.inside_container = False
self.moonraker_service_info: Dict[str, Any] = {}
self.sudo_req_lock = asyncio.Lock()
self._sudo_password: Optional[str] = None
sudo_template = config.gettemplate("sudo_password", None)
if sudo_template is not None:
@ -282,10 +283,13 @@ class Machine:
async def _set_sudo_password(
self, web_request: WebRequest
) -> Dict[str, Any]:
async with self.sudo_req_lock:
self._sudo_password = web_request.get_str("password")
if not await self.check_sudo_access():
self._sudo_password = None
raise self.server.error("Invalid password, sudo access was denied")
raise self.server.error(
"Invalid password, sudo access was denied"
)
sudo_responses = ["Sudo password successfully set."]
restart: bool = False
failed: List[Tuple[SudoCallback, str]] = []
@ -391,7 +395,7 @@ class Machine:
return False
return True
async def exec_sudo_command(self, command: str) -> str:
async def exec_sudo_command(self, command: str, tries: int = 1) -> str:
proc_input = None
full_cmd = f"sudo {command}"
if self._sudo_password is not None:
@ -399,7 +403,7 @@ class Machine:
full_cmd = f"sudo -S {command}"
shell_cmd: SCMDComp = self.server.lookup_component("shell_command")
return await shell_cmd.exec_cmd(
full_cmd, proc_input=proc_input, log_complete=False
full_cmd, proc_input=proc_input, log_complete=False, retries=tries
)
def _get_sdcard_info(self) -> Dict[str, Any]:
@ -861,7 +865,7 @@ class SystemdCliProvider(BaseProvider):
)
prop_args = ",".join(properties)
props: str = await self.shell_cmd.exec_cmd(
f"systemctl show -p {prop_args} {unit_name}"
f"systemctl show -p {prop_args} {unit_name}", retries=5
)
raw_props: Dict[str, Any] = {}
lines = [p.strip() for p in props.split("\n") if p.strip]
@ -1276,6 +1280,7 @@ class InstallValidator:
"must be updated manually."
)
if unit != "moonraker":
logging.info(f"Custom service file detected: {unit}")
# Not using he default unit name
if app_args["is_default_data_path"]:
# No datapath set, create a new, unique data path
@ -1290,11 +1295,13 @@ class InstallValidator:
f"data path '{new_dp}' already exists. Service file "
"must be updated manually."
)
# If the current path is bare we can remove it
if self._check_path_bare(self.data_path):
shutil.rmtree(self.data_path)
self.data_path = new_dp
if not self.data_path.exists():
logging.info(f"New data path created at {self.data_path}")
self.data_path.mkdir()
# A non-default datapath requires successful update of the
# service
@ -1362,8 +1369,13 @@ class InstallValidator:
% (SERVICE_VERSION, user, src_path, env_file, sys.executable)
)
try:
await machine.exec_sudo_command(f"cp -f {tmp_svc} {svc_dest}")
await machine.exec_sudo_command("systemctl daemon-reload")
# write new environment
env_file.write_text(ENVIRONMENT % (src_path, cmd_args))
await machine.exec_sudo_command(
f"cp -f {tmp_svc} {svc_dest}", tries=5)
await machine.exec_sudo_command(
"systemctl daemon-reload", tries=5
)
except asyncio.CancelledError:
raise
except Exception:
@ -1374,9 +1386,8 @@ class InstallValidator:
) from None
finally:
tmp_svc.unlink()
# write new environment
env_file.write_text(ENVIRONMENT % (src_path, cmd_args))
self.data_path_valid = True
self.sc_enabled = False
return True
def _check_path_bare(self, path: pathlib.Path) -> bool: