PageRenderTime 56ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/Orchestrator/scorchLauncher/Program.cs

#
C# | 404 lines | 389 code | 14 blank | 1 comment | 35 complexity | 78824ce2f1c0de4d5d7e6bdad5105a1b MD5 | raw file
  1. using OrchestratorInterop;
  2. using OrchestratorInterop.Data_Class;
  3. using OrchestratorInterop.SCOrchestrator;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Data.Services.Client;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Net;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Xml;
  14. using System.Xml.Linq;
  15. namespace scorchLauncher
  16. {
  17. class Program
  18. {
  19. private static string CONFIG_FILE_PATH = string.Empty;
  20. private static string WEBSERVICE_URL = string.Empty;
  21. private static string RUNBOOK_GUID = string.Empty;
  22. private static string RUNBOOK_PATH = string.Empty;
  23. private static string username = string.Empty;
  24. private static string domain = string.Empty;
  25. private static string password = string.Empty;
  26. private static bool useAltCreds = false;
  27. private static Dictionary<string,string> INPUT_RUNBOOK_PARAMETERS = new Dictionary<string,string>();
  28. private static bool waitForExit = false;
  29. // Try for up to 5 Minutes
  30. private static int tryCount = 30;
  31. private static TimeSpan delay = new TimeSpan(0, 0, 10);
  32. static void Main(string[] args)
  33. {
  34. int internalCounter = 0;
  35. bool finished = false;
  36. String exceptionMessage = String.Empty;
  37. if (parseInputs(args))
  38. {
  39. while (internalCounter < tryCount && !finished)
  40. {
  41. try
  42. {
  43. finished = runRunbook();
  44. }
  45. catch(Exception e)
  46. {
  47. exceptionMessage = String.Format("Summary: {0}\nDetails: {1}", e.Message, e.InnerException);
  48. if (exceptionMessage.Contains("Summary: No Input Parameter on Runbook Found for Key:"))
  49. {
  50. internalCounter = tryCount;
  51. break;
  52. }
  53. internalCounter++;
  54. Thread.Sleep(delay);
  55. }
  56. }
  57. if (internalCounter >= tryCount)
  58. {
  59. throw new Exception(exceptionMessage);
  60. }
  61. }
  62. }
  63. private static void ReadConfigFile(string path)
  64. {
  65. XDocument xdoc = null;
  66. try
  67. {
  68. xdoc = XDocument.Load(path);
  69. }
  70. catch (FileNotFoundException ex)
  71. {
  72. Console.Error.WriteLine("Error: Invalid configuration file path " + path);
  73. System.Environment.Exit(-200);
  74. }
  75. catch (XmlException ex)
  76. {
  77. Console.Error.WriteLine("Error: Configuration file is not valid xml.");
  78. System.Environment.Exit(-201);
  79. }
  80. XElement root = xdoc.Root;
  81. var urlNode = root.Descendants("webServerUrl");
  82. var pathNode = root.Descendants("rubookPathPrefix");
  83. var retryCountNode = root.Descendants("retryCount");
  84. var retryDelayNode = root.Descendants("retryDelay");
  85. if (urlNode.Count() != 1 || pathNode.Count() != 1 || retryCountNode.Count() != 1 || retryDelayNode.Count() != 1)
  86. {
  87. Console.Error.WriteLine("Error: Invalid configuration file. Must contain elements: <webServerUrl>,<runbookPathPrefix>,<retryCount>, <retryDelay>");
  88. System.Environment.Exit(-202);
  89. }
  90. WEBSERVICE_URL = (string)(urlNode.First());
  91. RUNBOOK_PATH = (string)(pathNode.First()) + "\\" + RUNBOOK_PATH;
  92. tryCount = (int)(retryCountNode.First());
  93. delay = new TimeSpan(0,0,(int)(retryDelayNode.First()));
  94. }
  95. private static bool runRunbook()
  96. {
  97. bool status = true;
  98. OrchestratorContext sco = setupOrchestratorConnection();
  99. string jobID;
  100. try
  101. {
  102. if (!String.IsNullOrEmpty(RUNBOOK_PATH)) { jobID = Convert.ToString(((Job)SCOrch.startRunbookJob(sco, RUNBOOK_PATH, INPUT_RUNBOOK_PARAMETERS)).Id); }
  103. else if (!String.IsNullOrEmpty(RUNBOOK_PATH)) { jobID = Convert.ToString(((Job)SCOrch.startRunbookJob(sco, new Guid(RUNBOOK_GUID), INPUT_RUNBOOK_PARAMETERS)).Id); }
  104. else { Console.WriteLine("Must pass either -RunbookPath or -RunbookGUID"); return false; }
  105. if (waitForExit)
  106. {
  107. pollForJobCompletion(sco, new Guid(jobID));
  108. }
  109. }
  110. // If webservice isn't available attempt 1 try again
  111. catch
  112. {
  113. throw;
  114. }
  115. return status;
  116. }
  117. private static OrchestratorContext setupOrchestratorConnection()
  118. {
  119. OrchestratorContext sco = new OrchestratorContext(new Uri(WEBSERVICE_URL));
  120. if (useAltCreds)
  121. {
  122. NetworkCredential credentials = new NetworkCredential();
  123. credentials.UserName = username;
  124. credentials.Domain = domain;
  125. credentials.Password = password;
  126. sco.Credentials = credentials;
  127. }
  128. else { sco.Credentials = CredentialCache.DefaultCredentials; }
  129. sco.MergeOption = MergeOption.OverwriteChanges;
  130. return sco;
  131. }
  132. private static void pollForJobCompletion(OrchestratorContext sco, Guid jobID)
  133. {
  134. try
  135. {
  136. while (!SCOrch.getJobDetails(sco, jobID).job.Status.Equals("Completed"))
  137. {
  138. System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3));
  139. }
  140. JobInstance j = SCOrch.getJobDetails(sco, jobID);
  141. Console.WriteLine("<OutputParameters>");
  142. foreach (string key in j.OutputParameters.Keys)
  143. {
  144. Console.WriteLine(string.Format("\t<{0}>{1}</{0}>", key, j.OutputParameters[key]));
  145. }
  146. Console.WriteLine("</OutputParameters>");
  147. }
  148. // Allow for 1 webservice Error
  149. catch
  150. {
  151. sco = setupOrchestratorConnection();
  152. while (!SCOrch.getJobDetails(sco, jobID).job.Status.Equals("Completed"))
  153. {
  154. System.Threading.Thread.Sleep(new TimeSpan(0, 0, 3));
  155. }
  156. JobInstance j = SCOrch.getJobDetails(sco, jobID);
  157. Console.WriteLine("<OutputParameters>");
  158. foreach (string key in j.OutputParameters.Keys)
  159. {
  160. Console.WriteLine(string.Format("\t<{0}>{1}</{0}>", key, j.OutputParameters[key]));
  161. }
  162. Console.WriteLine("</OutputParameters>");
  163. }
  164. }
  165. private static bool parseInputs(string[] args)
  166. {
  167. if (args.Count() == 0 || args.Contains("-help") || args.Contains("/?"))
  168. {
  169. printHelp();
  170. return false;
  171. }
  172. else if (args.Contains("-config") &&
  173. (args.Contains("-webServerUrl") || args.Contains("-w") ||
  174. args.Contains("-retrycount") || args.Contains("-rc") ||
  175. args.Contains("-retrydelay") || args.Contains("-rd")))
  176. {
  177. Console.Error.WriteLine("Error: The -config flag is incompatible with flags -webServerUrl, -retryCount, or -retryDelay.");
  178. Console.Error.WriteLine("Set those parameters using the configuration file instead.");
  179. return false;
  180. }
  181. else
  182. {
  183. for (int i = 0; i < args.Count(); i++)
  184. {
  185. parseInput(args, ref i);
  186. }
  187. if (!String.IsNullOrEmpty(CONFIG_FILE_PATH))
  188. {
  189. ReadConfigFile(CONFIG_FILE_PATH);
  190. }
  191. return verifyMandatoryParameters();
  192. }
  193. }
  194. private static void printHelp()
  195. {
  196. Console.WriteLine("scorchLauncher.exe -RunbookPath <String> -WebServerURL <String> [-Username <String> -Domain <String> -Password <String>] [-InputParameters <String>|<String>~<String>|<String>] [-WaitForExit (True|False)]\n\n");
  197. Console.WriteLine("-RunbookPath <String> : Path to runbook in the form of \"\\RootFolder\\Containing Folder\\Runbook Name\"");
  198. Console.WriteLine("-WebServerURL <String> : Path to the webserver in the form of http://webservername:81/Orchestrator2012/Orchestrator.svc");
  199. Console.WriteLine("-InputParameters <String>|<String>~<String>|<String> : a list of input parameter key|value pairs seperated by ~");
  200. Console.WriteLine("-WaitForExit (True|False) : tells the program to wait for the completion of the runbook or not. Must be set to True for accessing output parameters");
  201. Console.WriteLine("-UserName : The user name to connect to the web service with");
  202. Console.WriteLine("-Domain : Domain of the user to connect to the web service with");
  203. Console.WriteLine("-Password : Password of the user to connect to the web service with");
  204. Console.WriteLine("-RetryDelay : Delay between retry attempts in seconds (Default 10)");
  205. Console.WriteLine("-RetryCount : Number of Attempts to retry the web service call (Default 30)");
  206. Console.WriteLine("-Config : Supply the location of a configuration file to determine the WebServerUrl and prefix for the RunbookPath");
  207. Console.WriteLine("-Help : Prints this Help Page");
  208. }
  209. private static void parseInput(string[] args, ref int i)
  210. {
  211. switch (args[i].ToLower())
  212. {
  213. case "runbookguid":
  214. case "rg":
  215. i++;
  216. RUNBOOK_GUID = args[i];
  217. break;
  218. case "-retrycount":
  219. case "-rc":
  220. i++;
  221. tryCount = Convert.ToInt32(args[i]);
  222. break;
  223. case "-retrydelay":
  224. case "-rd":
  225. i++;
  226. delay = new TimeSpan(0, 0, Convert.ToInt32(args[i]));
  227. break;
  228. case "-runbookpath":
  229. i++;
  230. RUNBOOK_PATH = args[i];
  231. break;
  232. case "-r":
  233. i++;
  234. RUNBOOK_PATH = args[i];
  235. break;
  236. case "-webserverurl":
  237. i++;
  238. WEBSERVICE_URL = args[i];
  239. break;
  240. case "-w":
  241. i++;
  242. WEBSERVICE_URL = args[i];
  243. break;
  244. case "-username":
  245. i++;
  246. username = args[i];
  247. useAltCreds = true;
  248. break;
  249. case "-u":
  250. i++;
  251. username = args[i];
  252. useAltCreds = true;
  253. break;
  254. case "-domain":
  255. i++;
  256. domain = args[i];
  257. useAltCreds = true;
  258. break;
  259. case "-d":
  260. i++;
  261. domain = args[i];
  262. useAltCreds = true;
  263. break;
  264. case "-password":
  265. i++;
  266. password = args[i];
  267. useAltCreds = true;
  268. break;
  269. case "-p":
  270. i++;
  271. password = args[i];
  272. useAltCreds = true;
  273. break;
  274. case "-inputparameters":
  275. i++;
  276. ParseInputParameters(args, i);
  277. break;
  278. case "-i":
  279. i++;
  280. ParseInputParameters(args, i);
  281. break;
  282. case "-waitforexit":
  283. i++;
  284. waitForExit = Convert.ToBoolean(args[i]);
  285. break;
  286. case "-config":
  287. i++;
  288. CONFIG_FILE_PATH = args[i];
  289. break;
  290. default:
  291. break;
  292. }
  293. }
  294. private static void ParseInputParameters(string[] args, int i)
  295. {
  296. bool keyFinished = false;
  297. bool pairFinished = false;
  298. StringBuilder key = new StringBuilder();
  299. StringBuilder value = new StringBuilder();
  300. for (int j = 0; j < args[i].Length; j++)
  301. {
  302. if (!keyFinished)
  303. {
  304. if (args[i][j].Equals('|'))
  305. {
  306. keyFinished = true;
  307. }
  308. else
  309. {
  310. if (args[i][j].Equals('\\'))
  311. {
  312. if (args[i][j + 1].Equals('|') || args[i][j + 1].Equals('~') || args[i][j + 1].Equals('\\'))
  313. {
  314. j = j + 1;
  315. }
  316. key.Append(args[i][j]);
  317. }
  318. else
  319. {
  320. key.Append(args[i][j]);
  321. }
  322. }
  323. }
  324. else
  325. {
  326. if (args[i][j].Equals('~'))
  327. {
  328. pairFinished = true;
  329. }
  330. else
  331. {
  332. if (args[i][j].Equals('\\'))
  333. {
  334. if (args[i][j + 1].Equals('|') || args[i][j + 1].Equals('~') || args[i][j + 1].Equals('\\'))
  335. {
  336. j = j + 1;
  337. }
  338. value.Append(args[i][j]);
  339. }
  340. else
  341. {
  342. value.Append(args[i][j]);
  343. }
  344. }
  345. }
  346. if (pairFinished || j+1 == args[i].Length)
  347. {
  348. pairFinished = false;
  349. keyFinished = false;
  350. INPUT_RUNBOOK_PARAMETERS.Add(key.ToString(), value.ToString());
  351. key.Remove(0, key.Length);
  352. value.Remove(0, value.Length);
  353. }
  354. }
  355. }
  356. private static bool verifyMandatoryParameters()
  357. {
  358. if (WEBSERVICE_URL.Equals(string.Empty))
  359. {
  360. Console.WriteLine("Please specify a Webservice URL in the form of http://webservername:81/Orchestrator2012/Orchestrator.svc");
  361. return false;
  362. }
  363. if (RUNBOOK_PATH.Equals(string.Empty))
  364. {
  365. Console.WriteLine("Please specify the path to the runbook to initiate in the form of \\Root Folder\\ContainingFolder\\RunbookName");
  366. return false;
  367. }
  368. if (useAltCreds && (username.Equals(string.Empty) || domain.Equals(string.Empty) || password.Equals(string.Empty)))
  369. {
  370. Console.WriteLine(string.Format("If alternate credentials are used all fields related must be passed " +
  371. "(Username, Domain, Password), passed values were\n" +
  372. "Username:\t{0}\n" +
  373. "Domain:\t{1}\n" +
  374. "Password:\t{2}"
  375. ,username,domain,password));
  376. return false;
  377. }
  378. return true;
  379. }
  380. }
  381. }