cfn-forge
Version:
CloudFormation deployment automation tool with git-based workflows
447 lines (381 loc) • 12.5 kB
YAML
name: basic-lambda
description: Simple AWS Lambda function with CloudWatch logging and basic permissions
version: 1.0.0
author: CFN-Forge
cfnForgeVersion: 1.0.0
variables:
projectName:
prompt: "Project name"
default: "my-lambda-function"
description:
prompt: "Project description"
default: "A basic AWS Lambda function"
runtime:
prompt: "Lambda runtime"
default: "nodejs18.x"
options: ["nodejs18.x", "nodejs20.x", "python3.9", "python3.10", "python3.11", "python3.12"]
memorySize:
prompt: "Memory size (MB)"
default: "128"
type: "number"
timeout:
prompt: "Timeout (seconds)"
default: "30"
type: "number"
triggerType:
prompt: "Trigger type"
default: "manual"
options: ["manual", "s3", "eventbridge", "sqs"]
files:
include:
- "**/*"
exclude:
- "template.yaml"
- ".git/**"
- "node_modules/**"
structure:
cloudformation.yaml: |
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: {{description}}
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
Description: Environment name
Conditions:
HasS3Trigger: !Equals ["{{triggerType}}", "s3"]
HasEventBridgeTrigger: !Equals ["{{triggerType}}", "eventbridge"]
HasSQSTrigger: !Equals ["{{triggerType}}", "sqs"]
Resources:
# Lambda Function
{{projectName}}Function:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-function"
CodeUri: src/
Handler: !If
- !Equals ["{{runtime}}", "python3.9"]
- "handler.lambda_handler"
- !If
- !Equals ["{{runtime}}", "python3.10"]
- "handler.lambda_handler"
- !If
- !Equals ["{{runtime}}", "python3.11"]
- "handler.lambda_handler"
- !If
- !Equals ["{{runtime}}", "python3.12"]
- "handler.lambda_handler"
- "index.handler"
Runtime: {{runtime}}
MemorySize: {{memorySize}}
Timeout: {{timeout}}
Environment:
Variables:
ENVIRONMENT: !Ref Environment
LOG_LEVEL: INFO
Events:
# S3 Trigger (conditional)
S3Event:
Type: S3
Condition: HasS3Trigger
Properties:
Bucket: !Ref S3Bucket
Events: s3:ObjectCreated:*
Filter:
S3Key:
Rules:
- Name: prefix
Value: uploads/
# EventBridge Trigger (conditional)
EventBridgeRule:
Type: EventBridgeRule
Condition: HasEventBridgeTrigger
Properties:
Pattern:
source: ["custom.application"]
detail-type: ["Custom Event"]
# SQS Trigger (conditional)
SQSEvent:
Type: SQS
Condition: HasSQSTrigger
Properties:
Queue: !GetAtt SQSQueue.Arn
BatchSize: 10
# S3 Bucket (if S3 trigger selected)
S3Bucket:
Type: AWS::S3::Bucket
Condition: HasS3Trigger
Properties:
BucketName: !Sub "${AWS::StackName}-trigger-bucket"
NotificationConfiguration:
LambdaConfigurations:
- Event: s3:ObjectCreated:*
Function: !GetAtt {{projectName}}Function.Arn
Filter:
S3Key:
Rules:
- Name: prefix
Value: uploads/
# SQS Queue (if SQS trigger selected)
SQSQueue:
Type: AWS::SQS::Queue
Condition: HasSQSTrigger
Properties:
QueueName: !Sub "${AWS::StackName}-queue"
VisibilityTimeoutSeconds: !Ref {{timeout}}
# CloudWatch Log Group
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-function"
RetentionInDays: 14
Outputs:
FunctionName:
Description: Lambda Function Name
Value: !Ref {{projectName}}Function
Export:
Name: !Sub "${AWS::StackName}-FunctionName"
FunctionArn:
Description: Lambda Function ARN
Value: !GetAtt {{projectName}}Function.Arn
Export:
Name: !Sub "${AWS::StackName}-FunctionArn"
S3BucketName:
Condition: HasS3Trigger
Description: S3 Trigger Bucket Name
Value: !Ref S3Bucket
Export:
Name: !Sub "${AWS::StackName}-S3Bucket"
SQSQueueUrl:
Condition: HasSQSTrigger
Description: SQS Queue URL
Value: !Ref SQSQueue
Export:
Name: !Sub "${AWS::StackName}-SQSQueue"
.cfn-forge.yaml: |
project:
name: {{projectName}}
description: {{description}}
type: basic-lambda
environments:
dev:
stackName: "{{projectName}}-dev"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: dev
staging:
stackName: "{{projectName}}-staging"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: staging
prod:
stackName: "{{projectName}}-prod"
template: cloudformation.yaml
region: us-east-1
parameters:
Environment: prod
deployment:
packagingBucket: "{{projectName}}-deployment-artifacts"
createBucket: true
git:
watchBranches: ["main", "develop"]
deployOnPush: true
package.json: |
{
"name": "{{projectName}}",
"version": "1.0.0",
"description": "{{description}}",
"main": "src/index.js",
"scripts": {
"start": "sam local start-lambda",
"invoke": "sam local invoke",
"build": "sam build",
"deploy": "cfn-forge deploy",
"watch": "cfn-forge watch",
"validate": "cfn-forge validate",
"test": "jest",
"test:watch": "jest --watch",
"lint": "eslint src/",
"logs": "sam logs -n {{projectName}}Function --stack-name {{projectName}}-dev"
},
"dependencies": {
"aws-sdk": "^2.1490.0"
},
"devDependencies": {
"jest": "^29.0.0",
"eslint": "^8.0.0"
},
"keywords": ["lambda", "aws", "serverless"],
"author": "{{author}}",
"license": "MIT"
}
src/index.js: |
// Basic Lambda function handler for Node.js
exports.handler = async (event, context) => {
console.log('Event:', JSON.stringify(event, null, 2));
console.log('Context:', JSON.stringify(context, null, 2));
try {
// Your business logic here
const result = {
message: 'Hello from {{projectName}}!',
timestamp: new Date().toISOString(),
environment: process.env.ENVIRONMENT,
eventType: event.Records ? 'triggered' : 'direct',
requestId: context.awsRequestId
};
console.log('Result:', JSON.stringify(result, null, 2));
return {
statusCode: 200,
body: JSON.stringify(result)
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({
message: 'Internal server error',
error: error.message
})
};
}
};
src/handler.py: |
# Basic Lambda function handler for Python
import json
import logging
import os
from datetime import datetime
# Configure logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(f"Event: {json.dumps(event)}")
logger.info(f"Context: {vars(context)}")
try:
# Your business logic here
result = {
'message': 'Hello from {{projectName}}!',
'timestamp': datetime.now().isoformat(),
'environment': os.environ.get('ENVIRONMENT'),
'eventType': 'triggered' if 'Records' in event else 'direct',
'requestId': context.aws_request_id
}
logger.info(f"Result: {json.dumps(result)}")
return {
'statusCode': 200,
'body': json.dumps(result)
}
except Exception as error:
logger.error(f"Error: {str(error)}")
return {
'statusCode': 500,
'body': json.dumps({
'message': 'Internal server error',
'error': str(error)
})
}
tests/test-handler.js: |
const { handler } = require('../src/index');
describe('Lambda Handler', () => {
const mockContext = {
awsRequestId: 'test-request-id',
getRemainingTimeInMillis: () => 30000
};
test('should handle direct invocation', async () => {
const event = { test: 'data' };
const result = await handler(event, mockContext);
expect(result.statusCode).toBe(200);
expect(JSON.parse(result.body).message).toContain('Hello from {{projectName}}');
});
test('should handle S3 event', async () => {
const event = {
Records: [{
eventSource: 'aws:s3',
s3: {
bucket: { name: 'test-bucket' },
object: { key: 'test-key' }
}
}]
};
const result = await handler(event, mockContext);
expect(result.statusCode).toBe(200);
expect(JSON.parse(result.body).eventType).toBe('triggered');
});
});
README.md: |
# {{projectName}}
{{description}}
## Quick Start
1. Install dependencies:
```bash
npm install
```
2. Deploy to AWS:
```bash
cfn-forge deploy
```
3. Test locally:
```bash
npm run invoke
```
## Function Details
- **Runtime**: {{runtime}}
- **Memory**: {{memorySize}} MB
- **Timeout**: {{timeout}} seconds
- **Trigger**: {{triggerType}}
## Project Structure
```
{{projectName}}/
src/
index.js # Node.js handler
handler.py # Python handler
tests/
test-handler.js # Unit tests
cloudformation.yaml # AWS infrastructure
.cfn-forge.yaml # CFN-Forge configuration
package.json
```
## Local Development
```bash
# Start Lambda locally
npm run start
# Invoke function locally
npm run invoke
# Run tests
npm test
# Watch for changes
npm run test:watch
```
## Deployment
### Environments
- **dev**: Development environment
- **staging**: Staging environment
- **prod**: Production environment
### Commands
- `cfn-forge deploy` - Deploy to default environment
- `cfn-forge deploy --env prod` - Deploy to production
- `cfn-forge watch` - Watch for changes and auto-deploy
- `cfn-forge validate` - Validate CloudFormation template
## Monitoring
```bash
# View logs
npm run logs
# View CloudWatch metrics in AWS Console
aws logs describe-log-groups --log-group-name-prefix "/aws/lambda/{{projectName}}"
```
## Triggers
This template supports multiple trigger types:
- **manual**: Invoke directly or via API
- **s3**: Triggered by S3 object creation
- **eventbridge**: Triggered by EventBridge rules
- **sqs**: Triggered by SQS messages
hooks:
postInstall:
- type: npm
command: install
- type: message
content: "Lambda function template created! Choose the appropriate handler file for your runtime."