diff --git a/tpu/package.json b/tpu/package.json index 9ac90ca084..44140e7f0b 100644 --- a/tpu/package.json +++ b/tpu/package.json @@ -21,4 +21,4 @@ "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 new file mode 100644 index 0000000000..141f9d5e1c --- /dev/null +++ b/tpu/queuedResources/createQueuedResource.js @@ -0,0 +1,124 @@ +/* + * 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(tpuClient) { + // [START tpu_queued_resources_create] + // 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 + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); + + /** + * 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(); + + // 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 subnetwork, that you want the node to connect to. + const region = 'us-central1'; + + // The name for your queued resource. + const queuedResourceName = 'queued-resource-1'; + + // The name for your node. + 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 + 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. + 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 + const 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/ Before deleting the queued resource it is required to delete the TPU VM.' + }); + + 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(); + + // You can wait until TPU Node is READY, + // and check its status using callGetTpuVm() from `tpu_vm_get` sample. + console.log(`Queued resource ${queuedResourceName} created.`); + return response; + } + return await callCreateQueuedResource(); + // [END tpu_queued_resources_create] +} + +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 new file mode 100644 index 0000000000..2db83ef165 --- /dev/null +++ b/tpu/queuedResources/deleteQueuedResource.js @@ -0,0 +1,84 @@ +/* + * 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(tpuClient) { + // [START tpu_queued_resources_delete] + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); + + /** + * 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. + const queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + const zone = 'us-central1-f'; + + 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 [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); + + const [operation] = await tpuClient.deleteQueuedResource(request); + + // Wait for the delete operation to complete. + const [response] = await operation.promise(); + + console.log(`Queued resource ${queuedResourceName} deleted.`); + return response; + } + return await callDeleteQueuedResource(); + // [END tpu_queued_resources_delete] +} + +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 new file mode 100644 index 0000000000..066d40c1d1 --- /dev/null +++ b/tpu/queuedResources/forceDeleteQueuedResource.js @@ -0,0 +1,65 @@ +/* + * 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(tpuClient) { + // [START tpu_queued_resources_delete_force] + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); + + /** + * 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. + const queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + const zone = 'us-central1-f'; + + 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(`Queued resource ${queuedResourceName} deletion forced.`); + return response; + } + return await callForceDeleteQueuedResource(); + // [END tpu_queued_resources_delete_force] +} + +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 new file mode 100644 index 0000000000..7a243f187a --- /dev/null +++ b/tpu/queuedResources/getQueuedResource.js @@ -0,0 +1,61 @@ +/* + * 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(tpuClient) { + // [START tpu_queued_resources_get] + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + // TODO(developer): Uncomment below line before running the sample. + // tpuClient = new TpuClient(); + + /** + * 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. + const queuedResourceName = 'queued-resource-1'; + + // The zone of your queued resource. + const zone = 'us-central1-f'; + + async function callGetQueuedResource() { + const request = { + name: `projects/${projectId}/locations/${zone}/queuedResources/${queuedResourceName}`, + }; + + const [response] = await tpuClient.getQueuedResource(request); + + console.log(`Queued resource ${queuedResourceName} retrived.`); + return response; + } + return await callGetQueuedResource(); + // [END tpu_queued_resources_get] +} + +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 new file mode 100644 index 0000000000..21815db23e --- /dev/null +++ b/tpu/queuedResources/getQueuedResourcesList.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'; + +async function main(tpuClient) { + // [START tpu_queued_resources_list] + // Import the TPUClient + // TODO(developer): Uncomment below line before running the sample. + // const {TpuClient} = require('@google-cloud/tpu').v2alpha1; + + // Instantiate a tpuClient + // TODO(developer): Uncomment below line before running the sample. + // 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. + const zone = 'us-central1-f'; + + async function callGetQueuedResourcesList() { + const request = { + parent: `projects/${projectId}/locations/${zone}`, + }; + + const [response] = await tpuClient.listQueuedResources(request); + + return response; + } + return await callGetQueuedResourcesList(); + // [END tpu_queued_resources_list] +} + +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 new file mode 100644 index 0000000000..7887f6a4bb --- /dev/null +++ b/tpu/test/forceDeleteQueuedResource.test.js @@ -0,0 +1,63 @@ +/* + * 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 assert = require('node:assert/strict'); +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-1'; + const zone = 'us-central1-f'; + const projectId = 'project_id'; + let tpuClientMock; + + beforeEach(() => { + tpuClientMock = { + getProjectId: sinon.stub().resolves(projectId), + }; + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should force queued resource deletion', async () => { + const message = `Queued resource ${queuedResourceName} deletion forced.`; + tpuClientMock.deleteQueuedResource = sinon.stub().resolves([ + { + promise: sinon.stub().resolves([ + { + message, + }, + ]), + }, + ]); + + const response = await forceDeleteQueuedResource(tpuClientMock); + + 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 new file mode 100644 index 0000000000..d4c7e68d81 --- /dev/null +++ b/tpu/test/queuedResource.test.js @@ -0,0 +1,160 @@ +/* + * 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 assert = require('node:assert/strict'); +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-1'; + const nodeName = 'node-name-1'; + const zone = 'us-central1-f'; + const projectId = 'project_id'; + let tpuClientMock; + + beforeEach(() => { + tpuClientMock = { + getProjectId: sinon.stub().resolves(projectId), + }; + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should create a new queued resource', async () => { + tpuClientMock.createQueuedResource = sinon.stub().resolves([ + { + 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.name.includes(queuedResourceName)); + }); + + it('should return requested queued resource', async () => { + tpuClientMock.getQueuedResource = sinon.stub().resolves([ + { + name: queuedResourceName, + }, + ]); + + 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', 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.deepEqual(response, queuedResources); + }); + + it('should delete queued resource', async () => { + tpuClientMock.getQueuedResource = sinon.stub().resolves([ + { + name: queuedResourceName, + tpu: { + nodeSpec: [ + { + nodeId: nodeName, + }, + ], + }, + }, + ]); + tpuClientMock.deleteNode = sinon.stub().resolves([ + { + 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.` + ) + ); + }); +});