diff --git a/cmd/admin-bucket-handlers.go b/cmd/admin-bucket-handlers.go index cca40db0e..401652918 100644 --- a/cmd/admin-bucket-handlers.go +++ b/cmd/admin-bucket-handlers.go @@ -205,6 +205,12 @@ func (a adminAPIHandlers) SetRemoteTargetHandler(w http.ResponseWriter, r *http. } target = tgt } + + // enforce minimum bandwidth limit as 100MBps + if target.BandwidthLimit < 100*1000*1000 { + writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrReplicationBandwidthLimitError, err), r.URL) + return + } if err = globalBucketTargetSys.SetTarget(ctx, bucket, &target, update); err != nil { switch err.(type) { case BucketRemoteConnectionErr: diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 2cc9d3cdb..d14f7996c 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -115,6 +115,7 @@ const ( ErrReplicationDestinationMissingLock ErrRemoteTargetNotFoundError ErrReplicationRemoteConnectionError + ErrReplicationBandwidthLimitError ErrBucketRemoteIdenticalToSource ErrBucketRemoteAlreadyExists ErrBucketRemoteLabelInUse @@ -860,6 +861,11 @@ var errorCodes = errorCodeMap{ Description: "Remote service connection error - please check remote service credentials and target bucket", HTTPStatusCode: http.StatusNotFound, }, + ErrReplicationBandwidthLimitError: { + Code: "XMinioAdminReplicationBandwidthLimitError", + Description: "Bandwidth limit for remote target must be atleast 100MBps", + HTTPStatusCode: http.StatusBadRequest, + }, ErrReplicationNoMatchingRuleError: { Code: "XMinioReplicationNoMatchingRule", Description: "No matching replication rule found for this object prefix", diff --git a/cmd/apierrorcode_string.go b/cmd/apierrorcode_string.go index 0b50cf5a5..314d0f910 100644 --- a/cmd/apierrorcode_string.go +++ b/cmd/apierrorcode_string.go @@ -52,243 +52,244 @@ func _() { _ = x[ErrReplicationDestinationMissingLock-41] _ = x[ErrRemoteTargetNotFoundError-42] _ = x[ErrReplicationRemoteConnectionError-43] - _ = x[ErrBucketRemoteIdenticalToSource-44] - _ = x[ErrBucketRemoteAlreadyExists-45] - _ = x[ErrBucketRemoteLabelInUse-46] - _ = x[ErrBucketRemoteArnTypeInvalid-47] - _ = x[ErrBucketRemoteArnInvalid-48] - _ = x[ErrBucketRemoteRemoveDisallowed-49] - _ = x[ErrRemoteTargetNotVersionedError-50] - _ = x[ErrReplicationSourceNotVersionedError-51] - _ = x[ErrReplicationNeedsVersioningError-52] - _ = x[ErrReplicationBucketNeedsVersioningError-53] - _ = x[ErrReplicationNoMatchingRuleError-54] - _ = x[ErrObjectRestoreAlreadyInProgress-55] - _ = x[ErrNoSuchKey-56] - _ = x[ErrNoSuchUpload-57] - _ = x[ErrInvalidVersionID-58] - _ = x[ErrNoSuchVersion-59] - _ = x[ErrNotImplemented-60] - _ = x[ErrPreconditionFailed-61] - _ = x[ErrRequestTimeTooSkewed-62] - _ = x[ErrSignatureDoesNotMatch-63] - _ = x[ErrMethodNotAllowed-64] - _ = x[ErrInvalidPart-65] - _ = x[ErrInvalidPartOrder-66] - _ = x[ErrAuthorizationHeaderMalformed-67] - _ = x[ErrMalformedPOSTRequest-68] - _ = x[ErrPOSTFileRequired-69] - _ = x[ErrSignatureVersionNotSupported-70] - _ = x[ErrBucketNotEmpty-71] - _ = x[ErrAllAccessDisabled-72] - _ = x[ErrMalformedPolicy-73] - _ = x[ErrMissingFields-74] - _ = x[ErrMissingCredTag-75] - _ = x[ErrCredMalformed-76] - _ = x[ErrInvalidRegion-77] - _ = x[ErrInvalidServiceS3-78] - _ = x[ErrInvalidServiceSTS-79] - _ = x[ErrInvalidRequestVersion-80] - _ = x[ErrMissingSignTag-81] - _ = x[ErrMissingSignHeadersTag-82] - _ = x[ErrMalformedDate-83] - _ = x[ErrMalformedPresignedDate-84] - _ = x[ErrMalformedCredentialDate-85] - _ = x[ErrMalformedCredentialRegion-86] - _ = x[ErrMalformedExpires-87] - _ = x[ErrNegativeExpires-88] - _ = x[ErrAuthHeaderEmpty-89] - _ = x[ErrExpiredPresignRequest-90] - _ = x[ErrRequestNotReadyYet-91] - _ = x[ErrUnsignedHeaders-92] - _ = x[ErrMissingDateHeader-93] - _ = x[ErrInvalidQuerySignatureAlgo-94] - _ = x[ErrInvalidQueryParams-95] - _ = x[ErrBucketAlreadyOwnedByYou-96] - _ = x[ErrInvalidDuration-97] - _ = x[ErrBucketAlreadyExists-98] - _ = x[ErrMetadataTooLarge-99] - _ = x[ErrUnsupportedMetadata-100] - _ = x[ErrMaximumExpires-101] - _ = x[ErrSlowDown-102] - _ = x[ErrInvalidPrefixMarker-103] - _ = x[ErrBadRequest-104] - _ = x[ErrKeyTooLongError-105] - _ = x[ErrInvalidBucketObjectLockConfiguration-106] - _ = x[ErrObjectLockConfigurationNotFound-107] - _ = x[ErrObjectLockConfigurationNotAllowed-108] - _ = x[ErrNoSuchObjectLockConfiguration-109] - _ = x[ErrObjectLocked-110] - _ = x[ErrInvalidRetentionDate-111] - _ = x[ErrPastObjectLockRetainDate-112] - _ = x[ErrUnknownWORMModeDirective-113] - _ = x[ErrBucketTaggingNotFound-114] - _ = x[ErrObjectLockInvalidHeaders-115] - _ = x[ErrInvalidTagDirective-116] - _ = x[ErrInvalidEncryptionMethod-117] - _ = x[ErrInsecureSSECustomerRequest-118] - _ = x[ErrSSEMultipartEncrypted-119] - _ = x[ErrSSEEncryptedObject-120] - _ = x[ErrInvalidEncryptionParameters-121] - _ = x[ErrInvalidSSECustomerAlgorithm-122] - _ = x[ErrInvalidSSECustomerKey-123] - _ = x[ErrMissingSSECustomerKey-124] - _ = x[ErrMissingSSECustomerKeyMD5-125] - _ = x[ErrSSECustomerKeyMD5Mismatch-126] - _ = x[ErrInvalidSSECustomerParameters-127] - _ = x[ErrIncompatibleEncryptionMethod-128] - _ = x[ErrKMSNotConfigured-129] - _ = x[ErrNoAccessKey-130] - _ = x[ErrInvalidToken-131] - _ = x[ErrEventNotification-132] - _ = x[ErrARNNotification-133] - _ = x[ErrRegionNotification-134] - _ = x[ErrOverlappingFilterNotification-135] - _ = x[ErrFilterNameInvalid-136] - _ = x[ErrFilterNamePrefix-137] - _ = x[ErrFilterNameSuffix-138] - _ = x[ErrFilterValueInvalid-139] - _ = x[ErrOverlappingConfigs-140] - _ = x[ErrUnsupportedNotification-141] - _ = x[ErrContentSHA256Mismatch-142] - _ = x[ErrReadQuorum-143] - _ = x[ErrWriteQuorum-144] - _ = x[ErrParentIsObject-145] - _ = x[ErrStorageFull-146] - _ = x[ErrRequestBodyParse-147] - _ = x[ErrObjectExistsAsDirectory-148] - _ = x[ErrInvalidObjectName-149] - _ = x[ErrInvalidObjectNamePrefixSlash-150] - _ = x[ErrInvalidResourceName-151] - _ = x[ErrServerNotInitialized-152] - _ = x[ErrOperationTimedOut-153] - _ = x[ErrClientDisconnected-154] - _ = x[ErrOperationMaxedOut-155] - _ = x[ErrInvalidRequest-156] - _ = x[ErrTransitionStorageClassNotFoundError-157] - _ = x[ErrInvalidStorageClass-158] - _ = x[ErrBackendDown-159] - _ = x[ErrMalformedJSON-160] - _ = x[ErrAdminNoSuchUser-161] - _ = x[ErrAdminNoSuchGroup-162] - _ = x[ErrAdminGroupNotEmpty-163] - _ = x[ErrAdminNoSuchPolicy-164] - _ = x[ErrAdminInvalidArgument-165] - _ = x[ErrAdminInvalidAccessKey-166] - _ = x[ErrAdminInvalidSecretKey-167] - _ = x[ErrAdminConfigNoQuorum-168] - _ = x[ErrAdminConfigTooLarge-169] - _ = x[ErrAdminConfigBadJSON-170] - _ = x[ErrAdminConfigDuplicateKeys-171] - _ = x[ErrAdminCredentialsMismatch-172] - _ = x[ErrInsecureClientRequest-173] - _ = x[ErrObjectTampered-174] - _ = x[ErrAdminBucketQuotaExceeded-175] - _ = x[ErrAdminNoSuchQuotaConfiguration-176] - _ = x[ErrHealNotImplemented-177] - _ = x[ErrHealNoSuchProcess-178] - _ = x[ErrHealInvalidClientToken-179] - _ = x[ErrHealMissingBucket-180] - _ = x[ErrHealAlreadyRunning-181] - _ = x[ErrHealOverlappingPaths-182] - _ = x[ErrIncorrectContinuationToken-183] - _ = x[ErrEmptyRequestBody-184] - _ = x[ErrUnsupportedFunction-185] - _ = x[ErrInvalidExpressionType-186] - _ = x[ErrBusy-187] - _ = x[ErrUnauthorizedAccess-188] - _ = x[ErrExpressionTooLong-189] - _ = x[ErrIllegalSQLFunctionArgument-190] - _ = x[ErrInvalidKeyPath-191] - _ = x[ErrInvalidCompressionFormat-192] - _ = x[ErrInvalidFileHeaderInfo-193] - _ = x[ErrInvalidJSONType-194] - _ = x[ErrInvalidQuoteFields-195] - _ = x[ErrInvalidRequestParameter-196] - _ = x[ErrInvalidDataType-197] - _ = x[ErrInvalidTextEncoding-198] - _ = x[ErrInvalidDataSource-199] - _ = x[ErrInvalidTableAlias-200] - _ = x[ErrMissingRequiredParameter-201] - _ = x[ErrObjectSerializationConflict-202] - _ = x[ErrUnsupportedSQLOperation-203] - _ = x[ErrUnsupportedSQLStructure-204] - _ = x[ErrUnsupportedSyntax-205] - _ = x[ErrUnsupportedRangeHeader-206] - _ = x[ErrLexerInvalidChar-207] - _ = x[ErrLexerInvalidOperator-208] - _ = x[ErrLexerInvalidLiteral-209] - _ = x[ErrLexerInvalidIONLiteral-210] - _ = x[ErrParseExpectedDatePart-211] - _ = x[ErrParseExpectedKeyword-212] - _ = x[ErrParseExpectedTokenType-213] - _ = x[ErrParseExpected2TokenTypes-214] - _ = x[ErrParseExpectedNumber-215] - _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-216] - _ = x[ErrParseExpectedTypeName-217] - _ = x[ErrParseExpectedWhenClause-218] - _ = x[ErrParseUnsupportedToken-219] - _ = x[ErrParseUnsupportedLiteralsGroupBy-220] - _ = x[ErrParseExpectedMember-221] - _ = x[ErrParseUnsupportedSelect-222] - _ = x[ErrParseUnsupportedCase-223] - _ = x[ErrParseUnsupportedCaseClause-224] - _ = x[ErrParseUnsupportedAlias-225] - _ = x[ErrParseUnsupportedSyntax-226] - _ = x[ErrParseUnknownOperator-227] - _ = x[ErrParseMissingIdentAfterAt-228] - _ = x[ErrParseUnexpectedOperator-229] - _ = x[ErrParseUnexpectedTerm-230] - _ = x[ErrParseUnexpectedToken-231] - _ = x[ErrParseUnexpectedKeyword-232] - _ = x[ErrParseExpectedExpression-233] - _ = x[ErrParseExpectedLeftParenAfterCast-234] - _ = x[ErrParseExpectedLeftParenValueConstructor-235] - _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-236] - _ = x[ErrParseExpectedArgumentDelimiter-237] - _ = x[ErrParseCastArity-238] - _ = x[ErrParseInvalidTypeParam-239] - _ = x[ErrParseEmptySelect-240] - _ = x[ErrParseSelectMissingFrom-241] - _ = x[ErrParseExpectedIdentForGroupName-242] - _ = x[ErrParseExpectedIdentForAlias-243] - _ = x[ErrParseUnsupportedCallWithStar-244] - _ = x[ErrParseNonUnaryAgregateFunctionCall-245] - _ = x[ErrParseMalformedJoin-246] - _ = x[ErrParseExpectedIdentForAt-247] - _ = x[ErrParseAsteriskIsNotAloneInSelectList-248] - _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-249] - _ = x[ErrParseInvalidContextForWildcardInSelectList-250] - _ = x[ErrIncorrectSQLFunctionArgumentType-251] - _ = x[ErrValueParseFailure-252] - _ = x[ErrEvaluatorInvalidArguments-253] - _ = x[ErrIntegerOverflow-254] - _ = x[ErrLikeInvalidInputs-255] - _ = x[ErrCastFailed-256] - _ = x[ErrInvalidCast-257] - _ = x[ErrEvaluatorInvalidTimestampFormatPattern-258] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-259] - _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-260] - _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-261] - _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-262] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-263] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-264] - _ = x[ErrEvaluatorBindingDoesNotExist-265] - _ = x[ErrMissingHeaders-266] - _ = x[ErrInvalidColumnIndex-267] - _ = x[ErrAdminConfigNotificationTargetsFailed-268] - _ = x[ErrAdminProfilerNotEnabled-269] - _ = x[ErrInvalidDecompressedSize-270] - _ = x[ErrAddUserInvalidArgument-271] - _ = x[ErrAdminAccountNotEligible-272] - _ = x[ErrAccountNotEligible-273] - _ = x[ErrAdminServiceAccountNotFound-274] - _ = x[ErrPostPolicyConditionInvalidFormat-275] + _ = x[ErrReplicationBandwidthLimitError-44] + _ = x[ErrBucketRemoteIdenticalToSource-45] + _ = x[ErrBucketRemoteAlreadyExists-46] + _ = x[ErrBucketRemoteLabelInUse-47] + _ = x[ErrBucketRemoteArnTypeInvalid-48] + _ = x[ErrBucketRemoteArnInvalid-49] + _ = x[ErrBucketRemoteRemoveDisallowed-50] + _ = x[ErrRemoteTargetNotVersionedError-51] + _ = x[ErrReplicationSourceNotVersionedError-52] + _ = x[ErrReplicationNeedsVersioningError-53] + _ = x[ErrReplicationBucketNeedsVersioningError-54] + _ = x[ErrReplicationNoMatchingRuleError-55] + _ = x[ErrObjectRestoreAlreadyInProgress-56] + _ = x[ErrNoSuchKey-57] + _ = x[ErrNoSuchUpload-58] + _ = x[ErrInvalidVersionID-59] + _ = x[ErrNoSuchVersion-60] + _ = x[ErrNotImplemented-61] + _ = x[ErrPreconditionFailed-62] + _ = x[ErrRequestTimeTooSkewed-63] + _ = x[ErrSignatureDoesNotMatch-64] + _ = x[ErrMethodNotAllowed-65] + _ = x[ErrInvalidPart-66] + _ = x[ErrInvalidPartOrder-67] + _ = x[ErrAuthorizationHeaderMalformed-68] + _ = x[ErrMalformedPOSTRequest-69] + _ = x[ErrPOSTFileRequired-70] + _ = x[ErrSignatureVersionNotSupported-71] + _ = x[ErrBucketNotEmpty-72] + _ = x[ErrAllAccessDisabled-73] + _ = x[ErrMalformedPolicy-74] + _ = x[ErrMissingFields-75] + _ = x[ErrMissingCredTag-76] + _ = x[ErrCredMalformed-77] + _ = x[ErrInvalidRegion-78] + _ = x[ErrInvalidServiceS3-79] + _ = x[ErrInvalidServiceSTS-80] + _ = x[ErrInvalidRequestVersion-81] + _ = x[ErrMissingSignTag-82] + _ = x[ErrMissingSignHeadersTag-83] + _ = x[ErrMalformedDate-84] + _ = x[ErrMalformedPresignedDate-85] + _ = x[ErrMalformedCredentialDate-86] + _ = x[ErrMalformedCredentialRegion-87] + _ = x[ErrMalformedExpires-88] + _ = x[ErrNegativeExpires-89] + _ = x[ErrAuthHeaderEmpty-90] + _ = x[ErrExpiredPresignRequest-91] + _ = x[ErrRequestNotReadyYet-92] + _ = x[ErrUnsignedHeaders-93] + _ = x[ErrMissingDateHeader-94] + _ = x[ErrInvalidQuerySignatureAlgo-95] + _ = x[ErrInvalidQueryParams-96] + _ = x[ErrBucketAlreadyOwnedByYou-97] + _ = x[ErrInvalidDuration-98] + _ = x[ErrBucketAlreadyExists-99] + _ = x[ErrMetadataTooLarge-100] + _ = x[ErrUnsupportedMetadata-101] + _ = x[ErrMaximumExpires-102] + _ = x[ErrSlowDown-103] + _ = x[ErrInvalidPrefixMarker-104] + _ = x[ErrBadRequest-105] + _ = x[ErrKeyTooLongError-106] + _ = x[ErrInvalidBucketObjectLockConfiguration-107] + _ = x[ErrObjectLockConfigurationNotFound-108] + _ = x[ErrObjectLockConfigurationNotAllowed-109] + _ = x[ErrNoSuchObjectLockConfiguration-110] + _ = x[ErrObjectLocked-111] + _ = x[ErrInvalidRetentionDate-112] + _ = x[ErrPastObjectLockRetainDate-113] + _ = x[ErrUnknownWORMModeDirective-114] + _ = x[ErrBucketTaggingNotFound-115] + _ = x[ErrObjectLockInvalidHeaders-116] + _ = x[ErrInvalidTagDirective-117] + _ = x[ErrInvalidEncryptionMethod-118] + _ = x[ErrInsecureSSECustomerRequest-119] + _ = x[ErrSSEMultipartEncrypted-120] + _ = x[ErrSSEEncryptedObject-121] + _ = x[ErrInvalidEncryptionParameters-122] + _ = x[ErrInvalidSSECustomerAlgorithm-123] + _ = x[ErrInvalidSSECustomerKey-124] + _ = x[ErrMissingSSECustomerKey-125] + _ = x[ErrMissingSSECustomerKeyMD5-126] + _ = x[ErrSSECustomerKeyMD5Mismatch-127] + _ = x[ErrInvalidSSECustomerParameters-128] + _ = x[ErrIncompatibleEncryptionMethod-129] + _ = x[ErrKMSNotConfigured-130] + _ = x[ErrNoAccessKey-131] + _ = x[ErrInvalidToken-132] + _ = x[ErrEventNotification-133] + _ = x[ErrARNNotification-134] + _ = x[ErrRegionNotification-135] + _ = x[ErrOverlappingFilterNotification-136] + _ = x[ErrFilterNameInvalid-137] + _ = x[ErrFilterNamePrefix-138] + _ = x[ErrFilterNameSuffix-139] + _ = x[ErrFilterValueInvalid-140] + _ = x[ErrOverlappingConfigs-141] + _ = x[ErrUnsupportedNotification-142] + _ = x[ErrContentSHA256Mismatch-143] + _ = x[ErrReadQuorum-144] + _ = x[ErrWriteQuorum-145] + _ = x[ErrParentIsObject-146] + _ = x[ErrStorageFull-147] + _ = x[ErrRequestBodyParse-148] + _ = x[ErrObjectExistsAsDirectory-149] + _ = x[ErrInvalidObjectName-150] + _ = x[ErrInvalidObjectNamePrefixSlash-151] + _ = x[ErrInvalidResourceName-152] + _ = x[ErrServerNotInitialized-153] + _ = x[ErrOperationTimedOut-154] + _ = x[ErrClientDisconnected-155] + _ = x[ErrOperationMaxedOut-156] + _ = x[ErrInvalidRequest-157] + _ = x[ErrTransitionStorageClassNotFoundError-158] + _ = x[ErrInvalidStorageClass-159] + _ = x[ErrBackendDown-160] + _ = x[ErrMalformedJSON-161] + _ = x[ErrAdminNoSuchUser-162] + _ = x[ErrAdminNoSuchGroup-163] + _ = x[ErrAdminGroupNotEmpty-164] + _ = x[ErrAdminNoSuchPolicy-165] + _ = x[ErrAdminInvalidArgument-166] + _ = x[ErrAdminInvalidAccessKey-167] + _ = x[ErrAdminInvalidSecretKey-168] + _ = x[ErrAdminConfigNoQuorum-169] + _ = x[ErrAdminConfigTooLarge-170] + _ = x[ErrAdminConfigBadJSON-171] + _ = x[ErrAdminConfigDuplicateKeys-172] + _ = x[ErrAdminCredentialsMismatch-173] + _ = x[ErrInsecureClientRequest-174] + _ = x[ErrObjectTampered-175] + _ = x[ErrAdminBucketQuotaExceeded-176] + _ = x[ErrAdminNoSuchQuotaConfiguration-177] + _ = x[ErrHealNotImplemented-178] + _ = x[ErrHealNoSuchProcess-179] + _ = x[ErrHealInvalidClientToken-180] + _ = x[ErrHealMissingBucket-181] + _ = x[ErrHealAlreadyRunning-182] + _ = x[ErrHealOverlappingPaths-183] + _ = x[ErrIncorrectContinuationToken-184] + _ = x[ErrEmptyRequestBody-185] + _ = x[ErrUnsupportedFunction-186] + _ = x[ErrInvalidExpressionType-187] + _ = x[ErrBusy-188] + _ = x[ErrUnauthorizedAccess-189] + _ = x[ErrExpressionTooLong-190] + _ = x[ErrIllegalSQLFunctionArgument-191] + _ = x[ErrInvalidKeyPath-192] + _ = x[ErrInvalidCompressionFormat-193] + _ = x[ErrInvalidFileHeaderInfo-194] + _ = x[ErrInvalidJSONType-195] + _ = x[ErrInvalidQuoteFields-196] + _ = x[ErrInvalidRequestParameter-197] + _ = x[ErrInvalidDataType-198] + _ = x[ErrInvalidTextEncoding-199] + _ = x[ErrInvalidDataSource-200] + _ = x[ErrInvalidTableAlias-201] + _ = x[ErrMissingRequiredParameter-202] + _ = x[ErrObjectSerializationConflict-203] + _ = x[ErrUnsupportedSQLOperation-204] + _ = x[ErrUnsupportedSQLStructure-205] + _ = x[ErrUnsupportedSyntax-206] + _ = x[ErrUnsupportedRangeHeader-207] + _ = x[ErrLexerInvalidChar-208] + _ = x[ErrLexerInvalidOperator-209] + _ = x[ErrLexerInvalidLiteral-210] + _ = x[ErrLexerInvalidIONLiteral-211] + _ = x[ErrParseExpectedDatePart-212] + _ = x[ErrParseExpectedKeyword-213] + _ = x[ErrParseExpectedTokenType-214] + _ = x[ErrParseExpected2TokenTypes-215] + _ = x[ErrParseExpectedNumber-216] + _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-217] + _ = x[ErrParseExpectedTypeName-218] + _ = x[ErrParseExpectedWhenClause-219] + _ = x[ErrParseUnsupportedToken-220] + _ = x[ErrParseUnsupportedLiteralsGroupBy-221] + _ = x[ErrParseExpectedMember-222] + _ = x[ErrParseUnsupportedSelect-223] + _ = x[ErrParseUnsupportedCase-224] + _ = x[ErrParseUnsupportedCaseClause-225] + _ = x[ErrParseUnsupportedAlias-226] + _ = x[ErrParseUnsupportedSyntax-227] + _ = x[ErrParseUnknownOperator-228] + _ = x[ErrParseMissingIdentAfterAt-229] + _ = x[ErrParseUnexpectedOperator-230] + _ = x[ErrParseUnexpectedTerm-231] + _ = x[ErrParseUnexpectedToken-232] + _ = x[ErrParseUnexpectedKeyword-233] + _ = x[ErrParseExpectedExpression-234] + _ = x[ErrParseExpectedLeftParenAfterCast-235] + _ = x[ErrParseExpectedLeftParenValueConstructor-236] + _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-237] + _ = x[ErrParseExpectedArgumentDelimiter-238] + _ = x[ErrParseCastArity-239] + _ = x[ErrParseInvalidTypeParam-240] + _ = x[ErrParseEmptySelect-241] + _ = x[ErrParseSelectMissingFrom-242] + _ = x[ErrParseExpectedIdentForGroupName-243] + _ = x[ErrParseExpectedIdentForAlias-244] + _ = x[ErrParseUnsupportedCallWithStar-245] + _ = x[ErrParseNonUnaryAgregateFunctionCall-246] + _ = x[ErrParseMalformedJoin-247] + _ = x[ErrParseExpectedIdentForAt-248] + _ = x[ErrParseAsteriskIsNotAloneInSelectList-249] + _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-250] + _ = x[ErrParseInvalidContextForWildcardInSelectList-251] + _ = x[ErrIncorrectSQLFunctionArgumentType-252] + _ = x[ErrValueParseFailure-253] + _ = x[ErrEvaluatorInvalidArguments-254] + _ = x[ErrIntegerOverflow-255] + _ = x[ErrLikeInvalidInputs-256] + _ = x[ErrCastFailed-257] + _ = x[ErrInvalidCast-258] + _ = x[ErrEvaluatorInvalidTimestampFormatPattern-259] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-260] + _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-261] + _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-262] + _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-263] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-264] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-265] + _ = x[ErrEvaluatorBindingDoesNotExist-266] + _ = x[ErrMissingHeaders-267] + _ = x[ErrInvalidColumnIndex-268] + _ = x[ErrAdminConfigNotificationTargetsFailed-269] + _ = x[ErrAdminProfilerNotEnabled-270] + _ = x[ErrInvalidDecompressedSize-271] + _ = x[ErrAddUserInvalidArgument-272] + _ = x[ErrAdminAccountNotEligible-273] + _ = x[ErrAccountNotEligible-274] + _ = x[ErrAdminServiceAccountNotFound-275] + _ = x[ErrPostPolicyConditionInvalidFormat-276] } -const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationNoMatchingRuleErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumParentIsObjectStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" +const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorReplicationBandwidthLimitErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorReplicationNoMatchingRuleErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumParentIsObjectStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestTransitionStorageClassNotFoundErrorInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" -var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 142, 154, 176, 196, 222, 236, 257, 274, 289, 312, 329, 347, 364, 388, 403, 424, 442, 454, 474, 491, 514, 535, 547, 565, 586, 614, 635, 658, 684, 721, 751, 784, 809, 841, 870, 895, 917, 943, 965, 993, 1022, 1056, 1087, 1124, 1154, 1184, 1193, 1205, 1221, 1234, 1248, 1266, 1286, 1307, 1323, 1334, 1350, 1378, 1398, 1414, 1442, 1456, 1473, 1488, 1501, 1515, 1528, 1541, 1557, 1574, 1595, 1609, 1630, 1643, 1665, 1688, 1713, 1729, 1744, 1759, 1780, 1798, 1813, 1830, 1855, 1873, 1896, 1911, 1930, 1946, 1965, 1979, 1987, 2006, 2016, 2031, 2067, 2098, 2131, 2160, 2172, 2192, 2216, 2240, 2261, 2285, 2304, 2327, 2353, 2374, 2392, 2419, 2446, 2467, 2488, 2512, 2537, 2565, 2593, 2609, 2620, 2632, 2649, 2664, 2682, 2711, 2728, 2744, 2760, 2778, 2796, 2819, 2840, 2850, 2861, 2875, 2886, 2902, 2925, 2942, 2970, 2989, 3009, 3026, 3044, 3061, 3075, 3110, 3129, 3140, 3153, 3168, 3184, 3202, 3219, 3239, 3260, 3281, 3300, 3319, 3337, 3361, 3385, 3406, 3420, 3444, 3473, 3491, 3508, 3530, 3547, 3565, 3585, 3611, 3627, 3646, 3667, 3671, 3689, 3706, 3732, 3746, 3770, 3791, 3806, 3824, 3847, 3862, 3881, 3898, 3915, 3939, 3966, 3989, 4012, 4029, 4051, 4067, 4087, 4106, 4128, 4149, 4169, 4191, 4215, 4234, 4276, 4297, 4320, 4341, 4372, 4391, 4413, 4433, 4459, 4480, 4502, 4522, 4546, 4569, 4588, 4608, 4630, 4653, 4684, 4722, 4763, 4793, 4807, 4828, 4844, 4866, 4896, 4922, 4950, 4983, 5001, 5024, 5059, 5099, 5141, 5173, 5190, 5215, 5230, 5247, 5257, 5268, 5306, 5360, 5406, 5458, 5506, 5549, 5593, 5621, 5635, 5653, 5689, 5712, 5735, 5757, 5780, 5798, 5825, 5857} +var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 142, 154, 176, 196, 222, 236, 257, 274, 289, 312, 329, 347, 364, 388, 403, 424, 442, 454, 474, 491, 514, 535, 547, 565, 586, 614, 635, 658, 684, 721, 751, 784, 809, 841, 871, 900, 925, 947, 973, 995, 1023, 1052, 1086, 1117, 1154, 1184, 1214, 1223, 1235, 1251, 1264, 1278, 1296, 1316, 1337, 1353, 1364, 1380, 1408, 1428, 1444, 1472, 1486, 1503, 1518, 1531, 1545, 1558, 1571, 1587, 1604, 1625, 1639, 1660, 1673, 1695, 1718, 1743, 1759, 1774, 1789, 1810, 1828, 1843, 1860, 1885, 1903, 1926, 1941, 1960, 1976, 1995, 2009, 2017, 2036, 2046, 2061, 2097, 2128, 2161, 2190, 2202, 2222, 2246, 2270, 2291, 2315, 2334, 2357, 2383, 2404, 2422, 2449, 2476, 2497, 2518, 2542, 2567, 2595, 2623, 2639, 2650, 2662, 2679, 2694, 2712, 2741, 2758, 2774, 2790, 2808, 2826, 2849, 2870, 2880, 2891, 2905, 2916, 2932, 2955, 2972, 3000, 3019, 3039, 3056, 3074, 3091, 3105, 3140, 3159, 3170, 3183, 3198, 3214, 3232, 3249, 3269, 3290, 3311, 3330, 3349, 3367, 3391, 3415, 3436, 3450, 3474, 3503, 3521, 3538, 3560, 3577, 3595, 3615, 3641, 3657, 3676, 3697, 3701, 3719, 3736, 3762, 3776, 3800, 3821, 3836, 3854, 3877, 3892, 3911, 3928, 3945, 3969, 3996, 4019, 4042, 4059, 4081, 4097, 4117, 4136, 4158, 4179, 4199, 4221, 4245, 4264, 4306, 4327, 4350, 4371, 4402, 4421, 4443, 4463, 4489, 4510, 4532, 4552, 4576, 4599, 4618, 4638, 4660, 4683, 4714, 4752, 4793, 4823, 4837, 4858, 4874, 4896, 4926, 4952, 4980, 5013, 5031, 5054, 5089, 5129, 5171, 5203, 5220, 5245, 5260, 5277, 5287, 5298, 5336, 5390, 5436, 5488, 5536, 5579, 5623, 5651, 5665, 5683, 5719, 5742, 5765, 5787, 5810, 5828, 5855, 5887} func (i APIErrorCode) String() string { if i < 0 || i >= APIErrorCode(len(_APIErrorCode_index)-1) { diff --git a/cmd/bucket-replication.go b/cmd/bucket-replication.go index eeda5dd91..bc4b9f4b7 100644 --- a/cmd/bucket-replication.go +++ b/cmd/bucket-replication.go @@ -733,18 +733,6 @@ func replicateObject(ctx context.Context, ri ReplicateObjectInfo, objectAPI Obje logger.LogIf(ctx, fmt.Errorf("Unable to replicate metadata for object %s/%s(%s): %s", bucket, objInfo.Name, objInfo.VersionID, err)) } } else { - target, err := globalBucketMetadataSys.GetBucketTarget(bucket, cfg.RoleArn) - if err != nil { - logger.LogIf(ctx, fmt.Errorf("failed to get target for replication bucket:%s cfg:%s err:%s", bucket, cfg.RoleArn, err)) - sendEvent(eventArgs{ - EventName: event.ObjectReplicationNotTracked, - BucketName: bucket, - Object: objInfo, - Host: "Internal: [Replication]", - }) - return - } - putOpts, err := putReplicationOpts(ctx, dest, objInfo) if err != nil { logger.LogIf(ctx, fmt.Errorf("failed to get target for replication bucket:%s cfg:%s err:%w", bucket, cfg.RoleArn, err)) @@ -756,28 +744,18 @@ func replicateObject(ctx context.Context, ri ReplicateObjectInfo, objectAPI Obje }) return } - - // Setup bandwidth throttling - peers, _ := globalEndpoints.peers() - totalNodesCount := len(peers) - if totalNodesCount == 0 { - totalNodesCount = 1 // For standalone erasure coding - } - var headerSize int for k, v := range putOpts.Header() { headerSize += len(k) + len(v) } opts := &bandwidth.MonitorReaderOptions{ - Bucket: objInfo.Bucket, - Object: objInfo.Name, - HeaderSize: headerSize, - BandwidthBytesPerSec: target.BandwidthLimit / int64(totalNodesCount), - ClusterBandwidth: target.BandwidthLimit, + Bucket: objInfo.Bucket, + HeaderSize: headerSize, } - - r := bandwidth.NewMonitoredReader(ctx, globalBucketMonitor, gr, opts) + newCtx, cancel := context.WithTimeout(ctx, globalOperationTimeout.Timeout()) + defer cancel() + r := bandwidth.NewMonitoredReader(newCtx, globalBucketMonitor, gr, opts) if _, err = c.PutObject(ctx, dest.Bucket, object, r, size, "", "", putOpts); err != nil { replicationStatus = replication.Failed logger.LogIf(ctx, fmt.Errorf("Unable to replicate for object %s/%s(%s): %s", bucket, objInfo.Name, objInfo.VersionID, err)) diff --git a/cmd/bucket-targets.go b/cmd/bucket-targets.go index f06fc62be..8d4bc9307 100644 --- a/cmd/bucket-targets.go +++ b/cmd/bucket-targets.go @@ -131,9 +131,6 @@ func (sys *BucketTargetSys) SetTarget(ctx context.Context, bucket string, tgt *m if vcfg.Status != string(versioning.Enabled) { return BucketRemoteTargetNotVersioned{Bucket: tgt.TargetBucket} } - if tgt.ReplicationSync && tgt.BandwidthLimit > 0 { - return NotImplemented{Message: "Synchronous replication does not support bandwidth limits"} - } } sys.Lock() defer sys.Unlock() @@ -159,9 +156,23 @@ func (sys *BucketTargetSys) SetTarget(ctx context.Context, bucket string, tgt *m sys.targetsMap[bucket] = newtgts sys.arnRemotesMap[tgt.Arn] = clnt + sys.updateBandwidthLimit(bucket, tgt.BandwidthLimit) return nil } +func (sys *BucketTargetSys) updateBandwidthLimit(bucket string, limit int64) { + if globalIsGateway { + return + } + if limit == 0 { + globalBucketMonitor.DeleteBucket(bucket) + return + } + // Setup bandwidth throttling + + globalBucketMonitor.SetBandwidthLimit(bucket, limit) +} + // RemoveTarget - removes a remote bucket target for this source bucket. func (sys *BucketTargetSys) RemoveTarget(ctx context.Context, bucket, arnStr string) error { if globalIsGateway { @@ -214,6 +225,7 @@ func (sys *BucketTargetSys) RemoveTarget(ctx context.Context, bucket, arnStr str } sys.targetsMap[bucket] = targets delete(sys.arnRemotesMap, arnStr) + sys.updateBandwidthLimit(bucket, 0) return nil } @@ -278,6 +290,7 @@ func (sys *BucketTargetSys) UpdateAllTargets(bucket string, tgts *madmin.BucketT } } delete(sys.targetsMap, bucket) + sys.updateBandwidthLimit(bucket, 0) return } @@ -290,6 +303,7 @@ func (sys *BucketTargetSys) UpdateAllTargets(bucket string, tgts *madmin.BucketT continue } sys.arnRemotesMap[tgt.Arn] = tgtClient + sys.updateBandwidthLimit(bucket, tgt.BandwidthLimit) } sys.targetsMap[bucket] = tgts.Targets } @@ -315,6 +329,7 @@ func (sys *BucketTargetSys) load(ctx context.Context, buckets []BucketInfo, objA continue } sys.arnRemotesMap[tgt.Arn] = tgtClient + sys.updateBandwidthLimit(bucket.Name, tgt.BandwidthLimit) } sys.targetsMap[bucket.Name] = cfg.Targets } diff --git a/cmd/server-main.go b/cmd/server-main.go index f648d0089..a84fa96d2 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -214,7 +214,7 @@ func newAllSubsystems() { } // Create the bucket bandwidth monitor - globalBucketMonitor = bandwidth.NewMonitor(GlobalServiceDoneCh) + globalBucketMonitor = bandwidth.NewMonitor(GlobalContext, totalNodeCount()) // Create a new config system. globalConfigSys = NewConfigSys() diff --git a/cmd/utils.go b/cmd/utils.go index fda682307..926c73487 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -930,3 +930,13 @@ func loadAndResetRPCNetworkErrsCounter() uint64 { defer rest.ResetNetworkErrsCounter() return rest.GetNetworkErrsCounter() } + +// Helper method to return total number of nodes in cluster +func totalNodeCount() uint64 { + peers, _ := globalEndpoints.peers() + totalNodesCount := uint64(len(peers)) + if totalNodesCount == 0 { + totalNodesCount = 1 // For standalone erasure coding + } + return totalNodesCount +} diff --git a/go.mod b/go.mod index a51429058..2c100a995 100644 --- a/go.mod +++ b/go.mod @@ -82,6 +82,7 @@ require ( go.uber.org/zap v1.16.1-0.20210329175301-c23abee72d19 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b golang.org/x/sys v0.0.0-20210510120138-977fb7262007 + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.1 // indirect google.golang.org/api v0.31.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/internal/bucket/bandwidth/monitor.go b/internal/bucket/bandwidth/monitor.go index e645ac9a8..c4442a004 100644 --- a/internal/bucket/bandwidth/monitor.go +++ b/internal/bucket/bandwidth/monitor.go @@ -23,48 +23,47 @@ import ( "time" "github.com/minio/madmin-go" + "golang.org/x/time/rate" ) -// throttleBandwidth gets the throttle for bucket with the configured value -func (m *Monitor) throttleBandwidth(ctx context.Context, bucket string, bandwidthBytesPerSecond int64, clusterBandwidth int64) *throttle { - m.lock.Lock() - defer m.lock.Unlock() - throttle, ok := m.bucketThrottle[bucket] - if !ok { - throttle = newThrottle(ctx, bandwidthBytesPerSecond, clusterBandwidth) - m.bucketThrottle[bucket] = throttle - return throttle - } - throttle.SetBandwidth(bandwidthBytesPerSecond, clusterBandwidth) - return throttle +type throttle struct { + *rate.Limiter + NodeBandwidthPerSec int64 } -// Monitor implements the monitoring for bandwidth measurements. +// Monitor holds the state of the global bucket monitor type Monitor struct { - lock sync.Mutex // lock for all updates - - activeBuckets map[string]*bucketMeasurement // Buckets with objects in flight - - bucketMovingAvgTicker *time.Ticker // Ticker for calculating moving averages - - bucketThrottle map[string]*throttle - - doneCh <-chan struct{} + tlock sync.RWMutex // mutex for bucketThrottle + bucketThrottle map[string]*throttle + mlock sync.RWMutex // mutex for activeBuckets map + activeBuckets map[string]*bucketMeasurement // Buckets with objects in flight + bucketMovingAvgTicker *time.Ticker // Ticker for calculating moving averages + ctx context.Context // Context for generate + NodeCount uint64 } -// NewMonitor returns a monitor with defaults. -func NewMonitor(doneCh <-chan struct{}) *Monitor { +//NewMonitor returns a monitor with defaults. +func NewMonitor(ctx context.Context, numNodes uint64) *Monitor { m := &Monitor{ activeBuckets: make(map[string]*bucketMeasurement), - bucketMovingAvgTicker: time.NewTicker(2 * time.Second), bucketThrottle: make(map[string]*throttle), - doneCh: doneCh, + bucketMovingAvgTicker: time.NewTicker(2 * time.Second), + ctx: ctx, + NodeCount: numNodes, } go m.trackEWMA() return m } -// SelectionFunction for buckets +func (m *Monitor) updateMeasurement(bucket string, bytes uint64) { + m.mlock.Lock() + defer m.mlock.Unlock() + if m, ok := m.activeBuckets[bucket]; ok { + m.incrementBytes(bytes) + } +} + +//SelectionFunction for buckets type SelectionFunction func(bucket string) bool // SelectBuckets will select all the buckets passed in. @@ -86,8 +85,8 @@ func SelectBuckets(buckets ...string) SelectionFunction { // GetReport gets the report for all bucket bandwidth details. func (m *Monitor) GetReport(selectBucket SelectionFunction) *madmin.BucketBandwidthReport { - m.lock.Lock() - defer m.lock.Unlock() + m.mlock.RLock() + defer m.mlock.RUnlock() return m.getReport(selectBucket) } @@ -99,29 +98,38 @@ func (m *Monitor) getReport(selectBucket SelectionFunction) *madmin.BucketBandwi if !selectBucket(bucket) { continue } + m.tlock.RLock() bucketThrottle, ok := m.bucketThrottle[bucket] - if !ok { - continue - } - report.BucketStats[bucket] = madmin.BandwidthDetails{ - LimitInBytesPerSecond: bucketThrottle.clusterBandwidth, - CurrentBandwidthInBytesPerSecond: bucketMeasurement.getExpMovingAvgBytesPerSecond(), + if ok { + report.BucketStats[bucket] = madmin.BandwidthDetails{ + LimitInBytesPerSecond: bucketThrottle.NodeBandwidthPerSec * int64(m.NodeCount), + CurrentBandwidthInBytesPerSecond: bucketMeasurement.getExpMovingAvgBytesPerSecond(), + } } + m.tlock.RUnlock() + } return report } - func (m *Monitor) trackEWMA() { for { select { case <-m.bucketMovingAvgTicker.C: m.updateMovingAvg() - case <-m.doneCh: + case <-m.ctx.Done(): return } } } +func (m *Monitor) updateMovingAvg() { + m.mlock.Lock() + defer m.mlock.Unlock() + for _, bucketMeasurement := range m.activeBuckets { + bucketMeasurement.updateExponentialMovingAverage(time.Now()) + } +} + func (m *Monitor) getBucketMeasurement(bucket string, initTime time.Time) *bucketMeasurement { bucketTracker, ok := m.activeBuckets[bucket] if !ok { @@ -131,25 +139,43 @@ func (m *Monitor) getBucketMeasurement(bucket string, initTime time.Time) *bucke return bucketTracker } -func (m *Monitor) updateMovingAvg() { - m.lock.Lock() - defer m.lock.Unlock() - for _, bucketMeasurement := range m.activeBuckets { - bucketMeasurement.updateExponentialMovingAverage(time.Now()) - } -} - -// track returns the measurement object for bucket and object -func (m *Monitor) track(bucket string, object string) *bucketMeasurement { - m.lock.Lock() - defer m.lock.Unlock() - return m.getBucketMeasurement(bucket, time.Now()) +// track returns the measurement object for bucket +func (m *Monitor) track(bucket string) { + m.mlock.Lock() + defer m.mlock.Unlock() + m.getBucketMeasurement(bucket, time.Now()) } // DeleteBucket deletes monitoring the 'bucket' func (m *Monitor) DeleteBucket(bucket string) { - m.lock.Lock() - defer m.lock.Unlock() - delete(m.activeBuckets, bucket) + m.tlock.Lock() delete(m.bucketThrottle, bucket) + m.tlock.Unlock() + m.mlock.Lock() + delete(m.activeBuckets, bucket) + m.mlock.Unlock() +} + +// throttle returns currently configured throttle for this bucket +func (m *Monitor) throttle(bucket string) *throttle { + m.tlock.RLock() + defer m.tlock.RUnlock() + return m.bucketThrottle[bucket] +} + +// SetBandwidthLimit sets the bandwidth limit for a bucket +func (m *Monitor) SetBandwidthLimit(bucket string, limit int64) { + m.tlock.Lock() + defer m.tlock.Unlock() + bw := limit / int64(m.NodeCount) + t, ok := m.bucketThrottle[bucket] + if !ok { + t = &throttle{ + NodeBandwidthPerSec: bw, + } + } + t.NodeBandwidthPerSec = bw + newlimit := rate.Every(time.Second / time.Duration(t.NodeBandwidthPerSec)) + t.Limiter = rate.NewLimiter(newlimit, int(t.NodeBandwidthPerSec)) + m.bucketThrottle[bucket] = t } diff --git a/internal/bucket/bandwidth/monitor_test.go b/internal/bucket/bandwidth/monitor_test.go index bd5d58e2d..5a253c4f1 100644 --- a/internal/bucket/bandwidth/monitor_test.go +++ b/internal/bucket/bandwidth/monitor_test.go @@ -18,7 +18,6 @@ package bandwidth import ( - "context" "reflect" "testing" "time" @@ -30,52 +29,6 @@ const ( oneMiB uint64 = 1024 * 1024 ) -func TestMonitor_GetThrottle(t *testing.T) { - type fields struct { - bucketThrottles map[string]*throttle - bucket string - bpi int64 - } - t1 := newThrottle(context.Background(), 100, 1024*1024) - t2 := newThrottle(context.Background(), 200, 1024*1024) - tests := []struct { - name string - fields fields - want *throttle - }{ - { - name: "Existing", - fields: fields{ - bucketThrottles: map[string]*throttle{"bucket": t1}, - bucket: "bucket", - bpi: 100, - }, - want: t1, - }, - { - name: "new", - fields: fields{ - bucketThrottles: map[string]*throttle{"bucket": t1}, - bucket: "bucket2", - bpi: 200, - }, - want: t2, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - m := &Monitor{ - bucketThrottle: tt.fields.bucketThrottles, - } - if got := m.throttleBandwidth(context.Background(), tt.fields.bucket, tt.fields.bpi, 1024*1024); got.bytesPerInterval != tt.want.bytesPerInterval { - t.Errorf("throttleBandwidth() = %v, want %v", got, tt.want) - } - }) - } -} - func TestMonitor_GetReport(t *testing.T) { type fields struct { activeBuckets map[string]*bucketMeasurement @@ -136,12 +89,12 @@ func TestMonitor_GetReport(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() thr := throttle{ - bytesPerSecond: 1024 * 1024, - clusterBandwidth: 1024 * 1024, + NodeBandwidthPerSec: 1024 * 1024, } m := &Monitor{ activeBuckets: tt.fields.activeBuckets, bucketThrottle: map[string]*throttle{"bucket": &thr}, + NodeCount: 1, } m.activeBuckets["bucket"].updateExponentialMovingAverage(tt.fields.endTime) got := m.GetReport(SelectBuckets()) diff --git a/internal/bucket/bandwidth/reader.go b/internal/bucket/bandwidth/reader.go index be9a10362..acc4a2a93 100644 --- a/internal/bucket/bandwidth/reader.go +++ b/internal/bucket/bandwidth/reader.go @@ -20,61 +20,78 @@ package bandwidth import ( "context" "io" + "math" ) -// MonitoredReader monitors the bandwidth +// MonitoredReader represents a throttled reader subject to bandwidth monitoring type MonitoredReader struct { - opts *MonitorReaderOptions - bucketMeasurement *bucketMeasurement // bucket measurement object - reader io.Reader // Reader to wrap - throttle *throttle // throttle the rate at which replication occur - monitor *Monitor // Monitor reference - lastErr error // last error reported, if this non-nil all reads will fail. + r io.Reader + throttle *throttle + ctx context.Context // request context + lastErr error // last error reported, if this non-nil all reads will fail. + m *Monitor + opts *MonitorReaderOptions } // MonitorReaderOptions provides configurable options for monitor reader implementation. type MonitorReaderOptions struct { - Bucket string - Object string - HeaderSize int - BandwidthBytesPerSec int64 - ClusterBandwidth int64 + Bucket string + HeaderSize int } -// NewMonitoredReader returns a io.Reader that reports bandwidth details. -func NewMonitoredReader(ctx context.Context, monitor *Monitor, reader io.Reader, opts *MonitorReaderOptions) *MonitoredReader { - return &MonitoredReader{ - opts: opts, - bucketMeasurement: monitor.track(opts.Bucket, opts.Object), - reader: reader, - throttle: monitor.throttleBandwidth(ctx, opts.Bucket, opts.BandwidthBytesPerSec, opts.ClusterBandwidth), - monitor: monitor, - } -} - -// Read wraps the read reader -func (m *MonitoredReader) Read(p []byte) (n int, err error) { - if m.lastErr != nil { - err = m.lastErr +// Read implements a throttled read +func (r *MonitoredReader) Read(buf []byte) (n int, err error) { + if r.lastErr != nil { + err = r.lastErr return } - p = p[:m.throttle.GetLimitForBytes(int64(len(p)))] + b := r.throttle.Burst() // maximum available tokens + need := len(buf) // number of bytes requested by caller + hdr := r.opts.HeaderSize // remaining header bytes + var tokens int // number of tokens to request - n, err = m.reader.Read(p) + if hdr > 0 { // available tokens go towards header first + if hdr < b { // all of header can be accommodated + r.opts.HeaderSize = 0 + need = int(math.Min(float64(b-hdr), float64(need))) // use remaining tokens towards payload + tokens = need + hdr + + } else { // part of header can be accommodated + r.opts.HeaderSize -= b - 1 + need = 1 // to ensure we read at least one byte for every Read + tokens = b + } + + } else { // all tokens go towards payload + need = int(math.Min(float64(b), float64(need))) + tokens = need + } + + err = r.throttle.WaitN(r.ctx, tokens) if err != nil { - m.lastErr = err + return } - update := n + m.opts.HeaderSize - unused := len(p) - update - - m.bucketMeasurement.incrementBytes(uint64(update)) - m.opts.HeaderSize = 0 // Set to 0 post first read - - if unused > 0 { - m.throttle.ReleaseUnusedBandwidth(int64(unused)) + n, err = r.r.Read(buf[:need]) + if err != nil { + r.lastErr = err + return } - + r.m.updateMeasurement(r.opts.Bucket, uint64(tokens)) return } + +// NewMonitoredReader returns reference to a monitored reader that throttles reads to configured bandwidth for the +// bucket. +func NewMonitoredReader(ctx context.Context, m *Monitor, r io.Reader, opts *MonitorReaderOptions) *MonitoredReader { + reader := MonitoredReader{ + r: r, + throttle: m.throttle(opts.Bucket), + m: m, + opts: opts, + ctx: ctx, + } + reader.m.track(opts.Bucket) + return &reader +} diff --git a/internal/bucket/bandwidth/throttle.go b/internal/bucket/bandwidth/throttle.go deleted file mode 100644 index 2981e8d67..000000000 --- a/internal/bucket/bandwidth/throttle.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2015-2021 MinIO, Inc. -// -// This file is part of MinIO Object Storage stack -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package bandwidth - -import ( - "context" - "sync" - "sync/atomic" - "time" -) - -const ( - throttleInternal = 250 * time.Millisecond -) - -// throttle implements the throttling for bandwidth -type throttle struct { - generateTicker *time.Ticker // Ticker to generate available bandwidth - freeBytes int64 // unused bytes in the interval - bytesPerSecond int64 // max limit for bandwidth - bytesPerInterval int64 // bytes allocated for the interval - clusterBandwidth int64 // Cluster wide bandwidth needed for reporting - cond *sync.Cond // Used to notify waiting threads for bandwidth availability - goGenerate int64 // Flag to track if generate routine should be running. 0 == stopped - ctx context.Context // Context for generate -} - -// newThrottle returns a new bandwidth throttle. Set bytesPerSecond to 0 for no limit -func newThrottle(ctx context.Context, bytesPerSecond int64, clusterBandwidth int64) *throttle { - if bytesPerSecond == 0 { - return &throttle{} - } - t := &throttle{ - bytesPerSecond: bytesPerSecond, - generateTicker: time.NewTicker(throttleInternal), - clusterBandwidth: clusterBandwidth, - ctx: ctx, - } - - t.cond = sync.NewCond(&sync.Mutex{}) - t.SetBandwidth(bytesPerSecond, clusterBandwidth) - t.freeBytes = t.bytesPerInterval - return t -} - -// GetLimitForBytes gets the bytes that are possible to send within the limit -// if want is <= 0 or no bandwidth limit set, returns want. -// Otherwise a value > 0 will always be returned. -func (t *throttle) GetLimitForBytes(want int64) int64 { - if want <= 0 || atomic.LoadInt64(&t.bytesPerInterval) == 0 { - return want - } - t.cond.L.Lock() - defer t.cond.L.Unlock() - for { - var send int64 - freeBytes := atomic.LoadInt64(&t.freeBytes) - send = want - if freeBytes < want { - send = freeBytes - if send <= 0 { - t.cond.Wait() - continue - } - } - atomic.AddInt64(&t.freeBytes, -send) - - // Bandwidth was consumed, start generate routine to allocate bandwidth - if atomic.CompareAndSwapInt64(&t.goGenerate, 0, 1) { - go t.generateBandwidth(t.ctx) - } - return send - } -} - -// SetBandwidth sets a new bandwidth limit in bytes per second. -func (t *throttle) SetBandwidth(bandwidthBiPS int64, clusterBandwidth int64) { - bpi := int64(throttleInternal) * bandwidthBiPS / int64(time.Second) - atomic.StoreInt64(&t.bytesPerInterval, bpi) -} - -// ReleaseUnusedBandwidth releases bandwidth that was allocated for a user -func (t *throttle) ReleaseUnusedBandwidth(bytes int64) { - atomic.AddInt64(&t.freeBytes, bytes) -} - -// generateBandwidth periodically allocates new bandwidth to use -func (t *throttle) generateBandwidth(ctx context.Context) { - for { - select { - case <-t.generateTicker.C: - if atomic.LoadInt64(&t.freeBytes) == atomic.LoadInt64(&t.bytesPerInterval) { - // No bandwidth consumption stop the routine. - atomic.StoreInt64(&t.goGenerate, 0) - return - } - // A new window is available - t.cond.L.Lock() - atomic.StoreInt64(&t.freeBytes, atomic.LoadInt64(&t.bytesPerInterval)) - t.cond.Broadcast() - t.cond.L.Unlock() - case <-ctx.Done(): - return - } - } -}