mirror of https://github.com/minio/minio.git
Compare commits
6 Commits
90d232c2c2
...
d331ca7031
| Author | SHA1 | Date |
|---|---|---|
|
|
d331ca7031 | |
|
|
83b2ad418b | |
|
|
7a64bb9766 | |
|
|
34679befef | |
|
|
4021d8c8e2 | |
|
|
bdd961a82e |
14
README.md
14
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# MinIO Quickstart Guide
|
||||
|
||||
[](https://slack.min.io) [](https://hub.docker.com/r/minio/minio/) [](https://github.com/minio/minio/blob/master/LICENSE)
|
||||
[](https://slack.min.io) [](https://hub.docker.com/r/minio/minio) [](https://github.com/minio/minio/blob/master/LICENSE)
|
||||
|
||||
[](https://min.io)
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ Standalone MinIO servers are best suited for early development and evaluation. C
|
|||
|
||||
### Homebrew (recommended)
|
||||
|
||||
Run the following command to install the latest stable MinIO package using [Homebrew](https://brew.sh/). Replace ``/data`` with the path to the drive or directory in which you want MinIO to store data.
|
||||
Run the following command to install the latest stable MinIO package using [Homebrew](https://brew.sh). Replace ``/data`` with the path to the drive or directory in which you want MinIO to store data.
|
||||
|
||||
```sh
|
||||
brew install minio/stable/minio
|
||||
|
|
@ -69,7 +69,7 @@ brew install minio/stable/minio
|
|||
|
||||
The MinIO deployment starts using default root credentials `minioadmin:minioadmin`. You can test the deployment using the MinIO Console, an embedded web-based object browser built into MinIO Server. Point a web browser running on the host machine to <http://127.0.0.1:9000> and log in with the root credentials. You can use the Browser to create buckets, upload objects, and browse the contents of the MinIO server.
|
||||
|
||||
You can also connect using any S3-compatible tool, such as the MinIO Client `mc` commandline tool. See [Test using MinIO Client `mc`](#test-using-minio-client-mc) for more information on using the `mc` commandline tool. For application developers, see <https://min.io/docs/minio/linux/developers/minio-drivers.html/> to view MinIO SDKs for supported languages.
|
||||
You can also connect using any S3-compatible tool, such as the MinIO Client `mc` commandline tool. See [Test using MinIO Client `mc`](#test-using-minio-client-mc) for more information on using the `mc` commandline tool. For application developers, see <https://min.io/docs/minio/linux/developers/minio-drivers.html> to view MinIO SDKs for supported languages.
|
||||
|
||||
### Binary Download
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ The MinIO deployment starts using default root credentials `minioadmin:minioadmi
|
|||
You can also connect using any S3-compatible tool, such as the MinIO Client `mc` commandline tool. See [Test using MinIO Client `mc`](#test-using-minio-client-mc) for more information on using the `mc` commandline tool. For application developers, see <https://min.io/docs/minio/linux/developers/minio-drivers.html> to view MinIO SDKs for supported languages.
|
||||
|
||||
> [!NOTE]
|
||||
> Standalone MinIO servers are best suited for early development and evaluation. Certain features such as versioning, object locking, and bucket replication require distributed deploying MinIO with Erasure Coding. For extended development and production, deploy MinIO with Erasure Coding enabled - specifically, with a *minimum* of 4 drives per MinIO server. See [MinIO Erasure Code Overview](https://min.io/docs/minio/linux/operations/concepts/erasure-coding.html#) for more complete documentation.
|
||||
> Standalone MinIO servers are best suited for early development and evaluation. Certain features such as versioning, object locking, and bucket replication require distributed deploying MinIO with Erasure Coding. For extended development and production, deploy MinIO with Erasure Coding enabled - specifically, with a *minimum* of 4 drives per MinIO server. See [MinIO Erasure Code Overview](https://min.io/docs/minio/linux/operations/concepts/erasure-coding.html) for more complete documentation.
|
||||
|
||||
## Microsoft Windows
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ The MinIO deployment starts using default root credentials `minioadmin:minioadmi
|
|||
You can also connect using any S3-compatible tool, such as the MinIO Client `mc` commandline tool. See [Test using MinIO Client `mc`](#test-using-minio-client-mc) for more information on using the `mc` commandline tool. For application developers, see <https://min.io/docs/minio/linux/developers/minio-drivers.html> to view MinIO SDKs for supported languages.
|
||||
|
||||
> [!NOTE]
|
||||
> Standalone MinIO servers are best suited for early development and evaluation. Certain features such as versioning, object locking, and bucket replication require distributed deploying MinIO with Erasure Coding. For extended development and production, deploy MinIO with Erasure Coding enabled - specifically, with a *minimum* of 4 drives per MinIO server. See [MinIO Erasure Code Overview](https://min.io/docs/minio/linux/operations/concepts/erasure-coding.html#) for more complete documentation.
|
||||
> Standalone MinIO servers are best suited for early development and evaluation. Certain features such as versioning, object locking, and bucket replication require distributed deploying MinIO with Erasure Coding. For extended development and production, deploy MinIO with Erasure Coding enabled - specifically, with a *minimum* of 4 drives per MinIO server. See [MinIO Erasure Code Overview](https://min.io/docs/minio/linux/operations/concepts/erasure-coding.html) for more complete documentation.
|
||||
|
||||
## Install from Source
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ For example, consider a MinIO deployment behind a proxy `https://minio.example.n
|
|||
Upgrades require zero downtime in MinIO, all upgrades are non-disruptive, all transactions on MinIO are atomic. So upgrading all the servers simultaneously is the recommended way to upgrade MinIO.
|
||||
|
||||
> [!NOTE]
|
||||
> requires internet access to update directly from <https://dl.min.io>, optionally you can host any mirrors at <https://my-artifactory.example.com/minio/>
|
||||
> requires internet access to update directly from <https://dl.min.io>, optionally you can host any mirrors at <https://my-artifactory.example.com/minio>
|
||||
|
||||
- For deployments that installed the MinIO server binary by hand, use [`mc admin update`](https://min.io/docs/minio/linux/reference/minio-mc-admin/mc-admin-update.html)
|
||||
|
||||
|
|
@ -270,5 +270,5 @@ Please follow MinIO [Contributor's Guide](https://github.com/minio/minio/blob/ma
|
|||
## License
|
||||
|
||||
- MinIO source is licensed under the [GNU AGPLv3](https://github.com/minio/minio/blob/master/LICENSE).
|
||||
- MinIO [documentation](https://github.com/minio/minio/tree/master/docs) is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
||||
- MinIO [documentation](https://github.com/minio/minio/tree/master/docs) is licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0).
|
||||
- [License Compliance](https://github.com/minio/minio/blob/master/COMPLIANCE.md)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import (
|
|||
"github.com/minio/madmin-go/v3/logger/log"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/minio/internal/logger/target/console"
|
||||
"github.com/minio/minio/internal/logger/target/types"
|
||||
types "github.com/minio/minio/internal/logger/target/loggertypes"
|
||||
"github.com/minio/minio/internal/pubsub"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -635,15 +635,18 @@ func (z *erasureServerPools) getPoolIdxNoLock(ctx context.Context, bucket, objec
|
|||
// if none are found falls back to most available space pool, this function is
|
||||
// designed to be only used by PutObject, CopyObject (newObject creation) and NewMultipartUpload.
|
||||
func (z *erasureServerPools) getPoolIdx(ctx context.Context, bucket, object string, size int64) (idx int, err error) {
|
||||
idx, err = z.getPoolIdxExistingWithOpts(ctx, bucket, object, ObjectOptions{
|
||||
pinfo, _, err := z.getPoolInfoExistingWithOpts(ctx, bucket, object, ObjectOptions{
|
||||
SkipDecommissioned: true,
|
||||
SkipRebalancing: true,
|
||||
})
|
||||
|
||||
if err != nil && !isErrObjectNotFound(err) {
|
||||
return idx, err
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if isErrObjectNotFound(err) {
|
||||
idx = pinfo.Index
|
||||
if isErrObjectNotFound(err) || pinfo.Err == nil {
|
||||
// will generate a temp object
|
||||
idx = z.getAvailablePoolIdx(ctx, bucket, object, size)
|
||||
if idx < 0 {
|
||||
return -1, toObjectErr(errDiskFull)
|
||||
|
|
@ -1089,6 +1092,10 @@ func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, objec
|
|||
|
||||
object = encodeDirObject(object)
|
||||
if z.SinglePool() {
|
||||
_, err := z.getPoolIdx(ctx, bucket, object, data.Size())
|
||||
if err != nil {
|
||||
return ObjectInfo{}, err
|
||||
}
|
||||
return z.serverPools[0].PutObject(ctx, bucket, object, data, opts)
|
||||
}
|
||||
|
||||
|
|
@ -1816,6 +1823,10 @@ func (z *erasureServerPools) PutObjectPart(ctx context.Context, bucket, object,
|
|||
}
|
||||
|
||||
if z.SinglePool() {
|
||||
_, err := z.getPoolIdx(ctx, bucket, object, data.Size())
|
||||
if err != nil {
|
||||
return PartInfo{}, err
|
||||
}
|
||||
return z.serverPools[0].PutObjectPart(ctx, bucket, object, uploadID, partID, data, opts)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/klauspost/compress/gzhttp"
|
||||
|
|
@ -39,7 +41,7 @@ import (
|
|||
"github.com/minio/minio/internal/logger"
|
||||
)
|
||||
|
||||
func getLambdaEventData(bucket, object string, cred auth.Credentials, r *http.Request) (levent.Event, error) {
|
||||
var getLambdaEventData = func(bucket, object string, cred auth.Credentials, r *http.Request) (levent.Event, error) {
|
||||
host := globalLocalNodeName
|
||||
secure := globalIsTLS
|
||||
if globalMinioEndpointURL != nil {
|
||||
|
|
@ -100,80 +102,6 @@ func getLambdaEventData(bucket, object string, cred auth.Credentials, r *http.Re
|
|||
return eventData, nil
|
||||
}
|
||||
|
||||
var statusTextToCode = map[string]int{
|
||||
"Continue": http.StatusContinue,
|
||||
"Switching Protocols": http.StatusSwitchingProtocols,
|
||||
"Processing": http.StatusProcessing,
|
||||
"Early Hints": http.StatusEarlyHints,
|
||||
"OK": http.StatusOK,
|
||||
"Created": http.StatusCreated,
|
||||
"Accepted": http.StatusAccepted,
|
||||
"Non-Authoritative Information": http.StatusNonAuthoritativeInfo,
|
||||
"No Content": http.StatusNoContent,
|
||||
"Reset Content": http.StatusResetContent,
|
||||
"Partial Content": http.StatusPartialContent,
|
||||
"Multi-Status": http.StatusMultiStatus,
|
||||
"Already Reported": http.StatusAlreadyReported,
|
||||
"IM Used": http.StatusIMUsed,
|
||||
"Multiple Choices": http.StatusMultipleChoices,
|
||||
"Moved Permanently": http.StatusMovedPermanently,
|
||||
"Found": http.StatusFound,
|
||||
"See Other": http.StatusSeeOther,
|
||||
"Not Modified": http.StatusNotModified,
|
||||
"Use Proxy": http.StatusUseProxy,
|
||||
"Temporary Redirect": http.StatusTemporaryRedirect,
|
||||
"Permanent Redirect": http.StatusPermanentRedirect,
|
||||
"Bad Request": http.StatusBadRequest,
|
||||
"Unauthorized": http.StatusUnauthorized,
|
||||
"Payment Required": http.StatusPaymentRequired,
|
||||
"Forbidden": http.StatusForbidden,
|
||||
"Not Found": http.StatusNotFound,
|
||||
"Method Not Allowed": http.StatusMethodNotAllowed,
|
||||
"Not Acceptable": http.StatusNotAcceptable,
|
||||
"Proxy Authentication Required": http.StatusProxyAuthRequired,
|
||||
"Request Timeout": http.StatusRequestTimeout,
|
||||
"Conflict": http.StatusConflict,
|
||||
"Gone": http.StatusGone,
|
||||
"Length Required": http.StatusLengthRequired,
|
||||
"Precondition Failed": http.StatusPreconditionFailed,
|
||||
"Request Entity Too Large": http.StatusRequestEntityTooLarge,
|
||||
"Request URI Too Long": http.StatusRequestURITooLong,
|
||||
"Unsupported Media Type": http.StatusUnsupportedMediaType,
|
||||
"Requested Range Not Satisfiable": http.StatusRequestedRangeNotSatisfiable,
|
||||
"Expectation Failed": http.StatusExpectationFailed,
|
||||
"I'm a teapot": http.StatusTeapot,
|
||||
"Misdirected Request": http.StatusMisdirectedRequest,
|
||||
"Unprocessable Entity": http.StatusUnprocessableEntity,
|
||||
"Locked": http.StatusLocked,
|
||||
"Failed Dependency": http.StatusFailedDependency,
|
||||
"Too Early": http.StatusTooEarly,
|
||||
"Upgrade Required": http.StatusUpgradeRequired,
|
||||
"Precondition Required": http.StatusPreconditionRequired,
|
||||
"Too Many Requests": http.StatusTooManyRequests,
|
||||
"Request Header Fields Too Large": http.StatusRequestHeaderFieldsTooLarge,
|
||||
"Unavailable For Legal Reasons": http.StatusUnavailableForLegalReasons,
|
||||
"Internal Server Error": http.StatusInternalServerError,
|
||||
"Not Implemented": http.StatusNotImplemented,
|
||||
"Bad Gateway": http.StatusBadGateway,
|
||||
"Service Unavailable": http.StatusServiceUnavailable,
|
||||
"Gateway Timeout": http.StatusGatewayTimeout,
|
||||
"HTTP Version Not Supported": http.StatusHTTPVersionNotSupported,
|
||||
"Variant Also Negotiates": http.StatusVariantAlsoNegotiates,
|
||||
"Insufficient Storage": http.StatusInsufficientStorage,
|
||||
"Loop Detected": http.StatusLoopDetected,
|
||||
"Not Extended": http.StatusNotExtended,
|
||||
"Network Authentication Required": http.StatusNetworkAuthenticationRequired,
|
||||
}
|
||||
|
||||
// StatusCode returns a HTTP Status code for the HTTP text. It returns -1
|
||||
// if the text is unknown.
|
||||
func StatusCode(text string) int {
|
||||
if code, ok := statusTextToCode[text]; ok {
|
||||
return code
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func fwdHeadersToS3(h http.Header, w http.ResponseWriter) {
|
||||
const trim = "x-amz-fwd-header-"
|
||||
for k, v := range h {
|
||||
|
|
@ -183,19 +111,26 @@ func fwdHeadersToS3(h http.Header, w http.ResponseWriter) {
|
|||
}
|
||||
}
|
||||
|
||||
func fwdStatusToAPIError(resp *http.Response) *APIError {
|
||||
if status := resp.Header.Get(xhttp.AmzFwdStatus); status != "" && StatusCode(status) > -1 {
|
||||
apiErr := &APIError{
|
||||
HTTPStatusCode: StatusCode(status),
|
||||
Description: resp.Header.Get(xhttp.AmzFwdErrorMessage),
|
||||
Code: resp.Header.Get(xhttp.AmzFwdErrorCode),
|
||||
}
|
||||
if apiErr.HTTPStatusCode == http.StatusOK {
|
||||
return nil
|
||||
}
|
||||
return apiErr
|
||||
func fwdStatusToAPIError(statusCode int, resp *http.Response) *APIError {
|
||||
if statusCode < http.StatusBadRequest {
|
||||
return nil
|
||||
}
|
||||
desc := resp.Header.Get(xhttp.AmzFwdErrorMessage)
|
||||
if strings.TrimSpace(desc) == "" {
|
||||
apiErr := errorCodes.ToAPIErr(ErrInvalidRequest)
|
||||
return &apiErr
|
||||
}
|
||||
code := resp.Header.Get(xhttp.AmzFwdErrorCode)
|
||||
if strings.TrimSpace(code) == "" {
|
||||
apiErr := errorCodes.ToAPIErr(ErrInvalidRequest)
|
||||
apiErr.Description = desc
|
||||
return &apiErr
|
||||
}
|
||||
return &APIError{
|
||||
HTTPStatusCode: statusCode,
|
||||
Description: desc,
|
||||
Code: code,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetObjectLambdaHandler - GET Object with transformed data via lambda functions
|
||||
|
|
@ -262,26 +197,31 @@ func (api objectAPIHandlers) GetObjectLambdaHandler(w http.ResponseWriter, r *ht
|
|||
return
|
||||
}
|
||||
|
||||
statusCode := resp.StatusCode
|
||||
if status := resp.Header.Get(xhttp.AmzFwdStatus); status != "" {
|
||||
statusCode, err = strconv.Atoi(status)
|
||||
if err != nil {
|
||||
writeErrorResponse(ctx, w, APIError{
|
||||
Code: "LambdaFunctionStatusError",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
Description: err.Error(),
|
||||
}, r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Set all the relevant lambda forward headers if found.
|
||||
fwdHeadersToS3(resp.Header, w)
|
||||
|
||||
if apiErr := fwdStatusToAPIError(resp); apiErr != nil {
|
||||
if apiErr := fwdStatusToAPIError(statusCode, resp); apiErr != nil {
|
||||
writeErrorResponse(ctx, w, *apiErr, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
writeErrorResponse(ctx, w, APIError{
|
||||
Code: "LambdaFunctionError",
|
||||
HTTPStatusCode: resp.StatusCode,
|
||||
Description: "unexpected failure reported from lambda function",
|
||||
}, r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if !globalAPIConfig.shouldGzipObjects() {
|
||||
w.Header().Set(gzhttp.HeaderNoCompression, "true")
|
||||
}
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
io.Copy(w, resp.Body)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) 2015-2025 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 (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go/v7/pkg/signer"
|
||||
"github.com/minio/minio/internal/auth"
|
||||
"github.com/minio/minio/internal/config"
|
||||
"github.com/minio/minio/internal/config/lambda"
|
||||
levent "github.com/minio/minio/internal/config/lambda/event"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
)
|
||||
|
||||
func TestGetObjectLambdaHandler(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
statusCode int
|
||||
body string
|
||||
contentType string
|
||||
expectStatus int
|
||||
}{
|
||||
{
|
||||
name: "Success 206 Partial Content",
|
||||
statusCode: 206,
|
||||
body: "partial-object-data",
|
||||
contentType: "text/plain",
|
||||
expectStatus: 206,
|
||||
},
|
||||
{
|
||||
name: "Success 200 OK",
|
||||
statusCode: 200,
|
||||
body: "full-object-data",
|
||||
contentType: "application/json",
|
||||
expectStatus: 200,
|
||||
},
|
||||
{
|
||||
name: "Client Error 400",
|
||||
statusCode: 400,
|
||||
body: "bad-request",
|
||||
contentType: "application/xml",
|
||||
expectStatus: 400,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
runObjectLambdaTest(t, tc.statusCode, tc.body, tc.contentType, tc.expectStatus)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runObjectLambdaTest(t *testing.T, lambdaStatus int, lambdaBody, contentType string, expectStatus int) {
|
||||
ExecObjectLayerAPITest(ExecObjectLayerAPITestArgs{
|
||||
t: t,
|
||||
objAPITest: func(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, credentials auth.Credentials, t *testing.T) {
|
||||
objectName := "dummy-object"
|
||||
functionID := "lambda1"
|
||||
functionToken := "token123"
|
||||
|
||||
// Lambda mock server
|
||||
lambdaServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(xhttp.AmzRequestRoute, functionID)
|
||||
w.Header().Set(xhttp.AmzRequestToken, functionToken)
|
||||
w.Header().Set(xhttp.AmzFwdHeaderContentType, contentType)
|
||||
w.Header().Set(xhttp.AmzFwdStatus, strconv.Itoa(lambdaStatus))
|
||||
w.WriteHeader(lambdaStatus)
|
||||
w.Write([]byte(lambdaBody))
|
||||
}))
|
||||
defer lambdaServer.Close()
|
||||
|
||||
lambdaARN := "arn:minio:s3-object-lambda::lambda1:webhook"
|
||||
|
||||
cfg := config.New()
|
||||
cfg[config.LambdaWebhookSubSys] = map[string]config.KVS{
|
||||
functionID: {
|
||||
{Key: "endpoint", Value: lambdaServer.URL},
|
||||
{Key: "enable", Value: config.EnableOn},
|
||||
},
|
||||
}
|
||||
cfg[config.APISubSys] = map[string]config.KVS{
|
||||
"api": {
|
||||
{Key: "gzip", Value: config.EnableOff},
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
globalLambdaTargetList, err = lambda.FetchEnabledTargets(context.Background(), cfg, http.DefaultTransport.(*http.Transport))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load lambda targets: %v", err)
|
||||
}
|
||||
|
||||
getLambdaEventData = func(_, _ string, _ auth.Credentials, _ *http.Request) (levent.Event, error) {
|
||||
return levent.Event{
|
||||
GetObjectContext: &levent.GetObjectContext{
|
||||
OutputRoute: functionID,
|
||||
OutputToken: functionToken,
|
||||
InputS3URL: "http://localhost/dummy",
|
||||
},
|
||||
UserRequest: levent.UserRequest{
|
||||
Headers: map[string][]string{},
|
||||
},
|
||||
UserIdentity: levent.Identity{
|
||||
PrincipalID: "test-user",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
body := []byte{}
|
||||
req := httptest.NewRequest("GET", "/objectlambda/"+bucketName+"/"+objectName+"?lambdaArn="+url.QueryEscape(lambdaARN), bytes.NewReader(body))
|
||||
req.Form = url.Values{"lambdaArn": []string{lambdaARN}}
|
||||
req.Header.Set("Host", "localhost")
|
||||
req.Header.Set("X-Amz-Date", time.Now().UTC().Format("20060102T150405Z"))
|
||||
sum := sha256.Sum256(body)
|
||||
req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum[:]))
|
||||
req = signer.SignV4(*req, credentials.AccessKey, credentials.SecretKey, "", "us-east-1")
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
api := objectAPIHandlers{
|
||||
ObjectAPI: func() ObjectLayer {
|
||||
return obj
|
||||
},
|
||||
}
|
||||
api.GetObjectLambdaHandler(rec, req)
|
||||
|
||||
res := rec.Result()
|
||||
defer res.Body.Close()
|
||||
respBody, _ := io.ReadAll(res.Body)
|
||||
|
||||
if res.StatusCode != expectStatus {
|
||||
t.Errorf("Expected status %d, got %d", expectStatus, res.StatusCode)
|
||||
}
|
||||
|
||||
if contentType != "" {
|
||||
if ct := res.Header.Get("Content-Type"); ct != contentType {
|
||||
t.Errorf("Expected Content-Type %q, got %q", contentType, ct)
|
||||
}
|
||||
}
|
||||
|
||||
if res.StatusCode < 400 {
|
||||
if string(respBody) != lambdaBody {
|
||||
t.Errorf("Expected body %q, got %q", lambdaBody, string(respBody))
|
||||
}
|
||||
}
|
||||
},
|
||||
endpoints: []string{"GetObject"},
|
||||
})
|
||||
}
|
||||
|
|
@ -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.2025-06-13T11-33-47Z
|
||||
image: quay.io/minio/minio:RELEASE.2025-07-18T21-56-31Z
|
||||
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
|
||||
expose:
|
||||
- "9000"
|
||||
|
|
|
|||
|
|
@ -74,5 +74,5 @@ func TLSCiphersBackwardCompatible() []uint16 {
|
|||
// TLSCurveIDs returns a list of supported elliptic curve IDs
|
||||
// in preference order.
|
||||
func TLSCurveIDs() []tls.CurveID {
|
||||
return []tls.CurveID{tls.CurveP256, tls.X25519, tls.CurveP384, tls.CurveP521}
|
||||
return []tls.CurveID{tls.X25519MLKEM768, tls.CurveP256, tls.X25519, tls.CurveP384, tls.CurveP521}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import (
|
|||
jsoniter "github.com/json-iterator/go"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger/target/types"
|
||||
types "github.com/minio/minio/internal/logger/target/loggertypes"
|
||||
"github.com/minio/minio/internal/once"
|
||||
"github.com/minio/minio/internal/store"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import (
|
|||
saramatls "github.com/IBM/sarama/tools/tls"
|
||||
|
||||
xioutil "github.com/minio/minio/internal/ioutil"
|
||||
"github.com/minio/minio/internal/logger/target/types"
|
||||
types "github.com/minio/minio/internal/logger/target/loggertypes"
|
||||
"github.com/minio/minio/internal/once"
|
||||
"github.com/minio/minio/internal/store"
|
||||
xnet "github.com/minio/pkg/v3/net"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by "stringer -type=TargetType -trimprefix=Target types.go"; DO NOT EDIT.
|
||||
|
||||
package types
|
||||
package loggertypes
|
||||
|
||||
import "strconv"
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
// 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 types
|
||||
package loggertypes
|
||||
|
||||
// TargetType indicates type of the target e.g. console, http, kafka
|
||||
type TargetType uint8
|
||||
|
|
@ -36,7 +36,7 @@ import (
|
|||
|
||||
"github.com/minio/madmin-go/v3/logger/log"
|
||||
"github.com/minio/minio/internal/logger"
|
||||
"github.com/minio/minio/internal/logger/target/types"
|
||||
types "github.com/minio/minio/internal/logger/target/loggertypes"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
|
||||
"github.com/minio/minio/internal/logger/target/http"
|
||||
"github.com/minio/minio/internal/logger/target/kafka"
|
||||
"github.com/minio/minio/internal/logger/target/types"
|
||||
types "github.com/minio/minio/internal/logger/target/loggertypes"
|
||||
)
|
||||
|
||||
// Target is the entity that we will receive
|
||||
|
|
|
|||
Loading…
Reference in New Issue