diff --git a/compute/disks/createComputeHyperdiskFromPool.js b/compute/disks/createComputeHyperdiskFromPool.js new file mode 100644 index 0000000000..8f1c224964 --- /dev/null +++ b/compute/disks/createComputeHyperdiskFromPool.js @@ -0,0 +1,105 @@ +/* + * 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() { + // [START compute_hyperdisk_create_from_pool] + // Import the Compute library + const computeLib = require('@google-cloud/compute'); + const compute = computeLib.protos.google.cloud.compute.v1; + + // Instantiate a diskClient + const disksClient = new computeLib.DisksClient(); + // Instantiate a zoneOperationsClient + const zoneOperationsClient = new computeLib.ZoneOperationsClient(); + + /** + * TODO(developer): Update these variables before running the sample. + */ + // Project ID or project number of the Google Cloud project you want to use. + const projectId = await disksClient.getProjectId(); + // The zone where your VM and new disk are located. + const zone = 'europe-central2-b'; + // The name of the new disk + const diskName = 'disk-name-from-pool'; + // The name of the storage pool + const storagePoolName = 'storage-pool-name-hyperdisk'; + // Link to the storagePool you want to use. Use format: + // https://www.googleapis.com/compute/v1/projects/{projectId}/zones/{zone}/storagePools/{storagePoolName} + const storagePool = `https://www.googleapis.com/compute/v1/projects/${projectId}/zones/${zone}/storagePools/${storagePoolName}`; + // The type of disk. This value uses the following format: + // "zones/{zone}/diskTypes/(hyperdisk-balanced|hyperdisk-extreme|hyperdisk-ml|hyperdisk-throughput)". + // For example: "zones/us-west3-b/diskTypes/hyperdisk-balanced" + const diskType = `zones/${zone}/diskTypes/hyperdisk-balanced`; + // Size of the new disk in gigabytes. + const diskSizeGb = 10; + // Optional: For Hyperdisk Balanced or Hyperdisk Extreme disks, + // this is the number of I/O operations per second (IOPS) that the disk can handle. + const provisionedIops = 3000; + // Optional: For Hyperdisk Balanced or Hyperdisk Throughput volumes, + // this is an integer that represents the throughput, + // measured in MiB per second, that the disk can handle. + const provisionedThroughput = 140; + + async function callCreateComputeHyperdiskFromPool() { + // Create a disk + const disk = new compute.Disk({ + sizeGb: diskSizeGb, + name: diskName, + type: diskType, + zone, + storagePool, + provisionedIops, + provisionedThroughput, + }); + + const [response] = await disksClient.insert({ + project: projectId, + zone, + diskResource: disk, + }); + + let operation = response.latestResponse; + + // Wait for the create disk operation to complete. + while (operation.status !== 'DONE') { + [operation] = await zoneOperationsClient.wait({ + operation: operation.name, + project: projectId, + zone: operation.zone.split('/').pop(), + }); + } + + const hyperdisk = ( + await disksClient.get({ + project: projectId, + zone, + disk: diskName, + }) + )[0]; + + console.log(JSON.stringify(hyperdisk)); + } + + await callCreateComputeHyperdiskFromPool(); + // [END compute_hyperdisk_create_from_pool] +} + +main().catch(err => { + console.error(err); + process.exitCode = 1; +}); diff --git a/compute/test/createComputeHyperdisk.test.js b/compute/test/createComputeHyperdisk.test.js index 252ce9ccc0..ac4721f764 100644 --- a/compute/test/createComputeHyperdisk.test.js +++ b/compute/test/createComputeHyperdisk.test.js @@ -18,10 +18,9 @@ const path = require('path'); const {assert} = require('chai'); -const {describe, it} = require('mocha'); +const {before, after, describe, it} = require('mocha'); const cp = require('child_process'); const {DisksClient} = require('@google-cloud/compute').v1; -const {deleteDisk} = require('./util'); const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); const cwd = path.join(__dirname, '..'); @@ -34,10 +33,24 @@ describe('Create compute hyperdisk', async () => { before(async () => { projectId = await disksClient.getProjectId(); + try { + // Ensure resource is deleted attempting to recreate it + await disksClient.delete({ + project: projectId, + disk: diskName, + zone, + }); + } catch { + // ok to ignore (resource doesn't exist) + } }); after(async () => { - await deleteDisk(disksClient, projectId, zone, diskName); + await disksClient.delete({ + project: projectId, + disk: diskName, + zone, + }); }); it('should create a new hyperdisk', () => { diff --git a/compute/test/createComputeHyperdiskFromPool.test.js b/compute/test/createComputeHyperdiskFromPool.test.js new file mode 100644 index 0000000000..e210e66c35 --- /dev/null +++ b/compute/test/createComputeHyperdiskFromPool.test.js @@ -0,0 +1,128 @@ +/* + * 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('chai'); +const {after, before, describe, it} = require('mocha'); +const cp = require('child_process'); +const {DisksClient, StoragePoolsClient} = require('@google-cloud/compute').v1; + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Create compute hyperdisk from pool', async () => { + const diskName = 'disk-name-from-pool'; + const zone = 'europe-central2-b'; + const storagePoolName = 'storage-pool-name-hyperdisk'; + const disksClient = new DisksClient(); + const storagePoolsClient = new StoragePoolsClient(); + let projectId; + + before(async () => { + projectId = await disksClient.getProjectId(); + + // Ensure resources are deleted before attempting to recreate them + try { + await disksClient.delete({ + project: projectId, + disk: diskName, + zone, + }); + } catch (err) { + // Should be ok to ignore (resource doesn't exist) + console.error(err); + } + + try { + await storagePoolsClient.delete({ + project: projectId, + storagePool: storagePoolName, + zone, + }); + } catch (err) { + // Should be ok to ignore (resource doesn't exist) + console.error(err); + } + + await storagePoolsClient.insert({ + project: projectId, + storagePoolResource: { + name: storagePoolName, + poolProvisionedCapacityGb: 10240, + poolProvisionedIops: 10000, + poolProvisionedThroughput: 1024, + storagePoolType: `projects/${projectId}/zones/${zone}/storagePoolTypes/hyperdisk-balanced`, + capacityProvisioningType: 'advanced', + zone, + }, + zone, + }); + }); + + after(async () => { + // Trying to delete the disk too quickly seems to fail + const deleteDisk = async () => { + setTimeout(async () => { + await disksClient.delete({ + project: projectId, + disk: diskName, + zone, + }); + }, 120 * 1000); // wait two minutes + }; + + try { + await deleteDisk(); + } catch { + // Try one more time after repeating the delay + await deleteDisk(); + } + + // Need enough time after removing the disk before removing the pool + const deletePool = async () => { + setTimeout(async () => { + await storagePoolsClient.delete({ + project: projectId, + storagePool: storagePoolName, + zone, + }); + }, 120 * 1000); // wait two minutes + }; + + try { + await deletePool(); + } catch { + // Try one more time after repeating the delay + await deletePool(); + } + }); + + it('should create a new hyperdisk from pool', () => { + const response = JSON.parse( + execSync('node ./disks/createComputeHyperdiskFromPool.js', { + cwd, + }) + ); + + assert.equal(response.name, diskName); + assert.equal( + response.storagePool, + `https://www.googleapis.com/compute/v1/projects/${projectId}/zones/${zone}/storagePools/${storagePoolName}` + ); + }); +}); diff --git a/compute/test/createComputeHyperdiskPool.test.js b/compute/test/createComputeHyperdiskPool.test.js index 61c052af5b..f3d2cfb441 100644 --- a/compute/test/createComputeHyperdiskPool.test.js +++ b/compute/test/createComputeHyperdiskPool.test.js @@ -18,38 +18,39 @@ const path = require('path'); const assert = require('node:assert/strict'); -const {describe, it} = require('mocha'); +const {after, before, describe, it} = require('mocha'); const cp = require('child_process'); const {StoragePoolsClient} = require('@google-cloud/compute').v1; const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); const cwd = path.join(__dirname, '..'); -const storagePoolsClient = new StoragePoolsClient(); - -async function deleteStoragePool(projectId, zone, storagePoolName) { - try { - await storagePoolsClient.delete({ - project: projectId, - storagePool: storagePoolName, - zone, - }); - } catch (err) { - console.error('Deleting storage pool failed: ', err); - throw new Error(err); - } -} describe('Create compute hyperdisk pool', async () => { const storagePoolName = 'storage-pool-name'; const zone = 'us-central1-a'; + const storagePoolsClient = new StoragePoolsClient(); let projectId; before(async () => { projectId = await storagePoolsClient.getProjectId(); + try { + // Ensure resource is deleted attempting to recreate it + await storagePoolsClient.delete({ + project: projectId, + storagePool: storagePoolName, + zone, + }); + } catch { + // ok to ignore (resource doesn't exist) + } }); after(async () => { - await deleteStoragePool(projectId, zone, storagePoolName); + await storagePoolsClient.delete({ + project: projectId, + storagePool: storagePoolName, + zone, + }); }); it('should create a new storage pool', () => { diff --git a/compute/test/util.js b/compute/test/util.js index 9eb3e87f87..d192788ac1 100644 --- a/compute/test/util.js +++ b/compute/test/util.js @@ -82,22 +82,8 @@ async function deleteInstance(zone, instanceName) { } } -async function deleteDisk(disksClient, projectId, zone, diskName) { - try { - await disksClient.delete({ - project: projectId, - disk: diskName, - zone, - }); - } catch (err) { - console.error('Deleting disk failed: ', err); - throw new Error(err); - } -} - module.exports = { generateTestId, getStaleVMInstances, deleteInstance, - deleteDisk, };