mirror of
https://github.com/pgsty/minio.git
synced 2026-11-08 00:31:54 +03:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f56a182b71 | |||
| 317b40ef90 | |||
| e938ece492 | |||
| 02331a612c | |||
| 8317557f70 | |||
| 1bb7a2a295 | |||
| 215ca58d6a | |||
| 12f570a307 | |||
| e4b619ce1a | |||
| 0a286153bb | |||
| 22d59e757d | |||
| 0daa2dbf59 | |||
| 96c2304ae8 | |||
| 343dd2f491 | |||
| 38f35463b7 | |||
| 5573986e8e | |||
| f3367a1b20 | |||
| a3c2f7b0e8 | |||
| 8fbec30998 | |||
| a7466eeb0e | |||
| 8b1e819bf3 | |||
| fe63664164 | |||
| 4598827dcb | |||
| 9afdb05bf4 | |||
| 9569a85cee | |||
| 54721b7c7b | |||
| 91d8bddbd1 | |||
| 80adc87a14 | |||
| 117ad1b65b | |||
| 2229509362 | |||
| 6ef8e87492 | |||
| 0a25083fdb | |||
| 15137d0327 | |||
| 8c9974bc0f | |||
| 079b6c2b50 | |||
| 0924b34a17 | |||
| 754f7a8a39 | |||
| 64bafe1dfe | |||
| c3e456e7e6 | |||
| 57aaeafd2f | |||
| 3c2e1a87e2 | |||
| da95a2d13f | |||
| cc5e05fdeb | |||
| a79c390cca | |||
| 8a56af439c | |||
| f6e581ce54 | |||
| 8953f88780 | |||
| 4b4a98d5e5 | |||
| 7472818d94 | |||
| ad44fe8d3e | |||
| 55e713db0a | |||
| 33322e6638 | |||
| a1792ca0d1 | |||
| ac8c43fe9c | |||
| 4d40ee00e9 | |||
| 06f59ad631 | |||
| 877e0cac03 | |||
| ef67c39910 | |||
| 508710f4d1 | |||
| 3aa3d9cf14 | |||
| c2fedb4c3f | |||
| 03dc65e12d | |||
| b8d62a8068 | |||
| dbc2368a7b | |||
| 54aed421b8 | |||
| d5e8dac1cf | |||
| 96ec8fcba1 | |||
| 0663eb69ed | |||
| 0594d37230 | |||
| 3cc30bcc18 | |||
| 99c1a642a4 |
@@ -1,6 +1,6 @@
|
||||
## Community Contribution License
|
||||
All community contributions in this pull request are licensed to the project maintainers
|
||||
under the terms of the [Apache 2 license] (https://www.apache.org/licenses/LICENSE-2.0).
|
||||
under the terms of the [Apache 2 license](https://www.apache.org/licenses/LICENSE-2.0).
|
||||
By creating this pull request I represent that I have the right to license the
|
||||
contributions to the project maintainers under the Apache 2 license.
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ x-minio-common: &minio-common
|
||||
MINIO_COMPRESSION_ALLOW_ENCRYPTION: "on"
|
||||
MINIO_KMS_SECRET_KEY: "my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw="
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# starts 4 docker containers running minio server instances.
|
||||
# using nginx reverse proxy, load balancing, you can access
|
||||
|
||||
@@ -13,10 +13,10 @@ x-minio-common: &minio-common
|
||||
MINIO_ROOT_PASSWORD: "minio123"
|
||||
MINIO_KMS_SECRET_KEY: "my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw="
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# starts 4 docker containers running minio server instances.
|
||||
# using nginx reverse proxy, load balancing, you can access
|
||||
|
||||
@@ -13,10 +13,10 @@ x-minio-common: &minio-common
|
||||
MINIO_ROOT_PASSWORD: "minio123"
|
||||
MINIO_KMS_SECRET_KEY: "my-minio-key:OSMM+vkKUTCvQs9YL/CVMIMt43HFhkUpqJxTmGl6rYw="
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# starts 4 docker containers running minio server instances.
|
||||
# using nginx reverse proxy, load balancing, you can access
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21.3
|
||||
go-version: 1.21.4
|
||||
check-latest: true
|
||||
- name: Get official govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
|
||||
@@ -42,3 +42,4 @@ docs/debugging/healing-bin/healing-bin
|
||||
docs/debugging/inspect/inspect
|
||||
docs/debugging/pprofgoparser/pprofgoparser
|
||||
docs/debugging/reorder-disks/reorder-disks
|
||||
docs/debugging/populate-hard-links/populate-hardlinks
|
||||
|
||||
@@ -2416,6 +2416,60 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/VividCortex/ewma
|
||||
https://github.com/VividCortex/ewma
|
||||
----------------------------------------------------------------
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2013 VividCortex
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/acarl005/stripansi
|
||||
https://github.com/acarl005/stripansi
|
||||
----------------------------------------------------------------
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Andrew Carlson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/alecthomas/participle
|
||||
https://github.com/alecthomas/participle
|
||||
----------------------------------------------------------------
|
||||
@@ -4495,34 +4549,6 @@ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/djherbis/atime
|
||||
https://github.com/djherbis/atime
|
||||
----------------------------------------------------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Dustin H
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/docker/go-units
|
||||
@@ -15244,6 +15270,213 @@ https://github.com/matttproud/golang_protobuf_extensions
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/matttproud/golang_protobuf_extensions/v2
|
||||
https://github.com/matttproud/golang_protobuf_extensions/v2
|
||||
----------------------------------------------------------------
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/miekg/dns
|
||||
https://github.com/miekg/dns
|
||||
----------------------------------------------------------------
|
||||
@@ -25833,6 +26066,214 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/safchain/ethtool
|
||||
https://github.com/safchain/ethtool
|
||||
----------------------------------------------------------------
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/secure-io/sio-go
|
||||
@@ -27106,6 +27547,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/vbauerster/mpb/v8
|
||||
https://github.com/vbauerster/mpb/v8
|
||||
----------------------------------------------------------------
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
================================================================
|
||||
|
||||
github.com/xdg/scram
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
FROM minio/minio:latest
|
||||
|
||||
ENV PATH=/opt/bin:$PATH
|
||||
|
||||
COPY ./minio /opt/bin/minio
|
||||
COPY ./minio /usr/bin/minio
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
|
||||
+35
-23
@@ -1,4 +1,31 @@
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
|
||||
FROM golang:1.21-alpine as build
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RELEASE
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV CGO_ENABLED 0
|
||||
|
||||
# Install curl and minisign
|
||||
RUN apk add -U --no-cache ca-certificates && \
|
||||
apk add -U --no-cache curl && \
|
||||
go install aead.dev/minisign/cmd/minisign@v0.2.0
|
||||
|
||||
# Download minio binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/server/minio/hotfixes/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /go/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/hotfixes/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /go/bin/minio.minisig && \
|
||||
chmod +x /go/bin/minio
|
||||
|
||||
# Download mc binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc -o /go/bin/mc && \
|
||||
curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc.minisig -o /go/bin/mc.minisig && \
|
||||
chmod +x /go/bin/mc
|
||||
|
||||
# Verify binary signature using public key "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGavRUN"
|
||||
RUN minisign -Vqm /go/bin/minio -x /go/bin/minio.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav && \
|
||||
minisign -Vqm /go/bin/mc -x /go/bin/mc.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
|
||||
FROM registry.access.redhat.com/ubi9/ubi-micro:9.2
|
||||
|
||||
ARG RELEASE
|
||||
|
||||
@@ -17,33 +44,18 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
PATH=/opt/bin:$PATH
|
||||
MC_CONFIG_DIR=/tmp/.mc
|
||||
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/minio /usr/bin/minio
|
||||
COPY --from=build /go/bin/mc /usr/bin/mc
|
||||
|
||||
COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
COPY CREDITS /licenses/CREDITS
|
||||
COPY LICENSE /licenses/LICENSE
|
||||
|
||||
RUN \
|
||||
microdnf clean all && \
|
||||
microdnf update --nodocs && \
|
||||
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
|
||||
microdnf install curl ca-certificates shadow-utils util-linux gzip lsof tar net-tools iproute iputils jq minisign --nodocs && \
|
||||
mkdir -p /opt/bin && chmod -R 777 /opt/bin && \
|
||||
curl -s -q https://dl.min.io/server/minio/hotfixes/linux-amd64/archive/minio.${RELEASE} -o /opt/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/hotfixes/linux-amd64/archive/minio.${RELEASE}.sha256sum -o /opt/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/hotfixes/linux-amd64/archive/minio.${RELEASE}.minisig -o /opt/bin/minio.minisig && \
|
||||
microdnf clean all && \
|
||||
chmod +x /opt/bin/minio && \
|
||||
chmod +x /usr/bin/docker-entrypoint.sh && \
|
||||
chmod +x /usr/bin/verify-minio.sh && \
|
||||
/usr/bin/verify-minio.sh && \
|
||||
microdnf clean all
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
CMD ["minio"]
|
||||
|
||||
+33
-25
@@ -1,6 +1,31 @@
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
|
||||
FROM golang:1.21-alpine as build
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RELEASE
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV CGO_ENABLED 0
|
||||
|
||||
# Install curl and minisign
|
||||
RUN apk add -U --no-cache ca-certificates && \
|
||||
apk add -U --no-cache curl && \
|
||||
go install aead.dev/minisign/cmd/minisign@v0.2.0
|
||||
|
||||
# Download minio binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /go/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /go/bin/minio.minisig && \
|
||||
chmod +x /go/bin/minio
|
||||
|
||||
# Download mc binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc -o /go/bin/mc && \
|
||||
curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc.minisig -o /go/bin/mc.minisig && \
|
||||
chmod +x /go/bin/mc
|
||||
|
||||
# Verify binary signature using public key "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGavRUN"
|
||||
RUN minisign -Vqm /go/bin/minio -x /go/bin/minio.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav && \
|
||||
minisign -Vqm /go/bin/mc -x /go/bin/mc.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
|
||||
FROM registry.access.redhat.com/ubi9/ubi-micro:latest
|
||||
|
||||
ARG RELEASE
|
||||
|
||||
@@ -19,35 +44,18 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
PATH=/opt/bin:$PATH
|
||||
MC_CONFIG_DIR=/tmp/.mc
|
||||
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/minio /usr/bin/minio
|
||||
COPY --from=build /go/bin/mc /usr/bin/mc
|
||||
|
||||
COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
COPY CREDITS /licenses/CREDITS
|
||||
COPY LICENSE /licenses/LICENSE
|
||||
|
||||
RUN \
|
||||
microdnf clean all && \
|
||||
microdnf update --nodocs && \
|
||||
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
|
||||
microdnf install curl ca-certificates shadow-utils util-linux gzip lsof tar net-tools iproute iputils jq minisign --nodocs && \
|
||||
mkdir -p /opt/bin && chmod -R 777 /opt/bin && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /opt/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.sha256sum -o /opt/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /opt/bin/minio.minisig && \
|
||||
curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc -o /opt/bin/mc && \
|
||||
microdnf clean all && \
|
||||
chmod +x /opt/bin/minio && \
|
||||
chmod +x /opt/bin/mc && \
|
||||
chmod +x /usr/bin/docker-entrypoint.sh && \
|
||||
chmod +x /usr/bin/verify-minio.sh && \
|
||||
/usr/bin/verify-minio.sh && \
|
||||
microdnf clean all
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
CMD ["minio"]
|
||||
|
||||
+26
-24
@@ -1,6 +1,25 @@
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
|
||||
FROM golang:1.21-alpine as build
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RELEASE
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV CGO_ENABLED 0
|
||||
|
||||
# Install curl and minisign
|
||||
RUN apk add -U --no-cache ca-certificates && \
|
||||
apk add -U --no-cache curl && \
|
||||
go install aead.dev/minisign/cmd/minisign@v0.2.0
|
||||
|
||||
# Download minio binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips -o /go/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.minisig -o /go/bin/minio.minisig && \
|
||||
chmod +x /go/bin/minio
|
||||
|
||||
# Verify binary signature using public key "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGavRUN"
|
||||
RUN minisign -Vqm /go/bin/minio -x /go/bin/minio.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
|
||||
FROM registry.access.redhat.com/ubi9/ubi-micro:9.2
|
||||
|
||||
ARG RELEASE
|
||||
|
||||
@@ -18,34 +37,17 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_ROOT_PASSWORD_FILE=secret_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
PATH=/opt/bin:$PATH
|
||||
MINIO_CONFIG_ENV_FILE=config.env
|
||||
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/minio /usr/bin/minio
|
||||
|
||||
COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
COPY CREDITS /licenses/CREDITS
|
||||
COPY LICENSE /licenses/LICENSE
|
||||
|
||||
RUN \
|
||||
microdnf clean all && \
|
||||
microdnf update --nodocs && \
|
||||
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && \
|
||||
microdnf install curl ca-certificates shadow-utils util-linux gzip lsof tar net-tools iproute iputils jq minisign --nodocs && \
|
||||
mkdir -p /opt/bin && chmod -R 777 /opt/bin && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips -o /opt/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.sha256sum -o /opt/bin/minio.sha256sum && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.fips.minisig -o /opt/bin/minio.minisig && \
|
||||
microdnf clean all && \
|
||||
chmod +x /opt/bin/minio && \
|
||||
chmod +x /usr/bin/docker-entrypoint.sh && \
|
||||
chmod +x /usr/bin/verify-minio.sh && \
|
||||
/usr/bin/verify-minio.sh && \
|
||||
microdnf clean all
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
CMD ["minio"]
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
FROM golang:1.21-alpine as build
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RELEASE
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV CGO_ENABLED 0
|
||||
|
||||
# Install curl and minisign
|
||||
RUN apk add -U --no-cache ca-certificates && \
|
||||
apk add -U --no-cache curl && \
|
||||
go install aead.dev/minisign/cmd/minisign@v0.2.0
|
||||
|
||||
# Download minio binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE} -o /go/bin/minio && \
|
||||
curl -s -q https://dl.min.io/server/minio/release/linux-${TARGETARCH}/archive/minio.${RELEASE}.minisig -o /go/bin/minio.minisig && \
|
||||
chmod +x /go/bin/minio
|
||||
|
||||
# Download mc binary and signature file
|
||||
RUN curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc -o /go/bin/mc && \
|
||||
curl -s -q https://dl.min.io/client/mc/release/linux-${TARGETARCH}/mc.minisig -o /go/bin/mc.minisig && \
|
||||
chmod +x /go/bin/mc
|
||||
|
||||
# Verify binary signature using public key "RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGavRUN"
|
||||
RUN minisign -Vqm /go/bin/minio -x /go/bin/minio.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav && \
|
||||
minisign -Vqm /go/bin/mc -x /go/bin/mc.minisig -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
|
||||
FROM registry.access.redhat.com/ubi8/ubi-micro:latest
|
||||
|
||||
ARG RELEASE
|
||||
|
||||
LABEL name="MinIO" \
|
||||
vendor="MinIO Inc <dev@min.io>" \
|
||||
maintainer="MinIO Inc <dev@min.io>" \
|
||||
version="${RELEASE}" \
|
||||
release="${RELEASE}" \
|
||||
summary="MinIO is a High Performance Object Storage, API compatible with Amazon S3 cloud storage service." \
|
||||
description="MinIO object storage is fundamentally different. Designed for performance and the S3 API, it is 100% open-source. MinIO is ideal for large, private cloud environments with stringent security requirements and delivers mission-critical availability across a diverse range of workloads."
|
||||
|
||||
ENV MINIO_ACCESS_KEY_FILE=access_key \
|
||||
MINIO_SECRET_KEY_FILE=secret_key \
|
||||
MINIO_ROOT_USER_FILE=access_key \
|
||||
MINIO_ROOT_PASSWORD_FILE=secret_key \
|
||||
MINIO_KMS_SECRET_KEY_FILE=kms_master_key \
|
||||
MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" \
|
||||
MINIO_CONFIG_ENV_FILE=config.env \
|
||||
MC_CONFIG_DIR=/tmp/.mc
|
||||
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=build /go/bin/minio /usr/bin/minio
|
||||
COPY --from=build /go/bin/mc /usr/bin/mc
|
||||
|
||||
COPY CREDITS /licenses/CREDITS
|
||||
COPY LICENSE /licenses/LICENSE
|
||||
COPY dockerscripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
|
||||
|
||||
EXPOSE 9000
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
|
||||
CMD ["minio"]
|
||||
@@ -9,11 +9,6 @@ x-minio-common: &minio-common
|
||||
expose:
|
||||
- "9000"
|
||||
- "9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
|
||||
# starts 4 docker containers running minio server instances.
|
||||
# using nginx reverse proxy, load balancing, you can access
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/mux"
|
||||
"github.com/minio/pkg/v2/policy"
|
||||
@@ -537,7 +538,7 @@ func (a adminAPIHandlers) SiteReplicationDevNull(w http.ResponseWriter, r *http.
|
||||
|
||||
connectTime := time.Now()
|
||||
for {
|
||||
n, err := io.CopyN(io.Discard, r.Body, 128*humanize.KiByte)
|
||||
n, err := io.CopyN(xioutil.Discard, r.Body, 128*humanize.KiByte)
|
||||
atomic.AddUint64(&globalSiteNetPerfRX.RX, uint64(n))
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
// If there is a disconnection before globalNetPerfMinDuration (we give a margin of error of 1 sec)
|
||||
|
||||
@@ -781,6 +781,9 @@ func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Reque
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
if sp.Version == "" && len(sp.Statements) == 0 {
|
||||
sp = nil
|
||||
}
|
||||
}
|
||||
|
||||
opts.sessionPolicy = sp
|
||||
@@ -911,6 +914,9 @@ func (a adminAPIHandlers) UpdateServiceAccount(w http.ResponseWriter, r *http.Re
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
if sp.Version == "" && len(sp.Statements) == 0 {
|
||||
sp = nil
|
||||
}
|
||||
}
|
||||
opts := updateServiceAccountOpts{
|
||||
secretKey: updateReq.NewSecretKey,
|
||||
@@ -996,9 +1002,12 @@ func (a adminAPIHandlers) InfoServiceAccount(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
// if session policy is nil or empty, then it is implied policy
|
||||
impliedPolicy := sessionPolicy == nil || (sessionPolicy.Version == "" && len(sessionPolicy.Statements) == 0)
|
||||
|
||||
var svcAccountPolicy policy.Policy
|
||||
|
||||
if sessionPolicy != nil {
|
||||
if !impliedPolicy {
|
||||
svcAccountPolicy = *sessionPolicy
|
||||
} else {
|
||||
policiesNames, err := globalIAMSys.PolicyDBGet(svcAccount.ParentUser, false)
|
||||
@@ -1025,7 +1034,7 @@ func (a adminAPIHandlers) InfoServiceAccount(w http.ResponseWriter, r *http.Requ
|
||||
Name: svcAccount.Name,
|
||||
Description: svcAccount.Description,
|
||||
AccountStatus: svcAccount.Status,
|
||||
ImpliedPolicy: sessionPolicy == nil,
|
||||
ImpliedPolicy: impliedPolicy,
|
||||
Policy: string(policyJSON),
|
||||
Expiration: expiration,
|
||||
}
|
||||
|
||||
+40
-7
@@ -52,6 +52,7 @@ import (
|
||||
"github.com/minio/minio/internal/dsync"
|
||||
"github.com/minio/minio/internal/handlers"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/kms"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/mux"
|
||||
@@ -64,6 +65,8 @@ import (
|
||||
const (
|
||||
maxEConfigJSONSize = 262272
|
||||
kubernetesVersionEndpoint = "https://kubernetes.default.svc/version"
|
||||
anonymizeParam = "anonymize"
|
||||
anonymizeStrict = "strict"
|
||||
)
|
||||
|
||||
// Only valid query params for mgmt admin APIs.
|
||||
@@ -754,11 +757,8 @@ func (a adminAPIHandlers) ProfileHandler(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
}
|
||||
// read request body
|
||||
io.CopyN(io.Discard, r.Body, 1)
|
||||
|
||||
globalProfilerMu.Lock()
|
||||
|
||||
if globalProfiler == nil {
|
||||
globalProfiler = make(map[string]minioProfiler, 10)
|
||||
}
|
||||
@@ -1056,7 +1056,7 @@ func (a adminAPIHandlers) HealHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
respCh := make(chan healResp)
|
||||
respCh := make(chan healResp, 1)
|
||||
switch {
|
||||
case hip.forceStop:
|
||||
go func() {
|
||||
@@ -1218,7 +1218,7 @@ func (a adminAPIHandlers) ClientDevNull(w http.ResponseWriter, r *http.Request)
|
||||
totalRx := int64(0)
|
||||
connectTime := time.Now()
|
||||
for {
|
||||
n, err := io.CopyN(io.Discard, r.Body, 128*humanize.KiByte)
|
||||
n, err := io.CopyN(xioutil.Discard, r.Body, 128*humanize.KiByte)
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
// would mean the network is not stable. Logging here will help in debugging network issues.
|
||||
if time.Since(connectTime) < (globalNetPerfMinDuration - time.Second) {
|
||||
@@ -1400,13 +1400,21 @@ func (a adminAPIHandlers) ObjectSpeedTestHandler(w http.ResponseWriter, r *http.
|
||||
}
|
||||
|
||||
func makeObjectPerfBucket(ctx context.Context, objectAPI ObjectLayer, bucketName string) (bucketExists bool, err error) {
|
||||
if err = objectAPI.MakeBucket(ctx, bucketName, MakeBucketOptions{}); err != nil {
|
||||
if err = objectAPI.MakeBucket(ctx, bucketName, MakeBucketOptions{VersioningEnabled: globalSiteReplicationSys.isEnabled()}); err != nil {
|
||||
if _, ok := err.(BucketExists); !ok {
|
||||
// Only BucketExists error can be ignored.
|
||||
return false, err
|
||||
}
|
||||
bucketExists = true
|
||||
}
|
||||
|
||||
if globalSiteReplicationSys.isEnabled() {
|
||||
configData := []byte(`<VersioningConfiguration><Status>Enabled</Status><ExcludedPrefixes><Prefix>speedtest/*</Prefix></ExcludedPrefixes></VersioningConfiguration>`)
|
||||
if _, err = globalBucketMetadataSys.Update(ctx, bucketName, bucketVersioningConfig, configData); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return bucketExists, nil
|
||||
}
|
||||
|
||||
@@ -2027,8 +2035,14 @@ func getKubernetesInfo(dctx context.Context) madmin.KubernetesInfo {
|
||||
|
||||
func fetchHealthInfo(healthCtx context.Context, objectAPI ObjectLayer, query *url.Values, healthInfoCh chan madmin.HealthInfo, healthInfo madmin.HealthInfo) {
|
||||
hostAnonymizer := createHostAnonymizer()
|
||||
// anonAddr - Anonymizes hosts in given input string.
|
||||
|
||||
anonParam := query.Get(anonymizeParam)
|
||||
// anonAddr - Anonymizes hosts in given input string
|
||||
// (only if the anonymize param is set to srict).
|
||||
anonAddr := func(addr string) string {
|
||||
if anonParam != anonymizeStrict {
|
||||
return addr
|
||||
}
|
||||
newAddr, found := hostAnonymizer[addr]
|
||||
if found {
|
||||
return newAddr
|
||||
@@ -2089,6 +2103,20 @@ func fetchHealthInfo(healthCtx context.Context, objectAPI ObjectLayer, query *ur
|
||||
}
|
||||
}
|
||||
|
||||
getAndWriteNetInfo := func() {
|
||||
if query.Get(string(madmin.HealthDataTypeSysNet)) == "true" {
|
||||
localNetInfo := madmin.GetNetInfo(globalLocalNodeName, globalInternodeInterface)
|
||||
healthInfo.Sys.NetInfo = append(healthInfo.Sys.NetInfo, localNetInfo)
|
||||
|
||||
peerNetInfos := globalNotificationSys.GetNetInfo(healthCtx)
|
||||
for _, n := range peerNetInfos {
|
||||
anonymizeAddr(&n)
|
||||
healthInfo.Sys.NetInfo = append(healthInfo.Sys.NetInfo, n)
|
||||
}
|
||||
partialWrite(healthInfo)
|
||||
}
|
||||
}
|
||||
|
||||
getAndWriteOSInfo := func() {
|
||||
if query.Get("sysosinfo") == "true" {
|
||||
localOSInfo := madmin.GetOSInfo(healthCtx, globalLocalNodeName)
|
||||
@@ -2189,6 +2217,10 @@ func fetchHealthInfo(healthCtx context.Context, objectAPI ObjectLayer, query *ur
|
||||
}
|
||||
|
||||
anonymizeCmdLine := func(cmdLine string) string {
|
||||
if anonParam != anonymizeStrict {
|
||||
return cmdLine
|
||||
}
|
||||
|
||||
if !globalIsDistErasure {
|
||||
// FS mode - single server - hard code to `server1`
|
||||
anonCmdLine := strings.ReplaceAll(cmdLine, globalLocalNodeName, "server1")
|
||||
@@ -2310,6 +2342,7 @@ func fetchHealthInfo(healthCtx context.Context, objectAPI ObjectLayer, query *ur
|
||||
getAndWritePlatformInfo()
|
||||
getAndWriteCPUs()
|
||||
getAndWritePartitions()
|
||||
getAndWriteNetInfo()
|
||||
getAndWriteOSInfo()
|
||||
getAndWriteMemInfo()
|
||||
getAndWriteProcInfo()
|
||||
|
||||
@@ -561,6 +561,7 @@ func generateListVersionsResponse(bucket, prefix, marker, versionIDMarker, delim
|
||||
}
|
||||
content.UserMetadata.Set(k, v)
|
||||
}
|
||||
content.UserMetadata.Set("expires", object.Expires.Format(http.TimeFormat))
|
||||
content.Internal = &ObjectInternalInfo{
|
||||
K: object.DataBlocks,
|
||||
M: object.ParityBlocks,
|
||||
@@ -704,6 +705,7 @@ func generateListObjectsV2Response(bucket, prefix, token, nextToken, startAfter,
|
||||
}
|
||||
content.UserMetadata.Set(k, v)
|
||||
}
|
||||
content.UserMetadata.Set("expires", object.Expires.Format(http.TimeFormat))
|
||||
content.Internal = &ObjectInternalInfo{
|
||||
K: object.DataBlocks,
|
||||
M: object.ParityBlocks,
|
||||
|
||||
+12
-2
@@ -163,7 +163,7 @@ func (r *BatchJobReplicateV1) ReplicateFromSource(ctx context.Context, api Objec
|
||||
}
|
||||
rd, objInfo, _, err := core.GetObject(ctx, srcBucket, srcObject, gopts)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrorRespToObjectError(err, srcBucket, srcObject, srcObjInfo.VersionID)
|
||||
}
|
||||
defer rd.Close()
|
||||
|
||||
@@ -226,7 +226,7 @@ func (r *BatchJobReplicateV1) copyWithMultipartfromSource(ctx context.Context, a
|
||||
}
|
||||
rd, objInfo, _, err := c.GetObject(ctx, srcBucket, srcObject, gopts)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrorRespToObjectError(err, srcBucket, srcObject, srcObjInfo.VersionID)
|
||||
}
|
||||
defer rd.Close()
|
||||
|
||||
@@ -262,6 +262,9 @@ func (r *BatchJobReplicateV1) StartFromSource(ctx context.Context, api ObjectLay
|
||||
if err := ri.load(ctx, api, job); err != nil {
|
||||
return err
|
||||
}
|
||||
if ri.Complete {
|
||||
return nil
|
||||
}
|
||||
globalBatchJobsMetrics.save(job.ID, ri)
|
||||
|
||||
delay := job.Replicate.Flags.Retry.Delay
|
||||
@@ -517,6 +520,10 @@ func toObjectInfo(bucket, object string, objInfo miniogo.ObjectInfo) ObjectInfo
|
||||
oi.UserDefined[xhttp.AmzStorageClass] = objInfo.StorageClass
|
||||
}
|
||||
|
||||
for k, v := range objInfo.UserMetadata {
|
||||
oi.UserDefined[k] = v
|
||||
}
|
||||
|
||||
return oi
|
||||
}
|
||||
|
||||
@@ -837,6 +844,9 @@ func (r *BatchJobReplicateV1) Start(ctx context.Context, api ObjectLayer, job Ba
|
||||
if err := ri.load(ctx, api, job); err != nil {
|
||||
return err
|
||||
}
|
||||
if ri.Complete {
|
||||
return nil
|
||||
}
|
||||
globalBatchJobsMetrics.save(job.ID, ri)
|
||||
lastObject := ri.Object
|
||||
|
||||
|
||||
@@ -261,6 +261,9 @@ func (r *BatchJobKeyRotateV1) Start(ctx context.Context, api ObjectLayer, job Ba
|
||||
if err := ri.load(ctx, api, job); err != nil {
|
||||
return err
|
||||
}
|
||||
if ri.Complete {
|
||||
return nil
|
||||
}
|
||||
|
||||
globalBatchJobsMetrics.save(job.ID, ri)
|
||||
lastObject := ri.Object
|
||||
|
||||
@@ -983,7 +983,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
if fileName == "" {
|
||||
if name != "file" {
|
||||
if http.CanonicalHeaderKey(name) == http.CanonicalHeaderKey("x-minio-fanout-list") {
|
||||
dec := json.NewDecoder(part)
|
||||
|
||||
|
||||
+18
-8
@@ -43,6 +43,7 @@ import (
|
||||
"github.com/minio/minio/internal/s3select"
|
||||
"github.com/minio/pkg/v2/env"
|
||||
"github.com/minio/pkg/v2/workers"
|
||||
"github.com/zeebo/xxh3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -223,11 +224,19 @@ type transitionState struct {
|
||||
lastDayStats map[string]*lastDayTierStats
|
||||
}
|
||||
|
||||
func (t *transitionState) queueTransitionTask(oi ObjectInfo, event lifecycle.Event, src lcEventSrc) {
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
case t.transitionCh <- transitionTask{objInfo: oi, event: event, src: src}:
|
||||
default:
|
||||
func (t *transitionState) queueTransitionTask(oi ObjectInfo, event lifecycle.Event, src lcEventSrc, blocking bool) {
|
||||
task := transitionTask{objInfo: oi, event: event, src: src}
|
||||
if blocking {
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
case t.transitionCh <- task:
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
case t.transitionCh <- task:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +246,7 @@ var globalTransitionState *transitionState
|
||||
// via its Init method.
|
||||
func newTransitionState(ctx context.Context) *transitionState {
|
||||
return &transitionState{
|
||||
transitionCh: make(chan transitionTask, 10000),
|
||||
transitionCh: make(chan transitionTask, 100000),
|
||||
ctx: ctx,
|
||||
killCh: make(chan struct{}),
|
||||
lastDayStats: make(map[string]*lastDayTierStats),
|
||||
@@ -367,7 +376,7 @@ func enqueueTransitionImmediate(obj ObjectInfo, src lcEventSrc) {
|
||||
if lc, err := globalLifecycleSys.Get(obj.Bucket); err == nil {
|
||||
switch event := lc.Eval(obj.ToLifecycleOpts()); event.Action {
|
||||
case lifecycle.TransitionAction, lifecycle.TransitionVersionAction:
|
||||
globalTransitionState.queueTransitionTask(obj, event, src)
|
||||
globalTransitionState.queueTransitionTask(obj, event, src, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,7 +453,8 @@ func genTransitionObjName(bucket string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
us := u.String()
|
||||
obj := fmt.Sprintf("%s/%s/%s/%s/%s", globalDeploymentID(), bucket, us[0:2], us[2:4], us)
|
||||
hash := xxh3.HashString(pathJoin(globalDeploymentID(), bucket))
|
||||
obj := fmt.Sprintf("%s/%s/%s/%s", strconv.FormatUint(hash, 16), us[0:2], us[2:4], us)
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
|
||||
+25
-23
@@ -437,21 +437,8 @@ func (sys *BucketMetadataSys) Init(ctx context.Context, buckets []BucketInfo, ob
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sys *BucketMetadataSys) loadBucketMetadata(ctx context.Context, bucket BucketInfo) error {
|
||||
meta, err := loadBucketMetadata(ctx, sys.objAPI, bucket.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sys.Lock()
|
||||
sys.metadataMap[bucket.Name] = meta
|
||||
sys.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// concurrently load bucket metadata to speed up loading bucket metadata.
|
||||
func (sys *BucketMetadataSys) concurrentLoad(ctx context.Context, buckets []BucketInfo) {
|
||||
func (sys *BucketMetadataSys) concurrentLoad(ctx context.Context, buckets []BucketInfo, failedBuckets map[string]struct{}) {
|
||||
g := errgroup.WithNErrs(len(buckets))
|
||||
bucketMetas := make([]BucketMetadata, len(buckets))
|
||||
for index := range buckets {
|
||||
@@ -491,6 +478,10 @@ func (sys *BucketMetadataSys) concurrentLoad(ctx context.Context, buckets []Buck
|
||||
|
||||
for i, meta := range bucketMetas {
|
||||
if errs[i] != nil {
|
||||
if failedBuckets == nil {
|
||||
failedBuckets = make(map[string]struct{})
|
||||
}
|
||||
failedBuckets[buckets[i].Name] = struct{}{}
|
||||
continue
|
||||
}
|
||||
globalEventNotifier.set(buckets[i], meta) // set notification targets
|
||||
@@ -498,7 +489,7 @@ func (sys *BucketMetadataSys) concurrentLoad(ctx context.Context, buckets []Buck
|
||||
}
|
||||
}
|
||||
|
||||
func (sys *BucketMetadataSys) refreshBucketsMetadataLoop(ctx context.Context) {
|
||||
func (sys *BucketMetadataSys) refreshBucketsMetadataLoop(ctx context.Context, failedBuckets map[string]struct{}) {
|
||||
const bucketMetadataRefresh = 15 * time.Minute
|
||||
|
||||
sleeper := newDynamicSleeper(2, 150*time.Millisecond, false)
|
||||
@@ -513,7 +504,7 @@ func (sys *BucketMetadataSys) refreshBucketsMetadataLoop(ctx context.Context) {
|
||||
buckets, err := sys.objAPI.ListBuckets(ctx, BucketOptions{})
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
continue
|
||||
break
|
||||
}
|
||||
|
||||
// Handle if we have some buckets in-memory those are stale.
|
||||
@@ -525,38 +516,49 @@ func (sys *BucketMetadataSys) refreshBucketsMetadataLoop(ctx context.Context) {
|
||||
}
|
||||
sys.RemoveStaleBuckets(diskBuckets)
|
||||
|
||||
for _, bucket := range buckets {
|
||||
for i := range buckets {
|
||||
wait := sleeper.Timer(ctx)
|
||||
|
||||
err := sys.loadBucketMetadata(ctx, bucket)
|
||||
meta, err := loadBucketMetadata(ctx, sys.objAPI, buckets[i].Name)
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
wait() // wait to proceed to next entry.
|
||||
continue
|
||||
}
|
||||
|
||||
sys.Lock()
|
||||
sys.metadataMap[buckets[i].Name] = meta
|
||||
sys.Unlock()
|
||||
|
||||
// Initialize the failed buckets
|
||||
if _, ok := failedBuckets[buckets[i].Name]; ok {
|
||||
globalEventNotifier.set(buckets[i], meta)
|
||||
globalBucketTargetSys.set(buckets[i], meta)
|
||||
delete(failedBuckets, buckets[i].Name)
|
||||
}
|
||||
|
||||
wait() // wait to proceed to next entry.
|
||||
}
|
||||
|
||||
t.Reset(bucketMetadataRefresh)
|
||||
}
|
||||
t.Reset(bucketMetadataRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
// Loads bucket metadata for all buckets into BucketMetadataSys.
|
||||
func (sys *BucketMetadataSys) init(ctx context.Context, buckets []BucketInfo) {
|
||||
count := 100 // load 100 bucket metadata at a time.
|
||||
failedBuckets := make(map[string]struct{})
|
||||
for {
|
||||
if len(buckets) < count {
|
||||
sys.concurrentLoad(ctx, buckets)
|
||||
sys.concurrentLoad(ctx, buckets, failedBuckets)
|
||||
break
|
||||
}
|
||||
sys.concurrentLoad(ctx, buckets[:count])
|
||||
sys.concurrentLoad(ctx, buckets[:count], failedBuckets)
|
||||
buckets = buckets[count:]
|
||||
}
|
||||
|
||||
if globalIsDistErasure {
|
||||
go sys.refreshBucketsMetadataLoop(ctx)
|
||||
go sys.refreshBucketsMetadataLoop(ctx, failedBuckets)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -575,7 +575,7 @@ func (api objectAPIHandlers) ValidateBucketReplicationCredsHandler(w http.Respon
|
||||
if rule.Status == replication.Disabled {
|
||||
continue
|
||||
}
|
||||
clnt := globalBucketTargetSys.GetRemoteTargetClient(rule.Destination.Bucket)
|
||||
clnt := globalBucketTargetSys.GetRemoteTargetClient(bucket, rule.Destination.Bucket)
|
||||
if clnt == nil {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErrWithErr(ErrRemoteTargetNotFoundError, fmt.Errorf("replication config with rule ID %s has a stale target", rule.ID)), r.URL)
|
||||
return
|
||||
|
||||
+17
-17
@@ -113,7 +113,7 @@ func validateReplicationDestination(ctx context.Context, bucket string, rCfg *re
|
||||
if arn.Type != madmin.ReplicationService {
|
||||
return sameTarget, toAPIError(ctx, BucketRemoteArnTypeInvalid{Bucket: bucket})
|
||||
}
|
||||
clnt := globalBucketTargetSys.GetRemoteTargetClient(arnStr)
|
||||
clnt := globalBucketTargetSys.GetRemoteTargetClient(bucket, arnStr)
|
||||
if clnt == nil {
|
||||
return sameTarget, toAPIError(ctx, BucketRemoteTargetNotFound{Bucket: bucket})
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func validateReplicationDestination(ctx context.Context, bucket string, rCfg *re
|
||||
}
|
||||
}
|
||||
// validate replication ARN against target endpoint
|
||||
c := globalBucketTargetSys.GetRemoteTargetClient(arnStr)
|
||||
c := globalBucketTargetSys.GetRemoteTargetClient(bucket, arnStr)
|
||||
if c != nil {
|
||||
if err := checkRemoteEndpoint(ctx, c.EndpointURL()); err != nil {
|
||||
switch err.(type) {
|
||||
@@ -280,7 +280,7 @@ func mustReplicate(ctx context.Context, bucket, object string, mopts mustReplica
|
||||
}
|
||||
tgtArns := cfg.FilterTargetArns(opts)
|
||||
for _, tgtArn := range tgtArns {
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(tgtArn)
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(bucket, tgtArn)
|
||||
// the target online status should not be used here while deciding
|
||||
// whether to replicate as the target could be temporarily down
|
||||
opts.TargetArn = tgtArn
|
||||
@@ -383,7 +383,7 @@ func checkReplicateDelete(ctx context.Context, bucket string, dobj ObjectToDelet
|
||||
continue
|
||||
}
|
||||
}
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(tgtArn)
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(bucket, tgtArn)
|
||||
// the target online status should not be used here while deciding
|
||||
// whether to replicate deletes as the target could be temporarily down
|
||||
tgtDsc := newReplicateTargetDecision(tgtArn, false, false)
|
||||
@@ -495,7 +495,7 @@ func replicateDelete(ctx context.Context, dobj DeletedObjectReplicationInfo, obj
|
||||
if dobj.TargetArn != "" && dobj.TargetArn != tgtEntry.Arn {
|
||||
continue
|
||||
}
|
||||
tgtClnt := globalBucketTargetSys.GetRemoteTargetClient(tgtEntry.Arn)
|
||||
tgtClnt := globalBucketTargetSys.GetRemoteTargetClient(bucket, tgtEntry.Arn)
|
||||
if tgtClnt == nil {
|
||||
// Skip stale targets if any and log them to be missing atleast once.
|
||||
logger.LogOnceIf(ctx, fmt.Errorf("failed to get target for bucket:%s arn:%s", bucket, tgtEntry.Arn), tgtEntry.Arn)
|
||||
@@ -777,6 +777,7 @@ func putReplicationOpts(ctx context.Context, sc string, objInfo ObjectInfo) (put
|
||||
UserMetadata: meta,
|
||||
ContentType: objInfo.ContentType,
|
||||
ContentEncoding: objInfo.ContentEncoding,
|
||||
Expires: objInfo.Expires,
|
||||
StorageClass: sc,
|
||||
Internal: minio.AdvancedPutOptions{
|
||||
SourceVersionID: objInfo.VersionID,
|
||||
@@ -1023,7 +1024,7 @@ func replicateObject(ctx context.Context, ri ReplicateObjectInfo, objectAPI Obje
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
for _, tgtArn := range tgtArns {
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(tgtArn)
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(bucket, tgtArn)
|
||||
if tgt == nil {
|
||||
logger.LogOnceIf(ctx, fmt.Errorf("failed to get target for bucket:%s arn:%s", bucket, tgtArn), tgtArn)
|
||||
sendEvent(eventArgs{
|
||||
@@ -2188,7 +2189,7 @@ func proxyHeadToRepTarget(ctx context.Context, bucket, object string, rs *HTTPRa
|
||||
return nil, oi, proxy
|
||||
}
|
||||
for _, t := range proxyTargets.Targets {
|
||||
tgt = globalBucketTargetSys.GetRemoteTargetClient(t.Arn)
|
||||
tgt = globalBucketTargetSys.GetRemoteTargetClient(bucket, t.Arn)
|
||||
if tgt == nil || globalBucketTargetSys.isOffline(tgt.EndpointURL()) {
|
||||
continue
|
||||
}
|
||||
@@ -2560,7 +2561,7 @@ func (s *replicationResyncer) resyncBucket(ctx context.Context, objectAPI Object
|
||||
logger.LogIf(ctx, fmt.Errorf("replication resync failed for %s - arn specified %s is missing in the replication config", opts.bucket, opts.arn))
|
||||
return
|
||||
}
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(opts.arn)
|
||||
tgt := globalBucketTargetSys.GetRemoteTargetClient(opts.bucket, opts.arn)
|
||||
if tgt == nil {
|
||||
logger.LogIf(ctx, fmt.Errorf("replication resync failed for %s - target could not be created for arn %s", opts.bucket, opts.arn))
|
||||
return
|
||||
@@ -3187,12 +3188,16 @@ func (p *ReplicationPool) queueMRFSave(entry MRFReplicateEntry) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ReplicationPool) persistToDrive(ctx context.Context, v MRFReplicateEntries, data []byte) {
|
||||
func (p *ReplicationPool) persistToDrive(ctx context.Context, v MRFReplicateEntries) {
|
||||
newReader := func() io.ReadCloser {
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
// Initialize MRF meta header.
|
||||
var data [4]byte
|
||||
binary.LittleEndian.PutUint16(data[0:2], mrfMetaFormat)
|
||||
binary.LittleEndian.PutUint16(data[2:4], mrfMetaVersion)
|
||||
mw := msgp.NewWriter(w)
|
||||
n, err := mw.Write(data)
|
||||
n, err := mw.Write(data[:])
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
@@ -3230,15 +3235,10 @@ func (p *ReplicationPool) saveMRFEntries(ctx context.Context, entries map[string
|
||||
|
||||
v := MRFReplicateEntries{
|
||||
Entries: entries,
|
||||
Version: mrfMetaVersionV1,
|
||||
Version: mrfMetaVersion,
|
||||
}
|
||||
data := make([]byte, 4, v.Msgsize()+4)
|
||||
|
||||
// Initialize the resync meta header.
|
||||
binary.LittleEndian.PutUint16(data[0:2], mrfMetaFormat)
|
||||
binary.LittleEndian.PutUint16(data[2:4], mrfMetaVersion)
|
||||
|
||||
p.persistToDrive(ctx, v, data)
|
||||
p.persistToDrive(ctx, v)
|
||||
}
|
||||
|
||||
// load mrf entries from disk
|
||||
|
||||
+87
-8
@@ -40,14 +40,29 @@ const (
|
||||
defaultHealthCheckReloadDuration = 30 * time.Minute
|
||||
)
|
||||
|
||||
type arnTarget struct {
|
||||
Client *TargetClient
|
||||
lastRefresh time.Time
|
||||
}
|
||||
|
||||
// arnErrs represents number of errors seen for a ARN and if update is in progress
|
||||
// to refresh remote targets from bucket metadata.
|
||||
type arnErrs struct {
|
||||
count int64
|
||||
updateInProgress bool
|
||||
bucket string
|
||||
}
|
||||
|
||||
// BucketTargetSys represents bucket targets subsystem
|
||||
type BucketTargetSys struct {
|
||||
sync.RWMutex
|
||||
arnRemotesMap map[string]*TargetClient
|
||||
arnRemotesMap map[string]arnTarget
|
||||
targetsMap map[string][]madmin.BucketTarget
|
||||
hMutex sync.RWMutex
|
||||
hc map[string]epHealth
|
||||
hcClient *madmin.AnonymousClient
|
||||
aMutex sync.RWMutex
|
||||
arnErrsMap map[string]arnErrs // map of ARN to error count of failures to get target
|
||||
}
|
||||
|
||||
type latencyStat struct {
|
||||
@@ -364,7 +379,7 @@ func (sys *BucketTargetSys) SetTarget(ctx context.Context, bucket string, tgt *m
|
||||
}
|
||||
|
||||
sys.targetsMap[bucket] = newtgts
|
||||
sys.arnRemotesMap[tgt.Arn] = clnt
|
||||
sys.arnRemotesMap[tgt.Arn] = arnTarget{Client: clnt}
|
||||
sys.updateBandwidthLimit(bucket, tgt.Arn, tgt.BandwidthLimit)
|
||||
return nil
|
||||
}
|
||||
@@ -432,11 +447,71 @@ func (sys *BucketTargetSys) RemoveTarget(ctx context.Context, bucket, arnStr str
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sys *BucketTargetSys) markRefreshInProgress(bucket, arn string) {
|
||||
sys.aMutex.Lock()
|
||||
defer sys.aMutex.Unlock()
|
||||
if v, ok := sys.arnErrsMap[arn]; !ok {
|
||||
sys.arnErrsMap[arn] = arnErrs{
|
||||
updateInProgress: true,
|
||||
count: v.count + 1,
|
||||
bucket: bucket,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sys *BucketTargetSys) markRefreshDone(bucket, arn string) {
|
||||
sys.aMutex.Lock()
|
||||
defer sys.aMutex.Unlock()
|
||||
if v, ok := sys.arnErrsMap[arn]; ok {
|
||||
sys.arnErrsMap[arn] = arnErrs{
|
||||
updateInProgress: false,
|
||||
count: v.count,
|
||||
bucket: bucket,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sys *BucketTargetSys) isReloadingTarget(bucket, arn string) bool {
|
||||
sys.aMutex.RLock()
|
||||
defer sys.aMutex.RUnlock()
|
||||
if v, ok := sys.arnErrsMap[arn]; ok {
|
||||
return v.updateInProgress
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (sys *BucketTargetSys) incTargetErr(bucket, arn string) {
|
||||
sys.aMutex.Lock()
|
||||
defer sys.aMutex.Unlock()
|
||||
if v, ok := sys.arnErrsMap[arn]; ok {
|
||||
sys.arnErrsMap[arn] = arnErrs{
|
||||
updateInProgress: v.updateInProgress,
|
||||
count: v.count + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetRemoteTargetClient returns minio-go client for replication target instance
|
||||
func (sys *BucketTargetSys) GetRemoteTargetClient(arn string) *TargetClient {
|
||||
func (sys *BucketTargetSys) GetRemoteTargetClient(bucket, arn string) *TargetClient {
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
return sys.arnRemotesMap[arn]
|
||||
tgt := sys.arnRemotesMap[arn]
|
||||
sys.RUnlock()
|
||||
|
||||
if tgt.Client != nil {
|
||||
return tgt.Client
|
||||
}
|
||||
defer func() { // lazy refresh remote targets
|
||||
if tgt.Client == nil && !sys.isReloadingTarget(bucket, arn) && (tgt.lastRefresh.Equal(timeSentinel) || tgt.lastRefresh.Before(UTCNow().Add(-5*time.Minute))) {
|
||||
tgts, err := globalBucketMetadataSys.GetBucketTargetsConfig(bucket)
|
||||
if err == nil {
|
||||
sys.markRefreshInProgress(bucket, arn)
|
||||
sys.UpdateAllTargets(bucket, tgts)
|
||||
sys.markRefreshDone(bucket, arn)
|
||||
}
|
||||
}
|
||||
sys.incTargetErr(bucket, arn)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRemoteBucketTargetByArn returns BucketTarget for a ARN
|
||||
@@ -457,8 +532,9 @@ func (sys *BucketTargetSys) GetRemoteBucketTargetByArn(ctx context.Context, buck
|
||||
// NewBucketTargetSys - creates new replication system.
|
||||
func NewBucketTargetSys(ctx context.Context) *BucketTargetSys {
|
||||
sys := &BucketTargetSys{
|
||||
arnRemotesMap: make(map[string]*TargetClient),
|
||||
arnRemotesMap: make(map[string]arnTarget),
|
||||
targetsMap: make(map[string][]madmin.BucketTarget),
|
||||
arnErrsMap: make(map[string]arnErrs),
|
||||
hc: make(map[string]epHealth),
|
||||
hcClient: newHCClient(),
|
||||
}
|
||||
@@ -502,7 +578,10 @@ func (sys *BucketTargetSys) UpdateAllTargets(bucket string, tgts *madmin.BucketT
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
sys.arnRemotesMap[tgt.Arn] = tgtClient
|
||||
sys.arnRemotesMap[tgt.Arn] = arnTarget{
|
||||
Client: tgtClient,
|
||||
lastRefresh: UTCNow(),
|
||||
}
|
||||
sys.updateBandwidthLimit(bucket, tgt.Arn, tgt.BandwidthLimit)
|
||||
}
|
||||
|
||||
@@ -526,7 +605,7 @@ func (sys *BucketTargetSys) set(bucket BucketInfo, meta BucketMetadata) {
|
||||
logger.LogIf(GlobalContext, err)
|
||||
continue
|
||||
}
|
||||
sys.arnRemotesMap[tgt.Arn] = tgtClient
|
||||
sys.arnRemotesMap[tgt.Arn] = arnTarget{Client: tgtClient}
|
||||
sys.updateBandwidthLimit(bucket.Name, tgt.Arn, tgt.BandwidthLimit)
|
||||
}
|
||||
sys.targetsMap[bucket.Name] = cfg.Targets
|
||||
|
||||
+5
-2
@@ -167,9 +167,12 @@ func minioConfigToConsoleFeatures() {
|
||||
if value := env.Get(config.EnvBrowserLoginAnimation, "on"); value != "" {
|
||||
os.Setenv("CONSOLE_ANIMATED_LOGIN", value)
|
||||
}
|
||||
|
||||
// Pass on the session duration environment variable, else we will default to 12 hours
|
||||
if value := env.Get(config.EnvBrowserSessionDuration, ""); value != "" {
|
||||
os.Setenv("CONSOLE_STS_DURATION", value)
|
||||
if valueSts := env.Get(config.EnvMinioStsDuration, ""); valueSts != "" {
|
||||
os.Setenv("CONSOLE_STS_DURATION", valueSts)
|
||||
} else if valueSession := env.Get(config.EnvBrowserSessionDuration, ""); valueSession != "" {
|
||||
os.Setenv("CONSOLE_STS_DURATION", valueSession)
|
||||
}
|
||||
|
||||
os.Setenv("CONSOLE_MINIO_REGION", globalSite.Region)
|
||||
|
||||
+1
-2
@@ -343,7 +343,6 @@ func scanDataFolder(ctx context.Context, disks []StorageAPI, basePath string, ca
|
||||
// No useful information...
|
||||
return cache, err
|
||||
}
|
||||
|
||||
s.newCache.Info.LastUpdate = UTCNow()
|
||||
s.newCache.Info.NextCycle = cache.Info.NextCycle
|
||||
return s.newCache, nil
|
||||
@@ -1174,7 +1173,7 @@ func applyTransitionRule(event lifecycle.Event, src lcEventSrc, obj ObjectInfo)
|
||||
if obj.DeleteMarker {
|
||||
return false
|
||||
}
|
||||
globalTransitionState.queueTransitionTask(obj, event, src)
|
||||
globalTransitionState.queueTransitionTask(obj, event, src, false)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+27
-34
@@ -78,8 +78,8 @@ func newAllTierStats() *allTierStats {
|
||||
}
|
||||
}
|
||||
|
||||
func (ats *allTierStats) addSizes(sz sizeSummary) {
|
||||
for tier, st := range sz.tiers {
|
||||
func (ats *allTierStats) addSizes(tiers map[string]tierStats) {
|
||||
for tier, st := range tiers {
|
||||
ats.Tiers[tier] = ats.Tiers[tier].add(st)
|
||||
}
|
||||
}
|
||||
@@ -95,18 +95,16 @@ func (ats *allTierStats) clone() *allTierStats {
|
||||
return nil
|
||||
}
|
||||
dst := *ats
|
||||
if dst.Tiers != nil {
|
||||
dst.Tiers = make(map[string]tierStats, len(dst.Tiers))
|
||||
for tier, st := range dst.Tiers {
|
||||
dst.Tiers[tier] = st
|
||||
}
|
||||
dst.Tiers = make(map[string]tierStats, len(ats.Tiers))
|
||||
for tier, st := range ats.Tiers {
|
||||
dst.Tiers[tier] = st
|
||||
}
|
||||
return &dst
|
||||
}
|
||||
|
||||
func (ats *allTierStats) adminStats(stats map[string]madmin.TierStats) map[string]madmin.TierStats {
|
||||
func (ats *allTierStats) populateStats(stats map[string]madmin.TierStats) {
|
||||
if ats == nil {
|
||||
return stats
|
||||
return
|
||||
}
|
||||
|
||||
// Update stats for tiers as they become available.
|
||||
@@ -117,7 +115,7 @@ func (ats *allTierStats) adminStats(stats map[string]madmin.TierStats) map[strin
|
||||
NumObjects: st.NumObjects,
|
||||
}
|
||||
}
|
||||
return stats
|
||||
return
|
||||
}
|
||||
|
||||
// tierStats holds per-tier stats of a remote tier.
|
||||
@@ -128,10 +126,11 @@ type tierStats struct {
|
||||
}
|
||||
|
||||
func (ts tierStats) add(u tierStats) tierStats {
|
||||
ts.TotalSize += u.TotalSize
|
||||
ts.NumVersions += u.NumVersions
|
||||
ts.NumObjects += u.NumObjects
|
||||
return ts
|
||||
return tierStats{
|
||||
TotalSize: ts.TotalSize + u.TotalSize,
|
||||
NumVersions: ts.NumVersions + u.NumVersions,
|
||||
NumObjects: ts.NumObjects + u.NumObjects,
|
||||
}
|
||||
}
|
||||
|
||||
//msgp:tuple replicationStatsV1
|
||||
@@ -197,12 +196,11 @@ func (r *replicationAllStats) clone() *replicationAllStats {
|
||||
dst := *r
|
||||
|
||||
// Copy individual targets.
|
||||
if dst.Targets != nil {
|
||||
dst.Targets = make(map[string]replicationStats, len(dst.Targets))
|
||||
for k, v := range r.Targets {
|
||||
dst.Targets[k] = v
|
||||
}
|
||||
dst.Targets = make(map[string]replicationStats, len(r.Targets))
|
||||
for k, v := range r.Targets {
|
||||
dst.Targets[k] = v
|
||||
}
|
||||
|
||||
return &dst
|
||||
}
|
||||
|
||||
@@ -360,11 +358,11 @@ func (e *dataUsageEntry) addSizes(summary sizeSummary) {
|
||||
tgtStat.PendingCount += st.pendingCount
|
||||
e.ReplicationStats.Targets[arn] = tgtStat
|
||||
}
|
||||
if summary.tiers != nil {
|
||||
if len(summary.tiers) != 0 {
|
||||
if e.AllTierStats == nil {
|
||||
e.AllTierStats = newAllTierStats()
|
||||
}
|
||||
e.AllTierStats.addSizes(summary)
|
||||
e.AllTierStats.addSizes(summary.tiers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +401,7 @@ func (e *dataUsageEntry) merge(other dataUsageEntry) {
|
||||
e.ObjVersions[i] += v
|
||||
}
|
||||
|
||||
if other.AllTierStats != nil {
|
||||
if other.AllTierStats != nil && len(other.AllTierStats.Tiers) != 0 {
|
||||
if e.AllTierStats == nil {
|
||||
e.AllTierStats = newAllTierStats()
|
||||
}
|
||||
@@ -987,15 +985,10 @@ func (d *dataUsageCache) save(ctx context.Context, store objectIO, name string)
|
||||
return ctx.Err()
|
||||
case maxConcurrentScannerSaves <- struct{}{}:
|
||||
}
|
||||
defer func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-maxConcurrentScannerSaves:
|
||||
}
|
||||
}()
|
||||
|
||||
buf := bytebufferpool.Get()
|
||||
defer func() {
|
||||
<-maxConcurrentScannerSaves
|
||||
buf.Reset()
|
||||
bytebufferpool.Put(buf)
|
||||
}()
|
||||
@@ -1004,12 +997,12 @@ func (d *dataUsageCache) save(ctx context.Context, store objectIO, name string)
|
||||
return err
|
||||
}
|
||||
|
||||
hr, err := hash.NewReader(ctx, bytes.NewReader(buf.Bytes()), int64(buf.Len()), "", "", int64(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
save := func(name string, timeout time.Duration) error {
|
||||
hr, err := hash.NewReader(ctx, bytes.NewReader(buf.Bytes()), int64(buf.Len()), "", "", int64(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Abandon if more than a minute, so we don't hold up scanner.
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
@@ -1024,7 +1017,7 @@ func (d *dataUsageCache) save(ctx context.Context, store objectIO, name string)
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer save(name+".bkp", 30*time.Second) // Keep a backup as well
|
||||
defer save(name+".bkp", 5*time.Second) // Keep a backup as well
|
||||
|
||||
// drive timeout by default is 2 minutes, we do not need to wait longer.
|
||||
return save(name, time.Minute)
|
||||
|
||||
+8
-21
@@ -107,35 +107,22 @@ func (dui DataUsageInfo) tierStats() []madmin.TierInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
cfgs := globalTierConfigMgr.ListTiers()
|
||||
if len(cfgs) == 0 {
|
||||
if globalTierConfigMgr.Empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ts := make(map[string]madmin.TierStats, len(cfgs)+1)
|
||||
ts := make(map[string]madmin.TierStats)
|
||||
dui.TierStats.populateStats(ts)
|
||||
|
||||
infos := make([]madmin.TierInfo, 0, len(ts))
|
||||
|
||||
// Add STANDARD (hot-tier)
|
||||
ts[minioHotTier] = madmin.TierStats{}
|
||||
infos = append(infos, madmin.TierInfo{
|
||||
Name: minioHotTier,
|
||||
Type: "internal",
|
||||
})
|
||||
// Add configured remote tiers
|
||||
for _, cfg := range cfgs {
|
||||
ts[cfg.Name] = madmin.TierStats{}
|
||||
for tier, stats := range ts {
|
||||
infos = append(infos, madmin.TierInfo{
|
||||
Name: cfg.Name,
|
||||
Type: cfg.Type.String(),
|
||||
Name: tier,
|
||||
Type: globalTierConfigMgr.TierType(tier),
|
||||
Stats: stats,
|
||||
})
|
||||
}
|
||||
|
||||
ts = dui.TierStats.adminStats(ts)
|
||||
for i := range infos {
|
||||
info := infos[i]
|
||||
infos[i].Stats = ts[info.Name]
|
||||
}
|
||||
|
||||
sort.Slice(infos, func(i, j int) bool {
|
||||
if infos[i].Type == "internal" {
|
||||
return true
|
||||
|
||||
+47
-43
@@ -915,33 +915,35 @@ func CreatePoolEndpoints(serverAddr string, poolArgs ...[][]string) ([]Endpoints
|
||||
}
|
||||
|
||||
orchestrated := IsKubernetes() || IsDocker()
|
||||
if !orchestrated {
|
||||
reverseProxy := (env.Get("_MINIO_REVERSE_PROXY", "") != "") && ((env.Get("MINIO_CI_CD", "") != "") || (env.Get("CI", "") != ""))
|
||||
// If not orchestrated
|
||||
if !orchestrated &&
|
||||
// and not setup in reverse proxy
|
||||
!reverseProxy {
|
||||
// Check whether same path is not used in endpoints of a host on different port.
|
||||
// Only verify this on baremetal setups, DNS is not available in orchestrated
|
||||
// environments so we can't do much here.
|
||||
{
|
||||
pathIPMap := make(map[string]set.StringSet)
|
||||
hostIPCache := make(map[string]set.StringSet)
|
||||
for _, endpoint := range endpoints {
|
||||
host := endpoint.Hostname()
|
||||
hostIPSet, ok := hostIPCache[host]
|
||||
if !ok {
|
||||
var err error
|
||||
hostIPSet, err = getHostIP(host)
|
||||
if err != nil {
|
||||
return nil, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("host '%s' cannot resolve: %s", host, err))
|
||||
}
|
||||
hostIPCache[host] = hostIPSet
|
||||
pathIPMap := make(map[string]set.StringSet)
|
||||
hostIPCache := make(map[string]set.StringSet)
|
||||
for _, endpoint := range endpoints {
|
||||
host := endpoint.Hostname()
|
||||
hostIPSet, ok := hostIPCache[host]
|
||||
if !ok {
|
||||
var err error
|
||||
hostIPSet, err = getHostIP(host)
|
||||
if err != nil {
|
||||
return nil, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("host '%s' cannot resolve: %s", host, err))
|
||||
}
|
||||
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
||||
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
||||
return nil, setupType,
|
||||
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("same path '%s' can not be served by different port on same address", endpoint.Path))
|
||||
}
|
||||
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
||||
} else {
|
||||
pathIPMap[endpoint.Path] = hostIPSet
|
||||
hostIPCache[host] = hostIPSet
|
||||
}
|
||||
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
||||
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
||||
return nil, setupType,
|
||||
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("same path '%s' can not be served by different port on same address", endpoint.Path))
|
||||
}
|
||||
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
||||
} else {
|
||||
pathIPMap[endpoint.Path] = hostIPSet
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1113,32 +1115,34 @@ func CreateEndpoints(serverAddr string, args ...[]string) (Endpoints, SetupType,
|
||||
}
|
||||
|
||||
orchestrated := IsKubernetes() || IsDocker()
|
||||
if !orchestrated {
|
||||
reverseProxy := (env.Get("_MINIO_REVERSE_PROXY", "") != "") && ((env.Get("MINIO_CI_CD", "") != "") || (env.Get("CI", "") != ""))
|
||||
// If not orchestrated
|
||||
if !orchestrated &&
|
||||
// and not setup in reverse proxy
|
||||
!reverseProxy {
|
||||
// Check whether same path is not used in endpoints of a host on different port.
|
||||
// Only verify this on baremetal setups, DNS is not available in orchestrated
|
||||
// environments so we can't do much here.
|
||||
{
|
||||
pathIPMap := make(map[string]set.StringSet)
|
||||
hostIPCache := make(map[string]set.StringSet)
|
||||
for _, endpoint := range endpoints {
|
||||
host := endpoint.Hostname()
|
||||
hostIPSet, ok := hostIPCache[host]
|
||||
if !ok {
|
||||
hostIPSet, err = getHostIP(host)
|
||||
if err != nil {
|
||||
return endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("host '%s' cannot resolve: %s", host, err))
|
||||
}
|
||||
hostIPCache[host] = hostIPSet
|
||||
pathIPMap := make(map[string]set.StringSet)
|
||||
hostIPCache := make(map[string]set.StringSet)
|
||||
for _, endpoint := range endpoints {
|
||||
host := endpoint.Hostname()
|
||||
hostIPSet, ok := hostIPCache[host]
|
||||
if !ok {
|
||||
hostIPSet, err = getHostIP(host)
|
||||
if err != nil {
|
||||
return endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("host '%s' cannot resolve: %s", host, err))
|
||||
}
|
||||
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
||||
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
||||
return endpoints, setupType,
|
||||
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("same path '%s' can not be served by different port on same address", endpoint.Path))
|
||||
}
|
||||
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
||||
} else {
|
||||
pathIPMap[endpoint.Path] = hostIPSet
|
||||
hostIPCache[host] = hostIPSet
|
||||
}
|
||||
if IPSet, ok := pathIPMap[endpoint.Path]; ok {
|
||||
if !IPSet.Intersection(hostIPSet).IsEmpty() {
|
||||
return endpoints, setupType,
|
||||
config.ErrInvalidErasureEndpoints(nil).Msg(fmt.Sprintf("same path '%s' can not be served by different port on same address", endpoint.Path))
|
||||
}
|
||||
pathIPMap[endpoint.Path] = IPSet.Union(hostIPSet)
|
||||
} else {
|
||||
pathIPMap[endpoint.Path] = hostIPSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,11 @@ func (fi FileInfo) ToObjectInfo(bucket, object string, versioned bool) ObjectInf
|
||||
objInfo.ReplicationStatusInternal = fi.ReplicationState.ReplicationStatusInternal
|
||||
objInfo.VersionPurgeStatusInternal = fi.ReplicationState.VersionPurgeStatusInternal
|
||||
objInfo.ReplicationStatus = fi.ReplicationStatus()
|
||||
if objInfo.ReplicationStatus.Empty() { // overlay x-amx-replication-status if present for replicas
|
||||
if st, ok := fi.Metadata[xhttp.AmzBucketReplicationStatus]; ok && st == string(replication.Replica) {
|
||||
objInfo.ReplicationStatus = replication.StatusType(st)
|
||||
}
|
||||
}
|
||||
objInfo.VersionPurgeStatus = fi.VersionPurgeStatus()
|
||||
|
||||
objInfo.TransitionedObject = TransitionedObject{
|
||||
|
||||
@@ -323,7 +323,7 @@ func (er erasureObjects) ListMultipartUploads(ctx context.Context, bucket, objec
|
||||
UploadID: base64.RawURLEncoding.EncodeToString([]byte(fmt.Sprintf("%s.%s", globalDeploymentID(), uploadID))),
|
||||
Initiated: startTime,
|
||||
})
|
||||
|
||||
populatedUploadIds.Add(uploadID)
|
||||
}
|
||||
|
||||
sort.Slice(uploads, func(i int, j int) bool {
|
||||
|
||||
+32
-3
@@ -132,15 +132,18 @@ func (er erasureObjects) CopyObject(ctx context.Context, srcBucket, srcObject, d
|
||||
versionID = mustGetUUID()
|
||||
fi.IsLatest = true // we are creating a new version so this is latest.
|
||||
}
|
||||
modTime = UTCNow()
|
||||
}
|
||||
|
||||
modTime = UTCNow() // We only preserve modTime if dstOpts.MTime is true.
|
||||
// in all other cases mtime is latest.
|
||||
|
||||
fi.VersionID = versionID // set any new versionID we might have created
|
||||
fi.ModTime = modTime // set modTime for the new versionID
|
||||
if !dstOpts.MTime.IsZero() {
|
||||
modTime = dstOpts.MTime
|
||||
fi.ModTime = dstOpts.MTime
|
||||
}
|
||||
|
||||
fi.Metadata = srcInfo.UserDefined
|
||||
srcInfo.UserDefined["etag"] = srcInfo.ETag
|
||||
|
||||
@@ -663,6 +666,32 @@ func readAllXL(ctx context.Context, disks []StorageAPI, bucket, object string, r
|
||||
return metaFileInfos, errs
|
||||
}
|
||||
|
||||
// Checking if an object is dangling costs some IOPS; hence implementing this function
|
||||
// which decides which condition it is useful to check if an object is dangling
|
||||
//
|
||||
// errs: errors from reading xl.meta in all disks
|
||||
// err: reduced errs
|
||||
// bucket: the object name in question
|
||||
func shouldCheckForDangling(err error, errs []error, bucket string) bool {
|
||||
// Avoid data in .minio.sys for now
|
||||
if bucket == minioMetaBucket {
|
||||
return false
|
||||
}
|
||||
switch {
|
||||
// Check if we have a read quorum issue
|
||||
case errors.Is(err, errErasureReadQuorum):
|
||||
return true
|
||||
// Check if the object is inexistent in most disks but not all of them
|
||||
case errors.Is(err, errFileNotFound) || errors.Is(err, errFileVersionNotFound):
|
||||
for i := range errs {
|
||||
if errs[i] == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (er erasureObjects) getObjectFileInfo(ctx context.Context, bucket, object string, opts ObjectOptions, readData bool) (fi FileInfo, metaArr []FileInfo, onlineDisks []StorageAPI, err error) {
|
||||
disks := er.getDisks()
|
||||
|
||||
@@ -677,7 +706,7 @@ func (er erasureObjects) getObjectFileInfo(ctx context.Context, bucket, object s
|
||||
|
||||
readQuorum, _, err := objectQuorumFromMeta(ctx, metaArr, errs, er.defaultParityCount)
|
||||
if err != nil {
|
||||
if errors.Is(err, errErasureReadQuorum) && !strings.HasPrefix(bucket, minioMetaBucket) {
|
||||
if shouldCheckForDangling(err, errs, bucket) {
|
||||
_, derr := er.deleteIfDangling(ctx, bucket, object, metaArr, errs, nil, opts)
|
||||
if derr != nil {
|
||||
err = derr
|
||||
@@ -687,7 +716,7 @@ func (er erasureObjects) getObjectFileInfo(ctx context.Context, bucket, object s
|
||||
}
|
||||
|
||||
if reducedErr := reduceReadQuorumErrs(ctx, errs, objectOpIgnoredErrs, readQuorum); reducedErr != nil {
|
||||
if errors.Is(reducedErr, errErasureReadQuorum) && !strings.HasPrefix(bucket, minioMetaBucket) {
|
||||
if shouldCheckForDangling(err, errs, bucket) {
|
||||
_, derr := er.deleteIfDangling(ctx, bucket, object, metaArr, errs, nil, opts)
|
||||
if derr != nil {
|
||||
reducedErr = derr
|
||||
|
||||
@@ -701,10 +701,12 @@ func (set *erasureObjects) listObjectsToDecommission(ctx context.Context, bi dec
|
||||
return fmt.Errorf("no online drives found for set with endpoints %s", set.getEndpoints())
|
||||
}
|
||||
|
||||
listQuorum := (len(disks) + 1) / 2
|
||||
|
||||
// How to resolve partial results.
|
||||
resolver := metadataResolutionParams{
|
||||
dirQuorum: len(disks) / 2, // make sure to capture all quorum ratios
|
||||
objQuorum: len(disks) / 2, // make sure to capture all quorum ratios
|
||||
dirQuorum: listQuorum, // make sure to capture all quorum ratios
|
||||
objQuorum: listQuorum, // make sure to capture all quorum ratios
|
||||
bucket: bi.Name,
|
||||
}
|
||||
|
||||
@@ -714,7 +716,7 @@ func (set *erasureObjects) listObjectsToDecommission(ctx context.Context, bi dec
|
||||
path: bi.Prefix,
|
||||
recursive: true,
|
||||
forwardTo: "",
|
||||
minDisks: len(disks) / 2, // to capture all quorum ratios
|
||||
minDisks: len(disks) / 2,
|
||||
reportNotFound: false,
|
||||
agreed: fn,
|
||||
partial: func(entries metaCacheEntries, _ []error) {
|
||||
|
||||
+23
-32
@@ -970,7 +970,7 @@ func (z *erasureServerPools) GetObjectInfo(ctx context.Context, bucket, object s
|
||||
// PutObject - writes an object to least used erasure pool.
|
||||
func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, opts ObjectOptions) (ObjectInfo, error) {
|
||||
// Validate put object input args.
|
||||
if err := checkPutObjectArgs(ctx, bucket, object, z); err != nil {
|
||||
if err := checkPutObjectArgs(ctx, bucket, object); err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
|
||||
@@ -2253,11 +2253,12 @@ type HealthOptions struct {
|
||||
// additionally with any specific heuristic information which
|
||||
// was queried
|
||||
type HealthResult struct {
|
||||
Healthy bool
|
||||
HealingDrives int
|
||||
UnhealthyPools []struct {
|
||||
Healthy bool
|
||||
HealingDrives int
|
||||
ESHealth []struct {
|
||||
Maintenance bool
|
||||
PoolID, SetID int
|
||||
HealthyDrives int
|
||||
WriteQuorum int
|
||||
}
|
||||
WriteQuorum int
|
||||
@@ -2372,50 +2373,40 @@ func (z *erasureServerPools) Health(ctx context.Context, opts HealthOptions) Hea
|
||||
}
|
||||
|
||||
result := HealthResult{
|
||||
HealingDrives: len(aggHealStateResult.HealDisks),
|
||||
Healthy: true,
|
||||
WriteQuorum: maximumWriteQuorum,
|
||||
UsingDefaults: usingDefaults, // indicates if config was not initialized and we are using defaults on this node.
|
||||
}
|
||||
|
||||
for poolIdx := range erasureSetUpCount {
|
||||
for setIdx := range erasureSetUpCount[poolIdx] {
|
||||
result.ESHealth = append(result.ESHealth, struct {
|
||||
Maintenance bool
|
||||
PoolID, SetID int
|
||||
HealthyDrives, WriteQuorum int
|
||||
}{
|
||||
Maintenance: opts.Maintenance,
|
||||
SetID: setIdx,
|
||||
PoolID: poolIdx,
|
||||
HealthyDrives: erasureSetUpCount[poolIdx][setIdx],
|
||||
WriteQuorum: poolWriteQuorums[poolIdx],
|
||||
})
|
||||
|
||||
if erasureSetUpCount[poolIdx][setIdx] < poolWriteQuorums[poolIdx] {
|
||||
logger.LogIf(logger.SetReqInfo(ctx, reqInfo),
|
||||
fmt.Errorf("Write quorum may be lost on pool: %d, set: %d, expected write quorum: %d",
|
||||
poolIdx, setIdx, poolWriteQuorums[poolIdx]))
|
||||
result.UnhealthyPools = append(result.UnhealthyPools, struct {
|
||||
Maintenance bool
|
||||
PoolID, SetID, WriteQuorum int
|
||||
}{
|
||||
Maintenance: opts.Maintenance,
|
||||
SetID: setIdx,
|
||||
PoolID: poolIdx,
|
||||
WriteQuorum: poolWriteQuorums[poolIdx],
|
||||
})
|
||||
result.Healthy = false
|
||||
}
|
||||
}
|
||||
if len(result.UnhealthyPools) > 0 {
|
||||
// We have unhealthy pools return error.
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// when maintenance is not specified we don't have
|
||||
// to look at the healing side of the code.
|
||||
if !opts.Maintenance {
|
||||
return HealthResult{
|
||||
Healthy: true,
|
||||
WriteQuorum: maximumWriteQuorum,
|
||||
UsingDefaults: usingDefaults, // indicates if config was not initialized and we are using defaults on this node.
|
||||
}
|
||||
if opts.Maintenance {
|
||||
result.Healthy = result.Healthy && len(aggHealStateResult.HealDisks) == 0
|
||||
result.HealingDrives = len(aggHealStateResult.HealDisks)
|
||||
}
|
||||
|
||||
return HealthResult{
|
||||
Healthy: len(aggHealStateResult.HealDisks) == 0,
|
||||
HealingDrives: len(aggHealStateResult.HealDisks),
|
||||
WriteQuorum: maximumWriteQuorum,
|
||||
UsingDefaults: usingDefaults, // indicates if config was not initialized and we are using defaults on this node.
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// PutObjectMetadata - replace or add tags to an existing object
|
||||
|
||||
@@ -217,6 +217,10 @@ func (s *erasureSets) connectDisks() {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if cdisk != nil {
|
||||
// Close previous offline disk.
|
||||
cdisk.Close()
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(endpoint Endpoint) {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
@@ -26,7 +25,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/reedsolomon"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
)
|
||||
|
||||
@@ -85,7 +83,7 @@ func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, data
|
||||
|
||||
// We have written all the blocks, write the last remaining block.
|
||||
if write < int64(len(block)) {
|
||||
n, err := xioutil.Copy(dst, bytes.NewReader(block[:write]))
|
||||
n, err := dst.Write(block[:write])
|
||||
if err != nil {
|
||||
// The writer will be closed incase of range queries, which will emit ErrClosedPipe.
|
||||
// The reader pipe might be closed at ListObjects io.EOF ignore it.
|
||||
@@ -94,12 +92,12 @@ func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, data
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
totalWritten += n
|
||||
totalWritten += int64(n)
|
||||
break
|
||||
}
|
||||
|
||||
// Copy the block.
|
||||
n, err := xioutil.Copy(dst, bytes.NewReader(block))
|
||||
n, err := dst.Write(block)
|
||||
if err != nil {
|
||||
// The writer will be closed incase of range queries, which will emit ErrClosedPipe.
|
||||
// The reader pipe might be closed at ListObjects io.EOF ignore it.
|
||||
@@ -110,10 +108,10 @@ func writeDataBlocks(ctx context.Context, dst io.Writer, enBlocks [][]byte, data
|
||||
}
|
||||
|
||||
// Decrement output size.
|
||||
write -= n
|
||||
write -= int64(n)
|
||||
|
||||
// Increment written.
|
||||
totalWritten += n
|
||||
totalWritten += int64(n)
|
||||
}
|
||||
|
||||
// Success.
|
||||
|
||||
+2
-1
@@ -433,6 +433,7 @@ func (er erasureObjects) nsScanner(ctx context.Context, buckets []BucketInfo, wa
|
||||
}
|
||||
logger.LogOnceIf(ctx, cache.save(ctx, er, dataUsageCacheName), "nsscanner-cache-update")
|
||||
updates <- cache.clone()
|
||||
|
||||
lastSave = cache.Info.LastUpdate
|
||||
case v, ok := <-bucketResults:
|
||||
if !ok {
|
||||
@@ -440,7 +441,7 @@ func (er erasureObjects) nsScanner(ctx context.Context, buckets []BucketInfo, wa
|
||||
cache.Info.NextCycle = wantCycle
|
||||
cache.Info.LastUpdate = time.Now()
|
||||
logger.LogOnceIf(ctx, cache.save(ctx, er, dataUsageCacheName), "nsscanner-channel-closed")
|
||||
updates <- cache
|
||||
updates <- cache.clone()
|
||||
return
|
||||
}
|
||||
cache.replace(v.Name, v.Parent, v.Entry)
|
||||
|
||||
@@ -104,7 +104,7 @@ func (evnot *EventNotifier) InitBucketTargets(ctx context.Context, objAPI Object
|
||||
for res := range evnot.targetResCh {
|
||||
if res.Err != nil {
|
||||
reqInfo := &logger.ReqInfo{}
|
||||
reqInfo.AppendTags("targetID", res.ID.Name)
|
||||
reqInfo.AppendTags("targetID", res.ID.String())
|
||||
logger.LogOnceIf(logger.SetReqInfo(GlobalContext, reqInfo), res.Err, res.ID.String())
|
||||
}
|
||||
}
|
||||
@@ -128,40 +128,6 @@ func (evnot *EventNotifier) AddRulesMap(bucketName string, rulesMap event.RulesM
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveRulesMap - removes rules map for bucket name.
|
||||
func (evnot *EventNotifier) RemoveRulesMap(bucketName string, rulesMap event.RulesMap) {
|
||||
evnot.Lock()
|
||||
defer evnot.Unlock()
|
||||
|
||||
evnot.bucketRulesMap[bucketName].Remove(rulesMap)
|
||||
if len(evnot.bucketRulesMap[bucketName]) == 0 {
|
||||
delete(evnot.bucketRulesMap, bucketName)
|
||||
}
|
||||
}
|
||||
|
||||
// ConfiguredTargetIDs - returns list of configured target id's
|
||||
func (evnot *EventNotifier) ConfiguredTargetIDs() []event.TargetID {
|
||||
if evnot == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
evnot.RLock()
|
||||
defer evnot.RUnlock()
|
||||
|
||||
var targetIDs []event.TargetID
|
||||
for _, rmap := range evnot.bucketRulesMap {
|
||||
for _, rules := range rmap {
|
||||
for _, targetSet := range rules {
|
||||
for id := range targetSet {
|
||||
targetIDs = append(targetIDs, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetIDs
|
||||
}
|
||||
|
||||
// RemoveNotification - removes all notification configuration for bucket name.
|
||||
func (evnot *EventNotifier) RemoveNotification(bucketName string) {
|
||||
evnot.Lock()
|
||||
|
||||
@@ -18,20 +18,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/pkg/sftp"
|
||||
ftp "goftp.io/server/v2"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var globalRemoteFTPClientTransport = NewRemoteTargetHTTPTransport(true)()
|
||||
@@ -75,196 +69,6 @@ func (log *minioLogger) PrintResponse(sessionID string, code int, message string
|
||||
}
|
||||
}
|
||||
|
||||
func acceptSFTPConnection(conn net.Conn, config *ssh.ServerConfig) {
|
||||
// For SSH handshake keep a 2 minute deadline, as OpensSSH default.
|
||||
conn.SetDeadline(time.Now().Add(2 * time.Minute))
|
||||
|
||||
// Before use, a handshake must be performed on the incoming net.Conn.
|
||||
sconn, chans, reqs, err := ssh.NewServerConn(conn, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Once we are done with SSH handshake, remove deadline.
|
||||
conn.SetDeadline(time.Time{})
|
||||
|
||||
// The incoming Request channel must be serviced.
|
||||
go ssh.DiscardRequests(reqs)
|
||||
|
||||
// Service the incoming Channel channel.
|
||||
for newChannel := range chans {
|
||||
// Channels have a type, depending on the application level
|
||||
// protocol intended. In the case of an SFTP session, this is "subsystem"
|
||||
// with a payload string of "<length=4>sftp"
|
||||
if newChannel.ChannelType() != "session" {
|
||||
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
|
||||
continue
|
||||
}
|
||||
|
||||
channel, requests, err := newChannel.Accept()
|
||||
if err != nil {
|
||||
logger.LogOnceIf(context.Background(), fmt.Errorf("unable to accept the connection requests channel: %w", err), "accept-channel-sftp")
|
||||
continue
|
||||
}
|
||||
|
||||
// Sessions have out-of-band requests such as "shell",
|
||||
// "pty-req" and "env". Here we handle only the
|
||||
// "subsystem" request.
|
||||
go func(in <-chan *ssh.Request) {
|
||||
for req := range in {
|
||||
ok := false
|
||||
if req.Type == "subsystem" {
|
||||
if len(req.Payload) > 4 && string(req.Payload[4:]) == "sftp" {
|
||||
ok = true
|
||||
go handleSFTPConnection(channel, sconn)
|
||||
}
|
||||
}
|
||||
|
||||
if req.WantReply {
|
||||
// We only reply to SSH packets that have `sftp` payload, all other
|
||||
// packets are rejected
|
||||
req.Reply(ok, nil)
|
||||
}
|
||||
}
|
||||
}(requests)
|
||||
}
|
||||
}
|
||||
|
||||
func handleSFTPConnection(channel ssh.Channel, sconn *ssh.ServerConn) {
|
||||
// Create the server instance for the channel using the handler we created above.
|
||||
server := sftp.NewRequestServer(channel, NewSFTPDriver(sconn.Permissions), sftp.WithRSAllocator())
|
||||
defer server.Close()
|
||||
|
||||
server.Serve()
|
||||
}
|
||||
|
||||
func startSFTPServer(c *cli.Context) {
|
||||
args := c.StringSlice("sftp")
|
||||
|
||||
var (
|
||||
port int
|
||||
publicIP string
|
||||
sshPrivateKey string
|
||||
)
|
||||
|
||||
var err error
|
||||
for _, arg := range args {
|
||||
tokens := strings.SplitN(arg, "=", 2)
|
||||
if len(tokens) != 2 {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s", arg), "unable to start SFTP server")
|
||||
}
|
||||
switch tokens[0] {
|
||||
case "address":
|
||||
host, portStr, err := net.SplitHostPort(tokens[1])
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s (%v)", arg, err), "unable to start SFTP server")
|
||||
}
|
||||
port, err = strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s (%v)", arg, err), "unable to start SFTP server")
|
||||
}
|
||||
if port < 1 || port > 65535 {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s, (port number must be between 1 to 65535)", arg), "unable to start SFTP server")
|
||||
}
|
||||
publicIP = host
|
||||
case "ssh-private-key":
|
||||
sshPrivateKey = tokens[1]
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
port = 8022 // Default SFTP port, since no port was given.
|
||||
}
|
||||
|
||||
if sshPrivateKey == "" {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is mandatory for --sftp='ssh-private-key=path/to/id_ecdsa'"), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
privateBytes, err := os.ReadFile(sshPrivateKey)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is not accessible: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is not parseable: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
// An SSH server is represented by a ServerConfig, which holds
|
||||
// certificate details and handles authentication of ServerConns.
|
||||
config := &ssh.ServerConfig{
|
||||
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
||||
if globalIAMSys.LDAPConfig.Enabled() {
|
||||
targetUser, targetGroups, err := globalIAMSys.LDAPConfig.Bind(c.User(), string(pass))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ldapPolicies, _ := globalIAMSys.PolicyDBGet(targetUser, false, targetGroups...)
|
||||
if len(ldapPolicies) == 0 {
|
||||
return nil, errAuthentication
|
||||
}
|
||||
return &ssh.Permissions{
|
||||
CriticalOptions: map[string]string{
|
||||
ldapUser: targetUser,
|
||||
ldapUserN: c.User(),
|
||||
},
|
||||
Extensions: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
ui, ok := globalIAMSys.GetUser(context.Background(), c.User())
|
||||
if !ok {
|
||||
return nil, errNoSuchUser
|
||||
}
|
||||
|
||||
if subtle.ConstantTimeCompare([]byte(ui.Credentials.SecretKey), pass) == 1 {
|
||||
return &ssh.Permissions{
|
||||
CriticalOptions: map[string]string{
|
||||
"accessKey": c.User(),
|
||||
},
|
||||
Extensions: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
return nil, errAuthentication
|
||||
},
|
||||
}
|
||||
|
||||
config.AddHostKey(private)
|
||||
|
||||
// Once a ServerConfig has been configured, connections can be accepted.
|
||||
listener, err := net.Listen("tcp", net.JoinHostPort(publicIP, strconv.Itoa(port)))
|
||||
if err != nil {
|
||||
logger.Fatal(err, "unable to start listening on --sftp='port=%d'", port)
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("MinIO SFTP Server listening on %s", net.JoinHostPort(publicIP, strconv.Itoa(port))))
|
||||
|
||||
var tempDelay time.Duration // how long to sleep on accept failure
|
||||
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
// From https://github.com/golang/go/blob/4aa1efed4853ea067d665a952eee77c52faac774/src/net/http/server.go#L3046
|
||||
if ne, ok := err.(net.Error); ok && ne.Temporary() {
|
||||
if tempDelay == 0 {
|
||||
tempDelay = 5 * time.Millisecond
|
||||
} else {
|
||||
tempDelay *= 2
|
||||
}
|
||||
if max := 1 * time.Second; tempDelay > max {
|
||||
tempDelay = max
|
||||
}
|
||||
logger.LogOnceIf(context.Background(), fmt.Errorf("error while accepting connections: %w, retrying in %s", err, tempDelay), "accept-limit-sftp")
|
||||
time.Sleep(tempDelay)
|
||||
continue
|
||||
}
|
||||
logger.Fatal(err, "unrecoverable error while accepting new connections")
|
||||
}
|
||||
|
||||
go acceptSFTPConnection(conn, config)
|
||||
}
|
||||
}
|
||||
|
||||
func startFTPServer(c *cli.Context) {
|
||||
args := c.StringSlice("ftp")
|
||||
|
||||
|
||||
+33
-15
@@ -90,21 +90,15 @@ func ClusterReadCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
}
|
||||
|
||||
// ReadinessCheckHandler Checks if the process is up. Always returns success.
|
||||
// ReadinessCheckHandler checks whether MinIO is up and ready to serve requests.
|
||||
// It also checks whether the KMS is available and whether etcd is reachable,
|
||||
// if configured.
|
||||
func ReadinessCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
LivenessCheckHandler(w, r)
|
||||
}
|
||||
|
||||
// LivenessCheckHandler - Checks if the process is up. Always returns success.
|
||||
func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
objLayer := newObjectLayerFn()
|
||||
if objLayer == nil {
|
||||
// Service not initialized yet
|
||||
w.Header().Set(xhttp.MinIOServerStatus, unavailable)
|
||||
if objLayer := newObjectLayerFn(); objLayer == nil {
|
||||
w.Header().Set(xhttp.MinIOServerStatus, unavailable) // Service not initialized yet
|
||||
}
|
||||
|
||||
peerCall := r.Header.Get(xhttp.MinIOPeerCall) != ""
|
||||
if peerCall {
|
||||
if r.Header.Get(xhttp.MinIOPeerCall) != "" {
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -120,7 +114,7 @@ func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Verify if KMS is reachable if its configured
|
||||
if GlobalKMS != nil && !peerCall {
|
||||
if GlobalKMS != nil {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
@@ -153,6 +147,30 @@ func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func LivenessCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if objLayer := newObjectLayerFn(); objLayer == nil {
|
||||
w.Header().Set(xhttp.MinIOServerStatus, unavailable) // Service not initialized yet
|
||||
}
|
||||
if r.Header.Get(xhttp.MinIOPeerCall) != "" {
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
return
|
||||
}
|
||||
|
||||
if int(globalHTTPStats.loadRequestsInQueue()) > globalAPIConfig.getRequestsPoolCapacity() {
|
||||
apiErr := getAPIError(ErrBusy)
|
||||
switch r.Method {
|
||||
case http.MethodHead:
|
||||
writeResponse(w, apiErr.HTTPStatusCode, nil, mimeNone)
|
||||
case http.MethodGet:
|
||||
writeErrorResponse(r.Context(), w, apiErr, r.URL)
|
||||
}
|
||||
return
|
||||
}
|
||||
writeResponse(w, http.StatusOK, nil, mimeNone)
|
||||
}
|
||||
|
||||
+3
-3
@@ -420,10 +420,10 @@ func (c *iamCache) updateUserWithClaims(key string, u UserIdentity) error {
|
||||
}
|
||||
u.Credentials.Claims = jwtClaims.Map()
|
||||
}
|
||||
if !u.Credentials.IsTemp() {
|
||||
c.iamUsersMap[key] = u
|
||||
} else {
|
||||
if u.Credentials.IsTemp() && !u.Credentials.IsServiceAccount() {
|
||||
c.iamSTSAccountsMap[key] = u
|
||||
} else {
|
||||
c.iamUsersMap[key] = u
|
||||
}
|
||||
c.updatedAt = time.Now()
|
||||
return nil
|
||||
|
||||
+16
-9
@@ -1663,18 +1663,25 @@ func (sys *IAMSys) PolicyDBUpdateLDAP(ctx context.Context, isAttach bool,
|
||||
return
|
||||
}
|
||||
if dn == "" {
|
||||
err = errNoSuchUser
|
||||
return
|
||||
// Still attempt to detach if provided user is a DN.
|
||||
if !isAttach && sys.LDAPConfig.IsLDAPUserDN(r.User) {
|
||||
dn = r.User
|
||||
} else {
|
||||
err = errNoSuchUser
|
||||
return
|
||||
}
|
||||
}
|
||||
isGroup = false
|
||||
} else {
|
||||
var exists bool
|
||||
if exists, err = sys.LDAPConfig.DoesGroupDNExist(r.Group); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return
|
||||
} else if !exists {
|
||||
err = errNoSuchGroup
|
||||
return
|
||||
if isAttach {
|
||||
var exists bool
|
||||
if exists, err = sys.LDAPConfig.DoesGroupDNExist(r.Group); err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return
|
||||
} else if !exists {
|
||||
err = errNoSuchGroup
|
||||
return
|
||||
}
|
||||
}
|
||||
dn = r.Group
|
||||
isGroup = true
|
||||
|
||||
+24
-1
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -693,7 +694,7 @@ func getClusterObjectVersionsMD() MetricDescription {
|
||||
Namespace: clusterMetricNamespace,
|
||||
Subsystem: objectsSubsystem,
|
||||
Name: versionDistribution,
|
||||
Help: "Distribution of object sizes across a cluster",
|
||||
Help: "Distribution of object versions across a cluster",
|
||||
Type: histogramMetric,
|
||||
}
|
||||
}
|
||||
@@ -3187,6 +3188,16 @@ func getClusterHealthStatusMD() MetricDescription {
|
||||
}
|
||||
}
|
||||
|
||||
func getClusterErasureSetToleranceMD() MetricDescription {
|
||||
return MetricDescription{
|
||||
Namespace: clusterMetricNamespace,
|
||||
Subsystem: "health",
|
||||
Name: "erasure_set_tolerance",
|
||||
Help: "Get erasure set tolerance status",
|
||||
Type: gaugeMetric,
|
||||
}
|
||||
}
|
||||
|
||||
func getClusterHealthMetrics() *MetricsGroup {
|
||||
mg := &MetricsGroup{
|
||||
cacheInterval: 10 * time.Second,
|
||||
@@ -3218,6 +3229,18 @@ func getClusterHealthMetrics() *MetricsGroup {
|
||||
Value: float64(health),
|
||||
})
|
||||
|
||||
for _, h := range result.ESHealth {
|
||||
labels := map[string]string{
|
||||
"pool": strconv.Itoa(h.PoolID),
|
||||
"set": strconv.Itoa(h.SetID),
|
||||
}
|
||||
metrics = append(metrics, Metric{
|
||||
Description: getClusterErasureSetToleranceMD(),
|
||||
VariableLabels: labels,
|
||||
Value: float64(h.HealthyDrives - h.WriteQuorum),
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
|
||||
|
||||
@@ -701,6 +701,31 @@ func (sys *NotificationSys) GetCPUs(ctx context.Context) []madmin.CPUs {
|
||||
return reply
|
||||
}
|
||||
|
||||
// GetNetInfo - Network information
|
||||
func (sys *NotificationSys) GetNetInfo(ctx context.Context) []madmin.NetInfo {
|
||||
reply := make([]madmin.NetInfo, len(sys.peerClients))
|
||||
|
||||
g := errgroup.WithNErrs(len(sys.peerClients))
|
||||
for index, client := range sys.peerClients {
|
||||
if client == nil {
|
||||
continue
|
||||
}
|
||||
index := index
|
||||
g.Go(func() error {
|
||||
var err error
|
||||
reply[index], err = sys.peerClients[index].GetNetInfo(ctx)
|
||||
return err
|
||||
}, index)
|
||||
}
|
||||
|
||||
for index, err := range g.Wait() {
|
||||
if err != nil {
|
||||
sys.addNodeErr(&reply[index], sys.peerClients[index], err)
|
||||
}
|
||||
}
|
||||
return reply
|
||||
}
|
||||
|
||||
// GetPartitions - Disk partition information
|
||||
func (sys *NotificationSys) GetPartitions(ctx context.Context) []madmin.Partitions {
|
||||
reply := make([]madmin.Partitions, len(sys.peerClients))
|
||||
|
||||
@@ -149,7 +149,6 @@ func checkObjectArgs(ctx context.Context, bucket, object string, obj ObjectLayer
|
||||
// This is done on purpose since the order of errors is
|
||||
// important here bucket does not exist error should
|
||||
// happen before we return an error for invalid object name.
|
||||
// FIXME: should be moved to handler layer.
|
||||
if err := checkBucketExist(ctx, bucket, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -170,16 +169,7 @@ func checkObjectArgs(ctx context.Context, bucket, object string, obj ObjectLayer
|
||||
}
|
||||
|
||||
// Checks for PutObject arguments validity, also validates if bucket exists.
|
||||
func checkPutObjectArgs(ctx context.Context, bucket, object string, obj getBucketInfoI) error {
|
||||
// Verify if bucket exists before validating object name.
|
||||
// This is done on purpose since the order of errors is
|
||||
// important here bucket does not exist error should
|
||||
// happen before we return an error for invalid object name.
|
||||
// FIXME: should be moved to handler layer.
|
||||
if err := checkBucketExist(ctx, bucket, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func checkPutObjectArgs(ctx context.Context, bucket, object string) error {
|
||||
if err := checkObjectNameForLengthAndSlash(bucket, object); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1198,7 +1198,7 @@ func hasSpaceFor(di []*DiskInfo, size int64) (bool, error) {
|
||||
if disk == nil || disk.Total == 0 {
|
||||
continue
|
||||
}
|
||||
if disk.FreeInodes < diskMinInodes && disk.UsedInodes > 0 {
|
||||
if !globalIsErasureSD && disk.FreeInodes < diskMinInodes && disk.UsedInodes > 0 {
|
||||
// We have an inode count, but not enough inodes.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -143,7 +143,10 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
|
||||
|
||||
metadata[xhttp.AmzObjectTagging] = objTags
|
||||
}
|
||||
|
||||
if r.Header.Get(xhttp.AmzBucketReplicationStatus) == replication.Replica.String() {
|
||||
metadata[ReservedMetadataPrefixLower+ReplicaStatus] = replication.Replica.String()
|
||||
metadata[ReservedMetadataPrefixLower+ReplicaTimestamp] = UTCNow().Format(time.RFC3339Nano)
|
||||
}
|
||||
retPerms := isPutActionAllowed(ctx, getRequestAuthType(r), bucket, object, r, policy.PutObjectRetentionAction)
|
||||
holdPerms := isPutActionAllowed(ctx, getRequestAuthType(r), bucket, object, r, policy.PutObjectLegalHoldAction)
|
||||
|
||||
|
||||
@@ -134,6 +134,17 @@ func (client *peerRESTClient) GetCPUs(ctx context.Context) (info madmin.CPUs, er
|
||||
return info, err
|
||||
}
|
||||
|
||||
// GetNetInfo - fetch network information for a remote node.
|
||||
func (client *peerRESTClient) GetNetInfo(ctx context.Context) (info madmin.NetInfo, err error) {
|
||||
respBody, err := client.callWithContext(ctx, peerRESTMethodNetHwInfo, nil, nil, -1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer xhttp.DrainBody(respBody)
|
||||
err = gob.NewDecoder(respBody).Decode(&info)
|
||||
return info, err
|
||||
}
|
||||
|
||||
// GetPartitions - fetch disk partition information for a remote node.
|
||||
func (client *peerRESTClient) GetPartitions(ctx context.Context) (info madmin.Partitions, err error) {
|
||||
respBody, err := client.callWithContext(ctx, peerRESTMethodDiskHwInfo, nil, nil, -1)
|
||||
|
||||
@@ -31,6 +31,7 @@ const (
|
||||
peerRESTMethodLocalStorageInfo = "/localstorageinfo"
|
||||
peerRESTMethodCPUInfo = "/cpuinfo"
|
||||
peerRESTMethodDiskHwInfo = "/diskhwinfo"
|
||||
peerRESTMethodNetHwInfo = "/nethwinfo"
|
||||
peerRESTMethodOsInfo = "/osinfo"
|
||||
peerRESTMethodMemInfo = "/meminfo"
|
||||
peerRESTMethodProcInfo = "/procinfo"
|
||||
|
||||
+18
-1
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/minio/madmin-go/v3"
|
||||
b "github.com/minio/minio/internal/bucket/bandwidth"
|
||||
"github.com/minio/minio/internal/event"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/minio/internal/pubsub"
|
||||
"github.com/minio/mux"
|
||||
@@ -375,6 +376,21 @@ func (s *peerRESTServer) GetCPUsHandler(w http.ResponseWriter, r *http.Request)
|
||||
logger.LogIf(ctx, gob.NewEncoder(w).Encode(info))
|
||||
}
|
||||
|
||||
// GetNetInfoHandler - returns network information.
|
||||
func (s *peerRESTServer) GetNetInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.IsValid(w, r) {
|
||||
s.writeErrorResponse(w, errors.New("Invalid request"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(r.Context())
|
||||
defer cancel()
|
||||
|
||||
info := madmin.GetNetInfo(r.Host, globalInternodeInterface)
|
||||
|
||||
logger.LogIf(ctx, gob.NewEncoder(w).Encode(info))
|
||||
}
|
||||
|
||||
// GetPartitionsHandler - returns disk partition information.
|
||||
func (s *peerRESTServer) GetPartitionsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.IsValid(w, r) {
|
||||
@@ -1408,7 +1424,7 @@ func (s *peerRESTServer) DevNull(w http.ResponseWriter, r *http.Request) {
|
||||
connectTime := time.Now()
|
||||
ctx := newContext(r, w, "DevNull")
|
||||
for {
|
||||
n, err := io.CopyN(io.Discard, r.Body, 128*humanize.KiByte)
|
||||
n, err := io.CopyN(xioutil.Discard, r.Body, 128*humanize.KiByte)
|
||||
atomic.AddUint64(&globalNetPerfRX.RX, uint64(n))
|
||||
if err != nil && err != io.EOF {
|
||||
// If there is a disconnection before globalNetPerfMinDuration (we give a margin of error of 1 sec)
|
||||
@@ -1460,6 +1476,7 @@ func registerPeerRESTHandlers(router *mux.Router) {
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodSysConfig).HandlerFunc(h(server.GetSysConfigHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodOsInfo).HandlerFunc(h(server.GetOSInfoHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDiskHwInfo).HandlerFunc(h(server.GetPartitionsHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodNetHwInfo).HandlerFunc(h(server.GetNetInfoHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodCPUInfo).HandlerFunc(h(server.GetCPUsHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodGetAllBucketStats).HandlerFunc(h(server.GetAllBucketStatsHandler))
|
||||
subrouter.Methods(http.MethodPost).Path(peerRESTVersionPrefix + peerRESTMethodDeleteBucketMetadata).HandlerFunc(h(server.DeleteBucketMetadataHandler)).Queries(restQueries(peerRESTBucket)...)
|
||||
|
||||
+6
-2
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/minio/madmin-go/v3"
|
||||
"github.com/minio/minio-go/v7"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/pkg/v2/randreader"
|
||||
)
|
||||
|
||||
@@ -148,6 +149,8 @@ func selfSpeedTest(ctx context.Context, opts speedTestOpts) (SpeedTestResult, er
|
||||
var downloadTimes madmin.TimeDurations
|
||||
var downloadTTFB madmin.TimeDurations
|
||||
wg.Add(opts.concurrency)
|
||||
|
||||
c := minio.Core{Client: globalMinioClient}
|
||||
for i := 0; i < opts.concurrency; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
@@ -161,7 +164,8 @@ func selfSpeedTest(ctx context.Context, opts speedTestOpts) (SpeedTestResult, er
|
||||
}
|
||||
tmpObjName := pathJoin(objNamePrefix, fmt.Sprintf("%d/%d", i, j))
|
||||
t := time.Now()
|
||||
r, err := globalMinioClient.GetObject(downloadsCtx, opts.bucketName, tmpObjName, gopts)
|
||||
|
||||
r, _, _, err := c.GetObject(downloadsCtx, opts.bucketName, tmpObjName, gopts)
|
||||
if err != nil {
|
||||
errResp, ok := err.(minio.ErrorResponse)
|
||||
if ok && errResp.StatusCode == http.StatusNotFound {
|
||||
@@ -178,7 +182,7 @@ func selfSpeedTest(ctx context.Context, opts speedTestOpts) (SpeedTestResult, er
|
||||
fbr := firstByteRecorder{
|
||||
r: r,
|
||||
}
|
||||
n, err := io.Copy(io.Discard, &fbr)
|
||||
n, err := xioutil.Copy(xioutil.Discard, &fbr)
|
||||
r.Close()
|
||||
if err == nil {
|
||||
response := time.Since(t)
|
||||
|
||||
+33
-7
@@ -314,6 +314,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
||||
secretKey string
|
||||
dates []interface{}
|
||||
policy string
|
||||
noFilename bool
|
||||
corruptedBase64 bool
|
||||
corruptedMultipart bool
|
||||
}{
|
||||
@@ -327,6 +328,17 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
||||
dates: []interface{}{curTimePlus5Min.Format(iso8601TimeFormat), curTime.Format(iso8601DateFormat), curTime.Format(yyyymmdd)},
|
||||
policy: `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], ["starts-with", "$key", "test/"], ["eq", "$x-amz-algorithm", "AWS4-HMAC-SHA256"], ["eq", "$x-amz-date", "%s"], ["eq", "$x-amz-credential", "` + credentials.AccessKey + `/%s/us-east-1/s3/aws4_request"],["eq", "$x-amz-meta-uuid", "1234"]]}`,
|
||||
},
|
||||
// Success case, no multipart filename.
|
||||
{
|
||||
objectName: "test",
|
||||
data: []byte("Hello, World"),
|
||||
expectedRespStatus: http.StatusNoContent,
|
||||
accessKey: credentials.AccessKey,
|
||||
secretKey: credentials.SecretKey,
|
||||
dates: []interface{}{curTimePlus5Min.Format(iso8601TimeFormat), curTime.Format(iso8601DateFormat), curTime.Format(yyyymmdd)},
|
||||
policy: `{"expiration": "%s","conditions":[["eq", "$bucket", "` + bucketName + `"], ["starts-with", "$key", "test/"], ["eq", "$x-amz-algorithm", "AWS4-HMAC-SHA256"], ["eq", "$x-amz-date", "%s"], ["eq", "$x-amz-credential", "` + credentials.AccessKey + `/%s/us-east-1/s3/aws4_request"],["eq", "$x-amz-meta-uuid", "1234"]]}`,
|
||||
noFilename: true,
|
||||
},
|
||||
// Success case, big body.
|
||||
{
|
||||
objectName: "test",
|
||||
@@ -399,7 +411,7 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr
|
||||
testCase.policy = fmt.Sprintf(testCase.policy, testCase.dates...)
|
||||
|
||||
req, perr := newPostRequestV4Generic("", bucketName, testCase.objectName, testCase.data, testCase.accessKey,
|
||||
testCase.secretKey, region, curTime, []byte(testCase.policy), nil, testCase.corruptedBase64, testCase.corruptedMultipart)
|
||||
testCase.secretKey, region, curTime, []byte(testCase.policy), nil, testCase.noFilename, testCase.corruptedBase64, testCase.corruptedMultipart)
|
||||
if perr != nil {
|
||||
t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", i+1, instanceType, perr)
|
||||
}
|
||||
@@ -539,7 +551,7 @@ func testPostPolicyBucketHandlerRedirect(obj ObjectLayer, instanceType string, t
|
||||
// Create a new POST request with success_action_redirect field specified
|
||||
req, perr := newPostRequestV4Generic("", bucketName, keyName, []byte("objData"),
|
||||
credentials.AccessKey, credentials.SecretKey, region, curTime,
|
||||
[]byte(policy), map[string]string{"success_action_redirect": redirectURL.String()}, false, false)
|
||||
[]byte(policy), map[string]string{"success_action_redirect": redirectURL.String()}, false, false, false)
|
||||
|
||||
if perr != nil {
|
||||
t.Fatalf("%s: Failed to create HTTP request for PostPolicyHandler: <ERROR> %v", instanceType, perr)
|
||||
@@ -647,7 +659,7 @@ func buildGenericPolicy(t time.Time, accessKey, region, bucketName, objectName s
|
||||
}
|
||||
|
||||
func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData []byte, accessKey, secretKey string, region string,
|
||||
t time.Time, policy []byte, addFormData map[string]string, corruptedB64 bool, corruptedMultipart bool,
|
||||
t time.Time, policy []byte, addFormData map[string]string, noFilename bool, corruptedB64 bool, corruptedMultipart bool,
|
||||
) (*http.Request, error) {
|
||||
// Get the user credential.
|
||||
credStr := getCredentialString(accessKey, region, t)
|
||||
@@ -662,9 +674,17 @@ func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData []
|
||||
// Presign with V4 signature based on the policy.
|
||||
signature := postPresignSignatureV4(encodedPolicy, t, secretKey, region)
|
||||
|
||||
// If there is no filename on multipart, get the filename from the key.
|
||||
key := objectName
|
||||
if noFilename {
|
||||
key += "/upload.txt"
|
||||
} else {
|
||||
key += "/${filename}"
|
||||
}
|
||||
|
||||
formData := map[string]string{
|
||||
"bucket": bucketName,
|
||||
"key": objectName + "/${filename}",
|
||||
"key": key,
|
||||
"x-amz-credential": credStr,
|
||||
"policy": encodedPolicy,
|
||||
"x-amz-signature": signature,
|
||||
@@ -689,7 +709,13 @@ func newPostRequestV4Generic(endPoint, bucketName, objectName string, objData []
|
||||
}
|
||||
// Set the File formData but don't if we want send an incomplete multipart request
|
||||
if !corruptedMultipart {
|
||||
writer, err := w.CreateFormFile("file", "upload.txt")
|
||||
var writer io.Writer
|
||||
var err error
|
||||
if noFilename {
|
||||
writer, err = w.CreateFormField("file")
|
||||
} else {
|
||||
writer, err = w.CreateFormFile("file", "upload.txt")
|
||||
}
|
||||
if err != nil {
|
||||
// return nil, err
|
||||
return nil, err
|
||||
@@ -716,12 +742,12 @@ func newPostRequestV4WithContentLength(endPoint, bucketName, objectName string,
|
||||
t := UTCNow()
|
||||
region := "us-east-1"
|
||||
policy := buildGenericPolicy(t, accessKey, region, bucketName, objectName, true)
|
||||
return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false)
|
||||
return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false, false)
|
||||
}
|
||||
|
||||
func newPostRequestV4(endPoint, bucketName, objectName string, objData []byte, accessKey, secretKey string) (*http.Request, error) {
|
||||
t := UTCNow()
|
||||
region := "us-east-1"
|
||||
policy := buildGenericPolicy(t, accessKey, region, bucketName, objectName, false)
|
||||
return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false)
|
||||
return newPostRequestV4Generic(endPoint, bucketName, objectName, objData, accessKey, secretKey, region, t, policy, nil, false, false, false)
|
||||
}
|
||||
|
||||
@@ -201,19 +201,74 @@ func (f *sftpDriver) Fileread(r *sftp.Request) (ra io.ReaderAt, err error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
type writerAt struct {
|
||||
w *io.PipeWriter
|
||||
wg *sync.WaitGroup
|
||||
// TransferError will catch network errors during transfer.
|
||||
// When TransferError() is called Close() will also
|
||||
// be called, so we do not need to Wait() here.
|
||||
func (w *writerAt) TransferError(err error) {
|
||||
_ = w.w.CloseWithError(err)
|
||||
_ = w.r.CloseWithError(err)
|
||||
w.err = err
|
||||
}
|
||||
|
||||
func (w *writerAt) Close() error {
|
||||
err := w.w.Close()
|
||||
func (w *writerAt) Close() (err error) {
|
||||
switch {
|
||||
case len(w.buffer) > 0:
|
||||
err = errors.New("some file segments were not flushed from the queue")
|
||||
_ = w.w.CloseWithError(err)
|
||||
case w.err != nil:
|
||||
// No need to close here since both pipes were
|
||||
// closing inside TransferError()
|
||||
err = w.err
|
||||
default:
|
||||
err = w.w.Close()
|
||||
}
|
||||
for i := range w.buffer {
|
||||
delete(w.buffer, i)
|
||||
}
|
||||
w.wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
type writerAt struct {
|
||||
w *io.PipeWriter
|
||||
r *io.PipeReader
|
||||
wg *sync.WaitGroup
|
||||
buffer map[int64][]byte
|
||||
err error
|
||||
|
||||
nextOffset int64
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (w *writerAt) WriteAt(b []byte, offset int64) (n int, err error) {
|
||||
return w.w.Write(b)
|
||||
w.m.Lock()
|
||||
defer w.m.Unlock()
|
||||
|
||||
if w.nextOffset == offset {
|
||||
n, err = w.w.Write(b)
|
||||
w.nextOffset += int64(n)
|
||||
} else {
|
||||
w.buffer[offset] = make([]byte, len(b))
|
||||
copy(w.buffer[offset], b)
|
||||
n = len(b)
|
||||
}
|
||||
|
||||
again:
|
||||
nextOut, ok := w.buffer[w.nextOffset]
|
||||
if ok {
|
||||
n, err = w.w.Write(nextOut)
|
||||
delete(w.buffer, w.nextOffset)
|
||||
w.nextOffset += int64(n)
|
||||
if n != len(nextOut) {
|
||||
return 0, fmt.Errorf("expected write size %d but wrote %d bytes", len(nextOut), n)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
goto again
|
||||
}
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (f *sftpDriver) Filewrite(r *sftp.Request) (w io.WriterAt, err error) {
|
||||
@@ -238,7 +293,12 @@ func (f *sftpDriver) Filewrite(r *sftp.Request) (w io.WriterAt, err error) {
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
|
||||
wa := &writerAt{w: pw, wg: &sync.WaitGroup{}}
|
||||
wa := &writerAt{
|
||||
buffer: make(map[int64][]byte),
|
||||
w: pw,
|
||||
r: pr,
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
wa.wg.Add(1)
|
||||
go func() {
|
||||
_, err := clnt.PutObject(r.Context(), bucket, object, pr, -1, minio.PutObjectOptions{SendContentMd5: true})
|
||||
@@ -298,6 +358,7 @@ func (f *sftpDriver) Filecmd(r *sftp.Request) (err error) {
|
||||
return err.Err
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
||||
case "Remove":
|
||||
bucket, object := path2BucketObject(r.Filepath)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2015-2023 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
xsftp "github.com/minio/pkg/v2/sftp"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type sftpLogger struct{}
|
||||
|
||||
func (s *sftpLogger) Info(tag xsftp.LogType, msg string) {
|
||||
logger.Info(msg)
|
||||
}
|
||||
|
||||
func (s *sftpLogger) Error(tag xsftp.LogType, err error) {
|
||||
switch tag {
|
||||
case xsftp.AcceptNetworkError:
|
||||
logger.LogOnceIf(context.Background(), err, "accept-limit-sftp")
|
||||
case xsftp.AcceptChannelError:
|
||||
logger.LogOnceIf(context.Background(), err, "accept-channel-sftp")
|
||||
case xsftp.SSHKeyExchangeError:
|
||||
logger.LogOnceIf(context.Background(), err, "key-exchange-sftp")
|
||||
default:
|
||||
logger.LogOnceIf(context.Background(), err, "unknown-error-sftp")
|
||||
}
|
||||
}
|
||||
|
||||
func startSFTPServer(c *cli.Context) {
|
||||
args := c.StringSlice("sftp")
|
||||
|
||||
var (
|
||||
port int
|
||||
publicIP string
|
||||
sshPrivateKey string
|
||||
)
|
||||
|
||||
var err error
|
||||
for _, arg := range args {
|
||||
tokens := strings.SplitN(arg, "=", 2)
|
||||
if len(tokens) != 2 {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s", arg), "unable to start SFTP server")
|
||||
}
|
||||
switch tokens[0] {
|
||||
case "address":
|
||||
host, portStr, err := net.SplitHostPort(tokens[1])
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s (%v)", arg, err), "unable to start SFTP server")
|
||||
}
|
||||
port, err = strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s (%v)", arg, err), "unable to start SFTP server")
|
||||
}
|
||||
if port < 1 || port > 65535 {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed to --sftp=%s, (port number must be between 1 to 65535)", arg), "unable to start SFTP server")
|
||||
}
|
||||
publicIP = host
|
||||
case "ssh-private-key":
|
||||
sshPrivateKey = tokens[1]
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 {
|
||||
port = 8022 // Default SFTP port, since no port was given.
|
||||
}
|
||||
|
||||
if sshPrivateKey == "" {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is mandatory for --sftp='ssh-private-key=path/to/id_ecdsa'"), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
privateBytes, err := os.ReadFile(sshPrivateKey)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is not accessible: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("invalid arguments passed, private key file is not parseable: %v", err), "unable to start SFTP server")
|
||||
}
|
||||
|
||||
// An SSH server is represented by a ServerConfig, which holds
|
||||
// certificate details and handles authentication of ServerConns.
|
||||
sshConfig := &ssh.ServerConfig{
|
||||
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
||||
if globalIAMSys.LDAPConfig.Enabled() {
|
||||
targetUser, targetGroups, err := globalIAMSys.LDAPConfig.Bind(c.User(), string(pass))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ldapPolicies, _ := globalIAMSys.PolicyDBGet(targetUser, false, targetGroups...)
|
||||
if len(ldapPolicies) == 0 {
|
||||
return nil, errAuthentication
|
||||
}
|
||||
return &ssh.Permissions{
|
||||
CriticalOptions: map[string]string{
|
||||
ldapUser: targetUser,
|
||||
ldapUserN: c.User(),
|
||||
},
|
||||
Extensions: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
ui, ok := globalIAMSys.GetUser(context.Background(), c.User())
|
||||
if !ok {
|
||||
return nil, errNoSuchUser
|
||||
}
|
||||
|
||||
if subtle.ConstantTimeCompare([]byte(ui.Credentials.SecretKey), pass) == 1 {
|
||||
return &ssh.Permissions{
|
||||
CriticalOptions: map[string]string{
|
||||
"accessKey": c.User(),
|
||||
},
|
||||
Extensions: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
return nil, errAuthentication
|
||||
},
|
||||
}
|
||||
|
||||
sshConfig.AddHostKey(private)
|
||||
|
||||
handleSFTPSession := func(channel ssh.Channel, sconn *ssh.ServerConn) {
|
||||
server := sftp.NewRequestServer(channel, NewSFTPDriver(sconn.Permissions), sftp.WithRSAllocator())
|
||||
defer server.Close()
|
||||
server.Serve()
|
||||
}
|
||||
|
||||
sftpServer, err := xsftp.NewServer(&xsftp.Options{
|
||||
PublicIP: publicIP,
|
||||
Port: port,
|
||||
// OpensSSH default handshake timeout is 2 minutes.
|
||||
SSHHandshakeDeadline: 2 * time.Minute,
|
||||
Logger: new(sftpLogger),
|
||||
SSHConfig: sshConfig,
|
||||
HandleSFTPSession: handleSFTPSession,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal(err, "Unable to start SFTP Server")
|
||||
}
|
||||
|
||||
err = sftpServer.Listen()
|
||||
if err != nil {
|
||||
logger.Fatal(err, "SFTP Server had an unrecoverable error while accepting connections")
|
||||
}
|
||||
}
|
||||
+4
-15
@@ -3787,14 +3787,6 @@ func (c *SiteReplicationSys) PeerEditReq(ctx context.Context, arg madmin.PeerInf
|
||||
p := c.state.Peers[i]
|
||||
if p.DeploymentID == arg.DeploymentID {
|
||||
p.Endpoint = arg.Endpoint
|
||||
if arg.DefaultBandwidth.IsSet {
|
||||
if arg.DefaultBandwidth.UpdatedAt.After(p.DefaultBandwidth.UpdatedAt) {
|
||||
p.DefaultBandwidth = arg.DefaultBandwidth
|
||||
}
|
||||
}
|
||||
if !arg.SyncState.Empty() {
|
||||
p.SyncState = arg.SyncState
|
||||
}
|
||||
c.state.Peers[arg.DeploymentID] = p
|
||||
}
|
||||
if p.DeploymentID == globalDeploymentID() {
|
||||
@@ -5234,10 +5226,14 @@ func (c *SiteReplicationSys) startResync(ctx context.Context, objAPI ObjectLayer
|
||||
Status: ResyncStarted.String(),
|
||||
OpType: "start",
|
||||
ResyncID: rs.ResyncID,
|
||||
Buckets: res.Buckets,
|
||||
}
|
||||
if len(res.Buckets) > 0 {
|
||||
res.ErrDetail = "partial failure in starting site resync"
|
||||
}
|
||||
if len(buckets) != 0 && len(res.Buckets) == len(buckets) {
|
||||
return res, fmt.Errorf("all buckets resync failed")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -5259,13 +5255,6 @@ func (c *SiteReplicationSys) cancelResync(ctx context.Context, objAPI ObjectLaye
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
switch rs.Status {
|
||||
case ResyncCanceled:
|
||||
return res, errSRResyncCanceled
|
||||
case ResyncCompleted, NoResync:
|
||||
return res, errSRNoResync
|
||||
}
|
||||
|
||||
res = madmin.SRResyncOpStatus{
|
||||
Status: rs.Status.String(),
|
||||
OpType: "cancel",
|
||||
|
||||
+13
-1
@@ -238,9 +238,15 @@ func driveSpeedTest(ctx context.Context, opts madmin.DriveSpeedTestOpts) madmin.
|
||||
}
|
||||
|
||||
localPaths := globalEndpoints.LocalDisksPaths()
|
||||
var ignoredPaths []string
|
||||
paths := func() (tmpPaths []string) {
|
||||
for _, lp := range localPaths {
|
||||
tmpPaths = append(tmpPaths, pathJoin(lp, minioMetaTmpBucket))
|
||||
if _, err := Lstat(pathJoin(lp, minioMetaBucket, formatConfigFile)); err == nil {
|
||||
tmpPaths = append(tmpPaths, pathJoin(lp, minioMetaTmpBucket))
|
||||
} else {
|
||||
// Use dperf on only formatted drives.
|
||||
ignoredPaths = append(ignoredPaths, lp)
|
||||
}
|
||||
}
|
||||
return tmpPaths
|
||||
}()
|
||||
@@ -274,6 +280,12 @@ func driveSpeedTest(ctx context.Context, opts madmin.DriveSpeedTestOpts) madmin.
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
for _, inp := range ignoredPaths {
|
||||
results = append(results, madmin.DrivePerf{
|
||||
Path: inp,
|
||||
Error: errFaultyDisk.Error(),
|
||||
})
|
||||
}
|
||||
return results
|
||||
}(),
|
||||
Error: func() string {
|
||||
|
||||
@@ -296,7 +296,11 @@ func (fi FileInfo) GetDataDir() string {
|
||||
// InlineData returns true if object contents are inlined alongside its metadata.
|
||||
func (fi FileInfo) InlineData() bool {
|
||||
_, ok := fi.Metadata[ReservedMetadataPrefixLower+"inline-data"]
|
||||
return ok
|
||||
// Earlier MinIO versions didn't reset "x-minio-internal-inline-data"
|
||||
// from fi.Metadata when the object was tiered. So, tiered objects
|
||||
// would return true for InlineData() in these versions even though the
|
||||
// object isn't inlined in xl.meta
|
||||
return ok && !fi.IsRemote()
|
||||
}
|
||||
|
||||
// SetInlineData marks object (version) as inline.
|
||||
|
||||
@@ -856,10 +856,7 @@ func (client *storageRESTClient) CleanAbandonedData(ctx context.Context, volume
|
||||
return err
|
||||
}
|
||||
defer xhttp.DrainBody(respBody)
|
||||
respReader, err := waitForHTTPResponse(respBody)
|
||||
if err == nil {
|
||||
io.Copy(io.Discard, respReader)
|
||||
}
|
||||
_, err = waitForHTTPResponse(respBody)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -611,6 +611,8 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(xhttp.ContentLength, strconv.Itoa(length))
|
||||
|
||||
rc, err := s.storage.ReadFileStream(r.Context(), volume, filePath, int64(offset), int64(length))
|
||||
if err != nil {
|
||||
s.writeErrorResponse(w, err)
|
||||
@@ -618,12 +620,28 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
w.Header().Set(xhttp.ContentLength, strconv.Itoa(length))
|
||||
if _, err = xioutil.Copy(w, rc); err != nil {
|
||||
if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
|
||||
logger.LogIf(r.Context(), err)
|
||||
rf, ok := w.(io.ReaderFrom)
|
||||
if ok {
|
||||
// Attempt to use splice/sendfile() optimization, A very specific behavior mentioned below is necessary.
|
||||
// See https://github.com/golang/go/blob/f7c5cbb82087c55aa82081e931e0142783700ce8/src/net/sendfile_linux.go#L20
|
||||
dr, ok := rc.(*xioutil.DeadlineReader)
|
||||
if ok {
|
||||
sr, ok := dr.ReadCloser.(*sendFileReader)
|
||||
if ok {
|
||||
_, err = rf.ReadFrom(sr.Reader)
|
||||
if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
|
||||
logger.LogIf(r.Context(), err)
|
||||
}
|
||||
if err == nil || !errors.Is(err, xhttp.ErrNotImplemented) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
} // Fallback to regular copy
|
||||
|
||||
_, err = xioutil.Copy(w, rc)
|
||||
if !xnet.IsNetworkOrHostDown(err, true) { // do not need to log disconnected clients
|
||||
logger.LogIf(r.Context(), err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,9 +101,8 @@ func (l DailyAllTierStats) merge(m DailyAllTierStats) {
|
||||
|
||||
func (l DailyAllTierStats) addToTierInfo(tierInfos []madmin.TierInfo) []madmin.TierInfo {
|
||||
for i := range tierInfos {
|
||||
var lst lastDayTierStats
|
||||
var ok bool
|
||||
if lst, ok = l[tierInfos[i].Name]; !ok {
|
||||
lst, ok := l[tierInfos[i].Name]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for hr, st := range lst.Bins {
|
||||
|
||||
+16
-2
@@ -67,8 +67,6 @@ const (
|
||||
tierConfigFormat = 1
|
||||
tierConfigV1 = 1
|
||||
tierConfigVersion = 2
|
||||
|
||||
minioHotTier = "STANDARD"
|
||||
)
|
||||
|
||||
// tierConfigPath refers to remote tier config object name
|
||||
@@ -177,8 +175,24 @@ func (config *TierConfigMgr) Empty() bool {
|
||||
return len(config.ListTiers()) == 0
|
||||
}
|
||||
|
||||
// TierType returns the type of tier
|
||||
func (config *TierConfigMgr) TierType(name string) string {
|
||||
config.RLock()
|
||||
defer config.RUnlock()
|
||||
|
||||
cfg, ok := config.Tiers[name]
|
||||
if !ok {
|
||||
return "internal"
|
||||
}
|
||||
return cfg.Type.String()
|
||||
}
|
||||
|
||||
// ListTiers lists remote tiers configured in this deployment.
|
||||
func (config *TierConfigMgr) ListTiers() []madmin.TierConfig {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
config.RLock()
|
||||
defer config.RUnlock()
|
||||
|
||||
|
||||
@@ -99,12 +99,16 @@ func ErrorRespToObjectError(err error, params ...string) error {
|
||||
|
||||
bucket := ""
|
||||
object := ""
|
||||
versionID := ""
|
||||
if len(params) >= 1 {
|
||||
bucket = params[0]
|
||||
}
|
||||
if len(params) == 2 {
|
||||
object = params[1]
|
||||
}
|
||||
if len(params) == 3 {
|
||||
versionID = params[2]
|
||||
}
|
||||
|
||||
if xnet.IsNetworkOrHostDown(err, false) {
|
||||
return BackendDown{Err: err.Error()}
|
||||
@@ -142,6 +146,12 @@ func ErrorRespToObjectError(err error, params ...string) error {
|
||||
} else {
|
||||
err = BucketNotFound{Bucket: bucket}
|
||||
}
|
||||
case "NoSuchVersion":
|
||||
if object != "" {
|
||||
err = ObjectNotFound{Bucket: bucket, Object: object, VersionID: versionID}
|
||||
} else {
|
||||
err = BucketNotFound{Bucket: bucket}
|
||||
}
|
||||
case "XMinioInvalidObjectName":
|
||||
err = ObjectNameInvalid{}
|
||||
case "AccessDenied":
|
||||
|
||||
@@ -421,7 +421,13 @@ func (p *xlStorageDiskIDCheck) ReadFile(ctx context.Context, volume string, path
|
||||
}
|
||||
defer done(&err)
|
||||
|
||||
return p.storage.ReadFile(ctx, volume, path, offset, buf, verifier)
|
||||
w := xioutil.NewDeadlineWorker(diskMaxTimeout)
|
||||
err = w.Run(func() error {
|
||||
n, err = p.storage.ReadFile(ctx, volume, path, offset, buf, verifier)
|
||||
return err
|
||||
})
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Legacy API - does not have any deadlines
|
||||
@@ -432,7 +438,10 @@ func (p *xlStorageDiskIDCheck) AppendFile(ctx context.Context, volume string, pa
|
||||
}
|
||||
defer done(&err)
|
||||
|
||||
return p.storage.AppendFile(ctx, volume, path, buf)
|
||||
w := xioutil.NewDeadlineWorker(diskMaxTimeout)
|
||||
return w.Run(func() error {
|
||||
return p.storage.AppendFile(ctx, volume, path, buf)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *xlStorageDiskIDCheck) CreateFile(ctx context.Context, volume, path string, size int64, reader io.Reader) (err error) {
|
||||
@@ -442,7 +451,7 @@ func (p *xlStorageDiskIDCheck) CreateFile(ctx context.Context, volume, path stri
|
||||
}
|
||||
defer done(&err)
|
||||
|
||||
return p.storage.CreateFile(ctx, volume, path, size, reader)
|
||||
return p.storage.CreateFile(ctx, volume, path, size, xioutil.NewDeadlineReader(io.NopCloser(reader), diskMaxTimeout))
|
||||
}
|
||||
|
||||
func (p *xlStorageDiskIDCheck) ReadFileStream(ctx context.Context, volume, path string, offset, length int64) (io.ReadCloser, error) {
|
||||
@@ -452,9 +461,16 @@ func (p *xlStorageDiskIDCheck) ReadFileStream(ctx context.Context, volume, path
|
||||
}
|
||||
defer done(&err)
|
||||
|
||||
rc, err := p.storage.ReadFileStream(ctx, volume, path, offset, length)
|
||||
w := xioutil.NewDeadlineWorker(diskMaxTimeout)
|
||||
|
||||
var rc io.ReadCloser
|
||||
err = w.Run(func() error {
|
||||
var ierr error
|
||||
rc, ierr = p.storage.ReadFileStream(ctx, volume, path, offset, length)
|
||||
return ierr
|
||||
})
|
||||
if err != nil {
|
||||
return rc, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return xioutil.NewDeadlineReader(rc, diskMaxTimeout), nil
|
||||
|
||||
@@ -536,6 +536,10 @@ func (j xlMetaV2Object) InlineData() bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func (j *xlMetaV2Object) ResetInlineData() {
|
||||
delete(j.MetaSys, ReservedMetadataPrefixLower+"inline-data")
|
||||
}
|
||||
|
||||
const (
|
||||
metaTierStatus = ReservedMetadataPrefixLower + TransitionStatus
|
||||
metaTierObjName = ReservedMetadataPrefixLower + TransitionedObjectName
|
||||
@@ -1440,6 +1444,7 @@ func (x *xlMetaV2) DeleteVersion(fi FileInfo) (string, error) {
|
||||
err = x.setIdx(i, *ver)
|
||||
case fi.TransitionStatus == lifecycle.TransitionComplete:
|
||||
ver.ObjectV2.SetTransition(fi)
|
||||
ver.ObjectV2.ResetInlineData()
|
||||
err = x.setIdx(i, *ver)
|
||||
default:
|
||||
x.versions = append(x.versions[:i], x.versions[i+1:]...)
|
||||
|
||||
+36
-54
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/klauspost/filepathx"
|
||||
"github.com/minio/madmin-go/v3"
|
||||
"github.com/minio/minio/internal/bucket/lifecycle"
|
||||
"github.com/minio/minio/internal/config/storageclass"
|
||||
"github.com/minio/minio/internal/disk"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
@@ -544,9 +545,15 @@ func (s *xlStorage) NSScanner(ctx context.Context, cache dataUsageCache, updates
|
||||
}
|
||||
|
||||
sizeS := sizeSummary{}
|
||||
var noTiers bool
|
||||
if noTiers = globalTierConfigMgr.Empty(); !noTiers {
|
||||
sizeS.tiers = make(map[string]tierStats)
|
||||
for _, tier := range globalTierConfigMgr.ListTiers() {
|
||||
if sizeS.tiers == nil {
|
||||
sizeS.tiers = make(map[string]tierStats)
|
||||
}
|
||||
sizeS.tiers[tier.Name] = tierStats{}
|
||||
}
|
||||
if sizeS.tiers != nil {
|
||||
sizeS.tiers[storageclass.STANDARD] = tierStats{}
|
||||
sizeS.tiers[storageclass.RRS] = tierStats{}
|
||||
}
|
||||
|
||||
done := globalScannerMetrics.time(scannerMetricApplyAll)
|
||||
@@ -578,25 +585,27 @@ func (s *xlStorage) NSScanner(ctx context.Context, cache dataUsageCache, updates
|
||||
}
|
||||
sizeS.totalSize += sz
|
||||
|
||||
// Skip tier accounting if,
|
||||
// 1. no tiers configured
|
||||
// 2. object version is a delete-marker or a free-version
|
||||
// tracking deleted transitioned objects
|
||||
// Skip tier accounting if object version is a delete-marker or a free-version
|
||||
// tracking deleted transitioned objects
|
||||
switch {
|
||||
case noTiers, oi.DeleteMarker, oi.TransitionedObject.FreeVersion:
|
||||
case oi.DeleteMarker, oi.TransitionedObject.FreeVersion:
|
||||
continue
|
||||
}
|
||||
tier := minioHotTier
|
||||
tier := oi.StorageClass
|
||||
if tier == "" {
|
||||
tier = storageclass.STANDARD // no SC means "STANDARD"
|
||||
}
|
||||
if oi.TransitionedObject.Status == lifecycle.TransitionComplete {
|
||||
tier = oi.TransitionedObject.Tier
|
||||
}
|
||||
sizeS.tiers[tier] = sizeS.tiers[tier].add(oi.tierStats())
|
||||
if sizeS.tiers != nil {
|
||||
if st, ok := sizeS.tiers[tier]; ok {
|
||||
sizeS.tiers[tier] = st.add(oi.tierStats())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply tier sweep action on free versions
|
||||
if len(fivs.FreeVersions) > 0 {
|
||||
res["free-versions"] = strconv.Itoa(len(fivs.FreeVersions))
|
||||
}
|
||||
for _, freeVersion := range fivs.FreeVersions {
|
||||
oi := freeVersion.ToObjectInfo(item.bucket, item.objectPath(), versioned)
|
||||
done = globalScannerMetrics.time(scannerMetricTierObjSweep)
|
||||
@@ -606,15 +615,17 @@ func (s *xlStorage) NSScanner(ctx context.Context, cache dataUsageCache, updates
|
||||
|
||||
// These are rather expensive. Skip if nobody listens.
|
||||
if globalTrace.NumSubscribers(madmin.TraceScanner) > 0 {
|
||||
if len(fivs.FreeVersions) > 0 {
|
||||
res["free-versions"] = strconv.Itoa(len(fivs.FreeVersions))
|
||||
}
|
||||
|
||||
if sizeS.versions > 0 {
|
||||
res["versions"] = strconv.FormatUint(sizeS.versions, 10)
|
||||
}
|
||||
res["size"] = strconv.FormatInt(sizeS.totalSize, 10)
|
||||
if len(sizeS.tiers) > 0 {
|
||||
for name, tier := range sizeS.tiers {
|
||||
res["size-"+name] = strconv.FormatUint(tier.TotalSize, 10)
|
||||
res["versions-"+name] = strconv.Itoa(tier.NumVersions)
|
||||
}
|
||||
for name, tier := range sizeS.tiers {
|
||||
res["tier-size-"+name] = strconv.FormatUint(tier.TotalSize, 10)
|
||||
res["tier-versions-"+name] = strconv.Itoa(tier.NumVersions)
|
||||
}
|
||||
if sizeS.failedCount > 0 {
|
||||
res["repl-failed"] = fmt.Sprintf("%d versions, %d bytes", sizeS.failedCount, sizeS.failedSize)
|
||||
@@ -1768,6 +1779,11 @@ func (s *xlStorage) openFile(filePath string, mode int) (f *os.File, err error)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
type sendFileReader struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// ReadFileStream - Returns the read stream of the file.
|
||||
func (s *xlStorage) ReadFileStream(ctx context.Context, volume, path string, offset, length int64) (io.ReadCloser, error) {
|
||||
if offset < 0 {
|
||||
@@ -1785,14 +1801,7 @@ func (s *xlStorage) ReadFileStream(ctx context.Context, volume, path string, off
|
||||
return nil, err
|
||||
}
|
||||
|
||||
odirectEnabled := globalAPIConfig.odirectEnabled() && s.oDirect && length >= 0
|
||||
|
||||
var file *os.File
|
||||
if odirectEnabled {
|
||||
file, err = OpenFileDirectIO(filePath, readMode, 0o666)
|
||||
} else {
|
||||
file, err = OpenFile(filePath, readMode, 0o666)
|
||||
}
|
||||
file, err := OpenFile(filePath, readMode, 0o666)
|
||||
if err != nil {
|
||||
switch {
|
||||
case osIsNotExist(err):
|
||||
@@ -1841,14 +1850,6 @@ func (s *xlStorage) ReadFileStream(ctx context.Context, volume, path string, off
|
||||
return nil, errFileCorrupt
|
||||
}
|
||||
|
||||
alignment := offset%xioutil.DirectioAlignSize == 0
|
||||
if !alignment && odirectEnabled {
|
||||
if err = disk.DisableDirectIO(file); err != nil {
|
||||
file.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if offset > 0 {
|
||||
if _, err = file.Seek(offset, io.SeekStart); err != nil {
|
||||
file.Close()
|
||||
@@ -1856,26 +1857,7 @@ func (s *xlStorage) ReadFileStream(ctx context.Context, volume, path string, off
|
||||
}
|
||||
}
|
||||
|
||||
or := &xioutil.ODirectReader{
|
||||
File: file,
|
||||
// Select bigger blocks when reading at least 50% of a big block.
|
||||
SmallFile: length <= xioutil.BlockSizeLarge/2,
|
||||
}
|
||||
|
||||
r := struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{Reader: io.LimitReader(diskHealthReader(ctx, or), length), Closer: closeWrapper(func() error {
|
||||
if (!alignment || offset+length%xioutil.DirectioAlignSize != 0) && odirectEnabled {
|
||||
// invalidate page-cache for unaligned reads.
|
||||
// skip removing from page-cache only
|
||||
// if O_DIRECT was disabled.
|
||||
disk.FadviseDontNeed(file)
|
||||
}
|
||||
return or.Close()
|
||||
})}
|
||||
|
||||
return r, nil
|
||||
return &sendFileReader{Reader: io.LimitReader(file, length), Closer: file}, nil
|
||||
}
|
||||
|
||||
// closeWrapper converts a function to an io.Closer
|
||||
|
||||
@@ -15,6 +15,15 @@ docker buildx build --push --no-cache \
|
||||
|
||||
docker buildx prune -f
|
||||
|
||||
docker buildx build --push --no-cache \
|
||||
--build-arg RELEASE="${release}" \
|
||||
-t "minio/minio:${release}-cpuv1" \
|
||||
-t "quay.io/minio/minio:${release}-cpuv1" \
|
||||
--platform=linux/arm64,linux/amd64,linux/ppc64le,linux/s390x \
|
||||
-f Dockerfile.release.old_cpu .
|
||||
|
||||
docker buildx prune -f
|
||||
|
||||
docker buildx build --push --no-cache \
|
||||
--build-arg RELEASE="${release}" \
|
||||
-t "minio/minio:${release}.fips" \
|
||||
|
||||
@@ -8,22 +8,19 @@ if [ "${1}" != "minio" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# su-exec to requested user, if service cannot run exec will fail.
|
||||
docker_switch_user() {
|
||||
if [ -n "${MINIO_USERNAME}" ] && [ -n "${MINIO_GROUPNAME}" ]; then
|
||||
if [ -n "${MINIO_UID}" ] && [ -n "${MINIO_GID}" ]; then
|
||||
groupadd -f -g "$MINIO_GID" "$MINIO_GROUPNAME" &&
|
||||
useradd -u "$MINIO_UID" -g "$MINIO_GROUPNAME" "$MINIO_USERNAME"
|
||||
chroot --userspec=${MINIO_UID}:${MINIO_GID} / "$@"
|
||||
else
|
||||
groupadd -f "$MINIO_GROUPNAME" &&
|
||||
useradd -g "$MINIO_GROUPNAME" "$MINIO_USERNAME"
|
||||
echo "${MINIO_USERNAME}:x:1000:1000:${MINIO_USERNAME}:/:/sbin/nologin" >>/etc/passwd
|
||||
echo "${MINIO_GROUPNAME}:x:1000" >>/etc/group
|
||||
chroot --userspec=${MINIO_USERNAME}:${MINIO_GROUPNAME} / "$@"
|
||||
fi
|
||||
exec setpriv --reuid="${MINIO_USERNAME}" \
|
||||
--regid="${MINIO_GROUPNAME}" --keep-groups "$@"
|
||||
else
|
||||
exec "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
## Switch to user if applicable.
|
||||
## DEPRECATED and unsupported - switch to user if applicable.
|
||||
docker_switch_user "$@"
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -x "/opt/bin/minio" ]; then
|
||||
echo "minio executable binary not found refusing to proceed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
verify_sha256sum() {
|
||||
echo "verifying binary checksum"
|
||||
echo "$(awk '{print $1}' /opt/bin/minio.sha256sum) /opt/bin/minio" | sha256sum -c
|
||||
}
|
||||
|
||||
verify_signature() {
|
||||
if [ "${TARGETARCH}" = "arm" ]; then
|
||||
echo "ignoring verification of binary signature"
|
||||
return
|
||||
fi
|
||||
echo "verifying binary signature"
|
||||
minisign -VQm /opt/bin/minio -P RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav
|
||||
}
|
||||
|
||||
main() {
|
||||
verify_sha256sum
|
||||
|
||||
verify_signature
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -151,3 +151,7 @@ curl https://play.min.io/minio/v2/metrics/cluster
|
||||
### List of metrics reported Cluster and Bucket level
|
||||
|
||||
[The list of metrics reported can be here](https://github.com/minio/minio/blob/master/docs/metrics/prometheus/list.md)
|
||||
|
||||
### Configure Alerts for Prometheus
|
||||
|
||||
[The Prometheus AlertManager and alerts can be configured following this](https://github.com/minio/minio/blob/master/docs/metrics/prometheus/alerts.md)
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# How to configure Prometheus AlertManager
|
||||
|
||||
Alerting with prometheus is two step process. First we setup alerts in Prometheus server and then we need to send alerts to the AlertManager.
|
||||
Prometheus AlertManager is the component that manages sending, inhibition and silencing of the alerts generated from Prometheus. The AlertManager can be configured to send alerts to variety of receivers. Refer [Prometheus AlertManager receivers](https://prometheus.io/docs/alerting/latest/configuration/#receiver) for more details.
|
||||
|
||||
Follow below steps to enable and use AlertManager.
|
||||
|
||||
## Deploy and start AlertManager
|
||||
Install Prometheus AlertManager from https://prometheus.io/download/ and create configuration as below
|
||||
|
||||
```yaml
|
||||
route:
|
||||
group_by: ['alertname']
|
||||
group_wait: 30s
|
||||
group_interval: 5m
|
||||
repeat_interval: 1h
|
||||
receiver: 'web.hook'
|
||||
receivers:
|
||||
- name: 'web.hook'
|
||||
webhook_configs:
|
||||
- url: 'http://127.0.0.1:8010/webhook'
|
||||
inhibit_rules:
|
||||
- source_match:
|
||||
severity: 'critical'
|
||||
target_match:
|
||||
severity: 'warning'
|
||||
equal: ['alertname', 'dev', 'instance']
|
||||
```
|
||||
|
||||
This sample confoguration uses a `webhook` at http://127.0.0.1:8010/webhook to post the alerts.
|
||||
Start the AlertManager and it listens on port `9093` by default. Make sure your webhook is up and listening for the alerts.
|
||||
|
||||
## Configure Prometheus to use AlertManager
|
||||
|
||||
Add below section to your `prometheus.yml`
|
||||
```yaml
|
||||
alerting:
|
||||
alertmanagers:
|
||||
- static_configs:
|
||||
- targets: ['localhost:9093']
|
||||
rule_files:
|
||||
- rules.yml
|
||||
```
|
||||
Here `rules.yml` is the file which should contain the alerting rules defined.
|
||||
|
||||
## Add rules for your deployment
|
||||
Below is a sample alerting rules configuration for MinIO. Refer https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/ for more instructions on writing alerting rules for Prometheus.
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
- name: example
|
||||
rules:
|
||||
- alert: MinIOClusterTolerance
|
||||
expr: minio_cluster_health_erasure_set_tolerance <= 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Instance {{ $labels.server }} unable to tolerate node failures"
|
||||
description: "MinIO instance {{ $labels.server }} of job {{ $labels.job }} has tolerance <=0 for more than 5 minutes."
|
||||
```
|
||||
|
||||
## Verify the configuration and alerts
|
||||
To verify the above sample alert follow below steps
|
||||
|
||||
1. Start a distributed MinIO instance (4 nodes setup)
|
||||
2. Start Prometheus server and AlertManager
|
||||
3. Bring down couple of MinIO instances to bring down the Erasure Set tolerance to -1 and verify the same with `mc admin prometheus metrics ALIAS | grep minio_cluster_health_erasure_set_tolerance`
|
||||
4. Wait for 5 mins (as alert is configured to be firing after 5 mins), and verify that you see an entry in webhook for the alert as well as in Prometheus console as shown below
|
||||
|
||||
```json
|
||||
{
|
||||
"receiver": "web\\.hook",
|
||||
"status": "firing",
|
||||
"alerts": [
|
||||
{
|
||||
"status": "firing",
|
||||
"labels": {
|
||||
"alertname": "MinIOClusterTolerance",
|
||||
"instance": "localhost:9000",
|
||||
"job": "minio-job-node",
|
||||
"pool": "0",
|
||||
"server": "127.0.0.1:9000",
|
||||
"set": "0",
|
||||
"severity": "critical"
|
||||
},
|
||||
"annotations": {
|
||||
"description": "MinIO instance 127.0.0.1:9000 of job minio-job has tolerance <=0 for more than 5 minutes.",
|
||||
"summary": "Instance 127.0.0.1:9000 unable to tolerate node failures"
|
||||
},
|
||||
"startsAt": "2023-11-18T06:20:09.456Z",
|
||||
"endsAt": "0001-01-01T00:00:00Z",
|
||||
"generatorURL": "http://fedora-shubhendu:9090/graph?g0.expr=minio_cluster_health_erasure_set_tolerance+%3C%3D+0&g0.tab=1",
|
||||
"fingerprint": "2255608b0da28ca3"
|
||||
}
|
||||
],
|
||||
"groupLabels": {
|
||||
"alertname": "MinIOClusterTolerance"
|
||||
},
|
||||
"commonLabels": {
|
||||
"alertname": "MinIOClusterTolerance",
|
||||
"instance": "localhost:9000",
|
||||
"job": "minio-job-node",
|
||||
"pool": "0",
|
||||
"server": "127.0.0.1:9000",
|
||||
"set": "0",
|
||||
"severity": "critical"
|
||||
},
|
||||
"commonAnnotations": {
|
||||
"description": "MinIO instance 127.0.0.1:9000 of job minio-job has tolerance <=0 for more than 5 minutes.",
|
||||
"summary": "Instance 127.0.0.1:9000 unable to tolerate node failures"
|
||||
},
|
||||
"externalURL": "http://fedora-shubhendu:9093",
|
||||
"version": "4",
|
||||
"groupKey": "{}:{alertname=\"MinIOClusterTolerance\"}",
|
||||
"truncatedAlerts": 0
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
@@ -4173,6 +4173,537 @@
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"description": "",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [
|
||||
{
|
||||
"options": {
|
||||
"match": "null",
|
||||
"result": {
|
||||
"text": "N/A"
|
||||
}
|
||||
},
|
||||
"type": "special"
|
||||
}
|
||||
],
|
||||
"thresholds": {
|
||||
"mode": "percentage",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "dtdurations"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 109
|
||||
},
|
||||
"id": 89,
|
||||
"links": [],
|
||||
"maxDataPoints": 100,
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "none",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"mean"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"text": {},
|
||||
"textMode": "auto"
|
||||
},
|
||||
"pluginVersion": "10.0.2",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "minio_cluster_kms_uptime{job=\"$scrape_jobs\"}",
|
||||
"format": "time_series",
|
||||
"instant": true,
|
||||
"interval": "",
|
||||
"intervalFactor": 1,
|
||||
"legendFormat": "{{instance}}",
|
||||
"metric": "minio_cluster_kms_uptime",
|
||||
"refId": "A",
|
||||
"step": 60
|
||||
}
|
||||
],
|
||||
"title": "KMS Uptime",
|
||||
"type": "stat"
|
||||
},
|
||||
{
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 109
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 90,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "10.0.2",
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "Prometheus"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum by (server) (minio_cluster_kms_online{job=\"$scrape_jobs\"})",
|
||||
"interval": "1m",
|
||||
"legendFormat": "{{server}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeRegions": [],
|
||||
"title": "KMS Online(1)/Offline(0)",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"mode": "time",
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"$$hashKey": "object:212",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"min": "0",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"$$hashKey": "object:213",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"min": "0",
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"aliasColors": {
|
||||
"S3 Errors": "light-red",
|
||||
"S3 Requests": "light-green"
|
||||
},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 4,
|
||||
"x": 8,
|
||||
"y": 109
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 91,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "10.0.2",
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum by (server) (increase(minio_cluster_kms_request_error{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"interval": "1m",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{server}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeRegions": [],
|
||||
"title": "KMS Request 4xx Error Rate",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"mode": "time",
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"$$hashKey": "object:331",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"$$hashKey": "object:332",
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": false
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"aliasColors": {
|
||||
"S3 Errors": "light-red",
|
||||
"S3 Requests": "light-green"
|
||||
},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 109
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 92,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "10.0.2",
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum by (server) (increase(minio_cluster_kms_request_failure{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"interval": "1m",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "{{server}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeRegions": [],
|
||||
"title": "KMS Request 5xx Error Rate",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"mode": "time",
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"$$hashKey": "object:331",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"$$hashKey": "object:332",
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": false
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"aliasColors": {
|
||||
"S3 Errors": "light-red",
|
||||
"S3 Requests": "light-green"
|
||||
},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 109
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 93,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "10.0.2",
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "sum by (server) (rate(minio_cluster_kms_request_success{job=\"$scrape_jobs\"}[$__rate_interval]))",
|
||||
"interval": "1m",
|
||||
"intervalFactor": 2,
|
||||
"legendFormat": "KMS Request Success [{{server}}]",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeRegions": [],
|
||||
"title": "KMS Request Success Rate ",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"mode": "time",
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"$$hashKey": "object:331",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"$$hashKey": "object:332",
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": false
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 115
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 94,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"alertThreshold": true
|
||||
},
|
||||
"percentage": false,
|
||||
"pluginVersion": "10.0.2",
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "${DS_PROMETHEUS}"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "minio_cluster_health_erasure_set_tolerance{job=\"$scrape_jobs\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "Pool: {{pool}} Set: {{set}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeRegions": [],
|
||||
"title": "Erasure Set Tolerance",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"mode": "time",
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"$$hashKey": "object:1043",
|
||||
"format": "none",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"$$hashKey": "object:1044",
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"refresh": "",
|
||||
|
||||
@@ -40,7 +40,7 @@ For deployments behind a load balancer, use the load balancer hostname instead o
|
||||
| `minio_cluster_capacity_usable_free_bytes` | Total free usable capacity online in the cluster. |
|
||||
| `minio_cluster_capacity_usable_total_bytes` | Total usable capacity online in the cluster. |
|
||||
| `minio_cluster_objects_size_distribution` | Distribution of object sizes across a cluster |
|
||||
| `minio_cluster_objects_version_distribution` | Distribution of object sizes across a cluster |
|
||||
| `minio_cluster_objects_version_distribution` | Distribution of object versions across a cluster |
|
||||
| `minio_cluster_usage_object_total` | Total number of objects in a cluster |
|
||||
| `minio_cluster_usage_total_bytes` | Total cluster usage in bytes |
|
||||
| `minio_cluster_usage_version_total` | Total number of versions (includes delete marker) in a cluster |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
@@ -2,7 +2,7 @@ version: '3.7'
|
||||
|
||||
# Settings and configurations that are common for all containers
|
||||
x-minio-common: &minio-common
|
||||
image: quay.io/minio/minio:RELEASE.2023-10-24T04-42-36Z
|
||||
image: quay.io/minio/minio:RELEASE.2023-11-15T20-43-25Z
|
||||
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
||||
expose:
|
||||
- "9000"
|
||||
@@ -11,10 +11,10 @@ x-minio-common: &minio-common
|
||||
# MINIO_ROOT_USER: minioadmin
|
||||
# MINIO_ROOT_PASSWORD: minioadmin
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
test: ["CMD", "mc", "ready", "local"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# starts 4 docker containers running minio server instances.
|
||||
# using nginx reverse proxy, load balancing, you can access
|
||||
|
||||
@@ -5,7 +5,7 @@ go 1.20
|
||||
require (
|
||||
cloud.google.com/go/storage v1.33.0
|
||||
github.com/Azure/azure-storage-blob-go v0.15.0
|
||||
github.com/IBM/sarama v1.41.2
|
||||
github.com/IBM/sarama v1.41.3
|
||||
github.com/alecthomas/participle v0.7.1
|
||||
github.com/bcicen/jstream v1.0.1
|
||||
github.com/beevik/ntp v1.3.0
|
||||
@@ -15,7 +15,7 @@ require (
|
||||
github.com/coredns/coredns v1.11.1
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/cosnicolaou/pbzip2 v1.0.2
|
||||
github.com/cosnicolaou/pbzip2 v1.0.3
|
||||
github.com/dchest/siphash v1.2.3
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/eclipse/paho.mqtt.golang v1.4.3
|
||||
@@ -32,7 +32,7 @@ require (
|
||||
github.com/hashicorp/golang-lru v1.0.2
|
||||
github.com/inconshreveable/mousetrap v1.1.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/klauspost/compress v1.17.0
|
||||
github.com/klauspost/compress v1.17.1
|
||||
github.com/klauspost/cpuid/v2 v2.2.5
|
||||
github.com/klauspost/filepathx v1.1.1
|
||||
github.com/klauspost/pgzip v1.2.6
|
||||
@@ -42,16 +42,16 @@ require (
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0
|
||||
github.com/miekg/dns v1.1.56
|
||||
github.com/minio/cli v1.24.2
|
||||
github.com/minio/console v0.40.0
|
||||
github.com/minio/console v0.41.0
|
||||
github.com/minio/csvparser v1.0.0
|
||||
github.com/minio/dnscache v0.1.1
|
||||
github.com/minio/dperf v0.5.0
|
||||
github.com/minio/dperf v0.5.2
|
||||
github.com/minio/highwayhash v1.0.2
|
||||
github.com/minio/kes-go v0.2.0
|
||||
github.com/minio/madmin-go/v3 v3.0.21
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20230920204636-e783c9ba11b3
|
||||
github.com/minio/madmin-go/v3 v3.0.29
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20231119012610-6eebdd6d5eba
|
||||
github.com/minio/mux v1.9.0
|
||||
github.com/minio/pkg/v2 v2.0.2
|
||||
github.com/minio/pkg/v2 v2.0.3-0.20231107172951-8a60b89ec9b4
|
||||
github.com/minio/selfupdate v0.6.0
|
||||
github.com/minio/sha256-simd v1.0.1
|
||||
github.com/minio/simdjson-go v0.4.5
|
||||
@@ -60,7 +60,7 @@ require (
|
||||
github.com/minio/zipindex v0.3.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/nats-io/nats-server/v2 v2.9.23
|
||||
github.com/nats-io/nats.go v1.30.0
|
||||
github.com/nats-io/nats.go v1.31.0
|
||||
github.com/nats-io/stan.go v0.10.4
|
||||
github.com/ncw/directio v1.0.5
|
||||
github.com/nsqio/go-nsq v1.1.0
|
||||
@@ -68,16 +68,16 @@ require (
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.6
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
github.com/prometheus/common v0.44.0
|
||||
github.com/prometheus/procfs v0.11.1
|
||||
github.com/rabbitmq/amqp091-go v1.8.1
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/common v0.45.0
|
||||
github.com/prometheus/procfs v0.12.0
|
||||
github.com/rabbitmq/amqp091-go v1.9.0
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
|
||||
github.com/rs/cors v1.10.0
|
||||
github.com/rs/cors v1.10.1
|
||||
github.com/secure-io/sio-go v0.3.1
|
||||
github.com/shirou/gopsutil/v3 v3.23.8
|
||||
github.com/tidwall/gjson v1.16.0
|
||||
github.com/shirou/gopsutil/v3 v3.23.9
|
||||
github.com/tidwall/gjson v1.17.0
|
||||
github.com/tinylib/msgp v1.1.8
|
||||
github.com/valyala/bytebufferpool v1.0.0
|
||||
github.com/xdg/scram v1.0.5
|
||||
@@ -88,23 +88,25 @@ require (
|
||||
go.uber.org/zap v1.26.0
|
||||
goftp.io/server/v2 v2.0.1
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
|
||||
golang.org/x/oauth2 v0.12.0
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
|
||||
golang.org/x/oauth2 v0.13.0
|
||||
golang.org/x/sys v0.13.0
|
||||
golang.org/x/time v0.3.0
|
||||
google.golang.org/api v0.142.0
|
||||
google.golang.org/api v0.148.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
aead.dev/mem v0.2.0 // indirect
|
||||
aead.dev/minisign v0.2.0 // indirect
|
||||
cloud.google.com/go v0.110.8 // indirect
|
||||
cloud.google.com/go/compute v1.23.0 // indirect
|
||||
cloud.google.com/go v0.110.9 // indirect
|
||||
cloud.google.com/go/compute v1.23.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v1.1.2 // indirect
|
||||
cloud.google.com/go/iam v1.1.3 // indirect
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
github.com/apache/thrift v0.19.0 // indirect
|
||||
github.com/armon/go-metrics v0.4.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
@@ -112,7 +114,7 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/charmbracelet/bubbles v0.16.1 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.24.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.8.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.9.1 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
@@ -122,7 +124,7 @@ require (
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
|
||||
github.com/eapache/queue v1.1.0 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/frankban/quicktest v1.14.3 // indirect
|
||||
github.com/frankban/quicktest v1.14.4 // indirect
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/gdamore/tcell/v2 v2.6.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
@@ -141,8 +143,7 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
|
||||
@@ -158,7 +159,7 @@ require (
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.7 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.8 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/juju/ratelimit v1.0.2 // indirect
|
||||
@@ -170,17 +171,18 @@ require (
|
||||
github.com/lestrrat-go/jwx v1.2.26 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-ieproxy v0.0.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/minio/colorjson v1.0.6 // indirect
|
||||
github.com/minio/filepath v1.0.0 // indirect
|
||||
github.com/minio/mc v0.0.0-20230922050746-ae05d451739b // indirect
|
||||
github.com/minio/mc v0.0.0-20231030184332-9f2fb2b6a9f8 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/pkg v1.7.5 // indirect
|
||||
github.com/minio/websocket v1.6.0 // indirect
|
||||
@@ -194,7 +196,7 @@ require (
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.5.0 // indirect
|
||||
github.com/nats-io/nats-streaming-server v0.24.3 // indirect
|
||||
github.com/nats-io/nkeys v0.4.5 // indirect
|
||||
github.com/nats-io/nkeys v0.4.6 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/navidys/tvxwidgets v0.4.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
@@ -205,10 +207,11 @@ require (
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||
github.com/prometheus/prom2json v1.3.3 // indirect
|
||||
github.com/rivo/tview v0.0.0-20230916092115-0ad06c2ea3dd // indirect
|
||||
github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rjeczalik/notify v0.9.3 // indirect
|
||||
github.com/rs/xid v1.5.0 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
@@ -216,24 +219,25 @@ require (
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/unrolled/secure v1.13.0 // indirect
|
||||
github.com/vbauerster/mpb/v8 v8.6.2 // indirect
|
||||
github.com/xdg/stringprep v1.0.3 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
go.mongodb.org/mongo-driver v1.12.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/mod v0.13.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sync v0.4.0 // indirect
|
||||
golang.org/x/term v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
golang.org/x/tools v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
|
||||
google.golang.org/grpc v1.58.2 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/h2non/filetype.v1 v1.0.5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
||||
@@ -3,14 +3,14 @@ aead.dev/mem v0.2.0/go.mod h1:4qj+sh8fjDhlvne9gm/ZaMRIX9EkmDrKOLwmyDtoMWM=
|
||||
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
|
||||
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
|
||||
cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
|
||||
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
|
||||
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68=
|
||||
cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM=
|
||||
cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0=
|
||||
cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4=
|
||||
cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
|
||||
cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc=
|
||||
cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE=
|
||||
cloud.google.com/go/storage v1.33.0 h1:PVrDOkIC8qQVa1P3SXGpQvfuJhN2LHOoyZvWs8D2X5M=
|
||||
cloud.google.com/go/storage v1.33.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8=
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
|
||||
@@ -34,10 +34,14 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzS
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/IBM/sarama v1.41.2 h1:ZDBZfGPHAD4uuAtSv4U22fRZBgst0eEwGFzLj0fb85c=
|
||||
github.com/IBM/sarama v1.41.2/go.mod h1:xdpu7sd6OE1uxNdjYTSKUfY8FaKkJES9/+EyjSgiGQk=
|
||||
github.com/IBM/sarama v1.41.3 h1:MWBEJ12vHC8coMjdEXFq/6ftO6DUZnQlFYcxtOJFa7c=
|
||||
github.com/IBM/sarama v1.41.3/go.mod h1:Xxho9HkHd4K/MDUo/T/sOqwtX/17D33++E9Wib6hUdQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/alecthomas/participle v0.7.1 h1:2bN7reTw//5f0cugJcTOnY/NYZcWQOaajW+BwZB5xWs=
|
||||
github.com/alecthomas/participle v0.7.1/go.mod h1:HfdmEuwvr12HXQN44HPWXR0lHmVolVYe4dyL6lQ3duY=
|
||||
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
||||
@@ -78,8 +82,8 @@ github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5
|
||||
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
|
||||
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
|
||||
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
|
||||
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
|
||||
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
|
||||
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
|
||||
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
|
||||
github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo=
|
||||
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@@ -102,8 +106,8 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cosnicolaou/pbzip2 v1.0.2 h1:QrEc0zSpIzHtFK/SgPuaeQ3mB2qUvmXXN93K0pjvcFc=
|
||||
github.com/cosnicolaou/pbzip2 v1.0.2/go.mod h1:uCNfm0iE2wIKGRlLyq31M4toziFprNhEnvueGmh5u3M=
|
||||
github.com/cosnicolaou/pbzip2 v1.0.3 h1:CebGEQSYOg9uFDfTgIXNDI3cuaQovlnBUcdB614dQws=
|
||||
github.com/cosnicolaou/pbzip2 v1.0.3/go.mod h1:uCNfm0iE2wIKGRlLyq31M4toziFprNhEnvueGmh5u3M=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -144,8 +148,8 @@ github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fraugster/parquet-go v0.12.0 h1:1slnC5y2VWEOUSlzbeXatM0BvSWcLUDsR/EcZsXXCZc=
|
||||
github.com/fraugster/parquet-go v0.12.0/go.mod h1:dGzUxdNqXsAijatByVgbAWVPlFirnhknQbdazcUIjY0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -275,14 +279,14 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8 h1:gpptm606MZYGaMHMsB4Srmb6EbW/IVHnt04rcMXnkBQ=
|
||||
github.com/google/pprof v0.0.0-20230912144702-c363fe2c2ed8/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
@@ -346,8 +350,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.8 h1:HiNzyMSEpsBaduKhmK+CwcpulEeBrTmxutz4oX/oWkg=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.8/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
|
||||
@@ -369,8 +373,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g=
|
||||
github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
@@ -389,8 +393,8 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -417,8 +421,8 @@ github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQ
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
|
||||
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
|
||||
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -437,8 +441,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
@@ -452,41 +456,43 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
|
||||
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
|
||||
github.com/minio/cli v1.24.2 h1:J+fCUh9mhPLjN3Lj/YhklXvxj8mnyE/D6FpFduXJ2jg=
|
||||
github.com/minio/cli v1.24.2/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
|
||||
github.com/minio/colorjson v1.0.6 h1:m7TUvpvt0u7FBmVIEQNIa0T4NBQlxrcMBp4wJKsg2Ik=
|
||||
github.com/minio/colorjson v1.0.6/go.mod h1:LUXwS5ZGNb6Eh9f+t+3uJiowD3XsIWtsvTriUBeqgYs=
|
||||
github.com/minio/console v0.40.0 h1:zldPHumWA5SN6uAUyAsctUFQ80LvLDv3n0VlONmBJMc=
|
||||
github.com/minio/console v0.40.0/go.mod h1:ra5pDF0mFQ9DI8K5iyk6Q5gV6KQuZq3MKPGYU66a+vc=
|
||||
github.com/minio/console v0.41.0 h1:NjvBij5Hg4GLkO/iAUfZ4imATA/rKNtgVhnn3sEuKDo=
|
||||
github.com/minio/console v0.41.0/go.mod h1:LTDngEa3Z/s9+2oUb3eBtaVsS/vQFuWTH9d8Z2Pe1mo=
|
||||
github.com/minio/csvparser v1.0.0 h1:xJEHcYK8ZAjeW4hNV9Zu30u+/2o4UyPnYgyjWp8b7ZU=
|
||||
github.com/minio/csvparser v1.0.0/go.mod h1:lKXskSLzPgC5WQyzP7maKH7Sl1cqvANXo9YCto8zbtM=
|
||||
github.com/minio/dnscache v0.1.1 h1:AMYLqomzskpORiUA1ciN9k7bZT1oB3YZN4cEIi88W5o=
|
||||
github.com/minio/dnscache v0.1.1/go.mod h1:WCumm6offO4rQ/82oTCSoHnlhTmc81+vXgKpBtSYRbg=
|
||||
github.com/minio/dperf v0.5.0 h1:pMK/dnP/+oG4hVUMSb5vtoSS24/fjnZdA1pjE2EBdz4=
|
||||
github.com/minio/dperf v0.5.0/go.mod h1:Y8HlbQ90LbtybYXEyMfsoVyOWndB1kGUo707uCwEuxo=
|
||||
github.com/minio/dperf v0.5.2 h1:ZTCyWE9jnngK55w6eU9u4VvQktJGYsUP6kaaUYORDyE=
|
||||
github.com/minio/dperf v0.5.2/go.mod h1:Y8HlbQ90LbtybYXEyMfsoVyOWndB1kGUo707uCwEuxo=
|
||||
github.com/minio/filepath v1.0.0 h1:fvkJu1+6X+ECRA6G3+JJETj4QeAYO9sV43I79H8ubDY=
|
||||
github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEXx9T/Bw=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/kes-go v0.2.0 h1:HA33arq9s3MErbsj3PAXFVfFo4U4yw7lTKQ5kWFrpCA=
|
||||
github.com/minio/kes-go v0.2.0/go.mod h1:VorHLaIYis9/MxAHAtXN4d8PUMNKhIxTIlvFt0hBOEo=
|
||||
github.com/minio/madmin-go/v3 v3.0.21 h1:54LroTtjkn60nvDMBHmCEMGcFQ3k3Yel74RaEu9n2cY=
|
||||
github.com/minio/madmin-go/v3 v3.0.21/go.mod h1:B2EgtEGrfWx+AkXv+OAcS6IHwoIJcd1p75QfDPSPd6Q=
|
||||
github.com/minio/mc v0.0.0-20230922050746-ae05d451739b h1:oZ5XAtyKMFbMbxqShGA51/YD/YaW+B2BiBQI7rN2uFc=
|
||||
github.com/minio/mc v0.0.0-20230922050746-ae05d451739b/go.mod h1:+4OzbgOsVsKvdmLLjN47DKKyHiLJuT05m5qF9fAQWe4=
|
||||
github.com/minio/madmin-go/v3 v3.0.29 h1:3bNLArtxIFud5wyb5/DnF5DGLBvcSJyzCA44EclX1Ow=
|
||||
github.com/minio/madmin-go/v3 v3.0.29/go.mod h1:4QN2NftLSV7MdlT50dkrenOMmNVHluxTvlqJou3hte8=
|
||||
github.com/minio/mc v0.0.0-20231030184332-9f2fb2b6a9f8 h1:3WUMQABG8FytpYHRtLHjrnztcUB09hlIrh7rQI9H+tY=
|
||||
github.com/minio/mc v0.0.0-20231030184332-9f2fb2b6a9f8/go.mod h1:SoPU55ntH5d6IEq6jRBn6e/7SpwI/eSNdBDWmH7nwHk=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20230920204636-e783c9ba11b3 h1:0DtfDxg67S/IRcGnIBKgzyjZ0GXyk3jN1Fy5/+8CQlM=
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20230920204636-e783c9ba11b3/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4=
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20231119012610-6eebdd6d5eba h1:OF4FT9fUnXReMpMLQyoydIYJYPN3W3omFuD/TTL8cZg=
|
||||
github.com/minio/minio-go/v7 v7.0.64-0.20231119012610-6eebdd6d5eba/go.mod h1:R4WVUR6ZTedlCcGwZRauLMIKjgyaWxhs4Mqi/OMPmEc=
|
||||
github.com/minio/mux v1.9.0 h1:dWafQFyEfGhJvK6AwLOt83bIG5bxKxKJnKMCi0XAaoA=
|
||||
github.com/minio/mux v1.9.0/go.mod h1:1pAare17ZRL5GpmNL+9YmqHoWnLmMZF9C/ioUCfy0BQ=
|
||||
github.com/minio/pkg v1.7.5 h1:UOUJjewE5zoaDPlCMJtNx/swc1jT1ZR+IajT7hrLd44=
|
||||
github.com/minio/pkg v1.7.5/go.mod h1:mEfGMTm5Z0b5EGxKNuPwyb5A2d+CC/VlUyRj6RJtIwo=
|
||||
github.com/minio/pkg/v2 v2.0.2 h1:cytXmC21fBNS+0NVKEE5FuYmQfY+HFTqis6Kkj3U9ac=
|
||||
github.com/minio/pkg/v2 v2.0.2/go.mod h1:6xTAr5M9yobpUroXAAaTrGJ9fhOZIqKYOT0I87u2yZ4=
|
||||
github.com/minio/pkg/v2 v2.0.3-0.20231107172951-8a60b89ec9b4 h1:5eHjHtFZrrCQ3eO0sesXomdAUTtcGh0Fpp7Qa6dtjrY=
|
||||
github.com/minio/pkg/v2 v2.0.3-0.20231107172951-8a60b89ec9b4/go.mod h1:6xTAr5M9yobpUroXAAaTrGJ9fhOZIqKYOT0I87u2yZ4=
|
||||
github.com/minio/selfupdate v0.6.0 h1:i76PgT0K5xO9+hjzKcacQtO7+MjJ4JKA8Ak8XQ9DDwU=
|
||||
github.com/minio/selfupdate v0.6.0/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
@@ -539,11 +545,11 @@ github.com/nats-io/nats-streaming-server v0.24.3/go.mod h1:rqWfyCbxlhKj//fAp8POd
|
||||
github.com/nats-io/nats.go v1.13.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nats.go v1.13.1-0.20220308171302-2f2f6968e98d/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
|
||||
github.com/nats-io/nats.go v1.22.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA=
|
||||
github.com/nats-io/nats.go v1.30.0 h1:bj/rVsRCrFXxmm9mJiDhb74UKl2HhKpDwKRBtvCjZjc=
|
||||
github.com/nats-io/nats.go v1.30.0/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
|
||||
github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
|
||||
github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
|
||||
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||
github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
|
||||
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nats-io/stan.go v0.10.2/go.mod h1:vo2ax8K2IxaR3JtEMLZRFKIdoK/3o1/PKueapB7ezX0=
|
||||
@@ -570,6 +576,7 @@ github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9F
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -592,34 +599,34 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/prometheus/prom2json v1.3.3 h1:IYfSMiZ7sSOfliBoo89PcufjWO4eAR0gznGcETyaUgo=
|
||||
github.com/prometheus/prom2json v1.3.3/go.mod h1:Pv4yIPktEkK7btWsrUTWDDDrnpUrAELaOCj+oFwlgmc=
|
||||
github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA=
|
||||
github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo=
|
||||
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rivo/tview v0.0.0-20230916092115-0ad06c2ea3dd h1:5fv4woBUz69TNaDvJl19bFdMiDdhdGKtYmzZOk6pGVY=
|
||||
github.com/rivo/tview v0.0.0-20230916092115-0ad06c2ea3dd/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE=
|
||||
github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a h1:368NWOLkcJirQFjVSUfB6LWbkas6fd8lQ3DbO66tw1w=
|
||||
github.com/rivo/tview v0.0.0-20231007183732-6c844bdc5f7a/go.mod h1:nVwGv4MP47T0jvlk7KuTTjjuSmrGO4JF0iaiNt4bufE=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
@@ -630,18 +637,20 @@ github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4Ug
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rs/cors v1.10.0 h1:62NOS1h+r8p1mW6FM0FSB0exioXLhd/sh15KpjWBZ+8=
|
||||
github.com/rs/cors v1.10.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
|
||||
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||
github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc=
|
||||
github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs=
|
||||
github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
|
||||
github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
|
||||
github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E=
|
||||
github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@@ -677,8 +686,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg=
|
||||
github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
|
||||
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
@@ -698,6 +707,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs
|
||||
github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/vbauerster/mpb/v8 v8.6.2 h1:9EhnJGQRtvgDVCychJgR96EDCOqgg2NsMuk5JUcX4DA=
|
||||
github.com/vbauerster/mpb/v8 v8.6.2/go.mod h1:oVJ7T+dib99kZ/VBjoBaC8aPXiSAihnzuKmotuihyFo=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
@@ -771,8 +782,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
@@ -781,8 +792,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -814,8 +825,8 @@ golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
|
||||
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
|
||||
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
|
||||
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -828,8 +839,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -928,16 +939,16 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.142.0 h1:mf+7EJ94fi5ZcnpPy+m0Yv2dkz8bKm+UL0snTCuwXlY=
|
||||
google.golang.org/api v0.142.0/go.mod h1:zJAN5o6HRqR7O+9qJUFOWrZkYE66RH+efPBdTLA4xBA=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs=
|
||||
google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
@@ -945,19 +956,19 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13 h1:vlzZttNJGVqTsRFU9AmdnrcO1Znh8Ew9kCD//yjigk0=
|
||||
google.golang.org/genproto v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:CCviP9RmpZ1mxVr8MUjCnSiY09IbAXZxhLE6EhHIdPU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 h1:U7+wNaVuSTaUqNvK2+osJ9ejEZxbjHHk8F2b6Hpx0AE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
|
||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
|
||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
|
||||
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -94,7 +94,7 @@ var (
|
||||
},
|
||||
config.HelpKV{
|
||||
Key: apiODirect,
|
||||
Description: "set to enable or disable O_DIRECT for read and writes under special conditions. NOTE: do not disable O_DIRECT without prior testing" + defaultHelpPostfix(apiODirect),
|
||||
Description: "set to enable or disable O_DIRECT for writes under special conditions. NOTE: do not disable O_DIRECT without prior testing" + defaultHelpPostfix(apiODirect),
|
||||
Optional: true,
|
||||
Type: "boolean",
|
||||
},
|
||||
|
||||
@@ -1091,6 +1091,8 @@ func (c Config) GetAvailableTargets(subSys string) ([]string, error) {
|
||||
seen.Add(k)
|
||||
}
|
||||
|
||||
// env:prefix
|
||||
filterMap := map[string]string{}
|
||||
// Add targets that are configured via environment variables.
|
||||
for _, param := range defKVS {
|
||||
envVarPrefix := getEnvVarName(subSys, Default, param.Key) + Default
|
||||
@@ -1098,11 +1100,21 @@ func (c Config) GetAvailableTargets(subSys string) ([]string, error) {
|
||||
for _, k := range envsWithPrefix {
|
||||
tgtName := strings.TrimPrefix(k, envVarPrefix)
|
||||
if tgtName != "" {
|
||||
seen.Add(tgtName)
|
||||
if v, ok := filterMap[k]; ok {
|
||||
if strings.HasPrefix(envVarPrefix, v) {
|
||||
filterMap[k] = envVarPrefix
|
||||
}
|
||||
} else {
|
||||
filterMap[k] = envVarPrefix
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range filterMap {
|
||||
seen.Add(strings.TrimPrefix(k, v))
|
||||
}
|
||||
|
||||
seen.Remove(Default)
|
||||
targets := seen.ToSlice()
|
||||
sort.Strings(targets)
|
||||
|
||||
@@ -67,7 +67,8 @@ const (
|
||||
EnvRootDriveThresholdSize = "MINIO_ROOTDRIVE_THRESHOLD_SIZE"
|
||||
EnvRootDiskThresholdSize = "MINIO_ROOTDISK_THRESHOLD_SIZE" // Deprecated Sep 2023
|
||||
EnvBrowserLoginAnimation = "MINIO_BROWSER_LOGIN_ANIMATION"
|
||||
EnvBrowserSessionDuration = "MINIO_BROWSER_SESSION_DURATION"
|
||||
EnvBrowserSessionDuration = "MINIO_BROWSER_SESSION_DURATION" // Deprecated after November 2023
|
||||
EnvMinioStsDuration = "MINIO_STS_DURATION"
|
||||
EnvMinIOLogQueryURL = "MINIO_LOG_QUERY_URL"
|
||||
EnvMinIOLogQueryAuthToken = "MINIO_LOG_QUERY_AUTH_TOKEN"
|
||||
EnvMinIOPrometheusURL = "MINIO_PROMETHEUS_URL"
|
||||
@@ -82,3 +83,11 @@ const (
|
||||
EnvRegion = "MINIO_REGION" // legacy
|
||||
EnvRegionName = "MINIO_REGION_NAME" // legacy
|
||||
)
|
||||
|
||||
// Expiration Token durations
|
||||
// These values are used to validate the expiration time range from
|
||||
// either the exp claim or MINI_STS_DURATION value
|
||||
const (
|
||||
MinExpiration = 900
|
||||
MaxExpiration = 31536000
|
||||
)
|
||||
|
||||
@@ -114,8 +114,7 @@ func updateClaimsExpiry(dsecs string, claims map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
expAt, err := auth.ExpToInt64(expStr)
|
||||
if err != nil {
|
||||
if _, err := auth.ExpToInt64(expStr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -124,13 +123,6 @@ func updateClaimsExpiry(dsecs string, claims map[string]interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify if JWT expiry is lesser than default expiry duration,
|
||||
// if that is the case then set the default expiration to be
|
||||
// from the JWT expiry claim.
|
||||
if time.Unix(expAt, 0).UTC().Sub(time.Now().UTC()) < defaultExpiryDuration {
|
||||
defaultExpiryDuration = time.Unix(expAt, 0).UTC().Sub(time.Now().UTC())
|
||||
} // else honor the specified expiry duration.
|
||||
|
||||
claims["exp"] = time.Now().UTC().Add(defaultExpiryDuration).Unix() // update with new expiry.
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/minio/minio/internal/config"
|
||||
"github.com/minio/minio/internal/config/identity/openid/provider"
|
||||
"github.com/minio/minio/internal/hash/sha256"
|
||||
"github.com/minio/pkg/v2/env"
|
||||
xnet "github.com/minio/pkg/v2/net"
|
||||
"github.com/minio/pkg/v2/policy"
|
||||
)
|
||||
@@ -599,8 +600,12 @@ func (r Config) GetRoleInfo() map[arn.ARN]string {
|
||||
|
||||
// GetDefaultExpiration - returns the expiration seconds expected.
|
||||
func GetDefaultExpiration(dsecs string) (time.Duration, error) {
|
||||
defaultExpiryDuration := time.Duration(60) * time.Minute // Defaults to 1hr.
|
||||
if dsecs != "" {
|
||||
timeout := env.Get(config.EnvMinioStsDuration, "")
|
||||
defaultExpiryDuration, err := time.ParseDuration(timeout)
|
||||
if err != nil {
|
||||
defaultExpiryDuration = time.Hour
|
||||
}
|
||||
if timeout == "" && dsecs != "" {
|
||||
expirySecs, err := strconv.ParseInt(dsecs, 10, 64)
|
||||
if err != nil {
|
||||
return 0, auth.ErrInvalidDuration
|
||||
@@ -609,11 +614,18 @@ func GetDefaultExpiration(dsecs string) (time.Duration, error) {
|
||||
// The duration, in seconds, of the role session.
|
||||
// The value can range from 900 seconds (15 minutes)
|
||||
// up to 365 days.
|
||||
if expirySecs < 900 || expirySecs > 31536000 {
|
||||
if expirySecs < config.MinExpiration || expirySecs > config.MaxExpiration {
|
||||
return 0, auth.ErrInvalidDuration
|
||||
}
|
||||
|
||||
defaultExpiryDuration = time.Duration(expirySecs) * time.Second
|
||||
} else if timeout == "" && dsecs == "" {
|
||||
return time.Hour, nil
|
||||
}
|
||||
|
||||
if defaultExpiryDuration.Seconds() < config.MinExpiration || defaultExpiryDuration.Seconds() > config.MaxExpiration {
|
||||
return 0, auth.ErrInvalidDuration
|
||||
}
|
||||
|
||||
return defaultExpiryDuration, nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -31,6 +30,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio/internal/config/lambda/event"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/pkg/v2/certs"
|
||||
xnet "github.com/minio/pkg/v2/net"
|
||||
@@ -133,8 +133,7 @@ func (target *WebhookTarget) isActive() (bool, error) {
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
xhttp.DrainBody(resp.Body)
|
||||
// No network failure i.e response from the target means its up
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
elasticsearch7 "github.com/elastic/go-elasticsearch/v7"
|
||||
"github.com/minio/highwayhash"
|
||||
"github.com/minio/minio/internal/event"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/minio/internal/once"
|
||||
"github.com/minio/minio/internal/store"
|
||||
@@ -474,7 +475,7 @@ func (c *esClientV7) createIndex(args ElasticsearchArgs) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer DrainBody(resp.Body)
|
||||
defer xioutil.DiscardReader(resp.Body)
|
||||
if resp.IsError() {
|
||||
return fmt.Errorf("Create index err: %v", res)
|
||||
}
|
||||
@@ -490,7 +491,7 @@ func (c *esClientV7) ping(ctx context.Context, _ ElasticsearchArgs) (bool, error
|
||||
if err != nil {
|
||||
return false, store.ErrNotConnected
|
||||
}
|
||||
DrainBody(resp.Body)
|
||||
xioutil.DiscardReader(resp.Body)
|
||||
return !resp.IsError(), nil
|
||||
}
|
||||
|
||||
@@ -503,7 +504,7 @@ func (c *esClientV7) entryExists(ctx context.Context, index string, key string)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
DrainBody(res.Body)
|
||||
xioutil.DiscardReader(res.Body)
|
||||
return !res.IsError(), nil
|
||||
}
|
||||
|
||||
@@ -518,7 +519,7 @@ func (c *esClientV7) removeEntry(ctx context.Context, index string, key string)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer DrainBody(res.Body)
|
||||
defer xioutil.DiscardReader(res.Body)
|
||||
if res.IsError() {
|
||||
return fmt.Errorf("Delete err: %s", res.String())
|
||||
}
|
||||
@@ -546,7 +547,7 @@ func (c *esClientV7) updateEntry(ctx context.Context, index string, key string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer DrainBody(res.Body)
|
||||
defer xioutil.DiscardReader(res.Body)
|
||||
if res.IsError() {
|
||||
return fmt.Errorf("Update err: %s", res.String())
|
||||
}
|
||||
@@ -572,7 +573,7 @@ func (c *esClientV7) addEntry(ctx context.Context, index string, eventData event
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer DrainBody(res.Body)
|
||||
defer xioutil.DiscardReader(res.Body)
|
||||
if res.IsError() {
|
||||
return fmt.Errorf("Add err: %s", res.String())
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package target
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"strings"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/xdg/scram"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
)
|
||||
|
||||
func initScramClient(args KafkaArgs, config *sarama.Config) {
|
||||
switch args.SASL.Mechanism {
|
||||
switch strings.ToLower(args.SASL.Mechanism) {
|
||||
case "sha512":
|
||||
config.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient { return &XDGSCRAMClient{HashGeneratorFcn: KafkaSHA512} }
|
||||
config.Net.SASL.Mechanism = sarama.SASLMechanism(sarama.SASLTypeSCRAMSHA512)
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -34,8 +33,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/minio/minio/internal/event"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/minio/internal/once"
|
||||
"github.com/minio/minio/internal/store"
|
||||
@@ -197,7 +196,7 @@ func (target *WebhookTarget) send(eventData event.Event) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer DrainBody(resp.Body)
|
||||
defer xhttp.DrainBody(resp.Body)
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
return fmt.Errorf("sending event failed with %v", resp.Status)
|
||||
@@ -312,23 +311,3 @@ func NewWebhookTarget(ctx context.Context, id string, args WebhookArgs, loggerOn
|
||||
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// DrainBody close non nil response with any response Body.
|
||||
// convenient wrapper to drain any remaining data on response body.
|
||||
//
|
||||
// Subsequently this allows golang http RoundTripper
|
||||
// to re-use the same connection for future requests.
|
||||
func DrainBody(respBody io.ReadCloser) {
|
||||
// Callers should close resp.Body when done reading from it.
|
||||
// If resp.Body is not closed, the Client's underlying RoundTripper
|
||||
// (typically Transport) may not be able to re-use a persistent TCP
|
||||
// connection to the server for a subsequent "keep-alive" request.
|
||||
if respBody != nil {
|
||||
// Drain any remaining Body and then close the connection.
|
||||
// Without this closing connection would disallow re-using
|
||||
// the same connection for future uses.
|
||||
// - http://stackoverflow.com/a/17961593/4465767
|
||||
defer respBody.Close()
|
||||
io.CopyN(io.Discard, respBody, 1*humanize.MiByte)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package http
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
)
|
||||
|
||||
// DrainBody close non nil response with any response Body.
|
||||
@@ -37,6 +39,6 @@ func DrainBody(respBody io.ReadCloser) {
|
||||
// the same connection for future uses.
|
||||
// - http://stackoverflow.com/a/17961593/4465767
|
||||
defer respBody.Close()
|
||||
io.Copy(io.Discard, respBody)
|
||||
xioutil.DiscardReader(respBody)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -29,6 +30,7 @@ import (
|
||||
// status code and to record the response body
|
||||
type ResponseRecorder struct {
|
||||
http.ResponseWriter
|
||||
io.ReaderFrom
|
||||
StatusCode int
|
||||
// Log body of 4xx or 5xx responses
|
||||
LogErrBody bool
|
||||
@@ -51,13 +53,27 @@ type ResponseRecorder struct {
|
||||
// NewResponseRecorder - returns a wrapped response writer to trap
|
||||
// http status codes for auditing purposes.
|
||||
func NewResponseRecorder(w http.ResponseWriter) *ResponseRecorder {
|
||||
rf, _ := w.(io.ReaderFrom)
|
||||
return &ResponseRecorder{
|
||||
ResponseWriter: w,
|
||||
ReaderFrom: rf,
|
||||
StatusCode: http.StatusOK,
|
||||
StartTime: time.Now().UTC(),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrNotImplemented when a functionality is not implemented
|
||||
var ErrNotImplemented = errors.New("not implemented")
|
||||
|
||||
// ReadFrom implements support for calling internal io.ReaderFrom implementations
|
||||
// returns an error if the underlying ResponseWriter does not implement io.ReaderFrom
|
||||
func (lrw *ResponseRecorder) ReadFrom(r io.Reader) (int64, error) {
|
||||
if lrw.ReaderFrom != nil {
|
||||
return lrw.ReaderFrom.ReadFrom(r)
|
||||
}
|
||||
return 0, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (lrw *ResponseRecorder) Write(p []byte) (int, error) {
|
||||
if !lrw.headersLogged {
|
||||
// We assume the response code to be '200 OK' when WriteHeader() is not called,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2015-2023 MinIO, Inc.
|
||||
//
|
||||
// This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Discard is just like io.Discard without the io.ReaderFrom compatible
|
||||
// implementation which is buggy on NUMA systems, we have to use a simpler
|
||||
// io.Writer implementation alone avoids also unnecessary buffer copies,
|
||||
// and as such incurred latencies.
|
||||
var Discard io.Writer = discard{}
|
||||
|
||||
// discard is /dev/null for Golang.
|
||||
type discard struct{}
|
||||
|
||||
func (discard) Write(p []byte) (int, error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// DiscardReader discarded reader
|
||||
func DiscardReader(r io.Reader) {
|
||||
Copy(Discard, r)
|
||||
}
|
||||
@@ -379,10 +379,6 @@ func (h *Target) SendFromStore(key store.Key) (err error) {
|
||||
// Messages are queued in the disk if the store is enabled
|
||||
// If Cancel has been called the message is ignored.
|
||||
func (h *Target) Send(ctx context.Context, entry interface{}) error {
|
||||
if atomic.LoadInt32(&h.status) == statusOffline {
|
||||
h.config.LogOnce(ctx, fmt.Errorf("target %s is offline", h.Endpoint()), h.Endpoint())
|
||||
return nil
|
||||
}
|
||||
if atomic.LoadInt32(&h.status) == statusClosed {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package kafka
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"strings"
|
||||
|
||||
"github.com/IBM/sarama"
|
||||
"github.com/xdg/scram"
|
||||
@@ -27,7 +28,7 @@ import (
|
||||
)
|
||||
|
||||
func initScramClient(cfg Config, config *sarama.Config) {
|
||||
switch cfg.SASL.Mechanism {
|
||||
switch strings.ToLower(cfg.SASL.Mechanism) {
|
||||
case "sha512":
|
||||
config.Net.SASL.SCRAMClientGeneratorFunc = func() sarama.SCRAMClient { return &XDGSCRAMClient{HashGeneratorFcn: KafkaSHA512} }
|
||||
config.Net.SASL.Mechanism = sarama.SASLMechanism(sarama.SASLTypeSCRAMSHA512)
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/klauspost/compress/zstd"
|
||||
gzip "github.com/klauspost/pgzip"
|
||||
"github.com/minio/minio/internal/config"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/s3select/csv"
|
||||
"github.com/minio/minio/internal/s3select/json"
|
||||
"github.com/minio/minio/internal/s3select/parquet"
|
||||
@@ -91,7 +92,7 @@ var bufioWriterPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
// io.Discard is just used to create the writer. Actual destination
|
||||
// writer is set later by Reset() before using it.
|
||||
return bufio.NewWriter(io.Discard)
|
||||
return bufio.NewWriter(xioutil.Discard)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -467,7 +468,7 @@ func (s3Select *S3Select) marshal(buf *bytes.Buffer, record sql.Record) error {
|
||||
// Use bufio Writer to prevent csv.Writer from allocating a new buffer.
|
||||
bufioWriter := bufioWriterPool.Get().(*bufio.Writer)
|
||||
defer func() {
|
||||
bufioWriter.Reset(io.Discard)
|
||||
bufioWriter.Reset(xioutil.Discard)
|
||||
bufioWriterPool.Put(bufioWriter)
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user