def release_parent(path): ppath = os.path.dirname(path) info = examine_path(ppath) parent = get_volume_entry(info['vid']) if 'ro' in parent: vos('release', parent['name'], '-verbose') fs("checkvolumes")
def examine_path(path): info = {} out = fs('examine', '-path', path) for line in out.splitlines(): m = re.match(r'File (\S+) \(([\d\.]+)\) contained in volume (\d+)', line) if m: info['path'] = m.group(1) info['fid'] = m.group(2) info['vid'] = int(m.group(3)) m = re.match(r'Volume status for vid = (\d+) named (\S+)', line) if m: info['name'] = m.group(2) m = re.match(r'Current disk quota is unlimited', line) if m: info['quota'] = 0 m = re.match(r'Current disk quota is (\d+)', line) if m: info['quota'] = int(m.group(1)) m = re.match(r'Current blocks used are (\d+)', line) if m: info['blocks'] = int(m.group(1)) m = re.match(r'The partition has (\d+) blocks available out of (\d+)', line) if m: free = int(m.group(1)) total = int(m.group(2)) used = total - free info['part'] = {'free':free, 'used':used, 'total':total} return info
def get_cache_size(self): """Get the cache size. Outputs AFS cache size as the number of 1K blocks.""" s = fs("getcacheparms") # get output string size = re.findall('\d+', s) # find the decimal values in the string return int(size[1]) # output integer for number of 1K blocks
def from_path(cls, path): """Read an ACL from AFS directory to create an ACL test object.""" if not os.path.exists(path): raise AssertionError("Path does not exist: %s" % (path)) if not os.path.isdir(path): raise AssertionError("Path is not a directory: %s" % (path)) acl = AccessControlList() section = None output = fs('listacl', path) for line in output.splitlines(): if line.startswith("Access list for"): continue if line.startswith("Normal rights:"): section = "+" continue if line.startswith("Negative rights:"): section = "-" continue m = re.match(r' (\S+) (\S+)', line) if m: name,rights = (m.group(1),m.group(2)) if not section in ('+', '-'): raise AssertionError("Failed to parse fs listacl; missing section label") acl.add(name, section + rights) return acl
def from_path(cls, path): """Read an ACL from AFS directory to create an ACL test object.""" if not os.path.exists(path): raise AssertionError("Path does not exist: %s" % (path)) if not os.path.isdir(path): raise AssertionError("Path is not a directory: %s" % (path)) acl = AccessControlList() section = None output = fs('listacl', path) for line in output.splitlines(): if line.startswith("Access list for"): continue if line.startswith("Normal rights:"): section = "+" continue if line.startswith("Negative rights:"): section = "-" continue m = re.match(r' (\S+) (\S+)', line) if m: name, rights = (m.group(1), m.group(2)) if not section in ('+', '-'): raise AssertionError( "Failed to parse fs listacl; missing section label") acl.add(name, section + rights) return acl
def create_volume(self, name, server=None, part='a', path=None, quota='0', ro=False, acl=None, orphan=False): """Create and mount a volume. Create a volume and optionally mount the volume. Also optionally create a read-only clone of the volume and release the new new volume. Release the parent volume if it is replicated. """ vid = None if not name: raise AssertionError("volume name is required!") if server is None or server == '': # use this host server = socket.gethostname() if path: path = os.path.abspath(path) if not path.startswith('/afs'): raise AssertionError("Path not in '/afs'.") out = vos('create', '-server', server, '-partition', part, '-name', name, '-m', quota, '-verbose') for line in out.splitlines(): m = re.match(r'Volume (\d+) created on partition', line) if m: vid = m.group(1) break if vid is None: raise AssertionError("Created volume id not found!") if path: fs('mkmount', '-dir', path, '-vol', name) if acl: fs('setacl', '-dir', path, '-acl', *acl.split(',')) if ro: vos('addsite', '-server', server, '-partition', part, '-id', name) vos('release', name, '-verbose') if path: release_parent(path) if orphan: # Intentionally remove the vldb entry for testing! vos('delent', '-id', vid) return vid
def remove_volume(self, name_or_id, path=None, flush=False, server=None, part=None, zap=False): """Remove a volume. Remove the volume and any clones. Optionally remove the given mount point. """ if name_or_id == '0': logger.info("Skipping remove for volume id 0") return volume = None if path and os.path.exists(path): path = os.path.abspath(path) if not path.startswith('/afs'): raise AssertionError("Path not in '/afs': %s" % (path)) if flush: fs("flush", path) fs('rmmount', '-dir', path) release_parent(path) try: volume = get_volume_entry(name_or_id) except NoSuchEntryError: logger.info("No vldb entry found for volume '%s'" % name_or_id) if volume: if 'rosites' in volume: for server,part in volume['rosites']: vos('remove', '-server', server, '-part', part, '-id', "%s.readonly" % name_or_id) vos('remove', '-id', name_or_id) fs("checkvolumes") elif zap: if not server: server = socket.gethostname() if part: try: vos('zap', '-id', name_or_id, '-server', server, '-part', part); except NoSuchEntryError: logger.info("No volume {name_or_id} to zap on server {server} part {part}".format(**locals())) else: for part in get_parts(server): try: vos('zap', '-id', name_or_id, '-server', server, '-part', part); except NoSuchEntryError: logger.info("No volume {name_or_id} to zap on server {server} part {part}".format(**locals()))
def release_volume(self, name): vos('release', '-id', name, '-verbose') fs("checkvolumes")
def mount_volume(self, path, vol, *options): """Mount an AFS volume.""" fs('mkmount', '-dir', path, '-vol', vol, *options)
def add_access_rights(self, path, name, rights): """Add access rights to a path.""" fs('setacl', '-dir', path, '-acl', name, rights)