Browse Source

Merge "Add Murano Agent for Windows"

Jenkins 3 years ago
parent
commit
7b17e6d22e

+ 6
- 0
contrib/windows-agent/ExecutionPlanGenerator/App.config View File

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="utf-8" ?>
2
+<configuration>
3
+    <startup> 
4
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
5
+    </startup>
6
+</configuration>

+ 62
- 0
contrib/windows-agent/ExecutionPlanGenerator/ExecutionPlanGenerator.csproj View File

@@ -0,0 +1,62 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4
+  <PropertyGroup>
5
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7
+    <ProjectGuid>{501BE151-4B8C-4355-88DC-3AEF1921B2D7}</ProjectGuid>
8
+    <OutputType>Exe</OutputType>
9
+    <AppDesignerFolder>Properties</AppDesignerFolder>
10
+    <RootNamespace>Mirantis.Murano</RootNamespace>
11
+    <AssemblyName>ExecutionPlanGenerator</AssemblyName>
12
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13
+    <FileAlignment>512</FileAlignment>
14
+  </PropertyGroup>
15
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16
+    <PlatformTarget>AnyCPU</PlatformTarget>
17
+    <DebugSymbols>true</DebugSymbols>
18
+    <DebugType>full</DebugType>
19
+    <Optimize>false</Optimize>
20
+    <OutputPath>bin\Debug\</OutputPath>
21
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
22
+    <ErrorReport>prompt</ErrorReport>
23
+    <WarningLevel>4</WarningLevel>
24
+  </PropertyGroup>
25
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26
+    <PlatformTarget>AnyCPU</PlatformTarget>
27
+    <DebugType>pdbonly</DebugType>
28
+    <Optimize>true</Optimize>
29
+    <OutputPath>bin\Release\</OutputPath>
30
+    <DefineConstants>TRACE</DefineConstants>
31
+    <ErrorReport>prompt</ErrorReport>
32
+    <WarningLevel>4</WarningLevel>
33
+  </PropertyGroup>
34
+  <ItemGroup>
35
+    <Reference Include="Newtonsoft.Json">
36
+      <HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
37
+    </Reference>
38
+    <Reference Include="System" />
39
+    <Reference Include="System.Core" />
40
+    <Reference Include="System.Xml.Linq" />
41
+    <Reference Include="System.Data.DataSetExtensions" />
42
+    <Reference Include="Microsoft.CSharp" />
43
+    <Reference Include="System.Data" />
44
+    <Reference Include="System.Xml" />
45
+  </ItemGroup>
46
+  <ItemGroup>
47
+    <Compile Include="Program.cs" />
48
+    <Compile Include="Properties\AssemblyInfo.cs" />
49
+  </ItemGroup>
50
+  <ItemGroup>
51
+    <None Include="App.config" />
52
+    <None Include="packages.config" />
53
+  </ItemGroup>
54
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
55
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
56
+       Other similar extension points exist, see Microsoft.Common.targets.
57
+  <Target Name="BeforeBuild">
58
+  </Target>
59
+  <Target Name="AfterBuild">
60
+  </Target>
61
+  -->
62
+</Project>

+ 141
- 0
contrib/windows-agent/ExecutionPlanGenerator/Program.cs View File

@@ -0,0 +1,141 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.IO;
4
+using System.Linq;
5
+using System.Text;
6
+using System.Threading.Tasks;
7
+using Newtonsoft.Json;
8
+
9
+namespace Mirantis.Murano
10
+{
11
+	class Command
12
+	{
13
+		public string Name { get; set; }
14
+		public Dictionary<string, object>  Arguments { get; set; }
15
+	}
16
+	class ExecutionPlan
17
+	{
18
+		public List<string> Scripts { get; set; }
19
+		public List<Command> Commands { get; set; }
20
+		public int RebootOnCompletion { get; set; }
21
+	}
22
+
23
+
24
+	class Program
25
+	{
26
+		static void Main(string[] args)
27
+		{
28
+			if (args.Length < 1 || args.Length > 2)
29
+			{
30
+				Console.WriteLine("Usage: ExecutionPlanGenerator inputfile [outputfile]");
31
+				return;
32
+			}
33
+
34
+			var outFile = args.Length == 2 ? args[1] : null;
35
+
36
+			var plan = new ExecutionPlan {
37
+				Scripts = new List<string>(),
38
+				Commands = new List<Command>()
39
+			};
40
+
41
+
42
+
43
+			var lines = File.ReadAllLines(args[0]);
44
+
45
+
46
+			foreach (var statement in lines
47
+				.Select(t => t.Split(new[] { ' ', '\t' }, 2))
48
+				.Where(t => t.Length == 2)
49
+				.Select(t => new Tuple<string, string>(t[0].Trim().ToLower(), t[1].Trim())))
50
+			{
51
+				switch (statement.Item1)
52
+				{
53
+					case "include":
54
+						Include(statement.Item2, plan, args[0]);
55
+						break;
56
+					case "call":
57
+						Call(statement.Item2, plan);
58
+						break;
59
+					case "reboot":
60
+						plan.RebootOnCompletion = int.Parse(statement.Item2);
61
+						break;
62
+					case "out":
63
+						if (args.Length < 2)
64
+						{
65
+							var path = statement.Item2;
66
+							if (!Path.IsPathRooted(path))
67
+							{
68
+								path = Path.Combine(Path.GetDirectoryName(args[0]), path);
69
+							}
70
+							outFile = path;
71
+						}
72
+						break;
73
+				}
74
+			}
75
+
76
+			var data = JsonConvert.SerializeObject(plan, Formatting.Indented);
77
+			if (outFile == null)
78
+			{
79
+				Console.WriteLine(data);
80
+			}
81
+			else
82
+			{
83
+				File.WriteAllText(outFile, data);
84
+			}
85
+		}
86
+
87
+		private static void Call(string line, ExecutionPlan plan)
88
+		{
89
+			var parts = line.Split(new[] { ' ', '\t'}, 2);
90
+			var command = new Command() {
91
+				Name = parts[0].Trim(),
92
+				Arguments = new Dictionary<string, object>()
93
+			};
94
+
95
+
96
+			if (parts.Length == 2)
97
+			{
98
+				foreach (var x in parts[1]
99
+					.Split(',')
100
+					.Select(t => t.Split('='))
101
+					.Where(t => t.Length == 2)
102
+					.Select(t => new KeyValuePair<string, string>(t[0].Trim(), t[1].Trim())))
103
+				{
104
+					object value = null;
105
+					long num;
106
+					bool boolean;
107
+					if (x.Value.StartsWith("\""))
108
+					{
109
+						value = x.Value.Substring(1, x.Value.Length - 2);
110
+					}
111
+					else if (long.TryParse(x.Value, out num))
112
+					{
113
+						value = num;
114
+					}
115
+					else if (bool.TryParse(x.Value, out boolean))
116
+					{
117
+						value = boolean;
118
+					}
119
+					else
120
+					{
121
+						continue;
122
+					}
123
+					command.Arguments.Add(x.Key, value);
124
+				}
125
+			}
126
+			plan.Commands.Add(command);
127
+		}
128
+
129
+		private static void Include(string file, ExecutionPlan plan, string dslPath)
130
+		{
131
+			var path = file;
132
+			if (!Path.IsPathRooted(file))
133
+			{
134
+				path = Path.Combine(Path.GetDirectoryName(dslPath), path);
135
+			}
136
+
137
+			var text = File.ReadAllText(path, Encoding.UTF8);
138
+			plan.Scripts.Add(Convert.ToBase64String(Encoding.UTF8.GetBytes(text)));
139
+		}
140
+	}
141
+}

+ 36
- 0
contrib/windows-agent/ExecutionPlanGenerator/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,36 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following 
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+[assembly: AssemblyTitle("ConsoleApplication1")]
9
+[assembly: AssemblyDescription("")]
10
+[assembly: AssemblyConfiguration("")]
11
+[assembly: AssemblyCompany("")]
12
+[assembly: AssemblyProduct("ConsoleApplication1")]
13
+[assembly: AssemblyCopyright("Copyright ©  2013")]
14
+[assembly: AssemblyTrademark("")]
15
+[assembly: AssemblyCulture("")]
16
+
17
+// Setting ComVisible to false makes the types in this assembly not visible 
18
+// to COM components.  If you need to access a type in this assembly from 
19
+// COM, set the ComVisible attribute to true on that type.
20
+[assembly: ComVisible(false)]
21
+
22
+// The following GUID is for the ID of the typelib if this project is exposed to COM
23
+[assembly: Guid("9aab688a-ce5f-402e-8891-2d7b4ae85ea3")]
24
+
25
+// Version information for an assembly consists of the following four values:
26
+//
27
+//      Major Version
28
+//      Minor Version 
29
+//      Build Number
30
+//      Revision
31
+//
32
+// You can specify all the values or you can default the Build and Revision Numbers 
33
+// by using the '*' as shown below:
34
+// [assembly: AssemblyVersion("1.0.*")]
35
+[assembly: AssemblyVersion("1.0.0.0")]
36
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 4
- 0
contrib/windows-agent/ExecutionPlanGenerator/packages.config View File

@@ -0,0 +1,4 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<packages>
3
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
4
+</packages>

+ 8
- 0
contrib/windows-agent/README.rst View File

@@ -0,0 +1,8 @@
1
+Murano Windows Agent
2
+====================
3
+
4
+Murano Windows Agent is an initial version of Murano Agent.
5
+Currently, it's outdated and not supported.
6
+
7
+The main difference with the new Python agent is support of running Powershell.
8
+After this support will be added to Python Agent, Windows Agent will be dropped.

BIN
contrib/windows-agent/Tools/NuGet.exe View File


+ 26
- 0
contrib/windows-agent/WindowsAgent.sln View File

@@ -0,0 +1,26 @@
1
+
2
+Microsoft Visual Studio Solution File, Format Version 12.00
3
+# Visual Studio 2012
4
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsAgent", "WindowsAgent\WindowsAgent.csproj", "{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}"
5
+EndProject
6
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionPlanGenerator", "ExecutionPlanGenerator\ExecutionPlanGenerator.csproj", "{501BE151-4B8C-4355-88DC-3AEF1921B2D7}"
7
+EndProject
8
+Global
9
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
10
+		Debug|Any CPU = Debug|Any CPU
11
+		Release|Any CPU = Release|Any CPU
12
+	EndGlobalSection
13
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
14
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.Build.0 = Debug|Any CPU
16
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.ActiveCfg = Release|Any CPU
17
+		{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.Build.0 = Release|Any CPU
18
+		{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19
+		{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20
+		{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21
+		{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Release|Any CPU.Build.0 = Release|Any CPU
22
+	EndGlobalSection
23
+	GlobalSection(SolutionProperties) = preSolution
24
+		HideSolutionNode = FALSE
25
+	EndGlobalSection
26
+EndGlobal

+ 28
- 0
contrib/windows-agent/WindowsAgent/App.config View File

@@ -0,0 +1,28 @@
1
+<?xml version="1.0"?>
2
+<configuration>
3
+	<configSections>
4
+		<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
5
+	</configSections>
6
+	<startup> 
7
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
8
+    </startup>
9
+	<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
10
+		<targets>
11
+			<target name="file" xsi:type="File" fileName="${basedir}/log.txt" layout="${date} ${level}: &lt;${logger:shortName=true}&gt; ${message} ${exception:format=tostring}"/>
12
+		</targets>
13
+
14
+		<rules>
15
+			<logger name="*" minlevel="Debug" writeTo="file"/>
16
+		</rules>
17
+	</nlog>
18
+	<appSettings>
19
+		<add key="rabbitmq.host" value="localhost"/>
20
+		<add key="rabbitmq.user" value="murano"/>
21
+		<add key="rabbitmq.password" value="murano"/>
22
+		<add key="rabbitmq.vhost" value="murano"/>
23
+		<add key="rabbitmq.resultExchange" value=""/>
24
+		<add key="rabbitmq.resultRoutingKey" value="-execution-results"/>
25
+		<add key="rabbitmq.durableMessages" value="true"/>
26
+
27
+	</appSettings>
28
+</configuration>

+ 21
- 0
contrib/windows-agent/WindowsAgent/ExecutionPlan.cs View File

@@ -0,0 +1,21 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using System.Text;
5
+using System.Threading.Tasks;
6
+
7
+namespace Mirantis.Murano.WindowsAgent
8
+{
9
+	class ExecutionPlan
10
+	{
11
+		public class Command
12
+		{
13
+			public string Name { get; set; } 
14
+			public Dictionary<string, object> Arguments { get; set; }
15
+		}
16
+
17
+		public string[] Scripts { get; set; }
18
+		public LinkedList<Command> Commands { get; set; }
19
+		public int RebootOnCompletion { get; set; }
20
+	}
21
+}

+ 30
- 0
contrib/windows-agent/WindowsAgent/MqMessage.cs View File

@@ -0,0 +1,30 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using System.Text;
5
+using System.Threading.Tasks;
6
+
7
+namespace Mirantis.Murano.WindowsAgent
8
+{
9
+	class MqMessage
10
+	{
11
+		private readonly Action ackFunc;
12
+
13
+		public MqMessage(Action ackFunc)
14
+		{
15
+			this.ackFunc = ackFunc;
16
+		}
17
+		
18
+		public MqMessage()
19
+		{
20
+		}
21
+
22
+		public string Body { get; set; }
23
+		public string Id { get; set; }
24
+
25
+		public void Ack()
26
+		{
27
+			ackFunc();
28
+		}
29
+	}
30
+}

+ 233
- 0
contrib/windows-agent/WindowsAgent/PlanExecutor.cs View File

@@ -0,0 +1,233 @@
1
+using System;
2
+using System.Collections;
3
+using System.Collections.Generic;
4
+using System.IO;
5
+using System.Linq;
6
+using System.Management.Automation;
7
+using System.Management.Automation.Runspaces;
8
+using System.Text;
9
+using Newtonsoft.Json.Linq;
10
+using NLog;
11
+using Newtonsoft.Json;
12
+
13
+namespace Mirantis.Murano.WindowsAgent
14
+{
15
+	class PlanExecutor
16
+	{
17
+		private static readonly Logger Log = LogManager.GetCurrentClassLogger();
18
+
19
+		class ExecutionResult
20
+		{
21
+			public bool IsException { get; set; }
22
+			public object Result { get; set; }
23
+		}
24
+
25
+		private readonly string path;
26
+
27
+		public PlanExecutor(string path)
28
+		{
29
+			this.path = path;
30
+		}
31
+
32
+		public bool RebootNeeded { get; set; }
33
+
34
+		public void Execute()
35
+		{
36
+			RebootNeeded = false;
37
+			var resultPath = this.path + ".result";
38
+			Runspace runSpace = null;
39
+			try
40
+			{
41
+				var plan = JsonConvert.DeserializeObject<ExecutionPlan>(File.ReadAllText(this.path));
42
+				List<ExecutionResult> currentResults = null;
43
+				try
44
+				{
45
+					currentResults = File.Exists(resultPath) ? 
46
+						JsonConvert.DeserializeObject<List<ExecutionResult>>(File.ReadAllText(resultPath)) : 
47
+						new List<ExecutionResult>();
48
+				}
49
+				catch(Exception exception)
50
+				{
51
+					Log.WarnException("Cannot deserialize previous execution result", exception);
52
+					currentResults = new List<ExecutionResult>();
53
+				}
54
+
55
+				runSpace = RunspaceFactory.CreateRunspace();
56
+				runSpace.Open();
57
+
58
+				var runSpaceInvoker = new RunspaceInvoke(runSpace);
59
+				runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
60
+				if (plan.Scripts != null)
61
+				{
62
+					var index = 0;
63
+					foreach (var script in plan.Scripts)
64
+					{
65
+						runSpaceInvoker.Invoke(Encoding.UTF8.GetString(Convert.FromBase64String(script)));
66
+						Log.Debug("Loaded script #{0}", ++index);
67
+					}
68
+				}
69
+
70
+				while (plan.Commands != null && plan.Commands.Any())
71
+				{
72
+					var command = plan.Commands.First();
73
+					Log.Debug("Preparing to execute command {0}", command.Name);
74
+
75
+					var pipeline = runSpace.CreatePipeline();
76
+					var psCommand = new Command(command.Name);
77
+					if (command.Arguments != null)
78
+					{
79
+						foreach (var kvp in command.Arguments)
80
+						{
81
+							var value = ConvertArgument(kvp.Value);
82
+							psCommand.Parameters.Add(kvp.Key, value);
83
+						}
84
+					}
85
+
86
+					Log.Info("Executing {0} {1}", command.Name, string.Join(" ",
87
+						(command.Arguments ?? new Dictionary<string, object>()).Select(
88
+							t => string.Format("{0}={1}", t.Key, t.Value == null ? "null" : t.Value.ToString()))));
89
+
90
+					pipeline.Commands.Add(psCommand);
91
+
92
+					try
93
+					{
94
+						var result = pipeline.Invoke();
95
+						Log.Debug("Command {0} executed", command.Name);
96
+						if (result != null)
97
+						{
98
+							currentResults.Add(new ExecutionResult {
99
+								IsException = false,
100
+								Result = result.Select(SerializePsObject).Where(obj => obj != null).ToList()
101
+							});
102
+						}
103
+					}
104
+					catch (Exception exception)
105
+					{
106
+						object additionInfo = null;
107
+						if (exception is ActionPreferenceStopException)
108
+						{
109
+							var apse = exception as ActionPreferenceStopException;
110
+							if (apse.ErrorRecord != null)
111
+							{
112
+								additionInfo = new {
113
+									ScriptStackTrace = apse.ErrorRecord.ScriptStackTrace,
114
+									PositionMessage = apse.ErrorRecord.InvocationInfo.PositionMessage
115
+								};
116
+								exception = apse.ErrorRecord.Exception;
117
+							}
118
+						}
119
+
120
+
121
+						Log.WarnException("Exception while executing command " + command.Name, exception);
122
+						currentResults.Add(new ExecutionResult
123
+						{
124
+							IsException = true,
125
+							Result = new[] {
126
+								exception.GetType().FullName, exception.Message, command.Name, additionInfo
127
+							}
128
+						});
129
+						break;
130
+					}
131
+					finally
132
+					{
133
+						plan.Commands.RemoveFirst();
134
+						File.WriteAllText(path, JsonConvert.SerializeObject(plan));
135
+						File.WriteAllText(resultPath, JsonConvert.SerializeObject(currentResults));
136
+					}
137
+				}
138
+				runSpace.Close();
139
+				var executionResult = JsonConvert.SerializeObject(new ExecutionResult {
140
+					IsException = false,
141
+					Result = currentResults
142
+				}, Formatting.Indented);
143
+
144
+				if (plan.RebootOnCompletion > 0)
145
+				{
146
+					if (plan.RebootOnCompletion == 1)
147
+					{
148
+						RebootNeeded = !currentResults.Any(t => t.IsException);
149
+					}
150
+					else
151
+					{
152
+						RebootNeeded = true;
153
+					}
154
+				}
155
+				File.WriteAllText(resultPath, executionResult);
156
+			}
157
+			catch (Exception exception)
158
+			{
159
+				Log.WarnException("Exception while processing execution plan", exception);
160
+				File.WriteAllText(resultPath, JsonConvert.SerializeObject(new ExecutionResult {
161
+					IsException = true,
162
+					Result = exception.Message
163
+				}, Formatting.Indented));
164
+			}
165
+			finally
166
+			{
167
+				if (runSpace != null)
168
+				{
169
+					try
170
+					{
171
+						runSpace.Close();
172
+					}
173
+					catch
174
+					{}
175
+				}
176
+				Log.Debug("Finished processing of execution plan");
177
+			}
178
+		}
179
+
180
+		private static object ConvertArgument(object arg)
181
+		{
182
+			if (arg is JArray)
183
+			{
184
+				var array = arg as JArray;
185
+				return array.Select(ConvertArgument).ToArray();
186
+			}
187
+			else if (arg is JValue)
188
+			{
189
+				var value = (JValue) arg;
190
+				return value.Value;
191
+			}
192
+			else if (arg is JObject)
193
+			{
194
+				var dict = (JObject)arg;
195
+				var result = new Hashtable();
196
+				foreach (var item in dict)
197
+				{
198
+					result.Add(item.Key, ConvertArgument(item.Value));
199
+				}
200
+				return result;
201
+			}
202
+			return arg;
203
+		}
204
+	
205
+		private static object SerializePsObject(PSObject obj)
206
+		{
207
+			if (obj.BaseObject is PSCustomObject)
208
+			{
209
+				var result = new Dictionary<string, object>();
210
+				foreach (var property in obj.Properties.Where(p => p.IsGettable))
211
+				{
212
+					try
213
+					{
214
+						result[property.Name] = property.Value.ToString();
215
+					}
216
+					catch
217
+					{
218
+					}
219
+				}
220
+				return result;
221
+			}
222
+			else if (obj.BaseObject is IEnumerable<PSObject>)
223
+			{
224
+				return ((IEnumerable<PSObject>) obj.BaseObject).Select(SerializePsObject).ToArray();
225
+			}
226
+			else
227
+			{
228
+				return obj.BaseObject;
229
+			}
230
+		}
231
+	}
232
+
233
+}

+ 168
- 0
contrib/windows-agent/WindowsAgent/Program.cs View File

@@ -0,0 +1,168 @@
1
+using System;
2
+using System.ComponentModel;
3
+using System.Diagnostics;
4
+using System.IO;
5
+using System.Linq;
6
+using System.Management.Automation;
7
+using System.Net;
8
+using System.Text;
9
+using System.Threading;
10
+using NLog;
11
+
12
+namespace Mirantis.Murano.WindowsAgent
13
+{
14
+	[DisplayName("Murano Agent")]
15
+	sealed public class Program : WindowsService
16
+	{
17
+		private static readonly Logger Log = LogManager.GetCurrentClassLogger();
18
+		private volatile bool stop;
19
+		private Thread thread;
20
+		private RabbitMqClient rabbitMqClient;
21
+		private int delayFactor = 1;
22
+		private string plansDir;
23
+
24
+		static void Main(string[] args)
25
+		{
26
+			Start(new Program(), args);
27
+		}
28
+
29
+		protected override void OnStart(string[] args)
30
+		{
31
+			base.OnStart(args);
32
+
33
+			Log.Info("Version 0.5.3");
34
+
35
+			this.rabbitMqClient = new RabbitMqClient();
36
+
37
+			var basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
38
+			this.plansDir = Path.Combine(basePath, "plans");
39
+
40
+
41
+			if (!Directory.Exists(plansDir))
42
+			{
43
+				Directory.CreateDirectory(plansDir);
44
+			}
45
+
46
+			this.thread = new Thread(Loop);
47
+			this.thread.Start();
48
+		}
49
+
50
+		void Loop()
51
+		{
52
+			const string unknownName = "unknown";
53
+			while (!stop)
54
+			{
55
+				try
56
+				{
57
+					foreach (var file in Directory.GetFiles(this.plansDir, "*.json.result")
58
+						.Where(file => !File.Exists(Path.Combine(this.plansDir, Path.GetFileNameWithoutExtension(file)))))
59
+					{
60
+						var id = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file)) ?? unknownName;
61
+						if (id.Equals(unknownName, StringComparison.InvariantCultureIgnoreCase))
62
+						{
63
+							id = "";
64
+						}
65
+
66
+						var result = File.ReadAllText(file);
67
+						Log.Info("Sending results for {0}", id ?? unknownName);
68
+						rabbitMqClient.SendResult(new MqMessage { Body = result, Id =  id });
69
+						File.Delete(file);
70
+					}
71
+
72
+					var path = Directory.EnumerateFiles(this.plansDir, "*.json").FirstOrDefault();
73
+					if (path == null)
74
+					{
75
+						var message = rabbitMqClient.GetMessage();
76
+						var id = message.Id;
77
+						if(string.IsNullOrEmpty(id))
78
+						{
79
+							id = unknownName;
80
+						}
81
+						
82
+						path = Path.Combine(this.plansDir, string.Format("{0}.json", id));
83
+						File.WriteAllText(path, message.Body);
84
+						Log.Info("Received new execution plan {0}", id);
85
+						message.Ack();
86
+					}
87
+					else
88
+					{
89
+						var id = Path.GetFileNameWithoutExtension(path);
90
+						Log.Info("Executing exising plan {0}", id);
91
+					}
92
+					var executor = new PlanExecutor(path);
93
+					executor.Execute();
94
+					File.Delete(path);
95
+					delayFactor = 1;
96
+
97
+					if (stop) break;
98
+					if (executor.RebootNeeded)
99
+					{
100
+						Reboot();
101
+					}
102
+				}
103
+				catch (Exception exception)
104
+				{
105
+					WaitOnException(exception);
106
+				}
107
+				
108
+			}
109
+
110
+		}
111
+
112
+		private void Reboot()
113
+		{
114
+			Log.Info("Going for reboot!!");
115
+			LogManager.Flush();
116
+			/*try
117
+			{
118
+				System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0");
119
+			}
120
+			catch (Exception ex)
121
+			{
122
+				Log.ErrorException("Cannot execute shutdown.exe", ex);
123
+			}*/
124
+
125
+		
126
+			try
127
+			{
128
+				PowerShell.Create().AddCommand("Restart-Computer").AddParameter("Force").Invoke();
129
+			}
130
+			catch (Exception exception)
131
+			{
132
+
133
+				Log.FatalException("Reboot exception", exception);
134
+			}
135
+			finally
136
+			{
137
+				Log.Info("Waiting for reboot");
138
+				for (var i = 0; i < 10 * 60 * 5 && !stop; i++)
139
+				{
140
+					Thread.Sleep(100);
141
+				}
142
+				Log.Info("Done waiting for reboot");
143
+			}
144
+
145
+		}
146
+
147
+		private void WaitOnException(Exception exception)
148
+		{
149
+			if (stop) return;
150
+			Log.WarnException("Exception in main loop", exception);
151
+			var i = 0;
152
+			while (!stop && i < 10 * (delayFactor * delayFactor))
153
+			{
154
+				Thread.Sleep(100);
155
+				i++;
156
+			}
157
+			delayFactor = Math.Min(delayFactor + 1, 6);
158
+		}
159
+
160
+		protected override void OnStop()
161
+		{
162
+			stop = true;
163
+			this.rabbitMqClient.Dispose();
164
+			base.OnStop();
165
+		}
166
+
167
+	}
168
+}

+ 36
- 0
contrib/windows-agent/WindowsAgent/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,36 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following 
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+[assembly: AssemblyTitle("WindowsAgent")]
9
+[assembly: AssemblyDescription("")]
10
+[assembly: AssemblyConfiguration("")]
11
+[assembly: AssemblyCompany("")]
12
+[assembly: AssemblyProduct("WindowsAgent")]
13
+[assembly: AssemblyCopyright("Copyright ©  2013")]
14
+[assembly: AssemblyTrademark("")]
15
+[assembly: AssemblyCulture("")]
16
+
17
+// Setting ComVisible to false makes the types in this assembly not visible 
18
+// to COM components.  If you need to access a type in this assembly from 
19
+// COM, set the ComVisible attribute to true on that type.
20
+[assembly: ComVisible(false)]
21
+
22
+// The following GUID is for the ID of the typelib if this project is exposed to COM
23
+[assembly: Guid("9591bf2c-f38b-47e0-a39d-ea9849356371")]
24
+
25
+// Version information for an assembly consists of the following four values:
26
+//
27
+//      Major Version
28
+//      Minor Version 
29
+//      Build Number
30
+//      Revision
31
+//
32
+// You can specify all the values or you can default the Build and Revision Numbers 
33
+// by using the '*' as shown below:
34
+// [assembly: AssemblyVersion("1.0.*")]
35
+[assembly: AssemblyVersion("1.0.0.0")]
36
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 147
- 0
contrib/windows-agent/WindowsAgent/RabbitMqClient.cs View File

@@ -0,0 +1,147 @@
1
+using System;
2
+using System.Collections.Generic;
3
+using System.Configuration;
4
+using System.Linq;
5
+using System.Net;
6
+using System.Net.Security;
7
+using System.Security.Authentication;
8
+using System.Security.Cryptography.X509Certificates;
9
+using System.Text;
10
+using System.Threading.Tasks;
11
+using NLog;
12
+using RabbitMQ.Client;
13
+
14
+namespace Mirantis.Murano.WindowsAgent
15
+{
16
+	class RabbitMqClient : IDisposable
17
+	{
18
+		private static readonly Logger Log = LogManager.GetCurrentClassLogger();
19
+		private static readonly ConnectionFactory connectionFactory;
20
+		private IConnection currentConnecton;
21
+
22
+		static RabbitMqClient()
23
+		{
24
+		    var ssl = new SslOption {
25
+		        Enabled = bool.Parse(ConfigurationManager.AppSettings["rabbitmq.ssl"] ?? "false"),
26
+		        Version = SslProtocols.Default,
27
+                AcceptablePolicyErrors = bool.Parse(ConfigurationManager.AppSettings["rabbitmq.allowInvalidCA"] ?? "true") ? 
28
+                    SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None
29
+		    };
30
+
31
+		    var sslServerName = ConfigurationManager.AppSettings["rabbitmq.sslServerName"] ?? "";
32
+		    ssl.ServerName = sslServerName;
33
+            if (String.IsNullOrWhiteSpace(sslServerName))
34
+            {
35
+                ssl.AcceptablePolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
36
+            }
37
+
38
+            connectionFactory = new ConnectionFactory {
39
+                HostName = ConfigurationManager.AppSettings["rabbitmq.host"] ?? "localhost",
40
+                UserName = ConfigurationManager.AppSettings["rabbitmq.user"] ?? "guest",
41
+                Password = ConfigurationManager.AppSettings["rabbitmq.password"] ??"guest",
42
+                Protocol = Protocols.DefaultProtocol,
43
+                VirtualHost = ConfigurationManager.AppSettings["rabbitmq.vhost"] ?? "/",
44
+                Port = int.Parse(ConfigurationManager.AppSettings["rabbitmq.port"] ?? "5672"),
45
+                RequestedHeartbeat = 10,
46
+                Ssl = ssl
47
+            };
48
+		}
49
+		
50
+		public RabbitMqClient()
51
+		{
52
+			
53
+		}
54
+
55
+		public MqMessage GetMessage()
56
+		{
57
+			var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Dns.GetHostName().ToLower();
58
+			try
59
+			{
60
+				IConnection connection = null;
61
+				lock (this)
62
+				{
63
+					connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
64
+				}
65
+				var session = connection.CreateModel();
66
+				session.BasicQos(0, 1, false);
67
+				//session.QueueDeclare(queueName, true, false, false, null);
68
+				var consumer = new QueueingBasicConsumer(session);
69
+				var consumeTag = session.BasicConsume(queueName, false, consumer);
70
+				var e = (RabbitMQ.Client.Events.BasicDeliverEventArgs) consumer.Queue.Dequeue();
71
+				Action ackFunc = delegate {
72
+					session.BasicAck(e.DeliveryTag, false);
73
+					session.BasicCancel(consumeTag);
74
+					session.Close();
75
+				};
76
+
77
+				return new MqMessage(ackFunc) {
78
+					Body = Encoding.UTF8.GetString(e.Body),
79
+					Id = e.BasicProperties.MessageId
80
+				};
81
+			}
82
+			catch (Exception exception)
83
+			{
84
+
85
+				Dispose();
86
+				throw;
87
+			}
88
+		}
89
+
90
+		public void SendResult(MqMessage message)
91
+		{
92
+			var exchangeName = ConfigurationManager.AppSettings["rabbitmq.resultExchange"] ?? "";
93
+			var resultRoutingKey = ConfigurationManager.AppSettings["rabbitmq.resultRoutingKey"] ?? "-execution-results";
94
+			bool durable = bool.Parse(ConfigurationManager.AppSettings["rabbitmq.durableMessages"] ?? "true");
95
+
96
+			try
97
+			{
98
+				IConnection connection = null;
99
+				lock (this)
100
+				{
101
+					connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
102
+				}
103
+				var session = connection.CreateModel();
104
+				/*if (!string.IsNullOrEmpty(resultQueue))
105
+				{
106
+					//session.QueueDeclare(resultQueue, true, false, false, null);
107
+					if (!string.IsNullOrEmpty(exchangeName))
108
+					{
109
+						session.ExchangeBind(exchangeName, resultQueue, resultQueue);
110
+					}
111
+				}*/
112
+				var basicProperties = session.CreateBasicProperties();
113
+				basicProperties.SetPersistent(durable);
114
+				basicProperties.MessageId = message.Id;
115
+				basicProperties.ContentType = "application/json";
116
+				session.BasicPublish(exchangeName, resultRoutingKey, basicProperties, Encoding.UTF8.GetBytes(message.Body));
117
+				session.Close();
118
+			}
119
+			catch (Exception)
120
+			{
121
+				Dispose();
122
+				throw;
123
+			}
124
+		}
125
+
126
+		public void Dispose()
127
+		{
128
+			lock (this)
129
+			{
130
+				try
131
+				{
132
+					if (this.currentConnecton != null)
133
+					{
134
+						this.currentConnecton.Close();
135
+					}
136
+				}
137
+				catch
138
+				{
139
+				}
140
+				finally
141
+				{
142
+					this.currentConnecton = null;
143
+				}
144
+			}
145
+		}
146
+	}
147
+}

+ 37
- 0
contrib/windows-agent/WindowsAgent/SampleExecutionPlan.json View File

@@ -0,0 +1,37 @@
1
+{
2
+	"Scripts":
3
+	[
4
+		"ZnVuY3Rpb24gdDMgeyAxMjsgcmV0dXJuICJ0ZXN0IiB9",
5
+		"ZnVuY3Rpb24gTmV3LVBlcnNvbigpDQp7DQogIHBhcmFtICgkRmlyc3ROYW1lLCAkTGFzdE5hbWUsICRQaG9uZSkNCg0KICAkcGVyc29uID0gbmV3LW9iamVjdCBQU09iamVjdA0KDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBGaXJzdCAtVmFsdWUgJEZpcnN0TmFtZQ0KICAkcGVyc29uIHwgYWRkLW1lbWJlciAtdHlwZSBOb3RlUHJvcGVydHkgLU5hbWUgTGFzdCAtVmFsdWUgJExhc3ROYW1lDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBQaG9uZSAtVmFsdWUgJFBob25lDQoNCiAgcmV0dXJuICRwZXJzb24NCn0=",
6
+		"ZnVuY3Rpb24gVGVzdFRocm93KCkNCnsNCglUaHJvdyBbc3lzdGVtLkluZGV4T3V0T2ZSYW5nZUV4Y2VwdGlvbl0gDQp9"
7
+	],
8
+	"Commands" :  
9
+	[
10
+		{
11
+			"Name": "New-Person",
12
+			"Arguments" : 
13
+			{
14
+				"FirstName": "MyFirstName",
15
+				"LastName": "MyLastName",
16
+				"Phone": "123-456"
17
+			}
18
+
19
+		},
20
+		{
21
+			"Name": "t3",
22
+			"Arguments" : 
23
+			{
24
+			}
25
+
26
+		},
27
+		{
28
+			"Name": "Get-Date",
29
+
30
+		},
31
+		{
32
+			"Name": "TestThrow",
33
+
34
+		}
35
+	],
36
+	"RebootOnCompletion": 0
37
+}

+ 111
- 0
contrib/windows-agent/WindowsAgent/ServiceManager.cs View File

@@ -0,0 +1,111 @@
1
+using System;
2
+using System.Configuration.Install;
3
+using System.Reflection;
4
+using System.ServiceProcess;
5
+using NLog;
6
+
7
+namespace Mirantis.Murano.WindowsAgent
8
+{
9
+    public class ServiceManager
10
+    {
11
+        private readonly string serviceName;
12
+
13
+        public ServiceManager(string serviceName)
14
+        {
15
+            this.serviceName = serviceName;
16
+        }
17
+
18
+        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
19
+
20
+        public bool Restart(string[] args, TimeSpan timeout)
21
+        {
22
+            var service = new ServiceController(serviceName);
23
+            try
24
+            {
25
+                var millisec1 = TimeSpan.FromMilliseconds(Environment.TickCount);
26
+
27
+                service.Stop();
28
+                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
29
+                Log.Info("Service is stopped");
30
+
31
+                // count the rest of the timeout
32
+                var millisec2 = TimeSpan.FromMilliseconds(Environment.TickCount);
33
+                timeout = timeout - (millisec2 - millisec1);
34
+
35
+                service.Start(args);
36
+                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
37
+                Log.Info("Service has started");
38
+                return true;
39
+            }
40
+            catch (Exception ex)
41
+            {
42
+                Log.ErrorException("Cannot restart service " + serviceName, ex);
43
+                return false;
44
+            }
45
+        }
46
+
47
+        public bool Stop(TimeSpan timeout)
48
+        {
49
+            var service = new ServiceController(serviceName);
50
+            try
51
+            {
52
+                service.Stop();
53
+                service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
54
+                return true;
55
+            }
56
+            catch (Exception ex)
57
+            {
58
+                Log.ErrorException("Cannot stop service " + serviceName, ex);
59
+                return false;
60
+            }
61
+        }
62
+
63
+        public bool Start(string[] args, TimeSpan timeout)
64
+        {
65
+            var service = new ServiceController(serviceName);
66
+            try
67
+            {
68
+                service.Start(args);
69
+                service.WaitForStatus(ServiceControllerStatus.Running, timeout);
70
+                return true;
71
+            }
72
+            catch (Exception ex)
73
+            {
74
+                Log.ErrorException("Cannot start service " + serviceName, ex);
75
+                return false;
76
+            }
77
+        }
78
+
79
+        public bool Install()
80
+        {
81
+            try
82
+            {
83
+                ManagedInstallerClass.InstallHelper(
84
+                    new string[] { Assembly.GetEntryAssembly().Location });
85
+            }
86
+            catch(Exception ex)
87
+            {
88
+                Log.ErrorException("Cannot install service " + serviceName, ex);
89
+                return false;
90
+            }
91
+            return true;
92
+        }
93
+
94
+        public bool Uninstall()
95
+        {
96
+            try
97
+            {
98
+                ManagedInstallerClass.InstallHelper(
99
+                    new string[] { "/u", Assembly.GetEntryAssembly().Location });
100
+            }
101
+            catch (Exception ex)
102
+            {
103
+                Log.ErrorException("Cannot uninstall service " + serviceName, ex);
104
+                return false;
105
+            }
106
+            return true;
107
+        }
108
+
109
+    }
110
+    
111
+}

+ 95
- 0
contrib/windows-agent/WindowsAgent/WindowsAgent.csproj View File

@@ -0,0 +1,95 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4
+  <PropertyGroup>
5
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7
+    <ProjectGuid>{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}</ProjectGuid>
8
+    <OutputType>Exe</OutputType>
9
+    <AppDesignerFolder>Properties</AppDesignerFolder>
10
+    <RootNamespace>Mirantis.Murano.WindowsAgent</RootNamespace>
11
+    <AssemblyName>WindowsAgent</AssemblyName>
12
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
13
+    <FileAlignment>512</FileAlignment>
14
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
15
+  </PropertyGroup>
16
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17
+    <PlatformTarget>AnyCPU</PlatformTarget>
18
+    <DebugSymbols>true</DebugSymbols>
19
+    <DebugType>full</DebugType>
20
+    <Optimize>false</Optimize>
21
+    <OutputPath>bin\Debug\</OutputPath>
22
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
23
+    <ErrorReport>prompt</ErrorReport>
24
+    <WarningLevel>4</WarningLevel>
25
+    <Prefer32Bit>false</Prefer32Bit>
26
+  </PropertyGroup>
27
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28
+    <PlatformTarget>AnyCPU</PlatformTarget>
29
+    <DebugType>pdbonly</DebugType>
30
+    <Optimize>true</Optimize>
31
+    <OutputPath>bin\Release\</OutputPath>
32
+    <DefineConstants>TRACE</DefineConstants>
33
+    <ErrorReport>prompt</ErrorReport>
34
+    <WarningLevel>4</WarningLevel>
35
+    <Prefer32Bit>false</Prefer32Bit>
36
+  </PropertyGroup>
37
+  <ItemGroup>
38
+    <Reference Include="Newtonsoft.Json">
39
+      <HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
40
+    </Reference>
41
+    <Reference Include="NLog">
42
+      <HintPath>..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
43
+    </Reference>
44
+    <Reference Include="RabbitMQ.Client">
45
+      <HintPath>..\packages\RabbitMQ.Client.3.0.2\lib\net30\RabbitMQ.Client.dll</HintPath>
46
+    </Reference>
47
+    <Reference Include="System" />
48
+    <Reference Include="System.Configuration" />
49
+    <Reference Include="System.Configuration.Install" />
50
+    <Reference Include="System.Core" />
51
+    <Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
52
+      <SpecificVersion>False</SpecificVersion>
53
+      <HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll</HintPath>
54
+    </Reference>
55
+    <Reference Include="System.ServiceProcess" />
56
+    <Reference Include="System.Xml.Linq" />
57
+    <Reference Include="System.Data.DataSetExtensions" />
58
+    <Reference Include="Microsoft.CSharp" />
59
+    <Reference Include="System.Data" />
60
+    <Reference Include="System.Xml" />
61
+  </ItemGroup>
62
+  <ItemGroup>
63
+    <Compile Include="ExecutionPlan.cs" />
64
+    <Compile Include="MqMessage.cs" />
65
+    <Compile Include="PlanExecutor.cs" />
66
+    <Compile Include="Program.cs">
67
+      <SubType>Component</SubType>
68
+    </Compile>
69
+    <Compile Include="Properties\AssemblyInfo.cs" />
70
+    <Compile Include="RabbitMqClient.cs" />
71
+    <Compile Include="ServiceManager.cs" />
72
+    <Compile Include="WindowsService.cs">
73
+      <SubType>Component</SubType>
74
+    </Compile>
75
+    <Compile Include="WindowsServiceInstaller.cs">
76
+      <SubType>Component</SubType>
77
+    </Compile>
78
+  </ItemGroup>
79
+  <ItemGroup>
80
+    <None Include="App.config" />
81
+    <None Include="packages.config" />
82
+    <None Include="SampleExecutionPlan.json" />
83
+  </ItemGroup>
84
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
85
+  <PropertyGroup>
86
+    <PreBuildEvent>$(SolutionDir)Tools\nuget install $(ProjectDir)packages.config -o $(SolutionDir)Packages</PreBuildEvent>
87
+  </PropertyGroup>
88
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
89
+       Other similar extension points exist, see Microsoft.Common.targets.
90
+  <Target Name="BeforeBuild">
91
+  </Target>
92
+  <Target Name="AfterBuild">
93
+  </Target>
94
+  -->
95
+</Project>

+ 95
- 0
contrib/windows-agent/WindowsAgent/WindowsService.cs View File

@@ -0,0 +1,95 @@
1
+using System;
2
+using System.ComponentModel;
3
+using System.IO;
4
+using System.Linq;
5
+using System.Reflection;
6
+using System.ServiceProcess;
7
+using NLog;
8
+
9
+namespace Mirantis.Murano.WindowsAgent
10
+{
11
+    public abstract class WindowsService : ServiceBase
12
+    {
13
+        private static readonly Logger Log = LogManager.GetCurrentClassLogger();
14
+        public bool RunningAsService { get; private set; }
15
+
16
+	    protected static void Start(WindowsService service, string[] arguments)
17
+        {
18
+            Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
19
+
20
+			if (arguments.Contains("/install", StringComparer.OrdinalIgnoreCase))
21
+            {
22
+                new ServiceManager(service.ServiceName).Install();
23
+            }
24
+			else if (arguments.Contains("/uninstall", StringComparer.OrdinalIgnoreCase))
25
+			{
26
+                new ServiceManager(service.ServiceName).Uninstall();
27
+            }
28
+			else if (arguments.Contains("/start", StringComparer.OrdinalIgnoreCase))
29
+			{
30
+                new ServiceManager(service.ServiceName).Start(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
31
+            }
32
+			else if (arguments.Contains("/stop", StringComparer.OrdinalIgnoreCase))
33
+			{
34
+                new ServiceManager(service.ServiceName).Stop(TimeSpan.FromMinutes(1));
35
+            }
36
+			else if (arguments.Contains("/restart", StringComparer.OrdinalIgnoreCase))
37
+			{
38
+                new ServiceManager(service.ServiceName).Restart(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
39
+            }
40
+			else if (!arguments.Contains("/console", StringComparer.OrdinalIgnoreCase))
41
+			{
42
+				service.RunningAsService = true;
43
+				Run(service);
44
+			}
45
+			else
46
+			{
47
+				try
48
+				{
49
+					service.RunningAsService = false;
50
+					Console.Title = service.ServiceName;
51
+					service.OnStart(Environment.GetCommandLineArgs());
52
+					service.WaitForExitSignal();
53
+				}
54
+				finally
55
+				{
56
+					service.OnStop();
57
+					service.Dispose();
58
+				}
59
+			}
60
+        }
61
+        
62
+        protected WindowsService()
63
+        {
64
+            var displayNameAttribute =
65
+                this.GetType().GetCustomAttributes(typeof (DisplayNameAttribute), false).Cast<DisplayNameAttribute>().
66
+                    FirstOrDefault();
67
+            if(displayNameAttribute != null)
68
+            {
69
+                ServiceName = displayNameAttribute.DisplayName;
70
+            }
71
+        }
72
+
73
+
74
+        protected virtual void WaitForExitSignal()
75
+        {
76
+            Console.WriteLine("Press ESC to exit");
77
+            while (Console.ReadKey(true).Key != ConsoleKey.Escape)
78
+            {
79
+            }
80
+        }
81
+
82
+		protected override void OnStart(string[] args)
83
+		{
84
+			Log.Info("Service {0} started", ServiceName);
85
+
86
+			base.OnStart(args);
87
+		}
88
+
89
+		protected override void OnStop()
90
+		{
91
+			Log.Info("Service {0} exited", ServiceName);
92
+			base.OnStop();
93
+		}
94
+    }
95
+}

+ 39
- 0
contrib/windows-agent/WindowsAgent/WindowsServiceInstaller.cs View File

@@ -0,0 +1,39 @@
1
+using System.ComponentModel;
2
+using System.Configuration.Install;
3
+using System.Linq;
4
+using System.Reflection;
5
+using System.ServiceProcess;
6
+
7
+namespace Mirantis.Murano.WindowsAgent
8
+{
9
+	[RunInstaller(true)]
10
+	public class WindowsServiceInstaller : Installer
11
+    {
12
+		public WindowsServiceInstaller()
13
+        {
14
+            var processInstaller = new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem };
15
+            foreach (var type in Assembly.GetEntryAssembly().GetExportedTypes().Where(t => t.IsSubclassOf(typeof(ServiceBase))))
16
+            {
17
+                var nameAttribute = type.GetCustomAttributes(typeof (DisplayNameAttribute), false)
18
+                    .Cast<DisplayNameAttribute>().FirstOrDefault();
19
+                if(nameAttribute == null) continue;
20
+                var serviceInstaller = new ServiceInstaller {
21
+                    StartType = ServiceStartMode.Automatic,
22
+                    ServiceName = nameAttribute.DisplayName,
23
+                    DisplayName = nameAttribute.DisplayName
24
+                };
25
+                var descriptionAttribute = type.GetCustomAttributes(typeof(DescriptionAttribute), false)
26
+                    .Cast<DescriptionAttribute>().FirstOrDefault();
27
+                if(descriptionAttribute != null)
28
+                {
29
+                    serviceInstaller.Description = descriptionAttribute.Description;
30
+                }
31
+
32
+                Installers.Add(serviceInstaller);
33
+            }
34
+
35
+            Installers.Add(processInstaller);
36
+
37
+        }
38
+    }
39
+}

+ 6
- 0
contrib/windows-agent/WindowsAgent/packages.config View File

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<packages>
3
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
4
+  <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
5
+  <package id="RabbitMQ.Client" version="3.0.2" targetFramework="net45" />
6
+</packages>

+ 4
- 0
contrib/windows-agent/packages/repositories.config View File

@@ -0,0 +1,4 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<repositories>
3
+  <repository path="..\WindowsAgent\packages.config" />
4
+</repositories>

Loading…
Cancel
Save