view ServerMonitor/Objects/Checks/FileCheck.cs @ 13:a36cc5c123f4

Fix SSH command sublclasses holding on to old command strings after a program update.
author Brad Greco <brad@bgreco.net>
date Mon, 15 Apr 2019 19:25:27 -0400
parents 7127d5b5ac75
children 68d7834dc28e
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ServerMonitorApp
{
    [DisplayName("File check"), Description("Check file size or modified time"), DisplayWeight(12)]
    public class FileCheck : SshCheck
    {
        public override string Command => string.Format(FileCommand, Regex.Replace(File, "^~", "$HOME"));

        protected string FileCommand
        {
            get
            {
                int timeZoneOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Hours * -1; // Invert because POSIX says so.
                return "export TIME_STYLE=long-iso; export TZ=UTC" + timeZoneOffset + "; ls -l \"{0}\"";
            }
        }

        public string File { get; set; }

        public bool CheckFileSize { get; set; }

        public bool FileSizeLessThan { get; set; }

        public int FileSize { get; set; }

        public double FileSizeInSelectedUnits
        {
            get => Math.Round(ConvertBytesToSelectedUnits(FileSize), 1);
            set => FileSize = ConvertSelectedUnitsToBytes(value);
        }

        public SizeUnits FileSizeUnits { get; set; }

        public bool CheckDateModified { get; set; }

        public bool DateModifiedOlderThan { get; set; }

        public double DateModified { get; set; }

        public TimeUnits DateModifiedUnits { get; set; }

        public FileCheck()
        {
            CheckExitCode = true;
            ExitCode = 0;
        }

        protected override List<CheckResult> ProcessCommandResult(string output, int exitCode)
        {
            List<CheckResult> results = base.ProcessCommandResult(output, exitCode);
            if (results.Any(r => r.Failed))
                return results;

            if (output.Split('\n').Length > 1)
            {
                results.Add(Fail("ls output was more than one line: " + output));
            }
            else
            {
                string[] tokens = output.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
                if (CheckFileSize)
                {
                    if (int.TryParse(tokens[4], out int bytes))
                    {
                        string message = string.Format("File size is {0} {1}", Math.Round(ConvertBytesToSelectedUnits(bytes), 1), FileSizeUnits);
                        if ((bytes < FileSize && FileSizeLessThan) || (bytes > FileSize && !FileSizeLessThan))
                            results.Add(Pass(message));
                        else
                            results.Add(Fail(message));
                    }
                    else
                    {
                        results.Add(Fail("Unable to parse ls output as integer: " + tokens[4]));
                    }
                }
                if (CheckDateModified)
                {
                    string dateString = tokens[5] + " " + tokens[6];
                    if (DateTime.TryParse(dateString, out DateTime modified))
                    {
                        string message = string.Format("Last modified date is {0}", modified);
                        TimeSpan age = DateTime.Now.Subtract(modified);
                        double ageCompare = DateModifiedUnits == TimeUnits.Minute ? age.TotalMinutes :
                                         DateModifiedUnits == TimeUnits.Hour ? age.TotalHours :
                                         age.TotalDays;
                        if ((ageCompare > DateModified && DateModifiedOlderThan) || (ageCompare < DateModified && !DateModifiedOlderThan))
                            results.Add(Pass(message));
                        else
                            results.Add(Fail(message));
                    }
                    else
                    {
                        results.Add(Fail("Unable to parse ls output as date: " + dateString));
                    }
                }
            }
            return results;
        }

        public override string Validate(bool saving = true)
        {
            string message = base.Validate();
            if (File.IsNullOrEmpty())
                message += "File is required." + Environment.NewLine;
            if (!CheckFileSize && !CheckDateModified)
                message += "At least one check must be enabled." + Environment.NewLine;
            if (CheckFileSize && FileSize < 0)
                message += "File size must be at least 0." + Environment.NewLine;
            if (CheckDateModified && DateModified <= 0)
                message += "Date modified must be greater than 0." + Environment.NewLine;
            return message;
        }

        private double ConvertBytesToSelectedUnits(int sizeInBytes)
        {
            return sizeInBytes / Math.Pow(1024, (double)FileSizeUnits);
        }

        private int ConvertSelectedUnitsToBytes(double sizeInSelectedUnits)
        {
            return (int)(sizeInSelectedUnits * Math.Pow(1024, (int)FileSizeUnits));
        }
    }
}