Source code for infrahouse_core.aws.asg
"""
Module for ASG class - a class to work with Autoscaling group.
"""
from logging import getLogger
from pprint import pformat
from typing import Dict, List
from botocore.exceptions import ClientError
from infrahouse_core.aws import get_client
from infrahouse_core.aws.asg_instance import ASGInstance
LOG = getLogger(__name__)
[docs]
class ASG:
"""AWS Autoscaling group."""
def __init__(self, asg_name: str, region: str = None, role_arn: str = None, session=None):
self._asg_name = asg_name
self._region = region
self._role_arn = role_arn
self._session = session
self._autoscaling_client_instance = None
@property
def instance_refreshes(self) -> List[Dict]:
"""
:return: List of ASG instance refresh tasks.
"""
return self._autoscaling_client.describe_instance_refreshes(
AutoScalingGroupName=self._asg_name,
)["InstanceRefreshes"]
@property
def instances(self) -> List[ASGInstance]:
"""
:return: List of EC2 instances in the autoscaling group.
"""
return [
ASGInstance(
instance_id=instance["InstanceId"],
region=self._region,
role_arn=self._role_arn,
session=self._session,
)
for instance in self._describe_auto_scaling_groups["AutoScalingGroups"][0]["Instances"]
]
@property
def exists(self) -> bool:
"""
Check whether the autoscaling group currently exists.
:return: ``True`` if the ASG exists, ``False`` otherwise.
"""
result = self._autoscaling_client.describe_auto_scaling_groups(
AutoScalingGroupNames=[self._asg_name],
)
return len(result["AutoScalingGroups"]) > 0
[docs]
def delete(self, force_delete: bool = True) -> None:
"""
Delete the autoscaling group.
Idempotent -- does nothing if the ASG does not exist.
:param force_delete: If True (default), force-delete the ASG
even if it has running instances.
:type force_delete: bool
"""
try:
self._autoscaling_client.delete_auto_scaling_group(
AutoScalingGroupName=self._asg_name,
ForceDelete=force_delete,
)
LOG.info("Deleted ASG %s (force=%s)", self._asg_name, force_delete)
except ClientError as err:
if err.response["Error"]["Code"] == "ValidationError":
LOG.info("ASG %s does not exist.", self._asg_name)
else:
raise
[docs]
def cancel_instance_refresh(self):
"""Cancel all instance refreshes."""
try:
self._autoscaling_client.cancel_instance_refresh(AutoScalingGroupName=self._asg_name)
except ClientError as err:
if err.response["Error"]["Code"] == "ActiveInstanceRefreshNotFound":
LOG.warning(err)
else:
raise
[docs]
def complete_lifecycle_action(self, hook_name="terminating", result="CONTINUE", instance_id=None):
"""
Completes the lifecycle hook.
See details on https://docs.aws.amazon.com/autoscaling/ec2/userguide/completing-lifecycle-hooks.html
:param hook_name: Hook name.
:type hook_name: str
:param result: Result of the hook. Can be either CONTINUE or ABANDON.
:type result: str
:param instance_id: EC2 instance_id for which complete the hook.
If not given, assume the local instance.
:type instance_id: str
"""
self._autoscaling_client.complete_lifecycle_action(
LifecycleHookName=hook_name,
AutoScalingGroupName=self._asg_name,
LifecycleActionResult=result,
InstanceId=instance_id or ASGInstance().instance_id,
)
[docs]
def record_lifecycle_action_heartbeat(self, hook_name="terminating", instance_id=None):
"""
Extend lifecycle wait time.
:param hook_name: Hook name.
:type hook_name: str
:param instance_id: EC2 instance_id for which the hook is waiting.
If not given, assume the local instance.
:type instance_id: str
"""
self._autoscaling_client.record_lifecycle_action_heartbeat(
LifecycleHookName=hook_name,
AutoScalingGroupName=self._asg_name,
InstanceId=instance_id or ASGInstance().instance_id,
)
@property
def _autoscaling_client(self):
if self._autoscaling_client_instance is None:
if self._session is not None:
self._autoscaling_client_instance = self._session.client("autoscaling", region_name=self._region)
else:
self._autoscaling_client_instance = get_client(
"autoscaling", region=self._region, role_arn=self._role_arn
)
LOG.debug("Created autoscaling client in %s region", self._autoscaling_client_instance.meta.region_name)
return self._autoscaling_client_instance
@property
def _describe_auto_scaling_groups(self):
result = self._autoscaling_client.describe_auto_scaling_groups(
AutoScalingGroupNames=[
self._asg_name,
],
)
LOG.debug("_describe_auto_scaling_groups() = %s", pformat(result))
return result