function createBucket(authInfo, bucketName, headers,
    locationConstraint, log, cb) {
    log.trace('Creating bucket');
    assert.strictEqual(typeof bucketName, 'string');
    const canonicalID = authInfo.getCanonicalID();
    const ownerDisplayName =
        authInfo.getAccountDisplayName();
    const creationDate = new Date().toJSON();
    const isNFSEnabled = headers['x-scal-nfs-enabled'] === 'true';
    const headerObjectLock = headers['x-amz-bucket-object-lock-enabled'];
    const objectLockEnabled
        = headerObjectLock && headerObjectLock.toLowerCase() === 'true';
    const bucket = new BucketInfo(bucketName, canonicalID, ownerDisplayName,
        creationDate, BucketInfo.currentModelVersion(), null, null, null, null,
        null, null, null, null, null, null, null, null, null, isNFSEnabled,
        null, null, objectLockEnabled);
    let locationConstraintVal = null;

    if (locationConstraint) {
        const [locationConstraintStr, ingestion] =
            locationConstraint.split(zenkoSeparator);
        if (locationConstraintStr) {
            locationConstraintVal = locationConstraintStr;
            bucket.setLocationConstraint(locationConstraintStr);
        }
        if (ingestion === 'ingest') {
            bucket.enableIngestion();
            //automatically enable versioning for ingestion buckets
            bucket.setVersioningConfiguration({ Status: 'Enabled' });
        }
    }
    if (objectLockEnabled) {
        // default versioning configuration AWS sets
        // when a bucket is created with object lock
        const versioningConfiguration = {
            Status: 'Enabled',
            MfaDelete: 'Disabled',
        };
        bucket.setVersioningConfiguration(versioningConfiguration);
    }
    const parseAclParams = {
        headers,
        resourceType: 'bucket',
        acl: bucket.acl,
        log,
    };
    async.parallel({
        prepareNewBucketMD: function prepareNewBucketMD(callback) {
            acl.parseAclFromHeaders(parseAclParams, (err, parsedACL) => {
                if (err) {
                    log.debug('error parsing acl from headers', {
                        error: err,
                    });
                    return callback(err);
                }
                bucket.setFullAcl(parsedACL);
                return callback(null, bucket);
            });
        },
        getAnyExistingBucketInfo: function getAnyExistingBucketInfo(callback) {
            metadata.getBucket(bucketName, log, (err, data) => {
                // TODO: move to `.is` once BKTCLT-9 is done and bumped in Cloudserver
                if (err && err.NoSuchBucket) {
                    return callback(null, 'NoBucketYet');
                }
                if (err) {
                    return callback(err);
                }
                return callback(null, data);
            });
        },
    },
    // Function to run upon finishing both parallel requests
    (err, results) => {
        if (err) {
            return cb(err);
        }
        const existingBucketMD = results.getAnyExistingBucketInfo;
        if (existingBucketMD instanceof BucketInfo &&
            existingBucketMD.getOwner() !== canonicalID &&
            !isServiceAccount(canonicalID)) {
            // return existingBucketMD to collect cors headers
            return cb(errors.BucketAlreadyExists, existingBucketMD);
        }
        const newBucketMD = results.prepareNewBucketMD;
        if (existingBucketMD === 'NoBucketYet') {
            const bucketSseConfig = parseBucketEncryptionHeaders(headers);

            // Apply global SSE configuration when global encryption is enabled
            // and no SSE settings were specified during bucket creation.
            // Bucket-specific SSE headers override the default encryption.
            const sseConfig = config.globalEncryptionEnabled && !bucketSseConfig.algorithm
            ? {
                algorithm: 'AES256',
                mandatory: true,
            } : bucketSseConfig;

            return bucketLevelServerSideEncryption(
                bucket, sseConfig, log,
                (err, sseInfo) => {
                    if (err) {
                        return cb(err);
                    }
                    newBucketMD.setServerSideEncryption(sseInfo);
                    log.trace(
                        'new bucket without flags; adding transient label');
                    newBucketMD.addTransientFlag();
                    return freshStartCreateBucket(newBucketMD, canonicalID,
                                                  log, cb);
                });
        }
        if (existingBucketMD.hasTransientFlag() ||
            existingBucketMD.hasDeletedFlag()) {
            log.trace('bucket has transient flag or deleted flag. cleaning up');
            return cleanUpBucket(newBucketMD, canonicalID, log, cb);
        }
        // If bucket already exists in non-transient and non-deleted
        // state and owned by requester, then return BucketAlreadyOwnedByYou
        // error unless old AWS behavior (us-east-1)
        // Existing locationConstraint must have legacyAwsBehavior === true
        // New locationConstraint should have legacyAwsBehavior === true
        if (isLegacyAWSBehavior(locationConstraintVal) &&
            isLegacyAWSBehavior(existingBucketMD.getLocationConstraint())) {
            log.trace('returning 200 instead of 409 to mirror us-east-1');
            return cb(null, existingBucketMD);
        }
        return cb(errors.BucketAlreadyOwnedByYou, existingBucketMD);
    });
}
Creates bucket
@param {AuthInfo} authInfo - Instance of AuthInfo class with
                             requester's info
@param {string} bucketName - name of bucket
@param {object} headers - request headers
@param {string} locationConstraint - locationConstraint provided in
                                     request body xml (if provided)
@param {function} log - Werelogs logger
@param {function} cb - callback to bucketPut
@return {undefined}