/* Copyright (c) Cloud Software Group, Inc. * * 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.Collections.Generic; using XenAPI; using XenAdmin.Network; using XenAdmin.Dialogs; using XenAdmin.Core; using System.Windows.Forms; using XenAdmin.Actions; using XenCenterLib; using System.IO; namespace XenAdmin.Commands { /// /// Shows the ExportVMDialog dialog for the selected VM. /// internal class ExportVMCommand : Command { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); /// /// Initializes a new instance of this Command. The parameter-less constructor is required if /// this Command is to be attached to a ToolStrip menu item or button. It should not be used in any other scenario. /// public ExportVMCommand() { } public ExportVMCommand(IMainWindow mainWindow, IEnumerable selection) : base(mainWindow, selection) { } public ExportVMCommand(IMainWindow mainWindow, SelectedItem selection) : base(mainWindow, selection) { } public ExportVMCommand(IMainWindow mainWindow, VM vm) : base(mainWindow, vm) { } /// /// /// /// /// The VM to export. /// Used for filtering purposes. May be null. private void Run(IXenConnection connection, VM vm, Host host) { /* * These properties have not been copied over to the new save file dialog. * dlg.AddExtension = true; dlg.CheckPathExists = true; dlg.CreatePrompt = false; dlg.CheckFileExists = false; dlg.OverwritePrompt = true; dlg.ValidateNames = true;*/ string filename; bool verify; // Showing this dialog has the (undocumented) side effect of changing the working directory // to that of the file selected. This means a handle to the directory persists, making // it undeletable until the program exits, or the working dir moves on. So, save and // restore the working dir... String oldDir = ""; try { oldDir = Directory.GetCurrentDirectory(); while (true) { ExportVMDialog dlg = new ExportVMDialog(); dlg.DefaultExt = "xva"; dlg.Filter = Messages.MAINWINDOW_XVA_BLURB; dlg.Title = Messages.MAINWINDOW_XVA_TITLE; if (dlg.ShowDialog(Parent) != DialogResult.OK) return; filename = dlg.FileName; verify = dlg.Verify; // CA-12975: Warn the user if the export operation does not have enough disk space to // complete. This is an approximation only. Win32.DiskSpaceInfo diskSpaceInfo = null; try { diskSpaceInfo = Win32.GetDiskSpaceInfo(dlg.FileName); } catch (Exception exn) { log.Warn(exn, exn); } if (diskSpaceInfo == null) { // Could not determine free disk space. Carry on regardless. break; } else { ulong freeSpace = diskSpaceInfo.FreeBytesAvailable; decimal neededSpace = vm.GetRecommendedExportSpace(Properties.Settings.Default.ShowHiddenVMs); ulong spaceLeft = 100 * Util.BINARY_MEGA; // We want the user to be left with some disk space afterwards if (neededSpace >= freeSpace - spaceLeft) { string msg = string.Format(Messages.CONFIRM_EXPORT_NOT_ENOUGH_MEMORY, Util.DiskSizeString((long)neededSpace), Util.DiskSizeString((long)freeSpace), vm.Name()); DialogResult dr; using (var d = new WarningDialog(msg, new ThreeButtonDialog.TBDButton(Messages.CONTINUE_WITH_EXPORT, DialogResult.OK), new ThreeButtonDialog.TBDButton(Messages.CHOOSE_ANOTHER_DESTINATION, DialogResult.Retry), ThreeButtonDialog.ButtonCancel){HelpNameSetter = "ExportVmDialogInsufficientDiskSpace"}) { dr = d.ShowDialog(Parent); } if (dr == DialogResult.Retry) { continue; } else if (dr == DialogResult.Cancel) { return; } } if (diskSpaceInfo.IsFAT && neededSpace > (4 * Util.BINARY_GIGA) - 1) { string msg = string.Format(Messages.CONFIRM_EXPORT_FAT, Util.DiskSizeString((long)neededSpace), Util.DiskSizeString(4 * Util.BINARY_GIGA), vm.Name()); DialogResult dr; using (var d = new WarningDialog(msg, new ThreeButtonDialog.TBDButton(Messages.CONTINUE_WITH_EXPORT, DialogResult.OK), new ThreeButtonDialog.TBDButton(Messages.CHOOSE_ANOTHER_DESTINATION, DialogResult.Retry), ThreeButtonDialog.ButtonCancel){HelpNameSetter = "ExportVmDialogFSLimitExceeded"}) { dr = d.ShowDialog(Parent); } if (dr == DialogResult.Retry) { continue; } else if (dr == DialogResult.Cancel) { return; } } break; } } } finally { Directory.SetCurrentDirectory(oldDir); } new ExportVmAction(connection, host, vm, filename, verify).RunAsync(); } protected override void RunCore(SelectedItemCollection selection) { VM vm = (VM)selection[0].XenObject; Host host = vm.Home(); Pool pool = Helpers.GetPool(vm.Connection); if (host == null && pool != null) { host = pool.Connection.Resolve(pool.master); } Run(selection[0].Connection, vm, host); } protected override bool CanRunCore(SelectedItemCollection selection) { if (selection.Count == 1) { VM vm = selection[0].XenObject as VM; if (vm != null && !vm.is_a_template && !vm.Locked && vm.allowed_operations != null && vm.allowed_operations.Contains(vm_operations.export)) { return true; } } return false; } public override string MenuText { get { return Messages.MAINWINDOW_EXPORT_VM_AS_BACKUP; } } protected override string GetCantRunReasonCore(IXenObject item) { VM vm = item as VM; if (vm == null) return base.GetCantRunReasonCore(item); if (vm.power_state == vm_power_state.Running) return Messages.MAINWINDOW_EXPORT_VM_AS_BACKUP_TOOLTIP; return null; } } }