2013-06-24 13:41:48 +02:00
|
|
|
|
/* Copyright (c) Citrix Systems Inc.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
|
* that the following conditions are met:
|
|
|
|
|
*
|
|
|
|
|
* * Redistributions of source code must retain the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer.
|
|
|
|
|
* * Redistributions in binary form must reproduce the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer in the documentation and/or other
|
|
|
|
|
* materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
using XenAdmin.Network;
|
|
|
|
|
using XenAdmin.Core;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.Alerts
|
|
|
|
|
{
|
|
|
|
|
public class PerfmonDefinition
|
|
|
|
|
{
|
|
|
|
|
private const string xmlns = ""; // no namespace for perfmon
|
|
|
|
|
|
|
|
|
|
public const string PERFMON_KEY_NAME = "perfmon";
|
|
|
|
|
private const string ROOT_ELEMENT_NAME = "config";
|
|
|
|
|
private const string VARIABLE_ELEMENT_NAME = "variable";
|
|
|
|
|
|
|
|
|
|
private const string ALARM_TRIGGER_LEVEL_ELEMENT_NAME = "alarm_trigger_level";
|
|
|
|
|
private const string ALARM_TRIGGER_PERIOD_ELEMENT_NAME = "alarm_trigger_period";
|
|
|
|
|
private const string ALARM_AUTO_INHIBIT_PERIOD_ELEMENT_NAME = "alarm_auto_inhibit_period";
|
|
|
|
|
private const string ALARM_TYPE_ELEMENT_NAME = "name";
|
|
|
|
|
private const string ALARM_COMMON_ATTR_NAME = "value";
|
|
|
|
|
|
|
|
|
|
public const string ALARM_TYPE_CPU = "cpu_usage";
|
|
|
|
|
public const string ALARM_TYPE_NETWORK = "network_usage";
|
|
|
|
|
public const string ALARM_TYPE_DISK = "disk_usage";
|
|
|
|
|
public const string ALARM_TYPE_FILESYSTEM = "fs_usage";
|
2014-08-05 22:40:26 +02:00
|
|
|
|
public const string ALARM_TYPE_MEMORY_FREE = "memory_free_kib";
|
|
|
|
|
public const string ALARM_TYPE_MEMORY_DOM0_USAGE = "mem_usage";
|
2015-07-24 17:01:56 +02:00
|
|
|
|
public const string ALARM_TYPE_LOG_FILESYSTEM = "log_fs_usage";
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// This is the name that will be stored in the SR's other-config:perfmon key
|
|
|
|
|
/// </summary>
|
|
|
|
|
public const string ALARM_TYPE_SR = "sr_io_throughput_total_per_host";
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This matches the name of the host alert
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly Regex SrRegex = new Regex("^sr_io_throughput_total_([a-f0-9]{8})$");
|
|
|
|
|
|
|
|
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
|
|
|
|
|
|
private readonly string name;
|
|
|
|
|
private readonly decimal alarmTriggerLevel;
|
|
|
|
|
private readonly decimal alarmTriggerPeriod;
|
|
|
|
|
private readonly decimal alarmAutoInhibitPeriod;
|
|
|
|
|
|
|
|
|
|
public PerfmonDefinition(string name, decimal alarmTriggerLevel, decimal alarmTriggerPeriod, decimal alarmAutoInhibitPeriod)
|
|
|
|
|
{
|
|
|
|
|
this.name = name;
|
|
|
|
|
this.alarmTriggerLevel = alarmTriggerLevel;
|
|
|
|
|
this.alarmTriggerPeriod = alarmTriggerPeriod;
|
|
|
|
|
this.alarmAutoInhibitPeriod = alarmAutoInhibitPeriod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsCPUUsage
|
|
|
|
|
{
|
|
|
|
|
get { return name.Equals(ALARM_TYPE_CPU); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsNetworkUsage
|
|
|
|
|
{
|
|
|
|
|
get { return name.Equals(ALARM_TYPE_NETWORK); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsDiskUsage
|
|
|
|
|
{
|
|
|
|
|
get { return name.Equals(ALARM_TYPE_DISK); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsMemoryUsage
|
|
|
|
|
{
|
2014-08-05 22:40:26 +02:00
|
|
|
|
get { return name.Equals(ALARM_TYPE_MEMORY_FREE); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsDom0MemoryUsage
|
|
|
|
|
{
|
|
|
|
|
get { return name.Equals(ALARM_TYPE_MEMORY_DOM0_USAGE); }
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsSrUsage
|
|
|
|
|
{
|
|
|
|
|
get { return name.Equals(ALARM_TYPE_SR); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public decimal AlarmTriggerLevel
|
|
|
|
|
{
|
|
|
|
|
get { return alarmTriggerLevel; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public decimal AlarmTriggerPeriod
|
|
|
|
|
{
|
|
|
|
|
get { return alarmTriggerPeriod; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public decimal AlarmAutoInhibitPeriod
|
|
|
|
|
{
|
|
|
|
|
get { return alarmAutoInhibitPeriod; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return String.Format("{0} (Value: {1} Trigger Period: {2} Auto Inhibit Period: {3})",
|
|
|
|
|
name, alarmTriggerLevel, alarmTriggerPeriod, alarmAutoInhibitPeriod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
|
|
|
|
PerfmonDefinition other = obj as PerfmonDefinition;
|
|
|
|
|
if (other == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return other.name == name &&
|
|
|
|
|
other.alarmTriggerLevel == alarmTriggerLevel &&
|
|
|
|
|
other.alarmTriggerPeriod == alarmTriggerPeriod
|
|
|
|
|
&& other.alarmAutoInhibitPeriod == alarmAutoInhibitPeriod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
return name.GetHashCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PerfmonDefinition(XmlNode parentNode)
|
|
|
|
|
{
|
|
|
|
|
foreach (XmlNode node in parentNode.ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
bool success = false;
|
|
|
|
|
|
|
|
|
|
if (node.Attributes == null)
|
|
|
|
|
{
|
|
|
|
|
//ignore
|
|
|
|
|
}
|
|
|
|
|
else if (node.Name.Equals(ALARM_TYPE_ELEMENT_NAME))
|
|
|
|
|
{
|
|
|
|
|
name = node.Attributes[ALARM_COMMON_ATTR_NAME].Value;
|
|
|
|
|
}
|
|
|
|
|
else if (node.Name.Equals(ALARM_TRIGGER_LEVEL_ELEMENT_NAME))
|
|
|
|
|
{
|
|
|
|
|
success = Decimal.TryParse(
|
|
|
|
|
node.Attributes[ALARM_COMMON_ATTR_NAME].Value,
|
|
|
|
|
NumberStyles.Any,
|
|
|
|
|
CultureInfo.InvariantCulture,
|
|
|
|
|
out alarmTriggerLevel);
|
|
|
|
|
}
|
|
|
|
|
else if (node.Name.Equals(ALARM_TRIGGER_PERIOD_ELEMENT_NAME))
|
|
|
|
|
{
|
|
|
|
|
success = Decimal.TryParse(
|
|
|
|
|
node.Attributes[ALARM_COMMON_ATTR_NAME].Value,
|
|
|
|
|
NumberStyles.Any,
|
|
|
|
|
CultureInfo.InvariantCulture,
|
|
|
|
|
out alarmTriggerPeriod);
|
|
|
|
|
}
|
|
|
|
|
else if (node.Name.Equals(ALARM_AUTO_INHIBIT_PERIOD_ELEMENT_NAME))
|
|
|
|
|
{
|
|
|
|
|
success = Decimal.TryParse(
|
|
|
|
|
node.Attributes[ALARM_COMMON_ATTR_NAME].Value,
|
|
|
|
|
NumberStyles.Any,
|
|
|
|
|
CultureInfo.InvariantCulture,
|
|
|
|
|
out alarmAutoInhibitPeriod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
log.DebugFormat("Failed to unmarshal perfmon definition '{0}'", node.OuterXml);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a "variable" element using the PerfmonDefinition.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private XmlNode ToXmlNode(XmlDocument doc)
|
|
|
|
|
{
|
|
|
|
|
XmlNode node = doc.CreateNode(XmlNodeType.Element, VARIABLE_ELEMENT_NAME, xmlns);
|
|
|
|
|
|
|
|
|
|
XmlNode nameNode = doc.CreateNode(XmlNodeType.Element, ALARM_TYPE_ELEMENT_NAME, xmlns);
|
|
|
|
|
XmlAttribute nameAttr = doc.CreateAttribute(ALARM_COMMON_ATTR_NAME);
|
|
|
|
|
nameAttr.Value = name;
|
|
|
|
|
nameNode.Attributes.Append(nameAttr);
|
|
|
|
|
node.AppendChild(nameNode);
|
|
|
|
|
|
|
|
|
|
XmlNode alarmTriggerLevelNode = doc.CreateNode(XmlNodeType.Element, ALARM_TRIGGER_LEVEL_ELEMENT_NAME, xmlns);
|
|
|
|
|
XmlAttribute alarmTriggerLevelAttr = doc.CreateAttribute(ALARM_COMMON_ATTR_NAME);
|
|
|
|
|
alarmTriggerLevelAttr.Value = alarmTriggerLevel.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
alarmTriggerLevelNode.Attributes.Append(alarmTriggerLevelAttr);
|
|
|
|
|
node.AppendChild(alarmTriggerLevelNode);
|
|
|
|
|
|
|
|
|
|
XmlNode alarmTriggerPeriodNode = doc.CreateNode(XmlNodeType.Element, ALARM_TRIGGER_PERIOD_ELEMENT_NAME, xmlns);
|
|
|
|
|
XmlAttribute alarmTriggerPeriodAttr = doc.CreateAttribute(ALARM_COMMON_ATTR_NAME);
|
|
|
|
|
alarmTriggerPeriodAttr.Value = alarmTriggerPeriod.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
alarmTriggerPeriodNode.Attributes.Append(alarmTriggerPeriodAttr);
|
|
|
|
|
node.AppendChild(alarmTriggerPeriodNode);
|
|
|
|
|
|
|
|
|
|
XmlNode alarmAutoInhibitPeriodNode = doc.CreateNode(XmlNodeType.Element, ALARM_AUTO_INHIBIT_PERIOD_ELEMENT_NAME, xmlns);
|
|
|
|
|
XmlAttribute alarmAutoInhibitPeriodAttr = doc.CreateAttribute(ALARM_COMMON_ATTR_NAME);
|
|
|
|
|
alarmAutoInhibitPeriodAttr.Value = alarmAutoInhibitPeriod.ToString(CultureInfo.InvariantCulture);
|
|
|
|
|
alarmAutoInhibitPeriodNode.Attributes.Append(alarmAutoInhibitPeriodAttr);
|
|
|
|
|
node.AppendChild(alarmAutoInhibitPeriodNode);
|
|
|
|
|
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parse the entire perfmon xml config blob and build a collection of
|
|
|
|
|
/// perfmon definitions. Note the rootnode is a "config" element and the
|
|
|
|
|
/// child elements are "variable".
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static PerfmonDefinition[] GetPerfmonDefinitions(string xml)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
XmlDocument doc = new XmlDocument();
|
|
|
|
|
doc.LoadXml(xml);
|
|
|
|
|
|
|
|
|
|
XmlNode parentNode = doc.FirstChild;
|
|
|
|
|
|
|
|
|
|
List<PerfmonDefinition> perfmonDefinitions = new List<PerfmonDefinition>();
|
|
|
|
|
|
|
|
|
|
foreach (XmlNode node in parentNode.ChildNodes)
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
perfmonDefinitions.Add(new PerfmonDefinition(node));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.DebugFormat("Exception unmarshalling perfmon definition '{0}'", node.OuterXml);
|
|
|
|
|
log.Debug(e, e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return perfmonDefinitions.ToArray();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
log.Debug(e, e);
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static PerfmonDefinition[] GetPerfmonDefinitions(IXenObject xo)
|
|
|
|
|
{
|
|
|
|
|
if (!(xo is VM) && !(xo is Host) && !(xo is SR))
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
|
|
|
|
|
Dictionary<string, string> other_config = Helpers.GetOtherConfig(xo);
|
|
|
|
|
if (other_config == null)
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
|
|
|
|
|
if (!other_config.ContainsKey(PERFMON_KEY_NAME))
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
|
|
|
|
|
string perfmonConfigXML = other_config[PERFMON_KEY_NAME];
|
|
|
|
|
if (perfmonConfigXML == null)
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
|
|
|
|
|
perfmonConfigXML.Trim();
|
|
|
|
|
if (String.IsNullOrEmpty(perfmonConfigXML))
|
|
|
|
|
return new PerfmonDefinition[0];
|
|
|
|
|
|
|
|
|
|
return GetPerfmonDefinitions(perfmonConfigXML);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Build an entire "perfmon" xml config blob using the collection of
|
|
|
|
|
/// perfmon definitions. Note the rootnode is a "config" element and the
|
|
|
|
|
/// child elements are "variable". This will be used to set the other_config
|
|
|
|
|
/// of the host or vm objects.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static string GetPerfmonDefinitionXML(List<PerfmonDefinition> perfmonDefinitions)
|
|
|
|
|
{
|
|
|
|
|
XmlDocument doc = new XmlDocument();
|
|
|
|
|
|
|
|
|
|
XmlNode parentNode = doc.CreateNode(XmlNodeType.Element, ROOT_ELEMENT_NAME, xmlns);
|
|
|
|
|
doc.AppendChild(parentNode);
|
|
|
|
|
|
|
|
|
|
foreach (PerfmonDefinition perfmonDefinition in perfmonDefinitions)
|
|
|
|
|
parentNode.AppendChild(perfmonDefinition.ToXmlNode(doc));
|
|
|
|
|
|
|
|
|
|
return doc.OuterXml;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|