#region License Information /* HeuristicLab * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading; using System.Xml.Linq; using HeuristicLab.Clients.Hive.CloudManager.Model; namespace HeuristicLab.Clients.Hive.CloudManager.Azure { public static class ServiceManagementOperation { #region Namespaces private static XNamespace wa = Constants.NSWindowsAzure; private static XNamespace sc = Constants.NSSchemaMicrosoft; private static XNamespace sh = Constants.NSServiceConfiguration; #endregion #region Public Methods public static Subscription GetSubscriptionInfo(string subscriptionId, string thumbprint) { string uri = string.Format(Constants.URISubscriptionFormat, subscriptionId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); Subscription subscription = new Subscription(); subscription.SubscriptionID = response.Descendants(wa + "SubscriptionID").Single().Value; subscription.SubscriptionName = response.Descendants(wa + "SubscriptionName").Single().Value; subscription.SubscriptionStatus = response.Descendants(wa + "SubscriptionStatus").Single().Value; subscription.MaxCoreCount = Convert.ToInt32(response.Descendants(wa + "MaxCoreCount").Single().Value); subscription.MaxHostedServices = Convert.ToInt32(response.Descendants(wa + "MaxHostedServices").Single().Value); subscription.MaxStorageAccounts = Convert.ToInt32(response.Descendants(wa + "MaxStorageAccounts").Single().Value); subscription.CurrentCoreCount = Convert.ToInt32(response.Descendants(wa + "CurrentCoreCount").Single().Value); subscription.CurrentHostedServices = Convert.ToInt32(response.Descendants(wa + "CurrentHostedServices").Single().Value); subscription.CurrentStorageAccounts = Convert.ToInt32(response.Descendants(wa + "CurrentStorageAccounts").Single().Value); subscription.CertificateThumbprint = thumbprint; return subscription; } public static List ListLocations(string subscriptionId, string thumbprint) { string uri = string.Format(Constants.URILocationsFormat, subscriptionId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); List result = null; if (response.Root.HasElements) { result = (from s in response.Descendants(wa + "Name") select s.Value).ToList(); } return result; } public static List ListAffinityGroups(string subscriptionId, string thumbprint) { string uri = String.Format(Constants.URIAffinityGroupFormat, subscriptionId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); List result = null; if (response.Root.HasElements) { result = (from s in response.Elements() select new AffinityGroup() { Name = s.Descendants(wa + "Name").Single().Value, Label = Utils.ConvertFromBase64String(s.Descendants(wa + "Label").Single().Value), Description = s.Descendants(wa + "Description").Single().Value, Location = s.Descendants(wa + "Location").Single().Value }).ToList(); } return result; } public static List ListHostedServices(string subscriptionId, string thumbprint) { string uri = String.Format(Constants.URIHostedServiceFormat, subscriptionId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); List result = null; if (response.Root.HasElements) { result = (from s in response.Elements() select new HostedService() { ServiceName = s.Descendants(wa + "ServiceName").Single().Value, Url = s.Descendants(wa + "Url").Single().Value }).ToList(); } if (result != null) return result; else return new List(); } public static List ListStorageServices(string subscriptionId, string thumbprint) { string uri = string.Format(Constants.URIStorageServiceFormat, subscriptionId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); List result = null; if (response.Root.HasElements) { result = (from s in response.Elements() select new StorageService() { Url = s.Descendants(wa + "Url").Single().Value, ServiceName = s.Descendants(wa + "ServiceName").Single().Value }).ToList(); } if (result != null) return result; else return new List(); } public static HostedService GetHostedService(string subscriptionId, string thumbprint, string serviceName) { string uri = String.Format(Constants.URISpecificHostedServiceFormat, subscriptionId, serviceName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); HostedService service = new HostedService(); service.ServiceName = response.Descendants(wa + "ServiceName").Single().Value; service.Url = response.Descendants(wa + "Url").Single().Value; return service; } public static HostedService GetHostedServiceDetailed(string subscriptionId, string thumbprint, string serviceName) { string uri = String.Format(Constants.URISpecificHostedServiceFormat + "?embed-detail=true", subscriptionId, serviceName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); HostedService service = new HostedService(); service.ServiceName = response.Descendants(wa + "ServiceName").Single().Value; service.Url = response.Descendants(wa + "Url").First().Value; if (response.Root.Elements(wa + "HostedServiceProperties").Any()) { XElement xHostedServiceProperties = response.Descendants(wa + "HostedServiceProperties").Single(); string loc = string.Empty, affgroup = string.Empty; if (xHostedServiceProperties.HasElements) { string desc = xHostedServiceProperties.Descendants(wa + "Description").Single().Value; if (xHostedServiceProperties.Descendants(wa + "Location").Any()) { loc = xHostedServiceProperties.Descendants(wa + "Location").Single().Value; } else { affgroup = xHostedServiceProperties.Descendants(wa + "AffinityGroup").Single().Value; } string lbl = Utils.ConvertFromBase64String(xHostedServiceProperties.Descendants(wa + "Label").Single().Value); HostedServiceProperties props = new HostedServiceProperties() { Description = desc, Location = loc, AffinityGroup = affgroup, Label = lbl }; service.HostedServiceProperties = props; } } if (response.Root.Elements(wa + "Deployments").Any()) { XElement xDeployments = response.Descendants(wa + "Deployments").Single(); if (xDeployments.HasElements) { IEnumerable deps = (from s in xDeployments.Elements() select GetDeploymentFromXml(s)).ToList(); service.Deployments = new List(deps); } else { service.Deployments = new List(); } } return service; } public static Deployment GetDeployment(string subscriptionId, string thumbprint, string serviceName, string deploymentName) { string uri = String.Format(Constants.URISpecificDeploymentFormat, subscriptionId, serviceName, deploymentName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); Deployment deployment = GetDeploymentFromXml(response.Root); return deployment; } public static StorageServiceKeys GetStorageKeys(string subscriptionId, string thumbprint, string serviceName) { string uri = string.Format(Constants.URIStorageServiceKeys, subscriptionId, serviceName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument response = operation.Invoke(uri); StorageServiceKeys keys = new StorageServiceKeys(); keys.Primary = response.Descendants(wa + "Primary").Single().Value; keys.Secondary = response.Descendants(wa + "Secondary").Single().Value; return keys; } public static string AddCertificate(string subscriptionId, string thumbprint, string serviceName, string certificateFilePath, string password) { string uri = String.Format(Constants.URICertificateFormat, subscriptionId, serviceName); XDocument payload = CreateAddCertificatePayload(certificateFilePath, password); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, payload); return requestId; } public static string CreateHostedServiceWithLocation(string subscriptionId, string thumbprint, string serviceName, string label, string description, string location) { return CreateHostedService(subscriptionId, thumbprint, serviceName, label, description, location, String.Empty); } public static string CreateHostedServiceWithAffinityGroup(string subscriptionId, string thumbprint, string serviceName, string label, string description, string affinityGroup) { return CreateHostedService(subscriptionId, thumbprint, serviceName, label, description, String.Empty, affinityGroup); } public static string CreateDeployment(string subscriptionId, string thumbprint, string serviceName, string deploymentName, string deploymentSlot, string packageUrl, string configuration, string label, int instanceCount) { string uri = String.Format(Constants.URIDeploymentFormat, subscriptionId, serviceName, deploymentSlot); XElement xConfig = XElement.Parse(configuration); SetInstanceCount(xConfig, Constants.HLSlaveRoleName, instanceCount); XDocument payload = CreateDeploymentPayload(deploymentName, packageUrl, xConfig, label); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, payload); return requestId; } public static string DownloadBlobAsString(Uri uri) { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri); request.Headers.Add(Constants.HeaderVersionName, Constants.APIVersion20110818); request.Method = Constants.HttpMethodGET; request.ContentType = Constants.ContentTypeAppXml; string result = string.Empty; WebResponse response = request.GetResponse(); using (StreamReader reader = new StreamReader(response.GetResponseStream())) { result = reader.ReadToEnd(); } return result; } public static List DiscoverSlaveService(string subscriptionId, string thumbprint) { List hostedServices = new List(); foreach (HostedService hostedService in ListHostedServices(subscriptionId, thumbprint)) { HostedService hs = GetHostedServiceDetailed(subscriptionId, thumbprint, hostedService.ServiceName); foreach (Deployment deployment in hs.Deployments) { if (ContainsRoleNameInConfiguration(XDocument.Parse(deployment.Configuration), Constants.HLSlaveRoleName)) { if (!hostedServices.Contains(hs)) { hostedServices.Add(hs); } } } } return hostedServices; } public static string DeleteHostedService(string subscriptionId, string thumbprint, string serviceName) { string uri = String.Format(Constants.URISpecificHostedServiceFormat, subscriptionId, serviceName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, Constants.HttpMethodDELETE); return requestId; } public static string DeleteDeployment(string subscriptionId, string thumbprint, string serviceName, string deploymentName) { string uri = string.Format(Constants.URISpecificDeploymentFormat, subscriptionId, serviceName, deploymentName); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, Constants.HttpMethodDELETE); return requestId; } public static string ChangeInstanceCount(string subscriptionId, string thumbprint, string serviceName, string deploymentSlot, string roleName, int instanceCount) { string requestId = string.Empty; XElement configuration = LoadConfiguration(subscriptionId, thumbprint, serviceName, deploymentSlot); if (instanceCount != GetInstanceCount(configuration, roleName)) { SetInstanceCount(configuration, roleName, instanceCount); requestId = SaveConfiguration(subscriptionId, thumbprint, serviceName, deploymentSlot, configuration); } return requestId; } public static string GetOperationStatusString(string subscriptionId, string thumbprint, string requestId) { string status = GetOperationStatus(subscriptionId, thumbprint, requestId).Element(wa + "Status").Value; return status; } public static XElement GetOperationStatus(string subscriptionId, string thumbprint, string requestId) { string uri = string.Format(Constants.URIGetOperationStatusFormat, subscriptionId, requestId); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument operationStatus = operation.Invoke(uri); return operationStatus.Element(wa + "Operation"); } public static Constants.OperationResult PollGetOperationStatus(string subscriptionId, string thumbprint, string requestId, int pollIntervallSeconds, int timeoutSeconds) { Constants.OperationResult result = new Constants.OperationResult(); DateTime beginPollTime = DateTime.UtcNow; TimeSpan pollInterval = new TimeSpan(0, 0, pollIntervallSeconds); DateTime endPollTime = beginPollTime + new TimeSpan(0, 0, timeoutSeconds); bool done = false; while (!done) { XElement operationStatus = GetOperationStatus(subscriptionId, thumbprint, requestId); result.RunningTime = DateTime.UtcNow - beginPollTime; try { result.Status = (Constants.OperationStatus)Enum.Parse(typeof(Constants.OperationStatus), operationStatus.Element(wa + "Status").Value); } catch (Exception ex) { throw new ApplicationException(string.Format("Get Operation Status {0} returned unexpected status: {1}{2}", requestId, Environment.NewLine, operationStatus.ToString(SaveOptions.OmitDuplicateNamespaces))); } switch (result.Status) { case Constants.OperationStatus.InProgress: Thread.Sleep((int)pollInterval.TotalMilliseconds); break; case Constants.OperationStatus.Failed: result.StatusCode = (HttpStatusCode)Convert.ToInt32(operationStatus.Element(wa + "HttpStatusCode").Value); XElement error = operationStatus.Element(wa + "Error"); result.Code = error.Element(wa + "Code").Value; result.Message = error.Element(wa + "Message").Value; done = true; break; case Constants.OperationStatus.Succeeded: result.StatusCode = (HttpStatusCode)Convert.ToInt32(operationStatus.Element(wa + "HttpStatusCode").Value); done = true; break; } if (!done && DateTime.UtcNow > endPollTime) { result.Status = Constants.OperationStatus.TimedOut; done = true; } } return result; } #endregion #region Private Methods private static int GetInstanceCount(XElement configuration, string roleName) { XElement instanceElement = (from s in configuration.Elements(sh + "Role") where s.Attribute("name").Value == roleName select s.Element(sh + "Instances")).First(); int instanceCount = Convert.ToInt32(instanceElement.Attribute("count").Value); return instanceCount; } private static void SetInstanceCount(XElement configuration, string roleName, int value) { XElement instanceElement = (from s in configuration.Elements(sh + "Role") where s.Attribute("name").Value == roleName select s.Element(sh + "Instances")).First(); instanceElement.SetAttributeValue("count", value); } private static string CreateHostedService(string subscriptionId, string thumbprint, string serviceName, string label, string description, string location, string affinityGroup) { string uri = string.Format(Constants.URIHostedServiceFormat, subscriptionId); XDocument payload = CreateHostedServicePayload(serviceName, label, description, location, affinityGroup); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, payload); return requestId; } private static XDocument CreateHostedServicePayload(string serviceName, string label, string description, string location, string affinityGroup) { string base64LabelName = Utils.ConvertToBase64String(label); XElement xServiceName = new XElement(wa + "ServiceName", serviceName); XElement xLabel = new XElement(wa + "Label", base64LabelName); XElement xDescription = new XElement(wa + "Description", description); XElement createHostedService = new XElement(wa + "CreateHostedService"); createHostedService.Add(xServiceName); createHostedService.Add(xLabel); createHostedService.Add(xDescription); if (location != String.Empty) { XElement xLocation = new XElement(wa + "Location", location); createHostedService.Add(xLocation); } else { XElement xAffinityGroup = new XElement(wa + "AffinityGroup", affinityGroup); createHostedService.Add(xAffinityGroup); } XDocument payload = new XDocument(); payload.Add(createHostedService); payload.Declaration = new XDeclaration("1.0", "UTF-8", "no"); return payload; } private static XDocument CreateAddCertificatePayload(string certificateFilePath, string password) { XElement xData = new XElement(wa + "Data", Convert.ToBase64String(File.ReadAllBytes(certificateFilePath))); XElement xCertificateFormat = new XElement(wa + "CertificateFormat", "pfx"); XElement xPassword = new XElement(wa + "Password", password); XElement addcert = new XElement(wa + "CertificateFile"); addcert.Add(xData); addcert.Add(xCertificateFormat); addcert.Add(xPassword); XDocument payload = new XDocument(); payload.Add(addcert); payload.Declaration = new XDeclaration("1.0", "UTF-8", "no"); return payload; } private static XDocument CreateDeploymentPayload(string deploymentName, string packageUrl, string pathToConfigurationFile, string label) { string configurationFile = File.ReadAllText(pathToConfigurationFile); XElement xConfig = XElement.Parse(configurationFile); return CreateDeploymentPayload(deploymentName, packageUrl, xConfig, label); } private static XDocument CreateDeploymentPayload(string deploymentName, string packageUrl, XElement configuration, string label) { string base64ConfigurationFile = Utils.ConvertToBase64String(configuration.ToString()); string base64Label = Utils.ConvertToBase64String(label); XElement xName = new XElement(wa + "Name", deploymentName); XElement xPackageUrl = new XElement(wa + "PackageUrl", packageUrl); XElement xLabel = new XElement(wa + "Label", base64Label); XElement xConfiguration = new XElement(wa + "Configuration", base64ConfigurationFile); XElement xStartDeployment = new XElement(wa + "StartDeployment", "true"); XElement xTreatWarningsAsError = new XElement(wa + "TreatWarningsAsError", "false"); XElement createDeployment = new XElement(wa + "CreateDeployment"); createDeployment.Add(xName); createDeployment.Add(xPackageUrl); createDeployment.Add(xLabel); createDeployment.Add(xConfiguration); createDeployment.Add(xStartDeployment); createDeployment.Add(xTreatWarningsAsError); XDocument payload = new XDocument(); payload.Add(createDeployment); payload.Declaration = new XDeclaration("1.0", "UTF-8", "no"); return payload; } private static XElement LoadConfiguration(String subscriptionId, String thumbprint, String serviceName, String deploymentSlot) { string uri = string.Format(Constants.URIDeploymentFormat, subscriptionId, serviceName, deploymentSlot); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); XDocument deployment = operation.Invoke(uri); string base64Configuration = deployment.Element(wa + "Deployment").Element(wa + "Configuration").Value; string stringConfiguration = Utils.ConvertFromBase64String(base64Configuration); XElement configuration = XElement.Parse(stringConfiguration); return configuration; } private static string SaveConfiguration(String subscriptionId, String thumbprint, String serviceName, String deploymentSlot, XElement configuration) { string uri = string.Format(Constants.URIDeploymentConfigurationFormat, subscriptionId, serviceName, deploymentSlot); XDocument payload = CreateConfigurationPayload(configuration); ServiceWebRequest operation = new ServiceWebRequest(thumbprint); string requestId = operation.Invoke(uri, payload); return requestId; } private static XDocument CreateConfigurationPayload(XElement configuration) { string configurationString = configuration.ToString(); string base64Configuration = Utils.ConvertToBase64String(configurationString); XElement xConfiguration = new XElement(wa + "Configuration", base64Configuration); XElement xChangeConfiguration = new XElement(wa + "ChangeConfiguration", xConfiguration); XDocument payload = new XDocument(); payload.Add(xChangeConfiguration); payload.Declaration = new XDeclaration("1.0", "UTF-8", "no"); return payload; } private static XDocument GetConfigurationFromDeployment(string subscriptionId, string thumbprint, string serviceName, string deploymentName) { Deployment deployment = GetDeployment(subscriptionId, thumbprint, serviceName, deploymentName); XDocument config = XDocument.Parse(deployment.Configuration); return config; } private static bool ContainsRoleNameInConfiguration(XDocument configuration, string roleName) { if (configuration.Root.Name != sh + "ServiceConfiguration") throw new ArgumentException("No valid configuration", "configuration"); IEnumerable role = (from s in configuration.Root.Elements(sh + "Role") where s.Attribute("name").Value == roleName select s); return role.Count() > 0; } private static Deployment GetDeploymentFromXml(XElement xDeployment) { Deployment deployment = new Deployment(); deployment.Name = xDeployment.Descendants(wa + "Name").Single().Value; deployment.DeploymentSlot = xDeployment.Descendants(wa + "DeploymentSlot").Single().Value; deployment.PrivateID = xDeployment.Descendants(wa + "PrivateID").Single().Value; deployment.Status = xDeployment.Descendants(wa + "Status").Single().Value; deployment.Label = Utils.ConvertFromBase64String(xDeployment.Descendants(wa + "Label").Single().Value); if (xDeployment.Descendants(wa + "Url").Any()) { deployment.Url = xDeployment.Descendants(wa + "Url").Single().Value; } deployment.Configuration = Utils.ConvertFromBase64String(xDeployment.Descendants(wa + "Configuration").Single().Value); XElement xRoleInstanceList = xDeployment.Descendants(wa + "RoleInstanceList").Single(); if (xRoleInstanceList.HasElements) { IEnumerable instances = (from s in xRoleInstanceList.Elements() select new RoleInstance() { RoleName = s.Descendants(wa + "RoleName").Single().Value, InstanceName = s.Descendants(wa + "InstanceName").Single().Value, InstanceStatus = s.Descendants(wa + "InstanceStatus").Single().Value, InstanceSize = s.Descendants(wa + "InstanceSize").Single().Value, InstanceStateDetails = s.Descendants(wa + "InstanceStateDetails").Single().Value }).ToList(); deployment.RoleInstanceList = new List(instances); } if (xDeployment.Descendants(wa + "RoleList").Any()) { XElement xRoleList = xDeployment.Descendants(wa + "RoleList").Single(); if (xRoleList.HasElements) { IEnumerable roles = (from s in xRoleList.Elements() select new Role() { RoleName = s.Descendants(wa + "RoleName").Single().Value, OsVersion = s.Descendants(wa + "OsVersion").Single().Value }).ToList(); deployment.RoleList = new List(roles); } } if (xDeployment.Descendants(wa + "UpgradeDomainCount").Any()) { deployment.UpgradeDomainCount = Convert.ToInt32(xDeployment.Descendants(wa + "UpgradeDomainCount").Single().Value); } if (xDeployment.Elements("UpgradeStatus").Any()) { XElement xUpgradeStatus = xDeployment.Descendants(wa + "UpgradeStatus").Single(); if (xUpgradeStatus.HasElements) { UpgradeStatus upgradestatus = new UpgradeStatus() { UpgradeType = xUpgradeStatus.Descendants(wa + "RoleName").Single().Value, CurrentUpgradeDomain = Convert.ToInt32(xUpgradeStatus.Descendants(wa + "RoleName").Single().Value), CurrentUpgradeDomainState = xUpgradeStatus.Descendants(wa + "RoleName").Single().Value }; deployment.UpgradeStatus = upgradestatus; } } return deployment; } #endregion } }