CP-15790: Implementation improvement aimed to make manual testing easier.

- Ensure we read the updates.xml location anew from the registry, otherwise the
application has to be relaunched to pick a registry change. Look in both hives
HKCU and HKLM. To avoid performance impact on the UI, move the operation into
the action's Run() body.
- Some refactoring to improve OOP design and fix XmlReader leak.

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
Konstantina Chremmou 2020-10-29 12:38:34 +00:00
parent 0b0819b0aa
commit 80119e9411
9 changed files with 62 additions and 80 deletions

View File

@ -32,50 +32,51 @@
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Xml;
using XenAdmin.Actions;
using XenAdmin.Core;
using XenAPI;
namespace CFUValidator.Updates
{
class AlternativeUrlDownloadUpdatesXmlSourceAction : DownloadUpdatesXmlAction, ICheckForUpdatesXMLSource
{
private readonly string newLocation;
private readonly string _url;
public AlternativeUrlDownloadUpdatesXmlSourceAction(string url)
: base(true, true, true, "CFU", "1", url)
: base(true, true, true, "CFU", "1")
{
newLocation = url;
ErrorRaised = null;
_url = url ?? throw new ArgumentNullException(nameof(url));
}
protected override XmlDocument FetchCheckForUpdatesXml(string location)
{
XmlDocument xdoc;
using (Stream xmlstream = GetXmlDoc())
{
xdoc = Helpers.LoadXmlDocument(xmlstream);
}
return xdoc;
}
private Stream GetXmlDoc()
protected override XmlDocument FetchCheckForUpdatesXml()
{
try
{
WebRequest wr = WebRequest.Create(newLocation);
return wr.GetResponse().GetResponseStream();
XmlDocument doc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings
{
IgnoreComments = true,
IgnoreWhitespace = true,
IgnoreProcessingInstructions = true
};
WebRequest wr = WebRequest.Create(_url);
using (Stream xmlStream = wr.GetResponse().GetResponseStream())
{
if (xmlStream != null)
using (var reader = XmlReader.Create(xmlStream, settings))
doc.Load(reader);
}
return doc;
}
catch (Exception)
{
ErrorRaised = new CFUValidationException("Failed to wget the URL: " + newLocation);
ErrorRaised = new CFUValidationException("Failed to wget the URL: " + _url);
throw ErrorRaised;
}
}
public Exception ErrorRaised { get; private set; }
}
}

View File

@ -38,40 +38,37 @@ namespace CFUValidator.Updates
{
class ReadFromFileUpdatesXmlSource : DownloadUpdatesXmlAction, ICheckForUpdatesXMLSource
{
private readonly string newLocation;
private readonly string _location;
public ReadFromFileUpdatesXmlSource(string location)
: base(true, true, true, "CFU", "1", location)
: base(true, true, true, "CFU", "1")
{
newLocation = location;
ErrorRaised = null;
_location = location ?? throw new ArgumentNullException(nameof(location));
}
protected override XmlDocument FetchCheckForUpdatesXml(string location)
protected override XmlDocument FetchCheckForUpdatesXml()
{
if (!File.Exists(newLocation))
if (!File.Exists(_location))
{
ErrorRaised = new CFUValidationException("File not found at: " + newLocation);
ErrorRaised = new CFUValidationException("File not found at: " + _location);
throw ErrorRaised;
}
try
{
XmlDocument xdoc = new XmlDocument();
using (StreamReader sr = new StreamReader(newLocation))
{
using (StreamReader sr = new StreamReader(_location))
xdoc.Load(sr);
}
return xdoc;
}
catch(Exception)
{
ErrorRaised = new CFUValidationException("Could not read/parse file: " + newLocation);
ErrorRaised = new CFUValidationException("Could not read/parse file: " + _location);
throw ErrorRaised;
}
}
public Exception ErrorRaised { get; private set; }
}
}

View File

@ -165,7 +165,11 @@ namespace XenAdmin.Core
public static string AdditionalFeatures => ReadInstalledKey(ADDITIONAL_FEATURES);
public static string CustomUpdatesXmlLocation => ReadString(CUSTOM_UPDATES_XML_LOCATION);
public static string GetCustomUpdatesXmlLocation()
{
return ReadRegistryValue(RegistryHive.CurrentUser, XENCENTER_LOCAL_KEYS, CUSTOM_UPDATES_XML_LOCATION) ??
ReadRegistryValue(RegistryHive.LocalMachine, XENCENTER_LOCAL_KEYS, CUSTOM_UPDATES_XML_LOCATION);
}
public static string CustomHelpUrl => ReadString(HELP_URL_OVERRIDE);

View File

@ -50,8 +50,6 @@ namespace XenAdmin.Core
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string CheckForUpdatesUrl = Registry.CustomUpdatesXmlLocation ?? BrandManager.UpdatesUrl;
public static event Action<bool, string> CheckForUpdatesCompleted;
public static event Action CheckForUpdatesStarted;
public static event Action RestoreDismissedUpdatesStarted;
@ -122,7 +120,7 @@ namespace XenAdmin.Core
string userAgentId = GetUniqueIdHash();
return new DownloadUpdatesXmlAction(checkForXenCenter, checkForServerVersion, checkForPatches,
userAgent, userAgentId, CheckForUpdatesUrl);
userAgent, userAgentId);
}
internal static string GetUniqueIdHash()

View File

@ -212,6 +212,11 @@ namespace XenAdmin
public string GetXenCenterMetadata(bool isForXenCenter)
{
return Metadata.Generate(PluginManager, isForXenCenter);
}
}
public string GetCustomUpdatesXmlLocation()
{
return Registry.GetCustomUpdatesXmlLocation();
}
}
}

View File

@ -32,13 +32,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using XenAPI;
using System.IO;
using System.Xml;
using XenAdmin.Core;
using System.Diagnostics;
using System.Net;
using System.Text;
namespace XenAdmin.Actions
@ -54,9 +52,9 @@ namespace XenAdmin.Actions
private const string RequiredPatchNode = "requiredpatch";
public List<XenCenterVersion> XenCenterVersions { get; private set; }
public List<XenServerVersion> XenServerVersions { get; private set; }
public List<XenServerPatch> XenServerPatches { get; private set; }
public List<XenCenterVersion> XenCenterVersions { get; } = new List<XenCenterVersion>();
public List<XenServerVersion> XenServerVersions { get; } = new List<XenServerVersion>();
public List<XenServerPatch> XenServerPatches { get; } = new List<XenServerPatch>();
public List<XenServerVersion> XenServerVersionsForAutoCheck
{
@ -73,24 +71,17 @@ namespace XenAdmin.Actions
private readonly bool _checkForXenCenter;
private readonly bool _checkForServerVersion;
private readonly bool _checkForPatches;
private readonly string _checkForUpdatesUrl;
private readonly string _userAgent;
private readonly string _userAgentId;
public DownloadUpdatesXmlAction(bool checkForXenCenter, bool checkForServerVersion, bool checkForPatches, string userAgent, string userAgentId, string checkForUpdatesUrl)
public DownloadUpdatesXmlAction(bool checkForXenCenter, bool checkForServerVersion, bool checkForPatches, string userAgent, string userAgentId)
: base(null, "_get_updates", "_get_updates", true)
{
Debug.Assert(checkForUpdatesUrl != null, "Parameter checkForUpdatesUrl should not be null. This class does not default its value anymore.");
Debug.Assert(!string.IsNullOrWhiteSpace(userAgent) && !string.IsNullOrWhiteSpace(userAgentId));
XenServerPatches = new List<XenServerPatch>();
XenServerVersions = new List<XenServerVersion>();
XenCenterVersions = new List<XenCenterVersion>();
_checkForXenCenter = checkForXenCenter;
_checkForServerVersion = checkForServerVersion;
_checkForPatches = checkForPatches;
_checkForUpdatesUrl = checkForUpdatesUrl;
_userAgent = userAgent;
_userAgentId = userAgentId;
}
@ -99,12 +90,11 @@ namespace XenAdmin.Actions
{
this.Description = Messages.AVAILABLE_UPDATES_SEARCHING;
XmlDocument xdoc = FetchCheckForUpdatesXml(_checkForUpdatesUrl);
XmlDocument xdoc = FetchCheckForUpdatesXml();
GetXenCenterVersions(xdoc);
GetXenServerPatches(xdoc);
GetXenServerVersions(xdoc);
}
private void GetXenCenterVersions(XmlDocument xdoc)
@ -327,18 +317,20 @@ namespace XenAdmin.Actions
}
}
protected virtual XmlDocument FetchCheckForUpdatesXml(string location)
protected virtual XmlDocument FetchCheckForUpdatesXml()
{
var xdoc = new XmlDocument();
var uri = new Uri(location);
var proxy = XenAdminConfigManager.Provider.GetProxyFromSettings(Connection, false);
var checkForUpdatesUrl = XenAdminConfigManager.Provider.GetCustomUpdatesXmlLocation() ?? BrandManager.UpdatesUrl;
var uri = new Uri(checkForUpdatesUrl);
if (uri.IsFile)
{
xdoc.Load(location);
xdoc.Load(checkForUpdatesUrl);
}
else
{
var proxy = XenAdminConfigManager.Provider.GetProxyFromSettings(Connection, false);
using (var webClient = new WebClient())
{
webClient.Proxy = proxy;
@ -346,9 +338,7 @@ namespace XenAdmin.Actions
webClient.Headers.Add("X-User-Agent-Id", _userAgentId);
using (var stream = new MemoryStream(webClient.DownloadData(uri)))
{
xdoc.Load(stream);
}
}
}

View File

@ -1445,25 +1445,6 @@ namespace XenAdmin.Core
return null;
}
/// <summary>
/// Load an xml stream and ignore comments and whitespace
/// </summary>
/// <param name="xmlStream"></param>
/// <returns></returns>
public static XmlDocument LoadXmlDocument(Stream xmlStream)
{
XmlDocument doc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
settings.IgnoreProcessingInstructions = true;
doc.Load(XmlReader.Create(xmlStream, settings));
return doc;
}
public static Regex HostnameOrIpRegex = new Regex(@"[\w.]+");
public static string HostnameFromLocation(string p)

View File

@ -63,5 +63,6 @@ namespace XenAdmin
void SaveSettingsIfRequired();
bool ShowHiddenVMs { get; }
string GetXenCenterMetadata(bool isForXenCenter);
string GetCustomUpdatesXmlLocation();
}
}

View File

@ -73,6 +73,11 @@ namespace XenServerHealthCheck
return metadataString.Replace(HealthCheckSettings.REPORT_TIME_PLACEHOLDER, DateTime.UtcNow.ToString("u"));
}
public string GetCustomUpdatesXmlLocation()
{
return string.Empty;
}
public int GetProxyTimeout(bool timeout)
{
return timeout ? Properties.Settings.Default.HttpTimeout : 0;