/* 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 XenAPI; using XenAdmin.Core; namespace XenAdmin.Actions { public class UnplugPlugNetworkAction : AsyncAction { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private List PIFs; private List VIFs; private XenAPI.Network network; public UnplugPlugNetworkAction(XenAPI.Network network, bool suppressHistory) : base (network.Connection, Messages.ACTION_PIF_UNPLUG_PLUG_TITLE, Messages.ACTION_PIF_UNPLUG_PLUG_DESC, suppressHistory) { PIFs = Connection.ResolveAll(network.PIFs); PIFs.RemoveAll(delegate(PIF p) { return !p.currently_attached; }); VIFs = Connection.ResolveAll(network.VIFs); VIFs.RemoveAll(delegate(VIF v) { if (!v.currently_attached) return true; VM vm = v.Connection.Resolve(v.VM); if (vm == null || vm.power_state != vm_power_state.Running) // we only replug running VMs return true; return false; }); network.Locked = true; foreach (PIF p in PIFs) p.Locked = true; foreach (VIF v in VIFs) v.Locked = true; #region RBAC ApiMethodsToRoleCheck.Add("pif.async_unplug"); ApiMethodsToRoleCheck.Add("pif.async_plug"); ApiMethodsToRoleCheck.Add("vif.async_plug"); ApiMethodsToRoleCheck.Add("vif.async_unplug"); #endregion Pool = Helpers.GetPool(Connection); this.network = network; } protected override void Run() { // Make note of exceptions but don't let them throw, we want to carry on and try to replug // whatever we can to leave the state in a better condition Exception error = null; PercentComplete = 10; int percentStep = (int)Math.Floor(90.0d / (PIFs.Count*2 + VIFs.Count*2)); foreach (VIF v in VIFs) { try { Unplug(v); } catch (Exception e) { log.Error(e); if (error == null) error = e; } PercentComplete += percentStep; } foreach (PIF p in PIFs) { try { Unplug(p); } catch (Exception e) { log.Error(e); if (error == null) error = e; } PercentComplete += percentStep; } foreach (PIF p in PIFs) { try { Plug(p); } catch (Exception e) { log.Error(e); if (error == null) error = e; } PercentComplete += percentStep; } foreach (VIF v in VIFs) { try { Plug(v); } catch (Exception e) { log.Error(e); if (error == null) error = e; } PercentComplete += percentStep; } Tick(100, error != null ? Messages.COMPLETED_WITH_ERRORS : Messages.COMPLETED); if (error != null) { throw error; // Ideally we would like to keep the previous description, but we need to throw the error to force the history switch or red highlighting // otherwise the user thinks everything is ok. Here we've picked the first one. } } private void Unplug(PIF p) { if (!p.currently_attached) { // We will try and unplug the PIF even if it seems to be already unplugged (CA-75969) log.DebugFormat("Unplugging PIF '{0}': this PIF is not currently attached. Will try to unplug anyway", p.uuid); } PIF.unplug(Session, p.opaque_ref); } private void Plug(PIF p) { if (p.currently_attached) { // We will try and plug the PIF even if it seems to be already plugged (CA-75969) log.DebugFormat("Plugging PIF '{0}': this PIF is currently attached. Will try to plug anyway", p.uuid); } PIF.plug(Session, p.opaque_ref); } private void Unplug(VIF v) { if (!v.currently_attached) { // We will try and unplug the VIF even if it seems to be already unplugged (CA-75969) log.DebugFormat("Unplugging VIF '{0}': this VIF is not currently attached. Will try to unplug anyway", v.uuid); } VM vm = v.Connection.Resolve(v.VM); if (vm == null || vm.power_state != vm_power_state.Running) { log.DebugFormat("Ignoring VIF '{0}' for unplug as its VM is not running", v.uuid); return; } VIF.unplug(Session, v.opaque_ref); } private void Plug(VIF v) { if (v.currently_attached) { // We will try and plug the VIF even if it seems to be already plugged (CA-75969) log.DebugFormat("Plugging VIF '{0}': this VIF is currently attached. Will try to plug anyway", v.uuid); } VM vm = v.Connection.Resolve(v.VM); if (vm == null || vm.power_state != vm_power_state.Running) { log.DebugFormat("Ignoring VIF '{0}' for plug as its VM is not running", v.uuid); return; } VIF.plug(Session, v.opaque_ref); } protected override void Clean() { network.Locked = false; foreach (PIF p in PIFs) p.Locked = false; foreach (VIF v in VIFs) v.Locked = false; } } }