from Snapshot import Snapshot import datetime class Disk(object): """ Keeps snapshots assigned to corresponding disks, so we can filter by disks and check for disk replica anomalies. """ def __init__(self, disk): """At init we create empty list we can append Snapshot() objects to""" self.disk_name = disk self.snapshots = list() def add_snapshot(self, snapshot): """ After we created Disk() we want to add to it some Snapshot() This function performs necessary sanity checks to make sure that snapshot is assigned to correct disk :param snapshot: Snapshot() object we will try to assign to disk """ if isinstance(snapshot,Snapshot): disk = snapshot.get_disk_name() if snapshot.get_disk_name() == self.disk_name: self.snapshots.append(snapshot) else: raise AssertionError def get_latest_snapshot_ctime(self): """ We look for the latest taken snapshot, so we can check for failures :return: Epoch time of creation of the most recent snapshot """ latest = max(self.snapshots, key=lambda snapshot: snapshot.get_snapshot_creation_time_epoch()) assert isinstance(latest,Snapshot) return latest.get_snapshot_creation_time_epoch() def get_snapshot_cumulative_size(self, human_readable = True): """ Gets cumulative size of snapshots for the Disk() so we can look if it isn't 0 bytes or too small :param human_readable: For console app we want to use human-readable size values :return: cumulative size of snapshots human-readable or if not in bytes """ ## TODO Probably should add initial disk size to this or make seperate method if human_readable: return Snapshot.sizeof_fmt\ (sum(snapshot.get_snapshot_used_size(human_readable=False) for snapshot in self.snapshots)) else: return sum(snapshot.get_snapshot_used_size(human_readable=False) for snapshot in self.snapshots) def check_if_old(self): """ We check if we received snapshot from the last day :return: True if we didn't receive snapshot, False if everything is working fine here. """ latest_date = self.get_latest_snapshot_ctime() now = datetime.datetime.now().timestamp() acceptable_time = 24*60*60 # 1 day return True if (now - latest_date > acceptable_time) else False def check_if_zero_bytes(self): ## TODO Check if empty snapshot is for sure bad snapshot. If the last but one isn't empty, it might be ok. """ We check if the snapshot is empty. It's probably useless if it is :return: True if snapshot is zero bytes in size. False, if it's fine. """ size = self.get_snapshot_cumulative_size(human_readable=False) return True if (size == 0) else False def check_for_problems(self): ## TODO Some verbose information what is probably wrong about latest snapshot. """ We combine the factors that make snapshot bad. E.g if snapshot isn't empty but it's old it's still bad. :return: False if everyhing about latest snapshot is fine. True if something went wrong """ return True if any([self.check_if_zero_bytes(), self.check_if_old()]) else False def __repr__(self): return self.disk_name + " " + str(self.check_for_problems())