xenadmin/XenAdmin/Wizards/NewVMWizard/Page_InstallationMedia.cs
Mihaela Stoica 130dfe7b55 CA-310250: Improvements to the guest UEFI UI
-  hide the boot mode control if there is only one option (BIOS boot);
- add text "(experimental)" to the experimental options (in the radio button text);
- if an option is disabled, then hide the experimantal warning, as there is already a note saying why it is disabled;
- more detailed experimental warning.

Signed-off-by: Mihaela Stoica <mihaela.stoica@citrix.com>
2019-02-21 12:40:22 +00:00

380 lines
15 KiB
C#

/* Copyright (c) Citrix Systems, Inc.
* All rights reserved.
*
* 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 XenAdmin.Actions.VMActions;
using XenAPI;
using XenAdmin.Controls;
using XenAdmin.Core;
using System.Diagnostics;
using XenAdmin.Actions;
using XenAdmin.Dialogs;
using XenCenterLib;
using System.Windows.Forms;
using System.Drawing;
using BootMode = XenAdmin.Actions.VMActions.BootMode;
namespace XenAdmin.Wizards.NewVMWizard
{
public partial class Page_InstallationMedia : XenTabPage
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private VM m_template;
public Page_InstallationMedia()
{
InitializeComponent();
}
bool defaultTemplate, userTemplate, hvm, eli, installMethods, installCd, installUrl, cds, installed;
public Host Affinity { private get; set; }
public bool ShowInstallationMedia { private get; set; }
public bool IsSelectedTemplateHVM { get { return SelectedTemplate.IsHVM(); } }
protected override void PageLoadedCore(PageLoadedDirection direction)
{
VM oldTemplate = m_template;
m_template = SelectedTemplate;
// We only want to do all these updates if the template has changed (or has gone from null -> selected)
if (oldTemplate == m_template)
return;
/* This method is supposed to do the following:
*
* PV -> Install from DVD drive (no empty)
* Url
*
* HVM -> Install from DVD drive (no empty)
* Boot from network
*
* Custom -> DVD drive (inc empty)
*
* Disable Installation method section if the custom template has no DVD drive (except debian etch template)
*/
PvBootBox.Visible = !IsSelectedTemplateHVM;
PvBootTextBox.Text = m_template.PV_args;
bootModesControl1.Visible = IsSelectedTemplateHVM &&
BootModesControl.ShowBootModeOptions(SelectedTemplate.Connection);
;
bootModesControl1.TemplateVM = m_template;
if (!ShowInstallationMedia)
{
CdRadioButton.Checked = UrlRadioButton.Checked = false;
CdDropDownBox.Items.Clear();
UrlTextBox.Text = string.Empty;
panelInstallationMethod.Enabled = false;
return;
}
panelInstallationMethod.Enabled = true;
defaultTemplate = m_template.DefaultTemplate();
userTemplate = !defaultTemplate;
hvm = m_template.IsHVM();
eli = !hvm && m_template.PV_bootloader == "eliloader";
var tmplMethods = m_template.InstallMethods();
installMethods = !string.IsNullOrEmpty(tmplMethods);
installCd = installMethods && tmplMethods.Contains("cdrom") && (hvm || eli);
installUrl = installMethods &&
(tmplMethods.Contains("http") || tmplMethods.Contains("ftp") || tmplMethods.Contains("nfs")) &&
eli;
cds = Helpers.CDsExist(Connection);
installed = userTemplate || !installMethods;
CdRadioButton.Text = installed ? Messages.NEWVMWIZARD_INSTALLMEDIA_DVD : Messages.NEWVMWIZARD_INSTALLMEDIA_INSTALLDVD;
CdRadioButton.Enabled = (installed || installCd) && cds;
CdDropDownBox.Empty = installed;
UrlRadioButton.Text = hvm ? Messages.NEWVMWIZARD_INSTALLMEDIA_INSTALLPXE : Messages.NEWVMWIZARD_INSTALLMEDIA_INSTALLURL;
UrlRadioButton.Enabled = (!installed && ((eli && installUrl) || hvm));
UrlTextBox.Visible = !hvm;
UrlTextBox.Text = !installed ? m_template.InstallRepository() ?? "" : "";
if (installed || (installCd && cds)) // if installed we will always have the empty cd
{
CdRadioButton.Checked = true;
CdDropDownBox.Select();
}
else if (eli && installUrl)
{
UrlRadioButton.Checked = true;
UrlTextBox.Select();
}
else
{
// oh dear, select anything that is enabled
if (CdRadioButton.Enabled)
CdRadioButton.Checked = true;
else if (UrlRadioButton.Enabled)
UrlRadioButton.Checked = true;
else
Trace.Assert(false, string.Format("No install options were enabled, something is wrong with the template '{0}'", m_template.Name()));
}
if(IsBootFromNetworkCustomTemplate(userTemplate))
{
UrlRadioButton.Enabled = true;
UrlRadioButton.Checked = true;
CdRadioButton.Enabled = false;
}
LoadCdBox();
UpdateEnablement();
}
public BootMode SelectedBootMode { get { return IsSelectedTemplateHVM ? bootModesControl1.SelectedOption : BootMode.NOT_AVAILABLE; } }
private bool IsBootFromNetworkCustomTemplate(bool userTemplate)
{
return (userTemplate && m_template.GetBootOrder().StartsWith("N"));
}
private void LoadCdBox()
{
CdDropDownBox.vm = m_template;
CdDropDownBox.refreshAll();
RegisterBespokeEventsAgainstCdDropDownBox();
VBD cddrive = m_template.FindVMCDROM();
VDI cd = cddrive != null && !cddrive.empty
? Connection.Resolve<VDI>(cddrive.VDI)
: (CdDropDownBox.Empty ? null : GetAffinityDvdDrive());
if (cd == null)
return; // select default whatever that is
SR sr = Connection.Resolve<SR>(cd.SR);
if (sr == null)
return; // select default whatever that is
CdDropDownBox.SelectedCD = cd;
CdDropDownBox.SelectCD();
}
public VDI GetAffinityDvdDrive()
{
if (Affinity == null || Affinity.Connection == null)
return null;
List<SR> dvdSRs = Affinity.Connection.Cache.SRs.Where(sr => sr.content_type == SR.Content_Type_ISO && sr.Physical() && sr.GetStorageHost() == Affinity).ToList();
if (dvdSRs.Count > 0 && dvdSRs[0].VDIs.Count > 0)
return Affinity.Connection.Resolve(dvdSRs[0].VDIs[0]);
return null;
}
public InstallMethod SelectedInstallMethod
{
get
{
if (!ShowInstallationMedia || m_template.DefaultTemplate() && String.IsNullOrEmpty(m_template.InstallMethods()))
return InstallMethod.None;
if (CdRadioButton.Checked)
return InstallMethod.CD;
if (UrlRadioButton.Checked)
return InstallMethod.Network;
return InstallMethod.None;
}
}
public string SelectedPvArgs
{
get
{
return !IsSelectedTemplateHVM ? PvBootTextBox.Text : string.Empty;
}
}
public VDI SelectedCD
{
get
{
return ShowInstallationMedia && CdRadioButton.Checked ? CdDropDownBox.SelectedCD : null;
}
}
public string SelectedUrl
{
get
{
return ShowInstallationMedia && UrlRadioButton.Checked ? UrlTextBox.Text : string.Empty;
}
}
public VM SelectedTemplate { private get; set; }
public override bool EnableNext()
{
return ShowInstallationMedia ? CdRadioButton.Checked || UrlRadioButton.Checked : true;
}
public override string Text
{
get { return Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_NAME; }
}
public override string PageTitle
{
get { return Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_TITLE; }
}
public override string HelpID
{
get { return "InstallationMedia"; }
}
public override List<KeyValuePair<string, string>> PageSummary
{
get
{
List<KeyValuePair<string, string>> sum = new List<KeyValuePair<string, string>>();
switch (SelectedInstallMethod)
{
case InstallMethod.CD:
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_INSTALLMETHOD, Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_CD));
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_CDMEDIAPAGE_INSTALLATIONSOURCE, SelectedCD != null ? SelectedCD.Name() : Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_NONE));
break;
case InstallMethod.Network:
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_INSTALLMETHOD, Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_NETWORK));
sum.Add(new KeyValuePair<string, string>(Messages.NEWVMWIZARD_NETWORKMEDIAPAGE_INSTALLATIONURL, SelectedUrl));
break;
}
if (Helpers.NaplesOrGreater(SelectedTemplate.Connection) && IsSelectedTemplateHVM)
sum.Add(new KeyValuePair<string, string>(Messages.BOOT_MODE, SelectedBootMode.StringOf()));
return sum;
}
}
private void UpdateEnablement()
{
CdDropDownBox.Enabled = CdRadioButton.Checked;
UrlTextBox.Enabled = UrlRadioButton.Checked;
OnPageUpdated();
}
private void PhysicalRadioButton_CheckedChanged(object sender, EventArgs e)
{
UpdateEnablement();
}
private void UrlRadioButton_CheckedChanged(object sender, EventArgs e)
{
UpdateEnablement();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
NewSRWizard wizard = new NewSRWizard(Connection);
wizard.CheckNFSISORadioButton();
if (wizard.ShowDialog() == DialogResult.Cancel)
return;
// Return if we lost connection
if (Connection == null || Helpers.GetPoolOfOne(Connection) == null)
{
log.Error("Page_InstallationMedia: connection to the server was lost");
return;
}
// There's a chance the cd radio button was disabled because we didnt have any isos to select from, so refresh that bool
// and the enablement of that button.
cds = Helpers.CDsExist(Connection);
CdRadioButton.Enabled = (installed || installCd) && cds;
// We can get a lot of refresh flickering in the ISO box as all the VDIs are discovered
// Possibly slightly rude, but were going to have a pretend action here which gives it some breathing space before we look for VDIs
DelegatedAsyncAction waitAction = new DelegatedAsyncAction(Connection, Messages.SR_REFRESH_ACTION_DESC, Messages.SR_REFRESH_ACTION_DESC, Messages.COMPLETED,
delegate
{
System.Threading.Thread.Sleep(10000);
}, true);
using (var dlg = new ActionProgressDialog(waitAction, System.Windows.Forms.ProgressBarStyle.Marquee))
dlg.ShowDialog(this);
// Set the connection on the drop down iso box. This causes a complete refresh rather than a mini one - otherwise we miss out on
// getting event handlers for the new SR
CdDropDownBox.connection = Connection;
}
private void RegisterBespokeEventsAgainstCdDropDownBox()
{
CdDropDownBox.DrawMode = DrawMode.OwnerDrawFixed;
CdDropDownBox.DrawItem += AddToolTipToCdDropDownBox_DrawItemEvent;
CdDropDownBox.DropDownClosed += HideToolTipOnCdDropDownBox_DropDownClosedEvent;
}
private void HideToolTipOnCdDropDownBox_DropDownClosedEvent(object sender, EventArgs e)
{
comboBoxToolTip.Hide(CdDropDownBox);
}
private void AddToolTipToCdDropDownBox_DrawItemEvent(object sender, DrawItemEventArgs e)
{
string selectedText = "";
if (e.Index != -1)
selectedText = CdDropDownBox.GetItemText(CdDropDownBox.Items[e.Index]);
Font font = (e.Index != -1 && CdDropDownBox.Items[e.Index] is ToStringWrapper<SR>) ? Program.DefaultFontBold : Program.DefaultFont;
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected &&
CdDropDownBox.DroppedDown &&
TextRenderer.MeasureText(selectedText, font).Width > CdDropDownBox.DropDownWidth)
{
comboBoxToolTip.Show(selectedText, CdDropDownBox, e.Bounds.Right, e.Bounds.Bottom);
}
else
{
HideToolTipOnCdDropDownBox_DropDownClosedEvent(sender, e);
}
}
}
}