Skip to content

Commit

Permalink
[plugin/aws][feat] Add support for Lambda Functions (#992)
Browse files Browse the repository at this point in the history
* [plugins/aws][feat] Add support for AWS Lambda Functions
  • Loading branch information
fernandocarletti committed Jul 22, 2022
1 parent 337f747 commit 377b13a
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
58 changes: 58 additions & 0 deletions plugins/aws/resoto_plugin_aws/accountcollector.py
Expand Up @@ -112,6 +112,10 @@
"resoto_plugin_aws_collect_instances_seconds",
"Time it took the collect_instances() method",
)
metrics_collect_lambda_functions = Summary(
"resoto_plugin_aws_collect_lambda_functions_seconds",
"Time it took the collect_lambda_functions() method",
)
metrics_collect_keypairs = Summary(
"resoto_plugin_aws_collect_keypairs_seconds",
"Time it took the collect_keypairs() method",
Expand Down Expand Up @@ -287,6 +291,7 @@ def __init__(self, regions: List[str], account: AWSAccount) -> None:
"internet_gateways": self.collect_internet_gateways,
"keypairs": self.collect_keypairs,
"instances": self.collect_instances,
"lambda_functions": self.collect_lambda_functions,
"volumes": self.collect_volumes,
"snapshots": self.collect_snapshots,
"elbs": self.collect_elbs,
Expand Down Expand Up @@ -1246,6 +1251,59 @@ def collect_instances(self, region: AWSRegion, graph: Graph) -> None:
except botocore.exceptions.ClientError:
log.exception(f"Some boto3 call failed on resource {instance} - skipping")

@metrics_collect_lambda_functions.time() # type: ignore
def collect_lambda_functions(self, region: AWSRegion, graph: Graph) -> None:
log.info(f"Collecting AWS Lambda Functions in account {self.account.dname}, region {region.id}")
session = aws_session(self.account.id, self.account.role)
client = session.client("lambda", region_name=region.id)

for function in paginate(client.list_functions):
name = function["FunctionName"]
arn = function["FunctionArn"]

log.debug(f"Found AWS Lambda Function {name}")

tags_response = client.list_tags(Resource=arn)
tags = tags_response.get("Tags", [])

lambda_function = AWSLambdaFunction(
arn,
tags,
account=self.account,
region=region,
name=name,
arn=arn,
runtime=function["Runtime"],
code_size=function["CodeSize"],
memory_size=function["MemorySize"],
mtime=function["LastModified"],
role=function.get("Role"),
kms_key_arn=function.get("KmsKeyArn"),
)

vpc_config = function.get("VpcConfig", {})

vpc_id = vpc_config.get("VpcId")
if vpc_id:
vpc = graph.search_first("id", vpc_id)
if vpc:
graph.add_edge(vpc, lambda_function)
graph.add_edge(vpc, lambda_function, edge_type=EdgeType.delete)

for subnet_id in vpc_config.get("SubnetIds", {}):
subnet = graph.search_first("id", subnet_id)
if subnet:
graph.add_edge(subnet, lambda_function)
graph.add_edge(subnet, lambda_function, edge_type=EdgeType.delete)

for security_group_id in vpc_config.get("SecurityGroupIds", {}):
security_group = graph.search_first("id", security_group_id)
if security_group:
graph.add_edge(security_group, lambda_function)
graph.add_edge(security_group, lambda_function, edge_type=EdgeType.delete)

graph.add_resource(region, lambda_function)

@metrics_collect_autoscaling_groups.time() # type: ignore
def collect_autoscaling_groups(self, region: AWSRegion, graph: Graph) -> None:
log.info(f"Collecting AWS Autoscaling Groups in account {self.account.dname}, region {region.id}")
Expand Down
31 changes: 31 additions & 0 deletions plugins/aws/resoto_plugin_aws/resources.py
Expand Up @@ -101,6 +101,7 @@ class AWSRegion(BaseRegion):
"aws_alb_target_group",
"aws_alb_quota",
"aws_alb",
"aws_lambda_function",
],
"delete": [],
}
Expand Down Expand Up @@ -193,6 +194,36 @@ def delete_tag(self, key) -> bool:
return True


@define(eq=False, slots=False)
class AWSLambdaFunction(AWSResource, BaseServerlessFunction):
kind: ClassVar[str] = "aws_lambda_function"
successor_kinds: ClassVar[Dict[str, List[str]]] = {
"default": [],
"delete": ["aws_lambda_function"],
}

role: Optional[str] = None
runtime: str = None
code_size: int = None
memory_size: int = None
kms_key_arn: Optional[str] = None

def delete(self, graph: Graph) -> bool:
client = aws_client(self, "lambda", graph)
client.delete_function(self.name)
return True

def update_tag(self, key, value) -> bool:
client = aws_client(self, "lambda")
client.tag_resource(Resources=[self.id], Tags=[{"Key": key, "Value": value}])
return True

def delete_tag(self, key) -> bool:
client = aws_client(self, "lambda")
client.delete_tags(Resources=[self.id], Tags=[{"Key": key}])
return True


@define(eq=False, slots=False)
class AWSEC2KeyPair(AWSResource, BaseKeyPair):
kind: ClassVar[str] = "aws_ec2_keypair"
Expand Down
5 changes: 5 additions & 0 deletions resotolib/resotolib/baseresources.py
Expand Up @@ -788,6 +788,11 @@ class BaseBucket(BaseResource):
kind: ClassVar[str] = "bucket"


@define(eq=False, slots=False)
class BaseServerlessFunction(BaseResource):
kind: ClassVar[str] = "serverless_function"


@define(eq=False, slots=False)
class BaseKeyPair(BaseResource):
kind: ClassVar[str] = "keypair"
Expand Down

0 comments on commit 377b13a

Please sign in to comment.