Merge pull request #2848 from kc284/datasources

* DataSet field Uuid is not really a uuid. Renamed to Id to avoid misunderstandings.
* Renamed properties DataSet.Type and DataSourceItem.DataType to Category. The old name was not reflecting what they were.
* Renamed property DataSet.TypeString to DataSet.DataSourceName so it reflects better what it is.
* Renamed property DataSet.Name to DataSet.FriendlyName for clarity. Removed duplicate string.Format() call.
* The DataSourceItem.Uuid is not really a uuid. Renamed it to Id to avoid misunderstandings. Also, compacted DataSourceItem constructors.

* Removed unused and duplicate properties.
- DataKey.Hide was unused. Once removed, DataSet.Deselected was unused, hence was also removed.
- Dataset.Draw was duplicating DataSet.Show, hence was removed.
- DataSet.NeverShow is not necessary, DataSet.Hide can be used both for datasources
  that should not be shown at all as well as datasources that are wrong for this object.

* Made DataSet.FriendlyName a get-only property and compacted repetitive code.

* Use the Helpers regular expressions for assigning the datasource category.

* Removed id from the DataSet constructor parameters. It can be constructed from the XenObject and the datasource name.

* Compacted the code for readability (it was difficult to follow the build of the URIs).

Also, removed use of Helper.GetUuid to avoid the use of reflection. Minimised casts.

* CP-36567: Use the datasource units as specified in the API instead of deducing them from the datasource name.

- Also, merged static method DataSet.Create into the DataSet constructor.
- Minor restructuring of the ArchiveMaintainer file (moved all private fields
  and properties closer together).
- Added new resource file so the units can be separated from Messages.
This commit is contained in:
Konstantina Chremmou 2021-08-10 14:43:05 +01:00 committed by GitHub
commit af832f23cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 823 additions and 605 deletions

View File

@ -33,6 +33,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Xml;
@ -46,20 +47,6 @@ namespace XenAdmin.Controls.CustomDataGraph
public class ArchiveMaintainer
{
private delegate void ReaderDelegate(XmlReader reader, IXenObject xmo);
private delegate Uri URIDelegate(Session session, Host host, ArchiveInterval interval, IXenObject xmo);
internal const string RrdUpdatesPath = "rrd_updates";
private const string RrdHostPath = "host_rrds";
private const string RrdVmPath = "vm_rrds";
internal const string RrdCFAverage = "AVERAGE";
private const string RrdHostUpdatesQuery = "session_id={0}&start={1}&cf={2}&interval={3}&host=true&vm_uuid=";
internal const string RrdHostAndVmUpdatesQuery = "session_id={0}&start={1}&cf={2}&interval={3}&host=true";
private const string RrdVmUpdatesQuery = "session_id={0}&start={1}&cf={2}&interval={3}&vm_uuid={4}";
private const string RrdHostQuery = "session_id={0}";
private const string RrdVmQuery = "session_id={0}&uuid={1}";
private const long TicksInOneSecond = 10000000;
private const long TicksInFiveSeconds = 50000000;
internal const long TicksInTenSeconds = 100000000;
@ -119,8 +106,18 @@ namespace XenAdmin.Controls.CustomDataGraph
/// </summary>
private List<DataSet> SetsAdded;
private List<Data_source> _enabledDataSources = new List<Data_source>();
private IXenObject _xenObject;
private long EndTime;
private bool BailOut;
private long CurrentInterval;
private long StepSize;
private long CurrentTime;
private int ValueCount;
private string LastNode = "";
/// <summary>
/// Gui Thread
/// </summary>
@ -144,17 +141,13 @@ namespace XenAdmin.Controls.CustomDataGraph
public DateTime LastOneDayCollection = DateTime.MinValue;
public bool FirstTime = true;
public bool LoadingInitialData;
public bool LoadingInitialData = false;
private DateTime ServerNow => DateTime.UtcNow.Subtract(ClientServerOffset);
public TimeSpan ClientServerOffset
{
get
{
IXenObject m = XenObject;
return m == null ? TimeSpan.Zero : m.Connection.ServerTimeOffset;
}
}
public DateTime GraphNow => DateTime.Now - (ClientServerOffset + TimeSpan.FromSeconds(15));
public TimeSpan ClientServerOffset => XenObject?.Connection.ServerTimeOffset ?? TimeSpan.Zero;
public ArchiveMaintainer()
{
@ -176,9 +169,8 @@ namespace XenAdmin.Controls.CustomDataGraph
while (RunThread)
{
IXenObject xenObject = XenObject;
Host Host = GetHost(xenObject);
DateTime ServerWas = ServerNow(); // get time before updating so we don't miss any 5 second updates if getting the past data
DateTime serverWas = ServerNow; // get time before updating so we don't miss any 5 second updates if getting the past data
if (FirstTime)
{
@ -194,44 +186,58 @@ namespace XenAdmin.Controls.CustomDataGraph
Archives[ArchiveInterval.OneDay].MaxPoints = DaysInOneYear;
}
_enabledDataSources.Clear();
foreach (DataArchive a in Archives.Values)
a.ClearSets();
LoadingInitialData = true;
OnArchivesUpdated();
Get(ArchiveInterval.None, RrdsUri, RRD_Full_InspectCurrentNode, Host, xenObject);
LoadingInitialData = false;
OnArchivesUpdated();
try
{
LoadingInitialData = true;
ArchivesUpdated?.Invoke();
LastFiveSecondCollection = ServerWas;
LastOneMinuteCollection = ServerWas;
LastOneHourCollection = ServerWas;
LastOneDayCollection = ServerWas;
if (xenObject is Host h)
_enabledDataSources = Host.get_data_sources(h.Connection.Session, h.opaque_ref).Where(d => d.enabled).ToList();
else if (xenObject is VM vm && vm.power_state == vm_power_state.Running)
_enabledDataSources = VM.get_data_sources(vm.Connection.Session, vm.opaque_ref).Where(d => d.enabled).ToList();
Get(ArchiveInterval.None, RrdsUri, RRD_Full_InspectCurrentNode, xenObject);
}
finally
{
LoadingInitialData = false;
ArchivesUpdated?.Invoke();
}
LastFiveSecondCollection = serverWas;
LastOneMinuteCollection = serverWas;
LastOneHourCollection = serverWas;
LastOneDayCollection = serverWas;
FirstTime = false;
}
if (ServerWas - LastFiveSecondCollection > FiveSeconds)
if (serverWas - LastFiveSecondCollection > FiveSeconds)
{
GetUpdate(ArchiveInterval.FiveSecond, Host, xenObject);
LastFiveSecondCollection = ServerWas;
Get(ArchiveInterval.FiveSecond, UpdateUri, RRD_Update_InspectCurrentNode, xenObject);
LastFiveSecondCollection = serverWas;
Archives[ArchiveInterval.FiveSecond].Load(SetsAdded);
}
if (ServerWas - LastOneMinuteCollection > OneMinute)
if (serverWas - LastOneMinuteCollection > OneMinute)
{
GetUpdate(ArchiveInterval.OneMinute, Host, xenObject);
LastOneMinuteCollection = ServerWas;
Get(ArchiveInterval.OneMinute, UpdateUri, RRD_Update_InspectCurrentNode, xenObject);
LastOneMinuteCollection = serverWas;
Archives[ArchiveInterval.OneMinute].Load(SetsAdded);
}
if (ServerWas - LastOneHourCollection > OneHour)
if (serverWas - LastOneHourCollection > OneHour)
{
GetUpdate(ArchiveInterval.OneHour, Host, xenObject);
LastOneHourCollection = ServerWas;
Get(ArchiveInterval.OneHour, UpdateUri, RRD_Update_InspectCurrentNode, xenObject);
LastOneHourCollection = serverWas;
Archives[ArchiveInterval.OneHour].Load(SetsAdded);
}
if (ServerWas - LastOneDayCollection > OneDay)
if (serverWas - LastOneDayCollection > OneDay)
{
GetUpdate(ArchiveInterval.OneDay, Host, xenObject);
LastOneDayCollection = ServerWas;
Get(ArchiveInterval.OneDay, UpdateUri, RRD_Update_InspectCurrentNode, xenObject);
LastOneDayCollection = serverWas;
Archives[ArchiveInterval.OneDay].Load(SetsAdded);
}
@ -247,37 +253,16 @@ namespace XenAdmin.Controls.CustomDataGraph
}
}
/// <summary>
/// UpdaterThread Thread
/// </summary>
public DateTime ServerNow()
private void Get(ArchiveInterval interval, Func<ArchiveInterval, IXenObject, Uri> uriBuilder,
Action<XmlReader, IXenObject>Reader, IXenObject xenObject)
{
return DateTime.UtcNow.Subtract(ClientServerOffset);
}
/// <summary>
/// UpdaterThread Thread
/// </summary>
private void GetUpdate(ArchiveInterval interval, Host host, IXenObject xo)
{
Get(interval, UpdateUri, RRD_Update_InspectCurrentNode, host, xo);
}
/// <summary>
/// UpdaterThread Thread
/// </summary>
private void Get(ArchiveInterval interval, URIDelegate URI, ReaderDelegate Reader,
Host host, IXenObject xenObject)
{
if (host == null)
return;
try
{
Session session = xenObject.Connection.Session;
if (session == null)
var uri = uriBuilder(interval, xenObject);
if (uri == null)
return;
using (Stream httpstream = HTTPHelper.GET(URI(session, host, interval, xenObject), xenObject.Connection, true))
using (Stream httpstream = HTTPHelper.GET(uri, xenObject.Connection, true))
{
using (XmlReader reader = XmlReader.Create(httpstream))
{
@ -298,39 +283,62 @@ namespace XenAdmin.Controls.CustomDataGraph
}
}
/// <summary>
/// UpdaterThread Thread
/// </summary>
private Uri UpdateUri(Session session, Host host, ArchiveInterval interval, IXenObject xo)
private Uri UpdateUri(ArchiveInterval interval, IXenObject xo)
{
string query =
xo is Host ?
string.Format(RrdHostUpdatesQuery, Uri.EscapeDataString(session.opaque_ref), TimeFromInterval(interval), RrdCFAverage, ToSeconds(interval)) :
xo is VM ?
string.Format(RrdVmUpdatesQuery, Uri.EscapeDataString(session.opaque_ref), TimeFromInterval(interval), RrdCFAverage, ToSeconds(interval), Helpers.GetUuid(xo)) :
"";
return BuildUri(host, RrdUpdatesPath, query);
var sessionRef = xo?.Connection?.Session?.opaque_ref;
if (sessionRef == null)
return null;
var escapedRef = Uri.EscapeDataString(sessionRef);
var startTime = TimeFromInterval(interval);
var duration = ToSeconds(interval);
if (xo is Host host)
{
return BuildUri(host, "rrd_updates",
$"session_id={escapedRef}&start={startTime}&cf=AVERAGE&interval={duration}&host=true");
}
if (xo is VM vm)
{
var vmHost = vm.Connection.Resolve(vm.resident_on) ?? Helpers.GetMaster(vm.Connection);
BuildUri(vmHost, "rrd_updates",
$"session_id={escapedRef}&start={startTime}&cf=AVERAGE&interval={duration}&vm_uuid={vm.uuid}");
}
return null;
}
private static Uri RrdsUri(Session session, Host host, ArchiveInterval interval, IXenObject xo)
private static Uri RrdsUri(ArchiveInterval interval, IXenObject xo)
{
string query =
xo is Host ?
string.Format(RrdHostQuery, Uri.EscapeDataString(session.opaque_ref)) :
xo is VM ?
string.Format(RrdVmQuery, Uri.EscapeDataString(session.opaque_ref), Helpers.GetUuid(xo)) :
"";
return BuildUri(host, xo is Host ? RrdHostPath : RrdVmPath, query);
var sessionRef = xo.Connection.Session?.opaque_ref;
if (sessionRef == null)
return null;
var escapedRef = Uri.EscapeDataString(sessionRef);
if (xo is Host host)
return BuildUri(host, "host_rrds", $"session_id={escapedRef}");
if (xo is VM vm)
{
var vmHost = vm.Connection.Resolve(vm.resident_on) ?? Helpers.GetMaster(vm.Connection);
return BuildUri(vmHost, "vm_rrds", $"session_id={escapedRef}&uuid={vm.uuid}");
}
return null;
}
private static Uri BuildUri(Host host, string path, string query)
{
UriBuilder builder = new UriBuilder();
builder.Scheme = host.Connection.UriScheme;
builder.Host = host.address;
builder.Port = host.Connection.Port;
builder.Path = path;
builder.Query = query;
UriBuilder builder = new UriBuilder
{
Scheme = host.Connection.UriScheme,
Host = host.address,
Port = host.Connection.Port,
Path = path,
Query = query
};
return builder.Uri;
}
@ -395,15 +403,6 @@ namespace XenAdmin.Controls.CustomDataGraph
}
}
private long EndTime = 0;
private bool BailOut = false;
private long CurrentInterval = 0;
private long StepSize = 0;
/// <summary>
/// UpdaterThread Thread
/// </summary>
private void RRD_Full_InspectCurrentNode(XmlReader reader, IXenObject xmo)
{
if (reader.NodeType == XmlNodeType.Element)
@ -429,7 +428,7 @@ namespace XenAdmin.Controls.CustomDataGraph
ArchiveInterval i = GetArchiveIntervalFromFiveSecs(CurrentInterval);
if (i != ArchiveInterval.None)
Archives[i].CopyLoad(SetsAdded);
Archives[i].CopyLoad(SetsAdded, _enabledDataSources);
foreach (DataSet set in SetsAdded)
set.Points.Clear();
@ -443,8 +442,7 @@ namespace XenAdmin.Controls.CustomDataGraph
if (LastNode == "name")
{
string str = reader.ReadContentAsString();
string id = string.Format("{0}:{1}:{2}", xmo is Host ? "host" : "vm", Helpers.GetUuid(xmo), str);
SetsAdded.Add(DataSet.Create(id, xmo, true, str));
SetsAdded.Add(new DataSet(xmo, false, str, _enabledDataSources));
}
else if (LastNode == "step")
{
@ -472,7 +470,7 @@ namespace XenAdmin.Controls.CustomDataGraph
else if (LastNode == "cf")
{
string str = reader.ReadContentAsString();
if (str != RrdCFAverage)
if (str != "AVERAGE")
BailOut = true;
}
else if (LastNode == "v")
@ -482,19 +480,11 @@ namespace XenAdmin.Controls.CustomDataGraph
DataSet set = SetsAdded[ValueCount];
string str = reader.ReadContentAsString();
set.AddPoint(str, CurrentTime, SetsAdded);
set.AddPoint(str, CurrentTime, SetsAdded, _enabledDataSources);
ValueCount++;
}
}
private long CurrentTime = 0;
private int ValueCount;
private string LastNode = "";
/// <summary>
/// UpdaterThread Thread
/// </summary>
private void RRD_Update_InspectCurrentNode(XmlReader reader, IXenObject xo)
{
if (reader.NodeType == XmlNodeType.Element)
@ -509,7 +499,29 @@ namespace XenAdmin.Controls.CustomDataGraph
if (LastNode == "entry")
{
string str = reader.ReadContentAsString();
SetsAdded.Add(DataSet.Create(str, xo));
DataSet set = null;
if (DataSet.ParseId(str, out string objType, out string objUuid, out string dataSourceName))
{
if (objType == "host")
{
Host host = xo.Connection.Cache.Hosts.FirstOrDefault(h => h.uuid == objUuid);
if (host != null)
set = new DataSet(host, (xo as Host)?.uuid != objUuid, dataSourceName, _enabledDataSources);
}
if (objType == "vm")
{
VM vm = xo.Connection.Cache.VMs.FirstOrDefault(v => v.uuid == objUuid);
if (vm != null)
set = new DataSet(vm, (xo as VM)?.uuid != objUuid, dataSourceName, _enabledDataSources);
}
}
if (set == null)
set = new DataSet(null, true, str, _enabledDataSources);
SetsAdded.Add(set);
}
else if (LastNode == "t")
{
@ -521,7 +533,7 @@ namespace XenAdmin.Controls.CustomDataGraph
if (SetsAdded.Count <= ValueCount) return;
DataSet set = SetsAdded[ValueCount];
string str = reader.ReadContentAsString();
set.AddPoint(str, CurrentTime, SetsAdded);
set.AddPoint(str, CurrentTime, SetsAdded, _enabledDataSources);
ValueCount++;
}
}
@ -586,38 +598,5 @@ namespace XenAdmin.Controls.CustomDataGraph
return ArchiveInterval.None;
}
}
public DateTime GraphNow
{
get
{
return DateTime.Now - (ClientServerOffset + TimeSpan.FromSeconds(15));
}
}
private static Host GetHost(IXenObject xmo)
{
if (xmo is Host)
{
return (Host)xmo;
}
else if (xmo is VM)
{
VM vm = (VM)xmo;
return xmo.Connection.Resolve(vm.resident_on) ?? Helpers.GetMaster(xmo.Connection);
}
else
{
System.Diagnostics.Trace.Assert(false);
return null;
}
}
private void OnArchivesUpdated()
{
if (ArchivesUpdated != null)
ArchivesUpdated();
}
}
}

View File

@ -31,6 +31,7 @@
using System.Collections.Generic;
using System.Linq;
using XenAPI;
namespace XenAdmin.Controls.CustomDataGraph
{
@ -68,7 +69,7 @@ namespace XenAdmin.Controls.CustomDataGraph
set.Points.Sort();
var other = Sets.FirstOrDefault(s => s.Uuid == set.Uuid);
var other = Sets.FirstOrDefault(s => s.Id == set.Id);
if (other == null)
{
@ -101,16 +102,15 @@ namespace XenAdmin.Controls.CustomDataGraph
/// <summary>
/// Asserts off the event thread, for use when copying off the updater thread. Invokes onto event thread to update the sets safely.
/// </summary>
/// <param name="SetsAdded"></param>
internal void CopyLoad(List<DataSet> SetsAdded)
internal void CopyLoad(List<DataSet> setsAdded, List<Data_source> datasources)
{
Program.AssertOffEventThread();
if (SetsAdded == null)
if (setsAdded == null)
return;
foreach (DataSet set in SetsAdded)
foreach (DataSet set in setsAdded)
{
Palette.LoadSetColor(set);
DataSet copy = DataSet.Create(set.Uuid, set.XenObject, set.Show, set.TypeString);
DataSet copy = new DataSet(set.XenObject, set.Hide, set.DataSourceName, datasources);
foreach (DataPoint p in set.Points)
copy.AddPoint(new DataPoint(p.X,p.Y));

View File

@ -80,7 +80,7 @@ namespace XenAdmin.Controls.CustomDataGraph
lock (Palette.PaletteLock)
{
using (var thickPen = Palette.CreatePen(item.Sets[ArchiveInterval.FiveSecond].Uuid, Palette.PEN_THICKNESS_THICK))
using (var thickPen = Palette.CreatePen(item.Sets[ArchiveInterval.FiveSecond].Id, Palette.PEN_THICKNESS_THICK))
{
e.Graphics.DrawLine(thickPen,
new Point(e.Bounds.Left + 2, e.Bounds.Top + e.Bounds.Height / 2),
@ -116,7 +116,7 @@ namespace XenAdmin.Controls.CustomDataGraph
{
var wrapper = new DataSetCollectionWrapper();
if (!DataSourceUUIDsToShow.Contains(fivesecond.Uuid))
if (!DataSourceUUIDsToShow.Contains(fivesecond.Id))
continue;
wrapper.Sets.Add(ArchiveInterval.FiveSecond, fivesecond);
@ -124,7 +124,7 @@ namespace XenAdmin.Controls.CustomDataGraph
foreach (var interval in intervals)
{
var found = archives[interval].Sets.FirstOrDefault(s => s.Uuid == fivesecond.Uuid);
var found = archives[interval].Sets.FirstOrDefault(s => s.Id == fivesecond.Id);
if (found != null)
wrapper.Sets.Add(interval, found);
}
@ -263,15 +263,7 @@ namespace XenAdmin.Controls.CustomDataGraph
public void SelectDataSet(DataSet set)
{
SelectedItem = SelectWrapperFromUuid(set.Uuid);
}
public DataSetCollectionWrapper SelectWrapperFromUuid(string uuid)
{
return CurrentKeys.Find(new Predicate<DataSetCollectionWrapper>(delegate(DataSetCollectionWrapper item)
{
return item.Uuid == uuid;
}));
SelectedItem = CurrentKeys.Find(item => item.Id == set.Id);
}
protected override void OnPaint(PaintEventArgs e)
@ -290,7 +282,6 @@ namespace XenAdmin.Controls.CustomDataGraph
public Dictionary<ArchiveInterval, DataSet> Sets = new Dictionary<ArchiveInterval, DataSet>();
private bool _selected;
private bool _hide;
public bool Selected
{
@ -305,19 +296,6 @@ namespace XenAdmin.Controls.CustomDataGraph
}
}
public bool Hide
{
get { return _hide; }
set
{
_hide = value;
foreach (DataSet set in Sets.Values)
{
set.Deselected = value;
}
}
}
public DataRange YRange
{
get
@ -337,7 +315,7 @@ namespace XenAdmin.Controls.CustomDataGraph
if (!Sets.ContainsKey(ArchiveInterval.FiveSecond))
return false;
return Sets[ArchiveInterval.FiveSecond].Show;
return !Sets[ArchiveInterval.FiveSecond].Hide;
}
}
@ -346,14 +324,14 @@ namespace XenAdmin.Controls.CustomDataGraph
}
public string Uuid
public string Id
{
get
{
if (!Sets.ContainsKey(ArchiveInterval.FiveSecond))
return base.ToString();
return Sets[ArchiveInterval.FiveSecond].Uuid;
return Sets[ArchiveInterval.FiveSecond].Id;
}
}
@ -367,7 +345,7 @@ namespace XenAdmin.Controls.CustomDataGraph
public bool Equals(DataSetCollectionWrapper other)
{
return Uuid.Equals(other.Uuid);
return Id.Equals(other?.Id);
}
public int CompareTo(DataSetCollectionWrapper other)

View File

@ -263,7 +263,7 @@ namespace XenAdmin.Controls.CustomDataGraph
bool require_tools = true;
foreach (DataSetCollectionWrapper set in DataKey.CurrentKeys)
{
if (set.Sets[ArchiveInterval.FiveSecond].TypeString != "memory")
if (set.Sets[ArchiveInterval.FiveSecond].DataSourceName != "memory")
{
require_tools = false;
break;
@ -280,7 +280,7 @@ namespace XenAdmin.Controls.CustomDataGraph
// Refresh all sets
foreach (DataSet set in DataPlotNav.CurrentArchive.Sets.ToArray())
{
if (!set.Draw || !DataKey.DataSourceUUIDsToShow.Contains(set.Uuid))
if (set.Hide || !DataKey.DataSourceUUIDsToShow.Contains(set.Id))
continue;
List<DataPoint> todraw;
@ -363,16 +363,16 @@ namespace XenAdmin.Controls.CustomDataGraph
Array.Reverse(sets_to_show);
foreach (DataSet set in sets_to_show)
{
if (!set.Draw || DataKey == null || !DataKey.DataSourceUUIDsToShow.Contains(set.Uuid))
if (set.Hide || DataKey == null || !DataKey.DataSourceUUIDsToShow.Contains(set.Id))
continue;
lock (Palette.PaletteLock)
{
using (var thickPen = Palette.CreatePen(set.Uuid, Palette.PEN_THICKNESS_THICK))
using (var thickPen = Palette.CreatePen(set.Id, Palette.PEN_THICKNESS_THICK))
{
using (var normalPen = Palette.CreatePen(set.Uuid, Palette.PEN_THICKNESS_NORMAL))
using (var normalPen = Palette.CreatePen(set.Id, Palette.PEN_THICKNESS_NORMAL))
{
using (var shadowBrush = Palette.CreateBrush(set.Uuid))
using (var shadowBrush = Palette.CreateBrush(set.Id))
{
LineRenderer.Render(paintEventArgs.Graphics, SlightlySmaller, DataPlotNav.XRange, set.CustomYRange ?? SelectedYRange, set.Selected ? thickPen : normalPen, shadowBrush, set.CurrentlyDisplayed, true);
}
@ -387,8 +387,10 @@ namespace XenAdmin.Controls.CustomDataGraph
SizeF labelsize = new SizeF(0,0);
if (SelectedPoint != null && DataKey.SelectedDataSet != null)
{
string label = string.Format(string.Format("{0} - {1} = {2}", DataPlotNav.XRange.GetString(SelectedPoint.X + ArchiveMaintainer.ClientServerOffset.Ticks), DataKey.SelectedDataSet.Name,
SelectedPoint.Y >= 0 ? SelectedYRange.GetString(SelectedPoint.Y) : Messages.GRAPHS_NO_DATA));
string label = string.Format("{0} - {1} = {2}",
DataPlotNav.XRange.GetString(SelectedPoint.X + ArchiveMaintainer.ClientServerOffset.Ticks),
DataKey.SelectedDataSet.FriendlyName,
SelectedPoint.Y >= 0 ? SelectedYRange.GetString(SelectedPoint.Y) : Messages.GRAPHS_NO_DATA);
labelsize = paintEventArgs.Graphics.MeasureString(label,Palette.LabelFont);
paintEventArgs.Graphics.DrawString(label, Palette.LabelFont, Palette.LabelBrush, SlightlySmaller.Right - labelsize.Width, SlightlySmaller.Top - (labelsize.Height + 1));
}
@ -533,7 +535,7 @@ namespace XenAdmin.Controls.CustomDataGraph
{
foreach (DataSet set in DataPlotNav.CurrentArchive.Sets.ToArray())
{
if (!set.Draw || DataKey == null || !DataKey.DataSourceUUIDsToShow.Contains(set.Uuid))
if (set.Hide || DataKey == null || !DataKey.DataSourceUUIDsToShow.Contains(set.Id))
continue;
if (set.OnMouseClick(new MouseActionArgs(e.Location, GraphRectangle(), DataPlotNav.XRange, SelectedYRange)))
{

View File

@ -479,7 +479,7 @@ namespace XenAdmin.Controls.CustomDataGraph
foreach (DataSet set in ScrollWideArchive.Sets.ToArray())
{
if (!set.Draw || !DisplayedUuids.Contains(set.Uuid))
if (set.Hide || !DisplayedUuids.Contains(set.Id))
continue;
List<DataPoint> todraw;
@ -520,12 +520,12 @@ namespace XenAdmin.Controls.CustomDataGraph
foreach (DataSet set in ScrollWideArchive.Sets.ToArray())
{
if (!set.Draw || !DisplayedUuids.Contains(set.Uuid))
if (set.Hide || !DisplayedUuids.Contains(set.Id))
continue;
lock (Palette.PaletteLock)
{
using (var normalPen = Palette.CreatePen(set.Uuid, Palette.PEN_THICKNESS_NORMAL))
using (var normalPen = Palette.CreatePen(set.Id, Palette.PEN_THICKNESS_NORMAL))
{
LineRenderer.Render(paintEventArgs.Graphics, ScrollViewRectangle, everything, set.CustomYRange, normalPen, null, set.CurrentlyDisplayed, false);
}

View File

@ -100,6 +100,8 @@ namespace XenAdmin.Controls.CustomDataGraph
return Util.NanoSecondsString(constrVal);
case Unit.CountsPerSecond:
return Util.CountsPerSecondString(constrVal);
case Unit.SecondsPerSecond:
return Util.SecondsPerSecondString(constrVal);
case Unit.MilliWatt:
return Util.MilliWattString(constrVal);
case Unit.Centigrade:
@ -135,6 +137,8 @@ namespace XenAdmin.Controls.CustomDataGraph
return unit;
case Unit.CountsPerSecond:
return Messages.COUNTS_PER_SEC_UNIT;
case Unit.SecondsPerSecond:
return UnitStrings.SEC_PER_SEC_UNIT;
case Unit.Centigrade:
return "\u2103";
case Unit.MilliWatt:
@ -170,6 +174,7 @@ namespace XenAdmin.Controls.CustomDataGraph
case Unit.MegaHertz:
return Util.MegaHertzValue(constrVal, out unit);
case Unit.CountsPerSecond://fall through
case Unit.SecondsPerSecond://fall through
default:
return constrVal.ToString();
}
@ -201,6 +206,7 @@ namespace XenAdmin.Controls.CustomDataGraph
case Unit.Percentage:
case Unit.NanoSeconds:
case Unit.CountsPerSecond:
case Unit.SecondsPerSecond:
case Unit.MilliWatt:
case Unit.Centigrade:
case Unit.MegaHertz:
@ -257,5 +263,17 @@ namespace XenAdmin.Controls.CustomDataGraph
public enum RangeScaleMode { Fixed, Auto, Delegate }
public enum Unit { None, Percentage, BytesPerSecond, Bytes, NanoSeconds, CountsPerSecond, MilliWatt, Centigrade, MegaHertz }
public enum Unit
{
None,
Percentage,
BytesPerSecond,
Bytes,
NanoSeconds,
CountsPerSecond,
SecondsPerSecond,
MilliWatt,
Centigrade,
MegaHertz
}
}

View File

@ -43,329 +43,143 @@ namespace XenAdmin.Controls.CustomDataGraph
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private const int NegativeValue = -1;
/// <summary>
/// Things can only be added to the beginning or end of this list; it should
/// be sorted by X co-ordinate (which will be larger at the beginning of the list)
/// </summary>
public List<DataPoint> Points = new List<DataPoint>();
public string Name;
public bool Selected;
public List<DataPoint> CurrentlyDisplayed = new List<DataPoint>();
public IXenObject XenObject;
public string Uuid;
private bool _hide;
private bool _deselected;
/// <summary>
/// A guess at the data type
/// </summary>
public DataType Type;
/// <summary>
/// What it really is
/// </summary>
public string TypeString;
private const int NegativeValue = -1;
public readonly string Id = "";
public string DataSourceName;
public string FriendlyName { get; }
private int MultiplyingFactor = 1;
public DataRange CustomYRange = new DataRange(1, 0, 1, Unit.None, RangeScaleMode.Auto);
public bool Hide { get; }
/// <summary>
/// Can show in the lisbox
/// </summary>
public bool Show
{
get { return !_hide && !NeverShow; }
}
/// <summary>
/// This dataset is of the wrong xenobject
/// </summary>
public bool Hide
{
get { return _hide; }
set { _hide = value; }
}
/// <summary>
/// The user has chosen not to show this graph
/// </summary>
public bool Deselected
{
get { return _deselected; }
set { _deselected = value; }
}
/// <summary>
/// Never ever draw on graph or put in listbox
/// </summary>
private bool NeverShow { get; set; }
/// <summary>
/// Can draw on graph
/// </summary>
public bool Draw
{
get { return !_hide && !NeverShow && !_deselected; }
}
public DataRange CustomYRange;
private DataSet(string uuid, IXenObject xo, bool show, string settype)
public DataSet(IXenObject xo, bool hide, string datasourceName, List<Data_source> datasources)
{
XenObject = xo;
_hide = !show;
Uuid = uuid;
TypeString = settype;
Name = Helpers.GetFriendlyDataSourceName(settype, XenObject);
}
Hide = datasourceName == "xapi_open_fds" ||
datasourceName == "pool_task_count" ||
datasourceName == "pool_session_count" ||
datasourceName == "memory" ||
datasourceName == "memory_total_kib" || hide;
#region Static methods
DataSourceName = datasourceName;
public static DataSet Create(string uuid, IXenObject xo, bool show, string settype)
{
var dataSet = new DataSet(uuid, xo, show, settype);
if(settype == "xapi_open_fds" || settype == "pool_task_count" || settype == "pool_session_count")
{
dataSet.NeverShow = true;
}
if (settype.StartsWith("latency") || settype.EndsWith("latency"))
{
if (settype.StartsWith("latency_") || settype.StartsWith("read_latency_") ||
settype.StartsWith("write_latency_") || settype.StartsWith("vbd"))
{
//if it's storage or vbd latency xapi units are in microseconds
dataSet.MultiplyingFactor = 1000;
}
else
{
//otherwise they are in seconds
dataSet.MultiplyingFactor = 1000000000;
}
if (xo is Host host)
Id = $"host:{host.uuid}:{datasourceName}";
else if (xo is VM vm)
Id = $"vm:{vm.uuid}:{datasourceName}";
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.NanoSeconds, RangeScaleMode.Auto);
dataSet.Type = DataType.Latency;
}
else if (settype.StartsWith("vif") || settype.StartsWith("pif"))
{
//xapi units are in bytes/sec or errors/sec
Unit unit = settype.EndsWith("errors") ? Unit.CountsPerSecond : Unit.BytesPerSecond;
dataSet.CustomYRange = new DataRange(1, 0, 1, unit, RangeScaleMode.Auto);
dataSet.Type = DataType.Network;
}
else if (settype.StartsWith("vbd"))
{
if (settype.Contains("iops"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.CountsPerSecond, RangeScaleMode.Auto);
else if (settype.Contains("io_throughput"))
{
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
dataSet.MultiplyingFactor = (int)Util.BINARY_MEGA; //xapi units are in mebibytes/sec
}
else if (settype.EndsWith("iowait"))
{
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Auto);
dataSet.MultiplyingFactor = 100;
}
else if (settype.EndsWith("inflight") || settype.EndsWith("avgqu_sz"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.None, RangeScaleMode.Auto);
else
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
dataSet.Type = DataType.Disk;
}
else if ((settype.Contains("memory") || settype.Contains("allocation")) && !settype.Contains("utilisation"))
{
dataSet.Type = settype.Contains("gpu") ? DataType.Gpu : DataType.Memory;
dataSet.MultiplyingFactor = settype.Contains("kib") || settype == "memory_internal_free"
? (int)Util.BINARY_KILO
: 1;
if (settype == "memory" || settype == "memory_total_kib")
{
dataSet.NeverShow = true;
}
else if (settype == "memory_free_kib" && xo is Host)
{
dataSet.Name = Helpers.GetFriendlyDataSourceName("memory_used_kib", dataSet.XenObject);
Host host = (Host)xo;
Host_metrics metrics = host.Connection.Resolve(host.metrics);
long max = metrics != null ? metrics.memory_total : 100;
dataSet.CustomYRange = new DataRange(max, 0, max / 10d, Unit.Bytes, RangeScaleMode.Delegate)
{
UpdateMax = dataSet.GetMemoryMax,
UpdateResolution = dataSet.GetMemoryResolution
};
}
else if (settype == "memory_internal_free" && xo is VM)
{
dataSet.Name = Helpers.GetFriendlyDataSourceName("memory_internal_used", dataSet.XenObject);
VM vm = (VM)xo;
VM_metrics metrics = vm.Connection.Resolve(vm.metrics);
long max = metrics != null ? metrics.memory_actual : (long)vm.memory_dynamic_max;
dataSet.CustomYRange = new DataRange(max, 0, max / 10d, Unit.Bytes, RangeScaleMode.Delegate)
{
UpdateMax = dataSet.GetMemoryMax,
UpdateResolution = dataSet.GetMemoryResolution
};
}
else
{
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.Bytes, RangeScaleMode.Auto);
}
}
else if (settype.StartsWith("loadavg"))
{
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Auto);
dataSet.MultiplyingFactor = 100;
dataSet.Type = DataType.LoadAverage;
}
else if (settype.EndsWith("-avg-freq"))
{
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.MegaHertz, RangeScaleMode.Auto);
dataSet.Type = DataType.Cpu;
}
else if (settype.StartsWith("cpu") || settype == "avg_cpu" || settype.StartsWith("runstate"))
{
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Fixed);
dataSet.MultiplyingFactor = 100;
dataSet.Type = DataType.Cpu;
}
else if (settype.StartsWith("io_throughput"))
{
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
dataSet.MultiplyingFactor = (int)Util.BINARY_MEGA; //xapi units are in mebibytes/sec
dataSet.Type = DataType.Storage;
}
else if (settype.StartsWith("sr"))
{
dataSet.Type = DataType.Storage;
if (settype.EndsWith("cache_size"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.Bytes, RangeScaleMode.Auto);
else if (settype.EndsWith("cache_hits") || settype.EndsWith("cache_misses"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.CountsPerSecond, RangeScaleMode.Auto);
}
else if (settype.StartsWith("iops"))
{
//xapi units are in requests/sec
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.CountsPerSecond, RangeScaleMode.Auto);
dataSet.Type = DataType.Storage;
}
else if (settype.StartsWith("iowait"))
{
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Auto);
dataSet.MultiplyingFactor = 100;
dataSet.Type = DataType.Storage;
}
else if (settype.StartsWith("inflight") || settype.StartsWith("avgqu_sz"))
{
//xapi units are in requests
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.None, RangeScaleMode.Auto);
dataSet.Type = DataType.Storage;
}
else if (settype.StartsWith("gpu"))
{
if (settype.Contains("power_usage"))
{
//xapi units are in mW
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.MilliWatt, RangeScaleMode.Auto);
}
else if (settype.Contains("temperature"))
{
//xapi units are in Centigrade
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.Centigrade, RangeScaleMode.Auto);
}
else if (settype.Contains("utilisation"))
{
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Fixed);
dataSet.MultiplyingFactor = 100;
}
dataSet.Type = DataType.Gpu;
}
else if (settype.StartsWith("pvsaccelerator"))
{
if (settype.Contains("traffic") || settype.EndsWith("evicted"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
else if (settype.EndsWith("read_total") || settype.EndsWith("read_hits") || settype.EndsWith("read_misses"))
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.CountsPerSecond, RangeScaleMode.Auto);
else if (settype.Contains("utilization"))
dataSet.CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Fixed); // values range from 0 to 100
else
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.None, RangeScaleMode.Auto);
dataSet.Type = DataType.Pvs;
}
else if (settype.StartsWith("read_latency") || settype.StartsWith("write_latency"))
{
// Units are microseconds
dataSet.MultiplyingFactor = 1000;
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.NanoSeconds, RangeScaleMode.Auto);
dataSet.Type = DataType.Latency;
}
else if (settype.StartsWith("read") || settype.StartsWith("write"))
{
// Units are Bytes/second
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
dataSet.Type = DataType.Storage;
}
if (datasourceName == "memory_free_kib")
FriendlyName = Helpers.GetFriendlyDataSourceName("memory_used_kib", xo);
else if (datasourceName == "memory_internal_free")
FriendlyName = Helpers.GetFriendlyDataSourceName("memory_internal_used", xo);
else
FriendlyName = Helpers.GetFriendlyDataSourceName(datasourceName, xo);
var units = datasources.FirstOrDefault(d => datasourceName.StartsWith(d.name_label))?.units;
switch (units)
{
dataSet.CustomYRange = new DataRange(1, 0, 1, Unit.None, RangeScaleMode.Auto);
dataSet.Type = DataType.Custom;
case "count":
case "requests":
case "sessions":
case "tasks":
case "file descriptors":
break;
case "(fraction)":
//CP-34000: use Auto instead of Fixed scale
CustomYRange = new DataRange(100, 0, 10, Unit.Percentage, RangeScaleMode.Auto);
MultiplyingFactor = 100;
break;
case "MHz":
CustomYRange = new DataRange(1, 0, 1, Unit.MegaHertz, RangeScaleMode.Auto);
break;
case "requests/s":
case "err/s":
CustomYRange = new DataRange(1, 0, 1, Unit.CountsPerSecond, RangeScaleMode.Auto);
break;
case "s/s":
CustomYRange = new DataRange(1, 0, 1, Unit.SecondsPerSecond, RangeScaleMode.Auto);
break;
case "s":
CustomYRange = new DataRange(1, 0, 1, Unit.NanoSeconds, RangeScaleMode.Auto);
MultiplyingFactor = (int)Util.DEC_GIGA;
break;
case "ms":
CustomYRange = new DataRange(1, 0, 1, Unit.NanoSeconds, RangeScaleMode.Auto);
MultiplyingFactor = (int)Util.DEC_MEGA;
break;
case "μs":
CustomYRange = new DataRange(1, 0, 1, Unit.NanoSeconds, RangeScaleMode.Auto);
MultiplyingFactor = (int)Util.DEC_KILO;
break;
case "B":
CustomYRange = new DataRange(1, 0, 1, Unit.Bytes, RangeScaleMode.Auto);
break;
case "KiB":
CustomYRange = new DataRange(1, 0, 1, Unit.Bytes, RangeScaleMode.Auto);
MultiplyingFactor = (int)Util.BINARY_KILO;
break;
case "B/s":
CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
break;
case "MiB/s":
MultiplyingFactor = (int)Util.BINARY_MEGA;
CustomYRange = new DataRange(1, 0, 1, Unit.BytesPerSecond, RangeScaleMode.Auto);
break;
case "mW":
CustomYRange = new DataRange(1, 0, 1, Unit.MilliWatt, RangeScaleMode.Auto);
break;
case "Centigrade":
CustomYRange = new DataRange(1, 0, 1, Unit.Centigrade, RangeScaleMode.Auto);
break;
default:
if (!string.IsNullOrEmpty(units))
System.Diagnostics.Debug.Assert(false, $"Unhandled units {units}!");
break;
}
return dataSet;
if (datasourceName == "memory_free_kib" || datasourceName == "memory_internal_free")
{
var max = GetMemoryMax(xo);
var resolution = GetMemoryResolution(max);
CustomYRange = new DataRange(max, 0, resolution, Unit.Bytes, RangeScaleMode.Delegate)
{
UpdateMax = GetMemoryMax,
UpdateResolution = GetMemoryResolution
};
}
}
public static DataSet Create(string id, IXenObject xenObject)
public static bool ParseId(string id, out string objType, out string objUuid, out string dataSourceName)
{
string[] bits = id.Split(':');
if (bits.Length < 3)
return Create(id, null, false, id);
var bits = id.Split(':').ToList();
string theId;
string theObjType;
string theUuid;
string theDataName;
if (bits.Count > 3)
bits.RemoveAt(0);
if (bits.Length == 4)
if (bits.Count >= 3)
{
string[] important_bits = new string[3];
Array.Copy(bits, 1, important_bits, 0, 3);
theId = string.Join(":", important_bits);
theObjType = bits[1];
theUuid = bits[2];
theDataName = bits[3];
}
else
{
theId = id;
theObjType = bits[0];
theUuid = bits[1];
theDataName = bits[2];
objType = bits[0];
objUuid = bits[1];
dataSourceName = bits[2];
return true;
}
if (theObjType == "host")
{
Host host = xenObject.Connection.Cache.Find_By_Uuid<Host>(theUuid);
if (host != null)
return Create(theId, host, (xenObject is Host && ((Host)xenObject).uuid == theUuid), theDataName);
}
if (theObjType == "vm")
{
VM vm = xenObject.Connection.Cache.Find_By_Uuid<VM>(theUuid);
if (vm != null)
return Create(theId, vm, (xenObject is VM && ((VM)xenObject).uuid == theUuid), theDataName);
}
return Create(id, null, false, id);
objType = null;
objUuid = null;
dataSourceName = null;
return false;
}
#endregion
public List<DataPoint> GetRange(DataTimeRange xrange, long intervalneed, long intervalat)
{
List<DataPoint> fine = BinaryChop(Points, xrange);
@ -396,38 +210,25 @@ namespace XenAdmin.Controls.CustomDataGraph
return listout;
}
private double GetMemoryMax(IXenObject xo)
private static double GetMemoryMax(IXenObject xo)
{
if (xo is Host)
{
Host host = (Host)xo;
Host_metrics metrics = host.Connection.Resolve(host.metrics);
return metrics != null ? metrics.memory_total : 100;
}
else if (xo is VM)
{
VM vm = (VM)xo;
VM_metrics metrics = vm.Connection.Resolve(vm.metrics);
return metrics != null ? metrics.memory_actual : vm.memory_dynamic_max;
}
if (xo is Host host)
return host.Connection.Resolve(host.metrics)?.memory_total ?? 100;
if (xo is VM vm)
return (vm.Connection.Resolve(vm.metrics))?.memory_actual ?? vm.memory_dynamic_max;
return 100;
}
private double GetMemoryResolution(IXenObject xmo)
private static double GetMemoryResolution(IXenObject xmo)
{
if (xmo is Host)
{
Host host = (Host)xmo;
Host_metrics metrics = host.Connection.Resolve(host.metrics);
return metrics != null ? metrics.memory_total / 10 : 10;
}
else if (xmo is VM)
{
VM vm = (VM)xmo;
VM_metrics metrics = vm.Connection.Resolve(vm.metrics);
return ((metrics != null ? metrics.memory_actual : (long)vm.memory_dynamic_max) / 10d);
}
return 10;
return GetMemoryMax(xmo) / 10d;
}
private static double GetMemoryResolution(double max)
{
return max / 10d;
}
public static double GetMaxY(List<DataPoint> dataPoints)
@ -494,13 +295,11 @@ namespace XenAdmin.Controls.CustomDataGraph
public override string ToString()
{
return Name;
return FriendlyName;
}
public DataPoint OnMouseMove(MouseActionArgs args)
{
if (Deselected)
return null;
LongPoint p = LongPoint.DeTranslateFromScreen(new LongPoint(args.Point), args.XRange, args.YRange, new LongRectangle(args.Rectangle));
return ClosestPointTo(p);
}
@ -540,7 +339,7 @@ namespace XenAdmin.Controls.CustomDataGraph
return poly.Contains(new LongPoint(args.Point));
}
public void AddPoint(string str, long currentTime, List<DataSet> setsAdded)
public void AddPoint(string str, long currentTime, List<DataSet> setsAdded, List<Data_source> dataSources)
{
double value = Helpers.StringToDouble(str);
bool isNanOrInfinity = double.IsNaN(value) || double.IsInfinity(value);
@ -551,12 +350,12 @@ namespace XenAdmin.Controls.CustomDataGraph
var matchDelegate = new Func<string, bool>(s => Helpers.CpuRegex.IsMatch(s) &&
!Helpers.CpuStateRegex.IsMatch(s));
if (matchDelegate(TypeString))
if (matchDelegate(DataSourceName))
{
DataSet other = setsAdded.FirstOrDefault(s => s.TypeString == "avg_cpu");
DataSet other = setsAdded.FirstOrDefault(s => s.DataSourceName == "avg_cpu");
if (other == null)
{
other = Create(Palette.GetUuid("avg_cpu", XenObject), XenObject, true, "avg_cpu");
other = new DataSet(XenObject, false, "avg_cpu", dataSources);
setsAdded.Add(other);
}
@ -575,7 +374,7 @@ namespace XenAdmin.Controls.CustomDataGraph
foreach (DataSet s in setsAdded)
{
if (matchDelegate(s.TypeString) && s.GetPointAt(currentTime) != null && s != this)
if (matchDelegate(s.DataSourceName) && s.GetPointAt(currentTime) != null && s != this)
cpu_vals_added++;
}
@ -587,9 +386,9 @@ namespace XenAdmin.Controls.CustomDataGraph
#region memory
if (TypeString == "memory_total_kib")
if (DataSourceName == "memory_total_kib")
{
DataSet other = setsAdded.FirstOrDefault(s => s.TypeString == "memory_free_kib");
DataSet other = setsAdded.FirstOrDefault(s => s.DataSourceName == "memory_free_kib");
if (other != null && other.Points.Count - 1 == Points.Count)
{
yValue = isNanOrInfinity || other.Points[other.Points.Count - 1].Y < 0
@ -598,9 +397,9 @@ namespace XenAdmin.Controls.CustomDataGraph
other.Points[other.Points.Count - 1].Y = yValue;
}
}
else if (TypeString == "memory_free_kib")
else if (DataSourceName == "memory_free_kib")
{
DataSet other = setsAdded.FirstOrDefault(s => s.TypeString == "memory_total_kib");
DataSet other = setsAdded.FirstOrDefault(s => s.DataSourceName == "memory_total_kib");
if (other != null && other.Points.Count - 1 == Points.Count)
{
yValue = isNanOrInfinity || other.Points[other.Points.Count - 1].Y < 0
@ -608,9 +407,9 @@ namespace XenAdmin.Controls.CustomDataGraph
: other.Points[other.Points.Count - 1].Y - (value * MultiplyingFactor);
}
}
else if (TypeString == "memory")
else if (DataSourceName == "memory")
{
DataSet other = setsAdded.FirstOrDefault(s => s.TypeString == "memory_internal_free");
DataSet other = setsAdded.FirstOrDefault(s => s.DataSourceName == "memory_internal_free");
if (other != null && other.Points.Count - 1 == Points.Count)
{
yValue = isNanOrInfinity || other.Points[other.Points.Count - 1].Y < 0
@ -619,9 +418,9 @@ namespace XenAdmin.Controls.CustomDataGraph
other.Points[other.Points.Count - 1].Y = yValue;
}
}
else if (TypeString == "memory_internal_free")
else if (DataSourceName == "memory_internal_free")
{
DataSet other = setsAdded.FirstOrDefault(s => s.TypeString == "memory");
DataSet other = setsAdded.FirstOrDefault(s => s.DataSourceName == "memory");
if (other != null && other.Points.Count - 1 == Points.Count)
{
yValue = isNanOrInfinity || other.Points[other.Points.Count - 1].Y < 0
@ -684,14 +483,14 @@ namespace XenAdmin.Controls.CustomDataGraph
DataSet other = (DataSet)obj;
return Uuid == other.Uuid;
return Id == other.Id;
}
public override int GetHashCode()
{
if (string.IsNullOrEmpty(Uuid))
if (string.IsNullOrEmpty(Id))
return base.GetHashCode();
return Uuid.GetHashCode();
return Id.GetHashCode();
}
internal void InsertPointCollection(List<DataPoint> list)
@ -791,12 +590,12 @@ namespace XenAdmin.Controls.CustomDataGraph
public int CompareTo(DataSet other)
{
if (Uuid == other.Uuid)
if (Id == other.Id)
return 0;
int comp = DisplayArea.CompareTo(other.DisplayArea);
if (comp == 0)
return StringUtility.NaturalCompare(Name, other.Name);
return StringUtility.NaturalCompare(FriendlyName, other.FriendlyName);
return comp;
}
@ -810,36 +609,4 @@ namespace XenAdmin.Controls.CustomDataGraph
return null;
}
}
public enum DataType { Cpu, Memory, Disk, Storage, Network, Latency, LoadAverage, Gpu, Pvs, Custom };
public static class DatatypeExtensions
{
public static string ToStringI18N(this DataType datatype)
{
switch (datatype)
{
case DataType.Cpu:
return Messages.DATATYPE_CPU;
case DataType.Memory:
return Messages.DATATYPE_MEMORY;
case DataType.Disk:
return Messages.DATATYPE_DISK;
case DataType.Storage:
return Messages.DATATYPE_STORAGE;
case DataType.Network:
return Messages.DATATYPE_NETWORK;
case DataType.Latency:
return Messages.DATATYPE_LATENCY;
case DataType.LoadAverage:
return Messages.DATATYPE_LOADAVERAGE;
case DataType.Gpu:
return Messages.DATATYPE_GPU;
case DataType.Pvs:
return Messages.DATATYPE_PVS;
default:
return Messages.DATATYPE_CUSTOM;
}
}
}
}

View File

@ -59,7 +59,7 @@ namespace XenAdmin.Controls.CustomDataGraph
DisplayName = sourceGraph.DisplayName;
foreach (DataSourceItem dsi in sourceGraph.DataSources)
{
DataSources.Add(new DataSourceItem(dsi.DataSource, dsi.ToString(), dsi.Color, dsi.Uuid));
DataSources.Add(new DataSourceItem(dsi.DataSource, dsi.ToString(), dsi.Color, dsi.Id));
}
}
@ -91,7 +91,7 @@ namespace XenAdmin.Controls.CustomDataGraph
for (int i = 0; i < this.DataSources.Count; i++)
{
if (this.DataSources[i].Uuid != other.DataSources[i].Uuid)
if (this.DataSources[i].Id != other.DataSources[i].Id)
return false;
}
@ -129,28 +129,24 @@ namespace XenAdmin.Controls.CustomDataGraph
private string friendlyName;
public Color Color;
public bool ColorChanged;
public string Uuid;
public DataType DataType;
public string Id;
public Helpers.DataSourceCategory Category;
public DataSourceItem(Data_source ds, string friendlyname, Color color, string uuid)
public DataSourceItem(Data_source ds, string friendlyname, Color color, string id, IXenObject xo = null)
{
DataSource = ds;
Enabled = DataSource.enabled;
friendlyName = friendlyname;
Color = color;
Uuid = uuid;
}
Id = id;
public DataSourceItem(Data_source ds, string friendlyname, Color color, string uuid, IXenObject xo)
: this(ds, friendlyname, color, uuid)
{
DataSet dataSet = DataSet.Create(uuid, xo);
DataType = dataSet.Type;
if (DataSet.ParseId(id, out _, out _, out string dataSourceName))
Category = Helpers.GetDataSourceCategory(dataSourceName);
}
public string GetDataSource()
{
string[] lst = Uuid.Split(':');
string[] lst = Id.Split(':');
return lst.Length == 0 ? "" : lst[lst.Length - 1];
}
@ -166,7 +162,7 @@ namespace XenAdmin.Controls.CustomDataGraph
public bool Equals(DataSourceItem other)
{
return Uuid.Equals(other.Uuid);
return Id.Equals(other?.Id);
}
}

View File

@ -168,7 +168,7 @@ namespace XenAdmin.Controls.CustomDataGraph
DataKey newkey =
CreateKey(new Point(left - HorizontalScroll.Value, CONTROL_PADDING + y + GRAPH_PADDING));
foreach (DataSourceItem item in designedGraph.DataSources)
newkey.DataSourceUUIDsToShow.Add(item.Uuid);
newkey.DataSourceUUIDsToShow.Add(item.Id);
newplot.DataKey = newkey;
newkey.Enter += new EventHandler(dataKey_Enter);
newkey.MouseDown += new MouseEventHandler(dataKey_MouseDown);
@ -489,10 +489,10 @@ namespace XenAdmin.Controls.CustomDataGraph
found = graph.DataSources.Contains(dsi);
if (found)
{
if (!Palette.HasCustomColour(dsi.Uuid))
if (!Palette.HasCustomColour(dsi.Id))
{
dsi.ColorChanged = true;
Palette.SetCustomColor(dsi.Uuid, dsi.Color);
Palette.SetCustomColor(dsi.Id, dsi.Color);
}
break;
}
@ -514,11 +514,11 @@ namespace XenAdmin.Controls.CustomDataGraph
if (datasourceName == "memory_total_kib" || datasourceName == "memory")
continue;
if (!Palette.HasCustomColour(dsi.Uuid))
if (!Palette.HasCustomColour(dsi.Id))
{
dsi.DataSource.name_label = datasourceName;
dsi.ColorChanged = true;
Palette.SetCustomColor(dsi.Uuid, dsi.Color);
Palette.SetCustomColor(dsi.Id, dsi.Color);
dataSources.Add(dsi);
}
}
@ -686,7 +686,7 @@ namespace XenAdmin.Controls.CustomDataGraph
Plots[index].DisplayName = newGraph.DisplayName;
Keys[index].DataSourceUUIDsToShow.Clear();
foreach (DataSourceItem item in newGraph.DataSources)
Keys[index].DataSourceUUIDsToShow.Add(item.Uuid);
Keys[index].DataSourceUUIDsToShow.Add(item.Id);
Keys[index].UpdateItems();
if (isSelected)

View File

@ -140,7 +140,7 @@ namespace XenAdmin.Controls.CustomDataGraph
if(pool == null)
return;
string key = GetColorKey(set.TypeString, set.XenObject);
string key = GetColorKey(set.DataSourceName, set.XenObject);
Dictionary<string, string> gui_config = Helpers.GetGuiConfig(pool);
@ -151,7 +151,7 @@ namespace XenAdmin.Controls.CustomDataGraph
if (!int.TryParse(gui_config[key], out argb))
return;
SetCustomColor(set.Uuid, Color.FromArgb(argb));
SetCustomColor(set.Id, Color.FromArgb(argb));
}
public static string GetColorKey(string ds_name, IXenObject xo)

View File

@ -323,7 +323,7 @@ namespace XenAdmin.Dialogs
this.dsi = dataSourceItem;
var displayOnGraphCell = new DataGridViewCheckBoxCell { Value = displayOnGraph };
var datasourceCell = new DataGridViewTextBoxCell { Value = dsi.ToString() };
var typeCell = new DataGridViewTextBoxCell { Value = dsi.DataType.ToStringI18N() };
var typeCell = new DataGridViewTextBoxCell { Value = dsi.Category.ToStringI18N() };
var colourCell = new DataGridViewTextBoxCell { Value = dsi.Color };
Cells.AddRange(displayOnGraphCell, datasourceCell, typeCell, colourCell);
}

72
XenModel/UnitStrings.Designer.cs generated Normal file
View File

@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace XenAdmin {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class UnitStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal UnitStrings() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("XenAdmin.UnitStrings", typeof(UnitStrings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to s/s.
/// </summary>
public static string SEC_PER_SEC_UNIT {
get {
return ResourceManager.GetString("SEC_PER_SEC_UNIT", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

104
XenModel/UnitStrings.resx Normal file
View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="SEC_PER_SEC_UNIT" xml:space="preserve">
<value>s/s</value>
</data>
</root>

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -959,31 +959,114 @@ namespace XenAdmin.Core
#endregion
public enum DataSourceCategory
{
Cpu,
Memory,
Disk,
Storage,
Network,
Latency,
LoadAverage,
Gpu,
Pvs,
Custom
}
public static string ToStringI18N(this DataSourceCategory category)
{
switch (category)
{
case DataSourceCategory.Cpu:
return Messages.DATATYPE_CPU;
case DataSourceCategory.Memory:
return Messages.DATATYPE_MEMORY;
case DataSourceCategory.Disk:
return Messages.DATATYPE_DISK;
case DataSourceCategory.Storage:
return Messages.DATATYPE_STORAGE;
case DataSourceCategory.Network:
return Messages.DATATYPE_NETWORK;
case DataSourceCategory.Latency:
return Messages.DATATYPE_LATENCY;
case DataSourceCategory.LoadAverage:
return Messages.DATATYPE_LOADAVERAGE;
case DataSourceCategory.Gpu:
return Messages.DATATYPE_GPU;
case DataSourceCategory.Pvs:
return Messages.DATATYPE_PVS;
default:
return Messages.DATATYPE_CUSTOM;
}
}
public static Regex CpuRegex = new Regex("^cpu([0-9]+)$");
public static Regex CpuAvgFreqRegex = new Regex("^CPU([0-9]+)-avg-freq$");
static Regex CpuAvgFreqRegex = new Regex("^CPU([0-9]+)-avg-freq$");
public static Regex CpuStateRegex = new Regex("^cpu([0-9]+)-(C|P)([0-9]+)$");
static Regex CpuOtherRegex = new Regex("^cpu_avg|avg_cpu$");
private static Regex VcpuRegex = new Regex("^runstate_(blocked|concurrency_hazard|full_contention|fullrun|partial_contention|partial_run)$");
static Regex VifRegex = new Regex("^vif_([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifEthRegex = new Regex("^pif_eth([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifVlanRegex = new Regex("^pif_eth([0-9]+).([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifVlanRegex = new Regex("^pif_eth([0-9]+).([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifBrRegex = new Regex("^pif_xenbr([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifXapiRegex = new Regex("^pif_xapi([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifXapiRegex = new Regex("^pif_xapi([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifTapRegex = new Regex("^pif_tap([0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifLoRegex = new Regex("^pif_lo_(tx|rx)((_errors)?)$");
static Regex PifBondRegex = new Regex("^pif_(bond[0-9]+)_(tx|rx)((_errors)?)$");
static Regex PifOtherRegex = new Regex("^pif_aggr_(tx|rx)$");
static Regex DiskRegex = new Regex("^vbd_((xvd|hd)[a-z]+)(_(read|write))?(_latency)?$");
static Regex DiskIopsRegex = new Regex("^vbd_((xvd|hd)[a-z]+)_iops_(read|write|total)$");
static Regex DiskThroughputRegex = new Regex("^vbd_((xvd|hd)[a-z]+)_io_throughput_(read|write|total)$");
static Regex DiskOtherRegex = new Regex("^vbd_((xvd|hd)[a-z]+)_(avgqu_sz|inflight|iowait)$");
static Regex NetworkLatencyRegex = new Regex("^network/latency$");
static Regex XapiLatencyRegex = new Regex("^xapi_healthcheck/latency$");
static Regex XapiMemoryRegex = new Regex("^xapi_(allocation|free_memory|live_memory|memory_usage)_kib$");
static Regex StatefileLatencyRegex = new Regex("^statefile/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/latency$");
static Regex LoadAvgRegex = new Regex("loadavg");
static Regex SrRegex = new Regex("^sr_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}_cache_(size|hits|misses)");
static Regex SrRegex = new Regex("^sr_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}_cache_(size|hits|misses)");
static Regex SrIORegex = new Regex("^(io_throughput|iops)_(read|write|total)_([a-f0-9]{8})$");
static Regex SrOtherRegex = new Regex("^(latency|avgqu_sz|inflight|iowait)_([a-f0-9]{8})$");
static Regex SrReadWriteRegex = new Regex("^((read|write)(_latency)?)_([a-f0-9]{8})$");
static Regex GpuRegex = new Regex(@"^gpu_((memory_(free|used))|power_usage|temperature|(utilisation_(compute|memory_io)))_((([a-fA-F0-9]{4}\/)|([a-fA-F0-9]{8}\/))?[a-fA-F0-9]{2}\/[0-1][a-fA-F0-9].[0-7])$");
public static DataSourceCategory GetDataSourceCategory(string name)
{
if (CpuRegex.IsMatch(name) || CpuAvgFreqRegex.IsMatch(name) ||
CpuStateRegex.IsMatch(name) || CpuOtherRegex.IsMatch(name) || VcpuRegex.IsMatch(name))
return DataSourceCategory.Cpu;
if (VifRegex.IsMatch(name) || PifEthRegex.IsMatch(name) || PifVlanRegex.IsMatch(name) ||
PifBrRegex.IsMatch(name) || PifXapiRegex.IsMatch(name) || PifBondRegex.IsMatch(name) ||
PifLoRegex.IsMatch(name) || PifTapRegex.IsMatch(name) || PifOtherRegex.IsMatch(name))
return DataSourceCategory.Network;
if (DiskRegex.IsMatch(name) || DiskIopsRegex.IsMatch(name) ||
DiskThroughputRegex.IsMatch(name) || DiskOtherRegex.IsMatch(name))
return DataSourceCategory.Disk;
if (SrRegex.IsMatch(name) || SrIORegex.IsMatch(name) ||
SrOtherRegex.IsMatch(name) || SrReadWriteRegex.IsMatch(name))
return DataSourceCategory.Storage;
if (GpuRegex.IsMatch(name))
return DataSourceCategory.Gpu;
if (NetworkLatencyRegex.IsMatch(name) || XapiLatencyRegex.IsMatch(name) ||
StatefileLatencyRegex.IsMatch(name))
return DataSourceCategory.Latency;
if (LoadAvgRegex.IsMatch(name))
return DataSourceCategory.LoadAverage;
if (name.StartsWith("pvsaccelerator"))
return DataSourceCategory.Pvs;
if (XapiMemoryRegex.IsMatch(name) || name.StartsWith("memory"))
return DataSourceCategory.Memory;
return DataSourceCategory.Custom;
}
public static string GetFriendlyDataSourceName(string name, IXenObject iXenObject)
{
if (iXenObject == null)

View File

@ -411,6 +411,11 @@ namespace XenAdmin
return string.Format(Messages.VAL_FORMAT, p, Messages.COUNTS_PER_SEC_UNIT);
}
public static string SecondsPerSecondString(double p)
{
return string.Format(Messages.VAL_FORMAT, p, UnitStrings.SEC_PER_SEC_UNIT);
}
public static string MegaHertzString(double t)
{
string unit;

View File

@ -168,6 +168,11 @@
<Compile Include="Actions\ZipStatusReportAction.cs" />
<Compile Include="Alerts\Types\Alert.cs" />
<Compile Include="BrandManager.cs" />
<Compile Include="UnitStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>UnitStrings.resx</DependentUpon>
</Compile>
<Compile Include="Utils\StringExtensions.cs" />
<Compile Include="Utils\TimeSpanExtensions.cs" />
<Compile Include="WLB\WlbPoolConfiguration.cs" />
@ -607,6 +612,13 @@
<EmbeddedResource Include="Messages.zh-CN.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UnitStrings.ja.resx" />
<EmbeddedResource Include="UnitStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>UnitStrings.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UnitStrings.zh-CN.resx" />
<EmbeddedResource Include="XenAPI\FriendlyErrorNames.ja.resx" />
<EmbeddedResource Include="XenAPI\FriendlyErrorNames.resx">
<Generator>PublicResXFileCodeGenerator</Generator>