[lambda] Implement ListFunctions, GetFunction, and DeleteFunction

This commit is contained in:
Hugo Lopes Tavares 2016-02-12 14:39:20 -05:00
parent 63296049f1
commit bfad9b9ed6
9 changed files with 401 additions and 2 deletions

View File

@ -6,6 +6,7 @@ __title__ = 'moto'
__version__ = '0.4.21'
from .autoscaling import mock_autoscaling # flake8: noqa
from .awslambda import mock_lambda # flake8: noqa
from .cloudformation import mock_cloudformation # flake8: noqa
from .cloudwatch import mock_cloudwatch # flake8: noqa
from .datapipeline import mock_datapipeline # flake8: noqa

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from .models import lambda_backends
from ..core.models import MockAWS
lambda_backend = lambda_backends['us-east-1']
def mock_lambda(func=None):
if func:
return MockAWS(lambda_backends)(func)
else:
return MockAWS(lambda_backends)

82
moto/awslambda/models.py Normal file
View File

@ -0,0 +1,82 @@
from __future__ import unicode_literals
import datetime
import boto.awslambda
from moto.core import BaseBackend
class LambdaFunction(object):
def __init__(self, spec):
self.function_name = spec['FunctionName']
self.run_time = spec['Runtime']
self.role = spec['Role']
self.handler = spec['Handler']
self.description = spec['Description']
self.timeout = spec['Timeout']
self.memory_size = spec['MemorySize']
self.vpc_config = spec.get('VpcConfig', {})
self.code = spec['Code']
self.version = '$LATEST'
self.last_modified = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
self.code_size = 210 # hello world function
self.code_sha_256 = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9' # hello world function
self.function_arn = 'arn:aws:lambda:123456789012:function:{}'.format(self.function_name)
def __repr__(self):
return json.dumps(self.get_configuration())
def get_configuration(self):
return {
"CodeSha256": self.code_sha_256,
"CodeSize": self.code_size,
"Description": self.description,
"FunctionArn": self.function_arn,
"FunctionName": self.function_name,
"Handler": self.handler,
"LastModified": self.last_modified,
"MemorySize": self.memory_size,
"Role": self.role,
"Runtime": self.run_time,
"Timeout": self.timeout,
"Version": self.version,
"VpcConfig": self.vpc_config,
}
def get_code(self):
return {
"Code": {
"Location": "s3://lambda-functions.aws.amazon.com/{}".format(self.code['S3Key']),
"RepositoryType": "S3"
},
"Configuration": self.get_configuration(),
}
class LambdaBackend(BaseBackend):
def __init__(self):
self._functions = {}
def has_function(self, function_name):
return function_name in self._functions
def create_function(self, spec):
fn = LambdaFunction(spec)
self._functions[fn.function_name] = fn
return fn
def get_function(self, function_name):
return self._functions[function_name]
def delete_function(self, function_name):
del self._functions[function_name]
def list_functions(self):
return self._functions.values()
lambda_backends = {}
for region in boto.awslambda.regions():
lambda_backends[region.name] = LambdaBackend()

View File

@ -0,0 +1,78 @@
from __future__ import unicode_literals
import json
import re
from moto.core.responses import BaseResponse
from .models import lambda_backends
class LambdaResponse(BaseResponse):
@classmethod
def root(cls, request, full_url, headers):
if request.method == 'GET':
return cls()._list_functions(request, full_url, headers)
elif request.method == 'POST':
return cls()._create_function(request, full_url, headers)
else:
raise ValueError("Cannot handle request")
@classmethod
def function(cls, request, full_url, headers):
if request.method == 'GET':
return cls()._get_function(request, full_url, headers)
elif request.method == 'DELETE':
return cls()._delete_function(request, full_url, headers)
else:
raise ValueError("Cannot handle request")
def _list_functions(self, request, full_url, headers):
lambda_backend = self.get_lambda_backend(full_url)
return 200, headers, json.dumps({
"Functions": [fn.get_configuration() for fn in lambda_backend.list_functions()],
"NextMarker": "aws-lambda-next-marker",
})
def _create_function(self, request, full_url, headers):
lambda_backend = self.get_lambda_backend(full_url)
spec = json.loads(request.body)
fn = lambda_backend.create_function(spec)
config = fn.get_configuration()
return 200, headers, json.dumps(config)
def _delete_function(self, request, full_url, headers):
lambda_backend = self.get_lambda_backend(full_url)
function_name = request.path.split('/')[-1]
if lambda_backend.has_function(function_name):
lambda_backend.delete_function(function_name)
return 204, headers, ""
else:
return 404, headers, "{}"
def _get_function(self, request, full_url, headers):
lambda_backend = self.get_lambda_backend(full_url)
function_name = request.path.split('/')[-1]
if lambda_backend.has_function(function_name):
fn = lambda_backend.get_function(function_name)
code = fn.get_code()
return 200, headers, json.dumps(code)
else:
return 404, headers, "{}"
def get_lambda_backend(self, full_url):
from moto.awslambda.models import lambda_backends
region = self._get_aws_region(full_url)
return lambda_backends[region]
def _get_aws_region(self, full_url):
region = re.search(self.region_regex, full_url)
if region:
return region.group(1)
else:
return self.default_region

12
moto/awslambda/urls.py Normal file
View File

@ -0,0 +1,12 @@
from __future__ import unicode_literals
from .responses import LambdaResponse
url_bases = [
"https?://lambda.(.+).amazonaws.com",
]
url_paths = {
# double curly braces because the `format()` method is called on the strings
'{0}/\d{{4}}-\d{{2}}-\d{{2}}/functions/?$': LambdaResponse.root,
'{0}/\d{{4}}-\d{{2}}-\d{{2}}/functions/(?P<function_name>[\w_-]+)/?$': LambdaResponse.function,
}

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals
from moto.autoscaling import autoscaling_backend
from moto.awslambda import lambda_backend
from moto.cloudwatch import cloudwatch_backend
from moto.cloudformation import cloudformation_backend
from moto.datapipeline import datapipeline_backend
@ -43,7 +44,8 @@ BACKENDS = {
'sns': sns_backend,
'sqs': sqs_backend,
'sts': sts_backend,
'route53': route53_backend
'route53': route53_backend,
'lambda': lambda_backend,
}

View File

@ -5,5 +5,5 @@ sure>=1.2.24
coverage
freezegun
flask
boto3
boto3>=1.2.3
six

View File

@ -0,0 +1,211 @@
from __future__ import unicode_literals
import boto3
import sure # noqa
from freezegun import freeze_time
from moto import mock_lambda
@mock_lambda
def test_list_functions():
conn = boto3.client('lambda', 'us-west-2')
result = conn.list_functions()
result['Functions'].should.have.length_of(0)
@mock_lambda
@freeze_time('2015-01-01 00:00:00')
def test_create_function():
conn = boto3.client('lambda', 'us-west-2')
result = conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_handler.handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
# boto3 doesnt support it
# VpcConfig={
# "SecurityGroupIds": ["sg-123abc"],
# "SubnetIds": ["subnet-123abc"],
# "VpcId": "vpc-123abc"
# },
)
result.should.equal({
'FunctionName': 'testFunction',
'FunctionArn': 'arn:aws:lambda:123456789012:function:testFunction',
'Runtime': 'python2.7',
'Role': 'test-iam-role',
'Handler': 'lambda_handler.handler',
'CodeSize': 210,
'Description': 'test lambda function',
'Timeout': 3,
'MemorySize': 128,
'LastModified': '2015-01-01 00:00:00',
'CodeSha256': 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9',
'Version': '$LATEST',
# boto3 doesnt support it
# VpcConfig={
# "SecurityGroupIds": ["sg-123abc"],
# "SubnetIds": ["subnet-123abc"],
# "VpcId": "vpc-123abc"
# },
'ResponseMetadata': {'HTTPStatusCode': 200},
})
@mock_lambda
@freeze_time('2015-01-01 00:00:00')
def test_get_function():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_handler.handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
result = conn.get_function(FunctionName='testFunction')
result.should.equal({
"Code": {
"Location": "s3://lambda-functions.aws.amazon.com/test.zip",
"RepositoryType": "S3"
},
"Configuration": {
"CodeSha256": 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9',
"CodeSize": 210,
"Description": "test lambda function",
"FunctionArn": "arn:aws:lambda:123456789012:function:testFunction",
"FunctionName": "testFunction",
"Handler": "lambda_handler.handler",
"LastModified": "2015-01-01 00:00:00",
"MemorySize": 128,
"Role": "test-iam-role",
"Runtime": "python2.7",
"Timeout": 3,
"Version": '$LATEST',
# "VpcConfig": {
# "SecurityGroupIds": [
# "string"
# ],
# "SubnetIds": [
# "string"
# ],
# "VpcId": "string"
# }
},
'ResponseMetadata': {'HTTPStatusCode': 200},
})
@mock_lambda
def test_delete_function():
conn = boto3.client('lambda', 'us-west-2')
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_handler.handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
success_result = conn.delete_function(FunctionName='testFunction')
success_result.should.equal({'ResponseMetadata': {'HTTPStatusCode': 204}})
# FIXME:!!!!
# not_found_result = conn.delete_function(FunctionName='testFunctionThatDoesntExist')
# not_found_result.should.equal({'ResponseMetadata': {'HTTPStatusCode': 404}})
@mock_lambda
@freeze_time('2015-01-01 00:00:00')
def test_list_create_list_get_delete_list():
"""
test `list -> create -> list -> get -> delete -> list` integration
"""
conn = boto3.client('lambda', 'us-west-2')
conn.list_functions()['Functions'].should.have.length_of(0)
conn.create_function(
FunctionName='testFunction',
Runtime='python2.7',
Role='test-iam-role',
Handler='lambda_handler.handler',
Code={
'S3Bucket': 'test-bucket',
'S3Key': 'test.zip',
},
Description='test lambda function',
Timeout=3,
MemorySize=128,
Publish=True,
)
expected_function_result = {
"Code": {
"Location": "s3://lambda-functions.aws.amazon.com/test.zip",
"RepositoryType": "S3"
},
"Configuration": {
"CodeSha256": 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9',
"CodeSize": 210,
"Description": "test lambda function",
"FunctionArn": "arn:aws:lambda:123456789012:function:testFunction",
"FunctionName": "testFunction",
"Handler": "lambda_handler.handler",
"LastModified": "2015-01-01 00:00:00",
"MemorySize": 128,
"Role": "test-iam-role",
"Runtime": "python2.7",
"Timeout": 3,
"Version": '$LATEST',
# "VpcConfig": {
# "SecurityGroupIds": [
# "string"
# ],
# "SubnetIds": [
# "string"
# ],
# "VpcId": "string"
# }
},
'ResponseMetadata': {'HTTPStatusCode': 200},
}
conn.list_functions()['Functions'].should.equal([expected_function_result['Configuration']])
conn.get_function(FunctionName='testFunction').should.equal(expected_function_result)
conn.delete_function(FunctionName='testFunction')
conn.list_functions()['Functions'].should.have.length_of(0)

View File