Skip to content

Commit

Permalink
feat: create instances with processing units (#1279)
Browse files Browse the repository at this point in the history
Only one of processing units or nodes should be specified.
  • Loading branch information
skuruppu committed Jun 30, 2021
1 parent 96384a5 commit 05c2135
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 3 deletions.
67 changes: 67 additions & 0 deletions samples/instance-with-processing-units.js
@@ -0,0 +1,67 @@
/**
* Copyright 2021 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
*
* http://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 createInstanceWithProcessingUnits(instanceId, projectId) {
// [START spanner_create_instance_with_processing_units]
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';

// Creates a client
const spanner = new Spanner({
projectId: projectId,
});

const instance = spanner.instance(instanceId);

// Creates a new instance
try {
console.log(`Creating instance ${instance.formattedName_}.`);
const [, operation] = await instance.create({
config: 'regional-us-central1',
processingUnits: 500,
displayName: 'This is a display name.',
labels: {
['cloud_spanner_samples']: 'true',
},
});

console.log(`Waiting for operation on ${instance.id} to complete...`);
await operation.promise();

console.log(`Created instance ${instanceId}.`);

const [metadata] = await instance.getMetadata({
fieldNames: ['processingUnits'],
});
console.log(
`Instance ${instanceId} has ${metadata.processingUnits} ` +
'processing units.'
);
} catch (err) {
console.error('ERROR:', err);
}
// [END spanner_create_instance_with_processing_units]
}

module.exports.createInstanceWithProcessingUnits =
createInstanceWithProcessingUnits;
13 changes: 13 additions & 0 deletions samples/instance.js
Expand Up @@ -56,6 +56,10 @@ async function createInstance(instanceId, projectId) {
// [END spanner_create_instance]
}

const {
createInstanceWithProcessingUnits,
} = require('./instance-with-processing-units');

require('yargs')
.demand(1)
.command(
Expand All @@ -65,6 +69,15 @@ require('yargs')
opts => createInstance(opts.instanceName, opts.projectId)
)
.example('node $0 createInstance "my-instance" "my-project-id"')
.command(
'createInstanceWithProcessingUnits <instanceName> <projectId>',
'Creates an example instance in a Cloud Spanner instance with processing units.',
{},
opts => createInstanceWithProcessingUnits(opts.instanceName, opts.projectId)
)
.example(
'node $0 createInstanceWithProcessingUnits "my-instance" "my-project-id"'
)
.wrap(120)
.recommendCommands()
.epilogue('For more information, see https://cloud.google.com/spanner/docs')
Expand Down
25 changes: 23 additions & 2 deletions samples/system-test/spanner.test.js
Expand Up @@ -17,7 +17,7 @@
const {Spanner} = require('@google-cloud/spanner');
const {KeyManagementServiceClient} = require('@google-cloud/kms');
const {assert} = require('chai');
const {describe, it, before, after} = require('mocha');
const {describe, it, before, after, afterEach} = require('mocha');
const cp = require('child_process');
const pLimit = require('p-limit');

Expand Down Expand Up @@ -227,7 +227,7 @@ describe('Spanner', () => {
});

describe('instance', () => {
after(async () => {
afterEach(async () => {
const sample_instance = spanner.instance(SAMPLE_INSTANCE_ID);
await sample_instance.delete();
});
Expand All @@ -248,6 +248,27 @@ describe('Spanner', () => {
new RegExp(`Created instance ${SAMPLE_INSTANCE_ID}.`)
);
});

// create_instance_with_processing_units
it('should create an example instance with processing units', async () => {
const output = execSync(
`${instanceCmd} createInstanceWithProcessingUnits "${SAMPLE_INSTANCE_ID}" ${PROJECT_ID}`
);
assert.match(
output,
new RegExp(
`Waiting for operation on ${SAMPLE_INSTANCE_ID} to complete...`
)
);
assert.match(
output,
new RegExp(`Created instance ${SAMPLE_INSTANCE_ID}.`)
);
assert.match(
output,
new RegExp(`Instance ${SAMPLE_INSTANCE_ID} has 500 processing units.`)
);
});
});

// check that base instance was created
Expand Down
15 changes: 14 additions & 1 deletion src/index.ts
Expand Up @@ -92,6 +92,7 @@ export interface RequestConfig {
export interface CreateInstanceRequest {
config?: string;
nodes?: number;
processingUnits?: number;
displayName?: string;
labels?: {[k: string]: string} | null;
gaxOptions?: CallOptions;
Expand Down Expand Up @@ -383,12 +384,24 @@ class Spanner extends GrpcService {
{
name: formattedName,
displayName,
nodeCount: config.nodes || 1,
nodeCount: config.nodes,
processingUnits: config.processingUnits,
},
config
),
};

if (reqOpts.instance.nodeCount && reqOpts.instance.processingUnits) {
throw new Error(
['Only one of nodeCount or processingUnits can be specified.'].join('')
);
}
if (!reqOpts.instance.nodeCount && !reqOpts.instance.processingUnits) {
// If neither nodes nor processingUnits are specified, default to a
// nodeCount of 1.
reqOpts.instance.nodeCount = 1;
}

delete reqOpts.instance.nodes;
delete reqOpts.instance.gaxOptions;

Expand Down
27 changes: 27 additions & 0 deletions test/index.ts
Expand Up @@ -557,6 +557,7 @@ describe('Spanner', () => {
name: PATH,
displayName: NAME,
nodeCount: 1,
processingUnits: undefined,
config: `projects/project-id/instanceConfigs/${CONFIG.config}`,
},
});
Expand Down Expand Up @@ -587,6 +588,32 @@ describe('Spanner', () => {
spanner.createInstance(NAME, config, assert.ifError);
});

it('should create an instance with processing units', done => {
const processingUnits = 500;
const config = Object.assign({}, CONFIG, {processingUnits});

spanner.request = config => {
assert.strictEqual(
config.reqOpts.instance.processingUnits,
processingUnits
);
assert.strictEqual(config.reqOpts.instance.nodeCount, undefined);
done();
};

spanner.createInstance(NAME, config, assert.ifError);
});

it('should throw if both nodes and processingUnits are given', () => {
const nodeCount = 1;
const processingUnits = 500;
const config = Object.assign({}, CONFIG, {nodeCount, processingUnits});

assert.throws(() => {
spanner.createInstance(NAME, config);
}, /Only one of nodeCount or processingUnits can be specified\./);
});

it('should accept gaxOptions', done => {
const cfg = Object.assign({}, CONFIG, {gaxOptions: {}});
spanner.request = config => {
Expand Down
3 changes: 3 additions & 0 deletions test/mockserver/mockinstanceadmin.ts
Expand Up @@ -209,6 +209,9 @@ export class MockInstanceAdmin {
nodeCount: call.request!.instance
? call.request!.instance.nodeCount
: undefined,
processingUnits: call.request!.instance
? call.request!.instance.processingUnits
: undefined,
labels: call.request!.instance
? call.request!.instance.labels
: undefined,
Expand Down
23 changes: 23 additions & 0 deletions test/spanner.ts
Expand Up @@ -3288,6 +3288,29 @@ describe('Spanner with mock server', () => {
);
});

it('should create an instance with processing units', async () => {
const [createdInstance] = await spanner
.createInstance('new-instance', {
config: 'test-instance-config',
processingUnits: 500,
})
.then(data => {
const operation = data[1];
return operation.promise() as Promise<
[Instance, CreateInstanceMetadata, object]
>;
})
.then(response => {
return response;
});
assert.strictEqual(
createdInstance.name,
`projects/${spanner.projectId}/instances/new-instance`
);
assert.strictEqual(createdInstance.processingUnits, 500);
assert.strictEqual(createdInstance.nodeCount, 0);
});

it('should update an instance', async () => {
const instance = spanner.instance(mockInstanceAdmin.PROD_INSTANCE_NAME);
const [updatedInstance] = await instance
Expand Down

0 comments on commit 05c2135

Please sign in to comment.