/// <summary> /// Create a pool model from the pool cache entity /// </summary> public PoolModel(CloudPool pool) { this.Pool = pool; this.LastUpdatedTime = DateTime.UtcNow; this.ComputeNodes = new List<ComputeNodeModel>(); this.ComputeNodeCollection = CollectionViewSource.GetDefaultView(this.ComputeNodes); this.UpdateNodeView(); }
public void Pool_WhenReturnedFromServer_HasExpectedUnboundProperties() { const string cloudPoolId = "id-123"; const string osFamily = "2"; const string virtualMachineSize = "4"; const string cloudPoolDisplayName = "pool-display-name-test"; MetadataItem metadataItem = new MetadataItem("foo", "bar"); using (BatchClient client = ClientUnitTestCommon.CreateDummyClient()) { CloudPool cloudPool = client.PoolOperations.CreatePool(cloudPoolId, virtualMachineSize, new CloudServiceConfiguration(osFamily)); cloudPool.DisplayName = cloudPoolDisplayName; cloudPool.Metadata = new List <MetadataItem> { metadataItem }; Assert.Equal(cloudPoolId, cloudPool.Id); // can set an unbound object Assert.Equal(cloudPool.Metadata.First().Name, metadataItem.Name); Assert.Equal(cloudPool.Metadata.First().Value, metadataItem.Value); cloudPool.Commit(additionalBehaviors: InterceptorFactory.CreateAddPoolRequestInterceptor()); // writing isn't allowed for a cloudPool that is in an readonly state. Assert.Throws <InvalidOperationException>(() => cloudPool.AutoScaleFormula = "Foo"); Assert.Throws <InvalidOperationException>(() => cloudPool.DisplayName = "Foo"); Assert.Throws <InvalidOperationException>(() => cloudPool.CloudServiceConfiguration = null); Assert.Throws <InvalidOperationException>(() => cloudPool.ResizeTimeout = TimeSpan.FromSeconds(10)); Assert.Throws <InvalidOperationException>(() => cloudPool.Metadata = null); Assert.Throws <InvalidOperationException>(() => cloudPool.TargetDedicatedComputeNodes = 5); Assert.Throws <InvalidOperationException>(() => cloudPool.VirtualMachineConfiguration = null); Assert.Throws <InvalidOperationException>(() => cloudPool.VirtualMachineSize = "small"); //read is allowed though Assert.Null(cloudPool.AutoScaleFormula); Assert.Equal(cloudPoolDisplayName, cloudPool.DisplayName); Assert.NotNull(cloudPool.CloudServiceConfiguration); Assert.Null(cloudPool.ResizeTimeout); Assert.Equal(1, cloudPool.Metadata.Count); Assert.Null(cloudPool.TargetDedicatedComputeNodes); Assert.Null(cloudPool.VirtualMachineConfiguration); Assert.Equal(virtualMachineSize, cloudPool.VirtualMachineSize); } }
public void TestGetRemoteLoginSettings() { void test() { using BatchClient batchCli = TestUtilities.OpenBatchClient(TestUtilities.GetCredentialsFromEnvironment()); CloudPool sharedPool = poolFixture.Pool; try { // get a compute node. // get its RLS via PoolOps and via CN // Assert there are values and that the values are equal var nodes = sharedPool.ListComputeNodes().ToList(); Assert.Single(nodes); ComputeNode cn = nodes[0]; // get the RLS via each object RemoteLoginSettings rlsViaPoolOps = batchCli.PoolOperations.GetRemoteLoginSettings(sharedPool.Id, cn.Id); RemoteLoginSettings rlsViaNode = cn.GetRemoteLoginSettings(); // they must have RLS Assert.NotNull(rlsViaNode); Assert.NotNull(rlsViaPoolOps); // there must be an IP in each RLS Assert.False(string.IsNullOrWhiteSpace(rlsViaPoolOps.IPAddress)); Assert.False(string.IsNullOrWhiteSpace(rlsViaNode.IPAddress)); // the ports must match Assert.Equal(expected: rlsViaNode.Port, actual: rlsViaPoolOps.Port); } finally { // cleanup goes here } } SynchronizationContextHelper.RunTest(test, TestTimeout); }
/// <summary> /// Creates a pool. /// </summary> /// <param name="poolId"></param> /// <param name="virtualMachineSize"></param> /// <param name="targetDedicated"></param> /// <param name="autoScaleFormula"></param> /// <param name="communicationEnabled"></param> /// <param name="osFamily"></param> /// <param name="osVersion"></param> /// <param name="maxTasksPerComputeNode"></param> /// <param name="timeout"></param> /// <returns></returns> public async Task CreatePoolAsync( string poolId, string virtualMachineSize, int?targetDedicated, string autoScaleFormula, bool communicationEnabled, string osFamily, string osVersion, int maxTasksPerComputeNode, TimeSpan?timeout, StartTaskOptions startTask) { CloudPool unboundPool = this.Client.PoolOperations.CreatePool( poolId, osFamily: osFamily, virtualMachineSize: virtualMachineSize, targetDedicated: targetDedicated); unboundPool.TargetOSVersion = osVersion; unboundPool.InterComputeNodeCommunicationEnabled = communicationEnabled; unboundPool.ResizeTimeout = timeout; unboundPool.MaxTasksPerComputeNode = maxTasksPerComputeNode; if (!string.IsNullOrEmpty(autoScaleFormula)) { unboundPool.AutoScaleEnabled = true; unboundPool.AutoScaleFormula = autoScaleFormula; } if (startTask != null) { unboundPool.StartTask = new StartTask { CommandLine = startTask.CommandLine, RunElevated = startTask.RunElevated, ResourceFiles = startTask.ResourceFiles.ConvertAll(f => new ResourceFile(f.BlobSource, f.FilePath)), WaitForSuccess = true, }; } await unboundPool.CommitAsync(); }
private static async Task CreatePoolAsync(BatchClient batchClient, string poolId, int nodeCount) { Func <ImageReference, bool> imageScanner = imageRef => imageRef.Publisher.Equals("MicrosoftWindowsServer", StringComparison.InvariantCultureIgnoreCase) && imageRef.Offer.Equals("WindowsServer", StringComparison.InvariantCultureIgnoreCase) && imageRef.Sku.IndexOf("2012-R2-Datacenter", StringComparison.InvariantCultureIgnoreCase) > -1; ImageInformation imageInfo = await SampleHelpers.GetNodeAgentSkuReferenceAsync(batchClient, imageScanner); // Create and configure an unbound pool. CloudPool pool = batchClient.PoolOperations.CreatePool(poolId: poolId, virtualMachineSize: "standard_d1_v2", targetDedicatedComputeNodes: nodeCount, virtualMachineConfiguration: new VirtualMachineConfiguration( imageInfo.ImageReference, imageInfo.NodeAgentSkuId)); // Commit the pool to the Batch service await GettingStartedCommon.CreatePoolIfNotExistAsync(batchClient, pool); }
private static async Task CreatePoolAsync(BatchClient batchClient, string poolId, int nodeCount) { Func <ImageReference, bool> imageScanner = imageRef => imageRef.Publisher == "MicrosoftWindowsServer" && imageRef.Offer == "WindowsServer" && imageRef.Sku.Contains("2012-R2-Datacenter"); SampleHelpers.SkuAndImage skuAndImage = await SampleHelpers.GetNodeAgentSkuReferenceAsync(batchClient, imageScanner); // Create and configure an unbound pool. CloudPool pool = batchClient.PoolOperations.CreatePool(poolId: poolId, virtualMachineSize: "standard_d1_v2", targetDedicatedComputeNodes: nodeCount, virtualMachineConfiguration: new VirtualMachineConfiguration( skuAndImage.Image, skuAndImage.Sku.Id)); // Commit the pool to the Batch service await GettingStartedCommon.CreatePoolIfNotExistAsync(batchClient, pool); }
static CloudJob CreateJob(CloudPool pool) { var job = _BatchClient.JobOperations.GetJob(JOB_ID); if (job != null) { return(job); } job = _BatchClient.JobOperations.CreateJob(); job.Id = JOB_ID; job.PoolInformation = new PoolInformation() { PoolId = pool.Id }; job.Commit(); return(job); }
private static async Task CreateBatchPoolAsync(BatchClient batchClient, string poolId) { CloudPool pool = null; Console.WriteLine("Creating pool [{0}]...", poolId); // Create an image reference object to store the settings for the nodes to be added to the pool ImageReference imageReference = new ImageReference(publisher: "MicrosoftWindowsServer", offer: "WindowsServer", sku: "2012-R2-Datacenter-smalldisk", version: "latest"); // Use the image reference to create a VirtualMachineConfiguration object VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration(imageReference: imageReference, nodeAgentSkuId: "batch.node.windows amd64"); try { // Create an unbound pool. No pool is actually created in the Batch service until we call // CloudPool.CommitAsync(). This CloudPool instance is therefore considered "unbound," and we can // modify its properties. pool = batchClient.PoolOperations.CreatePool(poolId: poolId, targetDedicatedComputeNodes: DedicatedNodeCount, targetLowPriorityComputeNodes: LowPriorityNodeCount, virtualMachineSize: PoolVMSize, virtualMachineConfiguration: virtualMachineConfiguration); // Specify the application and version to install on the compute nodes pool.ApplicationPackageReferences = new List <ApplicationPackageReference> { new ApplicationPackageReference { ApplicationId = appPackageId, Version = appPackageVersion } }; // Create the pool await pool.CommitAsync(); } catch (BatchException be) { // Accept the specific error code PoolExists as that is expected if the pool already exists if (be.RequestInformation?.BatchError?.Code == BatchErrorCodeStrings.PoolExists) { Console.WriteLine("The pool [{0}] already existed when we tried to create it", poolId); } else { throw; // Any other exception is unexpected } } }
private static async Task PoolCreation(BatchClient p_batchClient, string p_poolId) { Console.WriteLine("Creating the pool of virtual machines"); try { ImageReference demo_image = new ImageReference( publisher: "MicrosoftWindowsServer", offer: "WindowsServer", sku: "2016-Datacenter", version: "latest"); VirtualMachineConfiguration demo_configuration = new VirtualMachineConfiguration( imageReference: demo_image, nodeAgentSkuId: "batch.node.windows amd64"); CloudPool demo_pool = null; demo_pool = p_batchClient.PoolOperations.CreatePool( poolId: p_poolId, targetDedicatedComputeNodes: 1, targetLowPriorityComputeNodes: 0, virtualMachineSize: "STANDARD_A1_v2", virtualMachineConfiguration: demo_configuration); demo_pool.ApplicationPackageReferences = new List <ApplicationPackageReference> { new ApplicationPackageReference { ApplicationId = demo_packageid, Version = demo_packageversion } }; await demo_pool.CommitAsync(); } catch (BatchException pool_error) { Console.WriteLine(pool_error.Message); } }
private static void CommonPatchPoolTest( Protocol.Models.CloudPool startEntity, Action <CloudPool> modificationFunction, Action <Protocol.Models.PoolPatchParameter> assertAction) { using (BatchClient client = ClientUnitTestCommon.CreateDummyClient()) { CloudPool pool = client.PoolOperations.GetPool( string.Empty, additionalBehaviors: InterceptorFactory.CreateGetPoolRequestInterceptor(startEntity)); modificationFunction(pool); var patchInterceptor = ShimPatchPool(assertAction); pool.CommitChanges(additionalBehaviors: new[] { patchInterceptor }); //Ensure that the job is in readable but unmodifiable state var id = pool.Id; Assert.Throws <InvalidOperationException>(() => pool.Metadata = null); } }
public void BugComputeNodeMissingStartTaskInfo_RunAfterPoolIsUsed() { void test() { using BatchClient batchCli = TestUtilities.OpenBatchClient(TestUtilities.GetCredentialsFromEnvironment()); CloudPool pool = batchCli.PoolOperations.GetPool(poolFixture.PoolId); // confirm start task info exists and has rational values foreach (ComputeNode curComputeNode in pool.ListComputeNodes()) { StartTaskInformation sti = curComputeNode.StartTaskInformation; // set when pool was created Assert.NotNull(sti); Assert.True(StartTaskState.Running == sti.State || StartTaskState.Completed == sti.State); } } SynchronizationContextHelper.RunTest(test, TestTimeout); }
/// <summary> /// Lists the pools matching the specified filter options. /// </summary> /// <param name="options">The options to use when querying for pools.</param> /// <returns>The pools matching the specified filter options.</returns> public IEnumerable <PSCloudPool> ListPools(ListPoolOptions options) { if (options == null) { throw new ArgumentNullException("options"); } // Get the single pool matching the specified id if (!string.IsNullOrWhiteSpace(options.PoolId)) { WriteVerbose(string.Format(Resources.GetPoolById, options.PoolId)); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; ODATADetailLevel getDetailLevel = new ODATADetailLevel(selectClause: options.Select, expandClause: options.Expand); CloudPool pool = poolOperations.GetPool(options.PoolId, detailLevel: getDetailLevel, additionalBehaviors: options.AdditionalBehaviors); PSCloudPool psPool = new PSCloudPool(pool); return(new PSCloudPool[] { psPool }); } // List pools using the specified filter else { string verboseLogString = null; ODATADetailLevel listDetailLevel = new ODATADetailLevel(selectClause: options.Select, expandClause: options.Expand); if (!string.IsNullOrEmpty(options.Filter)) { verboseLogString = Resources.GetPoolByOData; listDetailLevel.FilterClause = options.Filter; } else { verboseLogString = Resources.GetPoolNoFilter; } WriteVerbose(verboseLogString); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; IPagedEnumerable <CloudPool> pools = poolOperations.ListPools(listDetailLevel, options.AdditionalBehaviors); Func <CloudPool, PSCloudPool> mappingFunction = p => { return(new PSCloudPool(p)); }; return(PSPagedEnumerable <PSCloudPool, CloudPool> .CreateWithMaxCount( pools, mappingFunction, options.MaxCount, () => WriteVerbose(string.Format(Resources.MaxCount, options.MaxCount)))); } }
/// <summary> /// Creates a <see cref="CloudPool"/> with the specified id and configures its StartTask with the /// specified <see cref="ResourceFile"/> collection. /// </summary> /// <param name="batchClient">A <see cref="BatchClient"/>.</param> /// <param name="poolId">The id of the <see cref="CloudPool"/> to create.</param> /// <param name="resourceFiles">A collection of <see cref="ResourceFile"/> objects representing blobs within /// a Storage account container. The StartTask will download these files from Storage prior to execution.</param> /// <returns>A <see cref="System.Threading.Tasks.Task"/> object that represents the asynchronous operation.</returns> private static async Task CreatePoolIfNotExistAsync(BatchClient batchClient, string poolId, IList <ResourceFile> resourceFiles) { CloudPool pool = null; try { Console.WriteLine("Creating pool [{0}]...", poolId); // Create the unbound pool. Until we call CloudPool.Commit() or CommitAsync(), no pool is actually created in the // Batch service. This CloudPool instance is therefore considered "unbound," and we can modify its properties. pool = batchClient.PoolOperations.CreatePool( poolId: poolId, targetLowPriorityComputeNodes: 1, // 3 compute nodes virtualMachineSize: "small", // single-core, 1.75 GB memory, 225 GB disk cloudServiceConfiguration: new CloudServiceConfiguration(osFamily: "5")); // Windows Server 2012 R2 pool.MaxTasksPerComputeNode = 1; pool.ApplicationPackageReferences = new List <ApplicationPackageReference> { new ApplicationPackageReference { ApplicationId = "ApplicationPackage_Test_01", Version = "1.01" } }; await pool.CommitAsync(); } catch (BatchException be) { // Swallow the specific error code PoolExists since that is expected if the pool already exists if (be.RequestInformation?.BatchError != null && be.RequestInformation.BatchError.Code == BatchErrorCodeStrings.PoolExists) { Console.WriteLine("The pool {0} already existed when we tried to create it", poolId); } else { throw; // Any other exception is unexpected } } }
/// <summary> /// Vytvoření fondu výpočetních uzlů se systémem windows 2012 R2 ve službě Batch /// </summary> /// <param name="batchClient">klient pro vytvoření fondu</param> /// <param name="poolId">id fondu který chceme vytvořit</param> /// <param name="numberOfNodes">počet výpočetních uzlů pro fond</param> /// <param name="appPackageId">id balíčku aplikace</param> /// <param name="appPackageVersion">verze balíčku</param> private static async Task CreatePoolAsync(BatchClient batchClient, string poolId, int numberOfNodes, string appPackageId, string appPackageVersion) { //vytvoření fondu a poolu kde můžeme upravit vlastnosti Console.WriteLine($"Creating pool [{poolId}]..."); CloudPool unboundPool = batchClient.PoolOperations.CreatePool( poolId: poolId, virtualMachineSize: "standard_d2_v2", //virtualMachineSize: "Standard_H8", targetDedicatedComputeNodes: numberOfNodes, cloudServiceConfiguration: new CloudServiceConfiguration(osFamily: "5")); //spuštění komunikace mezi uzly pro ms-mpi unboundPool.InterComputeNodeCommunicationEnabled = true; //potřebné pro víceinstanční úlohy, aby každá část úlohy byla na jednom jádru v pc unboundPool.MaxTasksPerComputeNode = 1; // aplikace a verze která se bude spouštět v uzlech unboundPool.ApplicationPackageReferences = new List <ApplicationPackageReference> { new ApplicationPackageReference { ApplicationId = appPackageId, Version = appPackageVersion } }; //instalace ms-mpi na uzly StartTask startTask = new StartTask { CommandLine = $"cmd /c %AZ_BATCH_APP_PACKAGE_{appPackageId.ToUpper()}#{appPackageVersion}%\\MSMpiSetup.exe -unattend -force", UserIdentity = new UserIdentity(new AutoUserSpecification(elevationLevel: ElevationLevel.Admin)), WaitForSuccess = true }; unboundPool.StartTask = startTask; await unboundPool.CommitAsync(); }
private static async Task CreatePoolAsync(BatchClient batchClient, string poolId, IList <ResourceFile> resourceFiles) { // Create a Pool of Virtual Machines Console.WriteLine("Creating the Pool " + poolId); CloudPool pool = batchClient.PoolOperations.CreatePool( poolId: poolId, targetDedicatedComputeNodes: 2, // 2 Virtual Machines virtualMachineSize: "standard_d1_v2", // - https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-sizes-specs cloudServiceConfiguration: new CloudServiceConfiguration(osFamily: "6")); // - https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-guestos-update-matrix pool.StartTask = new StartTask() { CommandLine = "cmd /c (robocopy %AZ_BATCH_TASK_WORKING_DIR% %AZ_BATCH_NODE_SHARED_DIR%) " + "^& IF %ERRORLEVEL% LEQ 1 exit 0", ResourceFiles = resourceFiles, WaitForSuccess = true }; await pool.CommitAsync(); }
public AzureBatchClient(String accountName = null, String accountKey = null, String accountURL = null, BlobStorage storage = null, String poolID = null, String jobID = null, int poolNodeCount = 2, String poolVMSize = null, SystemMessageContainer container = null) { if (accountName == null) { throw new NullReferenceException("Please provide a valid batch account name"); } if (accountKey == null) { throw new NullReferenceException("Please provide a valid batch account key"); } if (accountURL == null) { throw new NullReferenceException("Please provide a valid batch account URL"); } if (storage == null) { throw new NullReferenceException("Please provide a valid blob storange reference"); } batchAccountName = accountName; batchAccountKey = accountKey; batchAccountURL = accountURL; blobStorage = storage; poolID = (poolID == null ? AzureConnectionUtility.BuildProjectNameReference() + "-pool" : poolID); jobID = (jobID == null ? AzureConnectionUtility.BuildProjectNameReference() + "-job" : jobID); poolVMSize = (poolVMSize == null ? "Basic_A1" : poolVMSize); messageContainer = (container == null ? new SystemMessageContainer() : container); messageContainer.AddInformationMessage("Creating batch client..."); batchClient = BatchClient.Open(new BatchSharedKeyCredentials(batchAccountURL, batchAccountName, batchAccountKey)); messageContainer.AddInformationMessage("Batch client created..."); //Create the pool if it doesn't exist pool = CreatePoolIfNotExists(poolID, poolVMSize, poolNodeCount); job = CreateJobIfNotExists(jobID, pool.Id); }
protected CloudPool CreatePool() { CloudPool currentPool = this.FindPoolIfExists(); if (currentPool == null) { // gotta create a new pool CloudServiceConfiguration passConfiguration = new CloudServiceConfiguration(OSFamily); currentPool = this.client.PoolOperations.CreatePool( this.PoolId, VMSize, passConfiguration, targetDedicatedComputeNodes: 1); var password = TestUtilities.GenerateRandomPassword(); currentPool.UserAccounts = new List <UserAccount>() { new UserAccount(AdminUserAccountName, password, ElevationLevel.Admin), new UserAccount(NonAdminUserAccountName, password, ElevationLevel.NonAdmin), }; StartTask st = new StartTask("cmd /c hostname"); // used for tests of StartTask(info) st.EnvironmentSettings = new List <EnvironmentSetting> { new EnvironmentSetting("key", "value") }; st.UserIdentity = new UserIdentity( autoUserSpecification: new AutoUserSpecification( scope: AutoUserScope.Pool, elevationLevel: ElevationLevel.NonAdmin)); currentPool.StartTask = st; currentPool.Commit(); } return(WaitForPoolAllocation(this.client, this.PoolId)); }
/// <summary> /// Method to wait until desired pool state is achieved /// </summary> /// <param name="pool">The pool</param> /// <param name="desiredState">The desired state of the pool</param> /// <returns>Returns a boolean when the pool is ready</returns> public async Task <bool> AwaitDesiredPoolState(CloudPool pool, AllocationState desiredState) { var watch = System.Diagnostics.Stopwatch.StartNew(); watch.Start(); do { await Task.Delay(5000); // Refresh pool to get latest state await pool.RefreshAsync(); // Timeout after 30 minutes if (watch.ElapsedTicks > TimeSpan.TicksPerHour / 2) { return(false); } }while (pool.AllocationState != desiredState); return(true); }
public static void JobMain(string[] args) { //Load the configuration Settings unzipperSettings = Settings.Default; CloudStorageAccount cloudStorageAccount = new CloudStorageAccount( new StorageCredentials( unzipperSettings.StorageAccountName, unzipperSettings.StorageAccountKey), unzipperSettings.StorageServiceUrl, useHttps: true); StagingStorageAccount stagingStorageAccount = new StagingStorageAccount( unzipperSettings.StorageAccountName, unzipperSettings.StorageAccountKey, cloudStorageAccount.BlobEndpoint.ToString()); using (BatchClient client = BatchClient.Open(new BatchSharedKeyCredentials(unzipperSettings.BatchServiceUrl, unzipperSettings.BatchAccountName, unzipperSettings.BatchAccountKey))) { string stagingContainer = null; //create pool CloudPool pool = CreatePool(unzipperSettings, client); try { CreateJob(unzipperSettings, client); List <CloudTask> tasksToRun = CreateTasks(unzipperSettings, stagingStorageAccount); AddTasksToJob(unzipperSettings, client, stagingContainer, tasksToRun); MonitorProgess(unzipperSettings, client); } finally { Cleanup(unzipperSettings, client, stagingContainer); } } }
/// <summary> /// create /// </summary> /// <param name="resource">resource</param> /// <returns>ApiResultCloudPool</returns> public ApiResultCloudPool CreateCloudPool(CloudPool resource) { // verify the required parameter 'resource' is set if (resource == null) { throw new ApiException(400, "Missing required parameter 'resource' when calling CreateCloudPool"); } var path = "/cloudpools"; path = path.Replace("{format}", "json"); var queryParams = new Dictionary <String, String>(); var headerParams = new Dictionary <String, String>(); var formParams = new Dictionary <String, String>(); var fileParams = new Dictionary <String, FileParameter>(); String postBody = null; postBody = ApiClient.Serialize(resource); // http body (model) parameter // authentication setting, if any String[] authSettings = new String[] { "FortifyToken" }; // make the HTTP request IRestResponse response = (IRestResponse)ApiClient.CallApi(path, Method.POST, queryParams, postBody, headerParams, formParams, fileParams, authSettings); if (((int)response.StatusCode) >= 400) { throw new ApiException((int)response.StatusCode, "Error calling CreateCloudPool: " + response.Content, response.Content); } else if (((int)response.StatusCode) == 0) { throw new ApiException((int)response.StatusCode, "Error calling CreateCloudPool: " + response.ErrorMessage, response.ErrorMessage); } return((ApiResultCloudPool)ApiClient.Deserialize(response.Content, typeof(ApiResultCloudPool), response.Headers)); }
private static async Task WaitForPoolToBeReady(CloudPool pool) { while (true) { await pool.RefreshAsync(); Log.Logger.Information("Pool {PoolId} is {AllocationState}.", pool.Id, pool.AllocationState); if (pool.AllocationState == AllocationState.Steady) { var nodes = await pool.ListComputeNodes().ToListAsync(); foreach (var node in nodes) { Log.Logger.Information("Node {NodeId} is {NodeState}.", node.Id, node.State); } if (nodes.All(x => x.State == ComputeNodeState.Idle)) { break; } } await Task.Delay(TimeSpan.FromSeconds(5)); } }
static void AddApplicationPool(BatchClient client, string code) { var poolId = "applicationpool" + code; IPagedEnumerable <CloudPool> pools = client.PoolOperations.ListPools(); foreach (CloudPool pool in pools) { if (pool.Id.Equals(poolId)) { Console.WriteLine("Pool already available for id : " + pool.Id); return; } } CloudPool newPool = client.PoolOperations.CreatePool( poolId: poolId, targetDedicatedComputeNodes: 3, // 3 compute nodes virtualMachineSize: "small", // single-core, 1.75 GB memory, 225 GB disk cloudServiceConfiguration: new CloudServiceConfiguration(osFamily: "3")); newPool.Commit(); Console.WriteLine("Created the pool for Code : " + code); }
/// <summary> /// Creates a <see cref="CloudPool"/> associated with the specified Batch account. If an existing pool with the /// specified ID is found, the pool is resized to match the specified node count. /// </summary> /// <param name="batchClient">A fully initialized <see cref="BatchClient"/>.</param> /// <param name="poolId">The ID of the <see cref="CloudPool"/>.</param> /// <param name="nodeSize">The size of the nodes within the pool.</param> /// <param name="nodeCount">The number of nodes to create within the pool.</param> /// <param name="maxTasksPerNode">The maximum number of tasks to run concurrently on each node.</param> /// <returns>A bound <see cref="CloudPool"/> with the specified properties.</returns> public async Task <CloudPool> CreatePoolIfNotExistAsync(BatchClient batchClient, string poolId, string nodeSize = null, int nodeCount = 0, int maxTasksPerNode = 0) { // You can learn more about os families and versions at: // https://azure.microsoft.com/en-us/documentation/articles/cloud-services-guestos-update-matrix/ CloudPool pool = batchClient.PoolOperations.CreatePool( poolId, targetDedicatedComputeNodes: Settings.PoolTargetNodeCount, virtualMachineSize: Settings.PoolNodeVirtualMachineSize, cloudServiceConfiguration: new CloudServiceConfiguration(Settings.PoolOsFamily)); pool.ApplicationPackageReferences = new List <ApplicationPackageReference> { new ApplicationPackageReference { ApplicationId = "signing", Version = "1.0" } }; await this.CreatePoolIfNotExistAsync(batchClient, pool).ConfigureAwait(continueOnCapturedContext: false); return(await batchClient.PoolOperations.GetPoolAsync(poolId).ConfigureAwait(continueOnCapturedContext: false)); }
public async Task TestBatchRequestCannotBeModifiedAfterExecutionStarted() { using BatchClient batchClient = ClientUnitTestCommon.CreateDummyClient(); Protocol.RequestInterceptor interceptor = new Protocol.RequestInterceptor(req => { PoolAddBatchRequest addPoolRequest = req as PoolAddBatchRequest; addPoolRequest.ServiceRequestFunc = token => { Assert.Throws <InvalidOperationException>(() => addPoolRequest.CancellationToken = CancellationToken.None); Assert.Throws <InvalidOperationException>(() => addPoolRequest.Options = null); Assert.Throws <InvalidOperationException>(() => addPoolRequest.RetryPolicy = null); Assert.Throws <InvalidOperationException>(() => addPoolRequest.ServiceRequestFunc = null); Assert.Throws <InvalidOperationException>(() => addPoolRequest.Timeout = TimeSpan.FromSeconds(0)); Assert.Throws <InvalidOperationException>(() => addPoolRequest.ClientRequestIdProvider = null); Assert.Throws <InvalidOperationException>(() => addPoolRequest.Parameters = null); return(Task.FromResult(new AzureOperationHeaderResponse <Protocol.Models.PoolAddHeaders>())); }; }); CloudPool pool = batchClient.PoolOperations.CreatePool("dummy", "small", default(CloudServiceConfiguration), targetDedicatedComputeNodes: 0); await pool.CommitAsync(additionalBehaviors : new[] { interceptor }); }
public async Task UnboundPoolCommitAndRefreshWorks() { using BatchClient batchClient = ClientUnitTestCommon.CreateDummyClient(); const string id = "Bar"; const string displayName = "Baz"; var startTask = new Protocol.Models.StartTask("cmd /c dir"); var protoPool = new Protocol.Models.CloudPool( id: id, displayName: displayName, startTask: startTask); CloudPool pool = batchClient.PoolOperations.CreatePool(id, "Woo", new CloudServiceConfiguration("4")); await pool.CommitAsync(additionalBehaviors : InterceptorFactory.CreateAddPoolRequestInterceptor()); await pool.RefreshAsync(additionalBehaviors : InterceptorFactory.CreateGetPoolRequestInterceptor(protoPool)); Assert.Equal(id, pool.Id); Assert.Equal(displayName, pool.DisplayName); Assert.Null(pool.CloudServiceConfiguration); Assert.NotNull(pool.StartTask); Assert.Equal(startTask.CommandLine, pool.StartTask.CommandLine); }
private static void CreatePoolIfNeeded(BatchClient client, string poolId) { // go through all the pools and see if the specified pool already exists bool found = false; // use an OData based select clause to limit the amount of data returned. This will result in incomplete // client objects but reduces the amount of data on the wire leading to faster completion when there are // a lot of objects for a given query. No spaces are allowed in the string and property names are case-sensitive. foreach (CloudPool p in client.PoolOperations.ListPools(new ODATADetailLevel(selectClause: "id,currentDedicated"))) { // pools are uniquely identified by their ID if (string.Equals(p.Id, poolId)) { Console.WriteLine("Using existing pool {0}", poolId); found = true; if (p.CurrentDedicated == 0) { Console.WriteLine("There are no compute nodes in this pool. No tasks will be run until at least one node has been added via resizing."); Console.WriteLine("Resizing pool to add 3 nodes. This might take a while..."); p.Resize(3); } break; } } if (!found) { Console.WriteLine("Creating pool: {0}", poolId); // if pool not found, call CreatePool. You can learn more about os families and versions at: // https://azure.microsoft.com/en-us/documentation/articles/cloud-services-guestos-update-matrix/ CloudPool pool = client.PoolOperations.CreatePool(poolId, targetDedicated: 3, virtualMachineSize: "small", osFamily: "3"); pool.Commit(); } }
protected CloudPool CreatePool() { CloudPool currentPool = this.FindPoolIfExists(); // gotta create a new pool if (currentPool == null) { var ubuntuImageDetails = GetUbuntuImageDetails(this.client); VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration( ubuntuImageDetails.ImageReference, nodeAgentSkuId: ubuntuImageDetails.NodeAgentSku.Id); currentPool = this.client.PoolOperations.CreatePool( poolId: this.PoolId, virtualMachineSize: VMSize, virtualMachineConfiguration: virtualMachineConfiguration, targetDedicatedComputeNodes: 1); currentPool.Commit(); } return(WaitForPoolAllocation(this.client, this.PoolId)); }
private static async Task TestCancelDeleteCertificateAsync( BatchClient batchCli, IList <CertificateReference> certificateReferences, Certificate certToDelete) { string poolId = "CancelDeleteCert-" + TestUtilities.GetMyName(); try { { CloudPool unboundPool = batchCli.PoolOperations.CreatePool( poolId: poolId, virtualMachineSize: PoolFixture.VMSize, cloudServiceConfiguration: new CloudServiceConfiguration(PoolFixture.OSFamily), targetDedicatedComputeNodes: 0); unboundPool.CertificateReferences = certificateReferences; await unboundPool.CommitAsync().ConfigureAwait(false); CloudPool boundPool = await batchCli.PoolOperations.GetPoolAsync(poolId).ConfigureAwait(false); // confirm the refs are there Assert.NotNull(boundPool.CertificateReferences); AssertCertificateReferenceCollectionsAreSame(certificateReferences, boundPool.CertificateReferences); } // test Certificate Delete/CancelDelete { await batchCli.CertificateOperations.DeleteCertificateAsync(certToDelete.ThumbprintAlgorithm, certToDelete.Thumbprint).ConfigureAwait(false); await certToDelete.RefreshAsync().ConfigureAwait(false); // ok, it should be deleting Assert.Equal(CertificateState.Deleting, certToDelete.State); //now we wait for delete failed await WaitForCertificateState(certToDelete, CertificateState.DeleteFailed).ConfigureAwait(false); // test CertificateManger.CancelDelete. now the delete failed, we can cancel it await batchCli.CertificateOperations.CancelDeleteCertificateAsync(certToDelete.ThumbprintAlgorithm, certToDelete.Thumbprint).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); // gift to server to get going on that cancel. // get fresh state await certToDelete.RefreshAsync().ConfigureAwait(false); // cert is now ok Assert.Equal(CertificateState.Active, certToDelete.State); } // test Certificate.Delete/CancelDelete { await certToDelete.DeleteAsync().ConfigureAwait(false); await certToDelete.RefreshAsync().ConfigureAwait(false); // ok, it should be deleting Assert.Equal(CertificateState.Deleting, certToDelete.State); //now we wait for delete failed await WaitForCertificateState(certToDelete, CertificateState.DeleteFailed).ConfigureAwait(false); await certToDelete.CancelDeleteAsync().ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); // get fresh state await certToDelete.RefreshAsync().ConfigureAwait(false); // cert is now ok Assert.Equal(CertificateState.Active, certToDelete.State); } } finally { TestUtilities.DeletePoolIfExistsAsync(batchCli, poolId).Wait(); } }
private static async Task TestPoolCreateAndUpdateWithCertificateReferencesAsync( BatchClient batchCli, IList <CertificateReference> certificateReferences) { PoolOperations poolOperations = batchCli.PoolOperations; string poolId = "CreateAndUpdateWithCertificateReferences-" + TestUtilities.GetMyName(); try { // create a pool with initial cert refs CloudPool boundPool; { CloudPool unboundPool = poolOperations.CreatePool( poolId: poolId, virtualMachineSize: PoolFixture.VMSize, cloudServiceConfiguration: new CloudServiceConfiguration(PoolFixture.OSFamily), targetDedicatedComputeNodes: 0); // create the pool with initial cert refs unboundPool.CertificateReferences = certificateReferences; await unboundPool.CommitAsync().ConfigureAwait(false); boundPool = await poolOperations.GetPoolAsync(poolId).ConfigureAwait(false); // confirm the refs are there Assert.NotNull(boundPool.CertificateReferences); AssertCertificateReferenceCollectionsAreSame(certificateReferences, boundPool.CertificateReferences); } // mutate the cert refs: assign only one { List <CertificateReference> listOfOne = new List <CertificateReference>(); // just pick one cert listOfOne.Add(certificateReferences.ToArray()[1]); boundPool.CertificateReferences = listOfOne; await boundPool.CommitAsync().ConfigureAwait(false); await boundPool.RefreshAsync().ConfigureAwait(false); // confirm that the ref collection is correct AssertCertificateReferenceCollectionsAreSame(listOfOne, boundPool.CertificateReferences); } // mutate the pool cert refs: assign null to clear { boundPool.CertificateReferences = null; await boundPool.CommitAsync().ConfigureAwait(false); await boundPool.RefreshAsync().ConfigureAwait(false); Assert.Empty(boundPool.CertificateReferences); } } finally { // cleanup TestUtilities.DeletePoolIfExistsAsync(batchCli, poolId).Wait(); } }
public void CanAddTaskWithFilesToStage() { StagingStorageAccount storageCreds = TestUtilities.GetStorageCredentialsFromEnvironment(); using (BatchClient batchCli = TestUtilities.OpenBatchClient(TestUtilities.GetCredentialsFromEnvironment())) { string jobId = "TestTaskWithFilesToStage-" + TestUtilities.GetMyName(); try { CloudJob job = batchCli.JobOperations.CreateJob(jobId, new PoolInformation() { PoolId = this.poolFixture.PoolId }); job.Commit(); CloudJob boundJob = batchCli.JobOperations.GetJob(jobId); CloudTask myTask = new CloudTask(id: "CountWordsTask", commandline: @"cmd /c dir /s .. & dir & wc localwords.txt"); myTask.FilesToStage = new List <IFileStagingProvider> { new FileToStage(Resources.LocalWordsDotText, storageCreds) }; // add the task to the job var artifacts = boundJob.AddTask(myTask); var specificArtifact = artifacts[typeof(FileToStage)]; SequentialFileStagingArtifact sfsa = specificArtifact as SequentialFileStagingArtifact; Assert.NotNull(sfsa); // Open the new Job as bound. CloudPool boundPool = batchCli.PoolOperations.GetPool(boundJob.ExecutionInformation.PoolId); // wait for the task to complete TaskStateMonitor taskStateMonitor = batchCli.Utilities.CreateTaskStateMonitor(); taskStateMonitor.WaitAll( boundJob.ListTasks(), Microsoft.Azure.Batch.Common.TaskState.Completed, TimeSpan.FromMinutes(10), controlParams: null, additionalBehaviors: new[] { // spam/logging interceptor new Microsoft.Azure.Batch.Protocol.RequestInterceptor((x) => { this.testOutputHelper.WriteLine("Issuing request type: " + x.GetType().ToString()); try { // print out the compute node states... we are actually waiting on the compute nodes List <ComputeNode> allComputeNodes = boundPool.ListComputeNodes().ToList(); this.testOutputHelper.WriteLine(" #compute nodes: " + allComputeNodes.Count); allComputeNodes.ForEach( (icn) => { this.testOutputHelper.WriteLine(" computeNode.id: " + icn.Id + ", state: " + icn.State); }); } catch (Exception ex) { // there is a race between the pool-life-job and the end of the job.. and the ListComputeNodes above Assert.True(false, "SampleWithFilesAndPool probably can ignore this if its pool not found: " + ex.ToString()); } }) }); List <CloudTask> tasks = boundJob.ListTasks().ToList(); CloudTask myCompletedTask = tasks.Single(); foreach (CloudTask curTask in tasks) { this.testOutputHelper.WriteLine("Task Id: " + curTask.Id + ", state: " + curTask.State); } boundPool.Refresh(); this.testOutputHelper.WriteLine("Pool Id: " + boundPool.Id + ", state: " + boundPool.State); string stdOut = myCompletedTask.GetNodeFile(Constants.StandardOutFileName).ReadAsString(); string stdErr = myCompletedTask.GetNodeFile(Constants.StandardErrorFileName).ReadAsString(); this.testOutputHelper.WriteLine("StdOut: "); this.testOutputHelper.WriteLine(stdOut); this.testOutputHelper.WriteLine("StdErr: "); this.testOutputHelper.WriteLine(stdErr); this.testOutputHelper.WriteLine("Task Files:"); foreach (NodeFile curFile in myCompletedTask.ListNodeFiles(recursive: true)) { this.testOutputHelper.WriteLine(" File path: " + curFile.Path); } var files = myCompletedTask.ListNodeFiles(recursive: true).ToList(); // confirm the files are there Assert.True(files.Any(file => file.Path.Contains("localWords.txt")), "missing file: localWords.txt"); } finally { TestUtilities.DeleteJobIfExistsAsync(batchCli, jobId).Wait(); } } }
static void Main(string[] args) { string storageConnectionString = $"DefaultEndpointsProtocol=https;AccountName={StorageAccountName};AccountKey={StorageAccountKey}"; // Retrieve the storage account CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString); // Create the blob client CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); // Upload the input files to blob storage const string inputContainerName = "batchinput"; List <string> inputFilePaths = new List <string> { "taskdata0.txt", "taskdata1.txt", "taskdata2.txt" }; List <ResourceFile> inputFiles = new List <ResourceFile>(); foreach (string filePath in inputFilePaths) { inputFiles.Add(UploadFileToContainer(blobClient, inputContainerName, filePath)); } // Get a SAS Url for the output container const string outputContainerName = "batchoutput"; string outputContainerSasUrl = GetOutputContainerSasUrl(blobClient, outputContainerName); // Specify a container registry ContainerRegistry containerRegistry = new ContainerRegistry( registryServer: RegistryServer, userName: RegistryUserName, password: RegistryPassword); // Create container configuration, prefetching Docker images from the container registry ContainerConfiguration containerConfig = new ContainerConfiguration() { ContainerImageNames = ContainerImageNames, ContainerRegistries = new List <ContainerRegistry> { containerRegistry } }; // Create the virtual machine image reference - make sure to choose an image that supports containers ImageReference imageReference = new ImageReference( publisher: "MicrosoftWindowsServer", offer: "WindowsServer", sku: "2016-datacenter-with-containers", version: "latest"); // Create the virtual machine configuration for the pool and set the container configuration VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration( imageReference: imageReference, nodeAgentSkuId: "batch.node.windows amd64"); virtualMachineConfiguration.ContainerConfiguration = containerConfig; BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey); using (BatchClient batchClient = BatchClient.Open(cred)) { Console.WriteLine("Creating pool [{0}]...", PoolId); try { CloudPool pool = batchClient.PoolOperations.CreatePool( poolId: PoolId, targetDedicatedComputeNodes: PoolNodeCount, virtualMachineSize: PoolVMSize, virtualMachineConfiguration: virtualMachineConfiguration); pool.Commit(); } catch (BatchException be) { // Accept the specific error code PoolExists as that is expected if the pool already exists if (be.RequestInformation?.BatchError?.Code == BatchErrorCodeStrings.PoolExists) { Console.WriteLine("The pool {0} already existed when we tried to create it", PoolId); } else { throw; // Any other exception is unexpected } } Console.WriteLine("Creating job [{0}]...", JobId); CloudJob job = null; try { job = batchClient.JobOperations.CreateJob(); job.Id = JobId; job.PoolInformation = new PoolInformation { PoolId = PoolId }; // Add job preparation task to remove existing Docker image Console.WriteLine("Adding job preparation task to job [{0}]...", JobId); string jobPreparationCmdLine = $"cmd /c docker rmi -f {ContainerImageNames[0]}:latest"; JobPreparationTask jobPreparationTask = new JobPreparationTask(jobPreparationCmdLine) { UserIdentity = new UserIdentity(new AutoUserSpecification(elevationLevel: ElevationLevel.Admin, scope: AutoUserScope.Task)) }; job.JobPreparationTask = jobPreparationTask; job.Commit(); } catch (BatchException be) { // Accept the specific error code JobExists as that is expected if the job already exists if (be.RequestInformation?.BatchError?.Code == BatchErrorCodeStrings.JobExists) { Console.WriteLine("The job {0} already existed when we tried to create it", JobId); } else { throw; // Any other exception is unexpected } } if (job != null) { // Create a collection to hold the tasks that we'll be adding to the job Console.WriteLine("Adding {0} tasks to job [{1}]...", inputFiles.Count, JobId); List <CloudTask> tasks = new List <CloudTask>(); // Create each of the tasks to process one of the input files. for (int i = 0; i < inputFiles.Count; i++) { string taskId = String.Format("Task{0}", i); string inputFilename = inputFiles[i].FilePath; string outputFileName = string.Format("out{0}", inputFilename); // Override the default entrypoint of the container string taskCommandLine = string.Format("C:\\ReadWriteFile\\ReadWriteFile.exe {0} {1}", inputFilename, outputFileName); // Specify the container the task will run TaskContainerSettings cmdContainerSettings = new TaskContainerSettings( imageName: "nimccollftacr.azurecr.io/batch/readwritefile" ); CloudTask task = new CloudTask(taskId, taskCommandLine); task.ContainerSettings = cmdContainerSettings; // Set the resource files and output files for the task task.ResourceFiles = new List <ResourceFile> { inputFiles[i] }; task.OutputFiles = new List <OutputFile> { new OutputFile( filePattern: outputFileName, destination: new OutputFileDestination(new OutputFileBlobContainerDestination(containerUrl: outputContainerSasUrl, path: outputFileName)), uploadOptions: new OutputFileUploadOptions(OutputFileUploadCondition.TaskCompletion)) }; // You must elevate the identity of the task in order to run a container task.UserIdentity = new UserIdentity(new AutoUserSpecification(elevationLevel: ElevationLevel.Admin, scope: AutoUserScope.Task)); tasks.Add(task); } // Add all tasks to the job. batchClient.JobOperations.AddTask(JobId, tasks); // Monitor task success/failure, specifying a maximum amount of time to wait for the tasks to complete. TimeSpan timeout = TimeSpan.FromMinutes(30); Console.WriteLine("Monitoring all tasks for 'Completed' state, timeout in {0}...", timeout); IEnumerable <CloudTask> addedTasks = batchClient.JobOperations.ListTasks(JobId); batchClient.Utilities.CreateTaskStateMonitor().WaitAll(addedTasks, TaskState.Completed, timeout); Console.WriteLine("All tasks reached state Completed."); // Print task output Console.WriteLine(); Console.WriteLine("Printing task output..."); IEnumerable <CloudTask> completedtasks = batchClient.JobOperations.ListTasks(JobId); foreach (CloudTask task in completedtasks) { string nodeId = String.Format(task.ComputeNodeInformation.ComputeNodeId); Console.WriteLine("Task: {0}", task.Id); Console.WriteLine("Node: {0}", nodeId); Console.WriteLine("Standard out:"); Console.WriteLine(task.GetNodeFile(Constants.StandardOutFileName).ReadAsString()); } } // Clean up Batch resources (if the user so chooses) Console.WriteLine(); Console.Write("Delete job? [yes] no: "); string response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { batchClient.JobOperations.DeleteJob(JobId); } Console.Write("Delete pool? [yes] no: "); response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { batchClient.PoolOperations.DeletePool(PoolId); } } }
public ShowHeatMapMessage(CloudPool pool) { this.Pool = pool; }
/// <summary> /// Creates a pool if it doesn't already exist. If the pool already exists, this method resizes it to meet the expected /// targets specified in settings. /// </summary> /// <param name="batchClient">The BatchClient to create the pool with.</param> /// <param name="pool">The pool to create.</param> /// <returns>An asynchronous <see cref="Task"/> representing the operation.</returns> public static async Task CreatePoolIfNotExistAsync(BatchClient batchClient, CloudPool pool) { bool successfullyCreatedPool = false; int poolTargetNodeCount = pool.TargetDedicated ?? 0; string poolNodeVirtualMachineSize = pool.VirtualMachineSize; string poolId = pool.Id; // Attempt to create the pool try { // Create an in-memory representation of the Batch pool which we would like to create. We are free to modify/update // this pool object in memory until we commit it to the service via the CommitAsync method. Console.WriteLine("Attempting to create pool: {0}", pool.Id); // Create the pool on the Batch Service await pool.CommitAsync(); successfullyCreatedPool = true; Console.WriteLine("Created pool {0} with {1} {2} nodes", pool, poolTargetNodeCount, poolNodeVirtualMachineSize); } catch (BatchException e) { // Swallow the specific error code PoolExists since that is expected if the pool already exists if (e.RequestInformation != null && e.RequestInformation.AzureError != null && e.RequestInformation.AzureError.Code == BatchErrorCodeStrings.PoolExists) { // The pool already existed when we tried to create it successfullyCreatedPool = false; Console.WriteLine("The pool already existed when we tried to create it"); } else { throw; // Any other exception is unexpected } } // If the pool already existed, make sure that its targets are correct if (!successfullyCreatedPool) { CloudPool existingPool = await batchClient.PoolOperations.GetPoolAsync(poolId); // If the pool doesn't have the right number of nodes and it isn't resizing then we need // to ask it to resize if (existingPool.CurrentDedicated != poolTargetNodeCount && existingPool.AllocationState != AllocationState.Resizing) { // Resize the pool to the desired target. Note that provisioning the nodes in the pool may take some time await existingPool.ResizeAsync(poolTargetNodeCount); } } }
public HeatMapModel(CloudPool pool) { this.Pool = pool; this.computeNodes = new List<ComputeNode>(); }