Compare commits

...

16 Commits

Author SHA1 Message Date
Shubhendu 19387cafab Use +Inf label additionally for Histogram metrics (#18807) 2024-01-18 14:51:28 -08:00
Harshavardhana 7c0673279b capture I/O in waiting and total tokens in diskMetrics (#18819)
This is needed for the subsequent changes
in ServerUpdate(), ServerRestart() etc.
2024-01-18 11:17:43 -08:00
Anis Eleuch 7ce0d71a96 Do not log volume not empty when healing dangling buckets (#18822)
Healing dangling buckets is conservative, and it is a typical use case to
fail to remove a dangling bucket because it contains some data because
healing danging bucket code is not allowed to remove data: only healing
the dangling object is allowed to do so.
2024-01-18 10:39:27 -08:00
Harshavardhana dd2542e96c add codespell action (#18818)
Original work here, #18474,  refixed and updated.
2024-01-17 23:03:17 -08:00
Harshavardhana 21d60eab7c remove all older unused APIs (#18769) 2024-01-17 20:41:23 -08:00
Frank Wessels 4d2320ba8b fix: a small typo in dsync (#18816) 2024-01-17 20:34:26 -08:00
Harshavardhana a4a74e9844 re-init the worker group to ensure errs[] slice is fresh 2024-01-17 20:33:25 -08:00
Harshavardhana 9588978028 fix: HealBucket regression for empty buckets, simplify it (#18815) 2024-01-17 15:19:09 -08:00
Klaus Post 479940b7d0 Deallocate huge read buffers (#18813)
If a message buffer is excessively huge, release it back so it isn't kept around forever.
2024-01-17 11:47:42 -08:00
chienguo 8cd967803c fix: a typo in storeDataUsageInBackend() comment (#18778) 2024-01-16 15:48:54 -08:00
Harshavardhana a0e1163fb6 reject reference format from a different deployment (#18800)
reference format is constant for any lifetime of
a minio cluster, we do not have to ever replace
it during HealFormat() as it will never change.

additionally we should simply reject reference
formats that we do not understand early on.
2024-01-16 15:13:14 -08:00
Minio Trusted 8ccd1ee34a Update yaml files to latest version RELEASE.2024-01-16T16-07-38Z 2024-01-16 16:33:40 +00:00
Klaus Post ca258c04cb xl-meta: Clean output (#18794)
* Sort files.
* Sort maps.
* Remove annoying stray ','
* Hide -ndjson - doesn't do what it claims.

Sample output:

```
{
	"/tmp/xl1/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":0,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":5,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl10/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":14,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl11/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":0,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":15,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl12/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":16,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl13/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":1,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl14/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":2,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl15/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":3,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl16/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":4,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl2/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":6,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl3/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":7,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl4/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":8,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl5/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":9,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl6/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":10,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl7/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":11,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl8/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":12,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]},
	"/tmp/xl9/testbucket/hosts/xl.meta": {"Versions":[{"Header":{"Flags":0,"ModTime":"2022-03-27T07:40:36.271878663+02:00","Signature":"4ffe317b","Type":2,"VersionID":"afc0611a63e0403b8078bf21b9111a2b"},"Idx":0,"Metadata":{"DelObj":{"ID":"r8BhGmPgQDuAeL8huREaKw==","MTime":1648359636271878700,"MetaSys":{}},"Type":2}},{"Header":{"Flags":6,"ModTime":"2022-03-27T07:35:22.820280431+02:00","Signature":"ac150d34","Type":1,"VersionID":"12468eb5e6024ab581de7aa9a5220a4e"},"Idx":1,"Metadata":{"Type":1,"V2Obj":{"CSumAlgo":1,"DDir":"DvH10ieUSPmBLbKfCp3lVQ==","EcAlgo":1,"EcBSize":1048576,"EcDist":[5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4],"EcIndex":13,"EcM":12,"EcN":4,"ID":"EkaOteYCSrWB3nqppSIKTg==","MTime":1648359322820280300,"MetaSys":{"x-minio-internal-inline-data":"dHJ1ZQ=="},"MetaUsr":{"content-type":"application/octet-stream","etag":"ea210162eeb4adc31ff984cb744d6af6"},"PartASizes":[303],"PartETags":null,"PartNums":[1],"PartSizes":[303],"Size":303}}}]}
}
```
2024-01-16 08:07:38 -08:00
Sveinn 30bd5e2669 adding a missing return case to fix GetObjectTagging (#18793) 2024-01-15 16:11:06 -08:00
Harshavardhana 38637897ba fix: listing SSE encrypted multipart objects (#18786)
GetActualSize() was heavily relying on o.Parts()
to be non-empty to figure out if the object is multipart or not, 
However, we have many indicators of whether an object is multipart 
or not.

Blindly assuming that o.Parts == nil is not a multipart, is an 
incorrect expectation instead, multipart must be obtained via

- Stored metadata value indicating this is a multipart encrypted object.

- Rely on <meta>-actual-size metadata to get the object's actual size.
  This value is preserved for additional reasons such as these.

- ETag != 32 length
2024-01-15 00:57:49 -08:00
Minio Trusted c727c8b684 Update yaml files to latest version RELEASE.2024-01-13T07-53-03Z 2024-01-13 09:24:52 +00:00
149 changed files with 582 additions and 708 deletions
+8
View File
@@ -0,0 +1,8 @@
[codespell]
# certs_test.go - has lots of ceritificates.
skip = go.mod,go.sum,*.txt,LICENSE,*.zip,.git,*.pdf,*.svg,.codespellrc,CREDITS,certs_test.go
check-hidden = true
ignore-regex = \b(newfolder/afile|filterIn|HelpES)\b
ignore-words-list = inout,bui,to,bu,te,ot,toi,ist,parms,flate
+20
View File
@@ -0,0 +1,20 @@
---
name: Codespell
on:
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Codespell
uses: codespell-project/actions-codespell@v2
+2 -2
View File
@@ -3054,7 +3054,7 @@ func createHostAnonymizerForFSMode() map[string]string {
// anonymizeHost - Add entries related to given endpoint in the host anonymizer map
// The health report data can contain the hostname in various forms e.g. host, host:port,
// host:port/drivepath, full url (http://host:port/drivepath)
// The anonymizer map will have mappings for all these varients for efficiently replacing
// The anonymizer map will have mappings for all these variants for efficiently replacing
// any of these strings to the anonymized versions at the time of health report generation.
func anonymizeHost(hostAnonymizer map[string]string, endpoint Endpoint, poolNum int, srvrNum int) {
if len(endpoint.Host) == 0 {
@@ -3102,7 +3102,7 @@ func anonymizeHost(hostAnonymizer map[string]string, endpoint Endpoint, poolNum
}
}
// createHostAnonymizer - Creats a map of various strings to corresponding anonymized names
// createHostAnonymizer - Creates a map of various strings to corresponding anonymized names
func createHostAnonymizer() map[string]string {
if !globalIsDistErasure {
return createHostAnonymizerForFSMode()
+1 -1
View File
@@ -959,7 +959,7 @@ var errorCodes = errorCodeMap{
},
ErrReplicationBandwidthLimitError: {
Code: "XMinioAdminReplicationBandwidthLimitError",
Description: "Bandwidth limit for remote target must be atleast 100MBps",
Description: "Bandwidth limit for remote target must be at least 100MBps",
HTTPStatusCode: http.StatusBadRequest,
},
ErrReplicationNoExistingObjects: {
+5 -5
View File
@@ -287,7 +287,7 @@ func mustNewSignedRequest(method string, urlStr string, contentLength int64, bod
req := mustNewRequest(method, urlStr, contentLength, body, t)
cred := globalActiveCred
if err := signRequestV4(req, cred.AccessKey, cred.SecretKey); err != nil {
t.Fatalf("Unable to inititalized new signed http request %s", err)
t.Fatalf("Unable to initialized new signed http request %s", err)
}
return req
}
@@ -298,7 +298,7 @@ func mustNewSignedV2Request(method string, urlStr string, contentLength int64, b
req := mustNewRequest(method, urlStr, contentLength, body, t)
cred := globalActiveCred
if err := signRequestV2(req, cred.AccessKey, cred.SecretKey); err != nil {
t.Fatalf("Unable to inititalized new signed http request %s", err)
t.Fatalf("Unable to initialized new signed http request %s", err)
}
return req
}
@@ -309,7 +309,7 @@ func mustNewPresignedV2Request(method string, urlStr string, contentLength int64
req := mustNewRequest(method, urlStr, contentLength, body, t)
cred := globalActiveCred
if err := preSignV2(req, cred.AccessKey, cred.SecretKey, time.Now().Add(10*time.Minute).Unix()); err != nil {
t.Fatalf("Unable to inititalized new signed http request %s", err)
t.Fatalf("Unable to initialized new signed http request %s", err)
}
return req
}
@@ -320,7 +320,7 @@ func mustNewPresignedRequest(method string, urlStr string, contentLength int64,
req := mustNewRequest(method, urlStr, contentLength, body, t)
cred := globalActiveCred
if err := preSignV4(req, cred.AccessKey, cred.SecretKey, time.Now().Add(10*time.Minute).Unix()); err != nil {
t.Fatalf("Unable to inititalized new signed http request %s", err)
t.Fatalf("Unable to initialized new signed http request %s", err)
}
return req
}
@@ -491,7 +491,7 @@ func TestValidateAdminSignature(t *testing.T) {
for i, testCase := range testCases {
req := mustNewRequest(http.MethodGet, "http://localhost:9000/", 0, nil, t)
if err := signRequestV4(req, testCase.AccessKey, testCase.SecretKey); err != nil {
t.Fatalf("Unable to inititalized new signed http request %s", err)
t.Fatalf("Unable to initialized new signed http request %s", err)
}
_, _, s3Error := validateAdminSignature(ctx, req, globalMinioDefaultRegion)
if s3Error != testCase.ErrCode {
+2 -2
View File
@@ -44,7 +44,7 @@ import (
// bucket: mybucket # Bucket where this batch job will expire matching objects from
// prefix: myprefix # (Optional) Prefix under which this job will expire objects matching the rules below.
// rules:
// - type: object # regular objects with zero ore more older versions
// - type: object # regular objects with zero or more older versions
// name: NAME # match object names that satisfy the wildcard expression.
// olderThan: 70h # match objects older than this value
// createdBefore: "2006-01-02T15:04:05.00Z" # match objects created before "date"
@@ -558,7 +558,7 @@ func (r *BatchJobExpire) Start(ctx context.Context, api ObjectLayer, job BatchJo
logger.LogIf(ctx, ri.updateAfter(ctx, api, 10*time.Second, job))
case <-ctx.Done():
// persist in-memory state immediately before exiting due to context cancelation.
// persist in-memory state immediately before exiting due to context cancellation.
logger.LogIf(ctx, ri.updateAfter(ctx, api, 0, job))
return
+1 -1
View File
@@ -30,7 +30,7 @@ expire: # Expire objects that match a condition
bucket: mybucket # Bucket where this batch job will expire matching objects from
prefix: myprefix # (Optional) Prefix under which this job will expire objects matching the rules below.
rules:
- type: object # regular objects with zero ore more older versions
- type: object # regular objects with zero or more older versions
name: NAME # match object names that satisfy the wildcard expression.
olderThan: 70h # match objects older than this value
createdBefore: "2006-01-02T15:04:05.00Z" # match objects created before "date"
+1 -1
View File
@@ -134,7 +134,7 @@ func (b *streamingBitrotReader) Close() error {
return nil
}
if closer, ok := b.rc.(io.Closer); ok {
// drain the body for connection re-use at network layer.
// drain the body for connection reuse at network layer.
xhttp.DrainBody(struct {
io.Reader
io.Closer
+1 -1
View File
@@ -261,7 +261,7 @@ func verifyServerSystemConfig(ctx context.Context, endpointServerPools EndpointS
retries++
// after 20 retries start logging that servers are not reachable yet
if retries >= 20 {
logger.Info(fmt.Sprintf("Waiting for atleast %d remote servers with valid configuration to be online", len(clnts)/2))
logger.Info(fmt.Sprintf("Waiting for at least %d remote servers with valid configuration to be online", len(clnts)/2))
if len(offlineEndpoints) > 0 {
logger.Info(fmt.Sprintf("Following servers are currently offline or unreachable %s", offlineEndpoints))
}
+1 -1
View File
@@ -424,7 +424,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter,
return
}
// Content-Md5 is requied should be set
// Content-Md5 is required should be set
// http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
if _, ok := r.Header[xhttp.ContentMD5]; !ok {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrMissingContentMD5), r.URL)
+2 -2
View File
@@ -252,7 +252,7 @@ func testHeadBucketHandler(obj ObjectLayer, instanceType, bucketName string, api
},
// Test case - 3.
// Testing for signature mismatch error.
// setting invalid acess and secret key.
// setting invalid access and secret key.
{
bucketName: bucketName,
accessKey: "abcd",
@@ -415,7 +415,7 @@ func testListMultipartUploadsHandler(obj ObjectLayer, instanceType, bucketName s
shouldPass: false,
},
// Test case - 6.
// Setting a negative value to max-uploads paramater, should result in http.StatusBadRequest.
// Setting a negative value to max-uploads parameter, should result in http.StatusBadRequest.
{
bucket: bucketName,
prefix: "",
+4 -4
View File
@@ -111,7 +111,7 @@ func (api objectAPIHandlers) listObjectVersionsHandler(w http.ResponseWriter, r
listObjectVersions := objectAPI.ListObjectVersions
// Inititate a list object versions operation based on the input params.
// Initiate a list object versions operation based on the input params.
// On success would return back ListObjectsInfo object to be
// marshaled into S3 compatible XML header.
listObjectVersionsInfo, err := listObjectVersions(ctx, bucket, prefix, marker, versionIDMarker, delimiter, maxkeys)
@@ -201,10 +201,10 @@ func (api objectAPIHandlers) listObjectsV2Handler(ctx context.Context, w http.Re
)
if r.Header.Get(xMinIOExtract) == "true" && strings.Contains(prefix, archivePattern) {
// Inititate a list objects operation inside a zip file based in the input params
// Initiate a list objects operation inside a zip file based in the input params
listObjectsV2Info, err = listObjectsV2InArchive(ctx, objectAPI, bucket, prefix, token, delimiter, maxKeys, fetchOwner, startAfter)
} else {
// Inititate a list objects operation based on the input params.
// Initiate a list objects operation based on the input params.
// On success would return back ListObjectsInfo object to be
// marshaled into S3 compatible XML header.
listObjectsV2Info, err = objectAPI.ListObjectsV2(ctx, bucket, prefix, token, delimiter, maxKeys, fetchOwner, startAfter)
@@ -304,7 +304,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
listObjects := objectAPI.ListObjects
// Inititate a list objects operation based on the input params.
// Initiate a list objects operation based on the input params.
// On success would return back ListObjectsInfo object to be
// marshaled into S3 compatible XML header.
listObjectsInfo, err := listObjects(ctx, bucket, prefix, marker, delimiter, maxKeys)
+4 -4
View File
@@ -317,7 +317,7 @@ func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string
if err != nil {
t.Fatalf("Test %d: %s: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, instanceType, err)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(recV4, reqV4)
if recV4.Code != testCase.expectedRespStatus {
@@ -331,7 +331,7 @@ func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string
if err != nil {
t.Fatalf("Test %d: %s: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, instanceType, err)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(recV2, reqV2)
if recV2.Code != testCase.expectedRespStatus {
@@ -407,7 +407,7 @@ func testGetBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string
if err != nil {
t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(recV4, reqV4)
if recV4.Code != testPolicy.expectedRespStatus {
@@ -421,7 +421,7 @@ func testGetBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string
if err != nil {
t.Fatalf("Test %d: Failed to create HTTP request for PutBucketPolicyHandler: <ERROR> %v", i+1, err)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(recV2, reqV2)
if recV2.Code != testPolicy.expectedRespStatus {
+3 -3
View File
@@ -219,7 +219,7 @@ type ReplicateDecision struct {
targetsMap map[string]replicateTargetDecision
}
// ReplicateAny returns true if atleast one target qualifies for replication
// ReplicateAny returns true if at least one target qualifies for replication
func (d ReplicateDecision) ReplicateAny() bool {
for _, t := range d.targetsMap {
if t.Replicate {
@@ -229,7 +229,7 @@ func (d ReplicateDecision) ReplicateAny() bool {
return false
}
// Synchronous returns true if atleast one target qualifies for synchronous replication
// Synchronous returns true if at least one target qualifies for synchronous replication
func (d ReplicateDecision) Synchronous() bool {
for _, t := range d.targetsMap {
if t.Synchronous {
@@ -336,7 +336,7 @@ type ReplicationState struct {
DeleteMarker bool // represents DeleteMarker replication state
ReplicationTimeStamp time.Time // timestamp when last replication activity happened
ReplicationStatusInternal string // stringified representation of all replication activity
// VersionPurgeStatusInternal is internally in the format "arn1=PENDING;arn2=COMMPLETED;"
// VersionPurgeStatusInternal is internally in the format "arn1=PENDING;arn2=COMPLETED;"
VersionPurgeStatusInternal string // stringified representation of all version purge statuses
ReplicateDecisionStr string // stringified representation of replication decision for each target
Targets map[string]replication.StatusType // map of ARN->replication status for ongoing replication activity
+2 -2
View File
@@ -495,7 +495,7 @@ func replicateDelete(ctx context.Context, dobj DeletedObjectReplicationInfo, obj
}
tgtClnt := globalBucketTargetSys.GetRemoteTargetClient(bucket, tgtEntry.Arn)
if tgtClnt == nil {
// Skip stale targets if any and log them to be missing atleast once.
// Skip stale targets if any and log them to be missing at least once.
logger.LogOnceIf(ctx, fmt.Errorf("failed to get target for bucket:%s arn:%s", bucket, tgtEntry.Arn), tgtEntry.Arn)
sendEvent(eventArgs{
EventName: event.ObjectReplicationNotTracked,
@@ -2997,7 +2997,7 @@ func (p *ReplicationPool) startResyncRoutine(ctx context.Context, buckets []Buck
}
duration := time.Duration(r.Float64() * float64(time.Minute))
if duration < time.Second {
// Make sure to sleep atleast a second to avoid high CPU ticks.
// Make sure to sleep at least a second to avoid high CPU ticks.
duration = time.Second
}
time.Sleep(duration)
+1 -1
View File
@@ -60,7 +60,7 @@ func initCallhome(ctx context.Context, objAPI ObjectLayer) {
// sleep for some time and try again.
duration := time.Duration(r.Float64() * float64(globalCallhomeConfig.FrequencyDur()))
if duration < time.Second {
// Make sure to sleep atleast a second to avoid high CPU ticks.
// Make sure to sleep at least a second to avoid high CPU ticks.
duration = time.Second
}
time.Sleep(duration)
+3 -3
View File
@@ -847,7 +847,7 @@ func loadRootCredentials() {
// It depends on KMS env variables and global cli flags.
func handleKMSConfig() {
if env.IsSet(kms.EnvKMSSecretKey) && env.IsSet(kms.EnvKESEndpoint) {
logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKMSSecretKey, kms.EnvKESEndpoint))
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKMSSecretKey, kms.EnvKESEndpoint))
}
if env.IsSet(kms.EnvKMSSecretKey) {
@@ -860,10 +860,10 @@ func handleKMSConfig() {
if env.IsSet(kms.EnvKESEndpoint) {
if env.IsSet(kms.EnvKESAPIKey) {
if env.IsSet(kms.EnvKESClientKey) {
logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientKey))
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientKey))
}
if env.IsSet(kms.EnvKESClientCert) {
logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientCert))
logger.Fatal(errors.New("ambiguous KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", kms.EnvKESAPIKey, kms.EnvKESClientCert))
}
}
if !env.IsSet(kms.EnvKESKeyName) {
+1 -1
View File
@@ -499,7 +499,7 @@ func lookupConfigs(s config.Config, objAPI ObjectLayer) {
if len(globalDomainNames) != 0 && !globalDomainIPs.IsEmpty() && globalEtcdClient != nil {
if globalDNSConfig != nil {
// if global DNS is already configured, indicate with a warning, incase
// if global DNS is already configured, indicate with a warning, in case
// users are confused.
logger.LogIf(ctx, fmt.Errorf("DNS store is already configured with %s, etcd is not used for DNS store", globalDNSConfig))
} else {
+3 -3
View File
@@ -79,7 +79,7 @@ func initDataScanner(ctx context.Context, objAPI ObjectLayer) {
runDataScanner(ctx, objAPI)
duration := time.Duration(r.Float64() * float64(scannerCycle.Load()))
if duration < time.Second {
// Make sure to sleep atleast a second to avoid high CPU ticks.
// Make sure to sleep at least a second to avoid high CPU ticks.
duration = time.Second
}
time.Sleep(duration)
@@ -710,7 +710,7 @@ func (f *folderScanner) scanFolder(ctx context.Context, folder cachedFolder, int
partial: func(entries metaCacheEntries, errs []error) {
entry, ok := entries.resolve(&resolver)
if !ok {
// check if we can get one entry atleast
// check if we can get one entry at least
// proceed to heal nonetheless, since
// this object might be dangling.
entry, _ = entries.firstFound()
@@ -1471,7 +1471,7 @@ func (d *dynamicSleeper) Sleep(ctx context.Context, base time.Duration) {
}
// Update the current settings and cycle all waiting.
// Parameters are the same as in the contructor.
// Parameters are the same as in the constructor.
func (d *dynamicSleeper) Update(factor float64, maxWait time.Duration) error {
d.mu.Lock()
defer d.mu.Unlock()
+1 -1
View File
@@ -980,7 +980,7 @@ type objectIO interface {
// The loader is optimistic and has no locking, but tries 5 times before giving up.
// If the object is not found, a nil error with empty data usage cache is returned.
func (d *dataUsageCache) load(ctx context.Context, store objectIO, name string) error {
// By defaut, empty data usage cache
// By default, empty data usage cache
*d = dataUsageCache{}
load := func(name string, timeout time.Duration) (bool, error) {
+1 -1
View File
@@ -41,7 +41,7 @@ const (
dataUsageCacheName = ".usage-cache.bin"
)
// storeDataUsageInBackend will store all objects sent on the gui channel until closed.
// storeDataUsageInBackend will store all objects sent on the dui channel until closed.
func storeDataUsageInBackend(ctx context.Context, objAPI ObjectLayer, dui <-chan DataUsageInfo) {
attempts := 1
for dataUsageInfo := range dui {
+3 -6
View File
@@ -209,9 +209,6 @@ func DecryptETags(ctx context.Context, k kms.KMS, objects []ObjectInfo) error {
// uploaded by the user using multipart mechanism:
// initiate new multipart, upload part, complete upload
func (o *ObjectInfo) isMultipart() bool {
if len(o.Parts) == 0 {
return false
}
_, encrypted := crypto.IsEncrypted(o.UserDefined)
if encrypted {
if !crypto.IsMultiPart(o.UserDefined) {
@@ -228,7 +225,7 @@ func (o *ObjectInfo) isMultipart() bool {
// Further check if this object is uploaded using multipart mechanism
// by the user and it is not about Erasure internally splitting the
// object into parts in PutObject()
return !(o.backendType == BackendErasure && len(o.ETag) == 32)
return len(o.ETag) != 32
}
// ParseSSECopyCustomerRequest parses the SSE-C header fields of the provided request.
@@ -667,7 +664,7 @@ func (d *DecryptBlocksReader) buildDecrypter(partID int) error {
mac.Write(partIDbin[:])
partEncryptionKey := mac.Sum(nil)
// Limit the reader, so the decryptor doesnt receive bytes
// Limit the reader, so the decryptor doesn't receive bytes
// from the next part (different DARE stream)
encLenToRead := d.parts[d.partIndex].Size - d.partEncRelOffset
decrypter, err := newDecryptReaderWithObjectKey(io.LimitReader(d.reader, encLenToRead), partEncryptionKey, d.startSeqNum)
@@ -754,7 +751,7 @@ func (o ObjectInfo) DecryptedSize() (int64, error) {
// However, DecryptETag does not try to decrypt the ETag if
// it consists of a 128 bit hex value (32 hex chars) and exactly
// one '-' followed by a 32-bit number.
// This special case adresses randomly-generated ETags generated
// This special case addresses randomly-generated ETags generated
// by the MinIO server when running in non-compat mode. These
// random ETags are not encrypt.
//
+1 -1
View File
@@ -158,7 +158,7 @@ func (p *parallelReader) Read(dst [][]byte) ([][]byte, error) {
bufIdx := p.readerToBuf[i]
if p.buf[bufIdx] == nil {
// Reading first time on this disk, hence the buffer needs to be allocated.
// Subsequent reads will re-use this buffer.
// Subsequent reads will reuse this buffer.
p.buf[bufIdx] = make([]byte, p.shardSize)
}
// For the last shard, the shardsize might be less than previous shard sizes.
+1 -1
View File
@@ -144,7 +144,7 @@ func TestErasureDecode(t *testing.T) {
}
if err == nil {
if content := writer.Bytes(); !bytes.Equal(content, data[test.offset:test.offset+test.length]) {
t.Errorf("Test %d: read retruns wrong file content.", i)
t.Errorf("Test %d: read returns wrong file content.", i)
}
}
+2 -2
View File
@@ -31,7 +31,7 @@ import (
// Returns the latest updated FileInfo files and error in case of failure.
func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, defaultParityCount int, errs []error) (FileInfo, error) {
// There should be atleast half correct entries, if not return failure
// There should be at least half correct entries, if not return failure
expectedRQuorum := len(partsMetadata) / 2
if defaultParityCount == 0 {
// if parity count is '0', we expected all entries to be present.
@@ -57,7 +57,7 @@ func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, defaultPar
return FileInfo{}, errErasureReadQuorum
}
// Interate through all the modTimes and count the FileInfo(s) with latest time.
// Iterate through all the modTimes and count the FileInfo(s) with latest time.
for index, t := range modTimes {
if partsMetadata[index].IsValid() && t.Equal(modTime) {
latestFileInfo = partsMetadata[index]
+6 -3
View File
@@ -108,7 +108,7 @@ func (er erasureObjects) listAndHeal(bucket, prefix string, scanMode madmin.Heal
partial: func(entries metaCacheEntries, _ []error) {
entry, ok := entries.resolve(&resolver)
if !ok {
// check if we can get one entry atleast
// check if we can get one entry at least
// proceed to heal nonetheless.
entry, _ = entries.firstFound()
}
@@ -334,7 +334,7 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object
erasure.ShardFileSize(latestMeta.Parts[0].ActualSize) < smallFileThreshold)
}
result.ObjectSize, err = latestMeta.GetActualSize()
result.ObjectSize, err = latestMeta.ToObjectInfo(bucket, object, true).GetActualSize()
if err != nil {
return result, err
}
@@ -614,7 +614,10 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object
// - Remove any remaining parts from outdated disks from before transition.
if recreate || partsMetadata[i].IsRemote() {
rmDataDir := partsMetadata[i].DataDir
disk.DeleteVol(ctx, pathJoin(bucket, encodeDirObject(object), rmDataDir), true)
disk.Delete(ctx, bucket, pathJoin(encodeDirObject(object), rmDataDir), DeleteOptions{
Immediate: true,
Recursive: true,
})
}
for i, v := range result.Before.Drives {
+1 -1
View File
@@ -1067,7 +1067,7 @@ func TestHealObjectCorruptedPools(t *testing.T) {
for i := 0; i < (nfi.Erasure.DataBlocks + nfi.Erasure.ParityBlocks); i++ {
stats, _ := erasureDisks[i].StatInfoFile(context.Background(), bucket, pathJoin(object, xlStorageFormatFile), false)
if len(stats) != 0 {
t.Errorf("Expected xl.meta file to be not present, but succeeeded")
t.Errorf("Expected xl.meta file to be not present, but succeeded")
}
}
}
+1 -1
View File
@@ -64,7 +64,7 @@ func reduceErrs(errs []error, ignoredErrs []error) (maxCount int, maxErr error)
if IsErrIgnored(err, ignoredErrs...) {
continue
}
// Errors due to context cancelation may be wrapped - group them by context.Canceled.
// Errors due to context cancellation may be wrapped - group them by context.Canceled.
if errors.Is(err, context.Canceled) {
errorCounts[context.Canceled]++
continue
+1 -1
View File
@@ -94,7 +94,7 @@ func TestReduceErrs(t *testing.T) {
},
nil, nil,
},
// Checks if wrapped context cancelation errors are grouped as one.
// Checks if wrapped context cancellation errors are grouped as one.
{canceledErrs, nil, context.Canceled},
}
// Validates list of all the testcases for returning valid errors.
+1 -51
View File
@@ -22,18 +22,15 @@ import (
"encoding/hex"
"fmt"
"sort"
"strconv"
"strings"
"time"
"github.com/minio/minio/internal/amztime"
"github.com/minio/minio/internal/bucket/replication"
"github.com/minio/minio/internal/crypto"
"github.com/minio/minio/internal/hash/sha256"
xhttp "github.com/minio/minio/internal/http"
"github.com/minio/minio/internal/logger"
"github.com/minio/pkg/v2/sync/errgroup"
"github.com/minio/sio"
)
// Object was stored with additional erasure codes due to degraded system at upload time
@@ -88,52 +85,6 @@ func (fi FileInfo) IsValid() bool {
correctIndexes)
}
func (fi FileInfo) checkMultipart() (int64, bool) {
if len(fi.Parts) == 0 {
return 0, false
}
if !crypto.IsMultiPart(fi.Metadata) {
return 0, false
}
var size int64
for _, part := range fi.Parts {
psize, err := sio.DecryptedSize(uint64(part.Size))
if err != nil {
return 0, false
}
size += int64(psize)
}
return size, len(extractETag(fi.Metadata)) != 32
}
// GetActualSize - returns the actual size of the stored object
func (fi FileInfo) GetActualSize() (int64, error) {
if _, ok := fi.Metadata[ReservedMetadataPrefix+"compression"]; ok {
sizeStr, ok := fi.Metadata[ReservedMetadataPrefix+"actual-size"]
if !ok {
return -1, errInvalidDecompressedSize
}
size, err := strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
return -1, errInvalidDecompressedSize
}
return size, nil
}
if _, ok := crypto.IsEncrypted(fi.Metadata); ok {
size, ok := fi.checkMultipart()
if !ok {
size, err := sio.DecryptedSize(uint64(fi.Size))
if err != nil {
err = errObjectTampered // assign correct error type
}
return int64(size), err
}
return size, nil
}
return fi.Size, nil
}
// ToObjectInfo - Converts metadata to object info.
func (fi FileInfo) ToObjectInfo(bucket, object string, versioned bool) ObjectInfo {
object = decodeDirObject(object)
@@ -166,7 +117,6 @@ func (fi FileInfo) ToObjectInfo(bucket, object string, versioned bool) ObjectInf
objInfo.Expires = t.UTC()
}
}
objInfo.backendType = BackendErasure
// Extract etag from metadata.
objInfo.ETag = extractETag(fi.Metadata)
@@ -533,7 +483,7 @@ func listObjectParities(partsMetadata []FileInfo, errs []error) (parities []int)
// readQuorum is the min required disks to read data.
// writeQuorum is the min required disks to write data.
func objectQuorumFromMeta(ctx context.Context, partsMetaData []FileInfo, errs []error, defaultParityCount int) (objectReadQuorum, objectWriteQuorum int, err error) {
// There should be atleast half correct entries, if not return failure
// There should be at least half correct entries, if not return failure
expectedRQuorum := len(partsMetaData) / 2
if defaultParityCount == 0 {
// if parity count is '0', we expected all entries to be present.
+3 -3
View File
@@ -103,7 +103,7 @@ func (er erasureObjects) checkUploadIDExists(ctx context.Context, bucket, object
return fi, partsMetadata, err
}
// Removes part.meta given by partName belonging to a mulitpart upload from minioMetaBucket
// Removes part.meta given by partName belonging to a multipart upload from minioMetaBucket
func (er erasureObjects) removePartMeta(bucket, object, uploadID, dataDir string, partNumber int) {
uploadIDPath := er.getUploadIDDir(bucket, object, uploadID)
curpartPath := pathJoin(uploadIDPath, dataDir, fmt.Sprintf("part.%d", partNumber))
@@ -127,7 +127,7 @@ func (er erasureObjects) removePartMeta(bucket, object, uploadID, dataDir string
g.Wait()
}
// Removes part given by partName belonging to a mulitpart upload from minioMetaBucket
// Removes part given by partName belonging to a multipart upload from minioMetaBucket
func (er erasureObjects) removeObjectPart(bucket, object, uploadID, dataDir string, partNumber int) {
uploadIDPath := er.getUploadIDDir(bucket, object, uploadID)
curpartPath := pathJoin(uploadIDPath, dataDir, fmt.Sprintf("part.%d", partNumber))
@@ -656,7 +656,7 @@ func (er erasureObjects) PutObjectPart(ctx context.Context, bucket, object, uplo
var buffer []byte
switch size := data.Size(); {
case size == 0:
buffer = make([]byte, 1) // Allocate atleast a byte to reach EOF
buffer = make([]byte, 1) // Allocate at least a byte to reach EOF
case size == -1:
if size := data.ActualSize(); size > 0 && size < fi.Erasure.BlockSize {
// Account for padding and forced compression overhead and encryption.
+3 -4
View File
@@ -955,7 +955,7 @@ func (er erasureObjects) getObjectFileInfo(ctx context.Context, bucket, object s
for i := range onlineMeta {
// verify metadata is valid, it has similar erasure info
// as well as common modtime, if modtime is not possible
// verify if it has common "etag" atleast.
// verify if it has common "etag" at least.
if onlineMeta[i].IsValid() && onlineMeta[i].Erasure.Equal(fi.Erasure) {
ok := onlineMeta[i].ModTime.Equal(modTime)
if modTime.IsZero() || modTime.Equal(timeSentinel) {
@@ -1150,7 +1150,7 @@ func (er erasureObjects) putMetacacheObject(ctx context.Context, key string, r *
var buffer []byte
switch size := data.Size(); {
case size == 0:
buffer = make([]byte, 1) // Allocate atleast a byte to reach EOF
buffer = make([]byte, 1) // Allocate at least a byte to reach EOF
case size >= fi.Erasure.BlockSize:
buffer = globalBytePoolCap.Get()
defer globalBytePoolCap.Put(buffer)
@@ -1401,7 +1401,7 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
var buffer []byte
switch size := data.Size(); {
case size == 0:
buffer = make([]byte, 1) // Allocate atleast a byte to reach EOF
buffer = make([]byte, 1) // Allocate at least a byte to reach EOF
case size >= fi.Erasure.BlockSize || size == -1:
buffer = globalBytePoolCap.Get()
defer globalBytePoolCap.Put(buffer)
@@ -1559,7 +1559,6 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
if errors.Is(err, errFileNotFound) {
return ObjectInfo{}, toObjectErr(errErasureWriteQuorum, bucket, object)
}
logger.LogOnceIf(ctx, err, "erasure-object-rename-"+bucket+"-"+object)
return ObjectInfo{}, toObjectErr(err, bucket, object)
}
+1 -1
View File
@@ -799,7 +799,7 @@ func TestPutObjectNoQuorumSmall(t *testing.T) {
}
// Test PutObject twice, one small and another bigger
// than small data thresold and checks reading them again
// than small data threshold and checks reading them again
func TestPutObjectSmallInlineData(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
+4 -68
View File
@@ -1931,76 +1931,12 @@ func (z *erasureServerPools) HealFormat(ctx context.Context, dryRun bool) (madmi
}
func (z *erasureServerPools) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
r := madmin.HealResultItem{
Type: madmin.HealItemBucket,
Bucket: bucket,
}
// Attempt heal on the bucket metadata, ignore any failures
hopts := opts
hopts.Recreate = false
defer z.HealObject(ctx, minioMetaBucket, pathJoin(bucketMetaPrefix, bucket, bucketMetadataFile), "", hopts)
type DiskStat struct {
VolInfos []VolInfo
Errs []error
}
for _, pool := range z.serverPools {
// map of node wise disk stats
diskStats := make(map[string]DiskStat)
for _, set := range pool.sets {
for _, disk := range set.getDisks() {
if disk == OfflineDisk {
continue
}
vi, err := disk.StatVol(ctx, bucket)
hostName := disk.Hostname()
if disk.IsLocal() {
hostName = "local"
}
ds, ok := diskStats[hostName]
if !ok {
newds := DiskStat{
VolInfos: []VolInfo{vi},
Errs: []error{err},
}
diskStats[hostName] = newds
} else {
ds.VolInfos = append(ds.VolInfos, vi)
ds.Errs = append(ds.Errs, err)
diskStats[hostName] = ds
}
}
}
nodeCount := len(diskStats)
bktNotFoundCount := 0
for _, ds := range diskStats {
if isAllBucketsNotFound(ds.Errs) {
bktNotFoundCount++
}
}
// if the bucket if not found on more than hslf the no of nodes, its dangling
if bktNotFoundCount > nodeCount/2 {
opts.Remove = true
} else {
opts.Recreate = true
}
result, err := z.s3Peer.HealBucket(ctx, bucket, opts)
if err != nil {
if _, ok := err.(BucketNotFound); ok {
continue
}
return result, err
}
r.DiskCount += result.DiskCount
r.SetCount += result.SetCount
r.Before.Drives = append(r.Before.Drives, result.Before.Drives...)
r.After.Drives = append(r.After.Drives, result.After.Drives...)
}
return r, nil
return z.s3Peer.HealBucket(ctx, bucket, opts)
}
// Walk a bucket, optionally prefix recursively, until we have returned
@@ -2324,7 +2260,7 @@ const (
vmware = "VMWare"
)
// HealthOptions takes input options to return sepcific information
// HealthOptions takes input options to return specific information
type HealthOptions struct {
Maintenance bool
DeploymentType string
@@ -2499,7 +2435,7 @@ func (z *erasureServerPools) PutObjectMetadata(ctx context.Context, bucket, obje
}
opts.MetadataChg = true
// We don't know the size here set 1GiB atleast.
// We don't know the size here set 1GiB at least.
idx, err := z.getPoolIdxExistingWithOpts(ctx, bucket, object, opts)
if err != nil {
return ObjectInfo{}, err
@@ -2517,7 +2453,7 @@ func (z *erasureServerPools) PutObjectTags(ctx context.Context, bucket, object s
opts.MetadataChg = true
// We don't know the size here set 1GiB atleast.
// We don't know the size here set 1GiB at least.
idx, err := z.getPoolIdxExistingWithOpts(ctx, bucket, object, opts)
if err != nil {
return ObjectInfo{}, err
+7 -3
View File
@@ -1111,6 +1111,13 @@ func (s *erasureSets) HealFormat(ctx context.Context, dryRun bool) (res madmin.H
return res, errNoHealRequired
}
if !reflect.DeepEqual(s.format, refFormat) {
// Format is corrupted and unrecognized by the running instance.
logger.LogIf(ctx, fmt.Errorf("Unable to heal the newly replaced drives due to format.json inconsistencies, please engage MinIO support for further assistance: %w",
errCorruptedFormat))
return res, errCorruptedFormat
}
formatOpID := mustGetUUID()
// Initialize a new set of set formats which will be written to disk.
@@ -1192,9 +1199,6 @@ func (s *erasureSets) HealFormat(ctx context.Context, dryRun bool) (res madmin.H
}
}
// Replace reference format with what was loaded from disks.
s.format = refFormat
s.erasureDisksMu.Unlock()
}
+2 -2
View File
@@ -85,7 +85,7 @@ func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, data
if write < int64(len(block)) {
n, err := dst.Write(block[:write])
if err != nil {
// The writer will be closed incase of range queries, which will emit ErrClosedPipe.
// The writer will be closed in case of range queries, which will emit ErrClosedPipe.
// The reader pipe might be closed at ListObjects io.EOF ignore it.
if err != io.ErrClosedPipe && err != io.EOF {
logger.LogIf(ctx, err)
@@ -99,7 +99,7 @@ func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, data
// Copy the block.
n, err := dst.Write(block)
if err != nil {
// The writer will be closed incase of range queries, which will emit ErrClosedPipe.
// The writer will be closed in case of range queries, which will emit ErrClosedPipe.
// The reader pipe might be closed at ListObjects io.EOF ignore it.
if err != io.ErrClosedPipe && err != io.EOF {
logger.LogIf(ctx, err)
+1 -22
View File
@@ -353,12 +353,6 @@ func saveFormatErasure(disk StorageAPI, format *formatErasureV3, healID string)
return errDiskNotFound
}
diskID := format.Erasure.This
if err := makeFormatErasureMetaVolumes(disk); err != nil {
return err
}
// Marshal and write to disk.
formatBytes, err := json.Marshal(format)
if err != nil {
@@ -383,7 +377,7 @@ func saveFormatErasure(disk StorageAPI, format *formatErasureV3, healID string)
return err
}
disk.SetDiskID(diskID)
disk.SetDiskID(format.Erasure.This)
if healID != "" {
ctx := context.Background()
ht := initHealingTracker(disk, healID)
@@ -814,21 +808,6 @@ func ecDrivesNoConfig(setDriveCount int) (int, error) {
return sc.GetParityForSC(storageclass.STANDARD), nil
}
// Make Erasure backend meta volumes.
func makeFormatErasureMetaVolumes(disk StorageAPI) error {
if disk == nil {
return errDiskNotFound
}
volumes := []string{
minioMetaTmpDeletedBucket, // creates .minio.sys/tmp as well as .minio.sys/tmp/.trash
minioMetaMultipartBucket, // creates .minio.sys/multipart
dataUsageBucket, // creates .minio.sys/buckets
minioConfigBucket, // creates .minio.sys/config
}
// Attempt to create MinIO internal buckets.
return disk.MakeVolBulk(context.TODO(), volumes...)
}
// Initialize a new set of set formats which will be written to all disks.
func newHealFormatSets(refFormat *formatErasureV3, setCount, setDriveCount int, formats []*formatErasureV3, errs []error) ([][]*formatErasureV3, [][]DiskInfo) {
newFormats := make([][]*formatErasureV3, setCount)
+1 -1
View File
@@ -483,7 +483,7 @@ func TestGetErasureID(t *testing.T) {
formats[2].ID = "bad-id"
if _, err = formatErasureGetDeploymentID(quorumFormat, formats); !errors.Is(err, errCorruptedFormat) {
t.Fatalf("Unexpect error %s", err)
t.Fatalf("Unexpected error %s", err)
}
}
+2 -2
View File
@@ -50,7 +50,7 @@ func (log *minioLogger) Printf(sessionID string, format string, v ...interface{}
}
}
// PrintCommand impelment Logger
// PrintCommand implement Logger
func (log *minioLogger) PrintCommand(sessionID string, command string, params string) {
if serverDebugLog {
if command == "PASS" {
@@ -61,7 +61,7 @@ func (log *minioLogger) PrintCommand(sessionID string, command string, params st
}
}
// PrintResponse impelment Logger
// PrintResponse implement Logger
func (log *minioLogger) PrintResponse(sessionID string, code int, message string) {
if serverDebugLog {
logger.Info("%s < %d %s", sessionID, code, message)
+1 -1
View File
@@ -263,7 +263,7 @@ func isKMSReq(r *http.Request) bool {
// Supported Amz date headers.
var amzDateHeaders = []string{
// Do not chane this order, x-amz-date value should be
// Do not change this order, x-amz-date value should be
// validated first.
"x-amz-date",
"date",
+1 -1
View File
@@ -433,7 +433,7 @@ func (er *erasureObjects) healErasureSet(ctx context.Context, buckets []string,
partial: func(entries metaCacheEntries, _ []error) {
entry, ok := entries.resolve(&resolver)
if !ok {
// check if we can get one entry atleast
// check if we can get one entry at least
// proceed to heal nonetheless.
entry, _ = entries.firstFound()
}
+1 -1
View File
@@ -293,7 +293,7 @@ var (
// Global server's network statistics
globalConnStats = newConnStats()
// Global HTTP request statisitics
// Global HTTP request statistics
globalHTTPStats = newHTTPStats()
// Global bucket network and API statistics
+2 -2
View File
@@ -206,7 +206,7 @@ func getReqAccessCred(r *http.Request, region string) (cred auth.Credentials) {
return cred
}
// Extract request params to be sent with event notifiation.
// Extract request params to be sent with event notification.
func extractReqParams(r *http.Request) map[string]string {
if r == nil {
return nil
@@ -237,7 +237,7 @@ func extractReqParams(r *http.Request) map[string]string {
return m
}
// Extract response elements to be sent with event notifiation.
// Extract response elements to be sent with event notification.
func extractRespElements(w http.ResponseWriter) map[string]string {
if w == nil {
return map[string]string{}
+1 -1
View File
@@ -152,7 +152,7 @@ func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) {
// LivenessCheckHandler checks whether MinIO is up. It differs from the
// readiness handler since a failing liveness check causes pod restarts
// in K8S enviromnents. Therefore, it does not contact external systems.
// in K8S environments. Therefore, it does not contact external systems.
func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) {
if objLayer := newObjectLayerFn(); objLayer == nil {
w.Header().Set(xhttp.MinIOServerStatus, unavailable) // Service not initialized yet
+1 -1
View File
@@ -140,7 +140,7 @@ func pickRelevantGoroutines() (gs []string) {
buf := debug.Stack()
// runtime stack of go routines will be listed with 2 blank spaces between each of them, so split on "\n\n" .
for _, g := range strings.Split(string(buf), "\n\n") {
// Again split on a new line, the first line of the second half contaisn the info about the go routine.
// Again split on a new line, the first line of the second half contains the info about the go routine.
sl := strings.SplitN(g, "\n", 2)
if len(sl) != 2 {
continue
+1 -1
View File
@@ -47,7 +47,7 @@ func initLicenseUpdateJob(ctx context.Context, objAPI ObjectLayer) {
// sleep for some time and try again.
duration := time.Duration(r.Float64() * float64(time.Hour))
if duration < time.Second {
// Make sure to sleep atleast a second to avoid high CPU ticks.
// Make sure to sleep at least a second to avoid high CPU ticks.
duration = time.Second
}
time.Sleep(duration)
+1 -1
View File
@@ -34,7 +34,7 @@ type lockRequesterInfo struct {
UID string // UID to uniquely identify request of client.
Timestamp time.Time // Timestamp set at the time of initialization.
TimeLastRefresh time.Time // Timestamp for last lock refresh.
Source string // Contains line, function and filename reqesting the lock.
Source string // Contains line, function and filename requesting the lock.
Group bool // indicates if it was a group lock.
// Owner represents the UUID of the owner who originally requested the lock
// useful in expiry.
+12
View File
@@ -20,6 +20,7 @@ package cmd
import (
"context"
"fmt"
"math"
"net/http"
"runtime"
"strconv"
@@ -1715,6 +1716,17 @@ func getHistogramMetrics(hist *prometheus.HistogramVec, desc MetricDescription)
}
metrics = append(metrics, metric)
}
// add metrics with +Inf label
labels1 := make(map[string]string)
for _, lp := range dtoMetric.GetLabel() {
labels1[*lp.Name] = *lp.Value
}
labels1["le"] = fmt.Sprintf("%.3f", math.Inf(+1))
metrics = append(metrics, Metric{
Description: desc,
VariableLabels: labels1,
Value: dtoMetric.Counter.GetValue(),
})
}
return metrics
}
+2 -1
View File
@@ -81,7 +81,8 @@ func TestGetHistogramMetrics(t *testing.T) {
}
metrics := getHistogramMetrics(ttfbHist, getBucketTTFBDistributionMD())
if expPoints := len(labels) * len(histBuckets); expPoints != len(metrics) {
// additional labels for +Inf for all histogram metrics
if expPoints := len(labels) * (len(histBuckets) + 1); expPoints != len(metrics) {
t.Fatalf("Expected %v data points but got %v", expPoints, len(metrics))
}
}
+2 -2
View File
@@ -111,9 +111,9 @@ func getHostIP(host string) (ipList set.StringSet, err error) {
return ipList, err
}
// sortIPs - sort ips based on higher octects.
// sortIPs - sort ips based on higher octets.
// The logic to sort by last octet is implemented to
// prefer CIDRs with higher octects, this in-turn skips the
// prefer CIDRs with higher octets, this in-turn skips the
// localhost/loopback address to be not preferred as the
// first ip on the list. Subsequently this list helps us print
// a user friendly message with appropriate values.
+1 -4
View File
@@ -200,8 +200,6 @@ type ObjectInfo struct {
Legacy bool // indicates object on disk is in legacy data format
// backendType indicates which backend filled this structure
backendType BackendType
// internal representation of version purge status
VersionPurgeStatusInternal string
VersionPurgeStatus VersionPurgeStatusType
@@ -282,7 +280,6 @@ func (o *ObjectInfo) Clone() (cinfo ObjectInfo) {
metadataOnly: o.metadataOnly,
versionOnly: o.versionOnly,
keyRotation: o.keyRotation,
backendType: o.backendType,
AccTime: o.AccTime,
Legacy: o.Legacy,
VersionPurgeStatus: o.VersionPurgeStatus,
@@ -431,7 +428,7 @@ func (lm ListMultipartsInfo) Lookup(uploadID string) bool {
return false
}
// ListMultipartsInfo - represnets bucket resources for incomplete multipart uploads.
// ListMultipartsInfo - represents bucket resources for incomplete multipart uploads.
type ListMultipartsInfo struct {
// Together with upload-id-marker, this parameter specifies the multipart upload
// after which listing should begin.
+1 -1
View File
@@ -539,7 +539,7 @@ func (e ObjectNameTooLong) Error() string {
// Error returns string an error formatted as the given text.
func (e ObjectNamePrefixAsSlash) Error() string {
return "Object name contains forward slash as pefix: " + e.Bucket + "/" + e.Object
return "Object name contains forward slash as prefix: " + e.Bucket + "/" + e.Object
}
// AllAccessDisabled All access to this object has been disabled
+2 -2
View File
@@ -825,7 +825,7 @@ func _testListObjects(obj ObjectLayer, instanceType string, t1 TestErrHandler, v
{"ad", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "ad"}, false},
// Using an existing file for bucket name, but its not a directory (5).
{"simple-file.txt", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "simple-file.txt"}, false},
// Valid bucket names, but they donot exist (6-8).
// Valid bucket names, but they do not exist (6-8).
{"volatile-bucket-1", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false},
@@ -1570,7 +1570,7 @@ func testListObjectVersions(obj ObjectLayer, instanceType string, t1 TestErrHand
{"ad", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "ad"}, false},
// Using an existing file for bucket name, but its not a directory (5).
{"simple-file.txt", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "simple-file.txt"}, false},
// Valid bucket names, but they donot exist (6-8).
// Valid bucket names, but they do not exist (6-8).
{"volatile-bucket-1", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", "", 0, ListObjectsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false},
+15 -15
View File
@@ -52,16 +52,16 @@ func testObjectNewMultipartUpload(obj ObjectLayer, instanceType string, t TestEr
}
errMsg := "Bucket not found: minio-bucket"
// opearation expected to fail since the bucket on which NewMultipartUpload is being initiated doesn't exist.
// operation expected to fail since the bucket on which NewMultipartUpload is being initiated doesn't exist.
_, err = obj.NewMultipartUpload(context.Background(), bucket, object, opts)
if err == nil {
t.Fatalf("%s: Expected to fail since the NewMultipartUpload is intialized on a non-existent bucket.", instanceType)
t.Fatalf("%s: Expected to fail since the NewMultipartUpload is initialized on a non-existent bucket.", instanceType)
}
if errMsg != err.Error() {
t.Errorf("%s, Expected to fail with Error \"%s\", but instead found \"%s\".", instanceType, errMsg, err.Error())
}
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err = obj.MakeBucket(context.Background(), bucket, MakeBucketOptions{})
if err != nil {
// failed to create newbucket, abort.
@@ -94,7 +94,7 @@ func testObjectAbortMultipartUpload(obj ObjectLayer, instanceType string, t Test
bucket := "minio-bucket"
object := "minio-object"
opts := ObjectOptions{}
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err := obj.MakeBucket(context.Background(), bucket, MakeBucketOptions{})
if err != nil {
// failed to create newbucket, abort.
@@ -150,7 +150,7 @@ func testObjectAPIIsUploadIDExists(obj ObjectLayer, instanceType string, t TestE
bucket := "minio-bucket"
object := "minio-object"
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err := obj.MakeBucket(context.Background(), bucket, MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -182,7 +182,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH
bucket := "minio-bucket"
object := "minio-object"
opts := ObjectOptions{}
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err := obj.MakeBucket(context.Background(), bucket, MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -348,7 +348,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
// bucketnames[1].
// objectNames[0].
// uploadIds [1-3].
// Bucket to test for mutiple upload Id's for a given object.
// Bucket to test for multiple upload Id's for a given object.
err = obj.MakeBucket(context.Background(), bucketNames[1], MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -366,7 +366,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
uploadIDs = append(uploadIDs, res.UploadID)
}
// Bucket to test for mutiple objects, each with unique UUID.
// Bucket to test for multiple objects, each with unique UUID.
// bucketnames[2].
// objectNames[0-2].
// uploadIds [4-9].
@@ -1045,7 +1045,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
{"Test", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "Test"}, false},
{"---", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "---"}, false},
{"ad", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "ad"}, false},
// Valid bucket names, but they donot exist (Test number 5-7).
// Valid bucket names, but they do not exist (Test number 5-7).
{"volatile-bucket-1", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", "", "", 0, ListMultipartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false},
@@ -1210,7 +1210,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks
// bucketnames[0].
// objectNames[0].
// uploadIds [0].
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err := obj.MakeBucket(context.Background(), bucketNames[0], MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -1362,7 +1362,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks
{"---", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "---"}, false},
{"ad", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "ad"}, false},
// Test cases for listing uploadID with single part.
// Valid bucket names, but they donot exist (Test number 5-7).
// Valid bucket names, but they do not exist (Test number 5-7).
{"volatile-bucket-1", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false},
@@ -1461,7 +1461,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler)
// bucketnames[0].
// objectNames[0].
// uploadIds [0].
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err := obj.MakeBucket(context.Background(), bucketNames[0], MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -1599,7 +1599,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler)
{"---", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "---"}, false},
{"ad", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "ad"}, false},
// Test cases for listing uploadID with single part.
// Valid bucket names, but they donot exist (Test number 5-7).
// Valid bucket names, but they do not exist (Test number 5-7).
{"volatile-bucket-1", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", 0, 0, ListPartsInfo{}, BucketNotFound{Bucket: "volatile-bucket-3"}, false},
@@ -1702,7 +1702,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T
// bucketnames[0].
// objectNames[0].
// uploadIds [0].
// Create bucket before intiating NewMultipartUpload.
// Create bucket before initiating NewMultipartUpload.
err = obj.MakeBucket(context.Background(), bucketNames[0], MakeBucketOptions{})
if err != nil {
// Failed to create newbucket, abort.
@@ -1814,7 +1814,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T
{"---", "", "", []CompletePart{}, "", BucketNotFound{Bucket: "---"}, false},
{"ad", "", "", []CompletePart{}, "", BucketNotFound{Bucket: "ad"}, false},
// Test cases for listing uploadID with single part.
// Valid bucket names, but they donot exist (Test number 5-7).
// Valid bucket names, but they do not exist (Test number 5-7).
{"volatile-bucket-1", "", "", []CompletePart{}, "", BucketNotFound{Bucket: "volatile-bucket-1"}, false},
{"volatile-bucket-2", "", "", []CompletePart{}, "", BucketNotFound{Bucket: "volatile-bucket-2"}, false},
{"volatile-bucket-3", "", "", []CompletePart{}, "", BucketNotFound{Bucket: "volatile-bucket-3"}, false},
+16 -10
View File
@@ -533,6 +533,14 @@ func (o ObjectInfo) GetActualSize() (int64, error) {
return size, nil
}
if _, ok := crypto.IsEncrypted(o.UserDefined); ok {
sizeStr, ok := o.UserDefined[ReservedMetadataPrefix+"actual-size"]
if ok {
size, err := strconv.ParseInt(sizeStr, 10, 64)
if err != nil {
return -1, errObjectTampered
}
return size, nil
}
return o.DecryptedSize()
}
@@ -632,16 +640,14 @@ func getCompressedOffsets(oi ObjectInfo, offset int64, decrypt func([]byte) ([]b
var skipLength int64
var cumulativeActualSize int64
var firstPartIdx int
if len(oi.Parts) > 0 {
for i, part := range oi.Parts {
cumulativeActualSize += part.ActualSize
if cumulativeActualSize <= offset {
compressedOffset += part.Size
} else {
firstPartIdx = i
skipLength = cumulativeActualSize - part.ActualSize
break
}
for i, part := range oi.Parts {
cumulativeActualSize += part.ActualSize
if cumulativeActualSize <= offset {
compressedOffset += part.Size
} else {
firstPartIdx = i
skipLength = cumulativeActualSize - part.ActualSize
break
}
}
partSkip = offset - skipLength
+1 -1
View File
@@ -99,7 +99,7 @@ func testPathTraversalExploit(obj ObjectLayer, instanceType, bucketName string,
t.Fatalf("failed to create HTTP request for Put Object: <ERROR> %v", err)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
+3
View File
@@ -3318,6 +3318,9 @@ func (api objectAPIHandlers) GetObjectTaggingHandler(w http.ResponseWriter, r *h
} // overlay tags from peer site.
ot = tags
w.Header()[xhttp.MinIOTaggingProxied] = []string{"true"} // indicate that the request was proxied.
} else {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
return
}
} else {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
+8 -8
View File
@@ -1914,7 +1914,7 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri
},
// Test case - 6.
// Test case with ivalid byte range for exceeding source size boundaries.
// Test case with invalid byte range for exceeding source size boundaries.
{
bucketName: bucketName,
uploadID: uploadID,
@@ -2030,7 +2030,7 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusNotFound,
},
// Test case - 16, Test case with ivalid byte range empty value.
// Test case - 16, Test case with invalid byte range empty value.
{
bucketName: bucketName,
uploadID: uploadID,
@@ -3021,7 +3021,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
},
// Test case - 7.
// Test case with proper parts.
// Should successed and the content in the response body is asserted.
// Should succeeded and the content in the response body is asserted.
{
bucket: bucketName,
object: objectName,
@@ -3037,7 +3037,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
},
// Test case - 8.
// Test case with proper parts.
// Should successed and the content in the response body is asserted.
// Should succeeded and the content in the response body is asserted.
{
bucket: bucketName,
object: objectName,
@@ -3088,7 +3088,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
if rec.Code == http.StatusOK {
// Verify whether the bucket obtained object is same as the one created.
if !bytes.Equal(testCase.expectedContent, actualContent) {
t.Errorf("Test %d : MinIO %s: CompleteMultipart response content differs from expected value. got %s, expecte %s", i+1, instanceType,
t.Errorf("Test %d : MinIO %s: CompleteMultipart response content differs from expected value. got %s, expected %s", i+1, instanceType,
string(actualContent), string(testCase.expectedContent))
}
continue
@@ -3366,7 +3366,7 @@ func testAPIDeleteObjectHandler(obj ObjectLayer, instanceType, bucketName string
}{
// Test case - 1.
// Deleting an existing object.
// Expected to return HTTP resposne status code 204.
// Expected to return HTTP response status code 204.
{
bucketName: bucketName,
objectName: objectName,
@@ -3490,7 +3490,7 @@ func testAPIPutObjectPartHandlerStreaming(obj ObjectLayer, instanceType, bucketN
}
apiRouter.ServeHTTP(rec, req)
// Get uploadID of the mulitpart upload initiated.
// Get uploadID of the multipart upload initiated.
var mpartResp InitiateMultipartUploadResponse
mpartRespBytes, err := io.ReadAll(rec.Result().Body)
if err != nil {
@@ -3897,7 +3897,7 @@ func testAPIListObjectPartsHandlerPreSign(obj ObjectLayer, instanceType, bucketN
}
apiRouter.ServeHTTP(rec, req)
// Get uploadID of the mulitpart upload initiated.
// Get uploadID of the multipart upload initiated.
var mpartResp InitiateMultipartUploadResponse
mpartRespBytes, err := io.ReadAll(rec.Result().Body)
if err != nil {
+1 -1
View File
@@ -104,7 +104,7 @@ func osMkdirAll(dirPath string, perm os.FileMode, baseDir string) error {
// refer https://github.com/golang/go/issues/24015
const blockSize = 8 << 10 // 8192
// By default atleast 128 entries in single getdents call (1MiB buffer)
// By default at least 128 entries in single getdents call (1MiB buffer)
var (
direntPool = sync.Pool{
New: func() interface{} {
+31 -1
View File
@@ -135,6 +135,36 @@ func NewS3PeerSys(endpoints EndpointServerPools) *S3PeerSys {
func (sys *S3PeerSys) HealBucket(ctx context.Context, bucket string, opts madmin.HealOpts) (madmin.HealResultItem, error) {
g := errgroup.WithNErrs(len(sys.peerClients))
for idx, client := range sys.peerClients {
idx := idx
client := client
g.Go(func() error {
if client == nil {
return errPeerOffline
}
_, err := client.GetBucketInfo(ctx, bucket, BucketOptions{})
return err
}, idx)
}
errs := g.Wait()
var poolErrs []error
for poolIdx := 0; poolIdx < sys.poolsCount; poolIdx++ {
perPoolErrs := make([]error, 0, len(sys.peerClients))
for i, client := range sys.peerClients {
if slices.Contains(client.GetPools(), poolIdx) {
perPoolErrs = append(perPoolErrs, errs[i])
}
}
quorum := len(perPoolErrs) / 2
poolErrs = append(poolErrs, reduceWriteQuorumErrs(ctx, perPoolErrs, bucketOpIgnoredErrs, quorum))
}
opts.Remove = isAllBucketsNotFound(poolErrs)
opts.Recreate = !opts.Remove
g = errgroup.WithNErrs(len(sys.peerClients))
healBucketResults := make([]madmin.HealResultItem, len(sys.peerClients))
for idx, client := range sys.peerClients {
idx := idx
@@ -152,7 +182,7 @@ func (sys *S3PeerSys) HealBucket(ctx context.Context, bucket string, opts madmin
}, idx)
}
errs := g.Wait()
errs = g.Wait()
for poolIdx := 0; poolIdx < sys.poolsCount; poolIdx++ {
perPoolErrs := make([]error, 0, len(sys.peerClients))
+1 -1
View File
@@ -165,7 +165,7 @@ func healBucketLocal(ctx context.Context, bucket string, opts madmin.HealOpts) (
return errDiskNotFound
}
err := globalLocalDrives[index].DeleteVol(ctx, bucket, false)
if errors.Is(err, errVolumeNotEmpty) {
if !errors.Is(err, errVolumeNotEmpty) {
logger.LogOnceIf(ctx, fmt.Errorf("While deleting dangling Bucket (%s), Drive %s:%s returned an error (%w)",
bucket, globalLocalDrives[index].Hostname(), globalLocalDrives[index], err), "delete-dangling-bucket-"+bucket)
}
+1 -1
View File
@@ -40,7 +40,7 @@ type fanOutOptions struct {
}
// fanOutPutObject takes an input source reader and fans out multiple PUT operations
// based on the incoming fan-out request, a context cancelation by the caller
// based on the incoming fan-out request, a context cancellation by the caller
// would ensure all fan-out operations are canceled.
func fanOutPutObject(ctx context.Context, bucket string, objectAPI ObjectLayer, fanOutEntries []minio.PutObjectFanOutEntry, fanOutBuf []byte, opts fanOutOptions) ([]ObjectInfo, []error) {
errs := make([]error, len(fanOutEntries))
+6 -6
View File
@@ -152,7 +152,7 @@ func testPostPolicyReservedBucketExploit(obj ObjectLayer, instanceType string, d
req.Header.Set("Content-Type", contentTypeHdr)
req.Header.Set("User-Agent", "Mozilla")
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
@@ -225,7 +225,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
if perr != nil {
t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", i+1, instanceType, perr)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
if rec.Code != test.expectedStatus {
@@ -284,7 +284,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
// Change the request body.
req.Body = io.NopCloser(bytes.NewReader([]byte("Hello,")))
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
if rec.Code != testCase.expectedRespStatus {
@@ -415,7 +415,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
if perr != nil {
t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", i+1, instanceType, perr)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
if rec.Code != testCase.expectedRespStatus {
@@ -487,7 +487,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
if perr != nil {
t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", i+1, instanceType, perr)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
if rec.Code != testCase.expectedRespStatus {
@@ -556,7 +556,7 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
if perr != nil {
t.Fatalf("%s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", instanceType, perr)
}
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
// Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler.
// Call the ServeHTTP to execute the handler.
apiRouter.ServeHTTP(rec, req)
+1 -1
View File
@@ -260,7 +260,7 @@ func parsePostPolicyForm(r io.Reader) (PostPolicyForm, error) {
return parsedPolicy, nil
}
// checkPolicyCond returns a boolean to indicate if a condition is satisified according
// checkPolicyCond returns a boolean to indicate if a condition is satisfied according
// to the passed operator
func checkPolicyCond(op string, input1, input2 string) bool {
switch op {
+2 -2
View File
@@ -95,7 +95,7 @@ var ServerFlags = []cli.Flag{
cli.DurationFlag{
Name: "idle-timeout",
Value: xhttp.DefaultIdleTimeout,
Usage: "idle timeout is the maximum amount of time to wait for the next request when keep-alives are enabled",
Usage: "idle timeout is the maximum amount of time to wait for the next request when keep-alive are enabled",
EnvVar: "MINIO_IDLE_TIMEOUT",
Hidden: true,
},
@@ -415,7 +415,7 @@ func initAllSubsystems(ctx context.Context) {
globalBucketVersioningSys = NewBucketVersioningSys()
}
// Create new bucket replication subsytem
// Create new bucket replication subsystem
globalBucketTargetSys = NewBucketTargetSys(GlobalContext)
// Create new ILM tier configuration subsystem
+1 -1
View File
@@ -199,7 +199,7 @@ func getReqAccessKeyV2(r *http.Request) (auth.Credentials, bool, APIErrorCode) {
return auth.Credentials{}, false, ErrMissingFields
}
// Then will be splitting on ":", this will seprate `AWSAccessKeyId` and `Signature` string.
// Then will be splitting on ":", this will separate `AWSAccessKeyId` and `Signature` string.
keySignFields := strings.Split(strings.TrimSpace(authFields[1]), ":")
if len(keySignFields) != 2 {
return auth.Credentials{}, false, ErrMissingFields
+2 -2
View File
@@ -161,7 +161,7 @@ type signValues struct {
Signature string
}
// preSignValues data type represents structued form of AWS Signature V4 query string.
// preSignValues data type represents structured form of AWS Signature V4 query string.
type preSignValues struct {
signValues
Date time.Time
@@ -248,7 +248,7 @@ func parsePreSignV4(query url.Values, region string, stype serviceType) (psv pre
return psv, aec
}
// Return structed form of signature query string.
// Return structured form of signature query string.
return preSignV4Values, ErrNone
}
+3 -3
View File
@@ -79,7 +79,7 @@ func validateCredentialfields(t *testing.T, testNum int, expectedCredentials cre
}
// TestParseCredentialHeader - validates the format validator and extractor for the Credential header in an aws v4 request.
// A valid format of creadential should be of the following format.
// A valid format of credential should be of the following format.
// Credential = accessKey + SlashSeparator+ scope
// where scope = string.Join([]string{ currTime.Format(yyyymmdd),
//
@@ -387,7 +387,7 @@ func TestParseSignV4(t *testing.T) {
},
// Test case - 5.
// Auth field with missing "SigHeaderTag",ErrMissingSignHeadersTag expected.
// A vaild credential is generated.
// A valid credential is generated.
// Test case with invalid credential field.
{
inputV4AuthStr: signV4Algorithm +
@@ -409,7 +409,7 @@ func TestParseSignV4(t *testing.T) {
},
// Test case - 6.
// Auth string with missing "SignatureTag",ErrMissingSignTag expected.
// A vaild credential is generated.
// A valid credential is generated.
// Test case with invalid credential field.
{
inputV4AuthStr: signV4Algorithm +
+1 -1
View File
@@ -206,7 +206,7 @@ func extractSignedHeaders(signedHeaders []string, r *http.Request) (http.Header,
extractedSignedHeaders := make(http.Header)
for _, header := range signedHeaders {
// `host` will not be found in the headers, can be found in r.Host.
// but its alway necessary that the list of signed headers containing host in it.
// but its always necessary that the list of signed headers containing host in it.
val, ok := reqHeaders[http.CanonicalHeaderKey(header)]
if !ok {
// try to set headers from Query String
+1 -1
View File
@@ -220,7 +220,7 @@ func TestDoesPresignedSignatureMatch(t *testing.T) {
expected: ErrRequestNotReadyYet,
},
// (7) Should not error with invalid region instead, call should proceed
// with sigature does not match.
// with signature does not match.
{
queryParams: map[string]string{
"X-Amz-Algorithm": signV4Algorithm,
+1 -1
View File
@@ -90,7 +90,7 @@ func (sm *siteResyncMetrics) init(ctx context.Context) {
}
duration := time.Duration(r.Float64() * float64(time.Second*10))
if duration < time.Second {
// Make sure to sleep atleast a second to avoid high CPU ticks.
// Make sure to sleep at least a second to avoid high CPU ticks.
duration = time.Second
}
time.Sleep(duration)
+2
View File
@@ -73,6 +73,8 @@ type DiskInfo struct {
type DiskMetrics struct {
LastMinute map[string]AccElem `json:"apiLatencies,omitempty"`
APICalls map[string]uint64 `json:"apiCalls,omitempty"`
TotalTokens uint32 `json:"totalTokens,omitempty"`
TotalWaiting uint32 `json:"totalWaiting,omitempty"`
TotalErrorsAvailability uint64 `json:"totalErrsAvailability"`
TotalErrorsTimeout uint64 `json:"totalErrsTimeout"`
TotalWrites uint64 `json:"totalWrites"`
+55 -5
View File
@@ -1327,6 +1327,18 @@ func (z *DiskMetrics) DecodeMsg(dc *msgp.Reader) (err error) {
}
z.APICalls[za0003] = za0004
}
case "TotalTokens":
z.TotalTokens, err = dc.ReadUint32()
if err != nil {
err = msgp.WrapError(err, "TotalTokens")
return
}
case "TotalWaiting":
z.TotalWaiting, err = dc.ReadUint32()
if err != nil {
err = msgp.WrapError(err, "TotalWaiting")
return
}
case "TotalErrorsAvailability":
z.TotalErrorsAvailability, err = dc.ReadUint64()
if err != nil {
@@ -1364,9 +1376,9 @@ func (z *DiskMetrics) DecodeMsg(dc *msgp.Reader) (err error) {
// EncodeMsg implements msgp.Encodable
func (z *DiskMetrics) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 6
// map header, size 8
// write "LastMinute"
err = en.Append(0x86, 0xaa, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65)
err = en.Append(0x88, 0xaa, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65)
if err != nil {
return
}
@@ -1409,6 +1421,26 @@ func (z *DiskMetrics) EncodeMsg(en *msgp.Writer) (err error) {
return
}
}
// write "TotalTokens"
err = en.Append(0xab, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73)
if err != nil {
return
}
err = en.WriteUint32(z.TotalTokens)
if err != nil {
err = msgp.WrapError(err, "TotalTokens")
return
}
// write "TotalWaiting"
err = en.Append(0xac, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67)
if err != nil {
return
}
err = en.WriteUint32(z.TotalWaiting)
if err != nil {
err = msgp.WrapError(err, "TotalWaiting")
return
}
// write "TotalErrorsAvailability"
err = en.Append(0xb7, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79)
if err != nil {
@@ -1455,9 +1487,9 @@ func (z *DiskMetrics) EncodeMsg(en *msgp.Writer) (err error) {
// MarshalMsg implements msgp.Marshaler
func (z *DiskMetrics) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 6
// map header, size 8
// string "LastMinute"
o = append(o, 0x86, 0xaa, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65)
o = append(o, 0x88, 0xaa, 0x4c, 0x61, 0x73, 0x74, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65)
o = msgp.AppendMapHeader(o, uint32(len(z.LastMinute)))
for za0001, za0002 := range z.LastMinute {
o = msgp.AppendString(o, za0001)
@@ -1474,6 +1506,12 @@ func (z *DiskMetrics) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.AppendString(o, za0003)
o = msgp.AppendUint64(o, za0004)
}
// string "TotalTokens"
o = append(o, 0xab, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73)
o = msgp.AppendUint32(o, z.TotalTokens)
// string "TotalWaiting"
o = append(o, 0xac, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67)
o = msgp.AppendUint32(o, z.TotalWaiting)
// string "TotalErrorsAvailability"
o = append(o, 0xb7, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79)
o = msgp.AppendUint64(o, z.TotalErrorsAvailability)
@@ -1567,6 +1605,18 @@ func (z *DiskMetrics) UnmarshalMsg(bts []byte) (o []byte, err error) {
}
z.APICalls[za0003] = za0004
}
case "TotalTokens":
z.TotalTokens, bts, err = msgp.ReadUint32Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "TotalTokens")
return
}
case "TotalWaiting":
z.TotalWaiting, bts, err = msgp.ReadUint32Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "TotalWaiting")
return
}
case "TotalErrorsAvailability":
z.TotalErrorsAvailability, bts, err = msgp.ReadUint64Bytes(bts)
if err != nil {
@@ -1619,7 +1669,7 @@ func (z *DiskMetrics) Msgsize() (s int) {
s += msgp.StringPrefixSize + len(za0003) + msgp.Uint64Size
}
}
s += 24 + msgp.Uint64Size + 19 + msgp.Uint64Size + 12 + msgp.Uint64Size + 13 + msgp.Uint64Size
s += 12 + msgp.Uint32Size + 13 + msgp.Uint32Size + 24 + msgp.Uint64Size + 19 + msgp.Uint64Size + 12 + msgp.Uint64Size + 13 + msgp.Uint64Size
return
}
+4 -26
View File
@@ -293,32 +293,17 @@ func (client *storageRESTClient) DiskInfo(ctx context.Context, metrics bool) (in
// MakeVolBulk - create multiple volumes in a bulk operation.
func (client *storageRESTClient) MakeVolBulk(ctx context.Context, volumes ...string) (err error) {
values := make(url.Values)
values.Set(storageRESTVolumes, strings.Join(volumes, ","))
respBody, err := client.call(ctx, storageRESTMethodMakeVolBulk, values, nil, -1)
defer xhttp.DrainBody(respBody)
return err
return errInvalidArgument
}
// MakeVol - create a volume on a remote disk.
func (client *storageRESTClient) MakeVol(ctx context.Context, volume string) (err error) {
values := make(url.Values)
values.Set(storageRESTVolume, volume)
respBody, err := client.call(ctx, storageRESTMethodMakeVol, values, nil, -1)
defer xhttp.DrainBody(respBody)
return err
return errInvalidArgument
}
// ListVols - List all volumes on a remote disk.
func (client *storageRESTClient) ListVols(ctx context.Context) (vols []VolInfo, err error) {
respBody, err := client.call(ctx, storageRESTMethodListVols, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
vinfos := VolsInfo(vols)
err = msgp.Decode(respBody, &vinfos)
return vinfos, err
return nil, errInvalidArgument
}
// StatVol - get volume info over the network.
@@ -337,14 +322,7 @@ func (client *storageRESTClient) StatVol(ctx context.Context, volume string) (vo
// DeleteVol - Deletes a volume over the network.
func (client *storageRESTClient) DeleteVol(ctx context.Context, volume string, forceDelete bool) (err error) {
values := make(url.Values)
values.Set(storageRESTVolume, volume)
if forceDelete {
values.Set(storageRESTForceDelete, "true")
}
respBody, err := client.call(ctx, storageRESTMethodDeleteVol, values, nil, -1)
defer xhttp.DrainBody(respBody)
return err
return errInvalidArgument
}
// AppendFile - append to a file.
+2 -6
View File
@@ -20,17 +20,13 @@ package cmd
//go:generate msgp -file $GOFILE -unexported
const (
storageRESTVersion = "v52" // Added DiskInfo drive signature
storageRESTVersion = "v54" // Add more metrics per drive
storageRESTVersionPrefix = SlashSeparator + storageRESTVersion
storageRESTPrefix = minioReservedBucketPath + "/storage"
)
const (
storageRESTMethodHealth = "/health"
storageRESTMethodMakeVol = "/makevol"
storageRESTMethodMakeVolBulk = "/makevolbulk"
storageRESTMethodDeleteVol = "/deletevol"
storageRESTMethodListVols = "/listvols"
storageRESTMethodHealth = "/health"
storageRESTMethodAppendFile = "/appendfile"
storageRESTMethodCreateFile = "/createfile"
+1 -19
View File
@@ -305,19 +305,6 @@ func (s *storageRESTServer) StatVolHandler(params *grid.MSS) (*VolInfo, *grid.Re
return &info, nil
}
// DeleteVolHandler - delete a volume.
func (s *storageRESTServer) DeleteVolHandler(w http.ResponseWriter, r *http.Request) {
if !s.IsValid(w, r) {
return
}
volume := r.Form.Get(storageRESTVolume)
forceDelete := r.Form.Get(storageRESTForceDelete) == "true"
err := s.getStorage().DeleteVol(r.Context(), volume, forceDelete)
if err != nil {
s.writeErrorResponse(w, err)
}
}
// AppendFileHandler - append data from the request to the file specified.
func (s *storageRESTServer) AppendFileHandler(w http.ResponseWriter, r *http.Request) {
if !s.IsValid(w, r) {
@@ -1201,7 +1188,7 @@ func checkDiskFatalErrs(errs []error) error {
// at each implementation of error for added hints.
//
// FIXME: This is an unusual function but serves its purpose for
// now, need to revist the overall erroring structure here.
// now, need to revisit the overall erroring structure here.
// Do not like it :-(
func logFatalErrs(err error, endpoint Endpoint, exit bool) {
switch {
@@ -1359,11 +1346,6 @@ func registerStorageRESTHandlers(router *mux.Router, endpointServerPools Endpoin
subrouter := router.PathPrefix(path.Join(storageRESTPrefix, endpoint.Path)).Subrouter()
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodHealth).HandlerFunc(h(server.HealthHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodMakeVol).HandlerFunc(h(server.MakeVolHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodMakeVolBulk).HandlerFunc(h(server.MakeVolBulkHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVol).HandlerFunc(h(server.DeleteVolHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListVols).HandlerFunc(h(server.ListVolsHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodAppendFile).HandlerFunc(h(server.AppendFileHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodWriteAll).HandlerFunc(h(server.WriteAllHandler))
+16 -176
View File
@@ -53,121 +53,8 @@ func testStorageAPIDiskInfo(t *testing.T, storage StorageAPI) {
}
}
func testStorageAPIMakeVol(t *testing.T, storage StorageAPI) {
testCases := []struct {
volumeName string
expectErr bool
}{
{"foo", false},
// volume exists error.
{"foo", true},
}
for i, testCase := range testCases {
err := storage.MakeVol(context.Background(), testCase.volumeName)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func testStorageAPIListVols(t *testing.T, storage StorageAPI) {
testCases := []struct {
volumeNames []string
expectedResult []VolInfo
expectErr bool
}{
{nil, []VolInfo{{Name: ".minio.sys"}}, false},
{[]string{"foo"}, []VolInfo{{Name: ".minio.sys"}, {Name: "foo"}}, false},
}
for i, testCase := range testCases {
for _, volumeName := range testCase.volumeNames {
err := storage.MakeVol(context.Background(), volumeName)
if err != nil {
t.Fatalf("unexpected error %v", err)
}
}
result, err := storage.ListVols(context.Background())
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if len(result) != len(testCase.expectedResult) {
t.Fatalf("case %v: result: expected: %+v, got: %+v", i+1, testCase.expectedResult, result)
}
}
}
}
func testStorageAPIStatVol(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
testCases := []struct {
volumeName string
expectErr bool
}{
{"foo", false},
// volume not found error.
{"bar", true},
}
for i, testCase := range testCases {
result, err := storage.StatVol(context.Background(), testCase.volumeName)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if result.Name != testCase.volumeName {
t.Fatalf("case %v: result: expected: %+v, got: %+v", i+1, testCase.volumeName, result.Name)
}
}
}
}
func testStorageAPIDeleteVol(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
testCases := []struct {
volumeName string
expectErr bool
}{
{"foo", false},
// volume not found error.
{"bar", true},
}
for i, testCase := range testCases {
err := storage.DeleteVol(context.Background(), testCase.volumeName, false)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
}
}
func testStorageAPIStatInfoFile(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", pathJoin("myobject", xlStorageFormatFile), []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", pathJoin("myobject", xlStorageFormatFile), []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -193,11 +80,7 @@ func testStorageAPIStatInfoFile(t *testing.T, storage StorageAPI) {
}
func testStorageAPIListDir(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", "path/to/myobject", []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", "path/to/myobject", []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -230,11 +113,7 @@ func testStorageAPIListDir(t *testing.T, storage StorageAPI) {
}
func testStorageAPIReadAll(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -267,11 +146,7 @@ func testStorageAPIReadAll(t *testing.T, storage StorageAPI) {
}
func testStorageAPIReadFile(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -308,11 +183,6 @@ func testStorageAPIReadFile(t *testing.T, storage StorageAPI) {
}
func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
testData := []byte("foo")
testCases := []struct {
volumeName string
@@ -324,7 +194,7 @@ func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) {
{"foo", "myobject", testData, false, false},
{"foo", "myobject-0byte", []byte{}, false, false},
// volume not found error.
{"bar", "myobject", testData, true, false},
{"foo-bar", "myobject", testData, true, false},
// Test some weird characters over the wire.
{"foo", "newline\n", testData, false, true},
{"foo", "newline\t", testData, false, true},
@@ -360,12 +230,7 @@ func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) {
}
func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -396,17 +261,7 @@ func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) {
}
func testStorageAPIRenameFile(t *testing.T, storage StorageAPI) {
err := storage.MakeVol(context.Background(), "foo")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.MakeVol(context.Background(), "bar")
if err != nil {
t.Fatalf("unexpected error %v", err)
}
err = storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
err := storage.AppendFile(context.Background(), "foo", "myobject", []byte("foo"))
if err != nil {
t.Fatalf("unexpected error %v", err)
}
@@ -484,6 +339,15 @@ func newStorageRESTHTTPServerClient(t testing.TB) *storageRESTClient {
registerStorageRESTHandlers(tg.Mux[0], poolEps, tg.Managers[0])
registerStorageRESTHandlers(tg.Mux[1], poolEps, tg.Managers[1])
storage := globalLocalSetDrives[0][0][0]
if err = storage.MakeVol(context.Background(), "foo"); err != nil {
t.Fatalf("unexpected error %v", err)
}
if err = storage.MakeVol(context.Background(), "bar"); err != nil {
t.Fatalf("unexpected error %v", err)
}
restClient, err := newStorageRESTClient(endpoint, false, tg.Managers[0])
if err != nil {
t.Fatal(err)
@@ -506,30 +370,6 @@ func TestStorageRESTClientDiskInfo(t *testing.T) {
testStorageAPIDiskInfo(t, restClient)
}
func TestStorageRESTClientMakeVol(t *testing.T) {
restClient := newStorageRESTHTTPServerClient(t)
testStorageAPIMakeVol(t, restClient)
}
func TestStorageRESTClientListVols(t *testing.T) {
restClient := newStorageRESTHTTPServerClient(t)
testStorageAPIListVols(t, restClient)
}
func TestStorageRESTClientStatVol(t *testing.T) {
restClient := newStorageRESTHTTPServerClient(t)
testStorageAPIStatVol(t, restClient)
}
func TestStorageRESTClientDeleteVol(t *testing.T) {
restClient := newStorageRESTHTTPServerClient(t)
testStorageAPIDeleteVol(t, restClient)
}
func TestStorageRESTClientStatInfoFile(t *testing.T) {
restClient := newStorageRESTHTTPServerClient(t)
+1 -1
View File
@@ -171,7 +171,7 @@ func calculateSeedSignature(r *http.Request, trailers bool) (cred auth.Credentia
return cred, "", "", time.Time{}, ErrSignatureDoesNotMatch
}
// Return caculated signature.
// Return calculated signature.
return cred, newSignature, region, date, ErrNone
}
+2 -2
View File
@@ -723,7 +723,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
// We have to establish a TLS connection and the
// client must provide exactly one client certificate.
// Otherwise, we don't have a certificate to verify or
// the policy lookup would ambigious.
// the policy lookup would ambiguous.
if r.TLS == nil {
writeSTSErrorResponse(ctx, w, ErrSTSInsecureConnection, errors.New("No TLS connection attempt"))
return
@@ -732,7 +732,7 @@ func (sts *stsAPIHandlers) AssumeRoleWithCertificate(w http.ResponseWriter, r *h
// A client may send a certificate chain such that we end up
// with multiple peer certificates. However, we can only accept
// a single client certificate. Otherwise, the certificate to
// policy mapping would be ambigious.
// policy mapping would be ambiguous.
// However, we can filter all CA certificates and only check
// whether they client has sent exactly one (non-CA) leaf certificate.
peerCertificates := make([]*x509.Certificate, 0, len(r.TLS.PeerCertificates))
+4 -4
View File
@@ -1511,7 +1511,7 @@ func removeRoots(roots []string) {
// creates a bucket for the tests and returns the bucket name.
// initializes the specified API endpoints for the tests.
// initialies the root and returns its path.
// initializes the root and returns its path.
// return credentials.
func initAPIHandlerTest(ctx context.Context, obj ObjectLayer, endpoints []string) (string, http.Handler, error) {
initAllSubsystems(ctx)
@@ -1660,7 +1660,7 @@ func ExecObjectLayerAPIAnonTest(t *testing.T, obj ObjectLayer, testName, bucketN
// expected error response when the unsigned HTTP request is not permitted.
unsupportedSignature := getAPIError(ErrSignatureVersionNotSupported).HTTPStatusCode
if rec.Code != unsupportedSignature {
t.Fatal(failTestStr(unknownSignTestStr, fmt.Sprintf("Object API Unknow auth test for \"%s\", expected to fail with %d, but failed with %d", testName, unsupportedSignature, rec.Code)))
t.Fatal(failTestStr(unknownSignTestStr, fmt.Sprintf("Object API Unknown auth test for \"%s\", expected to fail with %d, but failed with %d", testName, unsupportedSignature, rec.Code)))
}
}
@@ -1674,7 +1674,7 @@ func ExecObjectLayerAPINilTest(t TestErrHandler, bucketName, objectName, instanc
// httptest Recorder to capture all the response by the http handler.
rec := httptest.NewRecorder()
// The API handler gets the referece to the object layer via the global object Layer,
// The API handler gets the reference to the object layer via the global object Layer,
// setting it to `nil` in order test for handlers response for uninitialized object layer.
globalObjLayerMutex.Lock()
globalObjectAPI = nil
@@ -1757,7 +1757,7 @@ func ExecObjectLayerAPITest(t *testing.T, objAPITest objAPITestType, endpoints [
bucketErasure, erAPIRouter, err := initAPIHandlerTest(ctx, objLayer, endpoints)
if err != nil {
t.Fatalf("Initialzation of API handler tests failed: <ERROR> %s", err)
t.Fatalf("Initialization of API handler tests failed: <ERROR> %s", err)
}
// initialize the server and obtain the credentials and root.
+1 -1
View File
@@ -72,7 +72,7 @@ func NewTierJournal() *TierJournal {
return j
}
// Init intializes an in-memory journal built using a
// Init initializes an in-memory journal built using a
// buffered channel for new journal entries. It also initializes the on-disk
// journal only to process existing journal entries made from previous versions.
func (t *TierJournal) Init(ctx context.Context) error {
+1 -1
View File
@@ -99,7 +99,7 @@ var errNoSuchPolicy = errors.New("Specified canned policy does not exist")
var errPolicyInUse = errors.New("Specified policy is in use and cannot be deleted.")
// error returned when more than a single policy is specified when only one is
// expectd.
// expected.
var errTooManyPolicies = errors.New("Only a single policy may be specified here.")
// error returned in IAM subsystem when an external users systems is configured.
+1 -1
View File
@@ -292,7 +292,7 @@ func isMaxPartID(partID int) bool {
return partID > globalMaxPartID
}
// profilerWrapper is created becauses pkg/profiler doesn't
// profilerWrapper is created because pkg/profiler doesn't
// provide any API to calculate the profiler file path in the
// disk since the name of this latter is randomly generated.
type profilerWrapper struct {
+1 -1
View File
@@ -38,7 +38,7 @@ var _ WarmBackend = (*warmBackendMinIO)(nil)
func newWarmBackendMinIO(conf madmin.TierMinIO, tier string) (*warmBackendMinIO, error) {
// Validation of credentials
if conf.AccessKey == "" || conf.SecretKey == "" {
return nil, errors.New("both access and secret keys are requied")
return nil, errors.New("both access and secret keys are required")
}
if conf.Bucket == "" {
+48 -45
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2015-2021 MinIO, Inc.
// Copyright (c) 2015-2024 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
@@ -90,13 +90,13 @@ type xlStorageDiskIDCheck struct {
storage *xlStorage
health *diskHealthTracker
// diskStartChecking is a threshold above which we will start to check
// the state of disks, generally this value is less than diskMaxConcurrent
diskStartChecking int
// driveStartChecking is a threshold above which we will start to check
// the state of disks, generally this value is less than driveMaxConcurrent
driveStartChecking int
// diskMaxConcurrent represents maximum number of running concurrent
// driveMaxConcurrent represents maximum number of running concurrent
// operations for local and (incoming) remote disk operations.
diskMaxConcurrent int
driveMaxConcurrent int
metricsCache timedValue
diskCtx context.Context
@@ -127,8 +127,11 @@ func (p *xlStorageDiskIDCheck) getMetrics() DiskMetrics {
}
// Do not need this value to be cached.
diskMetric.TotalTokens = uint32(p.driveMaxConcurrent)
diskMetric.TotalWaiting = uint32(p.health.waiting.Load())
diskMetric.TotalErrorsTimeout = p.totalErrsTimeout.Load()
diskMetric.TotalErrorsAvailability = p.totalErrsAvailability.Load()
return diskMetric
}
@@ -189,42 +192,42 @@ func (e *lockedLastMinuteLatency) total() AccElem {
var maxConcurrentOnce sync.Once
func newXLStorageDiskIDCheck(storage *xlStorage, healthCheck bool) *xlStorageDiskIDCheck {
// diskMaxConcurrent represents maximum number of running concurrent
// driveMaxConcurrent represents maximum number of running concurrent
// operations for local and (incoming) remote disk operations.
//
// this value is a placeholder it is overridden via ENV for custom settings
// or this default value is used to pick the correct value HDDs v/s NVMe's
diskMaxConcurrent := -1
driveMaxConcurrent := -1
maxConcurrentOnce.Do(func() {
s := env.Get("_MINIO_DRIVE_MAX_CONCURRENT", "")
if s == "" {
s = env.Get("_MINIO_DISK_MAX_CONCURRENT", "")
}
if s != "" {
diskMaxConcurrent, _ = strconv.Atoi(s)
driveMaxConcurrent, _ = strconv.Atoi(s)
}
})
if diskMaxConcurrent <= 0 {
diskMaxConcurrent = 512
if driveMaxConcurrent <= 0 {
driveMaxConcurrent = 512
if storage.rotational {
diskMaxConcurrent = int(storage.nrRequests) / 2
if diskMaxConcurrent < 32 {
diskMaxConcurrent = 32
driveMaxConcurrent = int(storage.nrRequests) / 2
if driveMaxConcurrent < 32 {
driveMaxConcurrent = 32
}
}
}
diskStartChecking := 16 + diskMaxConcurrent/8
if diskStartChecking > diskMaxConcurrent {
diskStartChecking = diskMaxConcurrent
driveStartChecking := 16 + driveMaxConcurrent/8
if driveStartChecking > driveMaxConcurrent {
driveStartChecking = driveMaxConcurrent
}
xl := xlStorageDiskIDCheck{
storage: storage,
health: newDiskHealthTracker(diskMaxConcurrent),
diskMaxConcurrent: diskMaxConcurrent,
diskStartChecking: diskStartChecking,
storage: storage,
health: newDiskHealthTracker(driveMaxConcurrent),
driveMaxConcurrent: driveMaxConcurrent,
driveStartChecking: driveStartChecking,
}
if driveQuorum {
@@ -347,6 +350,8 @@ func (p *xlStorageDiskIDCheck) DiskInfo(ctx context.Context, metrics bool) (info
info.Metrics.TotalWrites = p.totalWrites.Load()
info.Metrics.TotalDeletes = p.totalDeletes.Load()
}
info.Metrics.TotalTokens = uint32(p.driveMaxConcurrent)
info.Metrics.TotalWaiting = uint32(p.health.waiting.Load())
info.Metrics.TotalErrorsTimeout = p.totalErrsTimeout.Load()
info.Metrics.TotalErrorsAvailability = p.totalErrsAvailability.Load()
}()
@@ -842,7 +847,7 @@ func (p *xlStorageDiskIDCheck) updateStorageMetrics(s storageMetric, paths ...st
}
const (
diskHealthOK = iota
diskHealthOK int32 = iota
diskHealthFaulty
)
@@ -867,24 +872,24 @@ type diskHealthTracker struct {
lastStarted int64
// Atomic status of disk.
status int32
status atomic.Int32
// Atomic number of requests blocking for a token.
blocked int32
// Atomic number of requests waiting for a token.
waiting atomic.Int32
// Concurrency tokens.
tokens chan struct{}
}
// newDiskHealthTracker creates a new disk health tracker.
func newDiskHealthTracker(diskMaxConcurrent int) *diskHealthTracker {
func newDiskHealthTracker(driveMaxConcurrent int) *diskHealthTracker {
d := diskHealthTracker{
lastSuccess: time.Now().UnixNano(),
lastStarted: time.Now().UnixNano(),
status: diskHealthOK,
tokens: make(chan struct{}, diskMaxConcurrent),
tokens: make(chan struct{}, driveMaxConcurrent),
}
for i := 0; i < diskMaxConcurrent; i++ {
d.status.Store(diskHealthOK)
for i := 0; i < driveMaxConcurrent; i++ {
d.tokens <- struct{}{}
}
return &d
@@ -896,7 +901,7 @@ func (d *diskHealthTracker) logSuccess() {
}
func (d *diskHealthTracker) isFaulty() bool {
return atomic.LoadInt32(&d.status) == diskHealthFaulty
return d.status.Load() == diskHealthFaulty
}
type (
@@ -982,10 +987,9 @@ func (p *xlStorageDiskIDCheck) TrackDiskHealth(ctx context.Context, s storageMet
// checking the disk status.
// If nil is returned a token was picked up.
func (p *xlStorageDiskIDCheck) waitForToken(ctx context.Context) (err error) {
atomic.AddInt32(&p.health.blocked, 1)
defer func() {
atomic.AddInt32(&p.health.blocked, -1)
}()
p.health.waiting.Add(1)
defer p.health.waiting.Add(-1)
// Avoid stampeding herd...
ticker := time.NewTicker(5*time.Second + time.Duration(rand.Int63n(int64(5*time.Second))))
defer ticker.Stop()
@@ -1008,11 +1012,11 @@ func (p *xlStorageDiskIDCheck) waitForToken(ctx context.Context) (err error) {
// checkHealth should only be called when tokens have run out.
// This will check if disk should be taken offline.
func (p *xlStorageDiskIDCheck) checkHealth(ctx context.Context) (err error) {
if atomic.LoadInt32(&p.health.status) == diskHealthFaulty {
if p.health.status.Load() == diskHealthFaulty {
return errFaultyDisk
}
// Check if there are tokens.
if p.diskMaxConcurrent-len(p.health.tokens) < p.diskStartChecking {
if p.driveMaxConcurrent-len(p.health.tokens) < p.driveStartChecking {
return nil
}
@@ -1030,8 +1034,9 @@ func (p *xlStorageDiskIDCheck) checkHealth(ctx context.Context) (err error) {
// If also more than 15 seconds since last success, take disk offline.
t = time.Since(time.Unix(0, atomic.LoadInt64(&p.health.lastSuccess)))
if t > maxTimeSinceLastSuccess {
if atomic.CompareAndSwapInt32(&p.health.status, diskHealthOK, diskHealthFaulty) {
if p.health.status.CompareAndSwap(diskHealthOK, diskHealthFaulty) {
logger.LogAlwaysIf(ctx, fmt.Errorf("node(%s): taking drive %s offline, time since last response %v", globalLocalNodeName, p.storage.String(), t.Round(time.Millisecond)))
p.health.waiting.Add(1)
go p.monitorDiskStatus(0, mustGetUUID())
}
return errFaultyDisk
@@ -1077,12 +1082,9 @@ func (p *xlStorageDiskIDCheck) monitorDiskStatus(spent time.Duration, fn string)
})
if err == nil {
t := time.Unix(0, atomic.LoadInt64(&p.health.lastSuccess))
if spent > 0 {
t = t.Add(spent)
}
logger.Info("node(%s): Read/Write/Delete successful, bringing drive %s online. Drive was offline for %s.", globalLocalNodeName, p.storage.String(), time.Since(t))
atomic.StoreInt32(&p.health.status, diskHealthOK)
logger.Info("node(%s): Read/Write/Delete successful, bringing drive %s online", globalLocalNodeName, p.storage.String())
p.health.status.Store(diskHealthOK)
p.health.waiting.Add(-1)
return
}
}
@@ -1128,7 +1130,7 @@ func (p *xlStorageDiskIDCheck) monitorDiskWritable(ctx context.Context) {
return false
}
if atomic.LoadInt32(&p.health.status) != diskHealthOK {
if p.health.status.Load() != diskHealthOK {
return true
}
@@ -1138,8 +1140,9 @@ func (p *xlStorageDiskIDCheck) monitorDiskWritable(ctx context.Context) {
}
goOffline := func(err error, spent time.Duration) {
if atomic.CompareAndSwapInt32(&p.health.status, diskHealthOK, diskHealthFaulty) {
if p.health.status.CompareAndSwap(diskHealthOK, diskHealthFaulty) {
logger.LogAlwaysIf(ctx, fmt.Errorf("node(%s): taking drive %s offline: %v", globalLocalNodeName, p.storage.String(), err))
p.health.waiting.Add(1)
go p.monitorDiskStatus(spent, fn)
}
}
+1 -1
View File
@@ -770,7 +770,7 @@ func readXLMetaNoData(r io.Reader, size int64) ([]byte, error) {
case 1, 2, 3:
sz, tmp, err := msgp.ReadBytesHeader(tmp)
if err != nil {
return nil, fmt.Errorf("readXLMetaNoData(read_meta): uknown metadata version %w", err)
return nil, fmt.Errorf("readXLMetaNoData(read_meta): unknown metadata version %w", err)
}
want := int64(sz) + int64(len(buf)-len(tmp))
+23 -8
View File
@@ -213,6 +213,21 @@ func newLocalXLStorage(path string) (*xlStorage, error) {
}, true)
}
// Make Erasure backend meta volumes.
func makeFormatErasureMetaVolumes(disk StorageAPI) error {
if disk == nil {
return errDiskNotFound
}
volumes := []string{
minioMetaTmpDeletedBucket, // creates .minio.sys/tmp as well as .minio.sys/tmp/.trash
minioMetaMultipartBucket, // creates .minio.sys/multipart
dataUsageBucket, // creates .minio.sys/buckets
minioConfigBucket, // creates .minio.sys/config
}
// Attempt to create MinIO internal buckets.
return disk.MakeVolBulk(context.TODO(), volumes...)
}
// Initialize a new storage disk.
func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
path := ep.Path
@@ -279,12 +294,12 @@ func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
s.formatFileInfo = formatFi
s.formatFile = pathJoin(s.drivePath, minioMetaBucket, formatConfigFile)
if len(s.formatData) == 0 {
// Create all necessary bucket folders if possible.
if err = makeFormatErasureMetaVolumes(s); err != nil {
return nil, err
}
} else {
// Create all necessary bucket folders if possible.
if err = makeFormatErasureMetaVolumes(s); err != nil {
return nil, err
}
if len(s.formatData) > 0 {
format := &formatErasureV3{}
json := jsoniter.ConfigCompatibleWithStandardLibrary
if err = json.Unmarshal(s.formatData, &format); err != nil {
@@ -2228,7 +2243,7 @@ func (s *xlStorage) deleteFile(basePath, deletePath string, recursive, immediate
if runtime.GOOS == globalMacOSName {
storeFilePath := pathJoin(deletePath, ".DS_Store")
_, err := Stat(storeFilePath)
// .DS_Store exsits
// .DS_Store exists
if err == nil {
// delete first
Remove(storeFilePath)
@@ -2439,7 +2454,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f
formatLegacy := s.formatLegacy
s.RUnlock()
// It is possible that some drives may not have `xl.meta` file
// in such scenarios verify if atleast `part.1` files exist
// in such scenarios verify if at least `part.1` files exist
// to verify for legacy version.
if formatLegacy {
// We only need this code if we are moving
+5 -5
View File
@@ -1200,7 +1200,7 @@ func TestXLStorageReadFile(t *testing.T) {
if err == nil && err != testCase.expectedErr {
t.Errorf("Case: %d %#v, expected: %s, got :%s", i+1, testCase, testCase.expectedErr, err)
}
// Expected error retured, proceed further to validate the returned results.
// Expected error returned, proceed further to validate the returned results.
if err != nil && testCase.expectedErr == nil {
t.Errorf("Case: %d %#v, expected: %s, got :%s", i+1, testCase, testCase.expectedErr, err)
}
@@ -1404,7 +1404,7 @@ func TestXLStorageAppendFile(t *testing.T) {
}
// TestXLStorage case with invalid volume name.
// A valid volume name should be atleast of size 3.
// A valid volume name should be at least of size 3.
err = xlStorage.AppendFile(context.Background(), "bn", "yes", []byte("hello, world"))
if err != errVolumeNotFound {
t.Fatalf("expected: \"Invalid argument error\", got: \"%s\"", err)
@@ -1560,7 +1560,7 @@ func TestXLStorageRenameFile(t *testing.T) {
expectedErr: errVolumeNotFound,
},
// TestXLStorage case - 12.
// TestXLStorage case with invalid src volume name. Length should be atleast 3.
// TestXLStorage case with invalid src volume name. Length should be at least 3.
// Expecting to fail with `errInvalidArgument`.
{
srcVol: "ab",
@@ -1570,7 +1570,7 @@ func TestXLStorageRenameFile(t *testing.T) {
expectedErr: errVolumeNotFound,
},
// TestXLStorage case - 13.
// TestXLStorage case with invalid destination volume name. Length should be atleast 3.
// TestXLStorage case with invalid destination volume name. Length should be at least 3.
// Expecting to fail with `errInvalidArgument`.
{
srcVol: "abcd",
@@ -1580,7 +1580,7 @@ func TestXLStorageRenameFile(t *testing.T) {
expectedErr: errVolumeNotFound,
},
// TestXLStorage case - 14.
// TestXLStorage case with invalid destination volume name. Length should be atleast 3.
// TestXLStorage case with invalid destination volume name. Length should be at least 3.
// Expecting to fail with `errInvalidArgument`.
{
srcVol: "abcd",
+1 -1
View File
@@ -857,7 +857,7 @@ When the _access_ format is used, MinIO appends events to a table. It creates ro
The steps below show how to use this notification target in `namespace` format. The other format is very similar and is omitted for brevity.
### Step 1: Ensure PostgresSQL minimum requirements are met
### Step 1: Ensure postgresql minimum requirements are met
MinIO requires PostgreSQL version 9.5 or above. MinIO uses the [`INSERT ON CONFLICT`](https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT) (aka UPSERT) feature, introduced in version 9.5 and the [JSONB](https://www.postgresql.org/docs/9.4/static/datatype-json.html) data-type introduced in version 9.4.
@@ -45,8 +45,11 @@ go install github.com/minio/minio/docs/debugging/s3-check-md5@latest
wget -O mc https://dl.minio.io/client/mc/release/linux-amd64/mc &&
chmod +x mc
wget -O mc.RELEASE.2021-03-12T03-36-59Z https://dl.minio.io/client/mc/release/linux-amd64/archive/mc.RELEASE.2021-03-12T03-36-59Z &&
chmod +x mc.RELEASE.2021-03-12T03-36-59Z
if [ ! -f mc.RELEASE.2021-03-12T03-36-59Z ]; then
wget -O mc.RELEASE.2021-03-12T03-36-59Z https://dl.minio.io/client/mc/release/linux-amd64/archive/mc.RELEASE.2021-03-12T03-36-59Z &&
chmod +x mc.RELEASE.2021-03-12T03-36-59Z
fi
minio server --address 127.0.0.1:9001 "http://127.0.0.1:9001/tmp/multisitea/data/disterasure/xl{1...4}" \
"http://127.0.0.1:9002/tmp/multisitea/data/disterasure/xl{5...8}" >/tmp/sitea_1.log 2>&1 &
@@ -209,4 +212,28 @@ s3-check-md5 -versions -access-key minio -secret-key minio123 -endpoint http://1
s3-check-md5 -versions -access-key minio -secret-key minio123 -endpoint http://127.0.0.1:9005/ -bucket olockbucket
s3-check-md5 -versions -access-key minio -secret-key minio123 -endpoint http://127.0.0.1:9006/ -bucket olockbucket
# additional tests for encryption object alignment
go install -v github.com/minio/multipart-debug@latest
upload_id=$(multipart-debug --endpoint 127.0.0.1:9001 --accesskey minio --secretkey minio123 multipart new --bucket bucket --object new-test-encrypted-object --encrypt)
dd if=/dev/urandom bs=1 count=7048531 of=/tmp/7048531.txt
dd if=/dev/urandom bs=1 count=2847391 of=/tmp/2847391.txt
sudo apt install jq -y
etag_1=$(multipart-debug --endpoint 127.0.0.1:9002 --accesskey minio --secretkey minio123 multipart upload --bucket bucket --object new-test-encrypted-object --uploadid ${upload_id} --file /tmp/7048531.txt --number 1 | jq -r .ETag)
etag_2=$(multipart-debug --endpoint 127.0.0.1:9001 --accesskey minio --secretkey minio123 multipart upload --bucket bucket --object new-test-encrypted-object --uploadid ${upload_id} --file /tmp/2847391.txt --number 2 | jq -r .ETag)
multipart-debug --endpoint 127.0.0.1:9002 --accesskey minio --secretkey minio123 multipart complete --bucket bucket --object new-test-encrypted-object --uploadid ${upload_id} 1.${etag_1} 2.${etag_2}
sleep 10
./mc stat sitea/bucket/new-test-encrypted-object
./mc stat siteb/bucket/new-test-encrypted-object
./mc stat sitec/bucket/new-test-encrypted-object
./mc ls -r sitea/bucket/
./mc ls -r siteb/bucket/
./mc ls -r sitec/bucket/
catch
@@ -234,7 +234,7 @@ fi
## Check replication of deleted ILM expiry rules
./mc ilm rule remove --id "${id}" sitea/bucket
sleep 30
# should error as rule doesnt exist
# should error as rule doesn't exist
error=$(./mc ilm rule list siteb/bucket --json | jq '.error.cause.message' | sed 's/"//g')
if [ "$error" != "The lifecycle configuration does not exist" ]; then
echo "BUG: Removed ILM expiry rule not replicated to 'siteb'"
+1 -1
View File
@@ -56,7 +56,7 @@ func getMountMap() (map[string]string, error) {
for scanner.Scan() {
s := strings.Split(scanner.Text(), " ")
if len(s) != 11 {
return nil, errors.New("unsupport /proc/self/mountinfo format")
return nil, errors.New("unsupported /proc/self/mountinfo format")
}
result[s[2]] = s[9]
}
+26 -27
View File
@@ -67,8 +67,9 @@ FLAGS:
app.Flags = []cli.Flag{
cli.BoolFlag{
Usage: "print each file as a separate line without formatting",
Name: "ndjson",
Usage: "print each file as a separate line without formatting",
Name: "ndjson",
Hidden: true,
},
cli.BoolFlag{
Usage: "display inline data keys and sizes",
@@ -286,13 +287,11 @@ FLAGS:
if len(files) == 0 {
return fmt.Errorf("no files found")
}
multiple := len(files) > 1 || strings.HasSuffix(files[0], ".zip")
if multiple {
if len(files) > 1 || strings.HasSuffix(files[0], ".zip") {
ndjson = true
fmt.Println("{")
}
hasWritten := false
toPrint := make([]string, 0, 16)
for _, file := range files {
var r io.Reader
var sz int64
@@ -323,42 +322,42 @@ FLAGS:
}
// Quote string...
b, _ := json.Marshal(file.Name)
if hasWritten {
fmt.Print(",\n")
}
fmt.Printf("\t%s: ", string(b))
b, err = decode(r, file.Name)
b2, err := decode(r, file.Name)
if err != nil {
return err
}
fmt.Print(string(b))
hasWritten = true
var tmp map[string]interface{}
if err := json.Unmarshal(b2, &tmp); err == nil {
if b3, err := json.Marshal(tmp); err == nil {
b2 = b3
}
}
toPrint = append(toPrint, fmt.Sprintf("\t%s: %s", string(b), string(b2)))
}
}
} else {
if multiple {
// Quote string...
b0 := ""
if ndjson {
b, _ := json.Marshal(file)
if hasWritten {
fmt.Print(",\n")
}
fmt.Printf("\t%s: ", string(b))
b0 = fmt.Sprintf("%s: ", string(b))
}
b, err := decode(r, file)
if err != nil {
return err
}
b = bytes.TrimSpace(b)
if !ndjson {
b = bytes.TrimFunc(b, func(r rune) bool {
return r == '{' || r == '}' || r == '\n' || r == '\r'
})
}
hasWritten = true
fmt.Print(string(b))
toPrint = append(toPrint, fmt.Sprintf("%s%s", b0, string(b)))
}
}
fmt.Println("")
if multiple {
fmt.Println("}")
}
sort.Strings(toPrint)
fmt.Printf("{\n%s\n}\n", strings.Join(toPrint, ",\n"))
if len(combineFiles) > 0 {
for k, v := range combineFiles {
if err := combine(v, k); err != nil {
+3 -3
View File
@@ -4,7 +4,7 @@ MinIO now supports starting the server arguments and configuration via a YAML co
Historically everything to MinIO was provided via command arguments for the hostnames and the drives via an ellipses syntax such as `minio server http://host{1...4}/disk{1...4}` this requirement added an additional burden to have sequential hostnames for us to make sure that we can provide horizontal distribution, however we have come across situations where sometimes this is not feasible and there are no easier alternatives without modifying /etc/hosts on the host system as root user. Many times in airgapped deployments this is not allowed or requires audits and approvals.
MinIO server configuration file allows users to provide topology that allows for heterogenous hostnames, allowing MinIO to deployed in pre-existing environments without any further OS level configurations.
MinIO server configuration file allows users to provide topology that allows for heterogeneous hostnames, allowing MinIO to deployed in pre-existing environments without any further OS level configurations.
### Usage
@@ -12,7 +12,7 @@ MinIO server configuration file allows users to provide topology that allows for
minio server --config config.yaml
```
Lets you start MinIO server with all inputs to start MinIO server provided via this configuration file, once the configuration file is provided all other pre-existing values on disk for configuration are overriden by the new values set in this configuration file.
Lets you start MinIO server with all inputs to start MinIO server provided via this configuration file, once the configuration file is provided all other pre-existing values on disk for configuration are overridden by the new values set in this configuration file.
Following is an example YAML configuration structure.
```
@@ -53,7 +53,7 @@ options:
- Mixing `local-path` and `distributed-path` is not allowed, doing so would cause MinIO to refuse starting the server.
- Ellipses notation (e.g. `{1...10}`) or bracket notations are fully allowed (e.g. `{a,c,f}`) to have multiple entries in one line.
> NOTE: MinIO environmental variables still take precedence over the `config.yaml` file, however `config.yaml` is preffered over MinIO internal config KV settings via `mc admin config set alias/ <sub-system>`.
> NOTE: MinIO environmental variables still take precedence over the `config.yaml` file, however `config.yaml` is preferred over MinIO internal config KV settings via `mc admin config set alias/ <sub-system>`.
### TODO
+1 -1
View File
@@ -26,7 +26,7 @@ MinIO follows strict **read-after-write** and **list-after-write** consistency m
**In our tests we also found ext4 does not honor POSIX O_DIRECT/Fdatasync semantics, ext4 trades performance for consistency guarantees. Please avoid ext4 in your setup.**
**If MinIO distributed setup is using NFS volumes underneath it is not guaranteed MinIO will provide these consistency guarantees since NFS is not strictly consistent (If you must use NFS we recommend that you atleast use NFSv4 instead of NFSv3 for relatively better outcomes).**
**If MinIO distributed setup is using NFS volumes underneath it is not guaranteed MinIO will provide these consistency guarantees since NFS is not strictly consistent (If you must use NFS we recommend that you at least use NFSv4 instead of NFSv3 for relatively better outcomes).**
## Get started
+14 -6
View File
@@ -21,7 +21,7 @@ export MINIO_KMS_AUTO_ENCRYPTION=on
export MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw=
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
pid=$!
sleep 30
@@ -52,8 +52,11 @@ policy_count=$(./mc admin policy list myminio/ | wc -l)
kill $pid
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
pid=$!
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_1.log) &
pid_1=$!
(minio server --address ":9001" http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_2.log) &
pid_2=$!
sleep 30
@@ -82,20 +85,25 @@ fi
./mc ls -r myminio/versioned/ >expanded_ns.txt
./mc ls -r --versions myminio/versioned/ >expanded_ns_versions.txt
./mc admin decom start myminio/ /tmp/xl/{1...10}/disk{0...1}
./mc admin decom start myminio/ http://localhost:9000/tmp/xl/{1...10}/disk{0...1}
until $(./mc admin decom status myminio/ | grep -q Complete); do
echo "waiting for decom to finish..."
sleep 1
done
kill $pid
kill $pid_1
kill $pid_2
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
sleep 5
(minio server --address ":9001" http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
pid=$!
sleep 30
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9001/"
decom_user_count=$(./mc admin user list myminio/ | wc -l)
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
+14 -6
View File
@@ -16,7 +16,7 @@ export CI=true
export MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw=
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9000/"
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
pid=$!
sleep 30
@@ -49,8 +49,11 @@ policy_count=$(./mc admin policy list myminio/ | wc -l)
kill $pid
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
pid=$!
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_1.log) &
pid_1=$!
(minio server --address ":9001" http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_2.log) &
pid_2=$!
sleep 30
@@ -86,20 +89,25 @@ fi
./mc ls -r myminio/versioned/ >expanded_ns.txt
./mc ls -r --versions myminio/versioned/ >expanded_ns_versions.txt
./mc admin decom start myminio/ /tmp/xl/{1...10}/disk{0...1}
./mc admin decom start myminio/ http://localhost:9000/tmp/xl/{1...10}/disk{0...1}
until $(./mc admin decom status myminio/ | grep -q Complete); do
echo "waiting for decom to finish..."
sleep 1
done
kill $pid
kill $pid_1
kill $pid_2
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
sleep 5
(minio server --address ":9001" http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
pid=$!
sleep 30
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9001/"
decom_user_count=$(./mc admin user list myminio/ | wc -l)
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
+15 -6
View File
@@ -16,7 +16,7 @@ export CI=true
export MINIO_KMS_AUTO_ENCRYPTION=on
export MINIO_KMS_SECRET_KEY=my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw=
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} 2>&1 >/dev/null) &
pid=$!
sleep 30
@@ -48,8 +48,12 @@ user_count=$(./mc admin user list myminio/ | wc -l)
policy_count=$(./mc admin policy list myminio/ | wc -l)
kill $pid
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
pid=$!
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_1.log) &
pid_1=$!
(minio server --address ":9001" http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_2.log) &
pid_2=$!
sleep 30
@@ -78,20 +82,25 @@ fi
./mc ls -r myminio/versioned/ >expanded_ns.txt
./mc ls -r --versions myminio/versioned/ >expanded_ns_versions.txt
./mc admin decom start myminio/ /tmp/xl/{1...10}/disk{0...1}
./mc admin decom start myminio/ http://localhost:9000/tmp/xl/{1...10}/disk{0...1}
until $(./mc admin decom status myminio/ | grep -q Complete); do
echo "waiting for decom to finish..."
sleep 1
done
kill $pid
kill $pid_1
kill $pid_2
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/dev/null) &
sleep 5
(minio server --address ":9001" http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
pid=$!
sleep 30
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9001/"
decom_user_count=$(./mc admin user list myminio/ | wc -l)
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
+19 -10
View File
@@ -16,7 +16,7 @@ fi
export CI=true
export MINIO_SCANNER_SPEED=fastest
(minio server /tmp/xl/{1...10}/disk{0...1} 2>&1 >/tmp/decom.log) &
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} 2>&1 >/tmp/decom.log) &
pid=$!
sleep 30
@@ -48,16 +48,16 @@ user_count=$(./mc admin user list myminio/ | wc -l)
policy_count=$(./mc admin policy list myminio/ | wc -l)
## create a warm tier instance
(minio server /tmp/xltier/{1...4}/disk{0...1} --address :9001 2>&1 >/dev/null) &
(minio server /tmp/xltier/{1...4}/disk{0...1} --address :9002 2>&1 >/dev/null) &
sleep 30
export MC_HOST_mytier="http://minioadmin:minioadmin@localhost:9001/"
export MC_HOST_mytier="http://minioadmin:minioadmin@localhost:9002/"
./mc mb -l myminio/bucket2
./mc mb -l mytier/tiered
## create a tier and set up ilm policy to tier immediately
./mc admin tier add minio myminio TIER1 --endpoint http://localhost:9001 --access-key minioadmin --secret-key minioadmin --bucket tiered --prefix prefix5/
./mc admin tier add minio myminio TIER1 --endpoint http://localhost:9002 --access-key minioadmin --secret-key minioadmin --bucket tiered --prefix prefix5/
./mc ilm add myminio/bucket2 --transition-days 0 --transition-tier TIER1 --transition-days 0
## mirror some content to bucket2 and capture versions tiered
@@ -70,8 +70,12 @@ sleep 30
./mc ls -r --versions mytier/tiered/ >tiered_ns_versions.txt
kill $pid
(minio server /tmp/xl/{1...10}/disk{0...1} /tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded.log) &
pid=$!
(minio server http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_1.log) &
pid_1=$!
(minio server --address ":9001" http://localhost:9000/tmp/xl/{1...10}/disk{0...1} http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/expanded_2.log) &
pid_2=$!
sleep 30
@@ -100,25 +104,30 @@ fi
./mc ls -r myminio/versioned/ >expanded_ns.txt
./mc ls -r --versions myminio/versioned/ >expanded_ns_versions.txt
./mc admin decom start myminio/ /tmp/xl/{1...10}/disk{0...1}
./mc admin decom start myminio/ http://localhost:9000/tmp/xl/{1...10}/disk{0...1}
count=0
until $(./mc admin decom status myminio/ | grep -q Complete); do
echo "waiting for decom to finish..."
count=$((count + 1))
if [ ${count} -eq 120 ]; then
./mc cat /tmp/expanded.log
./mc cat /tmp/expanded_*.log
fi
sleep 1
done
kill $pid
kill $pid_1
kill $pid_2
(minio server /tmp/xl/{11...30}/disk{0...3} 2>&1 >/dev/null) &
sleep 5
(minio server --address ":9001" http://localhost:9001/tmp/xl/{11...30}/disk{0...3} 2>&1 >/tmp/removed.log) &
pid=$!
sleep 30
export MC_HOST_myminio="http://minioadmin:minioadmin@localhost:9001/"
decom_user_count=$(./mc admin user list myminio/ | wc -l)
decom_policy_count=$(./mc admin policy list myminio/ | wc -l)
@@ -80,7 +80,7 @@ if [ "${expected_checksum}" != "${actual_checksum}" ]; then
exit
fi
# Compare the difference of the list of disks and their location, with the below exected output
# Compare the difference of the list of disks and their location, with the below expected output
diff <(./mc admin info minio1 --json | jq -r '.info.servers[].drives[] | "\(.pool_index),\(.set_index),\(.disk_index) \(.endpoint)"' | sort) <(
cat <<EOF
0,0,0 http://localhost:9001/tmp/xl/node9001/mnt/disk1

Some files were not shown because too many files have changed in this diff Show More