def __delete_network_acl(self, resource_id, vpc_id: str): try: nacls = self.get_detail_list( func_name=self.client.describe_network_acls, input_tag='NetworkAcls', check_tag='NextToken') vpc_nacls = self.__get_cluster_references( resource_id=resource_id, resource_list=nacls, input_resource_id='NetworkAclId', output_result='Associations') default_nacl = self.__get_cluster_references( resource_id=resource_id, resource_list=nacls, input_resource_id='NetworkAclId', output_result='IsDefault') if default_nacl: default_nacl = default_nacl[0] for vpc_nacl in vpc_nacls: self.__delete_subnet(resource_id=vpc_nacl['SubnetId']) if not default_nacl: self.client.delete_network_acl(NetworkAclId=resource_id) logger.info(f'delete_network_acl: {resource_id}') else: logger.info( f'default network acl: {resource_id} is deleted by vpc: {vpc_id} ' ) except Exception as err: logger.exception( f'Cannot delete_network_acl: {resource_id}, {err}')
def __delete_nat_gateways(self, resource_id: str): """ This method delete the NatGateway based on NatGateway ID :param resource_id: :return: """ try: nat_gateway = self.client.describe_nat_gateways( Filter=[{ 'Name': 'nat-gateway-id', 'Values': [resource_id] }])['NatGateways'][0] if nat_gateway.get('State') == 'available': self.client.delete_nat_gateway(NatGatewayId=resource_id) while nat_gateway.get('State') != 'deleted': nat_gateway = self.client.describe_nat_gateways( Filter=[{ 'Name': 'nat-gateway-id', 'Values': [resource_id] }])['NatGateways'][0] time.sleep(self.SLEEP_TIME) logger.info(f'delete_nat_gateway: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_nat_gateway: {resource_id}, {err}')
def __delete_iam_role(self, resource_id: str): """ This method deleted the zombie cluster iam role :param resource_id: :return: """ try: # Detach policy from role role_policies = self.iam_client.list_attached_role_policies(RoleName=resource_id) if role_policies['AttachedPolicies']: for role_policy in role_policies['AttachedPolicies']: self.iam_client.detach_role_policy(RoleName=resource_id, PolicyArn=role_policy.get('PolicyArn')) self.iam_client.delete_policy(PolicyArn=role_policy.get('PolicyArn')) policy_names = self.iam_client.list_role_policies(RoleName=resource_id) if policy_names.get('PolicyNames'): for policy in policy_names.get('PolicyNames'): self.iam_client.delete_role_policy(RoleName=resource_id, PolicyName=policy) instance_policies = self.iam_client.list_instance_profiles_for_role(RoleName=resource_id) if instance_policies['InstanceProfiles']: self.iam_client.remove_role_from_instance_profile(RoleName=resource_id, InstanceProfileName=resource_id.replace('role', 'profile')) self.iam_client.delete_role(RoleName=resource_id) logger.info(f'delete_role: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_role: {resource_id}, {err}')
def __delete_internet_gateway(self, resource_id: str, vpc_id: str): """ This method delete Internet gateway in the following order NatGateway( Delete Network Interface associated with It ) --> Release Address --> Internet Gateway :param resource_id: :param vpc_id: :return: """ try: network_interfaces = self.get_detail_list( func_name=self.client.describe_network_interfaces, input_tag='NetworkInterfaces', check_tag='NextToken') network_interface_ids = self.__get_cluster_references( resource_id=vpc_id, resource_list=network_interfaces, input_resource_id='VpcId', output_result='NetworkInterfaceId') for network_interface_id in network_interface_ids: self.__delete_network_interface( resource_id=network_interface_id) if vpc_id: self.client.detach_internet_gateway( InternetGatewayId=resource_id, VpcId=vpc_id) self.client.delete_internet_gateway(InternetGatewayId=resource_id) logger.info(f'delete_internet_gateway: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_internet_gateway: {resource_id}, {err}')
def cluster_load_balancer_v2(self): """ This method return list of cluster's load balancer according to cluster vpc @return: """ result_resources_list = [] load_balancers = self.elbv2_client.describe_load_balancers() load_balancers_data = load_balancers['LoadBalancers'] for resource in load_balancers_data: resource_id = resource['LoadBalancerArn'] tags = self.elbv2_client.describe_tags(ResourceArns=[resource_id]) for item in tags['TagDescriptions']: if item.get('Tags'): for tag in item['Tags']: if self.cluster_prefix in tag.get('Key'): all_tags = [] instance_tags = self.__get_cluster_tags_by_instance_cluster( cluster_name=tag.get('Key')) if not instance_tags: all_tags = self.__append_input_tags( item.get('Tags')) all_tags.extend(instance_tags) all_tags = self.__filter_resource_tags_by_add_tags( item.get('Tags'), all_tags) if all_tags: if self.cluster_name: if tag['Key'] == self.cluster_key: try: if self.dry_run == 'no': self.elbv2_client.add_tags( ResourceArns=[resource_id], Tags=all_tags) logger.info(all_tags) except Exception as err: logger.exception( f'Tags are already updated, {err}' ) result_resources_list.append( resource_id) break else: if self.dry_run == 'no': try: self.elbv2_client.add_tags( ResourceArns=[resource_id], Tags=all_tags) logger.info(all_tags) except Exception as err: logger.exception( f'Tags are already updated, {err}' ) result_resources_list.append(resource_id) break break logger.info( f'cluster_load_balancer_v2 count: {len(sorted(result_resources_list))} {sorted(result_resources_list)}' ) return sorted(result_resources_list)
def __delete_security_group(self, resource_id: str, vpc_id: str): """ This method deletes the NatGateway in the following order remove security group ingress --> modify security groups in Network interface --> delete security group :param resource_id: :return: """ try: security_groups = self.get_detail_list( func_name=self.client.describe_security_groups, input_tag='SecurityGroups', check_tag='NextToken') vpc_security_groups = self.__get_cluster_references( resource_id=vpc_id, resource_list=security_groups, input_resource_id='VpcId', output_result='') for vpc_security_group in vpc_security_groups: if vpc_security_group.get('IpPermissions'): self.client.revoke_security_group_ingress( GroupId=vpc_security_group.get('GroupId'), IpPermissions=vpc_security_group.get('IpPermissions')) network_interfaces = self.get_detail_list( func_name=self.client.describe_network_interfaces, input_tag='NetworkInterfaces', check_tag='NextToken') network_interface_ids = self.__get_cluster_references( resource_id=vpc_id, resource_list=network_interfaces, input_resource_id='VpcId', output_result='') default_security_group_id = [ security_group.get('GroupId') for security_group in vpc_security_groups if security_group.get('GroupName') == 'default' ][0] for network_interface in network_interface_ids: for security_group in network_interface.get('Groups'): if security_group.get( 'GroupId' ) == resource_id and default_security_group_id != security_group.get( 'GroupId'): self.client.modify_network_interface_attribute( Groups=[default_security_group_id], NetworkInterfaceId=network_interface.get( 'NetworkInterfaceId')) if resource_id == default_security_group_id: logger.info( f'default security group: {resource_id} is deleted by vpc: {vpc_id} ' ) else: self.client.delete_security_group(GroupId=resource_id) logger.info(f'delete_security_group: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_security_group: {resource_id}, {err}')
def __delete_vpc_endpoints(self, resource_id: str): """ This method delete the VPC endpoints based on vpc_endpoint ID :param resource_id: :return: """ try: self.client.delete_vpc_endpoints(VpcEndpointIds=[resource_id]) logger.info(f'delete_vpc_endpoints: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_vpc_endpoints: {resource_id}, {err}')
def __delete_load_balancer_v2(self, resource_id: str): """ Delete the Load Balancer based on LoadBalancer ID :param resource_id: :return: """ try: self.elbv2_client.delete_load_balancer(LoadBalancerArn=resource_id) logger.info(f'delete_load_balancer: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_load_balancer: {resource_id}, {err}')
def __delete_subnet(self, resource_id: str): """ This method delete the Subnets in the following order Network Interface --> Subnet :param resource_id: :return: """ try: self.network_interface(subnet_id=resource_id) self.client.delete_subnet(SubnetId=resource_id) logger.info(f'delete_subnet: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_subnet: {resource_id}, {err}')
def __delete_s3_bucket(self, resource_id: str): """ This method delete the bucket from s3 :param resource_id: :return: """ try: # delete bucket objects bucket = self.s3_resource.Bucket(resource_id) bucket.objects.all().delete() # delete bucket self.s3_client.delete_bucket(Bucket=resource_id) logger.info(f'delete_bucket: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_bucket: {resource_id}, {err}')
def __delete_dhcp_options(self, resource_id: str, vpc_id: str = ''): """ This method delete the dhcp options in the following order set associate dhcp options in vpc as default --> delete dhcp options :param resource_id: :return: """ try: if vpc_id: self.client.associate_dhcp_options(DhcpOptionsId='default', VpcId=vpc_id) self.client.delete_dhcp_options(DhcpOptionsId=resource_id) logger.info(f'delete_dhcp_options: {resource_id}') except Exception as err: logger.exception( f'Cannot delete_dhcp_options: {resource_id}, {err}')
def zombie_cluster_ami(self, vpc_id: str = ''): """ This method return list of cluster's ami according to cluster tag name and cluster name data """ images = self.ec2_client.describe_images(Owners=['self']) images_data = images['Images'] exist_ami = self.__get_cluster_resources(resources_list=images_data, input_resource_id='ImageId') zombies = self.__get_zombie_resources(exist_ami) if zombies and self.delete: for zombie in zombies: try: self.ec2_client.deregister_image(ImageId=zombie) logger.info(f'deregister_image: {zombie}') except Exception as err: logger.exception( f'Cannot deregister_image: {zombie}, {err}') return zombies
def __delete_user(self, resource_id: str): """ This method deletes the Zombie cluster user :param resource_id: :return: """ try: # Detach policy from user user_policies = self.iam_client.list_user_policies(UserName=resource_id) if user_policies['PolicyNames']: self.iam_client.delete_user_policy(UserName=resource_id, PolicyName=f'{resource_id}-policy') list_access_key = self.iam_client.list_access_keys(UserName=resource_id) # delete user access key for access_key in list_access_key['AccessKeyMetadata']: self.iam_client.delete_access_key(UserName=resource_id, AccessKeyId=access_key['AccessKeyId']) self.iam_client.delete_user(UserName=resource_id) logger.info(f'delete_user: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_user: {resource_id}, {err}')
def __delete_network_interface(self, resource_id: str): """ This method deletes the Network Interface in the following order Load balancer / NatGateway --> Release Elastic IPs --> detach Network Interface --> Delete Network Interface :param resource_id: :return: """ try: resource_list = self.get_detail_list( func_name=self.client.describe_network_interfaces, input_tag='NetworkInterfaces', check_tag='NextToken') descriptions = self.__get_cluster_references( resource_id=resource_id, resource_list=resource_list, input_resource_id='NetworkInterfaceId', output_result="Description") delete = False if descriptions: for description in descriptions: if "ELB" in description: self.__delete_load_balancer(description.split(" ")[-1]) elif "NAT" in description: self.__delete_nat_gateways( resource_id=description.split(" ")[-1]) delete = True if resource_list and not delete: attachments = self.__get_cluster_references( resource_id=resource_id, resource_list=resource_list, input_resource_id='NetworkInterfaceId', output_result='Attachment') if attachments: self.client.detach_network_interface( AttachmentId=attachments[0]['AttachmentId']) self.client.delete_network_interface( NetworkInterfaceId=resource_id) logger.info(f'delete_network_interface: {resource_id}') except Exception as err: logger.exception( f'Cannot disassociate_address: {resource_id}, {err}')
def __delete_elastic_ip(self, resource_id: str, deletion_type: str): """ This method delete Elastic Ip in the following order Network Interface --> Release IP :param resource_id: :return: """ try: if deletion_type: elastic_ips = self.client.describe_addresses()['Addresses'] network_interfaces = self.__get_cluster_references( resource_id=resource_id, resource_list=elastic_ips, input_resource_id='AssociationId', output_result='NetworkInterfaceId') for network_interface in network_interfaces: self.__delete_network_interface(network_interface) else: self.client.release_address(AllocationId=resource_id) logger.info(f'release_address: {resource_id}') except Exception as err: logger.exception(f'Cannot release_address: {resource_id}, {err}')
def __delete_route_table(self, resource_id: str, vpc_id: str): """ This method deleted the Route Table in the following order Disassociate Route Tables subnets --> Route table :param resource_id: :return: """ # @todo call vpc deletion try: route_tables = self.get_detail_list( func_name=self.client.describe_route_tables, input_tag='RouteTables', check_tag='NextToken') subnets = self.__get_cluster_references( resource_id=resource_id, resource_list=route_tables, input_resource_id='RouteTableId', output_result='Associations') main_route_table = False for subnet in subnets: if subnet.get('SubnetId'): self.client.disassociate_route_table( AssociationId=subnet['RouteTableAssociationId']) elif subnet.get('RouteTableId') and not subnet.get('Main'): self.client.disassociate_route_table( AssociationId=subnet['RouteTableAssociationId']) if subnet.get('Main'): main_route_table = True if not main_route_table: self.client.delete_route_table(RouteTableId=resource_id) logger.info(f'delete_route_table: {resource_id}') else: logger.info( f'Main route table: {resource_id} is deleted by vpc: {vpc_id} ' ) except Exception as err: logger.exception( f'Cannot delete_route_table: {resource_id}, {err}')
def __delete_vpc(self, resource_id: str, pending_resources: dict): """ This method delete the vpc in the following order NatGateway -> Network Interface -> Security groups --> VPC Endpoints --> Route Tables --> Network Acls --> vpc :param resource_id: :param pending_resources: :return: """ try: i = 0 for key, pending_resource in pending_resources.items(): pending_resource(resource_id) vpc_peerings = self.client.describe_vpc_peering_connections( )['VpcPeeringConnections'] for vpc_peering in vpc_peerings: if vpc_peering.get('Status').get('Code') == 'active': if vpc_peering.get('RequesterVpcInfo').get( 'VpcId') == resource_id: self.client.delete_vpc_peering_connection( VpcPeeringConnectionId=vpc_peering.get( 'VpcPeeringConnectionId')) elif vpc_peering.get('AccepterVpcInfo').get( 'VpcId') == resource_id: self.client.delete_vpc_peering_connection( VpcPeeringConnectionId=vpc_peering.get( 'VpcPeeringConnectionId')) elif vpc_peering.get('Status').get( 'Code') == 'pending-acceptance': if vpc_peering.get('RequesterVpcInfo').get( 'VpcId') == resource_id: self.client.delete_vpc_peering_connection( VpcPeeringConnectionId=vpc_peering.get( 'VpcPeeringConnectionId')) self.client.delete_vpc(VpcId=resource_id) logger.info(f'delete_vpc: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_vpc: {resource_id}, {err}')
def cluster_role(self, cluster_names: list = []): """ This method return list of cluster's role according to cluster name @param cluster_names: @return: """ # tag_role result_role_list = [] # if cluster_key exit if self.cluster_name: cluster_names.append(self.cluster_name) if cluster_names: for cluster_name in cluster_names: cluster_key = self.cluster_name if self.cluster_key else cluster_name if cluster_key: # starts with cluster name, search for specific role name for fast scan (a lot of roles) role_name_list = [] roles = self.__get_details_resource_list( func_name=self.iam_client.list_roles, input_tag='Roles', check_tag='Marker') for role in roles: if cluster_key in role.get('RoleName'): role_name_list.append(role.get('RoleName')) if role_name_list: for role_name in role_name_list: try: role = self.iam_client.get_role( RoleName=role_name) role_data = role['Role'] all_tags = [] instance_tags = self.__get_cluster_tags_by_instance_cluster( cluster_name= f'{self.cluster_prefix}{cluster_key}') if not instance_tags: all_tags = self.__append_input_tags( role_data.get('Tags')) else: all_tags.extend(instance_tags) all_tags = self.__filter_resource_tags_by_add_tags( role_data.get('Tags'), all_tags) if all_tags: if self.dry_run == 'no': try: self.iam_client.tag_role( RoleName=role_name, Tags=all_tags) logger.info(all_tags) except Exception as err: logger.exception( f'Tags are already updated, {err}' ) result_role_list.append(role_data['Arn']) except Exception as err: logger.exception( f'Missing cluster role name: {role_name}, {err}' ) else: logger.info(f'No roles for this {cluster_name}') logger.info( f'cluster_role count: {len(sorted(result_role_list))} {sorted(result_role_list)}' ) return sorted(result_role_list)
def __delete_volume(self, resource_id: str): try: self.client.delete_volume(VolumeId=resource_id) logger.info(f'delete_volume: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_volume: {resource_id}, {err}')
def __delete_snapshots(self, resource_id: str): try: self.client.delete_snapshot(SnapshotId=resource_id) logger.info(f'delete_snapshot: {resource_id}') except Exception as err: logger.exception(f'Cannot delete_snapshot: {resource_id}, {err}')