/// <summary> /// Internal constructor which accept broker as connection /// </summary> internal AsyncAzureOperation(AzureManagementBroker broker, string operationId, bool completed) { this.completed = completed; // We really only need the client from broker this.client = new AzureManagementClient(broker.certificate, broker.subscriptionId); this.status = AzureOperationStatus.InProgress; this.errorCode = null; this.errorMessage = null; this.operationId = operationId; }
/// <summary> /// Get all the azure accepted locations /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <returns></returns> public static List<string> GetAzureLocations(Guid subscriptionId, string thumbprint) { // Query Azure for locations AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2010-04-01", "locations"); // Create collection to return List<string> locations = new List<string>(); XmlNodeList nodes = response.GetXmlNodes("Location"); //locations like "Anywhere US", "Anywhere Europe" and "Anywhere Asia" are filtered out foreach (XmlNode node in nodes) { string location = response.GetXmlValue(node, "Name"); if (!location.StartsWith("Anywhere")) { locations.Add(response.GetXmlValue(node, "Name")); } } return locations; }
/// <summary> /// Get the list of affinity groups for specified subscription id /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <returns></returns> public static List<AzureAffinityGroup> GetAffinityGroups(Guid subscriptionId, string thumbprint) { // Query Azure for affinity group list AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2009-10-01", "affinitygroups"); // Create collection to return List<AzureAffinityGroup> groups = new List<AzureAffinityGroup>(); XmlNodeList nodes = response.GetXmlNodes("AffinityGroup"); // If there is no group in the result, return an empty collection if (nodes != null) { foreach (XmlNode node in nodes) { AzureAffinityGroup group = new AzureAffinityGroup(); // Right now, we only care about name and location group.Name = response.GetXmlValue(node, "Name"); group.Location = response.GetXmlValue(node, "Location"); groups.Add(group); } } return groups; }
/// <summary> /// Creates a hosted service for the given subscription /// </summary> /// <param name="name"></param> /// <param name="description"></param> /// <param name="label"></param> /// <param name="location"></param> /// <returns></returns> private IAsyncAzureOperation CreateHostedService(string name, string description, string label, string location) { string request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<CreateHostedService xmlns=\"http://schemas.microsoft.com/windowsazure\">" + "<ServiceName>{0}</ServiceName>" + "<Label>{1}</Label>" + "<Description>{2}</Description>" + "<Location>{3}</Location>" + //"<AffinityGroup></AffinityGroup>" + "</CreateHostedService>"; request = string.Format( request, name, Utility.Base64EncodeString(label), description, location ); AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.POST, request, "2010-10-28", "services/hostedservices" ); string operationId = response.OperationId; AsyncAzureOperation op = new AsyncAzureOperation(this, operationId, false); return op; }
/// <summary> /// Adds a certificate to the Azure certificate store /// </summary> private IAsyncAzureOperation AddCertificateToAzureStore(X509Certificate2 certificate, string password) { AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response; IEnumerable<X509Certificate2> currentCerts = this.EnumerateServiceCertificates(CertificateLocation.AzureManagement); foreach (X509Certificate2 existingCert in currentCerts) { if (existingCert.Thumbprint == certificate.Thumbprint && existingCert.Thumbprint != null && existingCert.GetCertHashString() == certificate.GetCertHashString()) { return new AsyncAzureOperation(this, string.Empty, true); } // If the certificate does not match, but has a matching name we should delete it if (string.Equals(existingCert.SubjectName.Name, certificate.SubjectName.Name)) { // Delete the certificate using Azure APIs response = client.SubmitRequest( RequestType.DELETE, "2009-10-01", "services/hostedservices/{0}/certificates/SHA1-{1}", this.serviceName, existingCert.Thumbprint ); IAsyncAzureOperation op = new AsyncAzureOperation(this, response.OperationId, false); op.WaitForCompletion(TimeSpan.FromSeconds(30)); } } string request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<CertificateFile xmlns=\"http://schemas.microsoft.com/windowsazure\">" + "<Data>{0}</Data>" + "<CertificateFormat>pfx</CertificateFormat>" + "<Password>{1}</Password>" + "</CertificateFile>"; byte[] content = certificate.Export(X509ContentType.Pfx, password); request = string.Format(request, Convert.ToBase64String(content), System.Security.SecurityElement.Escape(password)); response = client.SubmitRequestWithBody( RequestType.POST, request, "2009-10-01", "services/hostedservices/{0}/certificates", this.serviceName ); return new AsyncAzureOperation(this, response.OperationId, false); }
/// <summary> /// check whether a storage account with a different locaiton exists /// </summary> /// <param name="location"></param> /// <returns></returns> public string GetStorageAccountLocation(string storageAccountName) { try { AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.GET, null, "2009-10-01", "services/storageservices/{0}", storageAccountName ); XmlNode node = response.GetXmlNode("StorageServiceProperties"); return response.GetXmlValue(node, "Location"); ; } catch (AzureManagementException) { return null; // Storage Account does not exist } }
/// <summary> /// Return the primary access key of a storage account /// </summary> /// <returns>the associated primary key of a storage account</returns> private string GetStorageAccountPrimaryKey(string storageAccount) { AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.GET, null, "2009-10-01", "services/storageservices/" + storageAccount + "/keys" ); XmlNode node = response.GetXmlNode("StorageServiceKeys"); string accountName = String.Empty; accountName = response.GetXmlValue(node, "Primary"); return accountName; }
/// <summary> /// Get Azure VM image name/location list /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <returns></returns> /// <summary> public static List<AzureImage> GetVMImagesInfo(Guid subscriptionId, string thumbprint) { // Query Azure for VM image list AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2010-04-01", "machineimages"); // Create collection to return List<AzureImage> images = new List<AzureImage>(); // If there is no image in the result, return an empty collection XmlNodeList nodes = response.GetXmlNodes("MachineImage"); if (nodes != null) { foreach (XmlNode node in nodes) { AzureImage image = new AzureImage(); image.Name = response.GetXmlValue(node, "Name"); image.Location = response.GetXmlValue(node, "Location"); image.Uuid = new Guid(response.GetXmlValue(node, "Uuid")); image.LastModified = DateTime.Parse(response.GetXmlValue(node, "Timestamp")).ToUniversalTime(); image.ParentUuid = response.GetXmlValue(node, "ParentUuid"); image.Status = response.GetXmlValue(node, "Status"); images.Add(image); } } return images; }
/// <summary> /// Create Firewall Rule on SQL Azure server to allow access from the specified range of addresses /// </summary> /// <param name="server"></param> /// <param name="ruleName"></param> /// <param name="startAddresss"></param> /// <param name="endAddress"></param> public void CreateFirewallRule(string server, string ruleName, String startAddress, String endAddress) { // Query SQL Azure for server info AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); string request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<FirewallRule " + "xmlns=\"http://schemas.microsoft.com/sqlazure/2010/12/\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + "xsi:schemaLocation=\"http://schemas.microsoft.com/sqlazure/2010/12/ FirewallRule.xsd\">" + "<StartIpAddress>" + startAddress + "</StartIpAddress>" + "<EndIpAddress>" + endAddress + "</EndIpAddress>" + "</FirewallRule>"; AzureManagementResponse response = client.SubmitSQLAzureRequestWithBody( RequestType.PUT, request, "1.0", "servers/{0}/firewallrules/{1}", server, ruleName); }
/// <summary> /// Enumerates all Azure Deployments for the subscription/service /// </summary> public IEnumerable<AzureDeployment> EnumerateAzureDeployments() { // Query Azure for deployments AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2010-04-01", "services/hostedservices/{0}?embed-detail=true", this.serviceName); // Create collection to return List<AzureDeployment> deployments = new List<AzureDeployment>(); // If there is no deployment node in the result, return an empty collection XmlNode xmlDeployments = response.GetXmlNode("Deployments"); if (xmlDeployments == null) { return deployments; } // Populate our collection of deployments foreach (XmlNode xmlDeployment in xmlDeployments.ChildNodes) { AzureDeployment dep = new AzureDeployment(); // Get the deployment ID; string guidStr = response.GetXmlValue(xmlDeployment, "PrivateID"); dep.Id = new Guid(guidStr); // Get all the other deployment properties dep.Name = response.GetXmlValue(xmlDeployment, "Name"); string status = response.GetXmlValue(xmlDeployment, "Status"); dep.Status = AzureDeploymentState.Unknown; try { dep.Status = (AzureDeploymentState)Enum.Parse(typeof(AzureDeploymentState), status, true); } catch (Exception) { } dep.Label = response.GetXmlValue(xmlDeployment, "Label"); dep.Url = response.GetXmlValue(xmlDeployment, "Url"); dep.Configuration = response.GetXmlValue(xmlDeployment, "Configuration"); List<string> roles = new List<string>(); XmlNode roleList = response.GetXmlNode(xmlDeployment, "RoleList"); if (roleList != null) foreach (XmlNode role in roleList.ChildNodes) { roles.Add(response.GetXmlValue(role, "RoleName")); } dep.roles = roles; // Add to the collection deployments.Add(dep); } return deployments; }
/// <summary> /// Creates a SQL Azure server /// </summary> public string CreateAzureSQLServer(AzureSQLServer config) { string serverName = null; // Create a SQL Azure create server request from this template string azureRequest = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<Server xmlns=\"http://schemas.microsoft.com/sqlazure/2010/12/\">\r\n" + "<AdministratorLogin>{0}</AdministratorLogin>\r\n" + "<AdministratorLoginPassword>{1}</AdministratorLoginPassword>\r\n" + "<Location>{2}</Location>\r\n" + "</Server>"; // Fill in the request template azureRequest = string.Format( azureRequest, config.AdministratorLogin, config.AdministratorLoginPassword, config.Location ); // Submit the request AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitSQLAzureRequestWithBody( RequestType.POST, azureRequest, "1.0", "servers" ); XmlNode xml = response.GetSQLXmlNode("ServerName"); serverName = xml.InnerText; return serverName; }
/// <summary> /// Starts an azure deployment immediately after it is created /// </summary> public IAsyncAzureOperation CreateAzureDeployment(string configXml, string packageFileName, out AzureDeployment deployment) { // Initialize the return deployment struct deployment = new AzureDeployment(); // Start generating an Azure deployment request from this template string azureRequest = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + "<CreateDeployment xmlns=\"http://schemas.microsoft.com/windowsazure\">\r\n" + "<Name>{0}</Name>\r\n" + "<PackageUrl>{1}</PackageUrl>\r\n" + "<Label>{2}</Label>\r\n" + "<Configuration>{3}</Configuration>\r\n" + "<StartDeployment>true</StartDeployment>\r\n" + "</CreateDeployment>"; // Generate the URL of the HPC runtime package string blobUrl = string.Format( "https://{0}.{1}/{2}/{3}", this.storageServiceName, AzureNaming.AzureBlobStorageDomain, AzureNaming.GenerateAzureEntityName("HpcRuntime", this.clusterName, this.subscriptionId, this.serviceName), packageFileName ); // Generate a name for the deployment string deploymentName = AzureNaming.GenerateAzureEntityName("HpcDeployment", this.clusterName, this.subscriptionId, this.serviceName); // Generate a label string label = string.Format( "Deployment for Windows Azure HPC Scheduler: {0}", this.clusterName); label = Utility.Base64EncodeString(label); if (label.Length > 100) { label = label.Substring(0, 100); } // Fill in the request template azureRequest = string.Format( azureRequest, deploymentName, blobUrl, label, Utility.Base64EncodeString(configXml) ); // Submit the request AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.POST, azureRequest, "2010-04-01", "services/hostedservices/{0}/deploymentslots/production", this.serviceName ); // Generate an Async operation to track the deployment AsyncAzureOperation op = new AsyncAzureOperation(this, response.OperationId, false); // Need to poll Azure to find detailed information about the deployment for (; ; ) { // Loop through all deployments looking for the one we created foreach (AzureDeployment deploy in this.EnumerateAzureDeployments()) { // If we find it, return it if (string.Equals(deploy.Name, deploymentName, StringComparison.InvariantCultureIgnoreCase)) { deployment = deploy; return op; } } // Abort polling if the operation has failed if (op.GetOperationStatus() == AzureOperationStatus.Failed) { break; } // Wait 2 seconds before polling next System.Threading.Thread.Sleep(2 * 1000); } return op; }
/// <summary> /// Change Azure deployment state between the suspended and running states /// </summary> public IAsyncAzureOperation ChangeAzureDeploymentState(string deploymentName, out AzureDeployment deployment, AzureDeploymentState state) { string request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<UpdateDeploymentStatus xmlns=\"http://schemas.microsoft.com/windowsazure\">" + "<Status>{0}</Status>" + "</UpdateDeploymentStatus>"; request = string.Format(request, state.ToString()); AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.POST, request, "2009-10-01", "services/hostedservices/{0}/deployments/{1}/?comp=status", this.serviceName, deploymentName ); string operationId = response.OperationId; AsyncAzureOperation op = new AsyncAzureOperation(this, operationId, false); deployment = this.QueryAzureDeployment(deploymentName); return op; }
/// <summary> /// Get the location for specified service, if not location information, return the affinity group /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <param name="serviceName"></param> /// <param name="affinityGroup"></param> /// <returns></returns> public static string GetServiceLocation(Guid subscriptionId, string thumbprint, string serviceName, out string affinityGroup) { AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2009-10-01", "services/hostedservices/{0}", serviceName ); XmlNode node = response.GetXmlNode("HostedServiceProperties"); affinityGroup = response.GetXmlValue(node, "AffinityGroup"); return response.GetXmlValue(node, "Location"); }
/// <summary> /// Queries for all SQL Azure servers bound to the associated Subscription at specific location /// </summary> public IEnumerable<AzureSQLServer> EnumerateAzureSQLServers(string serverLocation) { // Query SQL Azure for server info AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitSQLAzureRequest( RequestType.GET, "1.0", "servers"); // Create collection to return List<AzureSQLServer> servers = new List<AzureSQLServer>(); // If there is no servers node in the result, return an empty collection XmlNode xmlServers = response.GetSQLXmlNode("Servers"); if (xmlServers == null) { return servers; } // Populate our collection of servers foreach (XmlNode xmlServer in xmlServers.ChildNodes) { AzureSQLServer srv = new AzureSQLServer(); // Get the server properties srv.Name = response.GetSQLXmlValue(xmlServer, "Name"); srv.AdministratorLogin = response.GetSQLXmlValue(xmlServer, "AdministratorLogin"); srv.Location = response.GetSQLXmlValue(xmlServer, "Location"); // if the SQL server is at "serverLocation" if (srv.Location.CompareTo(serverLocation) == 0) { // Add to the collection servers.Add(srv); } } return servers; }
/// <summary> /// Get Azure storage account name list /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <returns></returns> public static List<string> GetStorageAccountNames(Guid subscriptionId, string thumbprint) { AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2009-10-01", "services/storageservices" ); XmlNodeList nodes = response.GetXmlNodes("StorageService"); List<string> names = new List<string>(); foreach (XmlNode node in nodes) { names.Add(response.GetXmlValue(node, "ServiceName")); } return names; }
/// <summary> /// Enumerates all certificates associated with this service account from a specific location /// -- Either the service certificate container in Azure blob storage, or the Azure Certificate store /// </summary> public IEnumerable<X509Certificate2> EnumerateServiceCertificates(CertificateLocation location) { List<X509Certificate2> certs = new List<X509Certificate2>(); if (location == CertificateLocation.AzureManagement) { // Submit the Azure request AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2009-10-01", "services/hostedservices/{0}/certificates", this.serviceName ); XmlNode certXml = response.GetXmlNode("Certificates"); if (certXml == null) { return certs; } foreach (XmlNode certificate in certXml.ChildNodes) { string certData = response.GetXmlValue(certificate, "Data"); byte[] certBytes = Convert.FromBase64String(certData); certs.Add(new X509Certificate2(certBytes)); } } else // Blob storage { CloudBlobClient blobClient; CloudTableClient tableClient; CloudQueueClient queueClient; this.GetStorageClients(out tableClient, out queueClient, out blobClient); string certContainer = AzureNaming.GenerateAzureEntityName("HpcAzureCertificates", this.clusterName, this.subscriptionId, this.serviceName); CloudBlobContainer certBlob = blobClient.GetContainerReference(certContainer); try { foreach (IListBlobItem item in certBlob.ListBlobs()) { try { CloudBlockBlob blob = certBlob.GetBlockBlobReference(item.Uri.ToString()); X509Certificate2 cert = new X509Certificate2(blob.DownloadByteArray()); certs.Add(cert); } catch (Exception) { continue; } } } catch (Exception) { return certs; } } return certs; }
/// <summary> /// Really worker function to validate the user input azure information /// </summary> /// <param name="subscriptionId"></param> /// <param name="thumbprint"></param> /// <param name="serviceName"></param> /// <param name="storageName"></param> private static object[] ValidateAzureAccount(ValidationAsyncContext context, Guid subscriptionId, string thumbprint) { IList<string> services = null; IList<string> storages = null; IList<AzureImage> vmImages = null; // Use to store the log for validation StringBuilder log = new StringBuilder(); // This dictionary store the validation result // If the item through the validation, an item will be added to this dictionary, and true/false indicate the pass/fail. IDictionary<ValidateItem, bool> result = new Dictionary<ValidateItem, bool>(); // This varaible is used for exception to set failed item ValidateItem currentItem = ValidateItem.Certificate; // If external user cancel this action, just exit this function if (context.IsCancelling) return null; try { log.AppendLine("Validating Thumbprint"); // Here will validate the certificate AzureManagementClient client = new AzureManagementClient(thumbprint, subscriptionId); result.Add(ValidateItem.Certificate, true); // If external user cancel this action, just exit this function if (context.IsCancelling) return null; log.AppendLine("Validating Subscription ID"); currentItem = ValidateItem.SubscriptionId; // Here will validate the subscription AzureManagementResponse response = client.SubmitRequest( RequestType.GET, "2009-10-01", "services/hostedservices" ); result.Add(ValidateItem.SubscriptionId, true); log.AppendLine("Retrieving Service Name"); currentItem = ValidateItem.ServiceName; services = new List<string>(); // We will return all service name, so we don't need to validate in here XmlNodeList nodes = response.GetXmlNodes("HostedService"); foreach (XmlNode node in nodes) { services.Add(response.GetXmlValue(node, "ServiceName")); } // If external user cancel this action, just exit this function if (context.IsCancelling) return null; log.AppendLine("Retrieving Storage Account Name"); currentItem = ValidateItem.StorageAccountName; // We will return all storage name, so we don't need to validate in here response = client.SubmitRequest( RequestType.GET, "2009-10-01", "services/storageservices" ); storages = new List<string>(); nodes = response.GetXmlNodes("StorageService"); foreach (XmlNode node in nodes) { storages.Add(response.GetXmlValue(node, "ServiceName")); } // If external user cancel this action, just exit this function if (context.IsCancelling) return null; log.AppendLine("Retrieving Virtual Machine Image Name"); currentItem = ValidateItem.VMImageName; // Query Azure for VM image list response = client.SubmitRequest( RequestType.GET, "2010-04-01", "machineimages"); vmImages = new List<AzureImage>(); nodes = response.GetXmlNodes("MachineImage"); foreach (XmlNode node in nodes) { AzureImage image = new AzureImage(); image.Name = response.GetXmlValue(node, "Name"); image.Location = response.GetXmlValue(node, "Location"); image.Uuid = new Guid(response.GetXmlValue(node, "Uuid")); image.LastModified = DateTime.Parse(response.GetXmlValue(node, "Timestamp")).ToUniversalTime(); image.ParentUuid = response.GetXmlValue(node, "ParentUuid"); image.Status = response.GetXmlValue(node, "Status"); vmImages.Add(image); } } catch (Exception e) { log.AppendLine(e.Message); result.Add(currentItem, false); return new object[] { log.ToString(), result, services, storages, vmImages }; } // If there is no issue, we don't need return any information return new object[] { null, result, services, storages, vmImages }; }
/// <summary> /// Enumerates all the hosted services on the subscription by name /// </summary> /// <returns></returns> private IEnumerable<string> GetHostedServiceNames() { AzureManagementClient client = new AzureManagementClient(this.certificate, this.subscriptionId); AzureManagementResponse response = client.SubmitRequestWithBody( RequestType.GET, null, "2009-10-01", "services/hostedservices" ); XmlNode node = response.GetXmlNode("HostedServices"); List<string> accountNames = new List<string>(); foreach (XmlNode child in node.ChildNodes) { accountNames.Add(response.GetXmlValue(child, "ServiceName")); } return accountNames; }