JD2022-TU1/main/tools/modules/JD.Nas.Reporting.Console.Module/ReportingConsoleAction.cs

716 lines
No EOL
27 KiB
C#

namespace JD.Nas.Reporting.Console.Module
{
using JD.Nas.Reporting.Console.Module.Constants;
using JD.Nas.Reporting.Console.Module.Exception;
using JD.Nas.Service;
using JD.Nas.Service.Exception;
using JD.Nas.Service.NasReportingDto;
using Newtonsoft.Json;
using Plume.Core.Logging;
using Plume.Interfaces.CommandLines;
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
public class ReportingConsoleAction : CommandLineAction<ReportingConsoleOption>
{
private readonly INasReportingService _nasReportingService;
private ILogger _logger;
private readonly string _applicationLogPath;
private string _archiveDirectoryPath;
private string _reportDirectoryPath;
private string _reportPath;
private string _reportZipFilePath;
private string _reportZipFileArchivePath;
private NasReportConfiguration _nasReportConfiguration;
private NasReport _nasReport;
#region Constructor
public ReportingConsoleAction(INasReportingService nasReportingService, string applicationLogPath)
{
_nasReportingService = nasReportingService ?? throw new ArgumentNullException(nameof(nasReportingService));
_applicationLogPath = applicationLogPath;
}
#endregion
protected override int Execute(ReportingConsoleOption option, ILogger logger)
{
if (logger == null)
{
return (int)ReportingConsoleExitCode.ExecuteLoggerError;
}
_logger = logger;
try
{
if (option == null)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ExecuteOptionError,
string.Concat("Option undefined : ", nameof(option))
);
}
if (string.IsNullOrEmpty(option.ConfigurationFilePath))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ConfigurationFilePathNeeded,
"If ApiUrlForConfig arguments is feeled also ConfigFilePath is needed !"
);
}
#region ConfigurationFilePath verifications part 1
if (!Directory.Exists(Path.GetDirectoryName(option.ConfigurationFilePath)))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ConfigurationFilePathNotExist,
string.Concat("Directory not exist : ", Path.GetDirectoryName(option.ConfigurationFilePath))
);
}
if (!AccessDirectory(Path.GetDirectoryName(option.ConfigurationFilePath)))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ConfigurationFilePathAccessDenied,
string.Concat("Access denied to directory : ", Path.GetDirectoryName(option.ConfigurationFilePath))
);
}
#endregion
if (!string.IsNullOrEmpty(option.ApiUrlForConfiguration))
{
this.DownloadJsonFile(option.ApiUrlForConfiguration, option.ConfigurationFilePath);
}
#region ConfigurationFilePath verifications part 2
if (!option.ConfigurationFilePath.EndsWith(ReportingConsoleConstants.JsonExtension))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ConfigurationFileNotJson,
string.Concat("Configuration file is not a json file : ", option.ConfigurationFilePath)
);
}
#endregion
// Set _nasReportConfiguration variable with the option.ConfigFilePath configuration file
this._nasReportConfiguration = this.DeserializeJsonFile<NasReportConfiguration>(option.ConfigurationFilePath);
#region NasReportConfiguration verifications Part 1
if (_nasReportConfiguration == null)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ConfigurationFileEmpty,
"Configuration file is empty"
);
}
// OutputPath attribut
if (string.IsNullOrEmpty(_nasReportConfiguration.OutputPath))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.OutputPathNeeded,
"OutputPath arguments is needed !"
);
}
if (!Directory.Exists(Path.GetDirectoryName(_nasReportConfiguration.OutputPath)))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.OutputPathNotExist,
string.Concat("Directory not exist : ", Path.GetDirectoryName(_nasReportConfiguration.OutputPath))
);
}
if (!AccessDirectory(Path.GetDirectoryName(_nasReportConfiguration.OutputPath)))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.OutputPathNoAccess,
string.Concat("Access denied to directory : ", Path.GetDirectoryName(_nasReportConfiguration.OutputPath))
);
}
// NasReportId attribut
if (string.IsNullOrEmpty(_nasReportConfiguration.NasReportId))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ReportIdNeeded,
"ReportId is needed !"
);
}
#endregion
this._archiveDirectoryPath = Path.Combine(this._nasReportConfiguration.OutputPath, ReportingConsoleConstants.ArchiveFile);
this._reportDirectoryPath = Path.Combine(this._nasReportConfiguration.OutputPath, this._nasReportConfiguration.NasReportId);
#region NasReportConfiguration api verifications
if(!string.IsNullOrEmpty(this._nasReportConfiguration.ApiUrlForData) && string.IsNullOrEmpty(this._nasReportConfiguration.ApiUrlForError))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ExecuteOptionError,
string.Concat("If ApiUrlForData is fill also ApiUrlForError is needed : ", nameof(option))
);
}
if (this._nasReportConfiguration.IsDebugApi == true && !string.IsNullOrEmpty(this._nasReportConfiguration.ApiUrlForData) && !string.IsNullOrEmpty(this._nasReportConfiguration.ApiUrlForError))
{
this.WriteLogWarn("Api debug enabled");
this.WriteLogWarn("Try to post the report exclusively");
this._reportZipFilePath = Path.Combine(this._nasReportConfiguration.OutputPath, string.Concat(this._nasReportConfiguration.NasReportId, ReportingConsoleConstants.ZipExtension));
if (!File.Exists(Path.Combine(this._nasReportConfiguration.OutputPath, string.Concat(this._nasReportConfiguration.NasReportId, ReportingConsoleConstants.ZipExtension))))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ZipFileReportNotExist,
string.Concat("ZipFileReport not exist : ", this._reportZipFilePath)
);
}
this.PostZipFile(this._reportZipFilePath, this._nasReportConfiguration.ApiUrlForData);
this.WriteLogInfo("Api debug finished !");
return (int)ReportingConsoleExitCode.Ok;
}
#endregion
#region NasReportConfiguration verification Part 2
string reportPath =
Path.Combine(
_reportDirectoryPath,
string.Concat(this._nasReportConfiguration.NasReportId, ReportingConsoleConstants.JsonExtension));
// NasReportId already use
if (Directory.Exists(
Path.Combine(
this._nasReportConfiguration.OutputPath,
this._nasReportConfiguration.NasReportId))
&& File.Exists(reportPath))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.ReportIdAlreadyUsed,
string.Concat("Report already exists : ", reportPath)
);
}
// NasServerConfigurations
if (this._nasReportConfiguration.NasServerConfigurations == null || this._nasReportConfiguration.NasServerConfigurations.Count == 0)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.NasServerConfigurationEmpty,
string.Concat("No server configuration detected", reportPath)
);
}
#endregion
#region Reporting
this.WriteLogInfo("Reporting started !");
this.WriteLogInfo(string.Concat("They are ", this._nasReportConfiguration.NasServerConfigurations.Count, " to analyse"));
// Analyse
this.WriteLogInfo(string.Concat("The nas report analyse start"));
this.AnalyseReport();
this.WriteLogInfo(string.Concat("The nas report analyse is finish"));
// Setup directory result
this.CompleteReportDirectory();
// Zip directory result
this.ZipReport();
#endregion
// ApiUrl
if (!string.IsNullOrEmpty(_nasReportConfiguration.ApiUrlForData))
{
// Send data
this.PostZipFile(this._reportZipFilePath, this._nasReportConfiguration.ApiUrlForData);
// Archive the zip
this.ArchiveReport();
}
this.WriteLogInfo(string.Concat("Work finished !"));
return (int)ReportingConsoleExitCode.Ok;
}
catch (ReportingConsoleException ex)
{
this.WriteLogError(ex);
this.PostZipFileError();
return ex.GetExitCodeInt();
}
catch (System.Exception ex)
{
ReportingConsoleException exception = new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedError,
ex
);
this.WriteLogError(exception);
this.PostZipFileError();
return exception.GetExitCodeInt();
}
}
#region Private
/// <summary>
/// Zip, post and archive the report error data
/// </summary>
private void PostZipFileError()
{
// Create the report directory, if not exist
this.CreateReportDirectory();
// Complete it with logs and other
this.CompleteReportDirectory();
// Zip it
this.ZipReport();
// Send the zip error
this.PostZipFile(this._reportZipFilePath, this._nasReportConfiguration.ApiUrlForError);
this.WriteLogInfo(string.Concat("The zip error has been send"));
// Archive
this.ArchiveReport();
}
/// <summary>
/// Analyse report with current report configuration
/// </summary>
private void AnalyseReport()
{
this.CreateReportDirectory();
foreach (NasServerConfiguration nasServerConfiguration in this._nasReportConfiguration.NasServerConfigurations)
{
if (string.IsNullOrEmpty(nasServerConfiguration.NasServerConfigurationId))
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.NasServerConfigurationIdNeeded
);
}
else
{
try
{
AnalyseServer(this._reportPath, nasServerConfiguration);
}
catch (NasReportingServiceException ex)
{
this.WriteLogError(ex);
}
catch (ReportingConsoleException ex)
{
this.WriteLogError(ex);
}
}
}
// Save the date of end
this._nasReport.DateStop = DateTime.UtcNow;
}
/// <summary>
/// Alanyse one nas server
/// </summary>
/// <param name="outputPath"></param>
/// <param name="nasServerConfiguration"></param>
private void AnalyseServer(string outputPath, NasServerConfiguration nasServerConfiguration)
{
// Start sniffing
NasServerAnalyse nasServerAnalyse = this._nasReportingService.AnalyseNasServer(this._nasReport, nasServerConfiguration);
if (nasServerAnalyse != null)
{
// Order
nasServerAnalyse.Maps = nasServerAnalyse?.Maps.OrderBy(x => x.Name).ToList();
nasServerAnalyse.DateStop = DateTime.UtcNow;
// Save analyse file
string filePath = Path.Combine(outputPath, nasServerConfiguration.FileAnalyseName);
SaveFileAsJson(
filePath,
nasServerAnalyse,
(nasServerConfiguration.IsOutputFormatIndented ?? this._nasReportConfiguration.IsOutputFormatIndented ?? false)
);
this._nasReport.Servers.Add(filePath);
this.WriteLogInfo(string.Concat($"Nas server analyse finished of : ", nasServerConfiguration.Folder, " || ", DateTime.Now));
}
else
{
this.WriteLogWarn(string.Concat($"Nas server analyse of : ", nasServerConfiguration.Folder, " is empty || ", DateTime.Now));
}
}
/// <summary>
/// Post zip file
/// </summary>
/// <param name="zipPath"></param>
/// <param name="url"></param>
private void PostZipFile(string zipPath, string url)
{
try
{
HttpResponseMessage message;
using (HttpClient client = new HttpClient())
using (MultipartFormDataContent formData = new MultipartFormDataContent())
{
message = this.PostZipFileTask(client, formData, zipPath, url).GetAwaiter().GetResult();
}
if (message == null)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.PostZipFileError,
string.Concat("No response of http post : " + url)
);
}
else if (!message.IsSuccessStatusCode)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.PostZipFileError,
string.Concat("The server return ", message.StatusCode.ToString(), " of http post of ", url)
);
}
else
{
this.WriteLogInfo("PostZipFileReport() success !");
}
}
catch (ReportingConsoleException ex)
{
throw ex;
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorPostZipFile,
ex
);
}
}
/// <summary>
/// Post zip file (task)
/// </summary>
/// <param name="client"></param>
/// <param name="formData"></param>
/// <param name="zipPath"></param>
/// <param name="url"></param>
/// <returns></returns>
private async Task<HttpResponseMessage> PostZipFileTask(HttpClient client, MultipartFormDataContent formData, string zipPath, string url)
{
try
{
byte[] byteArray = File.ReadAllBytes(zipPath);
formData.Add(new ByteArrayContent(byteArray, 0, byteArray.Length), Path.GetFileNameWithoutExtension(zipPath), Path.GetFileName(zipPath));
return await client.PostAsync(url, formData);
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorPostZipFileTask,
ex
);
}
}
/// <summary>
/// Crete the report and his directory
/// </summary>
private void CreateReportDirectory()
{
try
{
// Setup report if not exist
if (_nasReport == null)
{
this._nasReport = new NasReport(this._nasReportConfiguration);
this._reportPath = Path.Combine(this._nasReportConfiguration.OutputPath, this._nasReport.Id);
}
// Create report directory if not exist
if (!Directory.Exists(this._reportPath))
{
Directory.CreateDirectory(this._reportPath);
}
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorCreateReportDirectory,
ex
);
}
}
/// <summary>
/// Save log, config, report files in the report directory
/// </summary>
private void CompleteReportDirectory()
{
try
{
// Save the report and reportConfiguration files
SaveFileAsJson(
Path.Combine(
this._reportDirectoryPath,
ReportingConsoleConstants.reportFile),
this._nasReport,
(this._nasReportConfiguration.IsOutputFormatIndented ?? false)
);
SaveFileAsJson(
Path.Combine(
this._reportDirectoryPath,
ReportingConsoleConstants.configurationFile),
this._nasReportConfiguration,
(this._nasReportConfiguration.IsOutputFormatIndented ?? false)
);
// Copy the log file
File.Copy(
Path.Combine(
this._applicationLogPath,
ReportingConsoleConstants.nasReportingLogsFile),
Path.Combine(
this._reportDirectoryPath,
ReportingConsoleConstants.logsFile), true);
}
catch (ReportingConsoleException ex)
{
throw ex;
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorCompleteReportDirectory,
ex
);
}
}
/// <summary>
/// Create the compress file of report
/// </summary>
private void ZipReport()
{
try
{
_reportZipFilePath = Path.Combine(
this._nasReportConfiguration.OutputPath,
string.Concat(this._nasReportConfiguration.NasReportId, ReportingConsoleConstants.ZipExtension));
// If zip already exist, destoy it to regenerate it
if (File.Exists(this._reportZipFilePath))
File.Delete(this._reportZipFilePath);
// Create zip from directory of report
ZipFile.CreateFromDirectory(
this._reportDirectoryPath,
this._reportZipFilePath
);
// Destroy directory of current analyse
Directory.Delete(this._reportDirectoryPath, true);
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorZipReport,
ex
);
}
}
/// <summary>
/// Archive the zip file report
/// </summary>
private void ArchiveReport()
{
try
{
this._reportZipFileArchivePath = Path.Combine(this._archiveDirectoryPath, this._nasReportConfiguration.NasReportId + ReportingConsoleConstants.ZipExtension);
//Create directory for archive
if (!Directory.Exists(this._archiveDirectoryPath))
Directory.CreateDirectory(this._archiveDirectoryPath);
// Copy the log file
File.Move(this._reportZipFilePath, this._reportZipFileArchivePath);
// Delete file
File.Delete(this._reportZipFilePath);
}
catch(System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorArchiveReport,
ex
);
}
}
/// <summary>
/// Save object as JsonFile
/// </summary>
/// <param name="filePath"></param>
/// <param name="obj"></param>
/// <param name="formatIndented"></param>
private void SaveFileAsJson(string filePath, object obj, bool formatIndented = false)
{
try
{
string json = JsonConvert.SerializeObject(obj, formatIndented ? Formatting.Indented : Formatting.None);
if (filePath.EndsWith(ReportingConsoleConstants.JsonExtension))
{
File.WriteAllText(filePath, json);
}
else
{
File.WriteAllText(filePath + ReportingConsoleConstants.JsonExtension, json);
}
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorSaveFileAsJson,
ex
);
}
}
/// <summary>
/// Deserialization of the configuration file
/// </summary>
/// <param name="filePath"></param>
public T DeserializeJsonFile<T>(string filePath)
{
try
{
if (filePath.EndsWith(ReportingConsoleConstants.JsonExtension))
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(filePath));
}
else
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText(filePath + ReportingConsoleConstants.JsonExtension));
}
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorDeserializeJsonFile,
ex
);
}
}
/// <summary>
/// Download a file at the url adress and save it in the path
/// </summary>
/// <param name="url"></param>
/// <param name="filePath"></param>
public void DownloadJsonFile(string url, string filePath)
{
try
{
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
WebReq.Method = "GET";
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
using (Stream stream = WebResp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
if (filePath.EndsWith(ReportingConsoleConstants.JsonExtension))
{
File.WriteAllText(filePath, reader.ReadToEnd());
}
else
{
File.WriteAllText(filePath + ReportingConsoleConstants.JsonExtension, reader.ReadToEnd());
}
}
}
catch (System.Exception ex)
{
throw new ReportingConsoleException(
ReportingConsoleExitCode.UnexpectedErrorDownloadJsonFile,
ex
);
}
}
/// <summary>
/// Try to get GetAccessControl of directory to detect if we have access
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private bool AccessDirectory(string path)
{
try
{
System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(path);
return true;
}
catch
{
return false;
}
}
#region Logs
private void WriteLogError(NasReportingServiceException exception, NasServerAnalyse nasServerAnalyse = null)
{
this._nasReport?.Logs.Add(exception.GetIdString());
nasServerAnalyse?.Logs.Add(exception.GetIdString());
this._logger.Error(exception.ToString());
}
private void WriteLogError(ReportingConsoleException exception)
{
this._nasReport?.Logs.Add(exception.GetIdString());
this._logger.Error(exception.ToString());
}
private void WriteLogWarn(string message)
{
this._nasReport?.Logs.Add(message);
this._logger.Warn(message);
}
private void WriteLogInfo(string message)
{
this._nasReport?.Logs.Add(message);
this._logger.Info(message);
}
#endregion
#endregion
}
}