/// <summary> /// Method to wait until node creation is complete /// </summary> /// <param name="node">The compute node</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> AwaitDesiredNodeState(ComputeNode node, ComputeNodeState desiredState) { var watch = System.Diagnostics.Stopwatch.StartNew(); watch.Start(); do { // Refresh pool to get latest state await node.RefreshAsync(); // Timeout after 30 minutes or if the node is an invalid state if (watch.ElapsedTicks > TimeSpan.TicksPerHour / 2 || node.State == ComputeNodeState.Unknown || node.State == ComputeNodeState.Unusable || node.State == ComputeNodeState.Offline || node.State == ComputeNodeState.StartTaskFailed || node.State == ComputeNodeState.Preempted) { return(false); } await Task.Delay(5000); }while (node.State != desiredState); return(true); }
public IComputeNode GetComputeNode() { IComputeNode compute_node = null; try { CloudStorageAccount storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("StorageAccount.ConnectionString")); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference(AzureContainer); container.CreateIfNotExist(); CloudBlob blob = container.GetBlobReference(BermudaConfig); string data = blob.DownloadText(); //deserialize compute_node = new ComputeNode().DeserializeComputeNode(data); if (compute_node.Catalogs.Values.Cast <ICatalog>().FirstOrDefault().CatalogMetadata.Tables.FirstOrDefault().Value.DataType == null) { compute_node.Catalogs.Values.Cast <ICatalog>().FirstOrDefault().CatalogMetadata.Tables.FirstOrDefault().Value.DataType = typeof(UDPTestDataItems); } compute_node.Init(CurrentInstanceIndex, AllNodeEndpoints.Count()); } catch (Exception ex) { Trace.WriteLine(ex.ToString()); } return(compute_node); }
public IComputeNode GetComputeNode() { IComputeNode compute_node = null; try { //amazon client using (var client = new AmazonS3Client()) { //download request using (var response = client.GetObject(new GetObjectRequest() .WithBucketName(AmazonBucket) .WithKey(BermudaConfig))) { using (StreamReader reader = new StreamReader(response.ResponseStream)) { //read the file string data = reader.ReadToEnd(); //deserialize compute_node = new ComputeNode().DeserializeComputeNode(data); compute_node.Init(CurrentInstanceIndex, AllNodeEndpoints.Count()); } } } } catch (Exception ex) { Trace.WriteLine(ex.ToString()); } return(compute_node); }
/// <summary> /// open from the storage interface /// </summary> /// <param name="storage"></param> private void OpenStorage(IStorageAccess storage) { //open file dialog string PathName; string FileName; if (!storage.OpenFileDialog(out PathName, out FileName)) { return; } //read the file string data; if (!storage.ReadFile(PathName, FileName, out data)) { MessageBox.Show("There was an error reading the file."); return; } //create the compute node and window IComputeNode compute_node = new ComputeNode().DeserializeComputeNode(data); ComputeNodeConfig dlg = new ComputeNodeConfig(compute_node); dlg.Show(); Close(); }
private void btnNew_Click(object sender, RoutedEventArgs e) { ComputeNode compute_node = new ComputeNode(); ComputeNodeConfig config = new ComputeNodeConfig(compute_node); config.Show(); Close(); }
public void TestComputeNodeUserIaas() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { CloudPool sharedPool = this.poolFixture.Pool; List <string> cnuNamesToDelete = new List <string>(); // pick a compute node to victimize with user accounts var nodes = sharedPool.ListComputeNodes().ToList(); ComputeNode cn = nodes[0]; try { ComputeNodeUser bob = batchCli.PoolOperations.CreateComputeNodeUser(sharedPool.Id, cn.Id); bob.Name = "bob"; bob.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(25); bob.Password = "******"; bob.SshPublicKey = "base64=="; cnuNamesToDelete.Add(bob.Name); // remember to clean this up bob.Commit(ComputeNodeUserCommitSemantics.AddUser); bob.SshPublicKey = "base65=="; bob.Commit(ComputeNodeUserCommitSemantics.UpdateUser); // TODO: need to close the loop on this somehow... move to unit/interceptor-based? // currently the server is timing out. } finally { // clear any old accounts try { foreach (string curCNUName in cnuNamesToDelete) { this.testOutputHelper.WriteLine("TestComputeNodeUserIAAS attempting to delete the following <nodeid,user>: <{0},{1}>", cn.Id, curCNUName); cn.DeleteComputeNodeUser(curCNUName); } } catch (Exception ex) { this.testOutputHelper.WriteLine("TestComputeNodeUserIAAS: exception deleting user account. ex: " + ex.ToString()); } } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
private static void CompareComputeNodeObjects(ComputeNode first, ComputeNode second) { Assert.Equal(first.AffinityId, second.AffinityId); Assert.Equal(first.IPAddress, second.IPAddress); Assert.Equal(first.LastBootTime, second.LastBootTime); Assert.Equal(first.Id, second.Id); Assert.Equal(first.StateTransitionTime, second.StateTransitionTime); Assert.Equal(first.Url, second.Url); Assert.Equal(first.AllocationTime, second.AllocationTime); Assert.Equal(first.VirtualMachineSize, second.VirtualMachineSize); }
public void Bug1771163TestGetComputeNode_RefreshComputeNode() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { PoolOperations poolOperations = batchCli.PoolOperations; List <ComputeNode> computeNodeList = poolOperations.ListComputeNodes(this.poolFixture.PoolId).ToList(); ComputeNode computeNodeToGet = computeNodeList.First(); string computeNodeId = computeNodeToGet.Id; // // Get compute node via the manager // ComputeNode computeNodeFromManager = poolOperations.GetComputeNode(this.poolFixture.PoolId, computeNodeId); CompareComputeNodeObjects(computeNodeToGet, computeNodeFromManager); // // Get compute node via the pool // CloudPool pool = poolOperations.GetPool(this.poolFixture.PoolId); ComputeNode computeNodeFromPool = pool.GetComputeNode(computeNodeId); CompareComputeNodeObjects(computeNodeToGet, computeNodeFromPool); // // Refresh compute node // //Refresh with a detail level computeNodeToGet.Refresh(new ODATADetailLevel() { SelectClause = "affinityId,id" }); //Confirm we have the reduced detail level Assert.Equal(computeNodeToGet.AffinityId, computeNodeFromManager.AffinityId); Assert.Null(computeNodeToGet.IPAddress); Assert.Null(computeNodeToGet.LastBootTime); Assert.Null(computeNodeToGet.State); Assert.Null(computeNodeToGet.StartTaskInformation); //Refresh again with increased detail level computeNodeToGet.Refresh(); CompareComputeNodeObjects(computeNodeToGet, computeNodeFromManager); } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
public void TestFilePropertiesFileMode() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { string jobId = null; try { string taskId; // create some files on the node TestUtilities.HelloWorld( batchCli, this.testOutputHelper, this.poolFixture.Pool, out jobId, out taskId, deleteJob: false, isLinux: true); var nodes = this.poolFixture.Pool.ListComputeNodes().ToList(); ComputeNode cn = nodes[0]; // get the node that has files on it List <NodeFile> files = cn.ListNodeFiles(recursive: true).ToList(); Assert.True(files.Count > 0); bool foundOne = false; // look through all the files for a filemode foreach (NodeFile curNF in files) { if ((null != curNF.Properties) && !string.IsNullOrWhiteSpace(curNF.Properties.FileMode)) { foundOne = true; break; } } Assert.True(foundOne); } finally { TestUtilities.DeleteJobIfExistsAsync(batchCli, jobId).Wait(); } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
public void TestRandomBoundComputeNodeProperties() { using BatchClient client = ClientUnitTestCommon.CreateDummyClient(); for (int i = 0; i < TestRunCount; i++) { Protocol.Models.ComputeNode computeNodeModel = this.customizedObjectFactory.GenerateNew <Protocol.Models.ComputeNode>(); ComputeNode boundComputeNode = new ComputeNode(client, "Foo", computeNodeModel, client.CustomBehaviors); ObjectComparer.CheckEqualityResult result = this.objectComparer.CheckEquality(boundComputeNode, computeNodeModel); Assert.True(result.Equal, result.Message); } }
/// <summary> /// Lists the compute nodes matching the specified filter options. /// </summary> /// <param name="options">The options to use when querying for compute nodes.</param> /// <returns>The compute nodes matching the specified filter options.</returns> public IEnumerable <PSComputeNode> ListComputeNodes(ListComputeNodeOptions options) { if (options == null) { throw new ArgumentNullException("options"); } string poolId = options.Pool == null ? options.PoolId : options.Pool.Id; // Get the single compute node matching the specified id if (!string.IsNullOrEmpty(options.ComputeNodeId)) { WriteVerbose(string.Format(Resources.GetComputeNodeById, options.ComputeNodeId, poolId)); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; ODATADetailLevel getDetailLevel = new ODATADetailLevel(selectClause: options.Select); ComputeNode computeNode = poolOperations.GetComputeNode(poolId, options.ComputeNodeId, detailLevel: getDetailLevel, additionalBehaviors: options.AdditionalBehaviors); PSComputeNode psComputeNode = new PSComputeNode(computeNode); return(new PSComputeNode[] { psComputeNode }); } // List compute nodes using the specified filter else { string verboseLogString = null; ODATADetailLevel listDetailLevel = new ODATADetailLevel(selectClause: options.Select); if (!string.IsNullOrEmpty(options.Filter)) { verboseLogString = string.Format(Resources.GetComputeNodeByOData, poolId); listDetailLevel.FilterClause = options.Filter; } else { verboseLogString = string.Format(Resources.GetComputeNodeNoFilter, poolId); } WriteVerbose(verboseLogString); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; IPagedEnumerable <ComputeNode> computeNodes = poolOperations.ListComputeNodes(poolId, listDetailLevel, options.AdditionalBehaviors); return(PSPagedEnumerable <PSComputeNode, ComputeNode> .CreateWithMaxCount ( computeNodes, c => { return new PSComputeNode(c); }, options.MaxCount, () => WriteMaxCount(options.MaxCount) )); } }
public void Bug2302907_TestComputeNodeDoesInheritBehaviors() { void test() { using BatchClient batchCli = TestUtilities.OpenBatchClient(TestUtilities.GetCredentialsFromEnvironment(), addDefaultRetryPolicy: false); Protocol.RequestInterceptor interceptor = new Protocol.RequestInterceptor(); batchCli.PoolOperations.CustomBehaviors.Add(interceptor); List <ComputeNode> computeNodeList = batchCli.PoolOperations.ListComputeNodes(poolFixture.PoolId).ToList(); ComputeNode computeNode = computeNodeList.First(); Assert.Equal(2, computeNode.CustomBehaviors.Count); Assert.Contains(interceptor, computeNode.CustomBehaviors); } SynchronizationContextHelper.RunTest(test, TestTimeout); }
public void TestGetRemoteLoginSettings() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { CloudPool sharedPool = this.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.Equal <int>(expected: 1, actual: nodes.Count); 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); }
public void TestComputeNodeCertificateReferencesAreReadOnly() { using (BatchClient batchClient = ClientUnitTestCommon.CreateDummyClient()) { var protoComputeNode = new Protocol.Models.ComputeNode() { CertificateReferences = new List <Protocol.Models.CertificateReference> { new Protocol.Models.CertificateReference( thumbprint: "1234", thumbprintAlgorithm: "SHA1", storeLocation: Protocol.Models.CertificateStoreLocation.CurrentUser, storeName: "My", visibility: new List <Protocol.Models.CertificateVisibility> { Protocol.Models.CertificateVisibility.Task }) } }; ComputeNode computeNode = batchClient.PoolOperations.GetComputeNode( "dummy", "dummy", additionalBehaviors: InterceptorFactory.CreateGetComputeNodeRequestInterceptor(protoComputeNode)); CertificateReference computeNodeCertificateReference = computeNode.CertificateReferences.First(); // reads are allowed this.testOutputHelper.WriteLine("{0}", computeNodeCertificateReference.StoreLocation); this.testOutputHelper.WriteLine("{0}", computeNodeCertificateReference.StoreName); this.testOutputHelper.WriteLine("{0}", computeNodeCertificateReference.Thumbprint); this.testOutputHelper.WriteLine("{0}", computeNodeCertificateReference.ThumbprintAlgorithm); this.testOutputHelper.WriteLine("{0}", computeNodeCertificateReference.Visibility); // writes are foribdden Assert.Throws <InvalidOperationException>(() => { computeNodeCertificateReference.StoreLocation = CertStoreLocation.CurrentUser; }); Assert.Throws <InvalidOperationException>(() => { computeNodeCertificateReference.StoreName = "x"; }); Assert.Throws <InvalidOperationException>(() => { computeNodeCertificateReference.Thumbprint = "y"; }); Assert.Throws <InvalidOperationException>(() => { computeNodeCertificateReference.ThumbprintAlgorithm = "z"; }); Assert.Throws <InvalidOperationException>(() => { computeNodeCertificateReference.Visibility = CertificateVisibility.None; }); } }
private string GetDriverUrlInternal(string filepath) { CloudTask driverTask = _azurebatchService.GetJobManagerTaskFromJobId(_jobId); NodeFile httpEndPointFile; try { httpEndPointFile = driverTask.GetNodeFile(Path.Combine(AzureBatchTaskWorkDirectory, filepath)); } catch (BatchException e) { throw new InvalidOperationException("driver http endpoint file is not ready.", e); } string driverHost = httpEndPointFile.ReadAsString().TrimEnd('\r', '\n', ' '); //// Get port string[] driverIpAndPorts = driverHost.Split(':'); if (driverIpAndPorts.Length <= 1 || !int.TryParse(driverIpAndPorts[1], out int backendPort)) { LOGGER.Log(Level.Warning, "Unable to get driver http endpoint port from: {0}", driverHost); return(null); } //// Get public Ip string publicIp = "0.0.0.0"; int frontEndPort = 0; string driverNodeId = driverTask.ComputeNodeInformation.ComputeNodeId; ComputeNode driverNode = _azurebatchService.GetComputeNodeFromNodeId(driverNodeId); IReadOnlyList <InboundEndpoint> inboundEndpoints = driverNode.EndpointConfiguration.InboundEndpoints; InboundEndpoint endpoint = inboundEndpoints.FirstOrDefault(s => s.BackendPort == backendPort); if (endpoint != null) { publicIp = endpoint.PublicIPAddress; frontEndPort = endpoint.FrontendPort; } return("http://" + publicIp + ':' + frontEndPort + '/'); }
/// <summary> /// Lists the compute nodes matching the specified filter options. /// </summary> /// <param name="options">The options to use when querying for compute nodes.</param> /// <returns>The compute nodes matching the specified filter options.</returns> public IEnumerable <PSComputeNode> ListComputeNodes(ListComputeNodeOptions options) { if (options == null) { throw new ArgumentNullException("options"); } string poolId = options.Pool == null ? options.PoolId : options.Pool.Id; // Get the single compute node matching the specified id if (!string.IsNullOrEmpty(options.ComputeNodeId)) { WriteVerbose(string.Format(Resources.GBCN_GetById, options.ComputeNodeId, poolId)); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; ComputeNode computeNode = poolOperations.GetComputeNode(poolId, options.ComputeNodeId, additionalBehaviors: options.AdditionalBehaviors); PSComputeNode psComputeNode = new PSComputeNode(computeNode); return(new PSComputeNode[] { psComputeNode }); } // List compute nodes using the specified filter else { ODATADetailLevel odata = null; string verboseLogString = null; if (!string.IsNullOrEmpty(options.Filter)) { verboseLogString = string.Format(Resources.GBCN_GetByOData, poolId); odata = new ODATADetailLevel(filterClause: options.Filter); } else { verboseLogString = string.Format(Resources.GBCN_NoFilter, poolId); } WriteVerbose(verboseLogString); PoolOperations poolOperations = options.Context.BatchOMClient.PoolOperations; IPagedEnumerable <ComputeNode> computeNodes = poolOperations.ListComputeNodes(poolId, odata, options.AdditionalBehaviors); Func <ComputeNode, PSComputeNode> mappingFunction = c => { return(new PSComputeNode(c)); }; return(PSPagedEnumerable <PSComputeNode, ComputeNode> .CreateWithMaxCount( computeNodes, mappingFunction, options.MaxCount, () => WriteVerbose(string.Format(Resources.MaxCount, options.MaxCount)))); } }
private static string GetComputeNodeEntry(ComputeNode computeNode) { if (string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["SubnetResourceId"])) { // Get public endpoint if (computeNode.EndpointConfiguration != null && computeNode.EndpointConfiguration.InboundEndpoints != null) { foreach (var endpoint in computeNode.EndpointConfiguration.InboundEndpoints) { if (endpoint.Name.StartsWith("VRay")) { Console.WriteLine(" {0} {1}:{2}", computeNode.Id, endpoint.PublicIPAddress, endpoint.FrontendPort); return(string.Format("{0} 1 {1}\n", endpoint.PublicIPAddress, endpoint.FrontendPort)); } } } } return(string.Format("{0} 1 {1}\n", computeNode.IPAddress, ConfigurationManager.AppSettings["VRaySererPort"])); }
/// <summary> /// save to the storage interface /// </summary> /// <param name="storage"></param> private void SaveStorage(IStorageAccess storage) { //save file dialog string PathName; string FileName; if (!storage.SaveFileDialog(out PathName, out FileName)) { return; } //get the data to save string data = ComputeNode.SerializeComputeNode(); //save the data if (!storage.SaveFile(data, PathName, FileName)) { MessageBox.Show("There was an error saving the file."); return; } Close(); }
public IComputeNode GetComputeNode() { IComputeNode compute_node = null; try { //amazon client using (var client = new AmazonS3Client()) { //download request using (var response = client.GetObject(new GetObjectRequest() .WithBucketName(AmazonBucket) .WithKey(BermudaConfig))) { using (StreamReader reader = new StreamReader(response.ResponseStream)) { //read the file string data = reader.ReadToEnd(); //deserialize compute_node = new ComputeNode().DeserializeComputeNode(data); if (compute_node.Catalogs.Values.Cast <ICatalog>().FirstOrDefault().CatalogMetadata.Tables.FirstOrDefault().Value.DataType == null) { compute_node.Catalogs.Values.Cast <ICatalog>().FirstOrDefault().CatalogMetadata.Tables.FirstOrDefault().Value.DataType = typeof(UDPTestDataItems); } compute_node.Init(CurrentInstanceIndex, AllNodeEndpoints.Count()); } } } } catch (Exception ex) { Trace.WriteLine(ex.ToString()); } return(compute_node); }
/// <summary> /// calls the two new get-status REST APIs and asserts their values /// /// 1: add a single quick task (quick because we don't need it to run very long) /// 2: this forces a victim compute node to run the JobPrep /// 3: poll for this compute node, ignore others (sharedPool.size probably > 1) /// 4: check status of JobPrep /// 4a: assert as many values as makes sense... this is not a retry test /// 5: JobPrep succeeds, task runs /// 6: poll for JobRelease.. it is long running /// 7: assert as many values as makes sense. /// </summary> /// <param name="batchCli"></param> private void TestGetPrepReleaseStatusCalls(BatchClient batchCli, CloudJobSchedule boundJobSchedule, string sharedPool, IEnumerable <ResourceFile> correctResFiles) { // need this often enough lets just pull it out string jobId = boundJobSchedule.ExecutionInformation.RecentJob.Id; PoolOperations poolOps = batchCli.PoolOperations; JobScheduleOperations jobScheduleOperations = batchCli.JobScheduleOperations; { DateTime beforeJobPrepRuns = DateTime.UtcNow; // used to test start time // need a task to force JobPrep CloudTask sillyTask = new CloudTask("forceJobPrep", "cmd /c hostname"); // add the task batchCli.JobOperations.AddTask(jobId, sillyTask); bool keepLooking = true; while (keepLooking) { this.testOutputHelper.WriteLine("Waiting for task to be scheduled."); foreach (CloudTask curTask in batchCli.JobOperations.GetJob(jobId).ListTasks()) { if (curTask.State != TaskState.Active) { keepLooking = false; break; } } Thread.Sleep(1000); } List <JobPreparationAndReleaseTaskExecutionInformation> jobPrepStatusList = new List <JobPreparationAndReleaseTaskExecutionInformation>(); while (jobPrepStatusList.Count == 0) { jobPrepStatusList = batchCli.JobOperations.ListJobPreparationAndReleaseTaskStatus(jobId).ToList(); } JobPreparationAndReleaseTaskExecutionInformation jptei = jobPrepStatusList.First(); ComputeNode victimComputeNodeRunningPrepAndRelease = poolOps.GetComputeNode(sharedPool, jptei.ComputeNodeId); // job prep tests { Assert.NotNull(jptei); Assert.Equal(0, jptei.JobPreparationTaskExecutionInformation.RetryCount); Assert.True(beforeJobPrepRuns < jptei.JobPreparationTaskExecutionInformation.StartTime + TimeSpan.FromSeconds(10)); // test that the start time is rational -- 10s of wiggle room Assert.Null(jptei.JobPreparationTaskExecutionInformation.FailureInformation); this.testOutputHelper.WriteLine(""); this.testOutputHelper.WriteLine("listing files for compute node: " + victimComputeNodeRunningPrepAndRelease.Id); // fiter the list so reduce noise List <NodeFile> filteredListJobPrep = new List <NodeFile>(); foreach (NodeFile curTF in victimComputeNodeRunningPrepAndRelease.ListNodeFiles(recursive: true)) { // filter on the jsId since we only run one job per job in this test. if (curTF.Path.IndexOf(boundJobSchedule.Id, StringComparison.InvariantCultureIgnoreCase) >= 0) { this.testOutputHelper.WriteLine(" name:" + curTF.Path + ", size: " + ((curTF.IsDirectory.HasValue && curTF.IsDirectory.Value) ? "<dir>" : curTF.Properties.ContentLength.ToString())); filteredListJobPrep.Add(curTF); } } // confirm resource files made it foreach (ResourceFile curCorrectRF in correctResFiles) { bool found = false; foreach (NodeFile curTF in filteredListJobPrep) { // look for the resfile filepath in the taskfile name found |= curTF.Path.IndexOf(curCorrectRF.FilePath, StringComparison.InvariantCultureIgnoreCase) >= 0; } Assert.True(found, "Looking for resourcefile: " + curCorrectRF.FilePath); } // poll for completion while (JobPreparationTaskState.Completed != jptei.JobPreparationTaskExecutionInformation.State) { this.testOutputHelper.WriteLine("waiting for jopPrep to complete"); Thread.Sleep(2000); // refresh the state info ODATADetailLevel detailLevel = new ODATADetailLevel() { FilterClause = string.Format("nodeId eq '{0}'", victimComputeNodeRunningPrepAndRelease.Id) }; jobPrepStatusList = batchCli.JobOperations.ListJobPreparationAndReleaseTaskStatus(jobId, detailLevel: detailLevel).ToList(); jptei = jobPrepStatusList.First(); } // need success Assert.Equal(0, jptei.JobPreparationTaskExecutionInformation.ExitCode); // check stdout to confirm prep ran //Why do I have to use the hardcoded string job-1 here...? string stdOutFileSpec = Path.Combine("workitems", boundJobSchedule.Id, "job-1", boundJobSchedule.JobSpecification.JobPreparationTask.Id, Constants.StandardOutFileName); string stdOut = victimComputeNodeRunningPrepAndRelease.GetNodeFile(stdOutFileSpec).ReadAsString(); string stdErrFileSpec = Path.Combine("workitems", boundJobSchedule.Id, "job-1", boundJobSchedule.JobSpecification.JobPreparationTask.Id, Constants.StandardErrorFileName); string stdErr = string.Empty; try { stdErr = victimComputeNodeRunningPrepAndRelease.GetNodeFile(stdErrFileSpec).ReadAsString(); } catch (Exception) { //Swallow any exceptions here since stderr may not exist } this.testOutputHelper.WriteLine(stdOut); this.testOutputHelper.WriteLine(stdErr); Assert.True(!string.IsNullOrWhiteSpace(stdOut)); Assert.Contains("jobpreparation", stdOut.ToLower()); } // jobPrep tests completed. let JobPrep complete and task run and wait for JobRelease TaskStateMonitor tsm = batchCli.Utilities.CreateTaskStateMonitor(); // spam/logging interceptor Protocol.RequestInterceptor consoleSpammer = new Protocol.RequestInterceptor((x) => { this.testOutputHelper.WriteLine("TestGetPrepReleaseStatusCalls: waiting for JobPrep and task to complete"); ODATADetailLevel detailLevel = new ODATADetailLevel() { FilterClause = string.Format("nodeId eq '{0}'", victimComputeNodeRunningPrepAndRelease.Id) }; jobPrepStatusList = batchCli.JobOperations.ListJobPreparationAndReleaseTaskStatus(jobId, detailLevel: detailLevel).ToList(); JobPreparationAndReleaseTaskExecutionInformation jpteiInterceptor = jobPrepStatusList.First(); this.testOutputHelper.WriteLine(" JobPrep.State: " + jpteiInterceptor.JobPreparationTaskExecutionInformation.State); this.testOutputHelper.WriteLine(""); }); // waiting for the task to complete means so JobRelease is run. tsm.WaitAll( batchCli.JobOperations.GetJob(jobId).ListTasks(additionalBehaviors: new[] { consoleSpammer }), TaskState.Completed, TimeSpan.FromSeconds(120), additionalBehaviors: new[] { consoleSpammer }); // trigger JobRelease batchCli.JobOperations.TerminateJob(jobId, terminateReason: "die! I want JobRelease to run!"); // now that the task has competed, we are racing with the JobRelease... but it is sleeping so we can can catch it while (true) { ODATADetailLevel detailLevel = new ODATADetailLevel() { FilterClause = string.Format("nodeId eq '{0}'", victimComputeNodeRunningPrepAndRelease.Id) }; jobPrepStatusList = batchCli.JobOperations.ListJobPreparationAndReleaseTaskStatus(jobId, detailLevel: detailLevel).ToList(); JobPreparationAndReleaseTaskExecutionInformation jrtei = jobPrepStatusList.FirstOrDefault(); if ((jrtei == null) || (null == jrtei.JobReleaseTaskExecutionInformation)) { Thread.Sleep(2000); } else { Assert.NotNull(jrtei); if (jrtei.JobReleaseTaskExecutionInformation.State != JobReleaseTaskState.Completed) { this.testOutputHelper.WriteLine("JobReleaseTask state is: " + jrtei.JobReleaseTaskExecutionInformation.State); Thread.Sleep(5000); } else { this.testOutputHelper.WriteLine("JobRelease commpleted!"); // we are done break; } } } } }
public void Bug1480491NodeFileFileProperties() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { string jobId = "Bug1480491Job-" + TestUtilities.GetMyName(); try { const string taskId = "hiWorld"; // // Create the job // CloudJob unboundJob = batchCli.JobOperations.CreateJob(jobId, new PoolInformation()); unboundJob.PoolInformation.PoolId = this.poolFixture.PoolId; unboundJob.Commit(); CloudJob boundJob = batchCli.JobOperations.GetJob(jobId); CloudTask myTask = new CloudTask(taskId, "cmd /c echo hello world"); boundJob.AddTask(myTask); this.testOutputHelper.WriteLine("Initial job commit()"); // // Wait for task to go to completion // Utilities utilities = batchCli.Utilities; TaskStateMonitor taskStateMonitor = utilities.CreateTaskStateMonitor(); taskStateMonitor.WaitAll( boundJob.ListTasks(), Microsoft.Azure.Batch.Common.TaskState.Completed, TimeSpan.FromMinutes(3)); const int expectedFileSize = 13; //Magic number based on output generated by the task // // NodeFile by task // NodeFile file = batchCli.JobOperations.GetNodeFile(jobId, taskId, Constants.StandardOutFileName); this.testOutputHelper.WriteLine("File {0} has content length: {1}", Constants.StandardOutFileName, file.Properties.ContentLength); this.testOutputHelper.WriteLine("File {0} has content type: {1}", Constants.StandardOutFileName, file.Properties.ContentType); this.testOutputHelper.WriteLine("File {0} has creation time: {1}", Constants.StandardOutFileName, file.Properties.CreationTime); this.testOutputHelper.WriteLine("File {0} has last modified time: {1}", Constants.StandardOutFileName, file.Properties.LastModified); Assert.Equal(expectedFileSize, file.Properties.ContentLength); Assert.Equal("text/plain", file.Properties.ContentType); // // NodeFile by node // CloudTask boundTask = boundJob.GetTask(taskId); string computeNodeId = boundTask.ComputeNodeInformation.AffinityId.Split(':')[1]; ComputeNode computeNode = batchCli.PoolOperations.GetComputeNode(this.poolFixture.PoolId, computeNodeId); this.testOutputHelper.WriteLine("Task ran on compute node: {0}", computeNodeId); List <NodeFile> files = computeNode.ListNodeFiles(recursive: true).ToList(); foreach (NodeFile nodeFile in files) { this.testOutputHelper.WriteLine("Found file: {0}", nodeFile.Path); } string filePathToGet = string.Format("workitems/{0}/{1}/{2}/{3}", jobId, "job-1", taskId, Constants.StandardOutFileName); file = computeNode.GetNodeFile(filePathToGet); this.testOutputHelper.WriteLine("File {0} has content length: {1}", filePathToGet, file.Properties.ContentLength); this.testOutputHelper.WriteLine("File {0} has content type: {1}", filePathToGet, file.Properties.ContentType); this.testOutputHelper.WriteLine("File {0} has creation time: {1}", filePathToGet, file.Properties.CreationTime); this.testOutputHelper.WriteLine("File {0} has last modified time: {1}", filePathToGet, file.Properties.LastModified); Assert.Equal(expectedFileSize, file.Properties.ContentLength); Assert.Equal("text/plain", file.Properties.ContentType); } finally { batchCli.JobOperations.DeleteJob(jobId); } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
public void TestNode_GetListDeleteFiles() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { string jobId = "TestNodeGetListDeleteFiles-" + TestUtilities.GetMyName(); try { const string taskId = "hiWorld"; const string directoryCreationTaskId1 = "dirTask1"; const string directoryCreationTaskId2 = "dirTask2"; const string directoryNameOne = "Foo"; const string directoryNameTwo = "Bar"; // // Create the job // CloudJob unboundJob = batchCli.JobOperations.CreateJob(jobId, new PoolInformation()); unboundJob.PoolInformation.PoolId = this.poolFixture.PoolId; unboundJob.Commit(); CloudJob boundJob = batchCli.JobOperations.GetJob(jobId); CloudTask myTask = new CloudTask(taskId, "cmd /c echo hello world"); CloudTask directoryCreationTask1 = new CloudTask(directoryCreationTaskId1, string.Format("cmd /c mkdir {0} && echo test > {0}/testfile.txt", directoryNameOne)); CloudTask directoryCreationTask2 = new CloudTask(directoryCreationTaskId2, string.Format("cmd /c mkdir {0} && echo test > {0}/testfile.txt", directoryNameTwo)); boundJob.AddTask(myTask); boundJob.AddTask(directoryCreationTask1); boundJob.AddTask(directoryCreationTask2); this.testOutputHelper.WriteLine("Initial job commit()"); // // Wait for task to go to completion // Utilities utilities = batchCli.Utilities; TaskStateMonitor taskStateMonitor = utilities.CreateTaskStateMonitor(); taskStateMonitor.WaitAll( boundJob.ListTasks(), Microsoft.Azure.Batch.Common.TaskState.Completed, TimeSpan.FromMinutes(3)); CloudTask boundTask = boundJob.GetTask(taskId); //Since the compute node name comes back as "Node:<computeNodeId>" we need to split on : to get the actual compute node name string computeNodeId = boundTask.ComputeNodeInformation.AffinityId.Split(':')[1]; ComputeNode computeNode = batchCli.PoolOperations.GetComputeNode(this.poolFixture.PoolId, computeNodeId); this.testOutputHelper.WriteLine("Task ran on compute node: {0}", computeNodeId); //Ensure that ListFiles done without a recursive option, or with recursive false return the same values { List <NodeFile> filesByComputeNodeRecursiveOmitted = batchCli.PoolOperations.ListNodeFiles( this.poolFixture.PoolId, computeNodeId).ToList(); List <NodeFile> filesByComputeNodeRecursiveFalse = batchCli.PoolOperations.ListNodeFiles( this.poolFixture.PoolId, computeNodeId, recursive: false).ToList(); AssertFileListsMatch(filesByComputeNodeRecursiveOmitted, filesByComputeNodeRecursiveFalse); } { List <NodeFile> filesByTaskRecursiveOmitted = batchCli.JobOperations.ListNodeFiles( jobId, taskId).ToList(); List <NodeFile> filesByTaskRecursiveFalse = batchCli.JobOperations.ListNodeFiles( jobId, taskId, recursive: false).ToList(); AssertFileListsMatch(filesByTaskRecursiveOmitted, filesByTaskRecursiveFalse); } // // List all node files from operations -- recursive true // //TODO: Detail level? List <NodeFile> fileListFromComputeNodeOperations = batchCli.PoolOperations.ListNodeFiles(this.poolFixture.PoolId, computeNodeId, recursive: true).ToList(); foreach (NodeFile f in fileListFromComputeNodeOperations) { this.testOutputHelper.WriteLine("Found file: {0}", f.Path); } //Check to make sure the expected folder named "Shared" exists Assert.Contains("shared", fileListFromComputeNodeOperations.Select(f => f.Path)); // // List all node files from the compute node -- recursive true // List <NodeFile> fileListFromComputeNode = computeNode.ListNodeFiles(recursive: true).ToList(); foreach (NodeFile f in fileListFromComputeNodeOperations) { this.testOutputHelper.WriteLine("Found file: {0}", f.Path); } //Check to make sure the expected folder named "Shared" exists Assert.Contains("shared", fileListFromComputeNode.Select(f => f.Path)); // // Get file from operations // string filePathToGet = fileListFromComputeNode.First(f => !f.IsDirectory.Value && f.Properties.ContentLength > 0).Path; this.testOutputHelper.WriteLine("Getting file: {0}", filePathToGet); NodeFile computeNodeFileFromManager = batchCli.PoolOperations.GetNodeFile(this.poolFixture.PoolId, computeNodeId, filePathToGet); this.testOutputHelper.WriteLine("Successfully retrieved file: {0}", filePathToGet); this.testOutputHelper.WriteLine("---- File data: ----"); var computeNodeFileContentFromManager = computeNodeFileFromManager.ReadAsString(); this.testOutputHelper.WriteLine(computeNodeFileContentFromManager); Assert.NotEmpty(computeNodeFileContentFromManager); // // Get file directly from operations (bypassing the properties call) // var computeNodeFileContentDirect = batchCli.PoolOperations.CopyNodeFileContentToString(this.poolFixture.PoolId, computeNodeId, filePathToGet); this.testOutputHelper.WriteLine("---- File data: ----"); this.testOutputHelper.WriteLine(computeNodeFileContentDirect); Assert.NotEmpty(computeNodeFileContentDirect); // // Get file from compute node // this.testOutputHelper.WriteLine("Getting file: {0}", filePathToGet); NodeFile fileFromComputeNode = computeNode.GetNodeFile(filePathToGet); this.testOutputHelper.WriteLine("Successfully retrieved file: {0}", filePathToGet); this.testOutputHelper.WriteLine("---- File data: ----"); var computeNodeFileContentFromNode = fileFromComputeNode.ReadAsString(); this.testOutputHelper.WriteLine(computeNodeFileContentFromNode); Assert.NotEmpty(computeNodeFileContentFromNode); // // Get file from compute node (bypassing the properties call) // computeNodeFileContentDirect = computeNode.CopyNodeFileContentToString(filePathToGet); this.testOutputHelper.WriteLine("---- File data: ----"); this.testOutputHelper.WriteLine(computeNodeFileContentDirect); Assert.NotEmpty(computeNodeFileContentDirect); // // NodeFile delete // string filePath = Path.Combine(@"workitems", jobId, "job-1", taskId, Constants.StandardOutFileName); NodeFile nodeFile = batchCli.PoolOperations.GetNodeFile(this.poolFixture.PoolId, computeNodeId, filePath); nodeFile.Delete(); //Ensure delete succeeded TestUtilities.AssertThrows <BatchException>(() => nodeFile.Refresh()); //Delete directory NodeFile directory = batchCli.PoolOperations.ListNodeFiles(this.poolFixture.PoolId, computeNodeId, recursive: true).First(item => item.Path.Contains(directoryNameOne)); Assert.True(directory.IsDirectory); TestUtilities.AssertThrows <BatchException>(() => directory.Delete(recursive: false)); directory.Delete(recursive: true); Assert.Null(batchCli.PoolOperations.ListNodeFiles(this.poolFixture.PoolId, computeNodeId, recursive: true).FirstOrDefault(item => item.Path.Contains(directoryNameOne))); // // PoolManager delete node file // filePath = Path.Combine(@"workitems", jobId, "job-1", taskId, Constants.StandardErrorFileName); NodeFile file = batchCli.JobOperations.GetNodeFile(jobId, taskId, Constants.StandardErrorFileName); batchCli.PoolOperations.DeleteNodeFile(this.poolFixture.PoolId, computeNodeId, filePath); //Ensure delete succeeded TestUtilities.AssertThrows <BatchException>(() => batchCli.JobOperations.GetNodeFile(jobId, taskId, Constants.StandardErrorFileName)); //Delete directory directory = batchCli.PoolOperations.ListNodeFiles(this.poolFixture.PoolId, computeNodeId, recursive: true).First(item => item.Path.Contains(directoryNameTwo)); Assert.True(directory.IsDirectory); TestUtilities.AssertThrows <BatchException>(() => batchCli.PoolOperations.DeleteNodeFile(this.poolFixture.PoolId, computeNodeId, directory.Path, recursive: false)); batchCli.PoolOperations.DeleteNodeFile(this.poolFixture.PoolId, computeNodeId, directory.Path, recursive: true); Assert.Null(batchCli.PoolOperations.ListNodeFiles(this.poolFixture.PoolId, computeNodeId, recursive: true).FirstOrDefault(item => item.Path.Contains(directoryNameTwo))); } finally { batchCli.JobOperations.DeleteJob(jobId); } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
/// <summary> /// Draws an individual compute node cell /// </summary> /// <param name="maxTasks"></param> /// <param name="nodeInfo"></param> /// <returns></returns> private UIElement DrawVMCell(int maxTasks, ComputeNode nodeInfo) { UIElement heatmapCell = null; ComputeNodeUIStates uiState; // Map all the node states onto few UI states/colors switch (nodeInfo.State) { case ComputeNodeState.Creating: case ComputeNodeState.LeavingPool: case ComputeNodeState.Rebooting: case ComputeNodeState.Reimaging: case ComputeNodeState.Starting: case ComputeNodeState.WaitingForStartTask: uiState = ComputeNodeUIStates.Transitioning; break; case ComputeNodeState.Idle: uiState = ComputeNodeUIStates.Idle; break; case ComputeNodeState.StartTaskFailed: case ComputeNodeState.Unknown: case ComputeNodeState.Unusable: uiState = ComputeNodeUIStates.Error; break; case ComputeNodeState.Running: uiState = ComputeNodeUIStates.Running; break; default: uiState = ComputeNodeUIStates.Unknown; break; } // Use one rectangle for a node if MaxTasksPerComputeNode is one or node can't be used if (maxTasks == 1 || uiState == ComputeNodeUIStates.Transitioning || uiState == ComputeNodeUIStates.Error || uiState == ComputeNodeUIStates.Unknown) { Brush nodeColor; Rectangle nodeRect = new Rectangle(); nodeRect.Margin = new Thickness(2); switch (uiState) { case ComputeNodeUIStates.Error: nodeColor = Brushes.Red; break; case ComputeNodeUIStates.Idle: nodeColor = Brushes.White; break; case ComputeNodeUIStates.Running: nodeColor = Brushes.LightGreen; break; case ComputeNodeUIStates.Transitioning: nodeColor = Brushes.Yellow; break; case ComputeNodeUIStates.Unknown: nodeColor = Brushes.Orange; break; default: nodeColor = Brushes.Orange; break; } nodeRect.Fill = nodeColor; nodeRect.StrokeThickness = 0.5; nodeRect.Stroke = Brushes.Gray; nodeRect.ToolTip = nodeInfo.State.ToString(); heatmapCell = nodeRect; } else { // MaxTasksPerComputeNode > 1 and compute node in state where could have tasks running // Have a grid to represent max number of tasks the compute node can run at a time // Determine number of running tasks for the compute node int numRunningTasks = 0; IEnumerable <TaskInformation> taskInfoList = nodeInfo.RecentTasks; if (taskInfoList != null) { foreach (TaskInformation ti in taskInfoList) { if (ti.TaskState == TaskState.Running) { numRunningTasks++; } } } // Create the Grid control Grid nodeGrid = new Grid(); nodeGrid.Margin = new Thickness(2); // Calculate grid dimensions int numRows = (int)Math.Sqrt(maxTasks); int numCols = (int)Math.Truncate((maxTasks + 0.5) / numRows); // Add grid rows and columns for (int i = 0; i < numRows; i++) { RowDefinition rowDef = new RowDefinition(); nodeGrid.RowDefinitions.Add(rowDef); } for (int i = 0; i < numCols; i++) { ColumnDefinition colDef = new ColumnDefinition(); nodeGrid.ColumnDefinitions.Add(colDef); } // Turn appropriate number of cells green according to running number of tasks int cellCount = 0; for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { Rectangle task = new Rectangle(); task.Stroke = Brushes.Gray; task.StrokeThickness = 0.5; if (cellCount < numRunningTasks) { task.Fill = Brushes.LightGreen; } else { task.Fill = Brushes.White; } Grid.SetRow(task, row); Grid.SetColumn(task, col); nodeGrid.Children.Add(task); cellCount++; } } heatmapCell = nodeGrid; } return(heatmapCell); }
/// <summary> /// Draws an individual compute node cell /// </summary> /// <param name="maxTasks"></param> /// <param name="nodeInfo"></param> /// <returns></returns> private UIElement DrawVMCell(int maxTasks, ComputeNode nodeInfo) { UIElement heatmapCell = null; ComputeNodeUIStates uiState; // Map all the node states onto few UI states/colors switch (nodeInfo.State) { case ComputeNodeState.Creating: case ComputeNodeState.LeavingPool: case ComputeNodeState.Rebooting: case ComputeNodeState.Reimaging: case ComputeNodeState.Starting: case ComputeNodeState.WaitingForStartTask: uiState = ComputeNodeUIStates.Transitioning; break; case ComputeNodeState.Idle: uiState = ComputeNodeUIStates.Idle; break; case ComputeNodeState.StartTaskFailed: case ComputeNodeState.Unknown: case ComputeNodeState.Unusable: uiState = ComputeNodeUIStates.Error; break; case ComputeNodeState.Running: uiState = ComputeNodeUIStates.Running; break; default: uiState = ComputeNodeUIStates.Unknown; break; } // Use one rectangle for a node if MaxTasksPerComputeNode is one or node can't be used if (maxTasks == 1 || uiState == ComputeNodeUIStates.Transitioning || uiState == ComputeNodeUIStates.Error || uiState == ComputeNodeUIStates.Unknown) { Brush nodeColor; Rectangle nodeRect = new Rectangle(); nodeRect.Margin = new Thickness(2); switch (uiState) { case ComputeNodeUIStates.Error: nodeColor = Brushes.Red; break; case ComputeNodeUIStates.Idle: nodeColor = Brushes.White; break; case ComputeNodeUIStates.Running: nodeColor = Brushes.LightGreen; break; case ComputeNodeUIStates.Transitioning: nodeColor = Brushes.Yellow; break; case ComputeNodeUIStates.Unknown: nodeColor = Brushes.Orange; break; default: nodeColor = Brushes.Orange; break; } nodeRect.Fill = nodeColor; nodeRect.StrokeThickness = 0.5; nodeRect.Stroke = Brushes.Gray; nodeRect.ToolTip = nodeInfo.State.ToString(); heatmapCell = nodeRect; } else { // MaxTasksPerComputeNode > 1 and compute node in state where could have tasks running // Have a grid to represent max number of tasks the compute node can run at a time // Determine number of running tasks for the compute node int numRunningTasks = 0; IEnumerable<TaskInformation> taskInfoList = nodeInfo.RecentTasks; if (taskInfoList != null) { foreach (TaskInformation ti in taskInfoList) { if (ti.TaskState == TaskState.Running) { numRunningTasks++; } } } // Create the Grid control Grid nodeGrid = new Grid(); nodeGrid.Margin = new Thickness(2); // Calculate grid dimensions int numRows = (int)Math.Sqrt(maxTasks); int numCols = (int)Math.Truncate((maxTasks + 0.5) / numRows); // Add grid rows and columns for (int i = 0; i < numRows; i++) { RowDefinition rowDef = new RowDefinition(); nodeGrid.RowDefinitions.Add(rowDef); } for (int i = 0; i < numCols; i++) { ColumnDefinition colDef = new ColumnDefinition(); nodeGrid.ColumnDefinitions.Add(colDef); } // Turn appropriate number of cells green according to running number of tasks int cellCount = 0; for (int row = 0; row < numRows; row++) { for (int col = 0; col < numCols; col++) { Rectangle task = new Rectangle(); task.Stroke = Brushes.Gray; task.StrokeThickness = 0.5; if (cellCount < numRunningTasks) { task.Fill = Brushes.LightGreen; } else { task.Fill = Brushes.White; } Grid.SetRow(task, row); Grid.SetColumn(task, col); nodeGrid.Children.Add(task); cellCount++; } } heatmapCell = nodeGrid; } return heatmapCell; }
public ComputeNodeModel(PoolModel parentPool, ComputeNode computeNode) { this.ComputeNode = computeNode; this.ParentPool = parentPool; this.LastUpdatedTime = DateTime.UtcNow; }
public static async Task MainAsync() { const string poolId = "MultiInstanceSamplePool"; const string jobId = "MultiInstanceSampleJob"; const string taskId = "MultiInstanceSampleTask"; const int numberOfNodes = 5; //jmeno package kterou uploaduju na azure s polu s MSMpiSetup const string appPackageId = "Parallel"; const string appPackageVersion = "1.0"; TimeSpan timeout = TimeSpan.FromMinutes(15); AccountSettings accountSettings = SampleHelpers.LoadAccountSettings(); //nakonfigurované batch accounty abych se mohl připojit ke svému účtu BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials( accountSettings.BatchServiceUrl, accountSettings.BatchAccountName, accountSettings.BatchAccountKey); using (BatchClient batchClient = BatchClient.Open(cred)) { // Vytvoření fondu výpočetních uzlů a úlohu, do které přidáme úlohu s více instancemi. await CreatePoolAsync(batchClient, poolId, numberOfNodes, appPackageId, appPackageVersion); await CreateJobAsync(batchClient, jobId, poolId); //batch vytvoří jednu hlavní a několik dílčích úkolů CloudTask multiInstanceTask = new CloudTask(id: taskId, commandline: $"cmd /c mpiexec.exe -c 1 -wdir %AZ_BATCH_TASK_SHARED_DIR% %AZ_BATCH_APP_PACKAGE_{appPackageId.ToUpper()}#{appPackageVersion}%\\ParallelMpiApp.exe"); // příkaz SPMD = více samostatných procesorů současně spouští stejný program multiInstanceTask.MultiInstanceSettings = new MultiInstanceSettings(@"cmd /c start cmd /c smpd.exe -d", numberOfNodes); //zadání úkolů, vytvoří se jeden primární a několik dílčích, //aby odpovídaly počtu uzlů a naplánuje se jejich provedení v uzlech Console.WriteLine($"Adding task [{taskId}] to job [{jobId}]..."); await batchClient.JobOperations.AddTaskAsync(jobId, multiInstanceTask); //verze úlohy CloudTask mainTask = await batchClient.JobOperations.GetTaskAsync(jobId, taskId); // sledování stavu úkolů,čekáme až bude úloha dokončena Console.WriteLine($"Awaiting task completion, timeout in {timeout}..."); TaskStateMonitor taskStateMonitor = batchClient.Utilities.CreateTaskStateMonitor(); await taskStateMonitor.WhenAll(new List <CloudTask> { mainTask }, TaskState.Completed, timeout); //aktualizace úlohy await mainTask.RefreshAsync(); string stdOut = mainTask.GetNodeFile(Constants.StandardOutFileName).ReadAsString(); string stdErr = mainTask.GetNodeFile(Constants.StandardErrorFileName).ReadAsString(); Console.WriteLine(); Console.WriteLine($"Main task [{mainTask.Id}] is in state [{mainTask.State}] and ran on compute node [{mainTask.ComputeNodeInformation.ComputeNodeId}]:"); Console.WriteLine("---- stdout.txt ----"); Console.WriteLine(stdOut); Console.WriteLine("---- stderr.txt ----"); Console.WriteLine(stdErr); // par sekund čas aby se stačily dílčí úlohy dokončit TimeSpan subtaskTimeout = TimeSpan.FromSeconds(10); Console.WriteLine($"Main task completed, waiting {subtaskTimeout} for subtasks to complete..."); System.Threading.Thread.Sleep(subtaskTimeout); Console.WriteLine(); Console.WriteLine("---- Subtask information ----"); //kolekce dílčích úlohů a tisk informací o každém IPagedEnumerable <SubtaskInformation> subtasks = mainTask.ListSubtasks(); await subtasks.ForEachAsync(async (subtask) => { Console.WriteLine("subtask: " + subtask.Id); Console.WriteLine("\texit code: " + subtask.ExitCode); if (subtask.State == SubtaskState.Completed) { //získání souborů z uzlů ComputeNode node = await batchClient.PoolOperations.GetComputeNodeAsync(subtask.ComputeNodeInformation.PoolId, subtask.ComputeNodeInformation.ComputeNodeId); string outPath = subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardOutFileName; string errPath = subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardErrorFileName; NodeFile stdOutFile = await node.GetNodeFileAsync(outPath.Trim('\\')); NodeFile stdErrFile = await node.GetNodeFileAsync(errPath.Trim('\\')); stdOut = await stdOutFile.ReadAsStringAsync(); stdErr = await stdErrFile.ReadAsStringAsync(); Console.WriteLine($"\tnode: " + node.Id); Console.WriteLine("\tstdout.txt: " + stdOut); Console.WriteLine("\tstderr.txt: " + stdErr); } else { Console.WriteLine($"\tSubtask {subtask.Id} is in state {subtask.State}"); } }); // vymazání zdrojů které jsme vytvořili, abychom to nemuseli dělat manuálně(fondy,úlohy) Console.WriteLine(); Console.Write("Delete job? [yes] no: "); string response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { await batchClient.JobOperations.DeleteJobAsync(jobId); } Console.Write("Delete pool? [yes] no: "); response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { await batchClient.PoolOperations.DeletePoolAsync(poolId); } } }
public async Task OnlineOfflineTest() { await SynchronizationContextHelper.RunTestAsync(async() => { using (BatchClient batchCli = await TestUtilities.OpenBatchClientFromEnvironmentAsync()) { TimeSpan refreshPollingTimeout = TimeSpan.FromMinutes(3); CloudPool pool = this.poolFixture.Pool; List <ComputeNode> nodes = pool.ListComputeNodes().ToList(); Assert.True(nodes.Count > 0); // pick a victim compute node. cleanup code needs this set ComputeNode victim = nodes[0]; try { Assert.True(victim.SchedulingState.HasValue && (SchedulingState.Enabled == victim.SchedulingState)); Assert.True(victim.State.HasValue && (ComputeNodeState.Idle == victim.State)); // PoolOperations methods { // disable task scheduling batchCli.PoolOperations.DisableComputeNodeScheduling(pool.Id, victim.Id, DisableComputeNodeSchedulingOption.Terminate); // Li says state change is not atomic so we will sleep // asserted above this node is idle so no need to wait for task fussery await TestUtilities.RefreshBasedPollingWithTimeoutAsync( refreshing: victim, condition: () => Task.FromResult(victim.SchedulingState.HasValue && (SchedulingState.Disabled == victim.SchedulingState)), timeout: refreshPollingTimeout).ConfigureAwait(false); Assert.Equal <SchedulingState?>(SchedulingState.Disabled, victim.SchedulingState); // enable task scheduling batchCli.PoolOperations.EnableComputeNodeScheduling(pool.Id, victim.Id); await TestUtilities.RefreshBasedPollingWithTimeoutAsync( refreshing: victim, condition: () => Task.FromResult(victim.SchedulingState.HasValue && (SchedulingState.Enabled == victim.SchedulingState)), timeout: refreshPollingTimeout); Assert.Equal <SchedulingState?>(SchedulingState.Enabled, victim.SchedulingState); } // ComputeNode methods { // disable task scheduling victim.DisableScheduling(DisableComputeNodeSchedulingOption.TaskCompletion); await TestUtilities.RefreshBasedPollingWithTimeoutAsync( refreshing: victim, condition: () => Task.FromResult(victim.SchedulingState.HasValue && (SchedulingState.Disabled == victim.SchedulingState)), timeout: refreshPollingTimeout).ConfigureAwait(false); Assert.Equal <SchedulingState?>(SchedulingState.Disabled, victim.SchedulingState); // enable task scheduling victim.EnableScheduling(); await TestUtilities.RefreshBasedPollingWithTimeoutAsync( refreshing: victim, condition: () => Task.FromResult(victim.SchedulingState.HasValue && (SchedulingState.Enabled == victim.SchedulingState)), timeout: refreshPollingTimeout).ConfigureAwait(false); Assert.Equal <SchedulingState?>(SchedulingState.Enabled, victim.SchedulingState); // now test azureerror code for: NodeAlreadyInTargetSchedulingState bool gotCorrectException = false; try { victim.EnableScheduling(); // it is already enabled so this should trigger exception } catch (Exception ex) { TestUtilities.AssertIsBatchExceptionAndHasCorrectAzureErrorCode(ex, Microsoft.Azure.Batch.Common.BatchErrorCodeStrings.NodeAlreadyInTargetSchedulingState, this.testOutputHelper); gotCorrectException = true; } if (!gotCorrectException) { throw new Exception("OnlineOfflineTest: failed to see an exception for NodeAlreadyInTargetSchedulingState test"); } } } finally // restore state of victim compute node { try { // do not pollute the shared pool with disabled scheduling if (null != victim) { victim.EnableScheduling(); } } catch (Exception ex) { this.testOutputHelper.WriteLine(string.Format("OnlineOfflineTest: exception during exit trying to restore scheduling state: {0}", ex.ToString())); } } } }, TestTimeout); }
public void Bug1770933_1770935_1771164_AddUserCRUDAndGetRDP() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { // names to create/delete List <string> names = new List <string>() { TestUtilities.GetMyName(), TestUtilities.GetMyName() + "1", TestUtilities.GetMyName() + "2", TestUtilities.GetMyName() + "3", TestUtilities.GetMyName() + "4" }; // pick a compute node to victimize with user accounts IEnumerable <ComputeNode> ienmComputeNodes = batchCli.PoolOperations.ListComputeNodes(this.poolFixture.PoolId); List <ComputeNode> computeNodeList = new List <ComputeNode>(ienmComputeNodes); ComputeNode computeNode = computeNodeList[0]; try { string rdpFileName = "Bug1770933.rdp"; // test user public constructor and IPoolMgr verbs { ComputeNodeUser newUser = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); newUser.Name = names[0]; newUser.IsAdmin = true; newUser.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(1.0); newUser.Password = @"!!Admin!!"; // commit that creates/adds the user newUser.Commit(ComputeNodeUserCommitSemantics.AddUser); // now update the user's password newUser.Password = @"!!!Admin!!!"; // commit that updates newUser.Commit(ComputeNodeUserCommitSemantics.UpdateUser); // clean up from prev run if (File.Exists(rdpFileName)) { File.Delete(rdpFileName); } // pull the rdp file batchCli.PoolOperations.GetRDPFile(this.poolFixture.PoolId, computeNode.Id, rdpFileName); // simple validation tests on the rdp file TestFileExistsAndHasLength(rdpFileName); // cleanup the rdp file File.Delete(rdpFileName); // "test" delete user from IPoolMgr // TODO: when GET/LIST User is available we should close the loop and confirm the user is gone. batchCli.PoolOperations.DeleteComputeNodeUser(this.poolFixture.PoolId, computeNode.Id, newUser.Name); } // test IPoolMgr CreateUser { ComputeNodeUser pmcUser = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); pmcUser.Name = names[1]; pmcUser.IsAdmin = true; pmcUser.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(1.0); pmcUser.Password = @"!!!Admin!!!"; // add the user pmcUser.Commit(ComputeNodeUserCommitSemantics.AddUser); // pull rdp file batchCli.PoolOperations.GetRDPFile(this.poolFixture.PoolId, computeNode.Id, rdpFileName); // simple validation on rdp file TestFileExistsAndHasLength(rdpFileName); // cleanup File.Delete(rdpFileName); // delete user batchCli.PoolOperations.DeleteComputeNodeUser(this.poolFixture.PoolId, computeNode.Id, pmcUser.Name); } // test IComputeNode verbs { ComputeNodeUser poolMgrUser = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); poolMgrUser.Name = names[2]; poolMgrUser.IsAdmin = true; poolMgrUser.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(1.0); poolMgrUser.Password = @"!!!Admin!!!"; poolMgrUser.Commit(ComputeNodeUserCommitSemantics.AddUser); // pull rdp file computeNode.GetRDPFile(rdpFileName); // simple validation on rdp file TestFileExistsAndHasLength(rdpFileName); // cleanup File.Delete(rdpFileName); // delete user computeNode.DeleteComputeNodeUser(poolMgrUser.Name); } // test ComputeNodeUser.Delete { ComputeNodeUser usrDelete = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); usrDelete.Name = names[3]; usrDelete.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(1.0); usrDelete.Password = @"!!!Admin!!!"; usrDelete.Commit(ComputeNodeUserCommitSemantics.AddUser); usrDelete.Delete(); } // test rdp-by-stream IPoolMgr and IComputeNode // the by-stream paths do not converge with the by-filename paths until IProtocol so we test them seperately { ComputeNodeUser byStreamUser = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); byStreamUser.Name = names[4]; byStreamUser.IsAdmin = true; byStreamUser.ExpiryTime = DateTime.UtcNow + TimeSpan.FromHours(1.0); byStreamUser.Password = @"!!!Admin!!!"; byStreamUser.Commit(ComputeNodeUserCommitSemantics.AddUser); // IPoolMgr using (Stream rdpStreamPoolMgr = File.Create(rdpFileName)) { batchCli.PoolOperations.GetRDPFile(this.poolFixture.PoolId, computeNode.Id, rdpStreamPoolMgr); rdpStreamPoolMgr.Flush(); rdpStreamPoolMgr.Close(); TestFileExistsAndHasLength(rdpFileName); File.Delete(rdpFileName); } // IComputeNode using (Stream rdpViaIComputeNode = File.Create(rdpFileName)) { computeNode.GetRDPFile(rdpViaIComputeNode); rdpViaIComputeNode.Flush(); rdpViaIComputeNode.Close(); TestFileExistsAndHasLength(rdpFileName); File.Delete(rdpFileName); } // delete the user account byStreamUser.Delete(); } } finally { // clear any old accounts foreach (string curName in names) { bool hitException = false; try { ComputeNodeUser deleteThis = batchCli.PoolOperations.CreateComputeNodeUser(this.poolFixture.PoolId, computeNode.Id); deleteThis.Name = curName; deleteThis.Delete(); } catch (BatchException ex) { Assert.Equal(BatchErrorCodeStrings.NodeUserNotFound, ex.RequestInformation.BatchError.Code); hitException = true; } Assert.True(hitException, "Should have hit exception on user: "******", compute node: " + computeNode.Id + "."); } } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
public void Bug2329884_ComputeNodeRecentTasksAndComputeNodeError() { Action test = () => { using (BatchClient batchCli = TestUtilities.OpenBatchClientAsync(TestUtilities.GetCredentialsFromEnvironment()).Result) { string jobId = "Bug2329884Job-" + TestUtilities.GetMyName(); Protocol.RequestInterceptor interceptor = null; try { const string taskId = "hiWorld"; // // Create the job // CloudJob unboundJob = batchCli.JobOperations.CreateJob(jobId, new PoolInformation()); unboundJob.PoolInformation.PoolId = this.poolFixture.PoolId; unboundJob.Commit(); CloudJob boundJob = batchCli.JobOperations.GetJob(jobId); CloudTask myTask = new CloudTask(taskId, "cmd /c echo hello world"); boundJob.AddTask(myTask); this.testOutputHelper.WriteLine("Initial job commit()"); // // Wait for task to go to completion // Utilities utilities = batchCli.Utilities; TaskStateMonitor taskStateMonitor = utilities.CreateTaskStateMonitor(); taskStateMonitor.WaitAll( boundJob.ListTasks(), Microsoft.Azure.Batch.Common.TaskState.Completed, new TimeSpan(0, 3 /*min*/, 0)); CloudTask boundTask = boundJob.GetTask(taskId); //Since the compute node name comes back as "Node:<computeNodeId>" we need to split on : to get the actual compute node name string computeNodeId = boundTask.ComputeNodeInformation.AffinityId.Split(':')[1]; // // Check recent tasks // ComputeNode computeNode = batchCli.PoolOperations.GetComputeNode(this.poolFixture.PoolId, computeNodeId); this.testOutputHelper.WriteLine("Recent tasks:"); foreach (TaskInformation recentTask in computeNode.RecentTasks) { this.testOutputHelper.WriteLine("Compute node has recent task Job: {0}, Task: {1}, State: {2}, Subtask: {3}", recentTask.JobId, recentTask.TaskId, recentTask.TaskState, recentTask.SubtaskId); } TaskInformation myTaskInfo = computeNode.RecentTasks.First(taskInfo => taskInfo.JobId.Equals( jobId, StringComparison.InvariantCultureIgnoreCase) && taskInfo.TaskId.Equals(taskId, StringComparison.InvariantCultureIgnoreCase)); Assert.Equal(TaskState.Completed, myTaskInfo.TaskState); Assert.NotNull(myTaskInfo.ExecutionInformation); Assert.Equal(0, myTaskInfo.ExecutionInformation.ExitCode); // // Check compute node Error // const string expectedErrorCode = "TestErrorCode"; const string expectedErrorMessage = "Test error message"; const string nvpValue = "Test"; //We use mocking to return a fake compute node object here to test Compute Node Error because we cannot force one easily interceptor = new Protocol.RequestInterceptor((req => { if (req is ComputeNodeGetBatchRequest) { var typedRequest = req as ComputeNodeGetBatchRequest; typedRequest.ServiceRequestFunc = (token) => { var response = new AzureOperationResponse <Protocol.Models.ComputeNode, Protocol.Models.ComputeNodeGetHeaders>(); List <Protocol.Models.ComputeNodeError> errors = new List <Protocol.Models.ComputeNodeError>(); //Generate first Compute Node Error List <Protocol.Models.NameValuePair> nvps = new List <Protocol.Models.NameValuePair>(); nvps.Add(new Protocol.Models.NameValuePair() { Name = nvpValue, Value = nvpValue }); Protocol.Models.ComputeNodeError error1 = new Protocol.Models.ComputeNodeError(); error1.Code = expectedErrorCode; error1.Message = expectedErrorMessage; error1.ErrorDetails = nvps; errors.Add(error1); //Generate second Compute Node Error nvps = new List <Protocol.Models.NameValuePair>(); nvps.Add(new Protocol.Models.NameValuePair() { Name = nvpValue, Value = nvpValue }); Protocol.Models.ComputeNodeError error2 = new Protocol.Models.ComputeNodeError(); error2.Code = expectedErrorCode; error2.Message = expectedErrorMessage; error2.ErrorDetails = nvps; errors.Add(error2); Protocol.Models.ComputeNode protoComputeNode = new Protocol.Models.ComputeNode(); protoComputeNode.Id = computeNodeId; protoComputeNode.State = Protocol.Models.ComputeNodeState.Idle; protoComputeNode.Errors = errors; response.Body = protoComputeNode; return(Task.FromResult(response)); }; } })); batchCli.PoolOperations.CustomBehaviors.Add(interceptor); computeNode = batchCli.PoolOperations.GetComputeNode(this.poolFixture.PoolId, computeNodeId); Assert.Equal(computeNodeId, computeNode.Id); Assert.NotNull(computeNode.Errors); Assert.Equal(2, computeNode.Errors.Count()); foreach (ComputeNodeError computeNodeError in computeNode.Errors) { Assert.Equal(expectedErrorCode, computeNodeError.Code); Assert.Equal(expectedErrorMessage, computeNodeError.Message); Assert.NotNull(computeNodeError.ErrorDetails); Assert.Equal(1, computeNodeError.ErrorDetails.Count()); Assert.Contains(nvpValue, computeNodeError.ErrorDetails.First().Name); } } finally { batchCli.JobOperations.DeleteJob(jobId); } } }; SynchronizationContextHelper.RunTest(test, TestTimeout); }
public static async Task MainAsync() { const string poolId = "MultiInstanceSamplePool"; const string jobId = "MultiInstanceSampleJob"; const string taskId = "MultiInstanceSampleTask"; const int numberOfNodes = 3; // The application package and version to deploy to the compute nodes. // It should contain your MPIHelloWorld sample MS-MPI program: // https://blogs.technet.microsoft.com/windowshpc/2015/02/02/how-to-compile-and-run-a-simple-ms-mpi-program/ // And the MSMpiSetup.exe installer: // https://www.microsoft.com/download/details.aspx?id=52981 // Then upload it as an application package: // https://azure.microsoft.com/documentation/articles/batch-application-packages/ const string appPackageId = "MPIHelloWorld"; const string appPackageVersion = "1.0"; TimeSpan timeout = TimeSpan.FromMinutes(30); // Configure your AccountSettings in the Microsoft.Azure.Batch.Samples.Common project within this solution BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(AccountSettings.Default.BatchServiceUrl, AccountSettings.Default.BatchAccountName, AccountSettings.Default.BatchAccountKey); using (BatchClient batchClient = BatchClient.Open(cred)) { // Create the pool of compute nodes and the job to which we add the multi-instance task. await CreatePoolAsync(batchClient, poolId, numberOfNodes, appPackageId, appPackageVersion); await CreateJobAsync(batchClient, jobId, poolId); // Create the multi-instance task. The MultiInstanceSettings property (configured // below) tells Batch to create one primary and several subtasks, the total number // of which matches the number of instances you specify in the MultiInstanceSettings. // This main task's command line is the "application command," and is executed *only* // by the primary, and only after the primary and all subtasks have executed the // "coordination command" (the MultiInstanceSettings.CoordinationCommandLine). CloudTask multiInstanceTask = new CloudTask(id: taskId, commandline: $"cmd /c mpiexec.exe -c 1 -wdir %AZ_BATCH_TASK_SHARED_DIR% %AZ_BATCH_APP_PACKAGE_{appPackageId.ToUpper()}#{appPackageVersion}%\\MPIHelloWorld.exe"); // Configure the task's MultiInstanceSettings. Specify the number of nodes // to allocate to the multi-instance task, and the "coordination command". // The CoordinationCommandLine is run by the primary and subtasks, and is // used in this sample to start SMPD on the compute nodes. multiInstanceTask.MultiInstanceSettings = new MultiInstanceSettings(@"cmd /c start cmd /c smpd.exe -d", numberOfNodes); // Submit the task to the job. Batch will take care of creating one primary and // enough subtasks to match the total number of nodes allocated to the task, // and schedule them for execution on the nodes. Console.WriteLine($"Adding task [{taskId}] to job [{jobId}]..."); await batchClient.JobOperations.AddTaskAsync(jobId, multiInstanceTask); // Get the "bound" version of the multi-instance task. CloudTask mainTask = await batchClient.JobOperations.GetTaskAsync(jobId, taskId); // We use a TaskStateMonitor to monitor the state of our tasks. In this case, // we will wait for the task to reach the Completed state. Console.WriteLine($"Awaiting task completion, timeout in {timeout}..."); TaskStateMonitor taskStateMonitor = batchClient.Utilities.CreateTaskStateMonitor(); await taskStateMonitor.WhenAll(new List <CloudTask> { mainTask }, TaskState.Completed, timeout); // Refresh the task to obtain up-to-date property values from Batch, such as // its current state and information about the node on which it executed. await mainTask.RefreshAsync(); string stdOut = mainTask.GetNodeFile(Constants.StandardOutFileName).ReadAsString(); string stdErr = mainTask.GetNodeFile(Constants.StandardErrorFileName).ReadAsString(); Console.WriteLine(); Console.WriteLine($"Main task [{mainTask.Id}] is in state [{mainTask.State}] and ran on compute node [{mainTask.ComputeNodeInformation.ComputeNodeId}]:"); Console.WriteLine("---- stdout.txt ----"); Console.WriteLine(stdOut); Console.WriteLine("---- stderr.txt ----"); Console.WriteLine(stdErr); // Need to delay a bit to allow the Batch service to mark the subtasks as Complete TimeSpan subtaskTimeout = TimeSpan.FromSeconds(10); Console.WriteLine($"Main task completed, waiting {subtaskTimeout} for subtasks to complete..."); System.Threading.Thread.Sleep(subtaskTimeout); Console.WriteLine(); Console.WriteLine("---- Subtask information ----"); // Obtain the collection of subtasks for the multi-instance task, and print // some information about each. IPagedEnumerable <SubtaskInformation> subtasks = mainTask.ListSubtasks(); await subtasks.ForEachAsync(async (subtask) => { Console.WriteLine("subtask: " + subtask.Id); Console.WriteLine("\texit code: " + subtask.ExitCode); if (subtask.State == SubtaskState.Completed) { // Obtain the file from the node on which the subtask executed. For normal CloudTasks, // we could simply call CloudTask.GetNodeFile(Constants.StandardOutFileName), but the // subtasks are not "normal" tasks in Batch, and thus must be handled differently. ComputeNode node = await batchClient.PoolOperations.GetComputeNodeAsync(subtask.ComputeNodeInformation.PoolId, subtask.ComputeNodeInformation.ComputeNodeId); string outPath = subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardOutFileName; string errPath = subtask.ComputeNodeInformation.TaskRootDirectory + "\\" + Constants.StandardErrorFileName; NodeFile stdOutFile = await node.GetNodeFileAsync(outPath.Trim('\\')); NodeFile stdErrFile = await node.GetNodeFileAsync(errPath.Trim('\\')); stdOut = await stdOutFile.ReadAsStringAsync(); stdErr = await stdErrFile.ReadAsStringAsync(); Console.WriteLine($"\tnode: " + node.Id); Console.WriteLine("\tstdout.txt: " + stdOut); Console.WriteLine("\tstderr.txt: " + stdErr); } else { Console.WriteLine($"\tSubtask {subtask.Id} is in state {subtask.State}"); } }); // Clean up the resources we've created in the Batch account Console.WriteLine(); Console.Write("Delete job? [yes] no: "); string response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { await batchClient.JobOperations.DeleteJobAsync(jobId); } Console.Write("Delete pool? [yes] no: "); response = Console.ReadLine().ToLower(); if (response != "n" && response != "no") { await batchClient.PoolOperations.DeletePoolAsync(poolId); } } }