Created
July 27, 2019 16:33
-
-
Save wifecooky/ede692eca0d60d7945546ee351aeff31 to your computer and use it in GitHub Desktop.
[AWS] EC2 Instance Scheduling with Terraform
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Cloudwatch Events ### | |
# Event rule: Runs at 8pm during working days | |
resource "aws_cloudwatch_event_rule" "start_instances_event_rule" { | |
name = "start_instances_event_rule" | |
description = "Starts stopped EC2 instances" | |
schedule_expression = "cron(0 8 ? * MON-FRI *)" | |
depends_on = ["aws_lambda_function.ec2_start_scheduler_lambda"] | |
} | |
# Runs at 8am during working days | |
resource "aws_cloudwatch_event_rule" "stop_instances_event_rule" { | |
name = "stop_instances_event_rule" | |
description = "Stops running EC2 instances" | |
schedule_expression = "cron(0 20 ? * MON-FRI *)" | |
depends_on = ["aws_lambda_function.ec2_stop_scheduler_lambda"] | |
} | |
# Event target: Associates a rule with a function to run | |
resource "aws_cloudwatch_event_target" "start_instances_event_target" { | |
target_id = "start_instances_lambda_target" | |
rule = "${aws_cloudwatch_event_rule.start_instances_event_rule.name}" | |
arn = "${aws_lambda_function.ec2_start_scheduler_lambda.arn}" | |
} | |
resource "aws_cloudwatch_event_target" "stop_instances_event_target" { | |
target_id = "stop_instances_lambda_target" | |
rule = "${aws_cloudwatch_event_rule.stop_instances_event_rule.name}" | |
arn = "${aws_lambda_function.ec2_stop_scheduler_lambda.arn}" | |
} | |
# AWS Lambda Permissions: Allow CloudWatch to execute the Lambda Functions | |
resource "aws_lambda_permission" "allow_cloudwatch_to_call_start_scheduler" { | |
statement_id = "AllowExecutionFromCloudWatch" | |
action = "lambda:InvokeFunction" | |
function_name = "${aws_lambda_function.ec2_start_scheduler_lambda.function_name}" | |
principal = "events.amazonaws.com" | |
source_arn = "${aws_cloudwatch_event_rule.start_instances_event_rule.arn}" | |
} | |
resource "aws_lambda_permission" "allow_cloudwatch_to_call_stop_scheduler" { | |
statement_id = "AllowExecutionFromCloudWatch" | |
action = "lambda:InvokeFunction" | |
function_name = "${aws_lambda_function.ec2_stop_scheduler_lambda.function_name}" | |
principal = "events.amazonaws.com" | |
source_arn = "${aws_cloudwatch_event_rule.stop_instances_event_rule.arn}" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### IAM Role and Policy ### | |
# Allows Lambda function to describe, stop and start EC2 instances | |
resource "aws_iam_role" "ec2_start_stop_scheduler" { | |
name = "ec2_start_stop_scheduler" | |
assume_role_policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": "sts:AssumeRole", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
}, | |
"Effect": "Allow", | |
"Sid": "" | |
} | |
] | |
} | |
EOF | |
} | |
data "aws_iam_policy_document" "ec2_start_stop_scheduler" { | |
statement = [ | |
{ | |
actions = [ | |
"logs:CreateLogGroup", | |
"logs:CreateLogStream", | |
"logs:PutLogEvents" | |
] | |
resources = [ | |
"arn:aws:logs:*:*:*", | |
] | |
}, | |
{ | |
actions = [ | |
"ec2:Describe*", | |
"ec2:Stop*", | |
"ec2:Start*" | |
] | |
resources = [ | |
"*", | |
] | |
} | |
] | |
} | |
resource "aws_iam_policy" "ec2_start_stop_scheduler" { | |
name = "ec2_access_scheduler" | |
path = "/" | |
policy = "${data.aws_iam_policy_document.ec2_start_stop_scheduler.json}" | |
} | |
resource "aws_iam_role_policy_attachment" "ec2_access_scheduler" { | |
role = "${aws_iam_role.ec2_start_stop_scheduler.name}" | |
policy_arn = "${aws_iam_policy.ec2_start_stop_scheduler.arn}" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### AWS Lambda function ### | |
# AWS Lambda API requires a ZIP file with the execution code | |
data "archive_file" "start_scheduler" { | |
type = "zip" | |
source_file = "start_instances.py" | |
output_path = "start_instances.zip" | |
} | |
data "archive_file" "stop_scheduler" { | |
type = "zip" | |
source_file = "stop_instances.py" | |
output_path = "stop_instances.zip" | |
} | |
# Lambda defined that runs the Python code with the specified IAM role | |
resource "aws_lambda_function" "ec2_start_scheduler_lambda" { | |
filename = "${data.archive_file.start_scheduler.output_path}" | |
function_name = "start_instances" | |
role = "${aws_iam_role.ec2_start_stop_scheduler.arn}" | |
handler = "start_instances.lambda_handler" | |
runtime = "python2.7" | |
timeout = 300 | |
source_code_hash = "${data.archive_file.start_scheduler.output_base64sha256}" | |
} | |
resource "aws_lambda_function" "ec2_stop_scheduler_lambda" { | |
filename = "${data.archive_file.stop_scheduler.output_path}" | |
function_name = "stop_instances" | |
role = "${aws_iam_role.ec2_start_stop_scheduler.arn}" | |
handler = "stop_instances.lambda_handler" | |
runtime = "python2.7" | |
timeout = 300 | |
source_code_hash = "${data.archive_file.stop_scheduler.output_base64sha256}" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import boto3 | |
# Boto Connection | |
ec2 = boto3.resource('ec2', 'eu-west-2') | |
def lambda_handler(event, context): | |
# Filters | |
filters = [{ | |
'Name': 'tag:AutoStop', | |
'Values': ['true'] | |
}, | |
{ | |
'Name': 'instance-state-name', | |
'Values': ['stopped'] | |
} | |
] | |
# Filter stopped instances that should start | |
instances = ec2.instances.filter(Filters=filters) | |
# Retrieve instance IDs | |
instance_ids = [instance.id for instance in instances] | |
# starting instances | |
starting_instances = ec2.instances.filter(InstanceIds=instance_ids).start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import boto3 | |
# Boto Connection | |
ec2 = boto3.resource('ec2', 'eu-west-2') | |
def lambda_handler(event, context): | |
# Filters | |
filters = [{ | |
'Name': 'tag:AutoStop', | |
'Values': ['true'] | |
}, | |
{ | |
'Name': 'instance-state-name', | |
'Values': ['running'] | |
} | |
] | |
# Filter running instances that should stop | |
instances = ec2.instances.filter(Filters=filters) | |
# Retrieve instance IDs | |
instance_ids = [instance.id for instance in instances] | |
# stopping instances | |
stopping_instances = ec2.instances.filter(InstanceIds=instance_ids).stop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment