diff --git a/aif/__init__.py b/aif/__init__.py index 2c80a0a..9de48b4 100644 --- a/aif/__init__.py +++ b/aif/__init__.py @@ -1,3 +1,13 @@ +from . import disk +from . import system +from . import config +from . import constants +from . import envsetup +from . import log +from . import network +from . import pacman +from . import utils + class AIF(object): def __init__(self): pass diff --git a/aif/aif_util.py b/aif/aif_util.py deleted file mode 100644 index 7e9d648..0000000 --- a/aif/aif_util.py +++ /dev/null @@ -1,9 +0,0 @@ -def xmlBool(xmlobj): - if isinstance(xmlobj, bool): - return (xmlobj) - if xmlobj.lower() in ('1', 'true'): - return(True) - elif xmlobj.lower() in ('0', 'false'): - return(False) - else: - return(None) \ No newline at end of file diff --git a/aif/config.py b/aif/config.py index f31e8e0..f84bd69 100644 --- a/aif/config.py +++ b/aif/config.py @@ -5,10 +5,6 @@ import re import requests from lxml import etree, objectify -_patterns = {'raw': re.compile(r'^\s*(?P<(\?xml|aif)\s+.*)\s*$', re.DOTALL|re.MULTILINE), - 'remote': re.compile(r'^(?P(?P(https?|ftps?)://)(?P.*))\s*$'), - 'local': re.compile(r'^(file://)?(?P(/?[^/]+)+/?)$')} - class Config(object): def __init__(self, xsd_path = None, *args, **kwargs): @@ -197,22 +193,21 @@ class ConfigBin(Config): return() +detector = {'raw': (re.compile(r'^\s*(?P<(\?xml|aif)\s+.*)\s*$', re.DOTALL | re.MULTILINE), ConfigStr), + 'remote': (re.compile(r'^(?P(?P(https?|ftps?)://)(?P.*))\s*$'), RemoteFile), + 'local': (re.compile(r'^(file://)?(?P(/?[^/]+)+/?)$'), LocalFile)} + + def getConfig(cfg_ref, validate = True, populate_defaults = True, xsd_path = None): cfgobj = None # This is kind of gross. - for configtype, pattern in _patterns.items(): + for configtype, (pattern, configClass) in detector.items(): try: if pattern.search(cfg_ref): - if configtype == 'raw': - cfgobj = ConfigStr(cfg_ref, xsd_path = xsd_path) - elif configtype == 'remote': - cfgobj = RemoteFile(cfg_ref, xsd_path = xsd_path) - elif configtype == 'local': - cfgobj = LocalFile(cfg_ref, xsd_path = xsd_path) - if cfgobj: - break + cfgobj = configClass(cfg_ref, xsd_path = xsd_path) + break except TypeError: - ptrn = re.compile(_patterns['raw'].pattern.encode('utf-8')) + ptrn = re.compile(detector['raw'][0].pattern.encode('utf-8')) if not ptrn.search(cfg_ref): raise ValueError('Received junk data for cfg_ref') else: diff --git a/aif/disk/block.py b/aif/disk/block.py index e6f680f..b67b8de 100644 --- a/aif/disk/block.py +++ b/aif/disk/block.py @@ -18,7 +18,7 @@ import blkinfo import parted # https://www.gnu.org/software/parted/api/index.html import psutil ## -from aif.aif_util import xmlBool +from aif.utils import xmlBool PARTED_FSTYPES = sorted(list(dict(vars(parted.filesystem))['fileSystemType'].keys())) @@ -148,6 +148,9 @@ class Partition(object): _pedpart = self.partition.getPedPartition() _pedpart.set_name(self.xml.attrib.get('name')) + def detect(self): + pass + class Disk(object): def __init__(self, disk_xml): diff --git a/aif/disk/mdadm.py b/aif/disk/mdadm.py index 31db274..95698eb 100644 --- a/aif/disk/mdadm.py +++ b/aif/disk/mdadm.py @@ -3,6 +3,7 @@ import datetime import math import re import subprocess +import uuid ## import mdstat ## @@ -88,7 +89,7 @@ class Member(object): v = re.sub(r'^raid', '', v) elif k == 'checksum': cksum, status = [i.strip() for i in v.split('-')] - v = (int(cksum), status) + v = (bytes.fromhex(cksum), status) elif k == 'unused_space': r = _mdblock_unused_re.search(v) if not r: @@ -108,6 +109,10 @@ class Member(object): v = {} for i in ('entries', 'offset'): v[i] = int(r.group(i)) # offset is in sectors + elif k == 'array_state': + v = [i.strip() for i in v.split(None, 1)][0].split() + elif k == 'device_uuid': + v = uuid.UUID(hex = v.replace(':', '-')) elif re.search((r'^(creation|update)_time$'), k): # TODO: Is this portable/correct? Or do I need to do '%a %b %d %H:%M:%s %Y'? v = datetime.datetime.strptime(v, '%c') @@ -119,7 +124,9 @@ class Member(object): self.devpath)) v = {} for i in ('sectors', 'GB', 'GiB'): - v[i] = int(r.group(i)) + v[i] = float(r.group(i)) + if i == 'sectors': + v[i] = int(v[i]) elif re.search(r'^(data|super)_offset$', k): v = int(v.split(None, 1)[0]) block[k] = v diff --git a/aif/utils.py b/aif/utils.py new file mode 100644 index 0000000..968da68 --- /dev/null +++ b/aif/utils.py @@ -0,0 +1,75 @@ +def xmlBool(xmlobj): + # https://bugs.launchpad.net/lxml/+bug/1850221 + if isinstance(xmlobj, bool): + return (xmlobj) + if xmlobj.lower() in ('1', 'true'): + return(True) + elif xmlobj.lower() in ('0', 'false'): + return(False) + else: + return(None) + +class _Sizer(object): + def __init__(self): + def _getKeys(d, keylist = None): + if not keylist: + keylist = [] + for k, v in d.items(): + if isinstance(v, dict): + keylist.append(k) + keylist = _getKeys(v, keylist = keylist) + else: + keylist.append(k) + return (keylist) + # We use different methods for converting between storage and BW, and different multipliers for each subtype. + # https://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python + # https://en.wikipedia.org/wiki/Orders_of_magnitude_(data) + # https://en.wikipedia.org/wiki/Binary_prefix + self.storageUnits = {'decimal': {'B': 0, + 'kB': 7, # Kilobyte + 'MB': 17, # Megabyte... + 'GB': 27, + 'TB': 37}, + 'binary': {'KiB': 10, # Kibibyte + 'MiB': 20, # Mebibyte... + 'GiB': 30, + 'TiB': 40}} + # https://en.wikipedia.org/wiki/Bit#Multiple_bits + self.bwUnits = {'b': None, + 'bit': None, + 'k': } + self.valid_storage = list(self.storageUnits.keys()) + self.valid_storage.insert('nibble') + self.valid_bw = _getKeys(self.bwUnits) + + def convert(self, n, suffix, target = None): + pass + + def convertBW(self, n, suffix, target = None): + inBits = n + if suffix not in self.valid_bw: + raise ValueError('suffix must be one of {0}'.format(', '.format(self.valid_bw))) + if suffix != 'b': + if self.bwUnits[suffix]: + inBits = n * (10 ** self.bwUnits[suffix]) + else: + inBits = None + + def convertStorage(self, n, suffix, target = None): + inBytes = n + if suffix not in self.valid_storage: + raise ValueError('suffix must be one of {0}'.format(', '.format(self.valid_storage))) + if suffix == 'nibble': + inBytes = n * 0.5 + elif suffix != 'B': + inBytes = float(n << self.storageUnits[suffix]) + if target: + conversion = float(inBytes / float(1 << self.storageUnits[target])) + else: + conversion = {} + for unit, shifter in self.storageUnits.items(): + conversion[unit] = float(inBytes / float(1 << self.storageUnits[unit])) + return(conversion) + + +size = _Sizer() diff --git a/examples/aif.xml b/examples/aif.xml index 11b08e3..43f25fc 100644 --- a/examples/aif.xml +++ b/examples/aif.xml @@ -23,9 +23,11 @@ raid - + swap + +