【问题标题】:NodeJS Lambda issue with order of operationsNodeJS Lambda问题与操作顺序
【发布时间】:2017-04-22 00:09:03
【问题描述】:

主要问题是当代码使用 CodePipeline 执行时,它会下载一个输入工件,解压缩下载的工件和 grep template.yml 以获得一个名为 Function name 的字符串。它大部分时间都有效,但偶尔会说找不到 template.yml 文件。如果我再次重新运行它,它将正常工作而不会出现错误。任何帮助表示赞赏。谢谢!

'使用严格'

// dependencies
const child_process = require('child_process')
const fs = require('fs')
const path = require('path')
const stripDirs = require('strip-dirs')
const AWS = require('aws-sdk')
const unzip = require('unzip')
const shell = require('shelljs')

// global process variable is still accessible
process.env['PATH'] = process.env['PATH'] + ':' + process.env['/tmp']

// get reference to S3 client
const s3 = new AWS.S3({maxRetries: 1, "signatureVersion":"v4"})

exports.handler = function(event, context) {

  const codepipeline = new AWS.CodePipeline()
  let jobId

  // Notify AWS CodePipeline of a successful job
  function putJobSuccess(message) {
    console.log(message)
    codepipeline.putJobSuccessResult({ jobId },
      (err, data) => {
        if (err)
          context.fail(err)
        else
          context.succeed(message)
       })
  }

  // Notify AWS CodePipeline of a failed job
  function putJobFailure(message) {
    console.error('job failure: ', message)
    codepipeline.putJobFailureResult({
      jobId,
      failureDetails: {
      message: JSON.stringify(message),
       type: 'JobFailed',
       externalExecutionId: context.invokeid
      }
    }, (err, data) => context.fail(message))
  }


  try {
const jobEvent = event['CodePipeline.job']
jobId = jobEvent.id
const jobData = jobEvent.data
console.log(jobData)

// Retrieve the value of UserParameters from the Lambda action configuration in AWS CodePipeline, in this case a URL which will be
// health checked by this function.
const userParams = jobData.actionConfiguration.configuration.UserParameters
const userParamsSplit = userParams && userParams.split(' ')
if (!userParams || !userParamsSplit || userParamsSplit.length !== 1)
  throw new Error('The User Parameters field must contain three items separated by spaces: the input artifact name, the location of the lambda function code within the input artifact, and the destination lambda function name')

const artifactName = userParamsSplit[0]
const artifact = jobData.inputArtifacts.find(a => a.name === artifactName && a.location.type === 'S3')
if (!artifact) throw new Error('artifact not found: ', artifactName)
console.log('Artifact:', artifact)

const tmpDir = '/tmp'

const artifactZipFilePath = path.join(tmpDir, stripDirs(artifact.location.s3Location.objectKey, 2))
console.log('ZipFilePath:', artifactZipFilePath)

s3.getObject({
  Bucket: artifact.location.s3Location.bucketName,
  Key: artifact.location.s3Location.objectKey
}, (err, data) => {
  if (err) return putJobFailure(`could not download artifact from S3: ${err.stack || err}`)
  console.log()
  fs.writeFileSync(artifactZipFilePath, data.Body)

const zipFileContents = fs.readFileSync(artifactZipFilePath)
const zipFileDir = stripDirs(artifact.location.s3Location.objectKey, 2).slice(0, -4)
console.log('zipFileDir:', zipFileDir)

const newZipArtifact = path.join('/tmp', stripDirs(artifact.location.s3Location.objectKey, 2))
fs.createReadStream(newZipArtifact).pipe(unzip.Extract({ path: '/tmp' }))
const prependFunctionName = shell.grep('FunctionName', '/tmp/template.yml')
const destLambdaFunctionName = prependFunctionName.replace(/^.+:/,'').replace(/\s/g,'')
const command = require('child_process').exec

command(`echo ${destLambdaFunctionName}`, (error, stdout, stderr) => {
  if (error) {
    console.log("Error occurs");
    console.error(error);
    return;
  }
  console.log(stdout);
  console.log(stderr);
})

lambda.updateFunctionCode({
    FunctionName: destLambdaFunctionName,
    Publish: true,
    ZipFile: zipFileContents
  }, function(err, data) {
    if (err) console.log(err, err.stack) // an error occurred
    else     console.log(data)           // successful response
    const sqsMsg = (data)
    putJobSuccess('lambda code updated')
  })
})
} catch (err) {
putJobFailure(err.stack)
 }
}

【问题讨论】:

    标签: node.js aws-lambda aws-sdk aws-codepipeline


    【解决方案1】:

    试一试:

    // dependencies
    const AWS = require('aws-sdk')
    const unzip = require('unzip')
    
    // global process variable is still accessible
    process.env['PATH'] = process.env['PATH'] + ':' + process.env['/tmp']
    // get reference to CodePipeline client
    const codepipeline = new AWS.CodePipeline()
    // get reference to S3 client
    const s3 = new AWS.S3({
      maxRetries: 1,
      "signatureVersion": "v4"
    })
    
    exports.handler = function(event, context) {
      let jobId
    
      // Notify AWS CodePipeline of a successful job
      function putJobSuccess(message) {
        console.log(message)
        if (!jobId) return context.fail(err)
        codepipeline.putJobSuccessResult({
            jobId
          },
          (err, data) => {
            if (err)
              context.fail(err)
            else
              context.succeed(message)
          })
      }
    
      // Notify AWS CodePipeline of a failed job
      function putJobFailure(message) {
        console.error('job failure: ', message)
        if (!jobId) return context.fail(err)
        codepipeline.putJobFailureResult({
          jobId,
          failureDetails: {
            message: JSON.stringify(message),
            type: 'JobFailed',
            externalExecutionId: context.invokeid
          }
        }, (err, data) => context.fail(message))
      }
    
    
      try {
        const jobEvent = event['CodePipeline.job']
        jobId = jobEvent.id
        const jobData = jobEvent.data
        console.log(jobData)
    
        // Retrieve the value of UserParameters from the Lambda action configuration in AWS CodePipeline, in this case a URL which will be
        // health checked by this function.
        const userParams = jobData.actionConfiguration.configuration.UserParameters
        const userParamsSplit = userParams && userParams.split(' ')
        if (!userParams || !userParamsSplit || userParamsSplit.length !== 1)
          throw new Error('The User Parameters field must contain three items separated by spaces: the input artifact name, the location of the lambda function code within the input artifact, and the destination lambda function name')
    
        const artifactName = userParamsSplit[0]
        const artifact = jobData.inputArtifacts.find(a => a.name === artifactName && a.location.type === 'S3')
        if (!artifact) throw new Error('artifact not found: ', artifactName)
        console.log('Artifact:', artifact)
    
        let destLambdaFunctionName = null
        let foundTemplateYml = false
        const Bucket = artifact.location.s3Location.bucketName
        const Key = artifact.location.s3Location.objectKey
    
        s3.getObject({ Bucket, Key })
          .createReadStream()
          .on('error', (err) => putJobFailure(`could not download artifact from S3: ${err.stack || err}`))
          .pipe(unzip.Parse())
          .on('error', (err) => putJobFailure(`could not parse zip from S3: ${err.stack || err}`))
          .on('entry', (entry) => {
            if (entry.path === 'template.yml') {
              let chunks = []
              foundTemplateYml = true
              entry.on('data', (chunk) => chunks.push(chunk)).on('end', () => {
                const match = Buffer.concat(chunks).toString().match(/FunctionName: (.+)/)
                if (!match || !match[1]) return putJobFailure(`could not find FunctionName in template.yml`)
                destLambdaFunctionName = match[1]
                lambda.updateFunctionCode({
                  FunctionName: destLambdaFunctionName,
                  Publish: true,
                  S3Bucket: Bucket,
                  S3Key: Key
                }, (err, data) => {
                  if (err) return putJobFailure(`could not update Lambda function code for ${destLambdaFunctionName}: ${err.stack || err}`)
                  console.log(data)
                  putJobSuccess('lambda code updated')
                })
              })
            } else {
              entry.autodrain()
            }
          })
          .on('end', () => {
            if (!foundTemplateYml) {
              putJobFailure(`could not find template.yml in zip`)
            }
          })
      } catch (err) {
        putJobFailure(err.stack)
      }
    }
    

    【讨论】:

    • 工作就像一个魅力。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2019-03-29
    • 1970-01-01
    相关资源
    最近更新 更多