Skip to content

Commit bacf2e1

Browse files
Create function, endpoint, frontend implementation for log persistence
Update CHANGELOG.md Lint ctrl.py Add persist_logs bool and integrate throughout the config flow Add many logger.info chunks for testing Add more logic to persist_logs toggle endpoint Change how default value is handled Change default permissions of journald.conf Fix spelling errors, add logger on frontend Move toggle_log_persistance away from FastAPI and towards the Api object Linting Call reinit at end of log toggle, reword models.py description of persist_logs Remove all uses of persist_logs from amplipi core, move to updater side Remove lingering changes from app.py, ctrl.py pylint pylint (2) Finish porting new admin settings tab to updater Change name of Updates tab on settings page Fix spelling in comment in app.py
1 parent 55b8524 commit bacf2e1

6 files changed

Lines changed: 107 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* Move system state out of running software directory
3838
* Fix updates on systems with an API password set
3939
* Fix the display service on systems with an API password set
40+
* Add toggleable option to persist logs
4041
* Streams
4142
* File Players can be temporary. A temporary File Player will remove itself from the list of available streams once disconnected from all sources.
4243
* File Players run their own Python container process similar to Internet Radio Stations, rather than running a cvlc command.

amplipi/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def shutdown():
225225
"""
226226
# preemptively save the state (just in case the shutdown procedure doesn't invoke a save)
227227
get_ctrl().save()
228-
# start the shutdown process and returning immediately (hopeully before the shutdown process begins)
228+
# start the shutdown process and returning immediately (hopefully before the shutdown process begins)
229229
Popen('sleep 1 && sudo systemctl poweroff', shell=True)
230230

231231

amplipi/ctrl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def reinit(self, settings: models.AppSettings = models.AppSettings(), change_not
222222
except Exception as exc:
223223
logger.exception("Error setting is_streamer flag: {exc}")
224224

225-
# determine if we're in LMS mode, based on a file
225+
# determine if we're in LMS mode, based on a file existing
226226
lms_mode_path = Path(defaults.USER_CONFIG_DIR, 'lms_mode')
227227
if lms_mode_path.exists():
228228
logger.info("lms mode")

amplipi/updater/asgi.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import shutil
3737
import asyncio
3838

39+
import configparser
40+
from typing import Optional
41+
3942
# web framework
4043
import requests
4144
from fastapi import FastAPI, Request, File, UploadFile, Depends, APIRouter, Response
@@ -95,6 +98,69 @@ class ReleaseInfo(BaseModel):
9598
logger.exception(f'Error loading identity file: {e}')
9699

97100

101+
@router.get("/settings/persist_logs")
102+
def get_log_persist_state():
103+
conf_path = '/etc/systemd'
104+
config = configparser.ConfigParser(strict=False, allow_no_value=True)
105+
config.read(f'{conf_path}/journald.conf')
106+
return config.get("Journal", "Storage", fallback="") == "persistent"
107+
108+
109+
@router.post("/settings/persist_logs")
110+
def toggle_persist_logs(value: Optional[bool] = None):
111+
"""
112+
Toggles the option within journald to save logs to memory or storage.
113+
Accepts an option bool called "value" for if you wish to change the value to a specific option rather than simply flip the state of the config file
114+
"""
115+
try:
116+
conf_path = '/etc/systemd'
117+
config = configparser.ConfigParser(strict=False, allow_no_value=True)
118+
config.read(f'{conf_path}/journald.conf')
119+
120+
if 'Journal' not in config:
121+
config.add_section('Journal')
122+
123+
# goal_value is a holdover from when this setting was in app.py and toggled via the config settings page
124+
# the bool is true if you wish to turn persistent logging on and false if you wish to turn it off
125+
# It can be set either with the optional arg of the function or it attempts to find the current value from the config file and set the opposite of that
126+
goal_value: bool
127+
if value is not None:
128+
goal_value = value
129+
else:
130+
goal_value = not get_log_persist_state()
131+
132+
if goal_value: # Set persist
133+
config.set('Journal', 'Storage', 'persistent')
134+
config.set('Journal', 'SyncIntervalSec', '30s')
135+
config.set('Journal', 'SystemMaxUse', '64M')
136+
137+
config.remove_option('Journal', 'RuntimeMaxUse')
138+
config.remove_option('Journal', 'ForwardToConsole')
139+
config.remove_option('Journal', 'ForwardToWall')
140+
141+
logger.info("persist_logs activated!")
142+
143+
else: # Reset config to default as seen in configure.py
144+
config.set('Journal', 'Storage', 'volatile')
145+
config.set('Journal', 'RuntimeMaxUse', '64M')
146+
config.set('Journal', 'ForwardToConsole', 'no')
147+
config.set('Journal', 'ForwardToWall', 'no')
148+
149+
config.remove_option('Journal', 'SyncIntervalSec')
150+
config.remove_option('Journal', 'SystemMaxUse')
151+
152+
logger.info("persist_logs deactivated!")
153+
154+
with open('/tmp/journald.conf.tmp', 'w', encoding="utf-8") as conf_file:
155+
config.write(conf_file)
156+
157+
subprocess.run(['sudo', 'mv', '/tmp/journald.conf.tmp', f'{conf_path}/journald.conf'], check=True)
158+
subprocess.run(['sudo', 'systemctl', 'restart', 'systemd-journald'], check=True)
159+
except Exception as exc:
160+
logger.error("persist_logs toggle failed!")
161+
raise exc
162+
163+
98164
@router.get('/update')
99165
def get_index():
100166
""" Get the update website """

amplipi/updater/static/index.html

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
</p>
2929
<h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1>
3030
<p class="lead mb-4">
31-
Update your AmpliPi device
31+
Update & configure your AmpliPi device
3232
</p>
3333
<div class="card">
3434
<div class="card-header">
@@ -43,7 +43,7 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
4343
<a class="nav-link" id="manual-update-tab" data-toggle="tab" href="#manual-update" role="tab" aria-controls="manual-update" aria-selected="false">Custom</a>
4444
</li>
4545
<li class="nav-item">
46-
<a class="nav-link" id="set-password-tab" data-toggle="tab" href="#set-password" role="tab" aria-controls="set-password" aria-selected="false">Set Password</a>
46+
<a class="nav-link" id="admin-settings-tab" data-toggle="tab" href="#admin-settings" role="tab" aria-controls="admin-settings" aria-selected="false">Admin Settings</a>
4747
</li>
4848
<li class="nav-item">
4949
<a class="nav-link" id="support-tunnel-tab" data-toggle="tab" href="#support-tunnel" role="tab" aria-controls="support-tunnel" aria-selected="false">Support Tunnel</a>
@@ -52,13 +52,15 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
5252
</div>
5353
<div class="card-body text-center">
5454
<div class="tab-content" id="myTabContent">
55+
5556
<div class="tab-pane fade show active" id="latest-update" role="tabpanel" aria-labelledby="latest-update-tab">
5657
<div id='latest-update-name'>...</div>
5758
<div id='latest-update-desc' class="text-left"></div>
5859
<a id="submit-latest-update" role="button" class="btn btn-lg btn-primary text-center mt-3 d-none"
5960
onclick="ui_start_software_update($('#latest-update').attr('data-url'), $('#latest-update').attr('data-version'));">
6061
Start Update</a>
6162
</div>
63+
6264
<div class="tab-pane fade" id="older-update" role="tabpanel" aria-labelledby="older-update-tab">
6365
<select class="custom-select" id="older-update-sel" onchange="ui_select_release(this);">
6466
<!-- Releases populated from GH -->
@@ -69,12 +71,14 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
6971
onclick="ui_start_software_update($('#older-update-sel').val(), $('#older-update-sel').find(':selected').data('version'));">
7072
Start Update</a>
7173
</div>
74+
7275
<div class="tab-pane fade" id="manual-update" role="tabpanel" aria-labelledby="manual-update-tab">
7376
<div class="custom-file">
7477
<input id="update-file-selector" type="file" accept=".gz" onchange="$('#submit-custom-update').removeClass('disabled');">
7578
</div>
7679
<a id="submit-custom-update" role="button" class="btn btn-lg btn-primary text-center mt-3 disabled" onclick="ui_upload_software_update();">Start Update</a>
7780
</div>
81+
7882
<div class="tab-pane fade text-left" id="set-password" role="tabpanel" aria-labelledby="set-password-tab">
7983
<div class="set-password-dialog">
8084
This form allows you to set a password for the web interface. If the password fields are empty, it will unset the password protection. This will only set a password for the web interface, not the system password. This action will also log out any existing sessions.
@@ -87,6 +91,7 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
8791
</div>
8892
<a id="password" role="button" class="btn btn-lg btn-primary text-center mt-3" onClick="set_password();">Update Password</a>
8993
</div>
94+
9095
<div class="tab-pane fade text-left" id="support-tunnel" role="tabpanel" aria-labelledby="support-tunnel-tab">
9196
<div id="support-tunnel-dialog">
9297
This dialog allows you to request a support tunnel. Once requested, you must give the tunnel ID and preshared key to support, who can be reached via <a href="mailto:support@micro-nova.com">support@micro-nova.com</a>.
@@ -105,6 +110,36 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
105110
</div>
106111
</div>
107112
</div>
113+
114+
<div class="tab-pane fade text-left" id="admin-settings" role="tabpanel" aria-labelledby="admin-settings-tab">
115+
<script>
116+
async function getPersist() {
117+
const response = await fetch("/settings/persist_logs", { method: "GET" });
118+
const data = await response.json();
119+
let checkbox = document.getElementById("persist_logs_checkbox");
120+
checkbox.checked = data;
121+
}
122+
123+
async function setPersist() {
124+
const checkbox = document.getElementById("persist_logs_checkbox");
125+
const response = await fetch("/settings/persist_logs", {method: "POST"});
126+
}
127+
128+
window.onload = getPersist;
129+
</script>
130+
131+
<div id="admin-settings-dialog">
132+
This tab allows you to change settings relating to the core of AmpliPi, things that do not belong on the standard config page
133+
</div>
134+
<p class="">
135+
<a class="btn btn-primary btn-sm text-center" id="set-password-button" data-toggle="tab" href="#set-password" role="tab" aria-controls="set-password" aria-selected="false">Set Password</a>
136+
</p>
137+
<h6>WARNING: leaving log persistence on for extended periods can damage your system and void your warranty</h6>
138+
<input id="persist_logs_checkbox" type="checkbox" onclick="setPersist()" />
139+
<label for="persist_logs_checkbox">Log Persistence</label>
140+
</div>
141+
142+
108143
</div>
109144
</div>
110145
</div>

web/src/pages/Settings/Settings.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const Settings = ({ openPage }) => {
155155
</ListItem>
156156

157157
<ListItem
158-
name="Updates"
158+
name="Admin"
159159
onClick={() => {
160160
window.location.href =
161161
"http://" + window.location.hostname + ":5001/update";

0 commit comments

Comments
 (0)