function bucketPutVersioning(authInfo, request, log, callback) {
    log.debug('processing request', { method: 'bucketPutVersioning' });

    const bucketName = request.bucketName;
    const metadataValParams = {
        authInfo,
        bucketName,
        requestType: request.apiMethods || 'bucketPutVersioning',
        request,
    };
    return waterfall([
        next => _parseXML(request, log, next),
        next => standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log,
            (err, bucket) => next(err, bucket)), // ignore extra null object,
        (bucket, next) => parseString(request.post, (err, result) => {
            // just for linting; there should not be any parsing error here
            if (err) {
                return next(err, bucket);
            }
            // prevent enabling versioning on an nfs exported bucket
            if (bucket.isNFS()) {
                const error = new Error();
                error.code = 'NFSBUCKET';
                return next(error);
            }
            // _checkBackendVersioningImplemented returns false if versioning
            // is not implemented on the bucket backend
            if (!_checkBackendVersioningImplemented(bucket)) {
                log.debug(externalVersioningErrorMessage,
                    { method: 'bucketPutVersioning',
                    error: errors.NotImplemented });
                const error = errorInstances.NotImplemented.customizeDescription(
                    externalVersioningErrorMessage);
                return next(error, bucket);
            }
            const versioningConfiguration = {};
            if (result.VersioningConfiguration.Status) {
                versioningConfiguration.Status =
                    result.VersioningConfiguration.Status[0];
            }
            if (result.VersioningConfiguration.MfaDelete) {
                versioningConfiguration.MfaDelete =
                    result.VersioningConfiguration.MfaDelete[0];
            }
            // the configuration has been checked before
            return next(null, bucket, versioningConfiguration);
        }),
        (bucket, versioningConfiguration, next) => {
            // check if replication is enabled if versioning is being suspended
            const replicationConfig = bucket.getReplicationConfiguration();
            const isIngestionBucket = bucket.isIngestionBucket && bucket.isIngestionBucket();
            const invalidAction =
                versioningConfiguration.Status === 'Suspended'
                && (isIngestionBucket || replicationConfig?.rules?.some(r => r.enabled));
            if (invalidAction) {
                const errorMsg = isIngestionBucket ?
                    ingestionVersioningErrorMessage : replicationVersioningErrorMessage;
                next(errorInstances.InvalidBucketState
                    .customizeDescription(errorMsg));
                return;
            }
            const objectLockEnabled = bucket.isObjectLockEnabled();
            if (objectLockEnabled) {
                next(errorInstances.InvalidBucketState
                    .customizeDescription(objectLockErrorMessage));
                return;
            }
            bucket.setVersioningConfiguration(versioningConfiguration);
            // TODO all metadata updates of bucket should be using CAS
            metadata.updateBucket(bucket.getName(), bucket, log, err =>
                next(err, bucket));
        },
    ], (err, bucket) => {
        const corsHeaders = collectCorsHeaders(request.headers.origin,
            request.method, bucket);
        if (err && err.code === 'NFSBUCKET') {
            log.trace('skipping versioning for nfs exported bucket');
            return callback(null, corsHeaders);
        }
        if (err) {
            log.trace('error processing request', { error: err,
                method: 'bucketPutVersioning' });
            monitoring.promMetrics(
                'PUT', bucketName, err.code, 'putBucketVersioning');
        } else {
            pushMetric('putBucketVersioning', log, {
                authInfo,
                bucket: bucketName,
            });
            monitoring.promMetrics(
                'PUT', bucketName, '200', 'putBucketVersioning');
        }
        return callback(err, corsHeaders);
    });
}
Bucket Put Versioning - Create or update bucket Versioning
@param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info
@param {object} request - http request object
@param {object} log - Werelogs logger
@param {function} callback - callback to server
@return {undefined}