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 get_volume_entry(name_or_id):
    info = {'locked':False}
    out = vos('listvldb', '-name', name_or_id, '-quiet', '-noresolve', '-noauth')
    for line in out.splitlines():
        m = re.search(r'^(\S+)', line)
        if m:
            info['name'] = m.group(1)
        m = re.search(r'RWrite: (\d+)', line)
        if m:
            info['rw'] = m.group(1)
        m = re.search(r'ROnly: (\d+)', line)
        if m:
            info['ro'] = m.group(1)
        m = re.search(r'Backup: (\d+)', line)
        if m:
            info['bk'] = m.group(1)
        m = re.match(r'\s+server (\S+) partition /vicep(\S+) RW Site', line)
        if m:
            info['server'] = m.group(1)
            info['part'] = m.group(2)
        m = re.match(r'\s+server (\S+) partition /vicep(\S+) RO Site', line)
        if m:
            server = m.group(1)
            part = m.group(2)
            if 'rosites' not in info:
                info['rosites'] = []
            info['rosites'].append((server, part))
        m = re.match(r'\s*Volume is currently LOCKED', line)
        if m:
            info['locked'] = True
        m = re.match(r'\s*Volume is locked for a (\S+) operation', line)
        if m:
            info['op'] = m.group(1)
    return info
 def volume_location_matches(self, name_or_id, server, part, vtype='rw'):
     address = socket.gethostbyname(server)
     if vtype not in ('rw', 'ro', 'bk'):
         raise AssertionError("Volume type must be one of 'rw', 'ro', or 'bk'.")
     volume = get_volume_entry(name_or_id)
     logger.info("volume: %s" % (volume))
     if vtype not in volume:
         raise AssertionError("Volume type '%s' not found in VLDB for volume '%s'" % (vtype, name_or_id))
     if vtype == 'ro':
         found = False
         for s,p in volume['rosites']:
             if s == address and p == part:
                 found = True
         if not found:
             raise AssertionError("Volume entry does not contain ro site! %s:%s" % (server, part))
     else:
         if volume['server'] != address or volume['part'] != part:
             raise AssertionError("Volume entry location does not match! expected %s:%s, found %s:%s" %
                                  (address, part, volume['server'], volume['part']))
     out = vos('listvol', '-server', volume['server'], '-partition', volume['part'], '-fast', '-noauth', '-quiet')
     for line in out.splitlines():
         vid = line.strip()
         if vid:
            if volume[vtype] == vid:
                return
     raise AssertionError("Volume id %s is not present on server '%s', partition '%s'" %
                          (volume['rw'], volume['server'], volume['part']))
def get_parts(server):
    """Get the server partitions."""
    parts = []
    for line in vos('listpart', server).splitlines():
        line = line.strip()
        if line.startswith("The partitions"):
            continue
        if line.startswith("Total"):
            continue
        for part in line.split():
            parts.append(part.replace("/vicep", ""))
    return parts
    def volume_should_exist(self, name_or_id):
        """Verify the existence of a read-write volume.

        Fails if the volume entry is not found in the VLDB or the volume is
        not present on the fileserver indicated by the VLDB.
        """
        volume = get_volume_entry(name_or_id)
        out = vos('listvol', '-server', volume['server'], '-partition', volume['part'], '-fast', '-noauth', '-quiet')
        for line in out.splitlines():
            vid = line.strip()
            if vid:
               if volume['rw'] == vid:
                   return
        raise AssertionError("Volume id %s is not present on server '%s', partition '%s'" %
                             (volume['rw'], volume['server'], volume['part']))
    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 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 release_volume(self, name):
     vos('release', '-id', name, '-verbose')
     fs("checkvolumes")
def _zap_volume(name_or_id, server, part):
    try:
        vos('zap', '-id', name_or_id, '-server', server, '-part', part);
    except NoSuchEntryError:
        logger.info("No such volume to zap")