mirror of https://github.com/winsw/winsw
Introduce the Download#FailOnError option. (#195)
* Introduce the Download#FailOnError option. The change also adds logging of download operations to the wrapper log * Add documentation for the failOnError flagpull/207/head
parent
5803d3ce15
commit
f0770a0e15
|
@ -159,12 +159,20 @@ For servers requiring authentication some parameters must be specified depending
|
|||
The parameter “unsecureAuth” is only effective when the transfer protocol is HTTP - unencrypted data transfer. This is a security vulnerability because the credentials are send in clear text! For a SSPI authentication this is not relevant because the authentication tokens are encrypted.
|
||||
|
||||
For target servers using the HTTPS transfer protocol it is necessary, that the CA which issued the server certificate is trusted by the client. This is normally the situation when the server ist located in the Internet. When an organisation is using a self issued CA for the intranet this probably is not the case. In this case it is necessary to import the CA to the Certificate MMC of the Windows client. Have a look to the instructions on this [site](https://msdn.microsoft.com/de-de/library/system.net.credentialcache.defaultcredentials(v=vs.85).aspx). The self issued CA must be imported to the Trusted Root Certification Authorities for the computer.
|
||||
```
|
||||
|
||||
By default, the `download` command does not fail the service startup if the operation fails (e.g. `from` is not available).
|
||||
In order to force the download failure in such case, it is possible to specify the `failOnError` boolean attribute.
|
||||
|
||||
Examples:
|
||||
|
||||
```xml
|
||||
<download from="http://example.com/some.dat" to="%BASE%\some.dat" />
|
||||
|
||||
<download from="http://example.com/some.dat" to="%BASE%\some.dat" failOnError="true"/>
|
||||
|
||||
<download from="https://example.com/some.dat" to="%BASE%\some.dat" auth="sspi" />
|
||||
|
||||
<download from="https://example.com/some.dat" to="%BASE%\some.dat"
|
||||
<download from="https://example.com/some.dat" to="%BASE%\some.dat" failOnError="true"
|
||||
auth="basic" username="aUser" password="aPassw0rd" />
|
||||
|
||||
<download from="http://example.com/some.dat" to="%BASE%\some.dat"
|
||||
|
|
|
@ -204,16 +204,25 @@ namespace winsw
|
|||
// handle downloads
|
||||
foreach (Download d in _descriptor.Downloads)
|
||||
{
|
||||
LogEvent("Downloading: " + d.From+ " to "+d.To);
|
||||
String downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError;
|
||||
LogEvent(downloadMsg);
|
||||
Log.Info(downloadMsg);
|
||||
try
|
||||
{
|
||||
d.Perform();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogEvent("Failed to download " + d.From + " to " + d.To + "\n" + e.Message);
|
||||
Log.Error("Failed to download " + d.From +" to "+d.To, e);
|
||||
// but just keep going
|
||||
string errorMessage = "Failed to download " + d.From + " to " + d.To;
|
||||
LogEvent(errorMessage + ". " + e.Message);
|
||||
Log.Error(errorMessage, e);
|
||||
// TODO: move this code into the download logic
|
||||
if (d.FailOnError)
|
||||
{
|
||||
throw new IOException(errorMessage, e);
|
||||
}
|
||||
|
||||
// Else just keep going
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,22 @@ namespace winsw
|
|||
public readonly string Username;
|
||||
public readonly string Password;
|
||||
public readonly bool UnsecureAuth = false;
|
||||
public readonly bool FailOnError;
|
||||
|
||||
public Download(string from, string to, bool failOnError = false)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
FailOnError = failOnError;
|
||||
}
|
||||
|
||||
internal Download(XmlNode n)
|
||||
{
|
||||
From = Environment.ExpandEnvironmentVariables(n.Attributes["from"].Value);
|
||||
To = Environment.ExpandEnvironmentVariables(n.Attributes["to"].Value);
|
||||
|
||||
var failOnErrorNode = n.Attributes["failOnError"];
|
||||
FailOnError = failOnErrorNode != null ? Boolean.Parse(failOnErrorNode.Value) : false;
|
||||
|
||||
string tmpStr = "";
|
||||
try
|
||||
|
@ -80,6 +91,12 @@ namespace winsw
|
|||
request.Headers["Authorization"] = "Basic " + authInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the requested file and puts it to the specified target.
|
||||
/// </summary>
|
||||
/// <exception cref="System.Net.WebException">
|
||||
/// Download failure. FailOnError flag should be processed outside.
|
||||
/// </exception>
|
||||
public void Perform()
|
||||
{
|
||||
WebRequest req = WebRequest.Create(From);
|
||||
|
@ -106,6 +123,15 @@ namespace winsw
|
|||
File.Move(To + ".tmp", To);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Produces the XML configuuration entry.
|
||||
/// </summary>
|
||||
/// <returns>XML String for the configuration file</returns>
|
||||
public String toXMLConfig()
|
||||
{
|
||||
return "<download from=\"" + From + "\" to=\"" + To + "\" failOnError=\"" + FailOnError + "\"/>";
|
||||
}
|
||||
|
||||
private static void CopyStream(Stream i, Stream o)
|
||||
{
|
||||
byte[] buf = new byte[8192];
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using winsw;
|
||||
using winswTests.Util;
|
||||
|
||||
namespace winswTests
|
||||
{
|
||||
[TestFixture]
|
||||
class DownloadTest
|
||||
{
|
||||
private const string From = "http://www.nosuchhostexists.foo.myorg/foo.xml";
|
||||
private const string To = "%BASE%\\foo.xml";
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the fail-on-error field is being processed correctly.
|
||||
/// </summary>
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void Download_FailOnError(bool failOnError)
|
||||
{
|
||||
Download d = new Download(From, To, failOnError);
|
||||
|
||||
var sd = ConfigXmlBuilder.create()
|
||||
.WithDownload(d)
|
||||
.ToServiceDescriptor(true);
|
||||
|
||||
var loaded = getSingleEntry(sd);
|
||||
Assert.That(loaded.From, Is.EqualTo(From));
|
||||
Assert.That(loaded.To, Is.EqualTo(To));
|
||||
Assert.That(loaded.FailOnError, Is.EqualTo(failOnError), "Unexpected FailOnError value");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the fail-on-error field is being processed correctly.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Download_FailOnError_Undefined()
|
||||
{
|
||||
var sd = ConfigXmlBuilder.create()
|
||||
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\"/>")
|
||||
.ToServiceDescriptor(true);
|
||||
|
||||
var loaded = getSingleEntry(sd);
|
||||
Assert.That(loaded.FailOnError, Is.False);
|
||||
}
|
||||
|
||||
private Download getSingleEntry(ServiceDescriptor sd)
|
||||
{
|
||||
var downloads = sd.Downloads.ToArray();
|
||||
Assert.That(downloads.Length, Is.EqualTo(1), "Service Descriptor is expected to have only one entry");
|
||||
return downloads[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -119,5 +119,10 @@ namespace winswTests.Util
|
|||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfigXmlBuilder WithDownload(Download download)
|
||||
{
|
||||
return WithRawEntry(download.toXMLConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration\ExamplesTest.cs" />
|
||||
<Compile Include="DownloadTest.cs" />
|
||||
<Compile Include="Extensions\ExtensionTestBase.cs" />
|
||||
<Compile Include="Extensions\RunawayProcessKillerTest.cs" />
|
||||
<Compile Include="Extensions\SharedDirectoryMapperTest.cs" />
|
||||
|
|
Loading…
Reference in New Issue