storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/admin-bucket-handlers.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2020 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"encoding/json"
    21  	"io"
    22  	"io/ioutil"
    23  	"net/http"
    24  
    25  	"github.com/gorilla/mux"
    26  
    27  	"storj.io/minio/cmd/logger"
    28  	iampolicy "storj.io/minio/pkg/iam/policy"
    29  	"storj.io/minio/pkg/madmin"
    30  )
    31  
    32  const (
    33  	bucketQuotaConfigFile = "quota.json"
    34  	bucketTargetsFile     = "bucket-targets.json"
    35  )
    36  
    37  // PutBucketQuotaConfigHandler - PUT Bucket quota configuration.
    38  // ----------
    39  // Places a quota configuration on the specified bucket. The quota
    40  // specified in the quota configuration will be applied by default
    41  // to enforce total quota for the specified bucket.
    42  func (a adminAPIHandlers) PutBucketQuotaConfigHandler(w http.ResponseWriter, r *http.Request) {
    43  	ctx := NewContext(r, w, "PutBucketQuotaConfig")
    44  
    45  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
    46  
    47  	objectAPI, _ := validateAdminReq(ctx, w, r, iampolicy.SetBucketQuotaAdminAction)
    48  	if objectAPI == nil {
    49  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
    50  		return
    51  	}
    52  
    53  	vars := mux.Vars(r)
    54  	bucket := pathClean(vars["bucket"])
    55  
    56  	if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil {
    57  		writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
    58  		return
    59  	}
    60  
    61  	data, err := ioutil.ReadAll(r.Body)
    62  	if err != nil {
    63  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
    64  		return
    65  	}
    66  
    67  	if _, err = parseBucketQuota(bucket, data); err != nil {
    68  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
    69  		return
    70  	}
    71  
    72  	if err = globalBucketMetadataSys.Update(bucket, bucketQuotaConfigFile, data); err != nil {
    73  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
    74  		return
    75  	}
    76  
    77  	// Write success response.
    78  	writeSuccessResponseHeadersOnly(w)
    79  }
    80  
    81  // GetBucketQuotaConfigHandler - gets bucket quota configuration
    82  func (a adminAPIHandlers) GetBucketQuotaConfigHandler(w http.ResponseWriter, r *http.Request) {
    83  	ctx := NewContext(r, w, "GetBucketQuotaConfig")
    84  
    85  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
    86  
    87  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.GetBucketQuotaAdminAction)
    88  	if objectAPI == nil {
    89  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
    90  		return
    91  	}
    92  
    93  	vars := mux.Vars(r)
    94  	bucket := pathClean(vars["bucket"])
    95  
    96  	if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil {
    97  		writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
    98  		return
    99  	}
   100  
   101  	config, err := globalBucketMetadataSys.GetQuotaConfig(bucket)
   102  	if err != nil {
   103  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   104  		return
   105  	}
   106  
   107  	configData, err := json.Marshal(config)
   108  	if err != nil {
   109  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   110  		return
   111  	}
   112  
   113  	// Write success response.
   114  	writeSuccessResponseJSON(w, configData)
   115  }
   116  
   117  // SetRemoteTargetHandler - sets a remote target for bucket
   118  func (a adminAPIHandlers) SetRemoteTargetHandler(w http.ResponseWriter, r *http.Request) {
   119  	ctx := NewContext(r, w, "SetBucketTarget")
   120  
   121  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   122  	vars := mux.Vars(r)
   123  	bucket := pathClean(vars["bucket"])
   124  	update := r.URL.Query().Get("update") == "true"
   125  
   126  	if !globalIsErasure {
   127  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
   128  		return
   129  	}
   130  
   131  	// Get current object layer instance.
   132  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.SetBucketTargetAction)
   133  	if objectAPI == nil {
   134  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   135  		return
   136  	}
   137  
   138  	// Check if bucket exists.
   139  	if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil {
   140  		writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
   141  		return
   142  	}
   143  
   144  	cred, _, _, s3Err := validateAdminSignature(ctx, r, "")
   145  	if s3Err != ErrNone {
   146  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
   147  		return
   148  	}
   149  	password := cred.SecretKey
   150  
   151  	reqBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength))
   152  	if err != nil {
   153  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   154  		return
   155  	}
   156  	var target madmin.BucketTarget
   157  	if err = json.Unmarshal(reqBytes, &target); err != nil {
   158  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   159  		return
   160  	}
   161  	sameTarget, _ := isLocalHost(target.URL().Hostname(), target.URL().Port(), globalMinioPort)
   162  	if sameTarget && bucket == target.TargetBucket {
   163  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrBucketRemoteIdenticalToSource), r.URL)
   164  		return
   165  	}
   166  
   167  	target.SourceBucket = bucket
   168  	if !update {
   169  		target.Arn = globalBucketTargetSys.getRemoteARN(bucket, &target)
   170  	}
   171  	if target.Arn == "" {
   172  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   173  		return
   174  	}
   175  
   176  	if err = globalBucketTargetSys.SetTarget(ctx, bucket, &target, update); err != nil {
   177  		switch err.(type) {
   178  		case BucketRemoteConnectionErr:
   179  			writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrReplicationRemoteConnectionError, err), r.URL)
   180  		default:
   181  			writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
   182  		}
   183  		return
   184  	}
   185  	targets, err := globalBucketTargetSys.ListBucketTargets(ctx, bucket)
   186  	if err != nil {
   187  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   188  		return
   189  	}
   190  	tgtBytes, err := json.Marshal(&targets)
   191  	if err != nil {
   192  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   193  		return
   194  	}
   195  	if err = globalBucketMetadataSys.Update(bucket, bucketTargetsFile, tgtBytes); err != nil {
   196  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   197  		return
   198  	}
   199  
   200  	data, err := json.Marshal(target.Arn)
   201  	if err != nil {
   202  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   203  		return
   204  	}
   205  	// Write success response.
   206  	writeSuccessResponseJSON(w, data)
   207  }
   208  
   209  // ListRemoteTargetsHandler - lists remote target(s) for a bucket or gets a target
   210  // for a particular ARN type
   211  func (a adminAPIHandlers) ListRemoteTargetsHandler(w http.ResponseWriter, r *http.Request) {
   212  	ctx := NewContext(r, w, "ListBucketTargets")
   213  
   214  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   215  	vars := mux.Vars(r)
   216  	bucket := pathClean(vars["bucket"])
   217  	arnType := vars["type"]
   218  	if !globalIsErasure {
   219  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
   220  		return
   221  	}
   222  	// Get current object layer instance.
   223  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.GetBucketTargetAction)
   224  	if objectAPI == nil {
   225  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   226  		return
   227  	}
   228  	if bucket != "" {
   229  		// Check if bucket exists.
   230  		if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil {
   231  			writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
   232  			return
   233  		}
   234  		if _, err := globalBucketMetadataSys.GetBucketTargetsConfig(bucket); err != nil {
   235  			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   236  			return
   237  		}
   238  	}
   239  	targets := globalBucketTargetSys.ListTargets(ctx, bucket, arnType)
   240  	data, err := json.Marshal(targets)
   241  	if err != nil {
   242  		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
   243  		return
   244  	}
   245  	// Write success response.
   246  	writeSuccessResponseJSON(w, data)
   247  }
   248  
   249  // RemoveRemoteTargetHandler - removes a remote target for bucket with specified ARN
   250  func (a adminAPIHandlers) RemoveRemoteTargetHandler(w http.ResponseWriter, r *http.Request) {
   251  	ctx := NewContext(r, w, "RemoveBucketTarget")
   252  
   253  	defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
   254  	vars := mux.Vars(r)
   255  	bucket := pathClean(vars["bucket"])
   256  	arn := vars["arn"]
   257  
   258  	if !globalIsErasure {
   259  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL)
   260  		return
   261  	}
   262  	// Get current object layer instance.
   263  	objectAPI, _ := validateAdminUsersReq(ctx, w, r, iampolicy.SetBucketTargetAction)
   264  	if objectAPI == nil {
   265  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
   266  		return
   267  	}
   268  
   269  	// Check if bucket exists.
   270  	if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil {
   271  		writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
   272  		return
   273  	}
   274  
   275  	if err := globalBucketTargetSys.RemoveTarget(ctx, bucket, arn); err != nil {
   276  		writeErrorResponseJSON(ctx, w, ToAPIError(ctx, err), r.URL)
   277  		return
   278  	}
   279  	targets, err := globalBucketTargetSys.ListBucketTargets(ctx, bucket)
   280  	if err != nil {
   281  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   282  		return
   283  	}
   284  	tgtBytes, err := json.Marshal(&targets)
   285  	if err != nil {
   286  		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErrWithErr(ErrAdminConfigBadJSON, err), r.URL)
   287  		return
   288  	}
   289  	if err = globalBucketMetadataSys.Update(bucket, bucketTargetsFile, tgtBytes); err != nil {
   290  		WriteErrorResponse(ctx, w, ToAPIError(ctx, err), r.URL, guessIsBrowserReq(r))
   291  		return
   292  	}
   293  
   294  	// Write success response.
   295  	writeSuccessNoContent(w)
   296  }