/* 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.Collections.ObjectModel; using System.Xml; using XenAdmin.Core; using XenAdmin.Network; using XenAPI; using System.Text.RegularExpressions; namespace XenAdmin.Actions { /// /// Performs a scan of a CSLG server for storage pools given a storage system. /// public class SrCslgStoragePoolScanAction : SrCslgScanAction { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly string _storageSystemId; private ReadOnlyCollection _cslgStoragePools; /// /// Initializes a new instance of the class. /// /// The connection. /// The hostname. /// The username. /// The password secret. /// The storage system id. public SrCslgStoragePoolScanAction(IXenConnection connection, string hostname, string username, string passwordSecret, string storageSystemId) : base(connection, hostname, username, passwordSecret) { Util.ThrowIfStringParameterNullOrEmpty(storageSystemId, "storageSystemId"); _storageSystemId = storageSystemId; } private readonly string _adapterId; public SrCslgStoragePoolScanAction(IXenConnection connection, string hostname, string username, string password, string storagesystemid, string adapterid) : base(connection, hostname, username, password) { _storageSystemId = storagesystemid; _adapterId = adapterid; } /// /// Gets the CSLG system storages. Returns null before the action has been run. /// /// The CSLG system storages. public ReadOnlyCollection CslgStoragePools { get { return _cslgStoragePools; } } private List ParseStoragePoolXml(String xml) { List output = new List(); XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); foreach (XmlNode storagePoolInfo in doc.GetElementsByTagName("csl__storagePoolInfo")) { string displayName = GetXmlNodeInnerText(storagePoolInfo, "displayName").Trim(); string storagePoolId = GetXmlNodeInnerText(storagePoolInfo, "storagePoolId").Trim(); List raidTypes = new List(); foreach (var raid in GetXmlChildNodeInnerTexts(storagePoolInfo, "provisioningOptions/supportedRaidTypes/raidType")) { raidTypes.Add(raid.Trim()); } List provisioningTypes = new List(); string parentStoragePoolId = GetXmlNodeInnerText(storagePoolInfo, "parentStoragePoolId"); foreach (string innerText in GetXmlChildNodeInnerTexts(storagePoolInfo, "provisioningOptions/supportedProvisioningTypes/provisioningType")) { var trimmedInnerText = innerText.Trim(); // CVSM-3277: bridge returns "FULL" for some versions but "THICK" is required. if (trimmedInnerText == "FULL" || trimmedInnerText == "THICK") { provisioningTypes.Add(new CslgParameter("THICK", Messages.NEWSR_CSLG_THICK_PROVISIONING)); } else if (trimmedInnerText == "THIN") { provisioningTypes.Add(new CslgParameter(trimmedInnerText, Messages.NEWSR_CSLG_THIN_PROVISIONING)); } } if (raidTypes.Count == 0) { raidTypes.Add("RAID_NONE"); } if (provisioningTypes.Count == 0) { provisioningTypes.Add(new CslgParameter(null, Messages.NEWSR_CSLG_DEFAULT_PROVISIONING)); } uint capacity = 0; uint usedSpace = 0; try { capacity = UInt32.Parse(GetXmlNodeInnerText(storagePoolInfo, "sizeInMB").Trim()); usedSpace = capacity - UInt32.Parse(GetXmlNodeInnerText(storagePoolInfo, "freeSpaceInMB").Trim()); } catch { } StorageLinkPool storageLinkPool = new StorageLinkPool(storagePoolId, displayName, parentStoragePoolId, _storageSystemId, capacity, usedSpace, (StorageLinkEnums.RaidType)Enum.Parse(typeof(StorageLinkEnums.RaidType), raidTypes[0].ToUpper()), (StorageLinkEnums.ProvisioningType)Enum.Parse(typeof(StorageLinkEnums.ProvisioningType), provisioningTypes[0].Name.ToUpper())); output.Add(new CslgStoragePool(displayName, storagePoolId, raidTypes, provisioningTypes, !string.IsNullOrEmpty(parentStoragePoolId), storageLinkPool)); } return output; } /// /// Runs this instance. /// protected override void Run() { Dictionary dconf = GetAuthenticationDeviceConfig(); dconf["storageSystemId"] = _storageSystemId; if (!string.IsNullOrEmpty(_adapterId)) dconf["adapterid"] = _adapterId; Log.DebugFormat("Attempting to find pools on {0}.", _storageSystemId); RunProbe(dconf); if (!string.IsNullOrEmpty(Result)) _cslgStoragePools = new ReadOnlyCollection(ParseStoragePoolXml(Util.GetContentsOfValueNode(Result))); } private static List GetRaidTypes(StorageLinkEnums.RaidType raidType) { List output = new List(); foreach (StorageLinkEnums.RaidType r in Enum.GetValues(typeof(StorageLinkEnums.RaidType))) { if ((raidType & r) != 0) { output.Add(r.ToString()); } } if (output.Count == 0) { output.Add("RAID_NONE"); } return output; } private static List GetProvisioningTypes(StorageLinkEnums.ProvisioningType provisioningType) { List output = new List(); if ((provisioningType & StorageLinkEnums.ProvisioningType.THICK) != 0) { output.Add(new CslgParameter("THICK", Messages.NEWSR_CSLG_THICK_PROVISIONING)); } if ((provisioningType & StorageLinkEnums.ProvisioningType.THIN) != 0) { output.Add(new CslgParameter("THIN", Messages.NEWSR_CSLG_THIN_PROVISIONING)); } return output; } } #region CslgStoragePool class /// /// Represents of storoage pool on a storage system on a CSLG server. /// public class CslgStoragePool { private readonly string _displayName; private readonly string _storagePoolId; private readonly ReadOnlyCollection _raidTypes; private readonly ReadOnlyCollection _provisioningTypes; private readonly bool _hasParent; /// /// Initializes a new instance of the class. /// /// The display name. /// The storage pool id. /// The raid types. /// The provisioning types. /// if set to true if this pool has a parent pool. public CslgStoragePool(string displayName, string storagePoolId, IEnumerable raidTypes, IEnumerable provisioningTypes, bool hasParent, StorageLinkPool storageLinkPool) { Util.ThrowIfStringParameterNullOrEmpty(displayName, "displayName"); Util.ThrowIfStringParameterNullOrEmpty(storagePoolId, "storagePoolId"); _displayName = displayName; _storagePoolId = storagePoolId; _raidTypes = new ReadOnlyCollection(new List(raidTypes)); _provisioningTypes = new ReadOnlyCollection(new List(provisioningTypes)); _hasParent = hasParent; StorageLinkPool = storageLinkPool; } public StorageLinkPool StorageLinkPool { get; private set; } /// /// Gets the available raid types for this pool. /// /// The available raid types for this pool. public ReadOnlyCollection RaidTypes { get { return _raidTypes; } } /// /// Gets the available provisioning types for this pool. /// /// The available provisioning types for this pool. public ReadOnlyCollection ProvisioningTypes { get { return _provisioningTypes; } } /// /// Gets the storage pool id. /// /// The storage pool id. public string StoragePoolId { get { return _storagePoolId; } } public override string ToString() { return _displayName; } /// /// Gets a value indicating whether this pool has a parent pool. /// /// /// true if this instance has a parent pool; otherwise, false. /// public bool HasParent { get { return _hasParent; } } } #endregion }