1
0
mirror of https://bitbucket.org/anguist/ntpa synced 2025-10-05 18:41:13 +00:00

Reload configuration & bugfixes

This commit is contained in:
2016-03-23 17:52:00 +01:00
parent 830cd86551
commit 5b11bc2a62
18 changed files with 326 additions and 164 deletions

27
INSTALL
View File

@ -21,7 +21,7 @@ Windows
Download a copy of ntpq and ntpdc. Make sure .NET is installed and
the required MySQL Server is accessible. Download and install MySQL
if needed.
if needed. Minor adjustments might be needed to get the code running.
Install
@ -44,33 +44,22 @@ Touch /var/log/ntpa.log and adjust pid file location if needed.
Configuration
In ntpa.conf Hostname must point to a name or IP reachable by ntpq.
ConfigFile must must point to ntp.conf. ConfigFile is only needed
when generating graphs and pages. Adjust the values of HostName and
ConfigFile settings accordingly.
Set database user name and password in the top of ntpa.conf. Leave the
Create setting to 1 if you want all tables and data created automatically.
Be sure the user you entered in ntpa.conf exists in your MySQL database.
If you want to generate graphs and pages then also copy ntp.conf from
NTP host to the machine running ntpa and add timeserver ID from
support.ntp.org. Search using google.com with f.x.
"ntp1.innolan.net" site:support.ntp.org
For servers not registered on support.ntp.org just add 10000 and above.
See ntp.conf in examples on how to add time server IDs.
Then later you can use phpMyAdmin, MySQL Workbench or similar to adjust
the auto generated values.
Set Hostname to point at a name or an IP address reachable by ntpq. If
you want to generate graphs and pages also copy ntp.conf from the NTP host
to the machine running ntpa and set ConfigFile to point at this file.
Configuration can be validated with the validation tool:
# mono ntpav.exe /etc/ntpa.conf
Use phpMyAdmin, MySQL Workbench or similar to adjust auto generated
values in the database.
Start ntpa and watch the data arriving in MySQL tables.
To start ntpa use:
# mono ntpa.exe
The log file contains errors and other clues for debugging.
Look in the log file for errors and other clues when debugging.
To stop ntpa use kill. Find the process id in the log file.
# kill 72354

View File

@ -102,7 +102,7 @@ namespace Ntp.Analyzer.Cli
try {
Main main = new Main (configFile, pid, name);
main.Start ();
main.Run ();
} catch (Exception e) {
Console.WriteLine (e.Message);
}

View File

@ -35,7 +35,7 @@ namespace Ntp.Analyzer.Data
/// </summary>
public sealed class DataFace
{
private static readonly DataFace instance = new DataFace ();
private static DataFace instance = new DataFace ();
private readonly Object locker = new Object ();
private readonly LogBase log;
private NtpConfCache ntpConfigCache;
@ -52,6 +52,11 @@ namespace Ntp.Analyzer.Data
log = DataConnection.Log;
}
public static void Reset()
{
instance = new DataFace ();
}
/// <summary>
/// Gets the Singleton instance.
/// </summary>

View File

@ -101,8 +101,10 @@ namespace Ntp.Analyzer.Data.Static
protected void AddItem (T item)
{
items.Add (item.Id, item);
hasContent = true;
lock (Locker) {
items.Add (item.Id, item);
hasContent = true;
}
}
protected void Open ()

View File

@ -30,7 +30,7 @@ namespace Ntp.Analyzer.Log
{
public class ActivityLog : LogBase, IEnumerable<String>
{
public ActivityLog ()
internal ActivityLog ()
{
activity = new List<string> (2001);
}
@ -43,6 +43,15 @@ namespace Ntp.Analyzer.Log
activity.Clear ();
}
public override void Refresh ()
{
}
public override void Close ()
{
activity.Clear ();
}
public override void WriteLine (string text, Severity severity)
{
string severityText;

View File

@ -32,6 +32,10 @@ namespace Ntp.Analyzer.Log
{
public abstract void Initialize();
public abstract void Close();
public abstract void Refresh();
public abstract void WriteLine(string text, Severity severity);
public abstract void WriteLine(Exception exception, Severity severity);

View File

@ -30,9 +30,36 @@ namespace Ntp.Analyzer.Log
{
public static class LogFactory
{
private static List<LogBase> logs = new List<LogBase>();
public static void RefreshLogs()
{
foreach (LogBase log in logs)
log.Refresh ();
}
public static void Cleanup()
{
foreach (LogBase log in logs)
log.Close ();
logs.Clear ();
}
public static ActivityLog CreateActivityLog()
{
return new ActivityLog ();
}
public static LogGroup CreateGroupLog()
{
return new LogGroup ();
}
public static LogBase CreateLog(LogConfiguration config)
{
TextLog log = new TextLog(config.File, config.Treshold);
logs.Add (log);
return log;
}
@ -46,6 +73,8 @@ namespace Ntp.Analyzer.Log
group.Add(log);
}
logs.Add (group);
return group;
}
}

View File

@ -33,7 +33,7 @@ namespace Ntp.Analyzer.Log
{
private readonly List<LogBase> logs;
public LogGroup()
internal LogGroup()
{
logs = new List<LogBase>();
}
@ -44,6 +44,18 @@ namespace Ntp.Analyzer.Log
log.Initialize();
}
public override void Refresh ()
{
foreach (LogBase log in logs)
log.Refresh();
}
public override void Close()
{
foreach (LogBase log in logs)
log.Close();
}
public override void WriteLine(string text, Severity severity)
{
foreach (LogBase log in logs)

View File

@ -39,7 +39,7 @@ namespace Ntp.Analyzer.Log
private bool initialized;
private TextWriter writer;
public TextLog(string file, Severity treshold, string timeFormat)
internal TextLog(string file, Severity treshold, string timeFormat)
{
this.file = file;
this.treshold = treshold;
@ -47,7 +47,7 @@ namespace Ntp.Analyzer.Log
initialized = false;
}
public TextLog(string file, Severity treshold)
internal TextLog(string file, Severity treshold)
: this(file, treshold, "yyyy-MM-dd HH:mm:ss")
{
}
@ -58,6 +58,12 @@ namespace Ntp.Analyzer.Log
initialized = true;
}
public override void Refresh ()
{
Close ();
Initialize ();
}
public override void WriteLine(string text, Severity severity)
{
if (!initialized)
@ -120,7 +126,7 @@ namespace Ntp.Analyzer.Log
WriteLine(exception.StackTrace, severity);
}
public void Close()
public override void Close()
{
writer.Close();
initialized = false;

View File

@ -66,6 +66,7 @@ namespace Ntp.Analyzer.Process
this.version = VersionInfo.Number;
}
private static bool firstrun = true;
private readonly string version;
private readonly string configFile;
private readonly int pid;
@ -89,6 +90,10 @@ namespace Ntp.Analyzer.Process
get { return nodes; }
}
public List<Listener> Listeners {
get { return listeners; }
}
public bool Ready {
get { return ready; }
}
@ -116,6 +121,7 @@ namespace Ntp.Analyzer.Process
}
ready = proceed;
firstrun = false;
}
/// <summary>
@ -156,14 +162,15 @@ namespace Ntp.Analyzer.Process
// Create log.
try {
log = LogFactory.CreateLog (config.Log);
log.Initialize();
log.Initialize ();
} catch (Exception ex) {
Console.WriteLine ("Cannot create log file. " + ex.Message);
return false;
}
// Initialize log.
log.WriteLine ("NTP Analyzer " + version + " started.", Severity.Notice);
if (firstrun)
log.WriteLine ("NTP Analyzer " + version + " started.", Severity.Notice);
log.WriteLine ("Using configuration: " + configFile, Severity.Notice);
log.WriteLine ("Running with pid: " + pid, Severity.Notice);
log.WriteLine ("Instance name: " + name, Severity.Notice);
@ -193,6 +200,7 @@ namespace Ntp.Analyzer.Process
DataConnection.InitializeString = config.Database.InitializeConnectionString;
DataConnection.Initialize = config.Database.Initialize;
DataConnection.Log = log;
DataFace.Reset ();
// Initialize database tables
if (config.Database.Initialize) {
@ -245,7 +253,7 @@ namespace Ntp.Analyzer.Process
}
}
} catch (Exception e) {
log.WriteLine ("Could not populating all data into tables.", Severity.Error);
log.WriteLine ("Could not populate tables with data.", Severity.Error);
log.WriteLine (e.Message, Severity.Debug);
log.WriteLine (e, Severity.Trace);
}

View File

@ -25,6 +25,8 @@
// THE SOFTWARE.
using System;
using Ntp.Process;
using Ntp.Analyzer.Log;
using Ntp.Monitor.Server;
namespace Ntp.Analyzer.Process
{
@ -41,17 +43,25 @@ namespace Ntp.Analyzer.Process
private readonly int pid;
private readonly string name;
public void Start ()
public void Run ()
{
Initializer i = new Initializer (configFile, pid, name);
i.Run ();
bool reload = true;
while (reload) {
Initializer i = new Initializer (configFile, pid, name);
i.Run ();
if (!i.Ready) {
return;
if (!i.Ready)
return;
Cluster c = new Cluster (name, i.Scheduler, i.Nodes, i.Log);
c.Activate ();
reload = c.Reload;
foreach (Listener l in i.Listeners)
l.Close ();
LogFactory.Cleanup ();
}
Cluster c = new Cluster (name, i.Scheduler, i.Nodes, i.Log);
c.Activate ();
}
}
}

View File

@ -45,11 +45,13 @@ namespace Ntp.Monitor.Server
IPAddress address = IPAddress.Parse (ip);
endPoint = new IPEndPoint (address, port);
this.log = log;
this.shuttingDown = false;
}
private readonly IPEndPoint endPoint;
private readonly LogBase log;
private Socket listenSocket;
private bool shuttingDown;
/// <summary>
/// Open this listener.
@ -78,6 +80,7 @@ namespace Ntp.Monitor.Server
/// </summary>
public void Close ()
{
shuttingDown = true;
listenSocket.Close ();
}
@ -103,9 +106,11 @@ namespace Ntp.Monitor.Server
ReceiveCallback,
req);
} catch (Exception ex) {
log.WriteLine ("Unexpected error in listener " + this.ToString (), Severity.Error);
log.WriteLine (ex.Message, Severity.Debug);
log.WriteLine (ex, Severity.Trace);
if (!shuttingDown) {
log.WriteLine ("Unexpected error in listener " + this.ToString (), Severity.Error);
log.WriteLine (ex.Message, Severity.Debug);
log.WriteLine (ex, Severity.Trace);
}
}
}

View File

@ -25,9 +25,7 @@
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Linq;
using System.Threading;
using Ntp.Analyzer.Log;
using Ntp.System;
@ -46,6 +44,7 @@ namespace Ntp.Process
this.scheduler = scheduler;
this.peers = peers;
this.log = log;
this.reload = false;
waitHandle = new EventWaitHandle (false, EventResetMode.AutoReset);
}
@ -54,25 +53,28 @@ namespace Ntp.Process
private readonly IEnumerable<IRequest> peers;
private readonly LogBase log;
private readonly EventWaitHandle waitHandle;
private bool reload;
private bool run;
public bool Reload {
get { return reload; }
}
public void Activate ()
{
log.WriteLine ("Starting cluster module.", Severity.Info);
bool activated = true;
if (peers.Count () != 0) {
log.WriteLine ("Starting cluster module.", Severity.Info);
}
Thread killSwitch = new Thread (KillSwitch);
killSwitch.Start ();
Thread signalHandler = new Thread (SignalHandler);
signalHandler.Start ();
run = true;
// TODO: Move to public scope (ApplicationState)
bool activated = true;
while (run) {
bool otherActive = false;
foreach (IRequest request in peers) {
try {
string answer = request.Send ("ping");
@ -94,8 +96,6 @@ namespace Ntp.Process
}
if (!otherActive) {
//log.WriteLine ("No other nodes active. Activting node.", Severity.Debug);
try {
scheduler.RunOneCycle ();
} catch (Exception e) {
@ -105,28 +105,57 @@ namespace Ntp.Process
return;
}
} else {
log.WriteLine ("Other node active. Going to fallback mode.", Severity.Debug);
waitHandle.WaitOne (10000);
}
// This node is now active and no longer "activated"
activated = false;
}
}
}
public void KillSwitch ()
public void SignalHandler ()
{
try {
InterLock.Wait (name, log);
waitHandle.Set ();
scheduler.WaitHandle.Set ();
run = false;
} catch (Exception e) {
log.WriteLine ("Error in mutux.", Severity.Error);
log.WriteLine (e.ToString (), Severity.Error);
log.WriteLine (e, Severity.Trace);
}
bool loop = true;
log.WriteLine ("Closing down.", Severity.Notice);
while (loop) {
try {
switch (InterProcess.Wait (name, log)) {
case InterProcess.Signal.Exit:
loop = false;
run = false;
waitHandle.Set ();
scheduler.WaitHandle.Set ();
log.WriteLine ("Closing down.", Severity.Notice);
break;
case InterProcess.Signal.Reload:
reload = true;
loop = false;
run = false;
waitHandle.Set ();
scheduler.WaitHandle.Set ();
log.WriteLine ("Reloading configuration.", Severity.Notice);
break;
case InterProcess.Signal.Refresh:
LogFactory.RefreshLogs ();
log.WriteLine ("Restarting logging module.", Severity.Notice);
break;
case InterProcess.Signal.Error:
log.WriteLine ("Error in inter process communication.", Severity.Error);
loop = false;
run = false;
break;
default:
log.WriteLine ("Unexpected InterProcess signal.", Severity.Error);
break;
}
} catch (Exception e) {
log.WriteLine ("Error in signal handler.", Severity.Error);
log.WriteLine (e.ToString (), Severity.Error);
log.WriteLine (e, Severity.Trace);
loop = false;
run = false;
}
}
}
}
}
}

View File

@ -53,9 +53,9 @@ namespace Ntp.Process
schedule = new List<ScheduledJob> ();
jobs = new List<Job> ();
activityLog = new ActivityLog ();
activityLog = LogFactory.CreateActivityLog ();
LogGroup logGroup = new LogGroup ();
LogGroup logGroup = LogFactory.CreateGroupLog ();
logGroup.Add (log);
logGroup.Add (activityLog);

View File

@ -1,91 +0,0 @@
//
// InterLock.cs
//
// Author:
// Carsten Sonne Larsen <cs@innolan.dk>
//
// Copyright (c) 2016 Carsten Sonne Larsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using Ntp.Analyzer.Log;
#if __MonoCS__
using Mono.Unix;
using Mono.Unix.Native;
#else
using System.Threading;
#endif
namespace Ntp.System
{
public static class InterLock
{
#if __MonoCS__
public static bool Wait (string name, LogBase log)
{
UnixSignal[] signals = new UnixSignal[]{
new UnixSignal (Signum.SIGTERM)
};
try {
UnixSignal.WaitAny (signals, -1);
log.WriteLine ("Received kill signal.", Severity.Notice);
} catch (Exception e) {
log.WriteLine ("Error in Signum handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return false;
}
return true;
}
#else
public static bool Release (string name, LogBase log)
{
try {
EventWaitHandle handle = EventWaitHandle.OpenExisting (name);
handle.Set ();
return true;
} catch (Exception e) {
log.WriteLine ("Error in mutex handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return false;
}
}
public static bool Wait (string name, LogBase log)
{
try {
EventWaitHandle handle = new EventWaitHandle (
false, EventResetMode.ManualReset,
name);
handle.WaitOne ();
return true;
} catch (Exception e) {
log.WriteLine ("Error in mutex handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return false;
}
}
#endif
}
}

130
Ntp.System/InterProcess.cs Normal file
View File

@ -0,0 +1,130 @@
//
// InterLock.cs
//
// Author:
// Carsten Sonne Larsen <cs@innolan.dk>
//
// Copyright (c) 2016 Carsten Sonne Larsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using Ntp.Analyzer.Log;
#if __MonoCS__
using Mono.Unix;
using Mono.Unix.Native;
#else
using System.Threading;
#endif
namespace Ntp.System
{
public static class InterProcess
{
public enum Signal
{
Error = 0,
Exit,
Refresh,
Reload
}
#if __MonoCS__
public static Signal Wait (string name, LogBase log)
{
UnixSignal[] signals = new UnixSignal[] {
new UnixSignal (Signum.SIGTERM),
new UnixSignal (Signum.SIGQUIT),
new UnixSignal (Signum.SIGINT),
new UnixSignal (Signum.SIGHUP),
new UnixSignal (Signum.SIGUSR1)
};
int sig = 0;
while (true) {
try {
sig = UnixSignal.WaitAny (signals, -1);
} catch (Exception e) {
log.WriteLine ("Error in Signum handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return Signal.Error;
}
if (sig >= 0 && sig < signals.Length) {
Signum signal = signals [sig].Signum;
switch (signal) {
case Signum.SIGINT:
log.WriteLine ("Interrupted.", Severity.Notice);
return Signal.Exit;
case Signum.SIGTERM:
log.WriteLine ("Received kill signal.", Severity.Notice);
return Signal.Exit;
case Signum.SIGQUIT:
log.WriteLine ("Received quit signal.", Severity.Notice);
return Signal.Exit;
case Signum.SIGHUP:
log.WriteLine ("Received log restart signal.", Severity.Debug);
return Signal.Refresh;
case Signum.SIGUSR1:
log.WriteLine ("Received reload config signal.", Severity.Debug);
return Signal.Reload;
default:
log.WriteLine ("Unknown signal received.", Severity.Warn);
break;
}
} else {
log.WriteLine ("Unknown signal received.", Severity.Warn);
}
}
}
#else
public static bool Release (string name, LogBase log)
{
try {
EventWaitHandle handle = EventWaitHandle.OpenExisting (name);
handle.Set ();
return Signal.Exit;
} catch (Exception e) {
log.WriteLine ("Error in mutex handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return Signal.Error;
}
}
public static Signal Wait (string name, LogBase log)
{
try {
EventWaitHandle handle = new EventWaitHandle (
false, EventResetMode.ManualReset,
name);
handle.WaitOne ();
return true;
} catch (Exception e) {
log.WriteLine ("Error in mutex handling.", Severity.Error);
log.WriteLine (e, Severity.Trace);
return false;
}
}
#endif
}
}

View File

@ -41,10 +41,10 @@
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ShellCommand.cs" />
<Compile Include="InterLock.cs" />
<Compile Include="ProcessInfo.cs" />
<Compile Include="Options.cs" />
<Compile Include="VersionInfo.cs" />
<Compile Include="InterProcess.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

View File

@ -24,6 +24,9 @@ rcvar=${name}_enable
start_cmd="ntpa_start"
stop_cmd="ntpa_stop"
reload_cmd="ntpa_reload"
extra_commands="reload"
load_rc_config ${name}
@ -42,6 +45,18 @@ ntpa_start()
fi
}
ntpa_reload()
{
if [ ! -f ${pidfile} ]; then
_run_rc_notrunning
return 1
else
echo "Reloading ${name}."
rc_pid=`cat ${pidfile}`
kill -USR1 $rc_pid
fi
}
ntpa_stop()
{
if [ ! -f ${pidfile} ]; then