diff --git a/cmd/logger/target/console/console.go b/cmd/logger/target/console/console.go index 65084e6bb..1a2d39375 100644 --- a/cmd/logger/target/console/console.go +++ b/cmd/logger/target/console/console.go @@ -74,6 +74,11 @@ func (c *Target) Send(e interface{}) error { apiString += ")" timeString := "Time: " + time.Now().Format(logger.TimeFormat) + var deploymentID string + if entry.DeploymentID != "" { + deploymentID = "\nDeploymentID: " + entry.DeploymentID + } + var requestID string if entry.RequestID != "" { requestID = "\nRequestID: " + entry.RequestID @@ -94,8 +99,8 @@ func (c *Target) Send(e interface{}) error { } var msg = logger.ColorFgRed(logger.ColorBold(entry.Trace.Message)) - var output = fmt.Sprintf("\n%s\n%s%s%s%s\nError: %s%s\n%s", - apiString, timeString, requestID, remoteHost, userAgent, + var output = fmt.Sprintf("\n%s\n%s%s%s%s%s\nError: %s%s\n%s", + apiString, timeString, deploymentID, requestID, remoteHost, userAgent, msg, tagString, strings.Join(trace, "\n")) fmt.Println(output) diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index f8d9e8687..7b4349f22 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -73,11 +73,34 @@ type ServerInfoRep struct { UIVersion string `json:"uiVersion"` } +// newWebContext creates a context with ReqInfo values from the given +// http request and api name. +func newWebContext(r *http.Request, api string) context.Context { + vars := mux.Vars(r) + bucket := vars["bucket"] + object := vars["object"] + prefix := vars["prefix"] + + if prefix != "" { + object = prefix + } + reqInfo := &logger.ReqInfo{ + DeploymentID: globalDeploymentID, + RemoteHost: handlers.GetSourceIP(r), + UserAgent: r.UserAgent(), + API: api, + BucketName: bucket, + ObjectName: object, + } + return logger.SetReqInfo(context.Background(), reqInfo) +} + // ServerInfo - get server info. func (web *webAPIHandlers) ServerInfo(r *http.Request, args *WebGenericArgs, reply *ServerInfoRep) error { + ctx := newWebContext(r, "webServerInfo") _, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } host, err := os.Hostname() if err != nil { @@ -124,15 +147,16 @@ type StorageInfoRep struct { // StorageInfo - web call to gather storage usage statistics. func (web *webAPIHandlers) StorageInfo(r *http.Request, args *WebGenericArgs, reply *StorageInfoRep) error { + ctx := newWebContext(r, "webStorageInfo") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } _, _, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } - reply.StorageInfo = objectAPI.StorageInfo(context.Background()) + reply.StorageInfo = objectAPI.StorageInfo(ctx) reply.UIVersion = browser.UIVersion return nil } @@ -144,13 +168,14 @@ type MakeBucketArgs struct { // MakeBucket - creates a new bucket. func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, reply *WebGenericRep) error { + ctx := newWebContext(r, "webMakeBucket") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // For authenticated users apply IAM policy. @@ -161,36 +186,36 @@ func (web *webAPIHandlers) MakeBucket(r *http.Request, args *MakeBucketArgs, rep ConditionValues: getConditionValues(r, "", claims.Subject), IsOwner: owner, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, true) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } if globalDNSConfig != nil { if _, err := globalDNSConfig.Get(args.BucketName); err != nil { if err == dns.ErrNoEntriesFound { // Proceed to creating a bucket. - if err = objectAPI.MakeBucketWithLocation(context.Background(), args.BucketName, globalServerConfig.GetRegion()); err != nil { - return toJSONError(err) + if err = objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerConfig.GetRegion()); err != nil { + return toJSONError(ctx, err) } if err = globalDNSConfig.Put(args.BucketName); err != nil { - objectAPI.DeleteBucket(context.Background(), args.BucketName) - return toJSONError(err) + objectAPI.DeleteBucket(ctx, args.BucketName) + return toJSONError(ctx, err) } reply.UIVersion = browser.UIVersion return nil } - return toJSONError(err) + return toJSONError(ctx, err) } - return toJSONError(errBucketAlreadyExists) + return toJSONError(ctx, errBucketAlreadyExists) } - if err := objectAPI.MakeBucketWithLocation(context.Background(), args.BucketName, globalServerConfig.GetRegion()); err != nil { - return toJSONError(err, args.BucketName) + if err := objectAPI.MakeBucketWithLocation(ctx, args.BucketName, globalServerConfig.GetRegion()); err != nil { + return toJSONError(ctx, err, args.BucketName) } reply.UIVersion = browser.UIVersion @@ -204,13 +229,14 @@ type RemoveBucketArgs struct { // DeleteBucket - removes a bucket, must be empty. func (web *webAPIHandlers) DeleteBucket(r *http.Request, args *RemoveBucketArgs, reply *WebGenericRep) error { + ctx := newWebContext(r, "webDeleteBucket") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // For authenticated users apply IAM policy. @@ -221,45 +247,43 @@ func (web *webAPIHandlers) DeleteBucket(r *http.Request, args *RemoveBucketArgs, ConditionValues: getConditionValues(r, "", claims.Subject), IsOwner: owner, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } reply.UIVersion = browser.UIVersion - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } core, err := getRemoteInstanceClient(r, getHostFromSrv(sr)) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } if err = core.RemoveBucket(args.BucketName); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } return nil } - ctx := context.Background() - deleteBucket := objectAPI.DeleteBucket if web.CacheAPI() != nil { deleteBucket = web.CacheAPI().DeleteBucket } if err := deleteBucket(ctx, args.BucketName); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } globalNotificationSys.RemoveNotification(args.BucketName) @@ -270,7 +294,7 @@ func (web *webAPIHandlers) DeleteBucket(r *http.Request, args *RemoveBucketArgs, if err := globalDNSConfig.Delete(args.BucketName); err != nil { // Deleting DNS entry failed, attempt to create the bucket again. objectAPI.MakeBucketWithLocation(ctx, args.BucketName, "") - return toJSONError(err) + return toJSONError(ctx, err) } } @@ -293,9 +317,10 @@ type WebBucketInfo struct { // ListBuckets - list buckets api. func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, reply *ListBucketsRep) error { + ctx := newWebContext(r, "webListBuckets") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } listBuckets := objectAPI.ListBuckets if web.CacheAPI() != nil { @@ -304,7 +329,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // Set prefix value for "s3:prefix" policy conditionals. @@ -317,7 +342,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re if globalDNSConfig != nil { dnsBuckets, err := globalDNSConfig.List() if err != nil && err != dns.ErrNoEntriesFound { - return toJSONError(err) + return toJSONError(ctx, err) } bucketSet := set.NewStringSet() for _, dnsRecord := range dnsBuckets { @@ -342,9 +367,9 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re } } } else { - buckets, err := listBuckets(context.Background()) + buckets, err := listBuckets(ctx) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } for _, bucket := range buckets { if globalIAMSys.IsAllowed(iampolicy.Args{ @@ -397,10 +422,11 @@ type WebObjectInfo struct { // ListObjects - list objects api. func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, reply *ListObjectsRep) error { + ctx := newWebContext(r, "webListObjects") reply.UIVersion = browser.UIVersion objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } listObjects := objectAPI.ListObjects @@ -408,23 +434,23 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r listObjects = web.CacheAPI().ListObjects } - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } core, err := getRemoteInstanceClient(r, getHostFromSrv(sr)) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } result, err := core.ListObjects(args.BucketName, args.Prefix, args.Marker, slashSeparator, 1000) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } reply.NextMarker = result.NextMarker reply.IsTruncated = result.IsTruncated @@ -480,7 +506,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r return nil } } else { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } } @@ -522,10 +548,10 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } - lo, err := listObjects(context.Background(), args.BucketName, args.Prefix, args.Marker, slashSeparator, 1000) + lo, err := listObjects(ctx, args.BucketName, args.Prefix, args.Marker, slashSeparator, 1000) if err != nil { return &json2.Error{Message: err.Error()} } @@ -533,7 +559,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r if crypto.IsEncrypted(lo.Objects[i].UserDefined) { lo.Objects[i].Size, err = lo.Objects[i].DecryptedSize() if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } } } @@ -573,9 +599,10 @@ type RemoveObjectArgs struct { // RemoveObject - removes an object, or all the objects at a given prefix. func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs, reply *WebGenericRep) error { + ctx := newWebContext(r, "webRemoveObject") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } listObjects := objectAPI.ListObjects if web.CacheAPI() != nil { @@ -594,37 +621,37 @@ func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs, IsOwner: false, ObjectName: object, }) { - return toJSONError(errAuthentication) + return toJSONError(ctx, errAuthentication) } } } else { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } } if args.BucketName == "" || len(args.Objects) == 0 { - return toJSONError(errInvalidArgument) + return toJSONError(ctx, errInvalidArgument) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } reply.UIVersion = browser.UIVersion - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } core, err := getRemoteInstanceClient(r, getHostFromSrv(sr)) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } objectsCh := make(chan string) @@ -639,7 +666,7 @@ func (web *webAPIHandlers) RemoveObject(r *http.Request, args *RemoveObjectArgs, for resp := range core.RemoveObjects(args.BucketName, objectsCh) { if resp.Err != nil { - return toJSONError(resp.Err, args.BucketName, resp.ObjectName) + return toJSONError(ctx, resp.Err, args.BucketName, resp.ObjectName) } } return nil @@ -652,8 +679,8 @@ next: if !hasSuffix(objectName, slashSeparator) && objectName != "" { // Deny if WORM is enabled if globalWORMEnabled { - if _, err = objectAPI.GetObjectInfo(context.Background(), args.BucketName, objectName, ObjectOptions{}); err == nil { - return toJSONError(errMethodNotAllowed) + if _, err = objectAPI.GetObjectInfo(ctx, args.BucketName, objectName, ObjectOptions{}); err == nil { + return toJSONError(ctx, errMethodNotAllowed) } } // Check for permissions only in the case of @@ -668,11 +695,11 @@ next: IsOwner: owner, ObjectName: objectName, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } } - if err = deleteObject(context.Background(), objectAPI, web.CacheAPI(), args.BucketName, objectName, r); err != nil { + if err = deleteObject(ctx, objectAPI, web.CacheAPI(), args.BucketName, objectName, r); err != nil { break next } continue @@ -686,20 +713,20 @@ next: IsOwner: owner, ObjectName: objectName, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // For directories, list the contents recursively and remove. marker := "" for { var lo ListObjectsInfo - lo, err = listObjects(context.Background(), args.BucketName, objectName, marker, "", 1000) + lo, err = listObjects(ctx, args.BucketName, objectName, marker, "", 1000) if err != nil { break next } marker = lo.NextMarker for _, obj := range lo.Objects { - err = deleteObject(context.Background(), objectAPI, web.CacheAPI(), args.BucketName, obj.Name, r) + err = deleteObject(ctx, objectAPI, web.CacheAPI(), args.BucketName, obj.Name, r) if err != nil { break next } @@ -712,7 +739,7 @@ next: if err != nil && !isErrObjectNotFound(err) { // Ignore object not found error. - return toJSONError(err, args.BucketName, "") + return toJSONError(ctx, err, args.BucketName, "") } return nil @@ -732,9 +759,10 @@ type LoginRep struct { // Login - user login handler. func (web *webAPIHandlers) Login(r *http.Request, args *LoginArgs, reply *LoginRep) error { + ctx := newWebContext(r, "webLogin") token, err := authenticateWeb(args.Username, args.Password) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } reply.Token = token @@ -750,16 +778,17 @@ type GenerateAuthReply struct { } func (web webAPIHandlers) GenerateAuth(r *http.Request, args *WebGenericArgs, reply *GenerateAuthReply) error { + ctx := newWebContext(r, "webGenerateAuth") _, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } if !owner { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } cred, err := auth.GetNewCredentials() if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } reply.AccessKey = cred.AccessKey reply.SecretKey = cred.SecretKey @@ -784,19 +813,20 @@ type SetAuthReply struct { // SetAuth - Set accessKey and secretKey credentials. func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *SetAuthReply) error { + ctx := newWebContext(r, "webSetAuth") claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // When WORM is enabled, disallow changing credenatials for owner and user if globalWORMEnabled { - return toJSONError(errChangeCredNotAllowed) + return toJSONError(ctx, errChangeCredNotAllowed) } if owner { if globalIsEnvCreds || globalEtcdClient != nil { - return toJSONError(errChangeCredNotAllowed) + return toJSONError(ctx, errChangeCredNotAllowed) } // get Current creds and verify @@ -807,7 +837,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se creds, err := auth.CreateCredentials(args.NewAccessKey, args.NewSecretKey) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } // Acquire lock before updating global configuration. @@ -818,16 +848,16 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se prevCred = globalServerConfig.SetCredential(creds) // Persist updated credentials. - if err = saveServerConfig(context.Background(), newObjectLayerFn(), globalServerConfig); err != nil { + if err = saveServerConfig(ctx, newObjectLayerFn(), globalServerConfig); err != nil { // Save the current creds when failed to update. globalServerConfig.SetCredential(prevCred) - logger.LogIf(context.Background(), err) - return toJSONError(err) + logger.LogIf(ctx, err) + return toJSONError(ctx, err) } reply.Token, err = authenticateWeb(args.NewAccessKey, args.NewSecretKey) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } } else { // for IAM users, access key cannot be updated @@ -844,7 +874,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se creds, err := auth.CreateCredentials(claims.Subject, args.NewSecretKey) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } err = globalIAMSys.SetUserSecretKey(creds.AccessKey, creds.SecretKey) @@ -854,8 +884,9 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se reply.Token, err = authenticateWeb(creds.AccessKey, creds.SecretKey) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } + } reply.UIVersion = browser.UIVersion @@ -871,9 +902,10 @@ type URLTokenReply struct { // CreateURLToken creates a URL token (short-lived) for GET requests. func (web *webAPIHandlers) CreateURLToken(r *http.Request, args *WebGenericArgs, reply *URLTokenReply) error { + ctx := newWebContext(r, "webCreateURLToken") claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } creds := globalServerConfig.GetCredential() @@ -881,13 +913,13 @@ func (web *webAPIHandlers) CreateURLToken(r *http.Request, args *WebGenericArgs, var ok bool creds, ok = globalIAMSys.GetUser(claims.Subject) if !ok { - return toJSONError(errInvalidAccessKeyID) + return toJSONError(ctx, errInvalidAccessKeyID) } } token, err := authenticateURL(creds.AccessKey, creds.SecretKey) if err != nil { - return toJSONError(err) + return toJSONError(ctx, err) } reply.Token = token @@ -963,7 +995,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { } // Extract incoming metadata if any. - metadata, err := extractMetadata(context.Background(), r) + metadata, err := extractMetadata(ctx, r) if err != nil { writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1041,7 +1073,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { if !hasServerSideEncryptionHeader(r.Header) && web.CacheAPI() != nil { putObject = web.CacheAPI().PutObject } - objInfo, err := putObject(context.Background(), bucket, object, pReader, opts) + objInfo, err := putObject(ctx, bucket, object, pReader, opts) if err != nil { writeWebErrorResponse(w, err) return @@ -1422,7 +1454,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { // date to the response writer. marker := "" for { - lo, err := listObjects(context.Background(), args.BucketName, pathJoin(args.Prefix, object), marker, "", 1000) + lo, err := listObjects(ctx, args.BucketName, pathJoin(args.Prefix, object), marker, "", 1000) if err != nil { return } @@ -1454,14 +1486,15 @@ type GetBucketPolicyRep struct { // GetBucketPolicy - get bucket policy for the requested prefix. func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolicyArgs, reply *GetBucketPolicyRep) error { + ctx := newWebContext(r, "webGetBucketPolicy") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // For authenticated users apply IAM policy. if !globalIAMSys.IsAllowed(iampolicy.Args{ @@ -1471,47 +1504,47 @@ func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolic ConditionValues: getConditionValues(r, "", claims.Subject), IsOwner: owner, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } var policyInfo = &miniogopolicy.BucketAccessPolicy{Version: "2012-10-17"} - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } client, rerr := getRemoteInstanceClient(r, getHostFromSrv(sr)) if rerr != nil { - return toJSONError(rerr, args.BucketName) + return toJSONError(ctx, rerr, args.BucketName) } policyStr, err := client.GetBucketPolicy(args.BucketName) if err != nil { - return toJSONError(rerr, args.BucketName) + return toJSONError(ctx, rerr, args.BucketName) } bucketPolicy, err := policy.ParseConfig(strings.NewReader(policyStr), args.BucketName) if err != nil { - return toJSONError(rerr, args.BucketName) + return toJSONError(ctx, rerr, args.BucketName) } policyInfo, err = PolicyToBucketAccessPolicy(bucketPolicy) if err != nil { // This should not happen. - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } else { - bucketPolicy, err := objectAPI.GetBucketPolicy(context.Background(), args.BucketName) + bucketPolicy, err := objectAPI.GetBucketPolicy(ctx, args.BucketName) if err != nil { if _, ok := err.(BucketPolicyNotFound); !ok { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } return err } @@ -1519,7 +1552,7 @@ func (web *webAPIHandlers) GetBucketPolicy(r *http.Request, args *GetBucketPolic policyInfo, err = PolicyToBucketAccessPolicy(bucketPolicy) if err != nil { // This should not happen. - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } @@ -1549,60 +1582,61 @@ type ListAllBucketPoliciesRep struct { // ListAllBucketPolicies - get all bucket policy. func (web *webAPIHandlers) ListAllBucketPolicies(r *http.Request, args *ListAllBucketPoliciesArgs, reply *ListAllBucketPoliciesRep) error { + ctx := newWebContext(r, "WebListAllBucketPolicies") objectAPI := web.ObjectAPI() if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } _, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } if !owner { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } var policyInfo = new(miniogopolicy.BucketAccessPolicy) - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } core, rerr := getRemoteInstanceClient(r, getHostFromSrv(sr)) if rerr != nil { - return toJSONError(rerr, args.BucketName) + return toJSONError(ctx, rerr, args.BucketName) } var policyStr string policyStr, err = core.Client.GetBucketPolicy(args.BucketName) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } if policyStr != "" { if err = json.Unmarshal([]byte(policyStr), policyInfo); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } } else { - bucketPolicy, err := objectAPI.GetBucketPolicy(context.Background(), args.BucketName) + bucketPolicy, err := objectAPI.GetBucketPolicy(ctx, args.BucketName) if err != nil { if _, ok := err.(BucketPolicyNotFound); !ok { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } policyInfo, err = PolicyToBucketAccessPolicy(bucketPolicy) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } @@ -1629,16 +1663,17 @@ type SetBucketPolicyWebArgs struct { // SetBucketPolicy - set bucket policy. func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolicyWebArgs, reply *WebGenericRep) error { + ctx := newWebContext(r, "webSetBucketPolicy") objectAPI := web.ObjectAPI() reply.UIVersion = browser.UIVersion if objectAPI == nil { - return toJSONError(errServerNotInitialized) + return toJSONError(ctx, errServerNotInitialized) } claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } // For authenticated users apply IAM policy. @@ -1649,12 +1684,12 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic ConditionValues: getConditionValues(r, "", claims.Subject), IsOwner: owner, }) { - return toJSONError(errAccessDenied) + return toJSONError(ctx, errAccessDenied) } // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } policyType := miniogopolicy.BucketPolicy(args.Policy) @@ -1664,40 +1699,38 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic } } - ctx := context.Background() - - if isRemoteCallRequired(context.Background(), args.BucketName, objectAPI) { + if isRemoteCallRequired(ctx, args.BucketName, objectAPI) { sr, err := globalDNSConfig.Get(args.BucketName) if err != nil { if err == dns.ErrNoEntriesFound { - return toJSONError(BucketNotFound{ + return toJSONError(ctx, BucketNotFound{ Bucket: args.BucketName, }, args.BucketName) } - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } core, rerr := getRemoteInstanceClient(r, getHostFromSrv(sr)) if rerr != nil { - return toJSONError(rerr, args.BucketName) + return toJSONError(ctx, rerr, args.BucketName) } var policyStr string // Use the abstracted API instead of core, such that // NoSuchBucketPolicy errors are automatically handled. policyStr, err = core.Client.GetBucketPolicy(args.BucketName) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } var policyInfo = &miniogopolicy.BucketAccessPolicy{Version: "2012-10-17"} if policyStr != "" { if err = json.Unmarshal([]byte(policyStr), policyInfo); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } policyInfo.Statements = miniogopolicy.SetPolicy(policyInfo.Statements, policyType, args.BucketName, args.Prefix) if len(policyInfo.Statements) == 0 { if err = core.SetBucketPolicy(args.BucketName, ""); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } return nil } @@ -1705,35 +1738,35 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic bucketPolicy, err := BucketAccessPolicyToPolicy(policyInfo) if err != nil { // This should not happen. - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } policyData, err := json.Marshal(bucketPolicy) if err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } if err = core.SetBucketPolicy(args.BucketName, string(policyData)); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } else { bucketPolicy, err := objectAPI.GetBucketPolicy(ctx, args.BucketName) if err != nil { if _, ok := err.(BucketPolicyNotFound); !ok { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } } policyInfo, err := PolicyToBucketAccessPolicy(bucketPolicy) if err != nil { // This should not happen. - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } policyInfo.Statements = miniogopolicy.SetPolicy(policyInfo.Statements, policyType, args.BucketName, args.Prefix) if len(policyInfo.Statements) == 0 { if err = objectAPI.DeleteBucketPolicy(ctx, args.BucketName); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } globalPolicySys.Remove(args.BucketName) @@ -1743,12 +1776,12 @@ func (web *webAPIHandlers) SetBucketPolicy(r *http.Request, args *SetBucketPolic bucketPolicy, err = BucketAccessPolicyToPolicy(policyInfo) if err != nil { // This should not happen. - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } // Parse validate and save bucket policy. if err := objectAPI.SetBucketPolicy(ctx, args.BucketName, bucketPolicy); err != nil { - return toJSONError(err, args.BucketName) + return toJSONError(ctx, err, args.BucketName) } globalPolicySys.Set(args.BucketName, *bucketPolicy) @@ -1782,16 +1815,17 @@ type PresignedGetRep struct { // PresignedGET - returns presigned-Get url. func (web *webAPIHandlers) PresignedGet(r *http.Request, args *PresignedGetArgs, reply *PresignedGetRep) error { + ctx := newWebContext(r, "webPresignedGet") claims, owner, authErr := webRequestAuthenticate(r) if authErr != nil { - return toJSONError(authErr) + return toJSONError(ctx, authErr) } var creds auth.Credentials if !owner { var ok bool creds, ok = globalIAMSys.GetUser(claims.Subject) if !ok { - return toJSONError(errInvalidAccessKeyID) + return toJSONError(ctx, errInvalidAccessKeyID) } } else { creds = globalServerConfig.GetCredential() @@ -1806,7 +1840,7 @@ func (web *webAPIHandlers) PresignedGet(r *http.Request, args *PresignedGetArgs, // Check if bucket is a reserved bucket name or invalid. if isReservedOrInvalidBucket(args.BucketName, false) { - return toJSONError(errInvalidBucketName) + return toJSONError(ctx, errInvalidBucketName) } reply.UIVersion = browser.UIVersion @@ -1852,8 +1886,8 @@ func presignedGet(host, bucket, object string, expiry int64, creds auth.Credenti // toJSONError converts regular errors into more user friendly // and consumable error message for the browser UI. -func toJSONError(err error, params ...string) (jerr *json2.Error) { - apiErr := toWebAPIError(err) +func toJSONError(ctx context.Context, err error, params ...string) (jerr *json2.Error) { + apiErr := toWebAPIError(ctx, err) jerr = &json2.Error{ Message: apiErr.Description, } @@ -1892,7 +1926,7 @@ func toJSONError(err error, params ...string) (jerr *json2.Error) { } // toWebAPIError - convert into error into APIError. -func toWebAPIError(err error) APIError { +func toWebAPIError(ctx context.Context, err error) APIError { switch err { case errServerNotInitialized: return APIError{ @@ -1973,7 +2007,7 @@ func toWebAPIError(err error) APIError { } // Log unexpected and unhandled errors. - logger.LogIf(context.Background(), err) + logger.LogIf(ctx, err) return APIError{ Code: "InternalError", HTTPStatusCode: http.StatusInternalServerError, @@ -1983,7 +2017,11 @@ func toWebAPIError(err error) APIError { // writeWebErrorResponse - set HTTP status code and write error description to the body. func writeWebErrorResponse(w http.ResponseWriter, err error) { - apiErr := toWebAPIError(err) + reqInfo := &logger.ReqInfo{ + DeploymentID: globalDeploymentID, + } + ctx := logger.SetReqInfo(context.Background(), reqInfo) + apiErr := toWebAPIError(ctx, err) w.WriteHeader(apiErr.HTTPStatusCode) w.Write([]byte(apiErr.Description)) }