/* 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.Threading; using XenAPI; using XenAdmin.Core; namespace XenAdmin.Actions.GUIActions { /// /// A "meddling" Action is one being performed by someone else -- in other words, they are ones that we've inferred by the /// presence of task instances on the pool. /// public class MeddlingAction : CancellingAction { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public MeddlingAction(Task task) : base(task.MeddlingActionTitle ?? task.Title, task.Description, false, false) { RelatedTask = new XenRef(task.opaque_ref); this.Host = task.Connection.Resolve(task.resident_on); if (this.Host == null) this.Host = Helpers.GetMaster(task.Connection); Started = (task.created + task.Connection.ServerTimeOffset).ToLocalTime(); SetAppliesToData(task); VM = VMFromAppliesTo(task); Connection = task.Connection; Update(task, false); } public void Update(Task task, bool deleting) { ThreadPool.QueueUserWorkItem(delegate { if (!deleting) { RecomputeCanCancel(); } if (task == null || IsCompleted) return; log.DebugFormat("Updating task {0} : {1} - {2}", task.opaque_ref, task.created, task.finished); int percentComplete = task.progress < 0 ? 0 : (int) (100.0*task.progress); if (PercentComplete < percentComplete) PercentComplete = percentComplete; SetFatalErrorData(task); DetermineIfTaskIsComplete(task, deleting); if (IsCompleted) Description = Messages.COMPLETED; DestroyUnwantedOperations(task); if (deleting) LogoutCancelSession(); }); } private void DetermineIfTaskIsComplete(Task task, bool deleting) { if (task.finished.Year > 1970) { DateTime t = task.finished + task.Connection.ServerTimeOffset; Finished = t.ToLocalTime(); IsCompleted = true; } else if (deleting) { Finished = DateTime.Now; IsCompleted = true; } else { StartedRunning = true; } } private void SetFatalErrorData(Task task) { string[] err = task.error_info; if (err != null && err.Length > 0) Exception = new Failure(err); else if (task.status == task_status_type.cancelled) Exception = new CancelledException(); } private void SetAppliesToData(Task task) { List applies_to = task.AppliesTo; if (applies_to != null) { AppliesTo.AddRange(applies_to); Description = task.Name; } else { // A non-aware client has created this task. We'll create a new action for this, and place it under // the task.resident_on host, or if that doesn't resolve, the pool master. Host host = task.Connection.Resolve(task.resident_on) ?? Helpers.GetMaster(task.Connection); if (host != null) AppliesTo.Add(host.opaque_ref); } } private VM VMFromAppliesTo(Task task) { foreach (string r in AppliesTo) { VM vm = task.Connection.Resolve(new XenRef(r)); if (vm != null) return vm; } return null; } private void DestroyUnwantedOperations(Task task) { string[] err = task.error_info; if (task.Name == "SR.create" && err != null && err.Length > 0 && err[0] == Failure.SR_BACKEND_FAILURE_107) { // This isn't an SR create at all, it is a scan for LUNs. Hide it, since the 'error' info contains loads of XML, // and is not useful. We don't know this until the error occurs though. Destroy the MeddlingAction. task.PropertyChanged -= MeddlingActionManager.Task_PropertyChanged; ConnectionsManager.History.Remove(this); } } } }