human
Complete this python program:
def locked_volume_id_operation(f, external=False):
assistant
#Here is the Python program you requested.

    """Lock decorator for volume operations.
    Takes a named lock prior to executing the operation. The lock is named
    with the id of the volume. This lock can be used by driver methods
    to prevent conflicts with other operations modifying the same volume.
    May be applied to methods that take a \volume\ or \snapshot\ argument.
    """
    def lvo_inner1(inst, *args, **kwargs):
        lock_tag = inst.driver_prefix
        call_args = inspect.getcallargs(f, inst, *args, **kwargs)
        if call_args.get('volume'):
            volume_id = call_args['volume'].id
        elif call_args.get('snapshot'):
            volume_id = call_args['snapshot'].volume.id
        else:
            err_msg = _('The    decorated    method    must    accept    either    a    volume    or    a    snapshot    object')
            raise exception.VolumeBackendAPIException(data=err_msg)
        @utils.synchronized(('%s-%s' % (lock_tag, volume_id)), external=external)
        def lvo_inner2():
            return f(inst, *args, **kwargs)
        return lvo_inner2()
    return lvo_inner1