def expired_cleanup(event: Event): graph = event.data now = datetime.utcnow().replace(tzinfo=timezone.utc) with graph.lock.read_access: for node in graph.nodes: cloud = node.cloud(graph) account = node.account(graph) region = node.region(graph) if isinstance(node, BaseResource) and isinstance(cloud, BaseCloud) and isinstance(account, BaseAccount) and isinstance(region, BaseRegion): if 'cloudkeeper:expires' in node.tags or ('expiration' in node.tags and node.tags['expiration'] != 'never'): try: if 'cloudkeeper:expires' in node.tags: expires_tag = node.tags['cloudkeeper:expires'] expires = make_valid_timestamp(datetime.fromisoformat(expires_tag)) else: expires_tag = node.tags['expiration'] expires = make_valid_timestamp(node.ctime + parse_delta(expires_tag)) except ValueError: log.exception((f'Found {node.resource_type} {node.dname} in cloud {cloud.name}' f' account {account.dname} region {region.name} age {node.age} with invalid expires tag {expires_tag}')) continue else: if now > expires: log.debug((f'Found expired resource {node.resource_type} {node.dname} in cloud {cloud.name}' f' account {account.dname} region {region.name} age {node.age} with expires tag {expires_tag}' f' - marking for cleanup')) node.clean = True
def __init__( self, *args, last_attach_timestamp: datetime = None, last_detach_timestamp: datetime = None, **kwargs, ) -> None: super().__init__(*args, **kwargs) self.set_label_identifier = "resource" self.last_attach_timestamp = make_valid_timestamp(last_attach_timestamp) self.last_detach_timestamp = make_valid_timestamp(last_detach_timestamp) # last_activity = ( # self.last_detach_timestamp # if self.last_detach_timestamp > self.last_attach_timestamp # else self.last_attach_timestamp # ) # if self.volume_status == "available": # self.atime = self.mtime = last_activity if isinstance(self.volume_type, BaseResource): self.volume_type = self.volume_type.name
def __init__(self, identifier, tags, user: User): super().__init__(identifier, tags) self.user_id = user.id self.external_id = user.external_id self.email = user.email self.username = user.username self.firstname = user.firstname self.lastname = user.lastname self.distinguished_name = user.distinguished_name self.phone = user.phone self.company = user.company self.department = user.department self.title = user.title self.status = user.status self.member_of = user.member_of self.samaccountname = user.samaccountname self.userprincipalname = user.userprincipalname self.group_id = user.group_id self.role_ids = user.role_ids self.custom_attributes = user.custom_attributes self.openid_name = user.openid_name self.locale_code = user.locale_code self.comment = user.comment self.directory_id = user.directory_id self.manager_ad_id = user.manager_ad_id self.trusted_idp_id = user.trusted_idp_id self.manager_user_id = user.manager_user_id self.activated_at = user.activated_at self.created_at = user.created_at self.updated_at = user.updated_at self.password_changed_at = user.password_changed_at self.invitation_sent_at = user.invitation_sent_at self.invalid_login_attempts = user.invalid_login_attempts self.last_login = user.last_login self.locked_until = user.locked_until self.state = user.state self.ctime = self.created_at self.atime = self.last_login self.mtime = self.updated_at self.password_age = datetime.utcnow().replace( tzinfo=timezone.utc) - make_valid_timestamp( self.password_changed_at)
def cmd_match(self, items: Iterable, args: str) -> Iterable: '''Usage: | match [not] <attribute> <operator> <value> Matches resources whose attribute matches a value. Valid operators are: > greather than < less than = equal to ~ regex match has value is contained in attribute ''' attr, action, value = None, None, None negate_match = False if args.startswith('not '): negate_match = True args = args[4:] for action in self.match_actions.keys(): if action in args: pos = args.index(action) if pos == 0 or pos == len(args) - 1: raise RuntimeError( f"Can't have {action} at the beginning or end of match" ) attr, value = args.split(action, 1) attr = attr.strip() value = value.strip() break if not attr or not action or not value: raise RuntimeError(f'Invalid match {args}') for item in items: item_attr = self.get_item_attr(item, attr) if item_attr is None: continue # We convert value for every resource even though # chances are that types for same attributes are the # same across all resource types. match_item_attr = item_attr match_value = value if isinstance(item_attr, timedelta): match_value = parse_delta(value) elif isinstance(item_attr, datetime): match_value = make_valid_timestamp( datetime.fromisoformat(value)) elif isinstance(item_attr, bool): match_value = strtobool(value) elif isinstance(item_attr, int): if str(value).isnumeric(): match_value = int(value) else: match_item_attr, match_value = str(item_attr), str(value) elif isinstance(item_attr, float): if not bool(re.search('[^0-9.]', str(value))): match_value = float(value) else: match_item_attr, match_value = str(item_attr), str(value) elif isinstance(item_attr, complex): if not bool(re.search('[^0-9.]', str(value))): match_value = complex(value) else: match_item_attr, match_value = str(item_attr), str(value) if (not negate_match and self.match_actions[action]( match_item_attr, match_value)) or ( negate_match and not self.match_actions[action] (match_item_attr, match_value)): yield item
import time import logging import copy from datetime import date from enum import Enum, auto from cloudkeeper.baseresources import * from cloudkeeper.graph import Graph from cloudkeeper.utils import make_valid_timestamp from .utils import aws_client, aws_resource default_ctime = make_valid_timestamp(date(2006, 3, 19)) # AWS public launch date log = logging.getLogger('cloudkeeper.' + __name__) # derived from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html class AWSAccount(BaseAccount): resource_type = 'aws_account' def __init__(self, *args, role: str = None, **kwargs) -> None: super().__init__(*args, **kwargs) self.role = role class AWSRegion(BaseRegion): resource_type = 'aws_region' def __init__(self, *args, role: str = None, **kwargs) -> None: super().__init__(*args, **kwargs) self.ctime = default_ctime