1414 * limitations under the License.
1515 */
1616
17- import { Common } from '../types/common-types' ;
17+ import { AuthenticationConfig , Common } from '../types/common-types' ;
1818const common : Common = require ( '@google-cloud/common' ) ;
1919
2020import * as crypto from 'crypto' ;
2121import { EventEmitter } from 'events' ;
2222import * as extend from 'extend' ;
23+ import * as dns from 'dns' ;
2324import * as fs from 'fs' ;
2425
2526import { GcpMetadata } from '../types/gcp-metadata-types' ;
@@ -235,7 +236,7 @@ export class Debuglet extends EventEmitter {
235236
236237 const jsStats = fileStats . selectStats ( / .j s $ / ) ;
237238 const mapFiles = fileStats . selectFiles ( / .m a p $ / , 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_ (
0 commit comments