annotate ServerMonitor/Objects/Checks/FileCheck.cs @ 23:3866c19535fd

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