107 lines
4.0 KiB
Python
107 lines
4.0 KiB
Python
import re
|
|
import datetime
|
|
|
|
class Snapshot(object):
|
|
"""
|
|
Snapshot class we use to convert zfs list string to proper object we can use to analyze replicas.
|
|
"""
|
|
def __init__(self, snapshot_string):
|
|
"""
|
|
We compile some regexes at init so we can use them quickly later.
|
|
We keep tuples of data returned by zfs list command. We do this because it returns Tab-Seperated Data
|
|
:param snapshot_string: string to parse into Snapshot() class object
|
|
"""
|
|
self.snapshot_string = snapshot_string
|
|
self.re_split_tabs = re.compile(r'\t+')
|
|
self.re_name = re.compile(r"[^/]+$")
|
|
self.re_zvol = re.compile(r"^.*[\\/]")
|
|
self.snapshot_tuple = self.parse_string_to_table()
|
|
self.disk_name = self.get_snapshot_name().split("@")[0]
|
|
|
|
def __repr__(self):
|
|
return self.get_snapshot_name()
|
|
|
|
def get_snapshot_string(self):
|
|
return self.snapshot_string
|
|
|
|
def parse_string_to_table(self):
|
|
"""
|
|
We split Tab-Seperaed data returned by zfs list to tuples so we can use it without hassle.
|
|
:return: Tuple containing name, ctime, used_size, ref_size of snapshot
|
|
"""
|
|
array = re.split(self.re_split_tabs, self.snapshot_string)
|
|
return tuple(array)
|
|
|
|
def get_snapshot_name(self):
|
|
"""
|
|
We grab the name only from tuple
|
|
:return: Whole name of the snapshot as str()
|
|
"""
|
|
name_str = self.snapshot_tuple[0]
|
|
name = next(self.re_name.finditer(name_str))
|
|
return name.group()
|
|
|
|
def get_snapshot_zvol(self):
|
|
"""
|
|
We grab the zvol only from tuple
|
|
:return: Zvol where replica is being kept - as str()
|
|
"""
|
|
name_str = self.snapshot_tuple[0]
|
|
zvol = next(self.re_zvol.finditer(name_str))
|
|
return zvol.group()
|
|
|
|
def get_snapshot_creation_time(self):
|
|
"""
|
|
We grab the epoch time from the data in the tuple
|
|
:return: UTC Human-Readable Date of creation of the snapshot
|
|
"""
|
|
time_epoch = int(self.snapshot_tuple[1])
|
|
return str(datetime.datetime.utcfromtimestamp(time_epoch))
|
|
|
|
def get_snapshot_creation_time_epoch(self):
|
|
"""
|
|
We will probably also make use of the epoch time
|
|
:return: Epoch time straight from tuple
|
|
"""
|
|
return int(self.snapshot_tuple[1])
|
|
|
|
def get_snapshot_used_size(self, human_readable = True):
|
|
"""
|
|
We grab used size of the snapshot
|
|
:param human_readable: For backend we want it in Bytes. But we want the user to quickly see how big snapshot is.
|
|
:return: Used Size of the snapshot Human-Readable or not
|
|
"""
|
|
used_str = self.snapshot_tuple[2]
|
|
if human_readable:
|
|
return self.sizeof_fmt(int(used_str))
|
|
else: return int(used_str)
|
|
|
|
def get_snapshot_referenced_size(self, human_readable = True):
|
|
"""
|
|
We grab referenced size of the snapshot
|
|
:param human_readable: For backend we want it in Bytes. But we want the user to quickly see how big snapshot is.
|
|
:return: Referenced Size of the snapshot Human-Readable or not
|
|
"""
|
|
referenced_str = self.snapshot_tuple[3]
|
|
if human_readable:
|
|
return self.sizeof_fmt(int(referenced_str))
|
|
else:
|
|
return int(referenced_str)
|
|
|
|
def get_disk_name(self):
|
|
return self.disk_name
|
|
|
|
@staticmethod
|
|
def sizeof_fmt(num, suffix='B'):
|
|
"""
|
|
Function taken from stackexchange. Used to make size in Bytes Human-readable
|
|
:param num: Bytes value we want to convert
|
|
:param suffix: suffix we want to add to SI Prefix like Ki, Gi etc. E.g. B for GiB
|
|
:return: Human-Readable size string
|
|
"""
|
|
## FIXME WOW taken from stack but it's too fucking slow. Probably because of division. Have to profile
|
|
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
|
if abs(num) < 1024.0:
|
|
return "%3.1f%s%s" % (num, unit, suffix)
|
|
num /= 1024.0
|
|
return "%.1f%s%s" % (num, 'Yi', suffix) |