2023-01-24 15:29:31 +01:00
|
|
|
|
/* Copyright (c) Cloud Software Group, Inc.
|
2013-06-24 13:41:48 +02:00
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
|
* that the following conditions are met:
|
|
|
|
|
*
|
|
|
|
|
* * Redistributions of source code must retain the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer.
|
|
|
|
|
* * Redistributions in binary form must reproduce the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer in the documentation and/or other
|
|
|
|
|
* materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using XenCenterLib.Archive;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.Actions
|
|
|
|
|
{
|
2023-02-13 14:47:21 +01:00
|
|
|
|
public class ZipStatusReportAction : StatusReportAction
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The folder containing the raw files as downloaded from the server
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly string _inputTempFolder;
|
2019-07-03 12:07:55 +02:00
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// <summary>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
/// Temporary folder in which we assemble the log files from the server
|
|
|
|
|
/// before repackaging them in a single zip file.
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// </summary>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
private string _extractTempDir;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
/// The destination zip file for the repackaged server log files
|
2013-06-24 13:41:48 +02:00
|
|
|
|
/// </summary>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
private readonly string _destFile;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2018-08-03 10:08:47 +02:00
|
|
|
|
/// <summary>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
/// Creates a new instance of the action for zipping downloaded server log files
|
2018-08-03 10:08:47 +02:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="tempFolder">Temporary folder to store the downloaded logs</param>
|
|
|
|
|
/// <param name="destFile">The target file to store the compressed result</param>
|
2023-02-13 14:47:21 +01:00
|
|
|
|
/// <param name="timeString">Time string used when running action as <see cref="StatusReportAction"/>. Can be omitted otherwise.</param>
|
2019-07-03 12:07:55 +02:00
|
|
|
|
/// <param name="suppressHistory">Whether to suppress history in the Events TabPage</param>
|
2023-02-13 14:47:21 +01:00
|
|
|
|
public ZipStatusReportAction(string tempFolder, string destFile, string timeString = null, bool suppressHistory = true)
|
|
|
|
|
: base(null, Messages.BUGTOOL_SAVING, destFile, timeString, suppressHistory)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
_inputTempFolder = tempFolder;
|
|
|
|
|
_destFile = destFile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Run()
|
|
|
|
|
{
|
2023-02-13 14:47:21 +01:00
|
|
|
|
Status = ReportStatus.inProgress;
|
2019-07-03 12:07:55 +02:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
_extractTempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
|
|
|
|
} while (Directory.Exists(_extractTempDir));
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory(_extractTempDir);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Calculate total bytes to save
|
2019-07-03 12:07:55 +02:00
|
|
|
|
long bytesToCompress = 0, bytesToExtract = 0, bytesExtracted = 0;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
var files = Directory.GetFiles(_inputTempFolder);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
foreach (string inputFile in files)
|
|
|
|
|
bytesToExtract += new FileInfo(inputFile).Length;
|
|
|
|
|
|
|
|
|
|
foreach (string inputFile in files)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (inputFile.ToLowerInvariant().EndsWith(".tar"))
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
// Sanitize and un-tar each of the raw server tars to the temp extraction directory
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
string outFilename = inputFile.Substring(0, inputFile.Length - 4);
|
|
|
|
|
if (outFilename.Length == 0)
|
|
|
|
|
outFilename = Path.GetRandomFileName();
|
2019-07-03 12:07:55 +02:00
|
|
|
|
string outputDir = Path.Combine(_extractTempDir, Path.GetFileName(outFilename));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2023-02-17 12:19:49 +01:00
|
|
|
|
string sanitizedTar = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
2019-07-03 12:07:55 +02:00
|
|
|
|
TarSanitization.SanitizeTarForWindows(inputFile, sanitizedTar, CheckCancellation);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
using (FileStream fs = File.OpenRead(sanitizedTar))
|
|
|
|
|
using (ArchiveIterator tarIterator = ArchiveFactory.Reader(ArchiveFactory.Type.Tar, fs))
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
Directory.CreateDirectory(outputDir);
|
|
|
|
|
tarIterator.ExtractAllContents(outputDir);
|
|
|
|
|
bytesToCompress += Core.Helpers.GetDirSize(new DirectoryInfo(outputDir));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
File.Delete(sanitizedTar);
|
|
|
|
|
}
|
|
|
|
|
catch
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2021-09-10 15:19:08 +02:00
|
|
|
|
// ignored
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Just copy vanilla input files unmodified to the temp directory
|
2019-07-03 12:07:55 +02:00
|
|
|
|
string outputFile = Path.Combine(_extractTempDir, Path.GetFileName(inputFile));
|
2013-06-24 13:41:48 +02:00
|
|
|
|
File.Copy(inputFile, outputFile);
|
|
|
|
|
bytesToCompress += new FileInfo(outputFile).Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytesExtracted += new FileInfo(inputFile).Length;
|
|
|
|
|
File.Delete(inputFile);
|
2019-07-03 12:07:55 +02:00
|
|
|
|
PercentComplete = (int)(50.0 * bytesExtracted / bytesToExtract);
|
|
|
|
|
CheckCancellation();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now zip up all the temporarily extracted files into a single zip file for the user
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.DebugFormat("Packing {0} of bug report files into zip file {1}",
|
2013-06-24 13:41:48 +02:00
|
|
|
|
Util.DiskSizeString(bytesToCompress), _destFile);
|
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
ZipToOutputFile(_extractTempDir, CheckCancellation, p => PercentComplete = 50 + p / 2);
|
|
|
|
|
CleanupFiles();
|
|
|
|
|
PercentComplete = 100;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
catch (CancelledException)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
CleanupFiles(true);
|
2023-02-13 14:47:21 +01:00
|
|
|
|
log.Info("Packaging system status cancelled");
|
|
|
|
|
Tick(100, Messages.ACTION_SAVE_STATUS_REPORT_CANCELLED);
|
|
|
|
|
Status = ReportStatus.cancelled;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exn)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
log.Error("Failed to package sanitized server status report: ", exn);
|
2023-02-13 14:47:21 +01:00
|
|
|
|
log.Info("Attempting to package raw downloaded server files.");
|
2019-07-03 12:07:55 +02:00
|
|
|
|
ZipToOutputFile(_inputTempFolder, CheckCancellation);
|
|
|
|
|
}
|
2023-02-13 14:47:21 +01:00
|
|
|
|
catch (CancelledException)
|
2019-07-03 12:07:55 +02:00
|
|
|
|
{
|
2023-02-13 14:47:21 +01:00
|
|
|
|
log.Info("Packaging raw downloaded server cancelled");
|
|
|
|
|
Tick(100, Messages.ACTION_SAVE_STATUS_REPORT_CANCELLED);
|
|
|
|
|
Status = ReportStatus.cancelled;
|
2019-07-03 12:07:55 +02:00
|
|
|
|
CleanupFiles(true);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2023-02-13 14:47:21 +01:00
|
|
|
|
catch (Exception exception)
|
2019-07-03 12:07:55 +02:00
|
|
|
|
{
|
2023-02-13 14:47:21 +01:00
|
|
|
|
log.Error("Failed to package raw downloaded server files.", exception);
|
2019-07-03 12:07:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 14:47:21 +01:00
|
|
|
|
Tick(100, Messages.ACTION_SAVE_STATUS_REPORT_FAILED);
|
|
|
|
|
Status = ReportStatus.failed;
|
|
|
|
|
throw new Exception(Messages.ACTION_SAVE_STATUS_REPORT_FAILED_PARTIAL);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2023-02-13 14:47:21 +01:00
|
|
|
|
|
|
|
|
|
Tick(100, Messages.COMPLETED);
|
|
|
|
|
Status = ReportStatus.succeeded;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
private void CheckCancellation()
|
|
|
|
|
{
|
|
|
|
|
if (Cancelling)
|
|
|
|
|
throw new CancelledException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ZipToOutputFile(string folderToZip, Action cancellingDelegate = null, Action<int> progressDelegate = null)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
using (ArchiveWriter zip = ArchiveFactory.Writer(ArchiveFactory.Type.Zip, File.OpenWrite(_destFile)))
|
2019-07-03 12:07:55 +02:00
|
|
|
|
zip.CreateArchive(folderToZip, cancellingDelegate, progressDelegate);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-03 12:07:55 +02:00
|
|
|
|
private void CleanupFiles(bool deleteDestFile = false)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Debug("Deleting temporary directory with raw downloaded server files");
|
2013-06-24 13:41:48 +02:00
|
|
|
|
Directory.Delete(_inputTempFolder, true);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exn)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Warn("Could not delete temporary directory with raw downloaded server files", exn);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Debug("Deleting directory with temporarily extracted files");
|
|
|
|
|
Directory.Delete(_extractTempDir, true);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception exn)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Warn("Could not delete directory with temporarily extracted files", exn);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
2017-06-29 12:44:17 +02:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (deleteDestFile)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Debug("Deleting destination zip file");
|
2017-06-29 12:44:17 +02:00
|
|
|
|
File.Delete(_destFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2019-07-03 12:07:55 +02:00
|
|
|
|
log.Warn("Could not delete destination zip file", ex);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void RecomputeCanCancel()
|
|
|
|
|
{
|
|
|
|
|
CanCancel = !Cancelling && !IsCompleted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void CancelRelatedTask()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|