Mercurial > servermonitor
comparison ServerMonitor/Objects/Checks/FileCheck.cs @ 17:68d7834dc28e
More comments.
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Sat, 25 May 2019 15:14:26 -0400 |
parents | a36cc5c123f4 |
children | 88ca7e4fc023 |
comparison
equal
deleted
inserted
replaced
16:7626b099aefd | 17:68d7834dc28e |
---|---|
1 using System; | 1 using System; |
2 using System.Collections.Generic; | 2 using System.Collections.Generic; |
3 using System.ComponentModel; | 3 using System.ComponentModel; |
4 using System.Linq; | 4 using System.Linq; |
5 using System.Text; | |
6 using System.Text.RegularExpressions; | 5 using System.Text.RegularExpressions; |
7 using System.Threading.Tasks; | |
8 using System.Xml.Serialization; | |
9 | 6 |
10 namespace ServerMonitorApp | 7 namespace ServerMonitorApp |
11 { | 8 { |
9 /// <summary>Checks file metadata on a remote server.</summary> | |
12 [DisplayName("File check"), Description("Check file size or modified time"), DisplayWeight(12)] | 10 [DisplayName("File check"), Description("Check file size or modified time"), DisplayWeight(12)] |
13 public class FileCheck : SshCheck | 11 public class FileCheck : SshCheck |
14 { | 12 { |
13 /// <summary>The command to execute. Must return the output format of GNU ls(1) with the long-iso time style.</summary> | |
14 /// <remarks>Would be better to not rely on the output of ls.</remarks> | |
15 public override string Command => string.Format(FileCommand, Regex.Replace(File, "^~", "$HOME")); | 15 public override string Command => string.Format(FileCommand, Regex.Replace(File, "^~", "$HOME")); |
16 | 16 |
17 /// <summary>The command to execute, with a placeholder of {0} for the file to check.</summary> | |
17 protected string FileCommand | 18 protected string FileCommand |
18 { | 19 { |
19 get | 20 get |
20 { | 21 { |
21 int timeZoneOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Hours * -1; // Invert because POSIX says so. | 22 // Invert because POSIX says so. |
23 int timeZoneOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Hours * -1; | |
24 // Set the date format to long-iso since it's easy to parse. | |
25 // Set the time zone to the match the client time zone so comparisons are reliable. | |
22 return "export TIME_STYLE=long-iso; export TZ=UTC" + timeZoneOffset + "; ls -l \"{0}\""; | 26 return "export TIME_STYLE=long-iso; export TZ=UTC" + timeZoneOffset + "; ls -l \"{0}\""; |
23 } | 27 } |
24 } | 28 } |
25 | 29 |
30 /// <summary>The path of the file to check.</summary> | |
26 public string File { get; set; } | 31 public string File { get; set; } |
27 | 32 |
33 /// <summary>Whether the file size will be checked.</summary> | |
28 public bool CheckFileSize { get; set; } | 34 public bool CheckFileSize { get; set; } |
29 | 35 |
36 /// <summary>Whether the file is expected to be less than or greater than a certain size.</summary> | |
30 public bool FileSizeLessThan { get; set; } | 37 public bool FileSizeLessThan { get; set; } |
31 | 38 |
39 /// <summary>The size to compare the file against in bytes.</summary> | |
32 public int FileSize { get; set; } | 40 public int FileSize { get; set; } |
33 | 41 |
42 /// <summary>The size to compare the file against in the selected size units.</summary> | |
34 public double FileSizeInSelectedUnits | 43 public double FileSizeInSelectedUnits |
35 { | 44 { |
36 get => Math.Round(ConvertBytesToSelectedUnits(FileSize), 1); | 45 get => Math.Round(ConvertBytesToSelectedUnits(FileSize), 1); |
37 set => FileSize = ConvertSelectedUnitsToBytes(value); | 46 set => FileSize = ConvertSelectedUnitsToBytes(value); |
38 } | 47 } |
39 | 48 |
49 /// <summary>The units of the file size.</summary> | |
40 public SizeUnits FileSizeUnits { get; set; } | 50 public SizeUnits FileSizeUnits { get; set; } |
41 | 51 |
52 /// <summary>Whether the file modified time will be checked.</summary> | |
42 public bool CheckDateModified { get; set; } | 53 public bool CheckDateModified { get; set; } |
43 | 54 |
55 /// <summary>Whether the file is expected to be older than or newer than a certain date.</summary> | |
44 public bool DateModifiedOlderThan { get; set; } | 56 public bool DateModifiedOlderThan { get; set; } |
45 | 57 |
58 /// <summary>The number of time units to compare then file modified time against.</summary> | |
46 public double DateModified { get; set; } | 59 public double DateModified { get; set; } |
47 | 60 |
61 /// <summary>The units of the file date modified.</summary> | |
48 public TimeUnits DateModifiedUnits { get; set; } | 62 public TimeUnits DateModifiedUnits { get; set; } |
49 | 63 |
50 public FileCheck() | 64 public FileCheck() |
51 { | 65 { |
66 // Set general SSH check settings for file checks. | |
52 CheckExitCode = true; | 67 CheckExitCode = true; |
53 ExitCode = 0; | 68 ExitCode = 0; |
54 } | 69 } |
55 | 70 |
71 /// <summary>Processes the output of the file check command.</summary> | |
56 protected override List<CheckResult> ProcessCommandResult(string output, int exitCode) | 72 protected override List<CheckResult> ProcessCommandResult(string output, int exitCode) |
57 { | 73 { |
74 // Check for general SSH failures. | |
58 List<CheckResult> results = base.ProcessCommandResult(output, exitCode); | 75 List<CheckResult> results = base.ProcessCommandResult(output, exitCode); |
76 // If there was an error running the command, fail immediately. | |
59 if (results.Any(r => r.Failed)) | 77 if (results.Any(r => r.Failed)) |
60 return results; | 78 return results; |
61 | 79 |
80 // Make sure there is only a single line of output. | |
62 if (output.Split('\n').Length > 1) | 81 if (output.Split('\n').Length > 1) |
63 { | 82 { |
64 results.Add(Fail("ls output was more than one line: " + output)); | 83 results.Add(Fail("ls output was more than one line: " + output)); |
65 } | 84 } |
66 else | 85 else |
67 { | 86 { |
87 // Split the string into tokens on whitespace. | |
68 string[] tokens = output.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); | 88 string[] tokens = output.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); |
69 if (CheckFileSize) | 89 if (CheckFileSize) |
70 { | 90 { |
91 // Check file size. | |
71 if (int.TryParse(tokens[4], out int bytes)) | 92 if (int.TryParse(tokens[4], out int bytes)) |
72 { | 93 { |
94 // Prepare a human-readable message with the comparison results. | |
73 string message = string.Format("File size is {0} {1}", Math.Round(ConvertBytesToSelectedUnits(bytes), 1), FileSizeUnits); | 95 string message = string.Format("File size is {0} {1}", Math.Round(ConvertBytesToSelectedUnits(bytes), 1), FileSizeUnits); |
74 if ((bytes < FileSize && FileSizeLessThan) || (bytes > FileSize && !FileSizeLessThan)) | 96 if ((bytes < FileSize && FileSizeLessThan) || (bytes > FileSize && !FileSizeLessThan)) |
75 results.Add(Pass(message)); | 97 results.Add(Pass(message)); |
76 else | 98 else |
77 results.Add(Fail(message)); | 99 results.Add(Fail(message)); |
81 results.Add(Fail("Unable to parse ls output as integer: " + tokens[4])); | 103 results.Add(Fail("Unable to parse ls output as integer: " + tokens[4])); |
82 } | 104 } |
83 } | 105 } |
84 if (CheckDateModified) | 106 if (CheckDateModified) |
85 { | 107 { |
108 // Check date modified. | |
109 // Tokens[5] contains the date, tokens[6] contains the time. | |
86 string dateString = tokens[5] + " " + tokens[6]; | 110 string dateString = tokens[5] + " " + tokens[6]; |
87 if (DateTime.TryParse(dateString, out DateTime modified)) | 111 if (DateTime.TryParse(dateString, out DateTime modified)) |
88 { | 112 { |
89 string message = string.Format("Last modified date is {0}", modified); | 113 string message = string.Format("Last modified date is {0}", modified); |
114 // Determine how old the file is. The command output is in the client time zone. | |
90 TimeSpan age = DateTime.Now.Subtract(modified); | 115 TimeSpan age = DateTime.Now.Subtract(modified); |
91 double ageCompare = DateModifiedUnits == TimeUnits.Minute ? age.TotalMinutes : | 116 double ageCompare = DateModifiedUnits == TimeUnits.Minute ? age.TotalMinutes : |
92 DateModifiedUnits == TimeUnits.Hour ? age.TotalHours : | 117 DateModifiedUnits == TimeUnits.Hour ? age.TotalHours : |
93 age.TotalDays; | 118 age.TotalDays; |
94 if ((ageCompare > DateModified && DateModifiedOlderThan) || (ageCompare < DateModified && !DateModifiedOlderThan)) | 119 if ((ageCompare > DateModified && DateModifiedOlderThan) || (ageCompare < DateModified && !DateModifiedOlderThan)) |
103 } | 128 } |
104 } | 129 } |
105 return results; | 130 return results; |
106 } | 131 } |
107 | 132 |
133 /// <summary>Validates file check options.</summary> | |
108 public override string Validate(bool saving = true) | 134 public override string Validate(bool saving = true) |
109 { | 135 { |
110 string message = base.Validate(); | 136 string message = base.Validate(); |
111 if (File.IsNullOrEmpty()) | 137 if (File.IsNullOrEmpty()) |
112 message += "File is required." + Environment.NewLine; | 138 message += "File is required." + Environment.NewLine; |
117 if (CheckDateModified && DateModified <= 0) | 143 if (CheckDateModified && DateModified <= 0) |
118 message += "Date modified must be greater than 0." + Environment.NewLine; | 144 message += "Date modified must be greater than 0." + Environment.NewLine; |
119 return message; | 145 return message; |
120 } | 146 } |
121 | 147 |
148 /// <summary>Converts bytes to a different size unit.</summary> | |
149 /// <param name="sizeInBytes">The size to convert in bytes.</param> | |
150 /// <returns>The size in the units used by this file check.</returns> | |
122 private double ConvertBytesToSelectedUnits(int sizeInBytes) | 151 private double ConvertBytesToSelectedUnits(int sizeInBytes) |
123 { | 152 { |
124 return sizeInBytes / Math.Pow(1024, (double)FileSizeUnits); | 153 return sizeInBytes / Math.Pow(1024, (double)FileSizeUnits); |
125 } | 154 } |
126 | 155 |
156 /// <summary>Converts a size in a different unit to bytes.</summary> | |
157 /// <param name="sizeInSelectedUnits">The size to convert in the units used by this file check.</param> | |
158 /// <returns>The size in bytes.</returns> | |
127 private int ConvertSelectedUnitsToBytes(double sizeInSelectedUnits) | 159 private int ConvertSelectedUnitsToBytes(double sizeInSelectedUnits) |
128 { | 160 { |
129 return (int)(sizeInSelectedUnits * Math.Pow(1024, (int)FileSizeUnits)); | 161 return (int)(sizeInSelectedUnits * Math.Pow(1024, (int)FileSizeUnits)); |
130 } | 162 } |
131 } | 163 } |