-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1463631
commit 450dc56
Showing
9 changed files
with
423 additions
and
6 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Module containing the logic for the lambda scheduler entry-points.""" |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
"""Exception functions.""" | ||
|
||
import logging | ||
|
||
|
||
def ec2_exception(resource_name: str, resource_id: str, exception) -> None: | ||
"""Exception raised during execution of ec2 scheduler. | ||
Log instance, spot instance and autoscaling groups exceptions | ||
on the specific aws resources. | ||
:param str resource_name: | ||
Aws resource name | ||
:param str resource_id: | ||
Aws resource id | ||
:param str exception: | ||
Human readable string describing the exception | ||
""" | ||
info_codes = ["IncorrectInstanceState"] | ||
warning_codes = [ | ||
"UnsupportedOperation", | ||
"IncorrectInstanceState", | ||
"InvalidParameterCombination", | ||
] | ||
|
||
if exception.response["Error"]["Code"] in info_codes: | ||
logging.info( | ||
"%s %s: %s", | ||
resource_name, | ||
resource_id, | ||
exception, | ||
) | ||
elif exception.response["Error"]["Code"] in warning_codes: | ||
logging.warning( | ||
"%s %s: %s", | ||
resource_name, | ||
resource_id, | ||
exception, | ||
) | ||
else: | ||
logging.error( | ||
"Unexpected error on %s %s: %s", | ||
resource_name, | ||
resource_id, | ||
exception, | ||
) |
54 changes: 54 additions & 0 deletions
54
build/infrastructure/package/scheduler/filter_resources_by_tags.py
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
"""Filter aws resouces with tags.""" | ||
|
||
from typing import Iterator | ||
|
||
import boto3 | ||
|
||
|
||
class FilterByTags: | ||
"""Abstract Filter aws resources by tags in a class.""" | ||
|
||
def __init__(self, region_name=None) -> None: | ||
"""Initialize resourcegroupstaggingapi client.""" | ||
if region_name: | ||
self.rgta = boto3.client( | ||
"resourcegroupstaggingapi", region_name=region_name | ||
) | ||
else: | ||
self.rgta = boto3.client("resourcegroupstaggingapi") | ||
|
||
def get_resources(self, resource_type, aws_tags) -> Iterator[str]: | ||
"""Filter aws resources using resource type and defined tags. | ||
Returns all the tagged defined resources that are located in | ||
the specified Region for the AWS account. | ||
:param str resource_type: | ||
The constraints on the resources that you want returned. | ||
The format of each resource type is service[:resourceType] . | ||
For example, specifying a resource type of ec2 returns all | ||
Amazon EC2 resources (which includes EC2 instances). | ||
Specifying a resource type of ec2:instance returns only | ||
EC2 instances. | ||
:param list[map] aws_tags: | ||
A list of TagFilters (keys and values). | ||
Each TagFilter specified must contain a key with values | ||
as optional. For example: | ||
[ | ||
{ | ||
'Key': 'string', | ||
'Values': [ | ||
'string', | ||
] | ||
}, | ||
] | ||
:yield Iterator[str]: | ||
The ids of the resources | ||
""" | ||
paginator = self.rgta.get_paginator("get_resources") | ||
page_iterator = paginator.paginate( | ||
TagFilters=aws_tags, ResourceTypeFilters=[resource_type] | ||
) | ||
for page in page_iterator: | ||
for resource_tag_map in page["ResourceTagMappingList"]: | ||
yield resource_tag_map["ResourceARN"] |
81 changes: 81 additions & 0 deletions
81
build/infrastructure/package/scheduler/instance_handler.py
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
"""ec2 instances scheduler.""" | ||
|
||
from typing import Dict, List | ||
|
||
import boto3 | ||
|
||
from botocore.exceptions import ClientError | ||
|
||
from .exceptions import ec2_exception | ||
from .filter_resources_by_tags import FilterByTags | ||
|
||
|
||
class InstanceScheduler: | ||
"""Abstract ec2 scheduler in a class.""" | ||
|
||
def __init__(self, region_name=None) -> None: | ||
"""Initialize ec2 scheduler.""" | ||
if region_name: | ||
self.ec2 = boto3.client("ec2", region_name=region_name) | ||
self.asg = boto3.client("autoscaling", region_name=region_name) | ||
else: | ||
self.ec2 = boto3.client("ec2") | ||
self.asg = boto3.client("autoscaling") | ||
self.tag_api = FilterByTags(region_name=region_name) | ||
|
||
def stop(self, aws_tags: List[Dict]) -> None: | ||
"""Aws ec2 instance stop function. | ||
Stop ec2 instances with defined tags and disable its Cloudwatch | ||
alarms. | ||
:param list[map] aws_tags: | ||
Aws tags to use for filter resources. | ||
For example: | ||
[ | ||
{ | ||
'Key': 'string', | ||
'Values': [ | ||
'string', | ||
] | ||
} | ||
] | ||
""" | ||
for instance_arn in self.tag_api.get_resources("ec2:instance", aws_tags): | ||
instance_id = instance_arn.split("/")[-1] | ||
try: | ||
if not self.asg.describe_auto_scaling_instances( | ||
InstanceIds=[instance_id] | ||
)["AutoScalingInstances"]: | ||
self.ec2.stop_instances(InstanceIds=[instance_id]) | ||
print(f"Stop instances {instance_id}") | ||
except ClientError as exc: | ||
ec2_exception("instance", instance_id, exc) | ||
|
||
def start(self, aws_tags: List[Dict]) -> None: | ||
"""Aws ec2 instance start function. | ||
Start ec2 instances with defined tags. | ||
Aws tags to use for filter resources | ||
Aws tags to use for filter resources. | ||
For example: | ||
[ | ||
{ | ||
'Key': 'string', | ||
'Values': [ | ||
'string', | ||
] | ||
} | ||
] | ||
""" | ||
for instance_arn in self.tag_api.get_resources("ec2:instance", aws_tags): | ||
instance_id = instance_arn.split("/")[-1] | ||
try: | ||
if not self.asg.describe_auto_scaling_instances( | ||
InstanceIds=[instance_id] | ||
)["AutoScalingInstances"]: | ||
self.ec2.start_instances(InstanceIds=[instance_id]) | ||
print(f"Start instances {instance_id}") | ||
except ClientError as exc: | ||
ec2_exception("instance", instance_id, exc) |
Oops, something went wrong.