/* 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 System.Linq; using System.Windows.Forms; using XenAdmin.Actions; using XenAdmin.Core; using XenAdmin.Network; using XenAdmin.Wizards.GenericPages; using XenAPI; using XenAdmin.Dialogs; using XenAdmin.Wizards.NewSRWizard_Pages; using XenAdmin.Wizards.NewSRWizard_Pages.Frontends; using XenAdmin.Controls; using XenAdmin.Actions.DR; namespace XenAdmin.Wizards { public partial class NewSRWizard : XenWizardBase { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #region Wizard pages private readonly NewSrWizardNamePage xenTabPageSrName; private readonly CIFS_ISO xenTabPageCifsIso; private readonly CifsFrontend xenTabPageCifs; private readonly VHDoNFS xenTabPageVhdoNFS; private readonly NFS_ISO xenTabPageNfsIso; private readonly LVMoISCSI xenTabPageLvmoIscsi; private readonly LVMoHBA xenTabPageLvmoHba; private readonly LVMoFCoE xenTabPageLvmoFcoe; private readonly LVMoHBASummary xenTabPageLvmoHbaSummary; private readonly ChooseSrTypePage xenTabPageChooseSrType; private readonly ChooseSrProvisioningPage xenTabPageChooseSrProv; private readonly RBACWarningPage xenTabPageRbacWarning; #endregion /// /// The final action for this wizard is handled in this class, but the front end pages sometimes need to know when it's done so they /// allow the user to leave them. /// public AsyncAction FinalAction; private readonly string m_text; // For SR Reconfiguration private readonly SR _srToReattach; private SrWizardType m_srWizardType; private readonly bool _rbac; private bool showProvisioningPage; public NewSRWizard(IXenConnection connection) : this(connection, null) { } public NewSRWizard(IXenConnection connection, SR srToReattach) : this(connection, srToReattach, false) { } internal NewSRWizard(IXenConnection connection, SR srToReattach, bool disasterRecoveryTask) : base(connection) { InitializeComponent(); xenTabPageSrName = new NewSrWizardNamePage(); xenTabPageCifsIso = new CIFS_ISO(); xenTabPageCifs = new CifsFrontend(); xenTabPageVhdoNFS = new VHDoNFS(); xenTabPageNfsIso = new NFS_ISO(); xenTabPageLvmoIscsi = new LVMoISCSI(); xenTabPageLvmoHba = new LVMoHBA(); xenTabPageLvmoFcoe = new LVMoFCoE(); xenTabPageLvmoHbaSummary = new LVMoHBASummary(); xenTabPageChooseSrType = new ChooseSrTypePage(); xenTabPageChooseSrProv = new ChooseSrProvisioningPage(); xenTabPageRbacWarning = new RBACWarningPage((srToReattach == null && !disasterRecoveryTask) ? Messages.RBAC_WARNING_PAGE_DESCRIPTION_SR_CREATE : Messages.RBAC_WARNING_PAGE_DESCRIPTION_SR_ATTACH); //do not use virtual members in constructor var format = (srToReattach == null && !disasterRecoveryTask) ? Messages.NEWSR_TEXT : Messages.NEWSR_TEXT_ATTACH; m_text = string.Format(format, Helpers.GetName(xenConnection)); _srToReattach = srToReattach; xenTabPageChooseSrType.SrToReattach = srToReattach; xenTabPageChooseSrType.DisasterRecoveryTask = disasterRecoveryTask; // Order the tab pages AddPage(xenTabPageChooseSrType); AddPage(xenTabPageSrName); AddPage(new XenTabPage {Text = Messages.NEWSR_LOCATION}); // RBAC warning page _rbac = (xenConnection != null && !xenConnection.Session.IsLocalSuperuser) && Helpers.GetCoordinator(xenConnection).external_auth_type != Auth.AUTH_TYPE_NONE; if (_rbac) { // if reattaching, add "Permission checks" page after "Name" page, otherwise as first page (Ref. CA-61525) if (_srToReattach != null) AddAfterPage(xenTabPageSrName, xenTabPageRbacWarning); else AddPage(xenTabPageRbacWarning, 0); ConfigureRbacPage(disasterRecoveryTask); } } private void ConfigureRbacPage(bool disasterRecoveryTask) { if (!_rbac) return; xenTabPageRbacWarning.Connection = xenConnection; var warningMessage = _srToReattach == null && !disasterRecoveryTask ? Messages.RBAC_WARNING_SR_WIZARD_CREATE : Messages.RBAC_WARNING_SR_WIZARD_ATTACH; var check = new WizardRbacCheck(warningMessage) { Blocking = true }; check.AddApiMethods("SR.probe"); if (Helpers.KolkataOrGreater(xenConnection) && !Helpers.FeatureForbidden(xenConnection, Host.CorosyncDisabled)) check.AddApiMethods("SR.probe_ext"); if (_srToReattach == null) { // create check.AddApiMethods(SrCreateAction.StaticRBACDependencies); } else if (disasterRecoveryTask && SR.SupportsDatabaseReplication(xenConnection, _srToReattach)) { // "Attach SR needed for DR" case check.AddApiMethods(DrTaskCreateAction.StaticRBACDependencies); } else { // reattach check.AddApiMethods(SrReattachAction.StaticRBACDependencies); } xenTabPageRbacWarning.SetPermissionChecks(xenConnection, check); } private bool SetFCDevicesOnLVMoHBAPage(LVMoHBA page) { List devices; var success = page.FiberChannelScan(this, xenConnection, out devices); page.FCDevices = devices; return success; } private bool CanShowLVMoHBASummaryPage(List SrDescriptors) { string description = m_srWizardType.Description; string name = m_srWizardType.SrName; List names = xenConnection.Cache.SRs.Select(sr => sr.Name()).ToList(); m_srWizardType.SrDescriptors.Clear(); foreach (var descriptor in SrDescriptors) { descriptor.Name = name; if (!string.IsNullOrEmpty(description)) descriptor.Description = description; m_srWizardType.SrDescriptors.Add(descriptor); m_srWizardType.IsGfs2 = descriptor is Gfs2HbaSrDescriptor || descriptor is Gfs2FcoeSrDescriptor; names.Add(name); name = SrWizardHelpers.DefaultSRName(m_srWizardType is SrWizardType_Hba ? Messages.NEWSR_HBA_DEFAULT_NAME : Messages.NEWSR_FCOE_DEFAULT_NAME, names); } xenTabPageLvmoHbaSummary.SuccessfullyCreatedSRs.Clear(); xenTabPageLvmoHbaSummary.FailedToCreateSRs.Clear(); RunFinalAction(out var closeWizard); return closeWizard; } protected override bool RunNextPagePrecheck(XenTabPage senderPage) { var runPrechecks = showProvisioningPage ? senderPage == xenTabPageChooseSrProv : (_srToReattach != null && _rbac ? senderPage == xenTabPageRbacWarning : senderPage == xenTabPageSrName); if (runPrechecks) { if (m_srWizardType is SrWizardType_Fcoe) { xenTabPageLvmoFcoe.SrType = showProvisioningPage && xenTabPageChooseSrProv.IsGfs2 ? SR.SRTypes.gfs2 : SR.SRTypes.lvmofcoe; return SetFCDevicesOnLVMoHBAPage(xenTabPageLvmoFcoe); } if (m_srWizardType is SrWizardType_Hba) { xenTabPageLvmoHba.SrType = showProvisioningPage && xenTabPageChooseSrProv.IsGfs2 ? SR.SRTypes.gfs2 : SR.SRTypes.lvmohba; return SetFCDevicesOnLVMoHBAPage(xenTabPageLvmoHba); } } if (senderPage == xenTabPageLvmoFcoe) { return CanShowLVMoHBASummaryPage(xenTabPageLvmoFcoe.SrDescriptors); } if (m_srWizardType is SrWizardType_Hba) { if (senderPage == xenTabPageLvmoHba) { return CanShowLVMoHBASummaryPage(xenTabPageLvmoHba.SrDescriptors); } } return base.RunNextPagePrecheck(senderPage); } protected override void UpdateWizardContent(XenTabPage senderPage) { var senderPagetype = senderPage.GetType(); if (senderPagetype == typeof(ChooseSrTypePage)) { #region showProvisioningPage = false; RemovePagesFrom(_rbac ? 3 : 2); m_srWizardType = xenTabPageChooseSrType.SrWizardType; if (m_srWizardType is SrWizardType_VhdoNfs) AddPage(xenTabPageVhdoNFS); else if (m_srWizardType is SrWizardType_Iscsi) { showProvisioningPage = Helpers.KolkataOrGreater(xenConnection) && !Helpers.FeatureForbidden(xenConnection, Host.CorosyncDisabled); if (showProvisioningPage) AddPage(xenTabPageChooseSrProv); AddPage(xenTabPageLvmoIscsi); } else if (m_srWizardType is SrWizardType_Hba) { showProvisioningPage = Helpers.KolkataOrGreater(xenConnection) && !Helpers.FeatureForbidden(xenConnection, Host.CorosyncDisabled); if (showProvisioningPage) AddPage(xenTabPageChooseSrProv); AddPage(xenTabPageLvmoHba); AddPage(xenTabPageLvmoHbaSummary); } else if (m_srWizardType is SrWizardType_Fcoe) { AddPage(xenTabPageLvmoFcoe); AddPage(xenTabPageLvmoHbaSummary); } else if (m_srWizardType is SrWizardType_CifsIso) AddPage(xenTabPageCifsIso); else if (m_srWizardType is SrWizardType_Cifs) AddPage(xenTabPageCifs); else if (m_srWizardType is SrWizardType_NfsIso) AddPage(xenTabPageNfsIso); xenTabPageSrName.SrWizardType = m_srWizardType; xenTabPageSrName.MatchingFrontends = xenTabPageChooseSrType.MatchingFrontends; NotifyNextPagesOfChange(xenTabPageSrName); #endregion } else if (senderPagetype == typeof(NewSrWizardNamePage)) { #region m_srWizardType.SrName = xenTabPageSrName.SrName; m_srWizardType.Description = xenTabPageSrName.SrDescription; m_srWizardType.AutoDescriptionRequired = xenTabPageSrName.AutoDescriptionRequired; if (m_srWizardType is SrWizardType_VhdoNfs) xenTabPageVhdoNFS.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_Iscsi) xenTabPageLvmoIscsi.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_Hba) xenTabPageLvmoHba.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_CifsIso) xenTabPageCifsIso.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_NfsIso) xenTabPageNfsIso.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_Cifs) xenTabPageCifs.SrWizardType = m_srWizardType; else if (m_srWizardType is SrWizardType_Fcoe) xenTabPageLvmoFcoe.SrWizardType = m_srWizardType; #endregion } else if (senderPagetype == typeof(ChooseSrProvisioningPage)) { var isGfs2 = xenTabPageChooseSrProv.IsGfs2; xenTabPageLvmoHba.SrType = isGfs2 ? SR.SRTypes.gfs2 : SR.SRTypes.lvmohba; xenTabPageLvmoFcoe.SrType = isGfs2 ? SR.SRTypes.gfs2 : SR.SRTypes.lvmofcoe; xenTabPageLvmoIscsi.SrType = isGfs2 ? SR.SRTypes.gfs2 : SR.SRTypes.lvmoiscsi; } else if (senderPagetype == typeof(CIFS_ISO)) { m_srWizardType.DeviceConfig = xenTabPageCifsIso.DeviceConfig; SetCustomDescription(m_srWizardType, xenTabPageCifsIso.SrDescription); } else if (senderPagetype == typeof(CifsFrontend)) { m_srWizardType.UUID = xenTabPageCifs.UUID; m_srWizardType.DeviceConfig = xenTabPageCifs.DeviceConfig; SetCustomDescription(m_srWizardType, xenTabPageCifs.SrDescription); } else if (senderPagetype == typeof(LVMoISCSI)) { SetCustomDescription(m_srWizardType, xenTabPageLvmoIscsi.SrDescription); m_srWizardType.UUID = xenTabPageLvmoIscsi.UUID; m_srWizardType.DeviceConfig = xenTabPageLvmoIscsi.DeviceConfig; m_srWizardType.IsGfs2 = xenTabPageLvmoIscsi.SrType == SR.SRTypes.gfs2; } else if (senderPagetype == typeof(NFS_ISO)) { m_srWizardType.DeviceConfig = xenTabPageNfsIso.DeviceConfig; SetCustomDescription(m_srWizardType, xenTabPageNfsIso.SrDescription); } else if (senderPagetype == typeof(VHDoNFS)) { m_srWizardType.UUID = xenTabPageVhdoNFS.UUID; m_srWizardType.DeviceConfig = xenTabPageVhdoNFS.DeviceConfig; SetCustomDescription(m_srWizardType, xenTabPageVhdoNFS.SrDescription); } } private static void SetCustomDescription(SrWizardType srwizardtype, string description) { if (srwizardtype.Description == null) srwizardtype.Description = description; } protected override void FinishWizard() { if (m_srWizardType is SrWizardType_Hba || m_srWizardType is SrWizardType_Fcoe) { base.FinishWizard(); return; } bool closeWizard; RunFinalAction(out closeWizard); if (closeWizard) base.FinishWizard(); } private void RunFinalAction(out bool closeWizard) { FinalAction = null; closeWizard = false; // Override the WizardBase: try running the SR create/attach. If it succeeds, close the wizard. // Otherwise show the error and allow the user to adjust the settings and try again. Pool pool = Helpers.GetPoolOfOne(xenConnection); if (pool == null) { log.Error("New SR Wizard: Pool has disappeared"); using (var dlg = new WarningDialog(string.Format(Messages.NEW_SR_CONNECTION_LOST, Helpers.GetName(xenConnection)))) { dlg.ShowDialog(this); } closeWizard = true; return; } Host coordinator = xenConnection.Resolve(pool.master); if (coordinator == null) { log.Error("New SR Wizard: Coordinator has disappeared"); using (var dlg = new WarningDialog(string.Format(Messages.NEW_SR_CONNECTION_LOST, Helpers.GetName(xenConnection)))) { dlg.ShowDialog(this); } closeWizard = true; return; } if (_srToReattach != null && _srToReattach.HasPBDs() && _srToReattach.Connection == xenConnection) { // Error - cannot reattach attached SR MessageBox.Show(this, String.Format(Messages.STORAGE_IN_USE, _srToReattach.Name(), Helpers.GetName(xenConnection)), Text, MessageBoxButtons.OK, MessageBoxIcon.Error); FinishCanceled(); return; } // show warning prompt if required if (!AskUserIfShouldContinue()) { FinishCanceled(); return; } List actionList = GetActions(coordinator, m_srWizardType.DisasterRecoveryTask); if (actionList.Count == 1) FinalAction = actionList[0]; else FinalAction = new ParallelAction(Messages.NEW_SR_WIZARD_FINAL_ACTION_TITLE, Messages.NEW_SR_WIZARD_FINAL_ACTION_START, Messages.NEW_SR_WIZARD_FINAL_ACTION_END, actionList, xenConnection); // if this is a Disaster Recovery Task, it could be either a "Find existing SRs" or an "Attach SR needed for DR" case if (m_srWizardType.DisasterRecoveryTask) { closeWizard = true; return; } ProgressBarStyle progressBarStyle = FinalAction is SrIntroduceAction ? ProgressBarStyle.Blocks : ProgressBarStyle.Marquee; using (var dialog = new ActionProgressDialog(FinalAction, progressBarStyle) {ShowCancel = true}) { if (m_srWizardType is SrWizardType_Hba || m_srWizardType is SrWizardType_Fcoe) { ActionProgressDialog closureDialog = dialog; // close dialog even when there's an error for HBA SR type as there will be the Summary page displayed. FinalAction.Completed += s => Program.Invoke(Program.MainWindow, () => { if (closureDialog != null) closureDialog.Close(); }); } dialog.ShowDialog(this); } if (m_srWizardType is SrWizardType_Hba || m_srWizardType is SrWizardType_Fcoe) { foreach (var asyncAction in actionList) { AddActionToSummary(asyncAction); } } if (!FinalAction.Succeeded && FinalAction is SrReattachAction && _srToReattach.HasPBDs()) { // reattach failed. Ensure PBDs are now unplugged and destroyed. using (var dialog = new ActionProgressDialog(new DetachSrAction(_srToReattach, true), progressBarStyle)) { dialog.ShowCancel = false; dialog.ShowDialog(); } } // If action failed and frontend wants to stay open, just return if (!FinalAction.Succeeded) { DialogResult = DialogResult.None; FinishCanceled(); if (m_srWizardType.AutoDescriptionRequired) { foreach (var srDescriptor in m_srWizardType.SrDescriptors) { srDescriptor.Description = null; } } return; } // Close wizard closeWizard = true; } private Dictionary actionSrDescriptorDict = new Dictionary(); void AddActionToSummary(AsyncAction action) { if (action == null) return; SrDescriptor srDescriptor; actionSrDescriptorDict.TryGetValue(action, out srDescriptor); if (srDescriptor == null) return; if (action.Succeeded) xenTabPageLvmoHbaSummary.SuccessfullyCreatedSRs.Add(srDescriptor); else xenTabPageLvmoHbaSummary.FailedToCreateSRs.Add(srDescriptor); } private List GetActions(Host coordinator, bool disasterRecoveryTask) { // Now we need to decide what to do. // This will be one off create, introduce, reattach List finalActions = new List(); actionSrDescriptorDict.Clear(); foreach (var srDescriptor in m_srWizardType.SrDescriptors) { var srType = srDescriptor is FibreChannelDescriptor ? (srDescriptor as FibreChannelDescriptor).SrType : m_srWizardType.Type; if (String.IsNullOrEmpty(srDescriptor.UUID)) { // Don't need to show any warning, as the only destructive creates // are in iSCSI and HBA, where they show their own warning finalActions.Add(new SrCreateAction(xenConnection, coordinator, srDescriptor.Name, srDescriptor.Description, srType, m_srWizardType.ContentType, srDescriptor.DeviceConfig, srDescriptor.SMConfig)); } else if (_srToReattach == null || _srToReattach.Connection != xenConnection) { // introduce if (disasterRecoveryTask && (_srToReattach == null || SR.SupportsDatabaseReplication(xenConnection, _srToReattach))) { // "Find existing SRs" or "Attach SR needed for DR" cases ScannedDeviceInfo deviceInfo = new ScannedDeviceInfo(srType, srDescriptor.DeviceConfig, srDescriptor.UUID); finalActions.Add(new DrTaskCreateAction(xenConnection, deviceInfo)); } else finalActions.Add(new SrIntroduceAction(xenConnection, srDescriptor.UUID, srDescriptor.Name, srDescriptor.Description, srType, m_srWizardType.ContentType, srDescriptor.DeviceConfig)); } else { // Reattach if (disasterRecoveryTask && SR.SupportsDatabaseReplication(xenConnection, _srToReattach)) { // "Attach SR needed for DR" case ScannedDeviceInfo deviceInfo = new ScannedDeviceInfo(_srToReattach.GetSRType(true), srDescriptor.DeviceConfig, _srToReattach.uuid); finalActions.Add(new DrTaskCreateAction(xenConnection, deviceInfo)); } else finalActions.Add(new SrReattachAction(_srToReattach, srDescriptor.Name, srDescriptor.Description, srDescriptor.DeviceConfig)); } AsyncAction action = finalActions.Last(); if (!actionSrDescriptorDict.ContainsKey(action)) actionSrDescriptorDict.Add(action, srDescriptor); } return finalActions; } private bool AskUserIfShouldContinue() { if (!Program.RunInAutomatedTestMode && !String.IsNullOrEmpty(m_srWizardType.UUID)) { if (_srToReattach == null) { // introduce if (m_srWizardType.ShowIntroducePrompt) { DialogResult dialogResult; using (var dlg = new WarningDialog(string.Format(Messages.NEWSR_MULTI_POOL_WARNING, BrandManager.BrandConsole, m_srWizardType.UUID), ThreeButtonDialog.ButtonYes, new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true)) {WindowTitle = Text}) { dialogResult = dlg.ShowDialog(this); } return DialogResult.Yes == dialogResult; } } else if (_srToReattach.Connection == xenConnection) { // Reattach if (m_srWizardType.ShowReattachWarning) { DialogResult dialogResult; using (var dlg = new WarningDialog(string.Format(Messages.NEWSR_MULTI_POOL_WARNING, BrandManager.BrandConsole, _srToReattach.Name()), ThreeButtonDialog.ButtonYes, new ThreeButtonDialog.TBDButton(Messages.NO_BUTTON_CAPTION, DialogResult.No, selected: true)) {WindowTitle = Text}) { dialogResult = dlg.ShowDialog(this); } return DialogResult.Yes == dialogResult; } } else { // uuid != null // _srToReattach != null // _srToReattach.Server.IsDetached // _srToReattach.Connection != current connection // Warn user SR is already attached to other pool, and then introduce to this pool DialogResult dialogResult; using (var dlg = new WarningDialog(string.Format(Messages.ALREADY_ATTACHED_ELSEWHERE, _srToReattach.Name(), Helpers.GetName(xenConnection), Text, BrandManager.BrandConsole), ThreeButtonDialog.ButtonOK, ThreeButtonDialog.ButtonCancel)) { dialogResult = dlg.ShowDialog(this); } return DialogResult.OK == dialogResult; } } return true; } protected override void OnShown(EventArgs e) { base.OnShown(e); Text = m_text; //set here; do not set virtual members in constructor if (_srToReattach == null) return; if (xenTabPageChooseSrType.MatchingFrontends <= 0) { using (var dlg = new ErrorDialog(string.Format(Messages.CANNOT_FIND_SR_WIZARD_TYPE, _srToReattach.type, BrandManager.BrandConsole))) dlg.ShowDialog(this); Close(); } else if (xenTabPageChooseSrType.MatchingFrontends == 1) { // move to "Name" page NextStep(); // move to "Location" page or "Permission checks" page NextStep(); // if rbac, stay on this page (Ref. CA-61525) if (_rbac) return; } } protected override string WizardPaneHelpID() { return CurrentStepTabPage is RBACWarningPage ? FormatHelpId("Rbac") : base.WizardPaneHelpID(); } public void CheckNFSISORadioButton() { xenTabPageChooseSrType.PreselectNewSrWizardType(typeof(SrWizardType_NfsIso)); } } }