/* 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 System.Text; using XenAdmin; using XenAdmin.Core; using XenAdmin.Network.StorageLink; namespace XenAPI { public partial class VDI : IComparable, IEquatable { public override string Name { get { if (Connection != null) { SR sr = Connection.Resolve(this.SR); if (sr != null) { Host host = sr.GetStorageHost(); if (sr.Physical && host != null) return string.Format(Messages.CD_DRIVE, host.Name); } } return name_label; } } public override string Description { get { return name_description; } } public string VMsOfVDI { get { StringBuilder sb = new StringBuilder(); bool comma = false; foreach (VM vm in this.GetVMs().Where(vm => vm.Show(true))) { if (comma) sb.Append(", "); else comma = true; sb.Append(vm.is_a_snapshot ? String.Format(Messages.SNAPSHOT_BRACKETS, vm.Name) : vm.Name); } return sb.ToString(); } } public override bool Show(bool showHiddenVMs) { return (!missing && managed && (showHiddenVMs || !IsHidden)); } public override bool IsHidden { get { return BoolKey(other_config, HIDE_FROM_XENCENTER); } } public IList GetVMs() { List vms = new List(); if (this.type == vdi_type.crashdump) { foreach (Crashdump crashdump in Connection.ResolveAll(crash_dumps)) { VM vm = Connection.Resolve(crashdump.VM); if (vm != null) vms.Add(vm); } } else if (this.type == vdi_type.suspend) { foreach (VM vm in Connection.Cache.VMs) { VDI vdi = Connection.Resolve(vm.suspend_VDI); if (vdi != null && vdi.uuid == this.uuid) vms.Add(vm); } } else { foreach (VBD vbd in Connection.ResolveAll(this.VBDs)) { VM vm = Connection.Resolve(vbd.VM); if (vm != null) vms.Add(vm); } } vms.Sort(); return vms; } public string VMHint { get { if (sm_config != null && sm_config.ContainsKey("vmhint")) return sm_config["vmhint"]; else return ""; } set { if (value != VMHint) { Dictionary new_sm_config = sm_config == null ? new Dictionary() : new Dictionary(sm_config); new_sm_config["vmhint"] = value; sm_config = new_sm_config; } } } public StorageLinkVolume StorageLinkVolume(IEnumerable connections) { string svid; if (sm_config.TryGetValue("SVID", out svid) && !string.IsNullOrEmpty(svid)) { foreach (StorageLinkConnection slCon in connections) { StorageLinkVolume volume = new List(slCon.Cache.StorageVolumes).Find(v => v.opaque_ref == svid); if (volume != null) { return volume; } } } return null; } public override string ToString() { return Name; } public virtual string SizeText { get { if (is_a_snapshot) return String.Empty; else return Util.DiskSizeString(virtual_size); } } public override string NameWithLocation { get { if (Connection != null) { var srOfVdi = Connection.Resolve(SR); if (srOfVdi == null) return base.NameWithLocation; return string.Format(Messages.VDI_ON_SR_TITLE, Name, srOfVdi.Name, srOfVdi.LocationString); } return base.NameWithLocation; } } #region IEquatable Members /// /// Indicates whether the current object is equal to the specified object. This calls the implementation from XenObject. /// This implementation is required for ToStringWrapper. /// public bool Equals(VDI other) { return base.Equals(other); } #endregion /// /// These are some types of VDI we care to distinguish between in the GUI. Determining what type a VDI is for XC depends on not /// just the vdi.type fields supplied by the server but some other logic. This is contained in VDI.VDIType, which returns one of /// these enums. /// public enum FriendlyType { SNAPSHOT, ISO, SYSTEM_DISK, VIRTUAL_DISK, NONE }; /// /// These are some types of VDI we care to distinguish between in the GUI. Determining what type a VDI is for XC depends on not /// just the vdi.type fields supplied by the server but some other logic. /// public FriendlyType VDIType { get { SR sr = Connection.Resolve(SR); if (sr == null) return FriendlyType.NONE; if (is_a_snapshot && GetVMs().Count >= 1) return FriendlyType.SNAPSHOT; if (sr.content_type == XenAPI.SR.Content_Type_ISO) return FriendlyType.ISO; if (type == vdi_type.system) return FriendlyType.SYSTEM_DISK; return FriendlyType.VIRTUAL_DISK; } } /// /// Is the disk of a type used by HA? /// public bool IsHaType { get { // The HA types changed in Boston if (Helpers.BostonOrGreater(Connection)) return (type == vdi_type.ha_statefile || type == vdi_type.redo_log); else return (type == vdi_type.ha_statefile || type == vdi_type.metadata); } } /// /// Is the disk currently being used by HA? /// public bool IsUsedByHA { get { return (IsHaType && Helpers.GetPoolOfOne(Connection).ha_enabled); } } /// /// Is the disk used by DR? /// public bool IsMetadataForDR { get { return Helpers.BostonOrGreater(Connection) && type == vdi_type.metadata; } } /// /// VDIs associated with storage motion are specially marked. This /// bool allows you to know if the current VDI is such. /// public bool IsAnIntermediateStorageMotionSnapshot { get { return sm_config.ContainsKey("base_mirror"); } } /// /// Try to determine if this VDI belongs to a WSS VM - this is a best guess only /// public bool CouldBeWss { get { const string wssName = "Webss-disk"; return name_label.Contains(wssName); } } public bool IsCloudConfigDrive { get { return other_config.ContainsKey("config-drive") && other_config["config-drive"].ToLower() == "true"; } } /// /// Whether read caching is enabled on this disk on a specific host /// public bool ReadCachingEnabled(Host host) { return BoolKey(sm_config, "read-caching-enabled-on-" + host.uuid); } /// /// ... and if not, why not /// public ReadCachingDisabledReasonCode ReadCachingDisabledReason(Host host) { string reasonstr; if (sm_config.TryGetValue("read-caching-reason-" + host.uuid, out reasonstr)) { ReadCachingDisabledReasonCode reason; if (Enum.TryParse(reasonstr, out reason)) return reason; } return ReadCachingDisabledReasonCode.UNKNOWN; } /// /// Possible reasons for read caching being disabled /// If there are multiple reasons, the topmost reason will be returned /// public enum ReadCachingDisabledReasonCode { UNKNOWN, // catch-all, shouldn't occur if read caching is disabled LICENSE_RESTRICTION, // self-explanatory SR_NOT_SUPPORTED, // the SR is not NFS or EXT NO_RO_IMAGE, // no part of the VDI is read-only => nothing to cache SR_OVERRIDE, // the feature has been explicitly disabled for the VDI's SR } } }