Skip to content
This repository was archived by the owner on Apr 3, 2024. It is now read-only.

Commit 8ddb5ec

Browse files
authored
Simplify metadata (#308)
* debuglet: add easier to test metadata operations * simplify metadata acquision
1 parent 800ed08 commit 8ddb5ec

File tree

3 files changed

+225
-92
lines changed

3 files changed

+225
-92
lines changed

src/agent/debuglet.ts

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {Common} from '../types/common-types';
17+
import {AuthenticationConfig, Common} from '../types/common-types';
1818
const common: Common = require('@google-cloud/common');
1919

2020
import * as crypto from 'crypto';
2121
import {EventEmitter} from 'events';
2222
import * as extend from 'extend';
23+
import * as dns from 'dns';
2324
import * as fs from 'fs';
2425

2526
import {GcpMetadata} from '../types/gcp-metadata-types';
@@ -235,7 +236,7 @@ export class Debuglet extends EventEmitter {
235236

236237
const jsStats = fileStats.selectStats(/.js$/);
237238
const mapFiles = fileStats.selectFiles(/.map$/, process.cwd());
238-
SourceMapper.create(mapFiles, function(err3, mapper) {
239+
SourceMapper.create(mapFiles, async function(err3, mapper) {
239240
if (err3) {
240241
that.logger_.error('Error processing the sourcemaps.', err3);
241242
that.emit('initError', err3);
@@ -251,48 +252,44 @@ export class Debuglet extends EventEmitter {
251252

252253
that.logger_.info('Unique ID for this Application: ' + id);
253254

254-
that.getProjectId_(function(
255-
err4: Error|null, project: string|undefined, onGCP?: boolean) {
256-
if (err4) {
257-
that.logger_.error(
258-
'Unable to discover projectId. Please provide ' +
259-
'the projectId to be able to use the Debuglet',
260-
err4);
261-
that.emit('initError', err4);
262-
return;
263-
}
255+
const onGCP = await Debuglet.runningOnGCP();
256+
let project: string;
257+
try {
258+
project = await Debuglet.getProjectId(that.debug_.options);
259+
} catch (err) {
260+
that.logger_.error(err.message);
261+
that.emit('initError', err);
262+
return;
263+
}
264264

265-
that.getSourceContext_(function(err5, sourceContext) {
266-
if (err5) {
267-
that.logger_.warn('Unable to discover source context', err5);
268-
// This is ignorable.
269-
}
265+
that.getSourceContext_(function(err5, sourceContext) {
266+
if (err5) {
267+
that.logger_.warn('Unable to discover source context', err5);
268+
// This is ignorable.
269+
}
270270

271-
if (semver.satisfies(process.version, '5.2 || <4')) {
272-
// Using an unsupported version. We report an error
273-
// message about the Node.js version, but we keep on
274-
// running. The idea is that the user may miss the error
275-
// message on the console. This way we can report the
276-
// error when the user tries to set a breakpoint.
277-
that.logger_.error(NODE_VERSION_MESSAGE);
278-
}
271+
if (semver.satisfies(process.version, '5.2 || <4')) {
272+
// Using an unsupported version. We report an error
273+
// message about the Node.js version, but we keep on
274+
// running. The idea is that the user may miss the error
275+
// message on the console. This way we can report the
276+
// error when the user tries to set a breakpoint.
277+
that.logger_.error(NODE_VERSION_MESSAGE);
278+
}
279279

280-
// We can register as a debuggee now.
281-
that.logger_.debug('Starting debuggee, project', project);
282-
that.running_ = true;
283-
// TODO: Address the case where `project` is `undefined`.
284-
that.project_ = project as string;
285-
that.debuggee_ = Debuglet.createDebuggee(
286-
// TODO: Address the case when `project` is
287-
// `undefined`.
288-
// TODO: Address the case when `id` is `undefined`.
289-
project as string, id as string, that.config_.serviceContext,
290-
// TODO: Handle the case where `onGCP` is `undefined`.
291-
sourceContext, that.config_.description, null, onGCP as boolean);
292-
that.scheduleRegistration_(0 /* immediately */);
293-
that.emit('started');
294-
});
280+
// We can register as a debuggee now.
281+
that.logger_.debug('Starting debuggee, project', project);
282+
that.running_ = true;
283+
// TODO: Address the case where `project` is `undefined`.
284+
that.project_ = project;
285+
that.debuggee_ = Debuglet.createDebuggee(
286+
// TODO: Address the case when `id` is `undefined`.
287+
project, id as string, that.config_.serviceContext, sourceContext,
288+
that.config_.description, null, onGCP);
289+
that.scheduleRegistration_(0 /* immediately */);
290+
that.emit('started');
295291
});
292+
296293
});
297294
}
298295

@@ -372,37 +369,37 @@ export class Debuglet extends EventEmitter {
372369
return new Debuggee(properties);
373370
}
374371

375-
/**
376-
* @private
377-
*/
378-
getProjectId_(
379-
callback: (err: Error|null, project?: string, onGCP?: boolean) => void):
380-
void {
381-
const that = this;
372+
static async getProjectId(options: AuthenticationConfig): Promise<string> {
373+
const project = options.projectId || process.env.GCLOUD_PROJECT ||
374+
await this.getProjectIdFromMetadata();
375+
if (!project) {
376+
const msg = 'Unable to discover projectId. Please provide the ' +
377+
'projectId to be able to use the Debug agent';
378+
throw new Error(msg);
379+
}
380+
return project;
381+
}
382382

383-
// We need to figure out whether we are running on GCP. We can use our
384-
// ability to access the metadata service as a test for that.
385-
// TODO: change this to getProjectId in the future.
386-
// TODO: Determine if it is expected that the second argument (which was
387-
// named `response`) is not used.
388-
metadata.project(
389-
'project-id',
390-
function(
391-
err: Error, _res: http.ServerResponse, metadataProject: string) {
392-
// We should get an error if we are not on GCP.
393-
const onGCP = !err;
394-
395-
// We perfer to use the locally available projectId as that is least
396-
// surprising to users.
397-
const project = that.debug_.options.projectId ||
398-
process.env.GCLOUD_PROJECT || metadataProject;
399-
400-
// We if don't have a projectId by now, we fail with an error.
401-
if (!project) {
402-
return callback(err);
403-
}
404-
return callback(null, project, onGCP);
405-
});
383+
static async runningOnGCP(): Promise<boolean> {
384+
const lookup = promisify(dns.lookup);
385+
try {
386+
await lookup('metadata.google.internal.');
387+
return true;
388+
} catch (err) {
389+
// Take failure to resolve metadata service to indicate that we are not
390+
// running on GCP.
391+
return false;
392+
}
393+
}
394+
395+
static getProjectIdFromMetadata(): Promise<string> {
396+
return new Promise<string>((resolve, reject) => {
397+
metadata.project(
398+
'project-id',
399+
(err: Error, _res: http.ServerResponse, projectId: string) => {
400+
err ? reject(err) : resolve(projectId);
401+
});
402+
});
406403
}
407404

408405
getSourceContext_(

test/nocks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function nockProjectId(reply) {
4646
return nock('http://metadata.google.internal')
4747
.get('/computeMetadata/v1/project/project-id')
4848
.once()
49-
.reply(reply);
49+
.reply(200, reply);
5050
}
5151

5252
module.exports = {

0 commit comments

Comments
 (0)