/* 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 bool ShowInstallationMedia { private get; set; } public bool ShowBootParameters { get { return !SelectedTemplate.IsHVM(); } } 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) * * Disable Installation method section if the custom template has no DVD drive (except debian etch template) */ PvBootBox.Visible = ShowBootParameters; PvBootTextBox.Text = m_template.PV_args; 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(); } 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(cddrive.VDI) : (CdDropDownBox.Empty ? null : GetAffinityDvdDrive()); if (cd == null) return; // select default whatever that is SR sr = Connection.Resolve(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 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 ShowBootParameters ? 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> PageSummary { get { List> sum = new List>(); switch (SelectedInstallMethod) { case InstallMethod.CD: sum.Add(new KeyValuePair(Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_INSTALLMETHOD, Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_CD)); sum.Add(new KeyValuePair(Messages.NEWVMWIZARD_CDMEDIAPAGE_INSTALLATIONSOURCE, SelectedCD != null ? SelectedCD.Name() : Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_NONE)); break; case InstallMethod.Network: sum.Add(new KeyValuePair(Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_INSTALLMETHOD, Messages.NEWVMWIZARD_INSTALLATIONMEDIAPAGE_NETWORK)); sum.Add(new KeyValuePair(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); 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) ? 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); } } } }