Skip to content

Commit

Permalink
initiate changelog for ntp
Browse files Browse the repository at this point in the history
  • Loading branch information
nori210 committed Jun 26, 2024
1 parent 440616e commit 3d86ad6
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 76 deletions.
25 changes: 25 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import shlex
import socket
from bson.json_util import dumps
from hashlib import sha256
import os

import config
from dhcp import scan_dhcp_pool, get_lease_info
Expand Down Expand Up @@ -220,6 +222,29 @@ def customize_ntp_test():
ntp_results = test_ntp_servers(servers)
return jsonify(ntp_results)

def log_ntp_results(ntp_results):
"""Log NTP test results to MongoDB."""
db.ntp_changes.insert_one({
'timestamp': datetime.datetime.now(),
'results': ntp_results,
'description': 'Regular NTP test'
})

@app.route('/ntp_changes', methods=['GET'])
def get_ntp_changes():
"""Retrieve NTP configuration changes from the last 24 hours."""
now = datetime.datetime.now()
start_time = now - datetime.timedelta(hours=24)
changes = list(db.ntp_changes.find({'timestamp': {'$gte': start_time}}, {'_id': 0}))
for change in changes:
if 'timestamp' in change:
change['timestamp'] = change['timestamp'].isoformat()
return jsonify({'ntp_changes': changes})

def cleanup_old_entries():
"""Remove entries older than 24 hours."""
threshold_time = datetime.datetime.now() - datetime.timedelta(hours=24)
db.ntp_changes.delete_many({'timestamp': {'$lt': threshold_time}})

@app.route('/ping_status', methods=['GET'])
def ping_status():
Expand Down
16 changes: 9 additions & 7 deletions backend/ntp.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ def __get_local_ntp_config__():
servers (array): An array of NTP servers found in ntp.conf
"""
servers = []
with open(config.NTP_FILE_PATH, 'r') as f:
lines = f.readlines()
for line in lines:
line = line.strip()
if line.startswith("pool") or line.startswith("server"):
server = line.split()[1]
servers.append(server)
try:
with open(config.NTP_FILE_PATH, 'r') as f:
lines = f.readlines()
for line in lines:
if line.startswith("pool") or line.startswith("server"):
server = line.split()[1]
servers.append(server)
except FileNotFoundError:
print("NTP configuration file not found.")
return servers


Expand Down
161 changes: 92 additions & 69 deletions frontend/src/NTPSources.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ const NTPSources = () => {
const [cNtpServers, setCNtpServers] = useState([]);
const [customTestResults, setCustomTestResults] = useState({});
const [customTestError, setCustomTestError] = useState('');
const [ntpChanges, setNtpChanges] = useState([]);
const [ntpChangesError, setNtpChangesError] = useState('');

useEffect(() => {
const fetchNTPSources = async () => {
const backendUrl = localStorage.getItem('backendUrl');
const port = localStorage.getItem('port');

try {
// get backendUrl and port from sessionStorage
const backendUrl = localStorage.getItem('backendUrl');
const port = localStorage.getItem('port');
if (!backendUrl || !port || backendUrl === '' || port === '') {
setError('Please set backend URL and port in the settings.');
return;
}

// make a request to the backend
// Make a request to the backend
const response = await axios.get(`http://${backendUrl}:${port}/ntp_sources`);
setSources(response.data);
if (Object.keys(response.data).length === 0) {
Expand All @@ -28,8 +30,13 @@ const NTPSources = () => {
} catch (error) {
setError('Error fetching NTP srouces: ' + error.message);
}
};

try {
const changesResponse = await axios.get(`http://${backendUrl}:${port}/ntp_changes`);
setNtpChanges(changesResponse.data.ntp_changes);
} catch (error) {
setNtpChangesError('Error fetching NTP changes: ' + error.message);
}
};
fetchNTPSources();
}, []);

Expand Down Expand Up @@ -59,71 +66,87 @@ const NTPSources = () => {

return (
<div className='page-container'>
<div className='ntp-local'>
<h2 style={{ fontFamily: "'Roboto Mono', sans-serif", textAlign: 'center'}} >Local NTP Status</h2>
{error && <p>{error}</p>}

{Object.keys(sources).length > 0 ? (
<div className="card-container">
{Object.keys(sources).map((key) => (
<div key={key} className={
sources[key] === null ? 'card card-error' :
sources[key].status === 'failed' ? 'card card-warning' : 'card card-success'
}>
<h3>{key}</h3>
{sources[key] === null ? <p>No Response</p>:(
<div>
<p>Status: {sources[key].status}</p>
<p>Offset: {(parseFloat(sources[key].offset)*1000).toFixed(2)} ms</p>
<p>Stratum: {sources[key].stratum}</p>
<p>Request Sent On: {new Date(parseInt(sources[key].local_sent_on)*1000).toLocaleTimeString()}</p>
<p>Response Received On: {new Date(parseInt(sources[key].local_received_on)*1000).toLocaleTimeString()}</p>
<p>Delay: {parseFloat(sources[key].delay).toFixed(2)}s</p>
</div>
)
}
</div>

))}
</div>
) : <p>Loading Local NTP Sources</p>}
</div>
<div className='ntp-custom'>
<h2 style={{ fontFamily: "'Roboto Mono', sans-serif" }}> Other NTP Servers</h2>
<form>
<textarea id='ntp-servers' placeholder='Enter 1 NTP server each line.' value={cNtpServers} onChange={(e) => setCNtpServers(e.target.value)} className='form-control'></textarea>
<button onClick={handleSubmit} className='btn btn-success'>Submit</button>
</form>
<br />
{customTestError && <p>{customTestError}</p>}
{Object.keys(customTestResults).length > 0 ? (
<div className="card-container-vertical">
{Object.keys(customTestResults).map((key) => (
<div key={key} className={
customTestResults[key] === null ? 'card card-error' :
customTestResults[key].status === 'failed' ? 'card card-warning' : 'card card-success'
}>
<h3>{key}</h3>
{customTestResults[key] === null ? <p>No Response</p>:(
<div>
<p>Status: {customTestResults[key].status}</p>
<p>Offset: {(parseFloat(customTestResults[key].offset)*1000).toFixed(2)} ms</p>
<p>Stratum: {customTestResults[key].stratum}</p>
<p>Request Sent On: {new Date(parseInt(customTestResults[key].local_sent_on)*1000).toLocaleTimeString()}</p>
<p>Response Received On: {new Date(parseInt(customTestResults[key].local_received_on)*1000).toLocaleTimeString()}</p>
<p>Delay: {parseFloat(customTestResults[key].delay).toFixed(2)}s</p>
</div>
)
}
</div>

))}
</div>
) : <p></p>}
</div>

<div className='ntp-local'>
<h2 style={{ fontFamily: "'Roboto Mono', sans-serif", textAlign: 'center' }}>Local NTP Status</h2>
{error && <p>{error}</p>}
{Object.keys(sources).length > 0 && (
<div className="card-container">
{Object.keys(sources).map((key) => (
<div key={key} className={
sources[key] === null ? 'card card-error' :
sources[key].status === 'failed' ? 'card card-warning' : 'card card-success'
}>
<h3>{key}</h3>
{sources[key] === null ? <p>No Response</p> : (
<div>
<p>Status: {sources[key].status}</p>
<p>Offset: {(parseFloat(sources[key].offset) * 1000).toFixed(2)} ms</p>
<p>Stratum: {sources[key].stratum}</p>
<p>Request Sent On: {new Date(sources[key].local_sent_on * 1000).toLocaleTimeString()}</p>
<p>Response Received On: {new Date(sources[key].local_received_on * 1000).toLocaleTimeString()}</p>
<p>Delay: {parseFloat(sources[key].delay).toFixed(2)}s</p>
</div>
)}
</div>
))}
</div>
)}
</div>
<div className='ntp-custom'>
<h2 style={{ fontFamily: "'Roboto Mono', sans-serif" }}>Other NTP Servers</h2>
<form onSubmit={handleSubmit}>
<textarea
id='ntp-servers'
placeholder='Enter 1 NTP server per line.'
value={cNtpServers}
onChange={(e) => setCNtpServers(e.target.value)}
className='form-control'
></textarea>
<button type='submit' className='btn btn-success'>Submit</button>
</form>
<br />
{customTestError && <p>{customTestError}</p>}
{Object.keys(customTestResults).length > 0 && (
<div className="card-container-vertical">
{Object.keys(customTestResults).map((key) => (
<div key={key} className={
customTestResults[key] === null ? 'card card-error' :
customTestResults[key].status === 'failed' ? 'card card-warning' : 'card card-success'
}>
<h3>{key}</h3>
{customTestResults[key] === null ? <p>No Response</p> : (
<div>
<p>Status: {customTestResults[key].status}</p>
<p>Offset: {(parseFloat(customTestResults[key].offset) * 1000).toFixed(2)} ms</p>
<p>Stratum: {customTestResults[key].stratum}</p>
<p>Request Sent On: {new Date(customTestResults[key].local_sent_on * 1000).toLocaleTimeString()}</p>
<p>Response Received On: {new Date(customTestResults[key].local_received_on * 1000).toLocaleTimeString()}</p>
<p>Delay: {parseFloat(customTestResults[key].delay).toFixed(2)}s</p>
</div>
)}
</div>
))}
</div>
)}
</div>
<div className='ntp-changes'>
<h2 style={{ fontFamily: "'Roboto Mono', sans-serif" }}>NTP Configuration Changes</h2>
{ntpChangesError && <p>{ntpChangesError}</p>}
{ntpChanges.length > 0 ? (
<ul>
{ntpChanges.filter((change, index) =>
index === 0 || ntpChanges[index - 1].hash !== change.hash
).map((change, index) => (
<li key={index}>
Changed on: {new Date(change.timestamp).toLocaleString()}
</li>
))}
</ul>
) : <p>No recent changes.</p>}
</div>
</div>
);
};

export default NTPSources;

0 comments on commit 3d86ad6

Please sign in to comment.