From a3c82408a8035c51f1b61b73e06fc54eca7db93a Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Wed, 16 Oct 2024 13:38:35 +0200 Subject: [PATCH 1/6] feat: tpu_queued_resources_create --- tpu/package.json | 23 ++++ tpu/queuedResource/createQueuedResource.js | 123 ++++++++++++++++++ tpu/queuedResource/deleteQueuedResource.js | 59 +++++++++ .../forceDeleteQueuedResource.js | 60 +++++++++ tpu/test/queuedResource.test.js | 59 +++++++++ 5 files changed, 324 insertions(+) create mode 100644 tpu/queuedResource/createQueuedResource.js create mode 100644 tpu/queuedResource/deleteQueuedResource.js create mode 100644 tpu/queuedResource/forceDeleteQueuedResource.js create mode 100644 tpu/test/queuedResource.test.js diff --git a/tpu/package.json b/tpu/package.json index 9ac90ca084..0c9fe9d005 100644 --- a/tpu/package.json +++ b/tpu/package.json @@ -22,3 +22,26 @@ "mocha": "^10.0.0" } } +{ + "name": "nodejs-docs-samples-tpu", + "license": "Apache-2.0", + "author": "Google Inc.", + "engines": { + "node": ">=16.0.0" + }, + "repository": "googleapis/nodejs-tpu", + "private": true, + "files": [ + "*.js" + ], + "scripts": { + "test": "c8 mocha -p -j 2 test --timeout 1200000" + }, + "dependencies": { + "@google-cloud/tpu": "^3.5.0" + }, + "devDependencies": { + "c8": "^10.0.0", + "mocha": "^10.0.0" + } +} diff --git a/tpu/queuedResource/createQueuedResource.js b/tpu/queuedResource/createQueuedResource.js new file mode 100644 index 0000000000..8dd06f7762 --- /dev/null +++ b/tpu/queuedResource/createQueuedResource.js @@ -0,0 +1,123 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main( + nodeName, + queuedResourceName, + zone, + tpuType, + tpuSoftwareVersion +) { + // [START tpu_queued_resources_create] + // Import the TPU library + const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + const {Node, NetworkConfig, QueuedResource} = + require('@google-cloud/tpu').protos.google.cloud.tpu.v2alpha1; + + // Instantiate a tpuClient + const tpuClient = new TpuClient(); + + /** + * TODO(developer): Update/uncomment these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project, where you want to create queued resource. + const projectId = await tpuClient.getProjectId(); + + // The name of the network you want the node to connect to. The network should be assigned to your project. + const networkName = 'compute-tpu-network'; + + // The region of the network, that you want the node to connect to. + const region = 'europe-west4'; + + // The name for your queued resource. + // queuedResourceName = 'queued-resource-1'; + + // The name for your node. + // nodeName = 'node-name-1'; + + // The zone in which to create the node. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + // zone = 'europe-west4-a'; + + // The accelerator type that specifies the version and size of the node you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + // tpuType = 'v2-8'; + + // Software version that specifies the version of the node runtime to install. For more information, + // see https://cloud.google.com/tpu/docs/runtimes + // tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; + + async function callCreateQueuedResource() { + // Create a node + const node = new Node({ + name: nodeName, + zone, + acceleratorType: tpuType, + runtimeVersion: tpuSoftwareVersion, + // Define network + networkConfig: new NetworkConfig({ + enableExternalIps: true, + network: `projects/${projectId}/global/networks/${networkName}`, + subnetwork: `projects/${projectId}/regions/${region}/subnetworks/${networkName}`, + }), + queuedResource: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }); + + // Define parent for requests + const parent = `projects/${projectId}/locations/${zone}`; + + // Create queued resource + const queuedResource = new QueuedResource({ + name: queuedResourceName, + tpu: { + nodeSpec: [ + { + parent, + node, + nodeId: nodeName, + }, + ], + }, + // TODO(developer): Uncomment next line if you want to specify reservation. + // reservationName: 'reservation-name' + }); + + const request = { + parent: `projects/${projectId}/locations/${zone}`, + queuedResource, + queuedResourceId: queuedResourceName, + }; + + const [operation] = await tpuClient.createQueuedResource(request); + + // Wait for the create operation to complete. + const [response] = await operation.promise(); + + console.log(JSON.stringify(response)); + console.log(`Queued resource ${queuedResourceName} created.`); + } + await callCreateQueuedResource(); + // [END tpu_queued_resources_create] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/tpu/queuedResource/deleteQueuedResource.js b/tpu/queuedResource/deleteQueuedResource.js new file mode 100644 index 0000000000..04fe75fe1b --- /dev/null +++ b/tpu/queuedResource/deleteQueuedResource.js @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main(queuedResourceName, zone) { + // [START tpu_queued_resources_delete] + // Import the TPU library + const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + const tpuClient = new TpuClient(); + + /** + * TODO(developer): Update/uncomment these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project, where you want to delete node. + const projectId = await tpuClient.getProjectId(); + + // The name of queued resource. + // queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + // zone = 'europe-west4-a'; + + async function callDeleteQueuedResource() { + const request = { + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }; + + const [operation] = await tpuClient.deleteQueuedResource(request); + + // Wait for the delete operation to complete. + const [response] = await operation.promise(); + + console.log(JSON.stringify(response)); + console.log(`Queued resource ${queuedResourceName} deleted.`); + } + await callDeleteQueuedResource(); + // [END tpu_queued_resources_delete] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/tpu/queuedResource/forceDeleteQueuedResource.js b/tpu/queuedResource/forceDeleteQueuedResource.js new file mode 100644 index 0000000000..49b623572c --- /dev/null +++ b/tpu/queuedResource/forceDeleteQueuedResource.js @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main(queuedResourceName, zone) { + // [START tpu_queued_resources_delete_force] + // Import the TPU library + const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + const tpuClient = new TpuClient(); + + /** + * TODO(developer): Update/uncomment these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project, where you want to delete node. + const projectId = await tpuClient.getProjectId(); + + // The name of queued resource. + // queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + // zone = 'europe-west4-a'; + + async function callForceDeleteQueuedResource() { + const request = { + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + force: true, + }; + + const [operation] = await tpuClient.deleteQueuedResource(request); + + // Wait for the delete operation to complete. + const [response] = await operation.promise(); + + console.log(JSON.stringify(response)); + console.log(`Queued resource ${queuedResourceName} deletion forced.`); + } + await callForceDeleteQueuedResource(); + // [END tpu_queued_resources_delete_force] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js new file mode 100644 index 0000000000..3e1649be0a --- /dev/null +++ b/tpu/test/queuedResource.test.js @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const path = require('path'); +const assert = require('node:assert/strict'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('TPU queued resource', async () => { + const queuedResourceName = `queued-resource-name-1a2sdf${Math.floor(Math.random() * 1000 + 1)}`; + const nodePrefix = 'node-name-2a2b3c'; + const nodeName = `${nodePrefix}${Math.floor(Math.random() * 1000 + 1)}`; + const zone = 'europe-west4-a'; + const tpuType = 'v2-8'; + const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; + + it('should create a new queued resource', () => { + const response = execSync( + `node ./queuedResource/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, + { + cwd, + } + ); + assert(response.includes(`Queued resource ${queuedResourceName} created.`)); + }); + + it('should force queued resource deletion', () => { + const response = execSync( + `node ./queuedResource/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, + { + cwd, + } + ); + + assert( + response.includes( + `Queued resource ${queuedResourceName} deletion forced.` + ) + ); + }); +}); From c113dfb746912da461b28631c2485682608a700c Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Thu, 17 Oct 2024 07:45:49 +0200 Subject: [PATCH 2/6] feat: tpu_queued_resources_get --- tpu/queuedResource/getQueuedResource.js | 56 +++++++++++++++++++++++++ tpu/test/queuedResource.test.js | 14 +++++++ 2 files changed, 70 insertions(+) create mode 100644 tpu/queuedResource/getQueuedResource.js diff --git a/tpu/queuedResource/getQueuedResource.js b/tpu/queuedResource/getQueuedResource.js new file mode 100644 index 0000000000..7a84ed467e --- /dev/null +++ b/tpu/queuedResource/getQueuedResource.js @@ -0,0 +1,56 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main(queuedResourceName, zone) { + // [START tpu_queued_resources_get] + // Import the TPU library + const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + const tpuClient = new TpuClient(); + + /** + * TODO(developer): Update/uncomment these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project, where you want to retrive node. + const projectId = await tpuClient.getProjectId(); + + // The name of queued resource. + // queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + // zone = 'europe-west4-a'; + + async function callGetQueuedResource() { + const request = { + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }; + + const [response] = await tpuClient.getQueuedResource(request); + + console.log(JSON.stringify(response)); + console.log(`Queued resource ${queuedResourceName} retrived.`); + } + await callGetQueuedResource(); + // [END tpu_queued_resources_get] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js index 3e1649be0a..5aa3171a04 100644 --- a/tpu/test/queuedResource.test.js +++ b/tpu/test/queuedResource.test.js @@ -39,9 +39,23 @@ describe('TPU queued resource', async () => { cwd, } ); + assert(response.includes(`Queued resource ${queuedResourceName} created.`)); }); + it('should return requested queued resource', () => { + const response = execSync( + `node ./queuedResource/getQueuedResource.js ${queuedResourceName} ${zone}`, + { + cwd, + } + ); + + assert( + response.includes(`Queued resource ${queuedResourceName} retrived.`) + ); + }); + it('should force queued resource deletion', () => { const response = execSync( `node ./queuedResource/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, From dd2747ce3e48b1e9c49b7a9270d462ec5410f2a3 Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Fri, 18 Oct 2024 12:28:05 +0200 Subject: [PATCH 3/6] refactor for create and delete --- tpu/queuedResource/createQueuedResource.js | 21 ++++++- tpu/queuedResource/deleteQueuedResource.js | 23 +++++++- .../forceDeleteQueuedResource.js | 3 +- tpu/test/forceDeleteQueuedResource.test.js | 57 +++++++++++++++++++ tpu/test/queuedResource.test.js | 10 +--- 5 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 tpu/test/forceDeleteQueuedResource.test.js diff --git a/tpu/queuedResource/createQueuedResource.js b/tpu/queuedResource/createQueuedResource.js index 8dd06f7762..b2d3bc9980 100644 --- a/tpu/queuedResource/createQueuedResource.js +++ b/tpu/queuedResource/createQueuedResource.js @@ -108,10 +108,27 @@ async function main( const [operation] = await tpuClient.createQueuedResource(request); // Wait for the create operation to complete. - const [response] = await operation.promise(); + await operation.promise(); - console.log(JSON.stringify(response)); console.log(`Queued resource ${queuedResourceName} created.`); + + const getNodeRequest = { + name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, + }; + + console.log(`Waiting for TPU node ${nodeName} to become ready...`); + + // Poll for TPU node state every 30 seconds + const intervalId = setInterval(async () => { + const [node] = await tpuClient.getNode(getNodeRequest); + + if (node.state === 'READY') { + clearInterval(intervalId); + console.log(`TPU node ${nodeName} is ready.`); + } else { + console.log(`TPU node ${nodeName} is in state: ${node.state}`); + } + }, 30000); } await callCreateQueuedResource(); // [END tpu_queued_resources_create] diff --git a/tpu/queuedResource/deleteQueuedResource.js b/tpu/queuedResource/deleteQueuedResource.js index 04fe75fe1b..a3e03cc821 100644 --- a/tpu/queuedResource/deleteQueuedResource.js +++ b/tpu/queuedResource/deleteQueuedResource.js @@ -36,17 +36,36 @@ async function main(queuedResourceName, zone) { // The zone of your queued resource. // zone = 'europe-west4-a'; + async function callDeleteTpuVM(nodeName) { + const request = { + name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, + }; + + const [operation] = await tpuClient.deleteNode(request); + + // Wait for the delete operation to complete. + await operation.promise(); + + console.log(`Node: ${nodeName} deleted.`); + } + async function callDeleteQueuedResource() { const request = { name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, }; + // Retrive node name + const [response] = await tpuClient.getQueuedResource(request); + const nodeName = response.tpu.nodeSpec[0].nodeId; + + // Before deleting the queued resource it is required to delete the TPU VM. + await callDeleteTpuVM(nodeName); + const [operation] = await tpuClient.deleteQueuedResource(request); // Wait for the delete operation to complete. - const [response] = await operation.promise(); + await operation.promise(); - console.log(JSON.stringify(response)); console.log(`Queued resource ${queuedResourceName} deleted.`); } await callDeleteQueuedResource(); diff --git a/tpu/queuedResource/forceDeleteQueuedResource.js b/tpu/queuedResource/forceDeleteQueuedResource.js index 49b623572c..e842c39e26 100644 --- a/tpu/queuedResource/forceDeleteQueuedResource.js +++ b/tpu/queuedResource/forceDeleteQueuedResource.js @@ -45,9 +45,8 @@ async function main(queuedResourceName, zone) { const [operation] = await tpuClient.deleteQueuedResource(request); // Wait for the delete operation to complete. - const [response] = await operation.promise(); + await operation.promise(); - console.log(JSON.stringify(response)); console.log(`Queued resource ${queuedResourceName} deletion forced.`); } await callForceDeleteQueuedResource(); diff --git a/tpu/test/forceDeleteQueuedResource.test.js b/tpu/test/forceDeleteQueuedResource.test.js new file mode 100644 index 0000000000..df1ec53879 --- /dev/null +++ b/tpu/test/forceDeleteQueuedResource.test.js @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const path = require('path'); +const assert = require('node:assert/strict'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('TPU queued resource force deletion', async () => { + const queuedResourceName = `queued-resource-force-delete-${Math.floor(Math.random() * 1000 + 1)}`; + const nodePrefix = 'node-force-delete-2a2b3c'; + const nodeName = `${nodePrefix}${Math.floor(Math.random() * 1000 + 1)}`; + const zone = 'us-central1-c'; + const tpuType = 'v2-8'; + const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; + + it('should force queued resource deletion', () => { + // Create queued resource + execSync( + `node ./queuedResource/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, + { + cwd, + } + ); + + const response = execSync( + `node ./queuedResource/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, + { + cwd, + } + ); + + assert( + response.includes( + `Queued resource ${queuedResourceName} deletion forced.` + ) + ); + }); +}); diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js index 5aa3171a04..1e24234422 100644 --- a/tpu/test/queuedResource.test.js +++ b/tpu/test/queuedResource.test.js @@ -56,18 +56,14 @@ describe('TPU queued resource', async () => { ); }); - it('should force queued resource deletion', () => { + it('should delete queued resource', () => { const response = execSync( - `node ./queuedResource/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, + `node ./queuedResource/deleteQueuedResource.js ${queuedResourceName} ${zone}`, { cwd, } ); - assert( - response.includes( - `Queued resource ${queuedResourceName} deletion forced.` - ) - ); + assert(response.includes(`Queued resource ${queuedResourceName} deleted.`)); }); }); From ed0c09f8e0eb11508b8b957e1a578a63fa2149a5 Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Mon, 21 Oct 2024 16:40:17 +0200 Subject: [PATCH 4/6] Fix samples and tests --- tpu/queuedResource/createQueuedResource.js | 23 +++--------- tpu/test/queuedResource.test.js | 42 ++++++++++++++++++---- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/tpu/queuedResource/createQueuedResource.js b/tpu/queuedResource/createQueuedResource.js index b2d3bc9980..bb5e991dc9 100644 --- a/tpu/queuedResource/createQueuedResource.js +++ b/tpu/queuedResource/createQueuedResource.js @@ -96,7 +96,7 @@ async function main( ], }, // TODO(developer): Uncomment next line if you want to specify reservation. - // reservationName: 'reservation-name' + // reservationName: 'reservation-name/ Before deleting the queued resource it is required to delete the TPU VM.' }); const request = { @@ -110,25 +110,10 @@ async function main( // Wait for the create operation to complete. await operation.promise(); + // If you also want to wait for create operation of TPU Node, + // you can use `tpu_vm_get` sample to check current status of the node + // and wait until it is READY. console.log(`Queued resource ${queuedResourceName} created.`); - - const getNodeRequest = { - name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, - }; - - console.log(`Waiting for TPU node ${nodeName} to become ready...`); - - // Poll for TPU node state every 30 seconds - const intervalId = setInterval(async () => { - const [node] = await tpuClient.getNode(getNodeRequest); - - if (node.state === 'READY') { - clearInterval(intervalId); - console.log(`TPU node ${nodeName} is ready.`); - } else { - console.log(`TPU node ${nodeName} is in state: ${node.state}`); - } - }, 30000); } await callCreateQueuedResource(); // [END tpu_queued_resources_create] diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js index 1e24234422..274049c273 100644 --- a/tpu/test/queuedResource.test.js +++ b/tpu/test/queuedResource.test.js @@ -20,26 +20,54 @@ const path = require('path'); const assert = require('node:assert/strict'); const {describe, it} = require('mocha'); const cp = require('child_process'); +const {TpuClient} = require('@google-cloud/tpu').v2alpha1; const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); const cwd = path.join(__dirname, '..'); -describe('TPU queued resource', async () => { +async function waitForTPUCreation(nodeName, zone) { + const tpuClient = new TpuClient(); + const projectId = await tpuClient.getProjectId(); + + // Give a time to start process of creating TPU Node + await new Promise(resolve => setTimeout(resolve, 60000)); + + const getNodeRequest = { + name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, + }; + + console.log(`Waiting for TPU node ${nodeName} to become ready...`); + + let state; + + while (state !== 'READY') { + try { + state = (await tpuClient.getNode(getNodeRequest))[0].state; + // Wait another minute to try + await new Promise(resolve => setTimeout(resolve, 60000)); + } catch (err) { + console.log('TPU node not ready'); + // Wait another minute to try + await new Promise(resolve => setTimeout(resolve, 60000)); + } + } +} + +describe('TPU queued resource', () => { const queuedResourceName = `queued-resource-name-1a2sdf${Math.floor(Math.random() * 1000 + 1)}`; const nodePrefix = 'node-name-2a2b3c'; const nodeName = `${nodePrefix}${Math.floor(Math.random() * 1000 + 1)}`; - const zone = 'europe-west4-a'; + const zone = 'us-central1-f'; const tpuType = 'v2-8'; const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; - it('should create a new queued resource', () => { + it('should create a new queued resource', async () => { const response = execSync( `node ./queuedResource/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, { cwd, } ); - assert(response.includes(`Queued resource ${queuedResourceName} created.`)); }); @@ -50,20 +78,20 @@ describe('TPU queued resource', async () => { cwd, } ); - assert( response.includes(`Queued resource ${queuedResourceName} retrived.`) ); }); - it('should delete queued resource', () => { + it('should delete queued resource', async () => { + // Wait until queued resource is ready to delete. + await waitForTPUCreation(nodeName, zone); const response = execSync( `node ./queuedResource/deleteQueuedResource.js ${queuedResourceName} ${zone}`, { cwd, } ); - assert(response.includes(`Queued resource ${queuedResourceName} deleted.`)); }); }); From 0e8699340c24ef0a2baa99e05297c189d4714170 Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Wed, 23 Oct 2024 10:58:34 +0200 Subject: [PATCH 5/6] feat: tpu_queued_resources_list --- .../createQueuedResource.js | 5 +- .../deleteQueuedResource.js | 0 .../forceDeleteQueuedResource.js | 0 .../getQueuedResource.js | 0 tpu/queuedResources/getQueuedResourcesList.js | 52 +++++++++++++++++++ tpu/test/forceDeleteQueuedResource.test.js | 4 +- tpu/test/queuedResource.test.js | 17 ++++-- 7 files changed, 70 insertions(+), 8 deletions(-) rename tpu/{queuedResource => queuedResources}/createQueuedResource.js (95%) rename tpu/{queuedResource => queuedResources}/deleteQueuedResource.js (100%) rename tpu/{queuedResource => queuedResources}/forceDeleteQueuedResource.js (100%) rename tpu/{queuedResource => queuedResources}/getQueuedResource.js (100%) create mode 100644 tpu/queuedResources/getQueuedResourcesList.js diff --git a/tpu/queuedResource/createQueuedResource.js b/tpu/queuedResources/createQueuedResource.js similarity index 95% rename from tpu/queuedResource/createQueuedResource.js rename to tpu/queuedResources/createQueuedResource.js index bb5e991dc9..e8ab1484d6 100644 --- a/tpu/queuedResource/createQueuedResource.js +++ b/tpu/queuedResources/createQueuedResource.js @@ -110,9 +110,8 @@ async function main( // Wait for the create operation to complete. await operation.promise(); - // If you also want to wait for create operation of TPU Node, - // you can use `tpu_vm_get` sample to check current status of the node - // and wait until it is READY. + // You can wait until TPU Node is READY, + // and check its status using getTpuVm() from `tpu_vm_get` sample. console.log(`Queued resource ${queuedResourceName} created.`); } await callCreateQueuedResource(); diff --git a/tpu/queuedResource/deleteQueuedResource.js b/tpu/queuedResources/deleteQueuedResource.js similarity index 100% rename from tpu/queuedResource/deleteQueuedResource.js rename to tpu/queuedResources/deleteQueuedResource.js diff --git a/tpu/queuedResource/forceDeleteQueuedResource.js b/tpu/queuedResources/forceDeleteQueuedResource.js similarity index 100% rename from tpu/queuedResource/forceDeleteQueuedResource.js rename to tpu/queuedResources/forceDeleteQueuedResource.js diff --git a/tpu/queuedResource/getQueuedResource.js b/tpu/queuedResources/getQueuedResource.js similarity index 100% rename from tpu/queuedResource/getQueuedResource.js rename to tpu/queuedResources/getQueuedResource.js diff --git a/tpu/queuedResources/getQueuedResourcesList.js b/tpu/queuedResources/getQueuedResourcesList.js new file mode 100644 index 0000000000..a553aa20c5 --- /dev/null +++ b/tpu/queuedResources/getQueuedResourcesList.js @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main(zone) { + // [START tpu_queued_resources_list] + // Import the TPU library + const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + const tpuClient = new TpuClient(); + + /** + * TODO(developer): Update/uncomment these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project, where you want to retrive the list of Queued Resources. + const projectId = await tpuClient.getProjectId(); + + // The zone from which the Queued Resources are retrived. + // zone = 'europe-west4-a'; + + async function callGetQueuedResourcesList() { + const request = { + parent: `projects/${projectId}/locations/${zone}`, + }; + + const [response] = await tpuClient.listQueuedResources(request); + + console.log(JSON.stringify(response)); + } + await callGetQueuedResourcesList(); + // [END tpu_queued_resources_list] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/tpu/test/forceDeleteQueuedResource.test.js b/tpu/test/forceDeleteQueuedResource.test.js index df1ec53879..8429f01d4d 100644 --- a/tpu/test/forceDeleteQueuedResource.test.js +++ b/tpu/test/forceDeleteQueuedResource.test.js @@ -35,14 +35,14 @@ describe('TPU queued resource force deletion', async () => { it('should force queued resource deletion', () => { // Create queued resource execSync( - `node ./queuedResource/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, + `node ./queuedResources/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, { cwd, } ); const response = execSync( - `node ./queuedResource/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, + `node ./queuedResources/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, { cwd, } diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js index 274049c273..0467172c4f 100644 --- a/tpu/test/queuedResource.test.js +++ b/tpu/test/queuedResource.test.js @@ -63,7 +63,7 @@ describe('TPU queued resource', () => { it('should create a new queued resource', async () => { const response = execSync( - `node ./queuedResource/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, + `node ./queuedResources/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, { cwd, } @@ -73,21 +73,32 @@ describe('TPU queued resource', () => { it('should return requested queued resource', () => { const response = execSync( - `node ./queuedResource/getQueuedResource.js ${queuedResourceName} ${zone}`, + `node ./queuedResources/getQueuedResource.js ${queuedResourceName} ${zone}`, { cwd, } ); + assert( response.includes(`Queued resource ${queuedResourceName} retrived.`) ); }); + it('should return list of queued resources', () => { + const response = JSON.parse( + execSync(`node ./queuedResources/getQueuedResourcesList.js ${zone}`, { + cwd, + }) + ); + + assert(Array.isArray(response)); + }); + it('should delete queued resource', async () => { // Wait until queued resource is ready to delete. await waitForTPUCreation(nodeName, zone); const response = execSync( - `node ./queuedResource/deleteQueuedResource.js ${queuedResourceName} ${zone}`, + `node ./queuedResources/deleteQueuedResource.js ${queuedResourceName} ${zone}`, { cwd, } From 1a65640ce88a90b82f69b82d4aca3b95c0fe5be8 Mon Sep 17 00:00:00 2001 From: Joanna Grycz Date: Tue, 12 Nov 2024 17:11:57 +0100 Subject: [PATCH 6/6] Use mocked TPUClient in tests --- tpu/package.json | 25 +-- tpu/queuedResources/createQueuedResource.js | 50 ++--- tpu/queuedResources/deleteQueuedResource.js | 36 ++-- .../forceDeleteQueuedResource.js | 32 +-- tpu/queuedResources/getQueuedResource.js | 31 +-- tpu/queuedResources/getQueuedResourcesList.js | 27 +-- tpu/test/forceDeleteQueuedResource.test.js | 66 ++++--- tpu/test/queuedResource.test.js | 184 +++++++++++------- 8 files changed, 254 insertions(+), 197 deletions(-) diff --git a/tpu/package.json b/tpu/package.json index 0c9fe9d005..44140e7f0b 100644 --- a/tpu/package.json +++ b/tpu/package.json @@ -21,27 +21,4 @@ "c8": "^10.0.0", "mocha": "^10.0.0" } -} -{ - "name": "nodejs-docs-samples-tpu", - "license": "Apache-2.0", - "author": "Google Inc.", - "engines": { - "node": ">=16.0.0" - }, - "repository": "googleapis/nodejs-tpu", - "private": true, - "files": [ - "*.js" - ], - "scripts": { - "test": "c8 mocha -p -j 2 test --timeout 1200000" - }, - "dependencies": { - "@google-cloud/tpu": "^3.5.0" - }, - "devDependencies": { - "c8": "^10.0.0", - "mocha": "^10.0.0" - } -} +} \ No newline at end of file diff --git a/tpu/queuedResources/createQueuedResource.js b/tpu/queuedResources/createQueuedResource.js index e8ab1484d6..141f9d5e1c 100644 --- a/tpu/queuedResources/createQueuedResource.js +++ b/tpu/queuedResources/createQueuedResource.js @@ -16,24 +16,20 @@ 'use strict'; -async function main( - nodeName, - queuedResourceName, - zone, - tpuType, - tpuSoftwareVersion -) { +async function main(tpuClient) { // [START tpu_queued_resources_create] - // Import the TPU library - const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; const {Node, NetworkConfig, QueuedResource} = require('@google-cloud/tpu').protos.google.cloud.tpu.v2alpha1; // Instantiate a tpuClient - const tpuClient = new TpuClient(); + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); /** - * TODO(developer): Update/uncomment these variables before running the sample. + * TODO(developer): Update these variables before running the sample. */ // Project ID or project number of the Google Cloud project, where you want to create queued resource. const projectId = await tpuClient.getProjectId(); @@ -41,28 +37,28 @@ async function main( // The name of the network you want the node to connect to. The network should be assigned to your project. const networkName = 'compute-tpu-network'; - // The region of the network, that you want the node to connect to. - const region = 'europe-west4'; + // The region of the subnetwork, that you want the node to connect to. + const region = 'us-central1'; // The name for your queued resource. - // queuedResourceName = 'queued-resource-1'; + const queuedResourceName = 'queued-resource-1'; // The name for your node. - // nodeName = 'node-name-1'; + const nodeName = 'node-name-1'; // The zone in which to create the node. // For more information about supported TPU types for specific zones, // see https://cloud.google.com/tpu/docs/regions-zones - // zone = 'europe-west4-a'; + const zone = `${region}-f`; // The accelerator type that specifies the version and size of the node you want to create. // For more information about supported accelerator types for each TPU version, // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. - // tpuType = 'v2-8'; + const tpuType = 'v2-8'; // Software version that specifies the version of the node runtime to install. For more information, // see https://cloud.google.com/tpu/docs/runtimes - // tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; + const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; async function callCreateQueuedResource() { // Create a node @@ -108,17 +104,21 @@ async function main( const [operation] = await tpuClient.createQueuedResource(request); // Wait for the create operation to complete. - await operation.promise(); + const [response] = await operation.promise(); // You can wait until TPU Node is READY, - // and check its status using getTpuVm() from `tpu_vm_get` sample. + // and check its status using callGetTpuVm() from `tpu_vm_get` sample. console.log(`Queued resource ${queuedResourceName} created.`); + return response; } - await callCreateQueuedResource(); + return await callCreateQueuedResource(); // [END tpu_queued_resources_create] } -main(...process.argv.slice(2)).catch(err => { - console.error(err); - process.exitCode = 1; -}); +module.exports = main; + +// TODO(developer): Uncomment below lines before running the sample. +// main(...process.argv.slice(2)).catch(err => { +// console.error(err); +// process.exitCode = 1; +// }); diff --git a/tpu/queuedResources/deleteQueuedResource.js b/tpu/queuedResources/deleteQueuedResource.js index a3e03cc821..2db83ef165 100644 --- a/tpu/queuedResources/deleteQueuedResource.js +++ b/tpu/queuedResources/deleteQueuedResource.js @@ -16,25 +16,27 @@ 'use strict'; -async function main(queuedResourceName, zone) { +async function main(tpuClient) { // [START tpu_queued_resources_delete] - // Import the TPU library - const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; // Instantiate a tpuClient - const tpuClient = new TpuClient(); + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); /** - * TODO(developer): Update/uncomment these variables before running the sample. + * TODO(developer): Update these variables before running the sample. */ // Project ID or project number of the Google Cloud project, where you want to delete node. const projectId = await tpuClient.getProjectId(); // The name of queued resource. - // queuedResourceName = 'queued-resource-1'; + const queuedResourceName = 'queued-resource-1'; // The zone of your queued resource. - // zone = 'europe-west4-a'; + const zone = 'us-central1-f'; async function callDeleteTpuVM(nodeName) { const request = { @@ -55,8 +57,8 @@ async function main(queuedResourceName, zone) { }; // Retrive node name - const [response] = await tpuClient.getQueuedResource(request); - const nodeName = response.tpu.nodeSpec[0].nodeId; + const [queuedResource] = await tpuClient.getQueuedResource(request); + const nodeName = queuedResource.tpu.nodeSpec[0].nodeId; // Before deleting the queued resource it is required to delete the TPU VM. await callDeleteTpuVM(nodeName); @@ -64,15 +66,19 @@ async function main(queuedResourceName, zone) { const [operation] = await tpuClient.deleteQueuedResource(request); // Wait for the delete operation to complete. - await operation.promise(); + const [response] = await operation.promise(); console.log(`Queued resource ${queuedResourceName} deleted.`); + return response; } - await callDeleteQueuedResource(); + return await callDeleteQueuedResource(); // [END tpu_queued_resources_delete] } -main(...process.argv.slice(2)).catch(err => { - console.error(err); - process.exitCode = 1; -}); +module.exports = main; + +// TODO(developer): Uncomment below lines before running the sample. +// main(...process.argv.slice(2)).catch(err => { +// console.error(err); +// process.exitCode = 1; +// }); diff --git a/tpu/queuedResources/forceDeleteQueuedResource.js b/tpu/queuedResources/forceDeleteQueuedResource.js index e842c39e26..066d40c1d1 100644 --- a/tpu/queuedResources/forceDeleteQueuedResource.js +++ b/tpu/queuedResources/forceDeleteQueuedResource.js @@ -16,25 +16,27 @@ 'use strict'; -async function main(queuedResourceName, zone) { +async function main(tpuClient) { // [START tpu_queued_resources_delete_force] - // Import the TPU library - const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; // Instantiate a tpuClient - const tpuClient = new TpuClient(); + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); /** - * TODO(developer): Update/uncomment these variables before running the sample. + * TODO(developer): Update these variables before running the sample. */ // Project ID or project number of the Google Cloud project, where you want to delete node. const projectId = await tpuClient.getProjectId(); // The name of queued resource. - // queuedResourceName = 'queued-resource-1'; + const queuedResourceName = 'queued-resource-1'; // The zone of your queued resource. - // zone = 'europe-west4-a'; + const zone = 'us-central1-f'; async function callForceDeleteQueuedResource() { const request = { @@ -45,15 +47,19 @@ async function main(queuedResourceName, zone) { const [operation] = await tpuClient.deleteQueuedResource(request); // Wait for the delete operation to complete. - await operation.promise(); + const [response] = await operation.promise(); console.log(`Queued resource ${queuedResourceName} deletion forced.`); + return response; } - await callForceDeleteQueuedResource(); + return await callForceDeleteQueuedResource(); // [END tpu_queued_resources_delete_force] } -main(...process.argv.slice(2)).catch(err => { - console.error(err); - process.exitCode = 1; -}); +module.exports = main; + +// TODO(developer): Uncomment below lines before running the sample. +// main(...process.argv.slice(2)).catch(err => { +// console.error(err); +// process.exitCode = 1; +// }); diff --git a/tpu/queuedResources/getQueuedResource.js b/tpu/queuedResources/getQueuedResource.js index 7a84ed467e..7a243f187a 100644 --- a/tpu/queuedResources/getQueuedResource.js +++ b/tpu/queuedResources/getQueuedResource.js @@ -16,25 +16,27 @@ 'use strict'; -async function main(queuedResourceName, zone) { +async function main(tpuClient) { // [START tpu_queued_resources_get] - // Import the TPU library - const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; // Instantiate a tpuClient - const tpuClient = new TpuClient(); + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); /** - * TODO(developer): Update/uncomment these variables before running the sample. + * TODO(developer): Update these variables before running the sample. */ // Project ID or project number of the Google Cloud project, where you want to retrive node. const projectId = await tpuClient.getProjectId(); // The name of queued resource. - // queuedResourceName = 'queued-resource-1'; + const queuedResourceName = 'queued-resource-1'; // The zone of your queued resource. - // zone = 'europe-west4-a'; + const zone = 'us-central1-f'; async function callGetQueuedResource() { const request = { @@ -43,14 +45,17 @@ async function main(queuedResourceName, zone) { const [response] = await tpuClient.getQueuedResource(request); - console.log(JSON.stringify(response)); console.log(`Queued resource ${queuedResourceName} retrived.`); + return response; } - await callGetQueuedResource(); + return await callGetQueuedResource(); // [END tpu_queued_resources_get] } -main(...process.argv.slice(2)).catch(err => { - console.error(err); - process.exitCode = 1; -}); +module.exports = main; + +// TODO(developer): Uncomment below lines before running the sample. +// main(...process.argv.slice(2)).catch(err => { +// console.error(err); +// process.exitCode = 1; +// }); diff --git a/tpu/queuedResources/getQueuedResourcesList.js b/tpu/queuedResources/getQueuedResourcesList.js index a553aa20c5..21815db23e 100644 --- a/tpu/queuedResources/getQueuedResourcesList.js +++ b/tpu/queuedResources/getQueuedResourcesList.js @@ -16,13 +16,15 @@ 'use strict'; -async function main(zone) { +async function main(tpuClient) { // [START tpu_queued_resources_list] - // Import the TPU library - const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; // Instantiate a tpuClient - const tpuClient = new TpuClient(); + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); /** * TODO(developer): Update/uncomment these variables before running the sample. @@ -31,7 +33,7 @@ async function main(zone) { const projectId = await tpuClient.getProjectId(); // The zone from which the Queued Resources are retrived. - // zone = 'europe-west4-a'; + const zone = 'us-central1-f'; async function callGetQueuedResourcesList() { const request = { @@ -40,13 +42,16 @@ async function main(zone) { const [response] = await tpuClient.listQueuedResources(request); - console.log(JSON.stringify(response)); + return response; } - await callGetQueuedResourcesList(); + return await callGetQueuedResourcesList(); // [END tpu_queued_resources_list] } -main(...process.argv.slice(2)).catch(err => { - console.error(err); - process.exitCode = 1; -}); +module.exports = main; + +// TODO(developer): Uncomment below lines before running the sample. +// main(...process.argv.slice(2)).catch(err => { +// console.error(err); +// process.exitCode = 1; +// }); diff --git a/tpu/test/forceDeleteQueuedResource.test.js b/tpu/test/forceDeleteQueuedResource.test.js index 8429f01d4d..7887f6a4bb 100644 --- a/tpu/test/forceDeleteQueuedResource.test.js +++ b/tpu/test/forceDeleteQueuedResource.test.js @@ -16,42 +16,48 @@ 'use strict'; -const path = require('path'); const assert = require('node:assert/strict'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); +const {beforeEach, afterEach, describe, it} = require('mocha'); +const sinon = require('sinon'); +const forceDeleteQueuedResource = require('../queuedResources/forceDeleteQueuedResource.js'); describe('TPU queued resource force deletion', async () => { - const queuedResourceName = `queued-resource-force-delete-${Math.floor(Math.random() * 1000 + 1)}`; - const nodePrefix = 'node-force-delete-2a2b3c'; - const nodeName = `${nodePrefix}${Math.floor(Math.random() * 1000 + 1)}`; - const zone = 'us-central1-c'; - const tpuType = 'v2-8'; - const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; - - it('should force queued resource deletion', () => { - // Create queued resource - execSync( - `node ./queuedResources/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, - { - cwd, - } - ); + const queuedResourceName = 'queued-resource-1'; + const zone = 'us-central1-f'; + const projectId = 'project_id'; + let tpuClientMock; + + beforeEach(() => { + tpuClientMock = { + getProjectId: sinon.stub().resolves(projectId), + }; + }); - const response = execSync( - `node ./queuedResources/forceDeleteQueuedResource.js ${queuedResourceName} ${zone}`, + afterEach(() => { + sinon.restore(); + }); + + it('should force queued resource deletion', async () => { + const message = `Queued resource ${queuedResourceName} deletion forced.`; + tpuClientMock.deleteQueuedResource = sinon.stub().resolves([ { - cwd, - } - ); + promise: sinon.stub().resolves([ + { + message, + }, + ]), + }, + ]); + + const response = await forceDeleteQueuedResource(tpuClientMock); - assert( - response.includes( - `Queued resource ${queuedResourceName} deletion forced.` - ) + sinon.assert.calledWith( + tpuClientMock.deleteQueuedResource, + sinon.match({ + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + force: true, + }) ); + assert(response.message.includes(message)); }); }); diff --git a/tpu/test/queuedResource.test.js b/tpu/test/queuedResource.test.js index 0467172c4f..d4c7e68d81 100644 --- a/tpu/test/queuedResource.test.js +++ b/tpu/test/queuedResource.test.js @@ -16,93 +16,145 @@ 'use strict'; -const path = require('path'); const assert = require('node:assert/strict'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const {TpuClient} = require('@google-cloud/tpu').v2alpha1; - -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -async function waitForTPUCreation(nodeName, zone) { - const tpuClient = new TpuClient(); - const projectId = await tpuClient.getProjectId(); - - // Give a time to start process of creating TPU Node - await new Promise(resolve => setTimeout(resolve, 60000)); - - const getNodeRequest = { - name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, - }; - - console.log(`Waiting for TPU node ${nodeName} to become ready...`); - - let state; - - while (state !== 'READY') { - try { - state = (await tpuClient.getNode(getNodeRequest))[0].state; - // Wait another minute to try - await new Promise(resolve => setTimeout(resolve, 60000)); - } catch (err) { - console.log('TPU node not ready'); - // Wait another minute to try - await new Promise(resolve => setTimeout(resolve, 60000)); - } - } -} +const {beforeEach, afterEach, describe, it} = require('mocha'); +const sinon = require('sinon'); +const createQueuedResource = require('../queuedResources/createQueuedResource.js'); +const getQueuedResource = require('../queuedResources/getQueuedResource.js'); +const getQueuedResourcesList = require('../queuedResources/getQueuedResourcesList.js'); +const deleteQueuedResource = require('../queuedResources/deleteQueuedResource.js'); describe('TPU queued resource', () => { - const queuedResourceName = `queued-resource-name-1a2sdf${Math.floor(Math.random() * 1000 + 1)}`; - const nodePrefix = 'node-name-2a2b3c'; - const nodeName = `${nodePrefix}${Math.floor(Math.random() * 1000 + 1)}`; + const queuedResourceName = 'queued-resource-1'; + const nodeName = 'node-name-1'; const zone = 'us-central1-f'; - const tpuType = 'v2-8'; - const tpuSoftwareVersion = 'tpu-vm-tf-2.14.1'; + const projectId = 'project_id'; + let tpuClientMock; + + beforeEach(() => { + tpuClientMock = { + getProjectId: sinon.stub().resolves(projectId), + }; + }); + + afterEach(() => { + sinon.restore(); + }); it('should create a new queued resource', async () => { - const response = execSync( - `node ./queuedResources/createQueuedResource.js ${nodeName} ${queuedResourceName} ${zone} ${tpuType} ${tpuSoftwareVersion}`, + tpuClientMock.createQueuedResource = sinon.stub().resolves([ { - cwd, - } + promise: sinon.stub().resolves([ + { + name: queuedResourceName, + }, + ]), + }, + ]); + + const response = await createQueuedResource(tpuClientMock); + + sinon.assert.calledWith( + tpuClientMock.createQueuedResource, + sinon.match({ + parent: `projects/${projectId}/locations/${zone}`, + queuedResource: { + name: queuedResourceName, + }, + queuedResourceId: queuedResourceName, + }) ); - assert(response.includes(`Queued resource ${queuedResourceName} created.`)); + assert(response.name.includes(queuedResourceName)); }); - it('should return requested queued resource', () => { - const response = execSync( - `node ./queuedResources/getQueuedResource.js ${queuedResourceName} ${zone}`, + it('should return requested queued resource', async () => { + tpuClientMock.getQueuedResource = sinon.stub().resolves([ { - cwd, - } - ); + name: queuedResourceName, + }, + ]); - assert( - response.includes(`Queued resource ${queuedResourceName} retrived.`) + const response = await getQueuedResource(tpuClientMock); + + sinon.assert.calledWith( + tpuClientMock.getQueuedResource, + sinon.match({ + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }) ); + assert(response.name.includes(queuedResourceName)); }); - it('should return list of queued resources', () => { - const response = JSON.parse( - execSync(`node ./queuedResources/getQueuedResourcesList.js ${zone}`, { - cwd, + it('should return list of queued resources', async () => { + const queuedResources = [ + { + name: queuedResourceName, + }, + { + name: 'queued-resource-2', + }, + ]; + tpuClientMock.listQueuedResources = sinon + .stub() + .resolves([queuedResources]); + + const response = await getQueuedResourcesList(tpuClientMock); + + sinon.assert.calledWith( + tpuClientMock.listQueuedResources, + sinon.match({ + parent: `projects/${projectId}/locations/${zone}`, }) ); - - assert(Array.isArray(response)); + assert.deepEqual(response, queuedResources); }); it('should delete queued resource', async () => { - // Wait until queued resource is ready to delete. - await waitForTPUCreation(nodeName, zone); - const response = execSync( - `node ./queuedResources/deleteQueuedResource.js ${queuedResourceName} ${zone}`, + tpuClientMock.getQueuedResource = sinon.stub().resolves([ + { + name: queuedResourceName, + tpu: { + nodeSpec: [ + { + nodeId: nodeName, + }, + ], + }, + }, + ]); + tpuClientMock.deleteNode = sinon.stub().resolves([ { - cwd, - } + promise: sinon.stub().resolves([]), + }, + ]); + tpuClientMock.deleteQueuedResource = sinon.stub().resolves([ + { + promise: sinon.stub().resolves([ + { + message: `Queued resource ${queuedResourceName} deleted.`, + }, + ]), + }, + ]); + + const response = await deleteQueuedResource(tpuClientMock); + + sinon.assert.calledWith( + tpuClientMock.getQueuedResource, + sinon.match({ + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }) + ); + sinon.assert.calledWith( + tpuClientMock.deleteNode, + sinon.match({ + name: `projects/${projectId}/locations/${zone}/nodes/${nodeName}`, + }) + ); + assert( + response.message.includes( + `Queued resource ${queuedResourceName} deleted.` + ) ); - assert(response.includes(`Queued resource ${queuedResourceName} deleted.`)); }); });