diff --git a/browser/app/js/browser/ChangePasswordModal.js b/browser/app/js/browser/ChangePasswordModal.js index af95f4ccc..850a54e43 100644 --- a/browser/app/js/browser/ChangePasswordModal.js +++ b/browser/app/js/browser/ChangePasswordModal.js @@ -88,11 +88,6 @@ export class ChangePasswordModal extends React.Component { canChangePassword() { const { serverInfo } = this.props - // Password change is not allowed in WORM mode - if (serverInfo.info.isWorm) { - return false - } - // Password change is not allowed for temporary users(STS) if(serverInfo.userInfo.isTempUser) { return false diff --git a/browser/app/js/browser/__tests__/ChangePasswordModal.test.js b/browser/app/js/browser/__tests__/ChangePasswordModal.test.js index a5e53c9b6..ba9489497 100644 --- a/browser/app/js/browser/__tests__/ChangePasswordModal.test.js +++ b/browser/app/js/browser/__tests__/ChangePasswordModal.test.js @@ -64,17 +64,6 @@ describe("ChangePasswordModal", () => { shallow() }) - it("should not allow changing password when isWorm is true", () => { - const newServerInfo = { ...serverInfo, info: { isWorm: true } } - const wrapper = shallow() - expect( - wrapper - .find("ModalBody") - .childAt(0) - .text() - ).toBe("Credentials of this user cannot be updated through MinIO Browser.") - }) - it("should not allow changing password when not IAM user", () => { const newServerInfo = { ...serverInfo, diff --git a/cmd/admin-handlers-config-kv.go b/cmd/admin-handlers-config-kv.go index 2bdc6e8f7..56845c072 100644 --- a/cmd/admin-handlers-config-kv.go +++ b/cmd/admin-handlers-config-kv.go @@ -66,12 +66,6 @@ func (a adminAPIHandlers) DelConfigKVHandler(w http.ResponseWriter, r *http.Requ return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) @@ -112,12 +106,6 @@ func (a adminAPIHandlers) SetConfigKVHandler(w http.ResponseWriter, r *http.Requ return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) @@ -358,12 +346,6 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { // More than maxConfigSize bytes were available writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) diff --git a/cmd/admin-handlers-users.go b/cmd/admin-handlers-users.go index 691e337f3..256251a7d 100644 --- a/cmd/admin-handlers-users.go +++ b/cmd/admin-handlers-users.go @@ -60,12 +60,6 @@ func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) { return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - vars := mux.Vars(r) accessKey := vars["accessKey"] @@ -290,12 +284,6 @@ func (a adminAPIHandlers) SetUserStatus(w http.ResponseWriter, r *http.Request) return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - vars := mux.Vars(r) accessKey := vars["accessKey"] status := vars["status"] @@ -329,12 +317,6 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - vars := mux.Vars(r) accessKey := vars["accessKey"] @@ -415,12 +397,6 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - newCred, err := globalIAMSys.NewServiceAccount(ctx, cred.AccessKey, createReq.Policy) if err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) @@ -528,12 +504,6 @@ func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Re return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - serviceAccount := mux.Vars(r)["accessKey"] if serviceAccount == "" { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminInvalidArgument), r.URL) @@ -681,12 +651,6 @@ func (a adminAPIHandlers) RemoveCannedPolicy(w http.ResponseWriter, r *http.Requ vars := mux.Vars(r) policyName := vars["name"] - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - if err := globalIAMSys.DeletePolicy(policyName); err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) return @@ -713,12 +677,6 @@ func (a adminAPIHandlers) AddCannedPolicy(w http.ResponseWriter, r *http.Request vars := mux.Vars(r) policyName := vars["name"] - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - // Error out if Content-Length is missing. if r.ContentLength <= 0 { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMissingContentLength), r.URL) @@ -771,12 +729,6 @@ func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http entityName := vars["userOrGroup"] isGroup := vars["isGroup"] == "true" - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - if !isGroup { ok, err := globalIAMSys.IsTempUser(entityName) if err != nil && err != errNoSuchUser { diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 25d75d174..398510190 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -920,7 +920,7 @@ func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http. } } - if _, ok := globalBucketObjectLockConfig.Get(bucket); (ok || globalWORMEnabled) && forceDelete { + if _, ok := globalBucketObjectLockConfig.Get(bucket); ok && forceDelete { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) return } @@ -1021,11 +1021,6 @@ func (api objectAPIHandlers) PutBucketObjectLockConfigHandler(w http.ResponseWri return } - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } if s3Error := checkRequestAuthType(ctx, r, policy.PutBucketObjectLockConfigurationAction, bucket, ""); s3Error != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL, guessIsBrowserReq(r)) return diff --git a/cmd/common-main.go b/cmd/common-main.go index 2e99f30cc..d813e7b37 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -173,7 +173,14 @@ func handleCommonCmdArgs(ctx *cli.Context) { } func handleCommonEnvVars() { - var err error + wormEnabled, err := config.LookupWorm() + if err != nil { + logger.Fatal(config.ErrInvalidWormValue(err), "Invalid worm configuration") + } + if wormEnabled { + logger.Fatal(errors.New("WORM is deprecated"), "global MINIO_WORM support is removed, please downgrade your server or migrate to https://github.com/minio/minio/tree/master/docs/retention") + } + globalBrowserEnabled, err = config.ParseBool(env.Get(config.EnvBrowser, config.EnableOn)) if err != nil { logger.Fatal(config.ErrInvalidBrowserValue(err), "Invalid MINIO_BROWSER value in environment variable") @@ -239,12 +246,6 @@ func handleCommonEnvVars() { os.Unsetenv(config.EnvAccessKeyOld) os.Unsetenv(config.EnvSecretKeyOld) } - - globalWORMEnabled, err = config.LookupWorm() - if err != nil { - logger.Fatal(config.ErrInvalidWormValue(err), "Invalid worm configuration") - } - } func logStartupMessage(msg string) { diff --git a/cmd/daily-lifecycle-ops.go b/cmd/daily-lifecycle-ops.go index eb9cd4548..aec4c7e56 100644 --- a/cmd/daily-lifecycle-ops.go +++ b/cmd/daily-lifecycle-ops.go @@ -51,11 +51,6 @@ func startDailyLifecycle(ctx context.Context, objAPI ObjectLayer) { } func lifecycleRound(ctx context.Context, objAPI ObjectLayer) error { - // No action is expected when WORM is enabled - if globalWORMEnabled { - return nil - } - buckets, err := objAPI.ListBuckets(ctx) if err != nil { return err diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index 6b15424e9..577d0d9cd 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -681,13 +681,6 @@ func (fs *FSObjects) CompleteMultipartUpload(ctx context.Context, bucket string, return oi, toObjectErr(err, bucket, object) } - // Deny if WORM is enabled - if isWORMEnabled(bucket) { - if _, err := fsStatFile(ctx, pathJoin(fs.fsPath, bucket, object)); err == nil { - return ObjectInfo{}, ObjectAlreadyExists{Bucket: bucket, Object: object} - } - } - err = fsRenameFile(ctx, appendFilePath, pathJoin(fs.fsPath, bucket, object)) if err != nil { logger.LogIf(ctx, err) diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index 83521c294..9a43eb68e 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -991,12 +991,6 @@ func (fs *FSObjects) putObject(ctx context.Context, bucket string, object string // Entire object was written to the temp location, now it's safe to rename it to the actual location. fsNSObjPath := pathJoin(fs.fsPath, bucket, object) - // Deny if WORM is enabled - if isWORMEnabled(bucket) { - if _, err := fsStatFile(ctx, fsNSObjPath); err == nil { - return ObjectInfo{}, ObjectAlreadyExists{Bucket: bucket, Object: object} - } - } if err = fsRenameFile(ctx, fsTmpObjPath, fsNSObjPath); err != nil { return ObjectInfo{}, toObjectErr(err, bucket, object) } diff --git a/cmd/globals.go b/cmd/globals.go index d5f169190..914128b85 100644 --- a/cmd/globals.go +++ b/cmd/globals.go @@ -213,9 +213,6 @@ var ( globalOperationTimeout = newDynamicTimeout(10*time.Minute /*30*/, 600*time.Second) // default timeout for general ops globalHealingTimeout = newDynamicTimeout(30*time.Minute /*1*/, 30*time.Minute) // timeout for healing related ops - // Is worm enabled - globalWORMEnabled bool - globalBucketObjectLockConfig = objectlock.NewBucketObjectLockConfig() // Disk cache drives diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index f7bfe13d2..de197fcb6 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -1527,14 +1527,6 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r return } - // Deny if WORM is enabled - if globalWORMEnabled { - if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } - } - // Validate storage class metadata if present if sc := r.Header.Get(xhttp.AmzStorageClass); sc != "" { if !storageclass.IsValid(sc) { @@ -1725,14 +1717,6 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt return } - // Deny if global WORM is enabled - if globalWORMEnabled { - if _, err := objectAPI.GetObjectInfo(ctx, dstBucket, dstObject, dstOpts); err == nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } - } - getObjectNInfo := objectAPI.GetObjectNInfo if api.CacheAPI() != nil { getObjectNInfo = api.CacheAPI().GetObjectNInfo @@ -2105,14 +2089,6 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http rawReader := hashReader pReader := NewPutObjReader(rawReader, nil, nil) - // Deny if WORM is enabled - if globalWORMEnabled { - if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } - } - isEncrypted := false var objectEncryptionKey crypto.ObjectKey if objectAPI.IsEncryptionSupported() && !isCompressed { @@ -2430,19 +2406,6 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite return } - // Deny if global WORM is enabled - if globalWORMEnabled { - opts, err := getOpts(ctx, r, bucket, object) - if err != nil { - writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) - return - } - if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } - } - if _, _, _, s3Err := checkPutObjectLockAllowed(ctx, r, bucket, object, objectAPI.GetObjectInfo, ErrNone, ErrNone); s3Err != ErrNone { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL, guessIsBrowserReq(r)) return @@ -2627,19 +2590,6 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http. } } - // Deny if global WORM is enabled - if globalWORMEnabled { - opts, err := getOpts(ctx, r, bucket, object) - if err != nil { - writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) - return - } - if _, err := objectAPI.GetObjectInfo(ctx, bucket, object, opts); err == nil { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL, guessIsBrowserReq(r)) - return - } - } - apiErr := ErrNone if _, ok := globalBucketObjectLockConfig.Get(bucket); ok { apiErr = enforceRetentionBypassForDelete(ctx, r, bucket, object, getObjectInfo) @@ -2864,11 +2814,6 @@ func (api objectAPIHandlers) PutObjectRetentionHandler(w http.ResponseWriter, r return } - if globalWORMEnabled { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrObjectLocked), r.URL, guessIsBrowserReq(r)) - return - } - if _, ok := globalBucketObjectLockConfig.Get(bucket); !ok { writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidBucketObjectLockConfiguration), r.URL, guessIsBrowserReq(r)) return diff --git a/cmd/object-lock.go b/cmd/object-lock.go index 917d8bef0..cd0046f2a 100644 --- a/cmd/object-lock.go +++ b/cmd/object-lock.go @@ -314,7 +314,7 @@ func checkPutObjectLockAllowed(ctx context.Context, r *http.Request, bucket, obj if objInfo, err := getObjectInfoFn(ctx, bucket, object, opts); err == nil { objExists = true r := objectlock.GetObjectRetentionMeta(objInfo.UserDefined) - if globalWORMEnabled || ((r.Mode == objectlock.RetCompliance) && r.RetainUntilDate.After(t)) { + if r.Mode == objectlock.RetCompliance && r.RetainUntilDate.After(t) { return mode, retainDate, legalHold, ErrObjectLocked } mode = r.Mode diff --git a/cmd/utils.go b/cmd/utils.go index 5fa08a3f0..327ff7391 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -652,10 +652,3 @@ func iamPolicyClaimNameOpenID() string { func iamPolicyClaimNameSA() string { return "sa-policy" } - -func isWORMEnabled(bucket string) bool { - if isMinioMetaBucketName(bucket) { - return false - } - return globalWORMEnabled -} diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 2a68cf75e..6d449c789 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -745,17 +745,6 @@ next: } apiErr := ErrNone - // Deny if global WORM is enabled - if globalWORMEnabled { - opts, err := getOpts(ctx, r, args.BucketName, objectName) - if err != nil { - apiErr = toAPIErrorCode(ctx, err) - } else { - if _, err := getObjectInfo(ctx, args.BucketName, objectName, opts); err == nil { - apiErr = ErrMethodNotAllowed - } - } - } if _, ok := globalBucketObjectLockConfig.Get(args.BucketName); ok && (apiErr == ErrNone) { apiErr = enforceRetentionBypassForDeleteWeb(ctx, r, args.BucketName, objectName, getObjectInfo) if apiErr != ErrNone && apiErr != ErrNoSuchKey { @@ -909,11 +898,6 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se return toJSONError(ctx, authErr) } - // When WORM is enabled, disallow changing credenatials for owner and user - if globalWORMEnabled { - return toJSONError(ctx, errChangeCredNotAllowed) - } - if owner { // Owner is not allowed to change credentials through browser. return toJSONError(ctx, errChangeCredNotAllowed) diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index 057d6f97f..7fb5ce4b4 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -673,13 +673,6 @@ func (xl xlObjects) CompleteMultipartUpload(ctx context.Context, bucket string, } if xl.isObject(bucket, object) { - // Deny if WORM is enabled - if isWORMEnabled(bucket) { - if _, err := xl.getObjectInfo(ctx, bucket, object, ObjectOptions{}); err == nil { - return ObjectInfo{}, ObjectAlreadyExists{Bucket: bucket, Object: object} - } - } - // Rename if an object already exists to temporary location. newUniqueID := mustGetUUID() diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index 8c3fd5587..526aa730a 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -628,13 +628,6 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, } if xl.isObject(bucket, object) { - // Deny if WORM is enabled - if isWORMEnabled(bucket) { - if _, err := xl.getObjectInfo(ctx, bucket, object, ObjectOptions{}); err == nil { - return ObjectInfo{}, ObjectAlreadyExists{Bucket: bucket, Object: object} - } - } - // Rename if an object already exists to temporary location. newUniqueID := mustGetUUID() diff --git a/docs/config/README.md b/docs/config/README.md index 3832739e3..973c5b26f 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -257,7 +257,7 @@ This behavior is consistent across all keys, each key self documents itself with ## Environment only settings (not in config) #### Usage crawler -Data usage crawler is enabled by default, following ENVs allow for more staggered delay in terms of usage calculation. +Data usage crawler is enabled by default, following ENVs allow for more staggered delay in terms of usage calculation. The crawler adapts to the system speed and completely pauses when the system is under load. It is possible to adjust the speed of the crawler and thereby the latency of updates being reflected. The delays between each operation of the crawl can be adjusted by the `MINIO_DISK_USAGE_CRAWL_DELAY` environment variable. By default the value is `10`. This means the crawler will sleep *10x* the time each operation takes. @@ -270,16 +270,6 @@ export MINIO_DISK_USAGE_CRAWL_DELAY=30 minio server /data ``` -#### Worm (deprecated) -Enable this to turn on Write-Once-Read-Many. By default it is set to `off`. Set ``MINIO_WORM=on`` environment variable to enable WORM mode. This ENV setting is not recommended anymore, please use Object Locking and Object Retention APIs documented [here](https://github.com/minio/minio/tree/master/docs/retention). - -Example: - -```sh -export MINIO_WORM=on -minio server /data -``` - ### Browser Enable or disable access to web UI. By default it is set to `on`. You may override this field with `MINIO_BROWSER` environment variable. diff --git a/docs/retention/README.md b/docs/retention/README.md index eadbd9bb4..b5a3e9d06 100644 --- a/docs/retention/README.md +++ b/docs/retention/README.md @@ -2,11 +2,9 @@ MinIO server allows selectively specify WORM for specific objects or configuring a bucket with default object lock configuration that applies default retention mode and retention duration to all incoming objects. Essentially, this makes objects in the bucket immutable i.e. delete and overwrite are not allowed till stipulated time specified in the bucket's object lock configuration or object retention. -Object locking requires locking to be enabled on a bucket at the time of bucket creation. In addition, a default retention period and retention mode can be configured on a bucket to be -applied to objects created in that bucket. +Object locking requires locking to be enabled on a bucket at the time of bucket creation. In addition, a default retention period and retention mode can be configured on a bucket to be applied to objects created in that bucket. -Independently of retention, an object can also be under legal hold. This effectively disallows -all deletes and overwrites of an object under legal hold until the hold is lifted. +Independently of retention, an object can also be under legal hold. This effectively disallows all deletes and overwrites of an object under legal hold until the hold is lifted. ## Get Started @@ -21,6 +19,7 @@ WORM on a bucket is enabled by setting object lock configuration. This configura ```sh $ awscli s3api put-object-lock-configuration --bucket mybucket --object-lock-configuration 'ObjectLockEnabled=\"Enabled\",Rule={DefaultRetention={Mode=\"GOVERNANCE\",Days=1}}' ``` + ### Set object lock PutObject API allows setting per object retention mode and retention duration using `x-amz-object-lock-mode` and `x-amz-object-lock-retain-until-date` headers. This takes precedence over any bucket object lock configuration w.r.t retention. @@ -29,8 +28,7 @@ PutObject API allows setting per object retention mode and retention duration us aws s3api put-object --bucket testbucket --key lockme --object-lock-mode GOVERNANCE --object-lock-retain-until-date "2019-11-20" --body /etc/issue ``` -See https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html for AWS S3 spec on -object locking and permissions required for object retention and governance bypass overrides. +See https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html for AWS S3 spec on object locking and permissions required for object retention and governance bypass overrides. ### Set legal hold on an object @@ -40,24 +38,14 @@ PutObject API allows setting legal hold using `x-amz-object-lock-legal-hold` hea aws s3api put-object --bucket testbucket --key legalhold --object-lock-legal-hold-status ON --body /etc/issue ``` -See https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html for AWS S3 spec on -object locking and permissions required for specifying legal hold. +See https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html for AWS S3 spec on object locking and permissions required for specifying legal hold. -### 3. Note - -- When global WORM is enabled by `MINIO_WORM` environment variable or `worm` field in configuration file supersedes bucket level WORM and `PUT object lock configuration` REST API is disabled. -- In global WORM mode objects can never be overwritten -- If an object is under legal hold, it cannot be overwritten unless the legal hold is explicitly removed. -- In `Compliance` mode, objects cannot be overwritten or deleted by anyone until retention period -is expired. If user has requisite governance bypass permissions, an object's retention date can -be extended in `Compliance` mode. -- Currently `Governance` mode does not allow overwriting an existing object as versioning is not -available in MinIO. However, if user has requisite `Governance` bypass permissions, an object in `Governance` mode can be overwritten. -- Once object lock configuration is set to a bucket, new objects inherit the retention settings of the bucket object lock configuration (if set) or the retention headers set in the PUT request -or set with PutObjectRetention API call - -- MINIO_NTP_SERVER environment variable can be set to remote NTP server endpoint if system time -is not desired for setting retention dates. +> NOTE: +> - If an object is under legal hold, it cannot be overwritten unless the legal hold is explicitly removed. +> - In `Compliance` mode, objects cannot be overwritten or deleted by anyone until retention period is expired. If user has requisite governance bypass permissions, an object's retention date can be extended in `Compliance` mode. +> - Currently `Governance` mode does not allow overwriting an existing object as versioning is not available in MinIO. However, if user has requisite `Governance` bypass permissions, an object in `Governance` mode can be overwritten. +> - Once object lock configuration is set to a bucket, new objects inherit the retention settings of the bucket object lock configuration (if set) or the retention headers set in the PUT request or set with PutObjectRetention API call +> - *MINIO_NTP_SERVER* environment variable can be set to remote NTP server endpoint if system time is not desired for setting retention dates. ## Explore Further diff --git a/mint/README.md b/mint/README.md index 580080856..4a33eec70 100644 --- a/mint/README.md +++ b/mint/README.md @@ -14,7 +14,6 @@ Mint is a testing framework for Minio object server, available as a docker image - minio-py - minio-dotnet - s3cmd -- worm ## Running Mint @@ -42,7 +41,7 @@ Below environment variables are required to be passed to the docker container. S | `ACCESS_KEY` | Access key of access `SERVER_ENDPOINT` | `Q3AM3UQ867SPQQA43P2F` | | `SECRET_KEY` | Secret Key of access `SERVER_ENDPOINT` | `zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG` | | `ENABLE_HTTPS` | (Optional) Set `1` to indicate to use HTTPS to access `SERVER_ENDPOINT`. Defaults to `0` (HTTP) | `1` | -| `MINT_MODE` | (Optional) Set mode indicating what category of tests to be run by values `core`, `full` or `worm`. Defaults to `core` | `full` | +| `MINT_MODE` | (Optional) Set mode indicating what category of tests to be run by values `core`, `full`. Defaults to `core` | `full` | | `DOMAIN` | (Optional) Value of MINIO_DOMAIN environment variable used in Minio server | `myminio.com` | | `ENABLE_VIRTUAL_STYLE` | (Optional) Set `1` to indicate virtual style access . Defaults to `0` (Path style) | `1` | @@ -87,22 +86,19 @@ $ docker run -e SERVER_ENDPOINT=play.minio.io:9000 -e ACCESS_KEY=Q3AM3UQ867SPQQA -e SECRET_KEY=zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG \ -e ENABLE_HTTPS=1 -e MINT_MODE=full minio/mint:latest ``` -In case of Worm Mode, start your server with configuration `MINT_MODE` set to `worm`. -Build/Run of local docker image for Worm mode, is to be tested against your server configuration, by -``` + ### Adding tests with new tool/SDK Below are the steps need to be followed -* Create new app directory under [build](https://github.com/minio/mint/tree/master/build) and [run/core](https://github.com/minio/mint/tree/master/run/core) directories. -* Create `install.sh` which does installation of required tool/SDK under app directory. -* Any build and install time dependencies should be added to [install-packages.list](https://github.com/minio/mint/blob/master/install-packages.list). -* Build time dependencies should be added to [remove-packages.list](https://github.com/minio/mint/blob/master/remove-packages.list) for removal to have clean Mint docker image. -* Add `run.sh` in app directory under `run/core` which execute actual tests. +- Create new app directory under [build](https://github.com/minio/mint/tree/master/build) and [run/core](https://github.com/minio/mint/tree/master/run/core) directories. +- Create `install.sh` which does installation of required tool/SDK under app directory. +- Any build and install time dependencies should be added to [install-packages.list](https://github.com/minio/mint/blob/master/install-packages.list). +- Build time dependencies should be added to [remove-packages.list](https://github.com/minio/mint/blob/master/remove-packages.list) for removal to have clean Mint docker image. +- Add `run.sh` in app directory under `run/core` which execute actual tests. #### Test data - Tests may use pre-created data set to perform various object operations on Minio server. Below data files are available under `/mint/data` directory. | File name | Size | diff --git a/mint/build/worm/install.sh b/mint/build/worm/install.sh deleted file mode 100755 index 5da4aa742..000000000 --- a/mint/build/worm/install.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -e -# -# Mint (C) 2017-2019 Minio, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -test_run_dir="$MINT_RUN_CORE_DIR/worm" -GO111MODULE=on CGO_ENABLED=0 go build -o "$test_run_dir/worm" "$test_run_dir/quick-worm-tests.go" diff --git a/mint/mint.sh b/mint/mint.sh index 15d5684a3..56d44b1cf 100755 --- a/mint/mint.sh +++ b/mint/mint.sh @@ -154,31 +154,16 @@ function main() [ "$ENABLE_HTTPS" == "1" ] && trust_s3_endpoint_tls_cert declare -a run_list - if [ "$MINT_MODE" == "worm" ]; then - if [ "$#" -gt 1 ]; then - echo "No argument is accepted for worm mode" - exit 1 - fi + sdks=( "$@" ) - run_list=( "$TESTS_DIR/worm" ) - else - sdks=( "$@" ) - - ## populate all sdks except worm when no argument is given. - if [ "$#" -eq 0 ]; then - sdks=( $(ls -I worm "$TESTS_DIR") ) - fi - - for sdk in "${sdks[@]}"; do - if [ "$sdk" == "worm" ]; then - echo "worm test cannot be run without worm mode" - exit 1 - fi - - run_list=( "${run_list[@]}" "$TESTS_DIR/$sdk" ) - done + if [ "$#" -eq 0 ]; then + sdks=( $(ls "$TESTS_DIR") ) fi + for sdk in "${sdks[@]}"; do + run_list=( "${run_list[@]}" "$TESTS_DIR/$sdk" ) + done + count="${#run_list[@]}" i=0 for sdk_dir in "${run_list[@]}"; do diff --git a/mint/run/core/worm/quick-worm-tests.go b/mint/run/core/worm/quick-worm-tests.go deleted file mode 100644 index 0574b87e4..000000000 --- a/mint/run/core/worm/quick-worm-tests.go +++ /dev/null @@ -1,409 +0,0 @@ -/* -* Mint, (C) 2018 Minio, Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software - -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* - */ - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "math/rand" - "net/http" - "os" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - log "github.com/sirupsen/logrus" -) - -const charset = "abcdefghijklmnopqrstuvwxyz0123456789" - -var randSource *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) - -const ( - letterIdxBits = 6 // 6 bits to represent a letter index - letterIdxMask = 1< " - exit 1 -fi - -output_log_file="$1" -error_log_file="$2" - -# run tests -/mint/run/core/worm/worm 1>>"$output_log_file" 2>"$error_log_file"