From 8013ab3d9d24d734a34a4cdc49516fb1f1342e1c Mon Sep 17 00:00:00 2001 From: Buddhika Chathuranga Date: Tue, 11 Aug 2020 16:35:23 +0530 Subject: [PATCH] Upate extension yaml support Remove old object query class and add methods to extension which can take yaml objects as aruments. Add unit test for runawayprocesskiller for yaml support --- .../Configuration/DefaultSettings.cs | 5 +- .../Configuration/IWinSWConfiguration.cs | 4 +- .../Configuration/YamlConfiguration.cs | 28 +-- .../Extensions/AbstractWinSWExtension.cs | 11 +- .../ExtensionConfigurationProvider.cs | 61 ------- .../WinSWCore/Extensions/IWinSWExtension.cs | 14 +- .../Extensions/WinSWExtensionConfiguration.cs | 23 --- .../Extensions/WinSWExtensionDescriptor.cs | 21 ++- .../Extensions/WinSWExtensionManager.cs | 85 ++++++++- src/Core/WinSWCore/ServiceDescriptor.cs | 15 +- src/Core/WinSWCore/Util/ConfigHelper.cs | 12 ++ src/Core/WinSWCore/Util/ObjectQuery.cs | 165 ------------------ .../RunawayProcessKillerExtension.cs | 33 +++- .../SharedDirectoryMapper.cs | 43 ++++- .../SharedDirectoryMapperConfig.cs | 19 +- .../Extensions/RunawayProcessKillerTest.cs | 42 ++++- src/Test/winswTests/YamlExtensionTest.cs | 70 -------- 17 files changed, 276 insertions(+), 375 deletions(-) delete mode 100644 src/Core/WinSWCore/Extensions/ExtensionConfigurationProvider.cs delete mode 100644 src/Core/WinSWCore/Extensions/WinSWExtensionConfiguration.cs delete mode 100644 src/Core/WinSWCore/Util/ObjectQuery.cs delete mode 100644 src/Test/winswTests/YamlExtensionTest.cs diff --git a/src/Core/WinSWCore/Configuration/DefaultSettings.cs b/src/Core/WinSWCore/Configuration/DefaultSettings.cs index ec35ba4..d5c94bb 100644 --- a/src/Core/WinSWCore/Configuration/DefaultSettings.cs +++ b/src/Core/WinSWCore/Configuration/DefaultSettings.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Xml; using WMI; namespace WinSW.Configuration @@ -132,7 +133,9 @@ namespace WinSW.Configuration public bool BeepOnShutdown => false; // Extensions - public object? ExtensionsConfiguration => null; + public XmlNode? ExtensionsConfiguration => null; + + public object? YamlExtensionsConfiguration => null; public string BaseName { diff --git a/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs b/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs index fd3786c..61d1493 100644 --- a/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs +++ b/src/Core/WinSWCore/Configuration/IWinSWConfiguration.cs @@ -74,7 +74,9 @@ namespace WinSW.Configuration bool BeepOnShutdown { get; } // Extensions - object? ExtensionsConfiguration { get; } + XmlNode? ExtensionsConfiguration { get; } + + object? YamlExtensionsConfiguration { get; } List ExtensionIds { get; } diff --git a/src/Core/WinSWCore/Configuration/YamlConfiguration.cs b/src/Core/WinSWCore/Configuration/YamlConfiguration.cs index 8356c32..e3e20ba 100644 --- a/src/Core/WinSWCore/Configuration/YamlConfiguration.cs +++ b/src/Core/WinSWCore/Configuration/YamlConfiguration.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Xml; using WinSW.Native; using WinSW.Util; using WMI; @@ -98,9 +99,6 @@ namespace WinSW.Configuration [YamlMember(Alias = "securityDescriptor")] public string? SecurityDescriptorYaml { get; set; } - [YamlMember(Alias = "extensions")] - public object? YamlExtensions { get; set; } - public class YamlEnv { [YamlMember(Alias = "name")] @@ -640,26 +638,32 @@ namespace WinSW.Configuration public string LogMode => this.Log.Mode is null ? this.Defaults.LogMode : this.Log.Mode; - public object? ExtensionsConfiguration => this.YamlExtensions; + // TODO - Extensions + public XmlNode? ExtensionsConfiguration => null; + + // YAML Extension + [YamlMember(Alias = "extensions")] + public object? YamlExtensionsConfiguration { get; set; } public List ExtensionIds { get { - var result = new List(0); - var extensions = this.ExtensionsConfiguration; + var result = new List(); - if (extensions is null) + if (!(this.YamlExtensionsConfiguration is List extensions)) { return result; } - var extensionConfigListObject = new ObjectQuery(extensions).AsList(); - - foreach (var item in extensionConfigListObject) + foreach (var item in extensions) { - var configObject = new ObjectQuery(item); - var id = configObject.On("id").AsString(); + if (!(item is Dictionary dict)) + { + continue; + } + + var id = (string)dict["id"]; result.Add(id); } diff --git a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs index 097ad33..58132b3 100644 --- a/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs +++ b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs @@ -1,5 +1,5 @@ -using WinSW.Configuration; -using WinSW.Util; +using System.Xml; +using WinSW.Configuration; namespace WinSW.Extensions { @@ -11,7 +11,12 @@ namespace WinSW.Extensions public WinSWExtensionDescriptor Descriptor { get; set; } #pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. - public virtual void Configure(IWinSWConfiguration descriptor, ObjectQuery settings) + public virtual void Configure(IWinSWConfiguration descriptor, XmlNode node) + { + // Do nothing + } + + public virtual void Configure(IWinSWConfiguration descriptor, object yamlObject) { // Do nothing } diff --git a/src/Core/WinSWCore/Extensions/ExtensionConfigurationProvider.cs b/src/Core/WinSWCore/Extensions/ExtensionConfigurationProvider.cs deleted file mode 100644 index f2f8e1d..0000000 --- a/src/Core/WinSWCore/Extensions/ExtensionConfigurationProvider.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Collections.Generic; -using WinSW.Configuration; -using WinSW.Util; - -namespace WinSW.Extensions -{ - public class ExtensionConfigurationProvider - { - private readonly IWinSWConfiguration serviceDescriptor; - - private readonly List extensionConfigList; - - public ExtensionConfigurationProvider(IWinSWConfiguration serviceConfigs) - { - this.serviceDescriptor = serviceConfigs; - this.extensionConfigList = this.CreateExtensionConfigList(); - } - - public WinSWExtensionConfiguration? GetExtenstionConfiguration(string id) - { - foreach (var item in this.extensionConfigList) - { - if (item.Id.Equals(id)) - { - return item; - } - } - - return null; - } - - private List CreateExtensionConfigList() - { - var result = new List(0); - - var extensions = this.serviceDescriptor.ExtensionsConfiguration; - - if (extensions is null) - { - return result; - } - - var extensionNodes = new ObjectQuery(extensions).AsList(); - - foreach (var extension in extensionNodes) - { - var query = new ObjectQuery(extension); - - var id = query.On("id").AsString(); - var enabled = query.On("enabled").AsBool(); - var className = query.On("classname").AsString(); - var settings = query.On("settings").AsParent(); - - var extensionConfig = new WinSWExtensionConfiguration(id, enabled, className, settings); - result.Add(extensionConfig); - } - - return result; - } - } -} diff --git a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs index e9e2556..dabd13b 100644 --- a/src/Core/WinSWCore/Extensions/IWinSWExtension.cs +++ b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs @@ -1,5 +1,5 @@ -using WinSW.Configuration; -using WinSW.Util; +using System.Xml; +using WinSW.Configuration; namespace WinSW.Extensions { @@ -27,7 +27,15 @@ namespace WinSW.Extensions /// Init handler. Extension should load it's config during that step /// /// Service descriptor - void Configure(IWinSWConfiguration descriptor, ObjectQuery settings); + /// Configuration node + void Configure(IWinSWConfiguration descriptor, XmlNode node); + + /// + /// Configure the extension from Yaml configuration + /// + /// Yaml Service Descptor + /// Configuration Node + void Configure(IWinSWConfiguration descriptor, object yamlObject); /// /// Start handler. Called during startup of the service before the child process. diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionConfiguration.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionConfiguration.cs deleted file mode 100644 index e730148..0000000 --- a/src/Core/WinSWCore/Extensions/WinSWExtensionConfiguration.cs +++ /dev/null @@ -1,23 +0,0 @@ -using WinSW.Util; - -namespace WinSW.Extensions -{ - public class WinSWExtensionConfiguration - { - public string Id { get; set; } - - public bool Enabled { get; set; } - - public string ClassName { get; set; } - - public ObjectQuery Settings { get; set; } - - public WinSWExtensionConfiguration(string id, bool enabled, string className, ObjectQuery settings) - { - this.Id = id; - this.Enabled = enabled; - this.ClassName = className; - this.Settings = settings; - } - } -} diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs index 105a686..383857b 100644 --- a/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs +++ b/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs @@ -1,4 +1,7 @@ -using System.Xml; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Xml; using WinSW.Util; namespace WinSW.Extensions @@ -26,7 +29,7 @@ namespace WinSW.Extensions /// public string ClassName { get; private set; } - public WinSWExtensionDescriptor(string id, string className, bool enabled) + private WinSWExtensionDescriptor(string id, string className, bool enabled) { this.Id = id; this.Enabled = enabled; @@ -40,5 +43,19 @@ namespace WinSW.Extensions string id = XmlHelper.SingleAttribute(node, "id"); return new WinSWExtensionDescriptor(id, className, enabled); } + + public static WinSWExtensionDescriptor FromYaml(object node) + { + if (!(node is Dictionary config)) + { + throw new InvalidDataException("Cannot get the configuration entry"); + } + + bool enabled = ConfigHelper.YamlBoolParse((string)config["enabled"]); + string className = (string)config["classname"]; + string id = (string)config["id"]; + + return new WinSWExtensionDescriptor(id, className, enabled); + } } } diff --git a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs index e00508a..c6809fa 100644 --- a/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs +++ b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Xml; using log4net; using WinSW.Configuration; @@ -11,15 +13,12 @@ namespace WinSW.Extensions public IWinSWConfiguration ServiceDescriptor { get; private set; } - public ExtensionConfigurationProvider ConfigProvider { get; private set; } - private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager)); public WinSWExtensionManager(IWinSWConfiguration serviceDescriptor) { this.ServiceDescriptor = serviceDescriptor; this.Extensions = new Dictionary(); - this.ConfigProvider = new ExtensionConfigurationProvider(this.ServiceDescriptor); } /// @@ -129,21 +128,34 @@ namespace WinSW.Extensions throw new ExtensionException(id, "Extension has been already loaded"); } - var configNode = this.ConfigProvider.GetExtenstionConfiguration(id); + if (this.ServiceDescriptor.GetType() == typeof(ServiceDescriptor)) + { + this.LoadExtensionFromXml(id); + } + else + { + this.LoadExtensionFromYaml(id); + } + } + private void LoadExtensionFromXml(string id) + { + XmlNode? extensionsConfig = this.ServiceDescriptor.ExtensionsConfiguration; + XmlElement? configNode = extensionsConfig is null ? null : extensionsConfig.SelectSingleNode("extension[@id='" + id + "'][1]") as XmlElement; if (configNode is null) { throw new ExtensionException(id, "Cannot get the configuration entry"); } - var descriptor = new WinSWExtensionDescriptor(configNode.Id, configNode.ClassName, configNode.Enabled); + var descriptor = WinSWExtensionDescriptor.FromXml(configNode); + if (descriptor.Enabled) { IWinSWExtension extension = this.CreateExtensionInstance(descriptor.Id, descriptor.ClassName); extension.Descriptor = descriptor; try { - extension.Configure(this.ServiceDescriptor, configNode.Settings); + extension.Configure(this.ServiceDescriptor, configNode); } catch (Exception ex) { // Consider any unexpected exception as fatal @@ -160,6 +172,67 @@ namespace WinSW.Extensions } } + private void LoadExtensionFromYaml(string id) + { + var extensionConfigList = this.ServiceDescriptor.YamlExtensionsConfiguration as List; + + if (extensionConfigList is null) + { + throw new ExtensionException(id, "Cannot get the configuration entry"); + } + + object? configNode = GetYamlonfigById(extensionConfigList, id); + + if (configNode is null) + { + throw new ExtensionException(id, "Cannot get the configuration entry"); + } + + var descriptor = WinSWExtensionDescriptor.FromYaml(configNode); + + if (descriptor.Enabled) + { + IWinSWExtension extension = this.CreateExtensionInstance(descriptor.Id, descriptor.ClassName); + extension.Descriptor = descriptor; + + if (!(configNode is Dictionary dict)) + { + // TODO : Replace with exntension exception + throw new InvalidDataException("Error in config node"); + } + + try + { + extension.Configure(this.ServiceDescriptor, dict["settings"]); + } + catch (Exception ex) + { // Consider any unexpected exception as fatal + Log.Fatal("Failed to configure the extension " + id, ex); + throw ex; + } + + this.Extensions.Add(id, extension); + Log.Info("Extension loaded: " + id); + } + else + { + Log.Warn("Extension is disabled: " + id); + } + + object? GetYamlonfigById(List configs, string id) + { + foreach (var item in configs) + { + if (item is Dictionary config && config["id"].Equals(id)) + { + return item; + } + } + + return null; + } + } + private IWinSWExtension CreateExtensionInstance(string id, string className) { object created; diff --git a/src/Core/WinSWCore/ServiceDescriptor.cs b/src/Core/WinSWCore/ServiceDescriptor.cs index 6f21c0c..b088987 100644 --- a/src/Core/WinSWCore/ServiceDescriptor.cs +++ b/src/Core/WinSWCore/ServiceDescriptor.cs @@ -208,7 +208,7 @@ namespace WinSW } } - /*public List ExtensionIds + public List ExtensionIds { get { @@ -227,18 +227,9 @@ namespace WinSW return result; } - }*/ - - public List ExtensionIds - { - get - { - return new List(0); - } } - // public XmlNode? ExtensionsConfiguration => this.dom.SelectSingleNode("//extensions"); - public object? ExtensionsConfiguration { get; set; } + public XmlNode? ExtensionsConfiguration => this.dom.SelectSingleNode("//extensions"); /// /// Combines the contents of all the elements of the given name, @@ -712,5 +703,7 @@ namespace WinSW return environment; } + + public object? YamlExtensionsConfiguration => null; } } diff --git a/src/Core/WinSWCore/Util/ConfigHelper.cs b/src/Core/WinSWCore/Util/ConfigHelper.cs index 8ca87fa..07bbe3f 100644 --- a/src/Core/WinSWCore/Util/ConfigHelper.cs +++ b/src/Core/WinSWCore/Util/ConfigHelper.cs @@ -33,5 +33,17 @@ namespace WinSW.Util { "day", 1000L * 60L * 60L * 24L }, { "days", 1000L * 60L * 60L * 24L } }; + + public static bool YamlBoolParse(string value) + { + value = value.ToLower(); + + if (value.Equals("true") || value.Equals("yes") || value.Equals("on")) + { + return true; + } + + return false; + } } } diff --git a/src/Core/WinSWCore/Util/ObjectQuery.cs b/src/Core/WinSWCore/Util/ObjectQuery.cs deleted file mode 100644 index f3232ff..0000000 --- a/src/Core/WinSWCore/Util/ObjectQuery.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace WinSW.Util -{ - public class ObjectQuery - { - private readonly object configObject; - private object? current; - private string? key; - - public ObjectQuery(object? config) - { - if (config is null) - { - throw new InvalidDataException("Query object is null"); - } - - this.configObject = config; - this.current = this.configObject; - } - - public ObjectQuery On(string key) - { - this.key = key; - this.current = this.Query(this.configObject, key); - return this; - } - - public ObjectQuery Get(string key) - { - if (this.current == null) - { - throw new InvalidDataException("The key <" + key + "> is not exist"); - } - - this.key = key; - this.current = this.Query(this.current, key); - return this; - } - - public string AsString() - { - if (this.current == null) - { - throw new InvalidDataException("The key <" + this.key + "> is not exist"); - } - - var result = this.current as string; - - if (result == null) - { - throw new InvalidDataException(this.key + " can't converto to a string"); - } - - return result; - } - - public List AsList() - { - if (this.current == null) - { - throw new InvalidDataException("The key <" + this.key + "> is not exist"); - } - - var list = this.current as List; - - if (list == null) - { - throw new InvalidDataException(this.key + " can't converto to List<" + typeof(T) + ">"); - } - - var result = new List(0); - foreach (var item in list) - { - result.Add((T)item); - } - - return result; - } - - public bool AsBool() - { - if (this.current == null) - { - throw new InvalidDataException("The key <" + this.key + "> is not exist"); - } - - var value = this.current as string; - - if (value == null) - { - throw new InvalidDataException(this.key + " can't convert into bool"); - } - - if (value == "true" || value == "yes" || value == "on") - { - return true; - } - else if (value == "false" || value == "no" || value == "off") - { - return false; - } - else - { - throw new InvalidDataException(value + " cannot convert into bool"); - } - } - - public ObjectQuery At(int index) - { - if (this.current == null) - { - throw new InvalidDataException("The key <" + this.key + "> is not exist"); - } - - var list = this.current as List; - - if (list == null) - { - throw new InvalidDataException("Can't execute At(index) on " + this.key); - } - - try - { - var result = list[index]; - this.current = result; - } - catch (IndexOutOfRangeException) - { - throw new InvalidDataException("Index " + index + " not in range"); - } - - return this; - } - - private object? Query(object? dic, string key) - { - if (dic == null) - { - throw new InvalidDataException(key + " is not found"); - } - - var dict = dic as IDictionary; - if (dict != null) - { - foreach (KeyValuePair kvp in dict) - { - if (kvp.Key as string == key) - { - return kvp.Value; - } - } - } - - return null; - } - - public ObjectQuery AsParent() - { - return new ObjectQuery(this.current); - } - } -} diff --git a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs index f0b2abc..59e6761 100644 --- a/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs +++ b/src/Plugins/RunawayProcessKiller/RunawayProcessKillerExtension.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Text; +using System.Xml; using log4net; using WinSW.Configuration; using WinSW.Extensions; @@ -179,20 +181,39 @@ namespace WinSW.Plugins.RunawayProcessKiller return parameters.Environment; } - public override void Configure(IWinSWConfiguration descriptor, ObjectQuery settings) + public override void Configure(IWinSWConfiguration descriptor, XmlNode node) { - this.Pidfile = settings.On("pidfile").AsString(); - this.StopTimeout = TimeSpan.FromMilliseconds(int.Parse(settings.On("stopTimeOut").AsString())); - this.StopParentProcessFirst = settings.On("StopParentFirst").AsBool(); + // We expect the upper logic to process any errors + // TODO: a better parser API for types would be useful + this.Pidfile = XmlHelper.SingleElement(node, "pidfile", false)!; + this.StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)!)); + this.StopParentProcessFirst = bool.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false)!); + this.ServiceId = descriptor.Id; + // TODO: Consider making it documented + var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true); + this.CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable is null ? true : bool.Parse(checkWinSWEnvironmentVariable); + } + + public override void Configure(IWinSWConfiguration descriptor, object yamlObject) + { + if (!(yamlObject is Dictionary dict)) + { + // TODO : throw ExtensionException + throw new InvalidDataException("Cann't configure"); + } + + this.Pidfile = (string)dict["pidfile"]; + this.StopTimeout = TimeSpan.FromMilliseconds(int.Parse((string)dict["stopTimeOut"])); + this.StopParentProcessFirst = bool.Parse((string)dict["StopParentFirst"]); + try { - this.CheckWinSWEnvironmentVariable = settings.Get("checkWinSWEnvironmentVariable").AsBool(); + this.CheckWinSWEnvironmentVariable = bool.Parse((string)dict["checkWinSWEnvironmentVariable"]); } catch { this.CheckWinSWEnvironmentVariable = true; } - this.ServiceId = descriptor.Id; } /// diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs index 4175931..35aa45b 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.IO; +using System.Xml; using log4net; using WinSW.Configuration; using WinSW.Extensions; @@ -26,18 +28,41 @@ namespace WinSW.Plugins.SharedDirectoryMapper this._entries.Add(config); } - public override void Configure(IWinSWConfiguration descriptor, ObjectQuery settings) + public override void Configure(IWinSWConfiguration descriptor, XmlNode node) { - var maps = settings.On("mapping").AsList(); - - foreach (var map in maps) + XmlNodeList? mapNodes = XmlHelper.SingleNode(node, "mapping", false)!.SelectNodes("map"); + if (mapNodes != null) { - var mapObject = new ObjectQuery(map); - var enable = mapObject.On("enabled").AsBool(); - var label = mapObject.On("label").AsString(); - var uncpath = mapObject.On("uncpath").AsString(); + for (int i = 0; i < mapNodes.Count; i++) + { + if (mapNodes[i] is XmlElement mapElement) + { + var config = SharedDirectoryMapperConfig.FromXml(mapElement); + this._entries.Add(config); + } + } + } + } - var config = new SharedDirectoryMapperConfig(enable, label, uncpath); + public override void Configure(IWinSWConfiguration descriptor, object yamlObject) + { + if (!(yamlObject is Dictionary dict)) + { + // TODO : throw ExtensionException + throw new InvalidDataException("Conn't configure"); + } + + var mappingNode = dict["mapping"]; + + if (!(mappingNode is List mappings)) + { + // TODO : throw ExtensionException + throw new InvalidDataException("Conn't configure"); + } + + foreach (var map in mappings) + { + var config = SharedDirectoryMapperConfig.FromYaml(map); this._entries.Add(config); } } diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs index 273e207..0a9402c 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs @@ -1,4 +1,6 @@ -using System.Xml; +using System.Collections.Generic; +using System.IO; +using System.Xml; using WinSW.Util; namespace WinSW.Plugins.SharedDirectoryMapper @@ -26,5 +28,20 @@ namespace WinSW.Plugins.SharedDirectoryMapper string uncPath = XmlHelper.SingleAttribute(node, "uncpath"); return new SharedDirectoryMapperConfig(enableMapping, label, uncPath); } + + public static SharedDirectoryMapperConfig FromYaml(object yamlObject) + { + if (!(yamlObject is Dictionary dict)) + { + // TODO : throw ExtensionExeption + throw new InvalidDataException("SharedDirectoryMapperConfig config error"); + } + + bool enableMapping = ConfigHelper.YamlBoolParse((string)dict["enabled"]); + string label = (string)dict["label"]; + string uncPath = (string)dict["uncpath"]; + + return new SharedDirectoryMapperConfig(enableMapping, label, uncPath); + } } } diff --git a/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs b/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs index b92bcfb..ae86acc 100644 --- a/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs +++ b/src/Test/winswTests/Extensions/RunawayProcessKillerTest.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using NUnit.Framework; using WinSW; +using WinSW.Configuration; using WinSW.Extensions; using WinSW.Plugins.RunawayProcessKiller; using WinSW.Util; @@ -14,7 +15,8 @@ namespace winswTests.Extensions [TestFixture] class RunawayProcessKillerExtensionTest : ExtensionTestBase { - ServiceDescriptor _testServiceDescriptor; + IWinSWConfiguration _testServiceDescriptor; + IWinSWConfiguration _testServiceDescriptorYaml; readonly string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); @@ -38,6 +40,29 @@ $@" "; this._testServiceDescriptor = ServiceDescriptor.FromXML(seedXml); + + string seedYaml = $@"--- +id: jenkins +name: Jenkins +description: This service runs Jenkins automation server. +env: + - + name: JENKINS_HOME + value: '%LocalAppData%\Jenkins.jenkins' +executable: java +arguments: >- + -Xrs -Xmx256m -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle + -jar E:\Winsw Test\yml6\jenkins.war --httpPort=8081 +extensions: + - id: killRunawayProcess + enabled: yes + classname: ""{this.testExtension}"" + settings: + pidfile: 'foo/bar/pid.txt' + stopTimeOut: 5000 + StopParentFirst: true"; + + this._testServiceDescriptorYaml = ServiceDescriptorYaml.FromYaml(seedYaml).Configurations; } [Test] @@ -55,6 +80,21 @@ $@" Assert.AreEqual(true, extension.StopParentProcessFirst, "Loaded StopParentFirst is not equal to the expected one"); } + [Test] + public void LoadExtensionsYaml() + { + WinSWExtensionManager manager = new WinSWExtensionManager(this._testServiceDescriptorYaml); + manager.LoadExtensions(); + Assert.AreEqual(1, manager.Extensions.Count, "One extension should be loaded"); + + // Check the file is correct + var extension = manager.Extensions["killRunawayProcess"] as RunawayProcessKillerExtension; + Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded"); + Assert.AreEqual("foo/bar/pid.txt", extension.Pidfile, "Loaded PID file path is not equal to the expected one"); + Assert.AreEqual(5000, extension.StopTimeout.TotalMilliseconds, "Loaded Stop Timeout is not equal to the expected one"); + Assert.AreEqual(true, extension.StopParentProcessFirst, "Loaded StopParentFirst is not equal to the expected one"); + } + [Test] public void StartStopExtension() { diff --git a/src/Test/winswTests/YamlExtensionTest.cs b/src/Test/winswTests/YamlExtensionTest.cs deleted file mode 100644 index f81cb2e..0000000 --- a/src/Test/winswTests/YamlExtensionTest.cs +++ /dev/null @@ -1,70 +0,0 @@ -using NUnit.Framework; -using WinSW; -using WinSW.Configuration; -using WinSW.Extensions; -using WinSW.Plugins.RunawayProcessKiller; -using WinSW.Util; -using winswTests.Extensions; - -namespace winswTests -{ - public class YamlExtensionTest : ExtensionTestBase - { - private IWinSWConfiguration _testServiceDescriptor { get; set; } - - readonly string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension)); - - [SetUp] - public void SetUp() - { - - string yamlDoc = $@"id: SERVICE_NAME -name: Jenkins Slave -description: This service runs Jenkins automation server. -executable: java -arguments: -Xrs -jar \""%BASE%\slave.jar\"" -jnlpUrl ... -extensions: - - id: killOnStartup - enabled: yes - classname: ""{this.testExtension}"" - settings: - pidfile: pid.txt - stopTimeOut: 5000 - StopParentFirst: true"; - - this._testServiceDescriptor = ServiceDescriptorYaml.FromYaml(yamlDoc).Configurations; - } - - - [Test] - public void LoadExtensions() - { - - WinSWExtensionManager manager = new WinSWExtensionManager(this._testServiceDescriptor); - manager.LoadExtensions(); - Assert.AreEqual(1, manager.Extensions.Count, "One extension should be loaded"); - - // Check the file is correct - var extension = manager.Extensions["killRunawayProcess"] as RunawayProcessKillerExtension; - Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded"); - Assert.AreEqual("foo/bar/pid.txt", extension.Pidfile, "Loaded PID file path is not equal to the expected one"); - Assert.AreEqual(5000, extension.StopTimeout.TotalMilliseconds, "Loaded Stop Timeout is not equal to the expected one"); - Assert.AreEqual(true, extension.StopParentProcessFirst, "Loaded StopParentFirst is not equal to the expected one"); - } - - [Test] - public void Sample_test() - { - ExtensionConfigurationProvider provider = new ExtensionConfigurationProvider(this._testServiceDescriptor); - var config = provider.GetExtenstionConfiguration("killOnStartup"); - - var pid = config.Settings.On("pidfile").AsString(); - var stopTimeOut = config.Settings.On("stopTimeOut").AsString(); - var StopParentFirst = config.Settings.On("StopParentFirst").AsString(); - - System.Console.WriteLine(pid); - System.Console.WriteLine(stopTimeOut); - System.Console.WriteLine(StopParentFirst); - } - } -}