#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
}
}