Mercurial > servermonitor
comparison ServerMonitor/Objects/Checks/Check.cs @ 2:453ecc1ed9ea
Disk space check
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Sun, 06 Jan 2019 20:49:08 -0500 |
parents | ServerMonitor/Objects/Check.cs@9e92780ebc0f |
children | 3142e52cbe69 |
comparison
equal
deleted
inserted
replaced
1:9e92780ebc0f | 2:453ecc1ed9ea |
---|---|
1 using System; | |
2 using System.Linq; | |
3 using System.Text; | |
4 using System.Text.RegularExpressions; | |
5 using System.Threading; | |
6 using System.Threading.Tasks; | |
7 using System.Xml.Serialization; | |
8 | |
9 namespace ServerMonitorApp | |
10 { | |
11 /*public enum CheckType | |
12 { | |
13 Command | |
14 }*/ | |
15 | |
16 public enum CheckStatus | |
17 { | |
18 Success, | |
19 Information, | |
20 Warning, | |
21 Error, | |
22 Running, | |
23 Disabled, | |
24 } | |
25 | |
26 public abstract class Check | |
27 { | |
28 private static Type[] _checkTypes; | |
29 | |
30 public static Type[] CheckTypes | |
31 { | |
32 get | |
33 { | |
34 return _checkTypes ?? (_checkTypes = typeof(Check).Assembly.GetTypes() | |
35 .Where(t => t.IsSubclassOf(typeof(Check))) | |
36 .OrderBy(t => t.GetAttribute<DisplayWeightAttribute>()?.DisplayWeight).ToArray()); | |
37 } | |
38 } | |
39 | |
40 public int Id { get; set; } | |
41 | |
42 public string Name { get; set; } | |
43 | |
44 /*public CheckType Type { get; set; }*/ | |
45 | |
46 public int Timeout { get; set; } | |
47 | |
48 public bool Enabled { get; set; } | |
49 | |
50 public Schedule Schedule { get; set; } | |
51 | |
52 public DateTime LastRunTime { get; set; } | |
53 | |
54 public DateTime LastScheduledRunTime { get; set; } | |
55 | |
56 public DateTime NextRunTime { get; set; } | |
57 | |
58 public string LastMessage { get; set; } | |
59 | |
60 public CheckStatus Status { get; set; } | |
61 | |
62 public CheckStatus FailStatus { get; set; } | |
63 | |
64 [XmlIgnore] | |
65 public Server Server { get; set; } | |
66 | |
67 public Check() | |
68 { | |
69 FailStatus = CheckStatus.Error; | |
70 } | |
71 | |
72 public override string ToString() | |
73 { | |
74 return Name; | |
75 } | |
76 | |
77 public virtual string Validate(bool saving = true) | |
78 { | |
79 string message = string.Empty; | |
80 if (Name.IsNullOrEmpty() && saving) | |
81 message += "Name cannot be blank." + Environment.NewLine; | |
82 return message; | |
83 } | |
84 | |
85 //public virtual CheckStatus Execute() | |
86 //{ | |
87 // //TODO | |
88 // throw new NotImplementedException(); | |
89 //} | |
90 | |
91 public async Task<CheckResult> ExecuteAsync(CancellationToken token = default(CancellationToken), bool update = true) | |
92 { | |
93 //TODO check cancellation token before proceeding | |
94 CheckResult result; | |
95 DateTime startTime = DateTime.Now; | |
96 try | |
97 { | |
98 Task<CheckResult> checkTask = ExecuteCheckAsync(token); | |
99 try | |
100 { | |
101 if (await Task.WhenAny(checkTask, Task.Delay(Timeout, token)) == checkTask) | |
102 { | |
103 result = await checkTask; | |
104 } | |
105 else | |
106 { | |
107 result = Fail("Timed out."); | |
108 } | |
109 } | |
110 catch (TaskCanceledException) | |
111 { | |
112 return null; | |
113 } | |
114 } | |
115 catch (Exception e) | |
116 { | |
117 result = Fail(e.GetBaseException().Message); | |
118 } | |
119 result.StartTime = startTime; | |
120 result.EndTime = DateTime.Now; | |
121 // If a check is executed from the CheckForm, we don't want to update the status or log the event. | |
122 if (update) | |
123 { | |
124 Status = result.CheckStatus; | |
125 LastMessage = result.Message; | |
126 LastRunTime = result.EndTime; | |
127 } | |
128 return result; | |
129 } | |
130 | |
131 public CheckResult Pass(string message) | |
132 { | |
133 return new CheckResult(this, CheckStatus.Success, message); | |
134 } | |
135 | |
136 public CheckResult Fail(string message) | |
137 { | |
138 return new CheckResult(this, FailStatus, message); | |
139 } | |
140 | |
141 protected CheckResult Fail(Exception e) | |
142 { | |
143 return new CheckResult(this, FailStatus, e.GetBaseException().Message); | |
144 } | |
145 | |
146 protected CheckResult GetIntResult(int expectedValue, int resultValue, string description) | |
147 { | |
148 if (expectedValue == resultValue) | |
149 return Pass(string.Format("{0}: {1}", description, resultValue)); | |
150 else | |
151 return Fail(string.Format("{0}: {1} (expected: {2})", description, resultValue, expectedValue)); | |
152 } | |
153 | |
154 protected CheckResult GetStringResult(MatchType matchType, string expectedPattern, bool useRegex, string resultValue, string description) | |
155 { | |
156 bool match; | |
157 if (useRegex) | |
158 { | |
159 if (matchType.In(MatchType.Equals, MatchType.NotEquals)) | |
160 { | |
161 if (!expectedPattern.StartsWith("^")) | |
162 expectedPattern = "^" + expectedPattern; | |
163 if (!expectedPattern.EndsWith("$")) | |
164 expectedPattern += "$"; | |
165 } | |
166 Regex re = new Regex(expectedPattern, RegexOptions.Singleline); | |
167 match = re.IsMatch(resultValue); | |
168 } | |
169 else | |
170 { | |
171 if (matchType.In(MatchType.Equals, MatchType.NotEquals)) | |
172 { | |
173 match = expectedPattern == resultValue; | |
174 } | |
175 else if (matchType.In(MatchType.Contains, MatchType.NotContains)) | |
176 { | |
177 match = resultValue.Contains(expectedPattern); | |
178 } | |
179 else | |
180 { | |
181 if (decimal.TryParse(expectedPattern, out decimal expectedNumeric) && | |
182 decimal.TryParse(resultValue, out decimal resultNumeric)) | |
183 { | |
184 match = (matchType == MatchType.GreaterThan && resultNumeric > expectedNumeric) || | |
185 (matchType == MatchType.LessThan && resultNumeric < expectedNumeric); | |
186 } | |
187 else | |
188 { | |
189 return Fail(string.Format("{0} is not numeric: {1}", description, resultValue)); | |
190 } | |
191 } | |
192 } | |
193 | |
194 if (matchType.In(MatchType.Equals, MatchType.Contains)) | |
195 { | |
196 if (match) | |
197 return Pass(string.Format("{0} {1} the pattern: {2}", description, matchType.ToString().ToLower(), expectedPattern)); | |
198 else | |
199 return Fail(string.Format("{0} does not {1} the pattern: {2} ({0}: {3})", description, matchType.ToString().ToLower().TrimEnd('s'), expectedPattern, resultValue)); | |
200 } | |
201 else if (matchType.In(MatchType.NotEquals, MatchType.NotContains)) | |
202 { | |
203 if (match) | |
204 return Fail(string.Format("{0} {1} the pattern: {2} ({0}: {3})", description, matchType.ToString().ToLower().Replace("not", ""), expectedPattern, resultValue)); | |
205 else | |
206 return Pass(string.Format("{0} does not {1} the pattern: {2}", description, matchType.ToString().ToLower().TrimEnd('s').Replace("not", ""), expectedPattern)); | |
207 } | |
208 else | |
209 { | |
210 if (match) | |
211 return Pass(string.Format("{0} ({1}) is {2} {3}", description, resultValue, matchType.ToString().ToLower().Replace("than", " than"), expectedPattern)); | |
212 else | |
213 return Fail(string.Format("{0} ({1}) is not {2} {3}", description, resultValue, matchType.ToString().ToLower().Replace("than", " than"), expectedPattern)); | |
214 } | |
215 } | |
216 | |
217 protected CheckResult MergeResults(params CheckResult[] results) | |
218 { | |
219 StringBuilder message = new StringBuilder(); | |
220 bool failed = false; | |
221 foreach (CheckResult result in results) | |
222 { | |
223 if (result == null) | |
224 continue; | |
225 if (result.CheckStatus != CheckStatus.Success) | |
226 failed = true; | |
227 message.AppendLine(result.Message); | |
228 } | |
229 return failed ? Fail(message.ToString().Trim()) : Pass(message.ToString().Trim()); | |
230 } | |
231 | |
232 protected abstract Task<CheckResult> ExecuteCheckAsync(CancellationToken token); | |
233 } | |
234 } |