AmmarFahmy
adding all files
105b369
from typing import Optional, Any, Dict, List, Union
from phi.aws.api_client import AwsApiClient
from phi.aws.resource.base import AwsResource
from phi.aws.resource.ec2.subnet import Subnet
from phi.aws.resource.ec2.security_group import SecurityGroup
from phi.cli.console import print_info
from phi.utils.log import logger
class LoadBalancer(AwsResource):
"""
Reference:
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/elbv2.html
"""
resource_type: Optional[str] = "LoadBalancer"
service_name: str = "elbv2"
# Name of the Load Balancer.
name: str
subnets: Optional[List[Union[str, Subnet]]] = None
subnet_mappings: Optional[List[Dict[str, str]]] = None
security_groups: Optional[List[Union[str, SecurityGroup]]] = None
scheme: Optional[str] = None
tags: Optional[List[Dict[str, str]]] = None
type: Optional[str] = None
ip_address_type: Optional[str] = None
customer_owned_ipv_4_pool: Optional[str] = None
# Protocol for load_balancer: HTTP or HTTPS
protocol: str = "HTTP"
def _create(self, aws_client: AwsApiClient) -> bool:
"""Creates the Load Balancer
Args:
aws_client: The AwsApiClient for the current Load Balancer
"""
print_info(f"Creating {self.get_resource_type()}: {self.get_resource_name()}")
# create a dict of args which are not null, otherwise aws type validation fails
not_null_args: Dict[str, Any] = {}
if self.subnets is not None:
subnet_ids = []
for subnet in self.subnets:
if isinstance(subnet, Subnet):
subnet_ids.append(subnet.name)
elif isinstance(subnet, str):
subnet_ids.append(subnet)
not_null_args["Subnets"] = subnet_ids
if self.subnet_mappings is not None:
not_null_args["SubnetMappings"] = self.subnet_mappings
if self.security_groups is not None:
security_group_ids = []
for sg in self.security_groups:
if isinstance(sg, SecurityGroup):
security_group_ids.append(sg.get_security_group_id(aws_client))
else:
security_group_ids.append(sg)
not_null_args["SecurityGroups"] = security_group_ids
if self.scheme is not None:
not_null_args["Scheme"] = self.scheme
if self.tags is not None:
not_null_args["tags"] = self.tags
if self.type is not None:
not_null_args["Type"] = self.type
if self.ip_address_type is not None:
not_null_args["IpAddressType"] = self.ip_address_type
if self.customer_owned_ipv_4_pool is not None:
not_null_args["CustomerOwnedIpv4Pool"] = self.customer_owned_ipv_4_pool
# Create LoadBalancer
service_client = self.get_service_client(aws_client)
try:
create_response = service_client.create_load_balancer(
Name=self.name,
**not_null_args,
)
logger.debug(f"Create Response: {create_response}")
resource_dict = create_response.get("LoadBalancers", {})
# Validate resource creation
if resource_dict is not None:
self.active_resource = create_response
return True
except Exception as e:
logger.error(f"{self.get_resource_type()} could not be created.")
logger.error(e)
return False
def post_create(self, aws_client: AwsApiClient) -> bool:
# Wait for LoadBalancer to be created
if self.wait_for_create:
try:
print_info(f"Waiting for {self.get_resource_type()} to be created.")
waiter = self.get_service_client(aws_client).get_waiter("load_balancer_exists")
waiter.wait(
Names=[self.get_resource_name()],
WaiterConfig={
"Delay": self.waiter_delay,
"MaxAttempts": self.waiter_max_attempts,
},
)
except Exception as e:
logger.error("Waiter failed.")
logger.error(e)
# Read the LoadBalancer
elb = self._read(aws_client)
if elb is None:
logger.error(f"Error reading {self.get_resource_type()}. Please get DNS name manually.")
else:
dns_name = elb.get("DNSName", None)
print_info(f"LoadBalancer DNS: {self.protocol.lower()}://{dns_name}")
return True
def _read(self, aws_client: AwsApiClient) -> Optional[Any]:
"""Returns the LoadBalancer
Args:
aws_client: The AwsApiClient for the current LoadBalancer
"""
logger.debug(f"Reading {self.get_resource_type()}: {self.get_resource_name()}")
from botocore.exceptions import ClientError
service_client = self.get_service_client(aws_client)
try:
describe_response = service_client.describe_load_balancers(Names=[self.name])
logger.debug(f"Describe Response: {describe_response}")
resource_list = describe_response.get("LoadBalancers", None)
if resource_list is not None and isinstance(resource_list, list):
self.active_resource = resource_list[0]
except ClientError as ce:
logger.debug(f"ClientError: {ce}")
except Exception as e:
logger.error(f"Error reading {self.get_resource_type()}.")
logger.error(e)
return self.active_resource
def _delete(self, aws_client: AwsApiClient) -> bool:
"""Deletes the LoadBalancer
Args:
aws_client: The AwsApiClient for the current LoadBalancer
"""
print_info(f"Deleting {self.get_resource_type()}: {self.get_resource_name()}")
service_client = self.get_service_client(aws_client)
self.active_resource = None
try:
lb_arn = self.get_arn(aws_client)
if lb_arn is None:
logger.warning(f"{self.get_resource_type()} not found.")
return True
delete_response = service_client.delete_load_balancer(LoadBalancerArn=lb_arn)
logger.debug(f"Delete Response: {delete_response}")
return True
except Exception as e:
logger.error(f"{self.get_resource_type()} could not be deleted.")
logger.error("Please try again or delete resources manually.")
logger.error(e)
return False
def post_delete(self, aws_client: AwsApiClient) -> bool:
# Wait for LoadBalancer to be deleted
if self.wait_for_delete:
try:
print_info(f"Waiting for {self.get_resource_type()} to be deleted.")
waiter = self.get_service_client(aws_client).get_waiter("load_balancers_deleted")
waiter.wait(
Names=[self.get_resource_name()],
WaiterConfig={
"Delay": self.waiter_delay,
"MaxAttempts": self.waiter_max_attempts,
},
)
except Exception as e:
logger.error("Waiter failed.")
logger.error(e)
return True
def get_arn(self, aws_client: AwsApiClient) -> Optional[str]:
lb = self._read(aws_client)
if lb is None:
return None
lb_arn = lb.get("LoadBalancerArn", None)
return lb_arn