首页 > 解决方案 > Firebase Cloud Function with Google Secrets Manager 如何让 async/await 工作

问题描述

我有一个小问题,我的 firebase 云功能在我通过调用 Google Secret Manager API 获得 API 密钥之前完成。API 密钥很重要,因为它通过 API 调用从外部服务器获取数据,以将 API 调用的结果存储在 Google Cloud Storage 中。

这是我的代码,

'use strict';

// Request Data From A URL
var request = require('request');
var https = require('https');

// Var Firebase Functions
var functions = require('firebase-functions');
const admin = require('firebase-admin');

// Initalise App
admin.initializeApp();
// init firebase admin and get the default project id
const projectId = admin.instanceId().app.options.projectId

const util = require('util');
// Imports the Google Storage client library
const {Storage} = require('@google-cloud/storage');

// Import the Secret Manager client and instantiate it:
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');
const secretClient = new SecretManagerServiceClient();

// Setting Timeout in Seconds - default is 1 second
// The maximum value for timeoutSeconds is 540, or 9 minutes. Valid values for memory are:
// 128MB, 256MB, 512MB, 1GB, 2GB

const runtimeOpts = {
  timeoutSeconds: 300,
  memory: '512MB'
}

let apikey = '';

// From were the data comes
// 1 = Shoreserver
var shipid = '1';

// Get the current date 
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();

today = '0000' + '-' + '00' + '-' + '00';

// Creates a storage client
const storage = new Storage({
  projectId: projectId,
});

// Set Bucket Name
const bucket = storage.bucket('masterlog');

/**
 * Delete a file from a storage bucket and download a new file from remote location to store in the bucket
 */
exports.getEmilyAPItoStorage = functions
  .runWith(runtimeOpts)
  .region('europe-west1')
  .https.onRequest((req, res) => {

    // Get Secret
    ***(async () => { apikey = await getSecret() })***
    console.info(`ApiKey Secret: ${apikey}`);

    // First we want to delete the current file, the filename is always the same.
    // Delete files in the Bucket people
    bucket.deleteFiles({
      prefix: `people.json`
    })
    .catch( (err) => {
      console.log(`Failed to delete people.json`);
    });

    // Start of the requesting different tables
    // Table to get data from
    var apitable = 'people';

    // Set destination filename
    const people = bucket.file('people.json'); 

    var url = 'https://<URL>/api/' + shipid + '/' + apitable + '?apikey=' + apikey + '&syncdate=' + today;

    // Set the options to make the request
    var options = {
      url: url,
      strictSSL: false,
      secureProtocol: 'TLSv1_method'
    }

    // Make a request for the API and store the file in Storage
    request(options)
      .pipe(people
      .createWriteStream({sourceFormat: 'NEWLINE_DELIMITED_JSON'}))
      .on('finish',  function(error) {
      if (error) {
          console.log(error);
          res.status(500).send(error);
      } else {
          console.log( "- done!")
          res.status(200).send("OK");
      }
    });
    // End Function with status code 200


    // Set destination filename
    const agents = bucket.file('agents.json'); 

    // Table to get data from
    var apitable = 'ports';

    var url = 'https://emily.greenpeace.net/api/' + shipid + '/' + apitable + '?apikey=' + apikey + '&syncdate=' + today;

    // Set the options to make the request
    var options = {
      url: url,
      strictSSL: false,
      secureProtocol: 'TLSv1_method'
    }

    // Make a request for the API and store the file in Storage
    request(options)
      .pipe(agents
      .createWriteStream({sourceFormat: 'NEWLINE_DELIMITED_JSON'}))
      .on('finish',  function(error) {
      if (error) {
          console.log(error);
          res.status(500).send(error);
      } else {
          console.log( "- done!")
          res.status(200).send("OK");
      }
    });
    // End Function with status code 200 

    async function getSecret() {
        // Access the secret.
        const resource_name = 'projects/' + projectId + '/secrets/emilyapikey/versions/latest';
        let [version] = await secretClient.accessSecretVersion({name: resource_name})    
        console.info(`Found secret ${version.payload.data} with state ${version.state}`);
        apikey = version.payload.data;
        return apikey;
    }    
  });

我可以在函数 getSecret() 中从 Google Secrets Manager 获取 API 密钥,当我将 API 密钥设置到我的服务器时,API 密钥不可用。我的期望是 getSecret 将在执行其余代码之前完成。

如果有人能洞察她我所缺少的东西,我真的很想听听你的意见。

标签: javascriptgoogle-cloud-platformasync-awaitgoogle-cloud-functions

解决方案


如果您想在任何函数中使用 async/await,则必须将该函数声明为 async:

exports.getEmilyAPItoStorage = functions
  .runWith(runtimeOpts)
  .region('europe-west1')
  .https.onRequest(async (req, res) => { ... })

然后您可以在其正文中的代码中等待:

const apikey = await getSecret()

推荐阅读