mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 10:51:36 -04:00
Delaying reboot/shutdown with asyncio sleep to give API time to shut down.
This commit is contained in:
parent
5ffb8bee8d
commit
4cc00a9cb1
9 changed files with 71 additions and 49 deletions
|
|
@ -32,6 +32,14 @@ function handleEvents(events) {
|
|||
eventToast('Refresh completed', 'Files have been refreshed.');
|
||||
}
|
||||
|
||||
if (event === 'shutdown') {
|
||||
eventToast('Shutdown', message, 'warning');
|
||||
}
|
||||
|
||||
if (event === 'shutdown_failed') {
|
||||
eventToast('Shutdown Failed', message, 'error');
|
||||
}
|
||||
|
||||
if (event === 'downloads_disabled') {
|
||||
eventToast('Downloads Disabled', message, 'info');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,13 @@ export function ShutdownButton() {
|
|||
time: 5000,
|
||||
type: "error",
|
||||
})
|
||||
} else if (response && response['code'] === 'NATIVE_ONLY') {
|
||||
toast({
|
||||
title: 'Shutdown Failed',
|
||||
description: 'Cannot shutdown while running in Docker',
|
||||
time: 5000,
|
||||
type: "error",
|
||||
})
|
||||
} else if (response !== null) {
|
||||
toast({
|
||||
title: 'Shutdown Failed',
|
||||
|
|
@ -58,13 +65,20 @@ export function RestartButton() {
|
|||
const handleRestart = async () => {
|
||||
try {
|
||||
const response = await postRestart();
|
||||
if (response && response['code'] === 'RESTART_FAILED') {
|
||||
if (response && response['code'] === 'SHUTDOWN_FAILED') {
|
||||
toast({
|
||||
title: 'Restart Failed',
|
||||
description: response['error'],
|
||||
time: 5000,
|
||||
type: "error",
|
||||
})
|
||||
} else if (response && response['code'] === 'NATIVE_ONLY') {
|
||||
toast({
|
||||
title: 'Restart Failed',
|
||||
description: 'Cannot restart while running in Docker',
|
||||
time: 5000,
|
||||
type: "error",
|
||||
})
|
||||
} else if (response !== null) {
|
||||
toast({
|
||||
title: 'Restart Failed',
|
||||
|
|
|
|||
|
|
@ -67,8 +67,7 @@ cat >/etc/sudoers.d/90-wrolpi <<'EOF'
|
|||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl stop wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl start wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/opt/wrolpi/scripts/import_map.sh
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/poweroff
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/reboot
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/shutdown
|
||||
EOF
|
||||
chmod 660 /etc/sudoers.d/90-wrolpi
|
||||
|
||||
|
|
|
|||
|
|
@ -89,8 +89,7 @@ cat >/etc/sudoers.d/90-wrolpi <<'EOF'
|
|||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl stop wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl start wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/opt/wrolpi/scripts/import_map.sh
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/poweroff
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/reboot
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/shutdown
|
||||
EOF
|
||||
chmod 660 /etc/sudoers.d/90-wrolpi
|
||||
# Verify this new file is valid.
|
||||
|
|
|
|||
|
|
@ -99,8 +99,7 @@ cat >/etc/sudoers.d/90-wrolpi <<'EOF'
|
|||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl stop wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/usr/bin/systemctl start wrolpi-app.service
|
||||
%wrolpi ALL= NOPASSWD:/opt/wrolpi/scripts/import_map.sh
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/poweroff
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/reboot
|
||||
%wrolpi ALL= NOPASSWD:/usr/sbin/shutdown
|
||||
EOF
|
||||
chmod 660 /etc/sudoers.d/90-wrolpi
|
||||
# Verify this new file is valid.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@ import enum
|
|||
import subprocess
|
||||
|
||||
from wrolpi.cmd import NMCLI_BIN, CPUFREQ_INFO_BIN, SUDO_BIN, CPUFREQ_SET_BIN
|
||||
from wrolpi.common import logger, WROLPI_CONFIG, get_warn_once
|
||||
from wrolpi.errors import RestartFailed, ShutdownFailed
|
||||
from wrolpi.common import logger, WROLPI_CONFIG, get_warn_once, background_task
|
||||
from wrolpi.errors import ShutdownFailed
|
||||
from wrolpi.events import Events
|
||||
from wrolpi.vars import DEFAULT_CPU_FREQUENCY, DOCKERIZED
|
||||
|
||||
logger = logger.getChild(__name__)
|
||||
|
|
@ -53,7 +54,7 @@ def enable_hotspot():
|
|||
logger.info(f'Hotspot status: {status}')
|
||||
|
||||
if status == HotspotStatus.connected:
|
||||
logger.info('Hotspot already connected. Restarting hotspot.')
|
||||
logger.info('Hotspot already connected. Rebooting hotspot.')
|
||||
disable_hotspot()
|
||||
return enable_hotspot()
|
||||
elif status == HotspotStatus.disconnected:
|
||||
|
|
@ -145,39 +146,39 @@ def throttle_cpu_off() -> bool:
|
|||
logger.error('Could not disable CPU throttle', exc_info=True)
|
||||
|
||||
|
||||
async def restart():
|
||||
"""Restart the WROLPi.
|
||||
async def shutdown(reboot: bool = False, delay: int = 10):
|
||||
"""Shutdown or reboot the WROLPi. Schedules an asyncio sleep to delay the shutdown.
|
||||
|
||||
@raise RestartFailed: If restart is not possible, or if sudo command failed."""
|
||||
@raise ShutdownFailed: If not possible, or if sudo command failed."""
|
||||
if DOCKERIZED:
|
||||
raise RestartFailed('Cannot restart because we are dockerized')
|
||||
raise ShutdownFailed('Cannot Reboot because we are dockerized')
|
||||
|
||||
try:
|
||||
cmd = f'{SUDO_BIN} reboot'
|
||||
proc = await asyncio.create_subprocess_shell(cmd, stderr=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
stdout, stderr = await proc.communicate()
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise RestartFailed() from e
|
||||
reboot = '--reboot' if reboot else ''
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise RestartFailed(f'Got return code {proc.returncode}')
|
||||
async def _():
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
try:
|
||||
cmd = f'{SUDO_BIN} shutdown {reboot}'
|
||||
proc = await asyncio.create_subprocess_shell(cmd, stderr=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
stdout, stderr = await proc.communicate()
|
||||
except subprocess.CalledProcessError as e:
|
||||
if reboot:
|
||||
Events.send_shutdown_failed('Reboot failed')
|
||||
else:
|
||||
Events.send_shutdown_failed('Shutdown failed')
|
||||
raise ShutdownFailed() from e
|
||||
|
||||
async def shutdown():
|
||||
"""Shutdown the WROLPi.
|
||||
if proc.returncode != 0:
|
||||
if reboot:
|
||||
Events.send_shutdown_failed('Reboot failed')
|
||||
else:
|
||||
Events.send_shutdown_failed('Shutdown failed')
|
||||
raise ShutdownFailed(f'Got return code {proc.returncode}')
|
||||
|
||||
@raise ShutdownFailed: If shutdown is not possible, or if sudo command failed."""
|
||||
if DOCKERIZED:
|
||||
raise ShutdownFailed('Cannot shutdown because we are dockerized')
|
||||
|
||||
try:
|
||||
cmd = f'{SUDO_BIN} poweroff'
|
||||
proc = await asyncio.create_subprocess_shell(cmd, stderr=asyncio.subprocess.PIPE,
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
stdout, stderr = await proc.communicate()
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise ShutdownFailed() from e
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise ShutdownFailed(f'Got return code {proc.returncode}')
|
||||
background_task(_())
|
||||
if reboot:
|
||||
Events.send_shutdown(f'Reboot in {delay} seconds')
|
||||
else:
|
||||
Events.send_shutdown(f'Shutdown in {delay} seconds')
|
||||
|
|
|
|||
|
|
@ -121,12 +121,6 @@ class HotspotPasswordTooShort(APIError):
|
|||
status = HTTPStatus.BAD_REQUEST
|
||||
|
||||
|
||||
class RestartFailed(APIError):
|
||||
code = 'RESTART_FAILED'
|
||||
summary = 'Unable to restart the WROLPi'
|
||||
status = HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
|
||||
|
||||
class ShutdownFailed(APIError):
|
||||
code = 'SHUTDOWN_FAILED'
|
||||
summary = 'Unable to shutdown the WROLPi'
|
||||
|
|
|
|||
|
|
@ -73,6 +73,14 @@ class Events:
|
|||
def send_map_import_failed(message: str = None):
|
||||
send_event('map_import_failed', message, subject='map')
|
||||
|
||||
@staticmethod
|
||||
def send_shutdown(message: str = None):
|
||||
send_event('shutdown', message, subject='shutdown')
|
||||
|
||||
@staticmethod
|
||||
def send_shutdown_failed(message: str = None):
|
||||
send_event('shutdown_failed', message, subject='shutdown')
|
||||
|
||||
|
||||
def log_event(event: str, message: str = None, action: str = None, subject: str = None):
|
||||
log = f'{event=}'
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from wrolpi.common import logger, get_config, wrol_mode_enabled, Base, get_media
|
|||
from wrolpi.dates import now, strptime
|
||||
from wrolpi.downloader import download_manager
|
||||
from wrolpi.errors import WROLModeEnabled, APIError, HotspotError, InvalidDownload, \
|
||||
HotspotPasswordTooShort, ShutdownFailed, RestartFailed
|
||||
HotspotPasswordTooShort, NativeOnly
|
||||
from wrolpi.events import get_events, Events
|
||||
from wrolpi.files.lib import get_file_statistics, estimate_search
|
||||
from wrolpi.vars import API_HOST, API_PORT, DOCKERIZED, API_DEBUG, API_ACCESS_LOG, API_WORKERS, API_AUTO_RELOAD, \
|
||||
|
|
@ -504,16 +504,16 @@ async def post_search_estimate(_: Request, body: schema.SearchEstimateRequest):
|
|||
@api_bp.post('/restart')
|
||||
async def post_restart(_: Request):
|
||||
if DOCKERIZED:
|
||||
raise RestartFailed(f'Cannot restart when running in Docker')
|
||||
raise NativeOnly(f'Cannot restart when running in Docker')
|
||||
|
||||
await admin.restart()
|
||||
await admin.shutdown(reboot=True)
|
||||
return response.empty(HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
@api_bp.post('/shutdown')
|
||||
async def post_shutdown(_: Request):
|
||||
if DOCKERIZED:
|
||||
raise ShutdownFailed(f'Cannot shutdown when running in Docker')
|
||||
raise NativeOnly(f'Cannot shutdown when running in Docker')
|
||||
|
||||
await admin.shutdown()
|
||||
return response.empty(HTTPStatus.NO_CONTENT)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue