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 }