Friday 21 April 2017

NodeJS Lambda issue with order of operations

The main issue is when the code executes using CodePipeline it will download an input artifact, unzip the downloaded artifact and grep template.yml for a string called Function name. It works most of the time but will fail saying template.yml file not found occasionally. If I rerun it again it will work without errors. Any help is appreciate. Thanks!

'use strict'

// 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)
 }
}



via jnbankston

No comments:

Post a Comment