mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-20 23:46:03 +01:00
292b333078
The rest of the code is robust to there being no CDs (and e.Index = -1) apart from this bit. Signed-off-by: David Scott <dave.scott@eu.citrix.com>
361 lines
14 KiB
C#
361 lines
14 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 System.Windows.Forms;
|
|
|
|
using System.Drawing;
|
|
|
|
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 override void PageLoaded(PageLoadedDirection direction)
|
|
{
|
|
base.PageLoaded(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)
|
|
*
|
|
* Skip this page if the custom template has no DVD drive (except debian etch template)
|
|
*/
|
|
|
|
defaultTemplate = m_template.DefaultTemplate;
|
|
userTemplate = !defaultTemplate;
|
|
hvm = m_template.IsHVM;
|
|
eli = !hvm && m_template.PV_bootloader == "eliloader";
|
|
installMethods = !string.IsNullOrEmpty(m_template.InstallMethods);
|
|
installCd = installMethods && m_template.InstallMethods.Contains("cdrom") && (hvm || eli);
|
|
installUrl = (installMethods &&
|
|
(m_template.InstallMethods.Contains("http") ||
|
|
m_template.InstallMethods.Contains("ftp") ||
|
|
m_template.InstallMethods.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;
|
|
}
|
|
|
|
PvBootBox.Visible = !hvm;
|
|
PvBootTextBox.Text = m_template.PV_args;
|
|
|
|
LoadCdBox();
|
|
|
|
UpdateEnablement();
|
|
}
|
|
|
|
private bool IsBootFromNetworkCustomTemplate(bool userTemplate)
|
|
{
|
|
return (userTemplate && m_template.BootOrder.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 (this.DisableStep || 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 PvBootTextBox.Text;
|
|
}
|
|
}
|
|
|
|
public VDI SelectedCD
|
|
{
|
|
get
|
|
{
|
|
if (CdRadioButton.Checked)
|
|
return CdDropDownBox.SelectedCD;
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public string SelectedUrl
|
|
{
|
|
get
|
|
{
|
|
return UrlRadioButton.Checked ? UrlTextBox.Text : string.Empty;
|
|
}
|
|
}
|
|
|
|
public VM SelectedTemplate { private get; set; }
|
|
|
|
public override bool EnableNext()
|
|
{
|
|
return CdRadioButton.Checked || UrlRadioButton.Checked;
|
|
}
|
|
|
|
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;
|
|
}
|
|
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);
|
|
new ActionProgressDialog(waitAction, System.Windows.Forms.ProgressBarStyle.Marquee).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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|