Socket
Socket
Sign inDemoInstall

serverless-leo

Package Overview
Dependencies
10
Maintainers
1
Versions
67
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.3.16 to 1.4.0

87

index.js

@@ -5,4 +5,6 @@ 'use strict'

const { execSync } = require('child_process')
const BbPromise = require('bluebird')
const path = require('path')
const fs = require('fs')
const validate = require('./lib/validate')

@@ -41,2 +43,26 @@ const compileLeo = require('./lib/leo')

}
},
'invoke-bot': {
usage: 'Run a leo bot locally',
lifecycleEvents: [
'leo-local'
],
options: {
botNumber: {
usage: 'Specify the bot number (default is 0)',
shortcut: 'b'
},
functionName: {
usage: 'Specify the name of the function for the bot',
shortcut: 'f'
},
name: {
usage: 'Specify the name of the bot',
shortcut: 'n'
},
stage: {
usage: 'Specify the stage of the bot',
shortcut: 's'
}
}
}

@@ -77,2 +103,63 @@ }

.then(this.compileLeo)
},
'invoke-bot:leo-local': () => {
const { functionName, name, stage = 'test', botNumber = 0 } = this.serverless.pluginManager.cliOptions
const lambdaName = functionName || name
const regex = new RegExp(lambdaName)
const functions = Object.keys(this.serverless.service.functions)
const matchingFunctions = functions.filter(i => regex.test(i))
let functionKey
if (matchingFunctions.length > 1) {
functionKey = matchingFunctions.find(i => i === lambdaName)
if (!functionKey) {
throw new Error('Multiple matches found for bot name/lambda, please be more specific.')
}
} else if (matchingFunctions.length === 1) {
functionKey = matchingFunctions[0]
} else {
throw new Error('Could not match bot name/lambda in serverless defined functions.')
}
const pathSegments = this.serverless.service.functions[functionKey].handler.split(/\//)
pathSegments[pathSegments.length - 1] = 'serverless.yml'
const serverlessYml = fs.readFileSync(path.join(...pathSegments)).toString()
const serverlessJson = utils.ymlToJson(serverlessYml)
// Build the event to invoke the lambda with
let event
let eventIndex = 0
if (serverlessJson[functionKey].events.length === 1) {
event = serverlessJson[functionKey].events[0].leo
} else {
let filteredEvents = serverlessJson[functionKey].events.filter((event, index) => {
if (Object.values(event.leo).some(leoKey => name === leoKey)) {
eventIndex = index
return true
}
})
if (filteredEvents.length === 1) {
event = filteredEvents[0].leo
} else {
filteredEvents = serverlessJson[functionKey].events.filter((event, index) => {
if (Object.values(event.leo).some(leoKey => new RegExp(name).test(leoKey))) {
eventIndex = index
return true
}
})
if (filteredEvents.length === 1) {
event = filteredEvents[0].leo
}
}
}
if (!event) {
throw new Error('Could not match the bot name with the bot configurations')
}
const botInfo = utils.getBotInfo(this.serverless.service.service, stage, functionKey, serverlessJson[functionKey].events, eventIndex, event, botNumber)
event.botId = botInfo.id
event.__cron = {
id: botInfo.id,
iid: '0',
ts: Date.now(),
force: true
}
this.serverless.cli.log(`Invoking local lambda ${functionKey} with data: ${JSON.stringify(event)}`)
return execSync(`serverless invoke local -f ${functionKey} -d ${JSON.stringify(JSON.stringify(event))}`, { stdio: 'inherit' })
}

@@ -79,0 +166,0 @@ }

63

lib/leo.js

@@ -6,2 +6,3 @@ 'use strict'

const BbPromise = require('bluebird')
const { getBotInfo } = require('./utils')

@@ -32,8 +33,7 @@ module.exports = {

function addInstallProperty (botId, installProperty) {
if (botIds.includes(botId)) {
throw new Error(`Bot IDs must be unique. ${botId} has already been added to the cloudformation.`)
function addInstallProperty (installProperty) {
if (botIds.includes(installProperty.id)) {
throw new Error(`Bot Ids must be unique. ${installProperty.id} has already been added to the cloudformation.`)
}
installProperty.id = botId
botIds.push(botId)
botIds.push(installProperty.id)
if (registrations.length === 0) {

@@ -47,3 +47,3 @@ registrations.push(cloneDeep(customInstall))

}
currentRegister.Properties[botId] = installProperty
currentRegister.Properties[installProperty.id] = installProperty
}

@@ -61,25 +61,25 @@

const config = leoEvent.leo instanceof Object ? leoEvent.leo : false
const prefix = config && config.prefix ? `${config.prefix}` : undefined
const suffix = config && config.suffix ? `${config.suffix}` : undefined
const botPrefix = prefix ? `${prefix}-` : ''
const sourceQueue = config ? config.queue : leoEvent.leo
const botNumbers = times((config && config.botCount) || 1, Number)
botNumbers.forEach(botNumber => {
let botId
let botSuffix = suffix ? `-${suffix}` : botNumber > 0 ? '-' + botNumber : ''
// If there is no botPrefix, no source queue and multiple bots: add the eventIndex to the botSuffix (botId ultimately)
if (!botPrefix && !sourceQueue && leoEvents.length > 1) {
botSuffix = `-${eventIndex}${botSuffix}`
}
// Only add the queue to the bot name if there are multiple events and no prefix
if (sourceQueue && !botPrefix && leoEvents.length > 1) {
botId = `${this.serverless.service.service}-${stage}-${botPrefix}${sourceQueue}-${ymlFunctionName}${botSuffix}`
} else {
botId = `${this.serverless.service.service}-${stage}-${botPrefix}${ymlFunctionName}${botSuffix}`
}
const {
id,
cron,
name,
prefix,
queue,
register,
suffix
} = getBotInfo(this.serverless.service.service, stage, ymlFunctionName, leoEvents, eventIndex, config, botNumber)
const installProperty = {
id,
name,
time: cron,
type: 'cron',
settings: {
botNumber,
codeOverrides: config && config.codeOverrides,
prefix,
queue,
source: queue,
suffix

@@ -91,20 +91,5 @@ },

}
if (sourceQueue) {
installProperty.settings.source = sourceQueue
installProperty.settings.queue = sourceQueue
if (queue || cron || register) {
addInstallProperty(installProperty)
}
if (config && config.cron) {
installProperty.time = config.cron
}
if (config && config.name) {
installProperty.name = config.name
} else {
installProperty.name = botId.replace(`${this.serverless.service.service}-${stage}-`, '')
}
if (config && config.codeOverrides) {
installProperty.settings.codeOverrides = config.codeOverrides
}
if (sourceQueue || (config && (config.cron || config.register))) {
addInstallProperty(botId, installProperty)
}
})

@@ -111,0 +96,0 @@ })

@@ -50,3 +50,119 @@ const fs = require('fs')

const getBotInfo = (serviceName, stage, ymlFunctionName, leoEvents, leoEventIndex, config, botNumber) => {
let id
let cron
let name
const prefix = config && config.prefix ? `${config.prefix}` : undefined
const suffix = config && config.suffix ? `${config.suffix}` : undefined
const botPrefix = prefix ? `${prefix}-` : ''
const queue = config ? config.queue : leoEvents[leoEventIndex].leo
let botSuffix = suffix ? `-${suffix}` : botNumber > 0 ? '-' + botNumber : ''
// If there is no botPrefix, no source queue and multiple bots: add the eventIndex to the botSuffix (bot id ultimately)
if (!botPrefix && !queue && leoEvents.length > 1) {
botSuffix = `-${leoEventIndex}${botSuffix}`
}
// Only add the queue to the bot name if there are multiple events and no prefix
if (queue && !botPrefix && leoEvents.length > 1) {
id = `${serviceName}-${stage}-${botPrefix}${queue}-${ymlFunctionName}${botSuffix}`
} else {
id = `${serviceName}-${stage}-${botPrefix}${ymlFunctionName}${botSuffix}`
}
if (config && config.cron) {
cron = config.cron
}
if (config && config.name) {
name = config.name
} else {
name = id.replace(`${serviceName}-${stage}-`, '')
}
return {
cron,
id,
name,
prefix,
queue,
register: config && config.register,
suffix
}
}
const ymlToJson = yml => {
if (/\t/.test(yml)) {
throw new Error('Yml error: tabs are not expected. Use double spaced indentation.')
}
try {
const json = {}
let section = []
const spaceRegex = / {2}/g
const lines = yml.replace(/\r/g, '').split('\n')
lines.forEach(actualLine => {
if (/^w*$/.test(actualLine)) {
return
}
let isArrayItem = false
let line = actualLine
const spaceMatch = line.match(spaceRegex)
const indentation = spaceMatch ? spaceMatch.length : 0
if (/^[\s]*-/.test(line)) {
line = line.replace(/-/, '')
isArrayItem = true
}
const splitLine = line.replace(spaceRegex, '').split(/:\s/).map(i => i.replace(/^[\s]*/, '').replace(/[\s]*$/, ''))
const endingColonRegex = /:$/
const key = splitLine[0].replace(endingColonRegex, '')
if (indentation < section.length) {
section = section.slice(0, indentation)
}
let objToManipulate = getObjViaPath(json, section)
if (!objToManipulate) {
mutateViaPath(json, section, {})
objToManipulate = getObjViaPath(json, section)
}
if (isArrayItem) {
if (!Array.isArray(objToManipulate)) {
mutateViaPath(json, section, [])
objToManipulate = getObjViaPath(json, section)
}
if (splitLine[1] === undefined && !endingColonRegex.test(splitLine[0])) {
objToManipulate.push(key)
} else {
const newObject = {}
newObject[key] = splitLine[1] === '' ? {} : splitLine[1]
objToManipulate.push(newObject)
section.push(objToManipulate.length - 1)
}
} else {
objToManipulate[key] = splitLine[1] || ''
}
section.push(key)
})
return json
} catch (err) {
console.log('!!!!! Error parsing yml. Note: it is expected to be in double spaced format.')
throw err
}
}
const getObjViaPath = (obj, section) => {
if (!section || section.length === 0) {
return obj
} else if (section[0] === '') {
return getObjViaPath(obj, section.slice(1, section.length))
} else {
return getObjViaPath(obj[section[0]], section.slice(1, section.length))
}
}
const mutateViaPath = (obj, section, value) => {
if (section.length === 1) {
obj[section] = value
} else if (section[0] === '') {
mutateViaPath(obj, section.slice(1, section.length), value)
} else {
mutateViaPath(obj[section[0]], section.slice(1, section.length), value)
}
}
module.exports = {
getBotInfo,
getDirInfo,

@@ -56,3 +172,4 @@ replaceTextInFile,

renameFilesInFolder,
recursePathAndOperate
recursePathAndOperate,
ymlToJson
}
{
"name": "serverless-leo",
"version": "1.3.16",
"version": "1.4.0",
"description": "Serverless plugin for leo microservices",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -55,4 +55,4 @@ # serverless-leo

events:
- leo
cron: 0 0 1 * * * # Trigger Lambda from a Leo Cron (down to minute)
- leo:
cron: 0 0 1 * * * # Trigger Lambda from a Leo Cron (down to minute)
```

@@ -97,4 +97,4 @@

events:
- leo:
cron: 0 0 1 * * *
- leo:
cron: 0 0 1 * * *
```

@@ -109,5 +109,5 @@ The bot will be named the same as the lambda.

events:
- leo:
queue: helloWorldTestQueue
botCount: 4
- leo:
queue: helloWorldTestQueue
botCount: 4
```

@@ -122,4 +122,4 @@ This allows you to partition the queue, or change the configuration of the bot based on the value of the variable at run time.

events:
- leo:
register: true
- leo:
register: true
```

@@ -139,1 +139,13 @@

In this example leoStack would be used when deployed using --stage dev. leoRegister would be used when using --stage test
### Invoke local bot
You can invoke a bot to run on your local machine as if it were running in the cloud. It will respect the checkpoint and update it as it progresses.
##### Run it locally with this command (from the main microservice directory)
```
serverless invoke-bot -s test -f your_function_name
```
#### Options - in order to run a specific bot there are additional options you can pass
##### -f/--functionName The name of the function the bot uses.
##### -s/--stage The stage of the microservice.
##### -n/--name The name of the bot. A regular expression will be used to compare against the prefix, suffix, name, queue, and cron on the bot.
##### -b/--botNumber The botNumber to execute. If there is no suffix/prefix/queue and there are multiple bots for the lambda, the botNumber can be used to identify the bot.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc