WIP
parent
1d9a61ec51
commit
f6d962ed5e
|
@ -52,29 +52,29 @@ namespace ln.skyscanner.checks
|
||||||
double voltage = (double)((Integer)(input[1].Items[1])).LongValue;
|
double voltage = (double)((Integer)(input[1].Items[1])).LongValue;
|
||||||
double current = (double)((Integer)(input[2].Items[1])).LongValue;
|
double current = (double)((Integer)(input[2].Items[1])).LongValue;
|
||||||
|
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_frequency", n), frequency, wLower: 48, wUpper: 52, cLower: 45, cUpper: 55);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_frequency", n), frequency, 48, 52, 45, 55, "Hz");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_voltage", n), voltage, wLower: 218.5, wUpper: 238, cLower: 212, cUpper: 245);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_voltage", n), voltage, 218.5, 238, 212, 245, "V");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_current", n), current);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_input_{0}_current", n), current, perfUnit: "A");
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
foreach (Sequence[] output in outputs)
|
foreach (Sequence[] output in outputs)
|
||||||
{
|
{
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_voltage", n), (double)((Integer)(output[0].Items[1])).LongValue, wLower: 218.5, wUpper: 238, cLower: 212, cUpper: 245);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_voltage", n), (double)((Integer)(output[0].Items[1])).LongValue, 218.5, 238, 212, 245, "V");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_current", n), (double)((Integer)(output[1].Items[1])).LongValue / 10.0);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_current", n), (double)((Integer)(output[1].Items[1])).LongValue / 10.0, perfUnit: "A");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_load", n), (double)((Integer)(output[2].Items[1])).LongValue, wUpper: 50, cUpper: 75);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_output_{0}_load", n), (double)((Integer)(output[2].Items[1])).LongValue, 50, 75, perfUnit: "%");
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
foreach (Sequence[] battery in batteries)
|
foreach (Sequence[] battery in batteries)
|
||||||
{
|
{
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_status", n), (double)((Integer)(battery[0].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_status", n), (double)((Integer)(battery[0].Items[1])).LongValue, perfUnit: "");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_minutes_remain", n), (double)((Integer)(battery[1].Items[1])).LongValue, wLower: 20, cLower: 10);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_minutes_remain", n), (double)((Integer)(battery[1].Items[1])).LongValue, wLower: 20, cLower: 10, perfUnit: "min");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_capacity", n), (double)((Integer)(battery[2].Items[1])).LongValue, wLower: 75, cLower: 50);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_capacity", n), (double)((Integer)(battery[2].Items[1])).LongValue / 100.0, wLower: 0.75, cLower: 0.50, perfUnit: "%");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_voltage", n), (double)((Integer)(battery[3].Items[1])).LongValue / 10.0);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_voltage", n), (double)((Integer)(battery[3].Items[1])).LongValue / 10.0, perfUnit: "V");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_temperature", n), (double)((Integer)(battery[4].Items[1])).LongValue, wUpper: 40, cUpper: 60);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ups_battery_{0}_temperature", n), (double)((Integer)(battery[4].Items[1])).LongValue, wUpper: 40, cUpper: 60, perfUnit: "°C");
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,9 @@ namespace ln.skyscanner.checks
|
||||||
{
|
{
|
||||||
checkState.CheckHistory();
|
checkState.CheckHistory();
|
||||||
}
|
}
|
||||||
|
} catch (TimeoutException te)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.WARNING, "CheckJob {0} for {1} ({3}) ran into timeout: {2}",checks[n].Name,Node.UniqueIdentity,te.Message,Node.Name);
|
||||||
} catch (Exception e)
|
} catch (Exception e)
|
||||||
{
|
{
|
||||||
Logging.Log(LogLevel.WARNING, "Exception caught by CheckJob {0} [{1} / {3}]: {2}", checks[n].Name,Node.Name,e,Node.UniqueIdentity);
|
Logging.Log(LogLevel.WARNING, "Exception caught by CheckJob {0} [{1} / {3}]: {2}", checks[n].Name,Node.Name,e,Node.UniqueIdentity);
|
||||||
|
|
|
@ -21,34 +21,27 @@ namespace ln.skyscanner.checks
|
||||||
|
|
||||||
foreach (URI snmpUri in node.FindURIs("snmp"))
|
foreach (URI snmpUri in node.FindURIs("snmp"))
|
||||||
{
|
{
|
||||||
try
|
using (SnmpInterface snmp = SnmpInterface.FromURI(snmpUri, checkService.SNMPEngine))
|
||||||
{
|
{
|
||||||
using (SnmpInterface snmp = SnmpInterface.FromURI(snmpUri, checkService.SNMPEngine))
|
Sequence[][] sigData = snmp.snmpWalk(new string[] {
|
||||||
|
"1.3.6.1.4.1.43356.2.1.2.6.1.1.3", // Signal Level
|
||||||
|
"1.3.6.1.4.1.43356.2.1.2.6.1.1.5", // SNR
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int n = 0; n < 4; n++)
|
||||||
{
|
{
|
||||||
Sequence[][] sigData = snmp.snmpWalk(new string[] {
|
if ((sigData.Length <= n))
|
||||||
"1.3.6.1.4.1.43356.2.1.2.6.1.1.3", // Signal Level
|
break;
|
||||||
"1.3.6.1.4.1.43356.2.1.2.6.1.1.5", // SNR
|
|
||||||
});
|
|
||||||
|
|
||||||
for (int n = 0; n < 4; n++)
|
double sig = (sigData[n][0].Items[1] as Integer).LongValue / 10.0;
|
||||||
{
|
double snr = (sigData[n][1].Items[1] as Integer).LongValue / 10.0;
|
||||||
if ((sigData.Length <= n))
|
|
||||||
break;
|
|
||||||
|
|
||||||
double sig = (sigData[n][0].Items[1] as Integer).LongValue / 10.0;
|
|
||||||
double snr = (sigData[n][1].Items[1] as Integer).LongValue / 10.0;
|
|
||||||
|
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_pwr_{0}",n), sig, -75.0, 0, -80.0, 0,"dBm",n.ToString());
|
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_snr_{0}",n), snr, 12, 99, 8, 99,"dB", n.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_pwr_{0}",n), sig, -75.0, 0, -80.0, 0,"dBm",n.ToString());
|
||||||
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_snr_{0}",n), snr, 12, 99, 8, 99,"dB", n.ToString());
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
Logging.Log(LogLevel.ERROR, "Exception caught in Mimosa(SkyCheck): {0}", e);
|
|
||||||
Logging.Log(e);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override bool IsValid(Node node)
|
public override bool IsValid(Node node)
|
||||||
|
|
|
@ -33,8 +33,8 @@ namespace ln.skyscanner.checks
|
||||||
foreach (Sequence[] row in ptp)
|
foreach (Sequence[] row in ptp)
|
||||||
{
|
{
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_pwr_{0}", n), (double)((Integer)(row[0].Items[1])).LongValue, -75.0, 0, -80.0, 0);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_rx_pwr_{0}", n), (double)((Integer)(row[0].Items[1])).LongValue, -75.0, 0, -80.0, 0);
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_tx_snr_{0}", n), (double)((Integer)(row[1].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_tx_snr_{0}", n), (double)((Integer)(row[1].Items[1])).LongValue, perfUnit: "dB");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_tx_pwr_{0}", n), (double)((Integer)(row[2].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, String.Format("ptp_tx_pwr_{0}", n), (double)((Integer)(row[2].Items[1])).LongValue, perfUnit: "dBm");
|
||||||
|
|
||||||
/* long rxBytes = ((Integer)(row[4].Items[1])).LongValue;
|
/* long rxBytes = ((Integer)(row[4].Items[1])).LongValue;
|
||||||
long txBytes = ((Integer)(row[5].Items[1])).LongValue;
|
long txBytes = ((Integer)(row[5].Items[1])).LongValue;
|
||||||
|
|
|
@ -77,6 +77,8 @@ namespace ln.skyscanner.checks
|
||||||
if ((history.Count == 0) || (history[history.Count - 1].NewState != CheckState))
|
if ((history.Count == 0) || (history[history.Count - 1].NewState != CheckState))
|
||||||
{
|
{
|
||||||
history.Add(new CheckStateChange(CheckState));
|
history.Add(new CheckStateChange(CheckState));
|
||||||
|
if (history.Count > 10)
|
||||||
|
history.RemoveAt(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace ln.skyscanner.checks
|
||||||
|
|
||||||
foreach (URI snmpUri in node.FindURIs("snmp"))
|
foreach (URI snmpUri in node.FindURIs("snmp"))
|
||||||
{
|
{
|
||||||
using (SnmpInterface snmp = SnmpInterface.FromURI(snmpUri,checkService.SNMPEngine))
|
using (SnmpInterface snmp = SnmpInterface.FromURI(snmpUri, checkService.SNMPEngine))
|
||||||
{
|
{
|
||||||
List<String> mibs = null;
|
List<String> mibs = null;
|
||||||
try
|
try
|
||||||
|
@ -38,7 +38,8 @@ namespace ln.skyscanner.checks
|
||||||
mibs.Add((s.Items[1] as ObjectIdentifier).AsString);
|
mibs.Add((s.Items[1] as ObjectIdentifier).AsString);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (TimeoutException)
|
}
|
||||||
|
catch (TimeoutException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,10 +56,10 @@ namespace ln.skyscanner.checks
|
||||||
|
|
||||||
foreach (Sequence[] row in ptp)
|
foreach (Sequence[] row in ptp)
|
||||||
{
|
{
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_capa", (double)((Integer)(row[0].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_capa", (double)((Integer)(row[0].Items[1])).LongValue, perfUnit: "bit/s");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_capa", (double)((Integer)(row[1].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_capa", (double)((Integer)(row[1].Items[1])).LongValue, perfUnit: "bit/s");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_pwr", (double)((Integer)(row[2].Items[1])).LongValue, -75.0, 0, -80.0, 0);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_pwr", (double)((Integer)(row[2].Items[1])).LongValue, -75.0, 0, -80.0, 0, perfUnit: "dBm");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_pwr", (double)((Integer)(row[3].Items[1])).LongValue);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_pwr", (double)((Integer)(row[3].Items[1])).LongValue, perfUnit: "dBm");
|
||||||
|
|
||||||
long rxBytes = ((Integer)(row[4].Items[1])).LongValue;
|
long rxBytes = ((Integer)(row[4].Items[1])).LongValue;
|
||||||
long txBytes = ((Integer)(row[5].Items[1])).LongValue;
|
long txBytes = ((Integer)(row[5].Items[1])).LongValue;
|
||||||
|
@ -66,8 +67,8 @@ namespace ln.skyscanner.checks
|
||||||
ubiquityCheckState.RXRate.Update(rxBytes * 8);
|
ubiquityCheckState.RXRate.Update(rxBytes * 8);
|
||||||
ubiquityCheckState.TXRate.Update(txBytes * 8);
|
ubiquityCheckState.TXRate.Update(txBytes * 8);
|
||||||
|
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_rate", ubiquityCheckState.RXRate.Current);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_rx_rate", ubiquityCheckState.RXRate.Current, perfUnit: "bit/s");
|
||||||
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_rate", ubiquityCheckState.TXRate.Current);
|
node.WritePerformanceValue(checkService.PerformanceValueService, Name, "ptp_tx_rate", ubiquityCheckState.TXRate.Current, perfUnit: "bit/s");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace ln.skyscanner.entities
|
||||||
// performanceValues[Name] = performanceValue;
|
// performanceValues[Name] = performanceValue;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
public void WritePerformanceValue(PerformanceValueService performanceValueService, String checkName, String perfName, double value, double wLower = Double.MinValue, double wUpper = Double.MaxValue, double cLower = Double.MinValue, double cUpper = Double.MaxValue,String perfUnit = "",String group = "",double exMin = double.MinValue,double exMax = double.MaxValue)
|
public void WritePerformanceValue(PerformanceValueService performanceValueService, String checkName, String perfName, double value, double wLower = Double.MinValue, double wUpper = Double.MaxValue, double cLower = Double.MinValue, double cUpper = Double.MaxValue, String perfUnit = "", String group = "", double exMin = double.MinValue, double exMax = double.MaxValue)
|
||||||
{
|
{
|
||||||
string[] perfPath = new string[] { UniqueIdentity, checkName, perfName };
|
string[] perfPath = new string[] { UniqueIdentity, checkName, perfName };
|
||||||
perfName = string.Join("/", perfPath);
|
perfName = string.Join("/", perfPath);
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
|
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Google.Protobuf">
|
<Reference Include="Google.Protobuf">
|
||||||
<HintPath>..\packages\Google.Protobuf.3.9.1\lib\net45\Google.Protobuf.dll</HintPath>
|
<HintPath>packages\Google.Protobuf.3.10.0\lib\net45\Google.Protobuf.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Renci.SshNet">
|
<Reference Include="Renci.SshNet">
|
||||||
<HintPath>..\packages\SSH.NET.2016.1.0\lib\net40\Renci.SshNet.dll</HintPath>
|
<HintPath>..\packages\SSH.NET.2016.1.0\lib\net40\Renci.SshNet.dll</HintPath>
|
||||||
|
@ -274,6 +274,21 @@
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="www\vue\ln.skyscanner.graphs.js" />
|
<None Include="www\vue\ln.skyscanner.graphs.js" />
|
||||||
|
<None Include="www\fonts\typicons.eot">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="www\fonts\typicons.svg">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="www\fonts\typicons.ttf">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="www\fonts\typicons.woff">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="www\css\typicons.css">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="identify\" />
|
<Folder Include="identify\" />
|
||||||
|
@ -290,6 +305,7 @@
|
||||||
<Folder Include="perfvalue\" />
|
<Folder Include="perfvalue\" />
|
||||||
<Folder Include="www\" />
|
<Folder Include="www\" />
|
||||||
<Folder Include="www\vue\" />
|
<Folder Include="www\vue\" />
|
||||||
|
<Folder Include="www\fonts\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ln.snmp\ln.snmp.csproj">
|
<ProjectReference Include="..\ln.snmp\ln.snmp.csproj">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="BouncyCastle" version="1.8.5" targetFramework="net47" />
|
<package id="BouncyCastle" version="1.8.5" targetFramework="net47" />
|
||||||
<package id="Google.Protobuf" version="3.9.1" targetFramework="net47" />
|
<package id="Google.Protobuf" version="3.10.0" targetFramework="net47" />
|
||||||
<package id="MySql.Data" version="8.0.17" targetFramework="net47" />
|
<package id="MySql.Data" version="8.0.17" targetFramework="net47" />
|
||||||
<package id="SSH.NET" version="2016.1.0" targetFramework="net47" />
|
<package id="SSH.NET" version="2016.1.0" targetFramework="net47" />
|
||||||
</packages>
|
</packages>
|
|
@ -10,6 +10,7 @@ using ln.types.threads;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ln.snmp;
|
using ln.snmp;
|
||||||
using ln.types.odb.ng;
|
using ln.types.odb.ng;
|
||||||
|
using ln.types.odb.ng.storage.session;
|
||||||
|
|
||||||
namespace ln.skyscanner.services
|
namespace ln.skyscanner.services
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ namespace ln.skyscanner.services
|
||||||
RPC = new CheckServiceRPC(this);
|
RPC = new CheckServiceRPC(this);
|
||||||
coreService.RPCContainer.Add("CheckService",RPC);
|
coreService.RPCContainer.Add("CheckService",RPC);
|
||||||
|
|
||||||
using (Session session = new Session(entityService.StorageContainer))
|
using (SessionStorageContainer session = new SessionStorageContainer(entityService.StorageContainer))
|
||||||
{
|
{
|
||||||
SessionMapper = new Mapper(session);
|
SessionMapper = new Mapper(session);
|
||||||
|
|
||||||
|
@ -121,24 +122,27 @@ namespace ln.skyscanner.services
|
||||||
{
|
{
|
||||||
Logging.Log(LogLevel.DEBUG, "CheckService: Synchronizing CheckJobs");
|
Logging.Log(LogLevel.DEBUG, "CheckService: Synchronizing CheckJobs");
|
||||||
|
|
||||||
HashSet<Node> knownNodes = new HashSet<Node>(SessionMapper.Load<Node>());
|
HashSet<Node> knownNodes = Timing.Meassure("knownNodes: ", () => new HashSet<Node>(SessionMapper.Load<Node>()));
|
||||||
HashSet<Node> currentNodes = new HashSet<Node>(checkJobs.Keys);
|
HashSet<Node> currentNodes = Timing.Meassure("currentNodes: ", () => new HashSet<Node>(checkJobs.Keys));
|
||||||
|
|
||||||
foreach (Node node in knownNodes)
|
Timing.Meassure("synchronization", () =>
|
||||||
{
|
{
|
||||||
if (!currentNodes.Contains(node))
|
foreach (Node node in knownNodes)
|
||||||
{
|
{
|
||||||
CheckJob checkJob = new CheckJob(this, node);
|
if (!currentNodes.Contains(node))
|
||||||
checkJobs.Add(node, checkJob);
|
{
|
||||||
|
CheckJob checkJob = new CheckJob(this, node);
|
||||||
|
checkJobs.Add(node, checkJob);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
foreach (Node node in currentNodes)
|
||||||
foreach (Node node in currentNodes)
|
|
||||||
{
|
|
||||||
if (!knownNodes.Contains(node))
|
|
||||||
{
|
{
|
||||||
checkJobs.Remove(node);
|
if (!knownNodes.Contains(node))
|
||||||
|
{
|
||||||
|
checkJobs.Remove(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@ using ln.types.odb.ng.storage;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ln.types.net;
|
using ln.types.net;
|
||||||
using ln.skyscanner.import.skytron;
|
using ln.skyscanner.import.skytron;
|
||||||
|
using ln.types.odb.ng.storage.fs;
|
||||||
|
using ln.types.odb.ng.storage.session;
|
||||||
|
|
||||||
namespace ln.skyscanner.services
|
namespace ln.skyscanner.services
|
||||||
{
|
{
|
||||||
public class EntityService : ApplicationServiceBase
|
public class EntityService : ApplicationServiceBase
|
||||||
|
@ -45,7 +48,7 @@ namespace ln.skyscanner.services
|
||||||
Logging.Log(LogLevel.INFO, "Entity Service: Initializing");
|
Logging.Log(LogLevel.INFO, "Entity Service: Initializing");
|
||||||
|
|
||||||
StorageContainer = new FSStorageContainer(System.IO.Path.Combine(BasePath, "storage"));
|
StorageContainer = new FSStorageContainer(System.IO.Path.Combine(BasePath, "storage"));
|
||||||
StorageSession = new Session(StorageContainer);
|
StorageSession = new SessionStorageContainer(StorageContainer);
|
||||||
SessionMapper = new Mapper(StorageSession);
|
SessionMapper = new Mapper(StorageSession);
|
||||||
|
|
||||||
StorageContainer.Open();
|
StorageContainer.Open();
|
||||||
|
@ -116,12 +119,13 @@ namespace ln.skyscanner.services
|
||||||
|
|
||||||
public Node GetNode(Guid nodeID)
|
public Node GetNode(Guid nodeID)
|
||||||
{
|
{
|
||||||
return EntityService.SessionMapper.Load<Node>(Query.Equals<Node>("ID", nodeID)).FirstOrDefault();
|
Node node = EntityService.SessionMapper.Load<Node>(Query.Equals<Node>("ID", nodeID),true).FirstOrDefault();
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node[] GetNodes()
|
public Node[] GetNodes()
|
||||||
{
|
{
|
||||||
return EntityService.SessionMapper.Load<Node>().ToArray();
|
return EntityService.SessionMapper.Load<Node>(true).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node CreateNode()
|
public Node CreateNode()
|
||||||
|
|
|
@ -33,6 +33,27 @@ a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a::before {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: inherit;
|
||||||
|
width: 1em;
|
||||||
|
height: 1.5em;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
font-family: typicons;
|
||||||
|
content: '\e01a';
|
||||||
|
}
|
||||||
|
|
||||||
|
.plain::before {
|
||||||
|
display: none;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
table td {
|
table td {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 182 KiB |
Binary file not shown.
Binary file not shown.
|
@ -181,6 +181,29 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildGraphs(node){
|
||||||
|
let graphs = node._graphs = node._graphs || {};
|
||||||
|
|
||||||
|
node.CheckStates.forEach(checkState => {
|
||||||
|
let checkName = checkState.CheckName;
|
||||||
|
|
||||||
|
checkState.PerformanceValues.forEach(performanceValue =>{
|
||||||
|
let groupName = checkName + " " + performanceValue.Group || "";
|
||||||
|
let perfUnit = performanceValue.PerfUnit || "";
|
||||||
|
|
||||||
|
if (!graphs[groupName])
|
||||||
|
graphs[groupName] = {}
|
||||||
|
|
||||||
|
if (!graphs[groupName][perfUnit])
|
||||||
|
graphs[groupName][perfUnit] = {}
|
||||||
|
|
||||||
|
graphs[groupName][perfUnit][performanceValue.PerfName] = performanceValue;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return graphs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,312 @@
|
||||||
SkyScanner.getInitializers().push(
|
SkyScanner.getInitializers().push(
|
||||||
new Promise((resolve,reject)=>{
|
new Promise((resolve, reject) => {
|
||||||
LN().load("/vue/ln.skyscanner.node.html").
|
LN().load("/vue/ln.skyscanner.node.html").
|
||||||
then((template)=>{
|
then((template) => {
|
||||||
skyScannerRoutes.push(
|
skyScannerRoutes.push(
|
||||||
{
|
{
|
||||||
path: "/vue/nodes/:nodeID",
|
path: "/vue/nodes/:nodeID",
|
||||||
component: {
|
component: {
|
||||||
template: template,
|
template: template,
|
||||||
data: function(){ return { node: null }; },
|
data: function () { return { node: null }; },
|
||||||
beforeRouteEnter: function(to,from,next){
|
beforeRouteEnter: function (to, from, next) {
|
||||||
next((vm)=>{
|
next((vm) => {
|
||||||
skyscanner.loadNode(to.params.nodeID,(node)=>{
|
skyscanner.loadNode(to.params.nodeID, (node) => {
|
||||||
vm.node = node;
|
vm.node = node;
|
||||||
}, 1000);
|
vm.$nextTick(() => {
|
||||||
});
|
skyscanner.buildGraphs(node);
|
||||||
|
loadGraphs(node);
|
||||||
|
});
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeRouteLeave: function (from, to, next) {
|
||||||
|
clearTimeout(skyscanner.currentTimeout);
|
||||||
|
next();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
beforeRouteLeave: function(from,to,next){
|
}
|
||||||
clearTimeout(skyscanner.currentTimeout);
|
);
|
||||||
next();
|
resolve();
|
||||||
},
|
});
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
function loadGraph(perfValue){
|
class ColorStack {
|
||||||
skyscanner.loadPerformanceGraph(perfValue.PerfPath,3600,(perfData)=>{
|
|
||||||
|
constructor() {
|
||||||
|
this.reset();
|
||||||
|
|
||||||
|
this.axColors = [
|
||||||
|
"#C0C0FF",
|
||||||
|
"#C040FF",
|
||||||
|
"#40C0FF",
|
||||||
|
"#4040FF",
|
||||||
|
"#C08080",
|
||||||
|
"#80C080",
|
||||||
|
"#808080"
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.resetRed()
|
||||||
|
this.resetYellow();
|
||||||
|
this.resetGreen();
|
||||||
|
this.resetBlue();
|
||||||
|
|
||||||
|
this.currentAxColor = 0;
|
||||||
|
}
|
||||||
|
resetRed() { this.currentRed = 208; }
|
||||||
|
resetYellow() { this.currentYellow = 208; }
|
||||||
|
resetGreen() { this.currentGreen = 208; }
|
||||||
|
resetBlue() { this.currentBlue = 208; }
|
||||||
|
|
||||||
|
toHex02(n) {
|
||||||
|
let sn = n.toString(16);
|
||||||
|
if (sn.length < 2)
|
||||||
|
sn = "0" + sn;
|
||||||
|
return sn;
|
||||||
|
}
|
||||||
|
|
||||||
|
toRGB(r, g, b) {
|
||||||
|
return "#" + this.toHex02(r) + this.toHex02(g) + this.toHex02(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
popRed() {
|
||||||
|
this.currentRed -= 16;
|
||||||
|
return this.toRGB(this.currentRed, 0, 0);
|
||||||
|
}
|
||||||
|
popYellow() {
|
||||||
|
this.currentYellow -= 16;
|
||||||
|
return this.toRGB(this.currentYellow, this.currentYellow, 0);
|
||||||
|
}
|
||||||
|
popGreen() {
|
||||||
|
this.currentGreen -= 16;
|
||||||
|
return this.toRGB(0, this.currentGreen, 0);
|
||||||
|
}
|
||||||
|
popBlue() {
|
||||||
|
this.currentBlue -= 16;
|
||||||
|
return this.toRGB(0, 0, this.currentBlue);
|
||||||
|
}
|
||||||
|
|
||||||
|
popAxColor() {
|
||||||
|
let axColor = this.axColors[this.currentAxColor];
|
||||||
|
this.currentAxColor = (this.currentAxColor + 1) % this.axColors.length;
|
||||||
|
return axColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(checkState) {
|
||||||
|
if (checkState == "CRITICAL")
|
||||||
|
return this.popRed();
|
||||||
|
if (checkState == "WARN")
|
||||||
|
return this.popYellow();
|
||||||
|
return this.popGreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorStackContainer {
|
||||||
|
constructor() {
|
||||||
|
this.colorStacks = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
getColorStack(graphName) {
|
||||||
|
if (!this.colorStacks.hasOwnProperty(graphName))
|
||||||
|
this.colorStacks[graphName] = new ColorStack();
|
||||||
|
|
||||||
|
return this.colorStacks[graphName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorContainer = new ColorStackContainer();
|
||||||
|
|
||||||
|
function toSI(value, perfUnit) {
|
||||||
|
if (perfUnit == "%"){
|
||||||
|
value = 100.0 * value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
let prefixes = { "12": "T", "9": "G", "6": "M", "3": "k", "0": " ", "-3": "m", "-6": "u", "-9": "n" }
|
||||||
|
let lg10 = Math.log10(Math.abs(value));
|
||||||
|
let nPrefix = Math.floor(lg10 / 3) * 3;
|
||||||
|
|
||||||
|
let nValue = value / Math.pow(10, nPrefix);
|
||||||
|
let prefix = prefixes[nPrefix] || `E${nPrefix}`;
|
||||||
|
|
||||||
|
return `${nValue}${prefix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGraphs(node) {
|
||||||
|
for (group in node._graphs) {
|
||||||
|
if (!node._graphs.hasOwnProperty(group)) continue;
|
||||||
|
|
||||||
|
let dataSets = [];
|
||||||
|
let yScales = [];
|
||||||
|
|
||||||
|
let perfValueDict = {};
|
||||||
|
|
||||||
|
for (perfUnit in node._graphs[group]) {
|
||||||
|
if (!node._graphs[group].hasOwnProperty(perfUnit)) continue;
|
||||||
|
|
||||||
|
let axColor = colorContainer.getColorStack(group).popAxColor();
|
||||||
|
let _perfUnit = perfUnit;
|
||||||
|
|
||||||
|
yScales.push({
|
||||||
|
display: true,
|
||||||
|
id: perfUnit,
|
||||||
|
scaleLabel: {
|
||||||
|
display: true,
|
||||||
|
labelString: perfUnit,
|
||||||
|
fontColor: axColor,
|
||||||
|
},
|
||||||
|
gridLines: {
|
||||||
|
color: axColor,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
callback: function (value, index, values) {
|
||||||
|
try {
|
||||||
|
return toSI(value, _perfUnit);
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (perfName in node._graphs[group][perfUnit]) {
|
||||||
|
if (!node._graphs[group][perfUnit].hasOwnProperty(perfName)) continue;
|
||||||
|
|
||||||
|
let perfValue = node._graphs[group][perfUnit][perfName];
|
||||||
|
let color = colorContainer.getColorStack(group).pop(perfValue.CheckState);
|
||||||
|
|
||||||
|
dataSets.push({
|
||||||
|
perfName: perfName,
|
||||||
|
perfUnit: perfUnit,
|
||||||
|
label: perfName + (perfUnit ? " [" + perfUnit + "]" : ""),
|
||||||
|
data: [],
|
||||||
|
borderColor: color,
|
||||||
|
backgroundColor: color,
|
||||||
|
fill: false,
|
||||||
|
yAxisID: perfUnit,
|
||||||
|
});
|
||||||
|
|
||||||
|
perfValueDict[perfName] = perfValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let chart = getOrCreateChart(`chart-${group}`, yScales, dataSets);
|
||||||
|
chart.options.title.text = `${group}`;
|
||||||
|
|
||||||
|
chart.data.datasets.forEach((dataSet) => {
|
||||||
|
console.log("dataSet: " + dataSet.perfName);
|
||||||
|
loadChartLine(chart, dataSet, perfValueDict[dataSet.perfName]);
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadChartLine(chart, dataSet, perfValue) {
|
||||||
|
console.log("loadChartLine()");
|
||||||
|
|
||||||
|
skyscanner.loadPerformanceGraph(perfValue.PerfPath, 3600, (perfData) => {
|
||||||
|
console.log("loadPerformaceGraph(): callback");
|
||||||
|
|
||||||
|
let chartColor = perfValue.CheckState == "CRITICAL" ? '#C00000' : (perfValue.CheckState == "WARN") ? '#C0C000' : '#008000';
|
||||||
|
let perfName = perfValue.PerfName;
|
||||||
|
|
||||||
|
dataSet.data.length = 0;
|
||||||
|
$.each(perfData, function () {
|
||||||
|
if (this.TimeStamp != 0)
|
||||||
|
dataSet.data.push({ x: this.TimeStamp, y: this.Value });
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrCreateChart(chartID, yAxes, datasets) {
|
||||||
|
var gDiv = $("#" + CSS.escape(chartID));
|
||||||
|
var chart = null;
|
||||||
|
|
||||||
|
if (!gDiv.length) {
|
||||||
|
gDiv = $("<div></div>").attr("id", chartID).css("height", "400px");
|
||||||
|
var canvas = $("<canvas></canvas>").appendTo(gDiv);
|
||||||
|
chart = new Chart(canvas, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
datasets,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: '-'
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
yAxes,
|
||||||
|
xAxes: [{
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: "minute",
|
||||||
|
tooltipFormat: "DD.MM.YYYY HH:mm",
|
||||||
|
displayFormats: {
|
||||||
|
minute: "DD.MM.YYYY HH:mm"
|
||||||
|
},
|
||||||
|
parser: moment.unix
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
cubicInterpolationMode: "monotone",
|
||||||
|
fill: false,
|
||||||
|
|
||||||
|
tooltips: {
|
||||||
|
callbacks: {
|
||||||
|
label: function(tooltipItem, data) {
|
||||||
|
let dataSet = data.datasets[tooltipItem.datasetIndex];
|
||||||
|
let value = tooltipItem.yLabel;
|
||||||
|
|
||||||
|
if (dataSet.perfUnit == "%")
|
||||||
|
{
|
||||||
|
value = value * 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let label = dataSet.label || '';
|
||||||
|
if (label) {
|
||||||
|
label += ': ';
|
||||||
|
}
|
||||||
|
label += toSI(value);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chart.data.labels.length = 0;
|
||||||
|
gDiv.data("chart", chart);
|
||||||
|
|
||||||
|
$("#graphs").append(gDiv);
|
||||||
|
} else {
|
||||||
|
chart = gDiv.data("chart");
|
||||||
|
}
|
||||||
|
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGraph(perfValue) {
|
||||||
|
skyscanner.loadPerformanceGraph(perfValue.PerfPath, 3600, (perfData) => {
|
||||||
var perfID = skyscanner.encodeID(perfValue.PerfName);
|
var perfID = skyscanner.encodeID(perfValue.PerfName);
|
||||||
var chartColor = perfValue.CheckState == "CRITICAL" ? '#C00000' : (perfValue.CheckState == "WARN") ? '#C0C000' : '#008000';
|
var chartColor = perfValue.CheckState == "CRITICAL" ? '#C00000' : (perfValue.CheckState == "WARN") ? '#C0C000' : '#008000';
|
||||||
|
|
||||||
var gDiv = $("#" + perfID);
|
var gDiv = $("#" + perfID);
|
||||||
var chart = null;
|
var chart = null;
|
||||||
|
|
||||||
if (!gDiv.length)
|
if (!gDiv.length) {
|
||||||
{
|
gDiv = $("<div></div>").attr("id", perfID).css("height", "400px");
|
||||||
gDiv = $("<div></div>").attr("id",perfID).css("height","400px");
|
|
||||||
var canvas = $("<canvas></canvas>").appendTo(gDiv);
|
var canvas = $("<canvas></canvas>").appendTo(gDiv);
|
||||||
chart = new Chart( canvas, {
|
chart = new Chart(canvas, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
datasets: [
|
datasets: [
|
||||||
|
@ -79,25 +346,24 @@ function loadGraph(perfValue){
|
||||||
cubicInterpolationMode: "monotone",
|
cubicInterpolationMode: "monotone",
|
||||||
fill: false,
|
fill: false,
|
||||||
}
|
}
|
||||||
} );
|
});
|
||||||
chart.data.labels.length = 0;
|
chart.data.labels.length = 0;
|
||||||
chart.data.datasets[0].data.length = 0;
|
chart.data.datasets[0].data.length = 0;
|
||||||
chart.data.datasets[0].label = perfValue.PerfName;
|
chart.data.datasets[0].label = perfValue.PerfName;
|
||||||
|
|
||||||
gDiv.data("chart",chart);
|
gDiv.data("chart", chart);
|
||||||
} else
|
} else {
|
||||||
{
|
|
||||||
chart = gDiv.data("chart");
|
chart = gDiv.data("chart");
|
||||||
}
|
}
|
||||||
|
|
||||||
chart.data.datasets[0].data.length = 0;
|
chart.data.datasets[0].data.length = 0;
|
||||||
$.each( perfData, function(){
|
$.each(perfData, function () {
|
||||||
if (this.TimeStamp != 0)
|
if (this.TimeStamp != 0)
|
||||||
chart.data.datasets[0].data.push( { x: this.TimeStamp, y: this.Value } );
|
chart.data.datasets[0].data.push({ x: this.TimeStamp, y: this.Value });
|
||||||
});
|
});
|
||||||
|
|
||||||
chart.update();
|
chart.update();
|
||||||
|
|
||||||
$("#graphs").append(gDiv);
|
$("#graphs").append(gDiv);
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
<tr
|
<tr
|
||||||
v-for="node in currentNodes"
|
v-for="node in currentNodes"
|
||||||
>
|
>
|
||||||
<td>{{ node.Name }}</td>
|
<td><router-link :to="'/vue/nodes/' + node.ID" target="_blank">{{ node.Name }}</router-link></td>
|
||||||
<td>{{ node.PrimaryIP }}</td>
|
<td>{{ node.PrimaryIP }}</td>
|
||||||
<td>{{ node.Vendor }}</td>
|
<td>{{ node.Vendor }}</td>
|
||||||
<td>{{ node.Product }}</td>
|
<td>{{ node.Product }}</td>
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
<td>System</td>
|
<td>System</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td style="width: 100px;"></td>
|
<td style="width: 100px;"></td>
|
||||||
<td style="width: 100px;"><button onclick="LN().rpc('','Shutdown',[],function(r,e){});">Shutdown</button></td>
|
<td style="width: 100px;">
|
||||||
|
<button onclick="LN().rpc('','Shutdown',[],function(r,e){});">Shutdown</button><br>
|
||||||
|
<button onclick="LN().rpc('entities','SyncSkytron',[],function(r,e){});">Sync Nodes</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Crawler</td>
|
<td>Crawler</td>
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
<link href="/css/jquery-ui.min.css" rel="stylesheet" />
|
<link href="/css/jquery-ui.min.css" rel="stylesheet" />
|
||||||
<link href="/css/datatables.min.css" rel="stylesheet" />
|
<link href="/css/datatables.min.css" rel="stylesheet" />
|
||||||
<link href="/css/Chart.min.css" rel="stylesheet" />
|
<link href="/css/Chart.min.css" rel="stylesheet" />
|
||||||
|
<link href="/css/typicons.css" rel="stylesheet"/>
|
||||||
|
|
||||||
<link href="/css/style.css" rel="stylesheet" />
|
<link href="/css/style.css" rel="stylesheet" />
|
||||||
<link href="/vue/page.layout.css" rel="stylesheet" />
|
<link href="/vue/page.layout.css" rel="stylesheet" />
|
||||||
<link href="/vue/tables.layout.css" rel="stylesheet" />
|
<link href="/vue/tables.layout.css" rel="stylesheet" />
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
v-for="route in skyScannerRoutes"
|
v-for="route in skyScannerRoutes"
|
||||||
v-if="route.label"
|
v-if="route.label"
|
||||||
v-bind:to="route.path"
|
v-bind:to="route.path"
|
||||||
|
class="plain"
|
||||||
>{{ route.label }}</router-link>
|
>{{ route.label }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue