diff --git a/XenAdmin/Controls/CustomDataGraph/ArchiveMaintainer.cs b/XenAdmin/Controls/CustomDataGraph/ArchiveMaintainer.cs index 1071889cd..759c0e789 100644 --- a/XenAdmin/Controls/CustomDataGraph/ArchiveMaintainer.cs +++ b/XenAdmin/Controls/CustomDataGraph/ArchiveMaintainer.cs @@ -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 /// private List SetsAdded; + private List _enabledDataSources = new List(); + private IXenObject _xenObject; + private long EndTime; + private bool BailOut; + private long CurrentInterval; + private long StepSize; + private long CurrentTime; + private int ValueCount; + private string LastNode = ""; + /// /// Gui Thread /// @@ -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 } } - /// - /// UpdaterThread Thread - /// - public DateTime ServerNow() + private void Get(ArchiveInterval interval, Func uriBuilder, + ActionReader, IXenObject xenObject) { - return DateTime.UtcNow.Subtract(ClientServerOffset); - } - - /// - /// UpdaterThread Thread - /// - private void GetUpdate(ArchiveInterval interval, Host host, IXenObject xo) - { - Get(interval, UpdateUri, RRD_Update_InspectCurrentNode, host, xo); - } - - /// - /// UpdaterThread Thread - /// - 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 } } - /// - /// UpdaterThread Thread - /// - 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; - - /// - /// UpdaterThread Thread - /// 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 = ""; - - /// - /// UpdaterThread Thread - /// 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(); - } } } diff --git a/XenAdmin/Controls/CustomDataGraph/DataArchive.cs b/XenAdmin/Controls/CustomDataGraph/DataArchive.cs index 9065f2fb0..963dabc84 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataArchive.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataArchive.cs @@ -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 /// /// Asserts off the event thread, for use when copying off the updater thread. Invokes onto event thread to update the sets safely. /// - /// - internal void CopyLoad(List SetsAdded) + internal void CopyLoad(List setsAdded, List 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)); diff --git a/XenAdmin/Controls/CustomDataGraph/DataKey.cs b/XenAdmin/Controls/CustomDataGraph/DataKey.cs index f2a6ba034..f9622b2c6 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataKey.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataKey.cs @@ -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(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 Sets = new Dictionary(); 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) diff --git a/XenAdmin/Controls/CustomDataGraph/DataPlot.cs b/XenAdmin/Controls/CustomDataGraph/DataPlot.cs index 5d360732a..8275c5e76 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataPlot.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataPlot.cs @@ -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 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))) { diff --git a/XenAdmin/Controls/CustomDataGraph/DataPlotNav.cs b/XenAdmin/Controls/CustomDataGraph/DataPlotNav.cs index 88532375e..38baf8f3e 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataPlotNav.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataPlotNav.cs @@ -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 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); } diff --git a/XenAdmin/Controls/CustomDataGraph/DataRange.cs b/XenAdmin/Controls/CustomDataGraph/DataRange.cs index 3415b1f21..7455b5967 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataRange.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataRange.cs @@ -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 + } } diff --git a/XenAdmin/Controls/CustomDataGraph/DataSet.cs b/XenAdmin/Controls/CustomDataGraph/DataSet.cs index a28a1acfa..615edc016 100644 --- a/XenAdmin/Controls/CustomDataGraph/DataSet.cs +++ b/XenAdmin/Controls/CustomDataGraph/DataSet.cs @@ -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; + /// /// 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) /// public List Points = new List(); - public string Name; - public bool Selected; public List CurrentlyDisplayed = new List(); public IXenObject XenObject; - public string Uuid; - private bool _hide; - private bool _deselected; - - /// - /// A guess at the data type - /// - public DataType Type; - /// - /// What it really is - /// - 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; } - /// - /// Can show in the lisbox - /// - public bool Show - { - get { return !_hide && !NeverShow; } - } - - /// - /// This dataset is of the wrong xenobject - /// - public bool Hide - { - get { return _hide; } - set { _hide = value; } - } - - /// - /// The user has chosen not to show this graph - /// - public bool Deselected - { - get { return _deselected; } - set { _deselected = value; } - } - - /// - /// Never ever draw on graph or put in listbox - /// - private bool NeverShow { get; set; } - - /// - /// Can draw on graph - /// - 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 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(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(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 GetRange(DataTimeRange xrange, long intervalneed, long intervalat) { List 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 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 setsAdded) + public void AddPoint(string str, long currentTime, List setsAdded, List 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(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 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; - } - } - } } diff --git a/XenAdmin/Controls/CustomDataGraph/GraphHelpers.cs b/XenAdmin/Controls/CustomDataGraph/GraphHelpers.cs index e8c992d24..7d2ba63a8 100644 --- a/XenAdmin/Controls/CustomDataGraph/GraphHelpers.cs +++ b/XenAdmin/Controls/CustomDataGraph/GraphHelpers.cs @@ -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); } } diff --git a/XenAdmin/Controls/CustomDataGraph/GraphList.cs b/XenAdmin/Controls/CustomDataGraph/GraphList.cs index 927bac279..eee7b914d 100644 --- a/XenAdmin/Controls/CustomDataGraph/GraphList.cs +++ b/XenAdmin/Controls/CustomDataGraph/GraphList.cs @@ -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) diff --git a/XenAdmin/Controls/CustomDataGraph/Palette.cs b/XenAdmin/Controls/CustomDataGraph/Palette.cs index 43a67a8aa..3567af3e6 100644 --- a/XenAdmin/Controls/CustomDataGraph/Palette.cs +++ b/XenAdmin/Controls/CustomDataGraph/Palette.cs @@ -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 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) diff --git a/XenAdmin/Dialogs/GraphDetailsDialog.cs b/XenAdmin/Dialogs/GraphDetailsDialog.cs index 4478060f8..0dfbd2f9a 100644 --- a/XenAdmin/Dialogs/GraphDetailsDialog.cs +++ b/XenAdmin/Dialogs/GraphDetailsDialog.cs @@ -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); } diff --git a/XenModel/UnitStrings.Designer.cs b/XenModel/UnitStrings.Designer.cs new file mode 100644 index 000000000..a84185c04 --- /dev/null +++ b/XenModel/UnitStrings.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace XenAdmin { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to s/s. + /// + public static string SEC_PER_SEC_UNIT { + get { + return ResourceManager.GetString("SEC_PER_SEC_UNIT", resourceCulture); + } + } + } +} diff --git a/XenModel/UnitStrings.ja.resx b/XenModel/UnitStrings.ja.resx new file mode 100644 index 000000000..d00213b78 --- /dev/null +++ b/XenModel/UnitStrings.ja.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/XenModel/UnitStrings.resx b/XenModel/UnitStrings.resx new file mode 100644 index 000000000..3aaa51a1e --- /dev/null +++ b/XenModel/UnitStrings.resx @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + s/s + + \ No newline at end of file diff --git a/XenModel/UnitStrings.zh-CN.resx b/XenModel/UnitStrings.zh-CN.resx new file mode 100644 index 000000000..d00213b78 --- /dev/null +++ b/XenModel/UnitStrings.zh-CN.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/XenModel/Utils/Helpers.cs b/XenModel/Utils/Helpers.cs index 788608da8..6a3f7597e 100755 --- a/XenModel/Utils/Helpers.cs +++ b/XenModel/Utils/Helpers.cs @@ -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) diff --git a/XenModel/Utils/Util.cs b/XenModel/Utils/Util.cs index b232391ba..c04161159 100644 --- a/XenModel/Utils/Util.cs +++ b/XenModel/Utils/Util.cs @@ -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; diff --git a/XenModel/XenModel.csproj b/XenModel/XenModel.csproj index 1bd3ec9ad..c1422754a 100755 --- a/XenModel/XenModel.csproj +++ b/XenModel/XenModel.csproj @@ -168,6 +168,11 @@ + + True + True + UnitStrings.resx + @@ -607,6 +612,13 @@ Designer + + + PublicResXFileCodeGenerator + UnitStrings.Designer.cs + Designer + + PublicResXFileCodeGenerator