def test_base_n(self): """Test to/from_base_n conversions.""" alphabet = (string.digits + string.ascii_lowercase + string.ascii_uppercase) for base in [2, 10, 16, 36, 62]: for num in [0, 10, 2313, 23134223879243284]: n_num = utils.to_base_n(num, base=base, alphabet=alphabet) _num = utils.from_base_n(n_num, base=base, alphabet=alphabet) self.assertTrue(num == _num) self.assertEquals(utils.to_base_n(15, base=16), 'f') self.assertEquals(utils.to_base_n(10, base=2), '1010') self.assertEquals( utils.from_base_n('101', base=2), int('101', base=2), ) self.assertEquals(utils.from_base_n('deadbeef', base=16), int('deadbeef', base=16))
def gen_uniqueid(event_file): """Generate a uniqueid for a given event file Uniqueid needs to be length constrained (exactly 13 char) and character set constrained ([a-z0-9]) to avoid issues with the naming limitations of the different resources of the container (root dir, logical volume, virtual ethernet device, ...) The current smallest length limiter is: virtual ethernet device(13): IFNAMESZ 16 char - 1 (zero terminated) - 2 ('.0'/'.1' suffix) This function will output an unique identifier of a maximum of 13 chars by encoding the event's instance_id, inode number and ctime in base 62. :param event_file: Full path to an event file :type event_file: ``str`` :returns: (``str``) -- 13 chars identifier """ event_stat = os.stat(event_file) # Event time is the creation time in millisec event_time = int(event_stat.st_ctime * 10**6) # Event data is the event inode (64bit) combined with the instance id # (33bit) # Why: InstanceID is 10 digits: # int(10 * math.log(10) / math.log(2)) -> 33 event_data = int(event_stat.st_ino) _name, _sep, instance = os.path.basename(event_file).rpartition('#') event_data ^= (int(instance) << 31) event_data &= (2**64) - 1 seed = (event_time << 64) + int(event_data) # Trim the top bits so that we only consider 77bits. # Note we trim from the ctime high bits. # Why: int(13 * math.log(62) / math.log(2)) -> 77 seed &= (2**77) - 1 numerals = string.digits + string.ascii_lowercase + string.ascii_uppercase ret = utils.to_base_n(seed, base=len(numerals), alphabet=numerals) return '{identifier:>013s}'.format(identifier=ret)