mirror of https://github.com/minio/minio.git
615 lines
18 KiB
Go
615 lines
18 KiB
Go
// Copyright (c) 2015-2021 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 (
|
|
"io"
|
|
"math"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/minio/madmin-go/v3"
|
|
"github.com/minio/minio/internal/bucket/replication"
|
|
"github.com/minio/minio/internal/hash"
|
|
"github.com/minio/minio/internal/logger"
|
|
)
|
|
|
|
// BackendType - represents different backend types.
|
|
type BackendType int
|
|
|
|
// Enum for different backend types.
|
|
const (
|
|
Unknown = BackendType(madmin.Unknown)
|
|
// Filesystem backend.
|
|
BackendFS = BackendType(madmin.FS)
|
|
// Multi disk BackendErasure (single, distributed) backend.
|
|
BackendErasure = BackendType(madmin.Erasure)
|
|
// Add your own backend.
|
|
)
|
|
|
|
// StorageInfo - represents total capacity of underlying storage.
|
|
type StorageInfo = madmin.StorageInfo
|
|
|
|
// objectHistogramInterval is an interval that will be
|
|
// used to report the histogram of objects data sizes
|
|
type objectHistogramInterval struct {
|
|
name string
|
|
start, end int64
|
|
}
|
|
|
|
const (
|
|
// dataUsageBucketLen must be length of ObjectsHistogramIntervals
|
|
dataUsageBucketLen = 7
|
|
dataUsageVersionLen = 7
|
|
)
|
|
|
|
// ObjectsHistogramIntervals is the list of all intervals
|
|
// of object sizes to be included in objects histogram.
|
|
var ObjectsHistogramIntervals = [dataUsageBucketLen]objectHistogramInterval{
|
|
{"LESS_THAN_1024_B", 0, humanize.KiByte - 1},
|
|
{"BETWEEN_1024_B_AND_1_MB", humanize.KiByte, humanize.MiByte - 1},
|
|
{"BETWEEN_1_MB_AND_10_MB", humanize.MiByte, humanize.MiByte*10 - 1},
|
|
{"BETWEEN_10_MB_AND_64_MB", humanize.MiByte * 10, humanize.MiByte*64 - 1},
|
|
{"BETWEEN_64_MB_AND_128_MB", humanize.MiByte * 64, humanize.MiByte*128 - 1},
|
|
{"BETWEEN_128_MB_AND_512_MB", humanize.MiByte * 128, humanize.MiByte*512 - 1},
|
|
{"GREATER_THAN_512_MB", humanize.MiByte * 512, math.MaxInt64},
|
|
}
|
|
|
|
// ObjectsVersionCountIntervals is the list of all intervals
|
|
// of object version count to be included in objects histogram.
|
|
var ObjectsVersionCountIntervals = [dataUsageVersionLen]objectHistogramInterval{
|
|
{"UNVERSIONED", 0, 0},
|
|
{"SINGLE_VERSION", 1, 1},
|
|
{"BETWEEN_2_AND_10", 2, 9},
|
|
{"BETWEEN_10_AND_100", 10, 99},
|
|
{"BETWEEN_100_AND_1000", 100, 999},
|
|
{"BETWEEN_1000_AND_10000", 1000, 9999},
|
|
{"GREATER_THAN_10000", 10000, math.MaxInt64},
|
|
}
|
|
|
|
// BucketInfo - represents bucket metadata.
|
|
type BucketInfo struct {
|
|
// Name of the bucket.
|
|
Name string
|
|
|
|
// Date and time when the bucket was created.
|
|
Created time.Time
|
|
Deleted time.Time
|
|
|
|
// Bucket features enabled
|
|
Versioning, ObjectLocking bool
|
|
}
|
|
|
|
// ObjectInfo - represents object metadata.
|
|
type ObjectInfo struct {
|
|
// Name of the bucket.
|
|
Bucket string
|
|
|
|
// Name of the object.
|
|
Name string
|
|
|
|
// Date and time when the object was last modified.
|
|
ModTime time.Time
|
|
|
|
// Total object size.
|
|
Size int64
|
|
|
|
// Actual size is the real size of the object uploaded by client.
|
|
ActualSize *int64
|
|
|
|
// IsDir indicates if the object is prefix.
|
|
IsDir bool
|
|
|
|
// Hex encoded unique entity tag of the object.
|
|
ETag string
|
|
|
|
// Version ID of this object.
|
|
VersionID string
|
|
|
|
// IsLatest indicates if this is the latest current version
|
|
// latest can be true for delete marker or a version.
|
|
IsLatest bool
|
|
|
|
// DeleteMarker indicates if the versionId corresponds
|
|
// to a delete marker on an object.
|
|
DeleteMarker bool
|
|
|
|
// Transitioned object information
|
|
TransitionedObject TransitionedObject
|
|
|
|
// RestoreExpires indicates date a restored object expires
|
|
RestoreExpires time.Time
|
|
|
|
// RestoreOngoing indicates if a restore is in progress
|
|
RestoreOngoing bool
|
|
|
|
// A standard MIME type describing the format of the object.
|
|
ContentType string
|
|
|
|
// Specifies what content encodings have been applied to the object and thus
|
|
// what decoding mechanisms must be applied to obtain the object referenced
|
|
// by the Content-Type header field.
|
|
ContentEncoding string
|
|
|
|
// Date and time at which the object is no longer able to be cached
|
|
Expires time.Time
|
|
|
|
// Cache-Control - Specifies caching behavior along the request/reply chain
|
|
CacheControl string
|
|
|
|
// Specify object storage class
|
|
StorageClass string
|
|
|
|
ReplicationStatusInternal string
|
|
ReplicationStatus replication.StatusType
|
|
// User-Defined metadata
|
|
UserDefined map[string]string
|
|
|
|
// User-Defined object tags
|
|
UserTags string
|
|
|
|
// List of individual parts, maximum size of upto 10,000
|
|
Parts []ObjectPartInfo `json:"-"`
|
|
|
|
// Implements writer and reader used by CopyObject API
|
|
Writer io.WriteCloser `json:"-"`
|
|
Reader *hash.Reader `json:"-"`
|
|
PutObjReader *PutObjReader `json:"-"`
|
|
|
|
metadataOnly bool
|
|
versionOnly bool // adds a new version, only used by CopyObject
|
|
keyRotation bool
|
|
|
|
// Date and time when the object was last accessed.
|
|
AccTime time.Time
|
|
|
|
Legacy bool // indicates object on disk is in legacy data format
|
|
|
|
// backendType indicates which backend filled this structure
|
|
backendType BackendType
|
|
// internal representation of version purge status
|
|
VersionPurgeStatusInternal string
|
|
VersionPurgeStatus VersionPurgeStatusType
|
|
|
|
replicationDecision string // internal representation of replication decision for use by DeleteObject handler
|
|
// The total count of all versions of this object
|
|
NumVersions int
|
|
// The modtime of the successor object version if any
|
|
SuccessorModTime time.Time
|
|
|
|
// Checksums added on upload.
|
|
// Encoded, maybe encrypted.
|
|
Checksum []byte
|
|
|
|
// Inlined
|
|
Inlined bool
|
|
|
|
DataBlocks int
|
|
ParityBlocks int
|
|
}
|
|
|
|
// ExpiresStr returns a stringified version of Expires header in http.TimeFormat
|
|
func (o ObjectInfo) ExpiresStr() string {
|
|
var expires string
|
|
if !o.Expires.IsZero() {
|
|
expires = o.Expires.UTC().Format(http.TimeFormat)
|
|
}
|
|
return expires
|
|
}
|
|
|
|
// ArchiveInfo returns any saved zip archive meta information.
|
|
// It will be decrypted if needed.
|
|
func (o *ObjectInfo) ArchiveInfo() []byte {
|
|
if len(o.UserDefined) == 0 {
|
|
return nil
|
|
}
|
|
z, ok := o.UserDefined[archiveInfoMetadataKey]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
data := []byte(z)
|
|
if v, ok := o.UserDefined[archiveTypeMetadataKey]; ok && v == archiveTypeEnc {
|
|
decrypted, err := o.metadataDecrypter()(archiveTypeEnc, data)
|
|
if err != nil {
|
|
logger.LogIf(GlobalContext, err)
|
|
return nil
|
|
}
|
|
data = decrypted
|
|
}
|
|
return data
|
|
}
|
|
|
|
// Clone - Returns a cloned copy of current objectInfo
|
|
func (o *ObjectInfo) Clone() (cinfo ObjectInfo) {
|
|
cinfo = ObjectInfo{
|
|
Bucket: o.Bucket,
|
|
Name: o.Name,
|
|
ModTime: o.ModTime,
|
|
Size: o.Size,
|
|
IsDir: o.IsDir,
|
|
ETag: o.ETag,
|
|
VersionID: o.VersionID,
|
|
IsLatest: o.IsLatest,
|
|
DeleteMarker: o.DeleteMarker,
|
|
TransitionedObject: o.TransitionedObject,
|
|
RestoreExpires: o.RestoreExpires,
|
|
RestoreOngoing: o.RestoreOngoing,
|
|
ContentType: o.ContentType,
|
|
ContentEncoding: o.ContentEncoding,
|
|
Expires: o.Expires,
|
|
StorageClass: o.StorageClass,
|
|
ReplicationStatus: o.ReplicationStatus,
|
|
UserTags: o.UserTags,
|
|
Parts: o.Parts,
|
|
Writer: o.Writer,
|
|
Reader: o.Reader,
|
|
PutObjReader: o.PutObjReader,
|
|
metadataOnly: o.metadataOnly,
|
|
versionOnly: o.versionOnly,
|
|
keyRotation: o.keyRotation,
|
|
backendType: o.backendType,
|
|
AccTime: o.AccTime,
|
|
Legacy: o.Legacy,
|
|
VersionPurgeStatus: o.VersionPurgeStatus,
|
|
NumVersions: o.NumVersions,
|
|
SuccessorModTime: o.SuccessorModTime,
|
|
ReplicationStatusInternal: o.ReplicationStatusInternal,
|
|
VersionPurgeStatusInternal: o.VersionPurgeStatusInternal,
|
|
}
|
|
cinfo.UserDefined = make(map[string]string, len(o.UserDefined))
|
|
for k, v := range o.UserDefined {
|
|
cinfo.UserDefined[k] = v
|
|
}
|
|
return cinfo
|
|
}
|
|
|
|
func (o ObjectInfo) tierStats() tierStats {
|
|
ts := tierStats{
|
|
TotalSize: uint64(o.Size),
|
|
NumVersions: 1,
|
|
}
|
|
// the current version of an object is accounted towards objects count
|
|
if o.IsLatest {
|
|
ts.NumObjects = 1
|
|
}
|
|
return ts
|
|
}
|
|
|
|
// ToObjectInfo converts a replication object info to a partial ObjectInfo
|
|
// do not rely on this function to give you correct ObjectInfo, this
|
|
// function is merely and optimization.
|
|
func (ri ReplicateObjectInfo) ToObjectInfo() ObjectInfo {
|
|
return ObjectInfo{
|
|
Name: ri.Name,
|
|
Bucket: ri.Bucket,
|
|
VersionID: ri.VersionID,
|
|
ModTime: ri.ModTime,
|
|
UserTags: ri.UserTags,
|
|
Size: ri.Size,
|
|
ActualSize: &ri.ActualSize,
|
|
ReplicationStatus: ri.ReplicationStatus,
|
|
ReplicationStatusInternal: ri.ReplicationStatusInternal,
|
|
VersionPurgeStatus: ri.VersionPurgeStatus,
|
|
VersionPurgeStatusInternal: ri.VersionPurgeStatusInternal,
|
|
DeleteMarker: true,
|
|
UserDefined: map[string]string{},
|
|
}
|
|
}
|
|
|
|
// ReplicateObjectInfo represents object info to be replicated
|
|
type ReplicateObjectInfo struct {
|
|
Name string
|
|
Bucket string
|
|
VersionID string
|
|
ETag string
|
|
Size int64
|
|
ActualSize int64
|
|
ModTime time.Time
|
|
UserTags string
|
|
SSEC bool
|
|
ReplicationStatus replication.StatusType
|
|
ReplicationStatusInternal string
|
|
VersionPurgeStatusInternal string
|
|
VersionPurgeStatus VersionPurgeStatusType
|
|
ReplicationState ReplicationState
|
|
DeleteMarker bool
|
|
|
|
OpType replication.Type
|
|
EventType string
|
|
RetryCount uint32
|
|
ResetID string
|
|
Dsc ReplicateDecision
|
|
ExistingObjResync ResyncDecision
|
|
TargetArn string
|
|
TargetStatuses map[string]replication.StatusType
|
|
TargetPurgeStatuses map[string]VersionPurgeStatusType
|
|
ReplicationTimestamp time.Time
|
|
}
|
|
|
|
// MultipartInfo captures metadata information about the uploadId
|
|
// this data structure is used primarily for some internal purposes
|
|
// for verifying upload type such as was the upload
|
|
// - encrypted
|
|
// - compressed
|
|
type MultipartInfo struct {
|
|
// Name of the bucket.
|
|
Bucket string
|
|
|
|
// Name of the object.
|
|
Object string
|
|
|
|
// Upload ID identifying the multipart upload whose parts are being listed.
|
|
UploadID string
|
|
|
|
// Date and time at which the multipart upload was initiated.
|
|
Initiated time.Time
|
|
|
|
// Any metadata set during InitMultipartUpload, including encryption headers.
|
|
UserDefined map[string]string
|
|
}
|
|
|
|
// ListPartsInfo - represents list of all parts.
|
|
type ListPartsInfo struct {
|
|
// Name of the bucket.
|
|
Bucket string
|
|
|
|
// Name of the object.
|
|
Object string
|
|
|
|
// Upload ID identifying the multipart upload whose parts are being listed.
|
|
UploadID string
|
|
|
|
// The class of storage used to store the object.
|
|
StorageClass string
|
|
|
|
// Part number after which listing begins.
|
|
PartNumberMarker int
|
|
|
|
// When a list is truncated, this element specifies the last part in the list,
|
|
// as well as the value to use for the part-number-marker request parameter
|
|
// in a subsequent request.
|
|
NextPartNumberMarker int
|
|
|
|
// Maximum number of parts that were allowed in the response.
|
|
MaxParts int
|
|
|
|
// Indicates whether the returned list of parts is truncated.
|
|
IsTruncated bool
|
|
|
|
// List of all parts.
|
|
Parts []PartInfo
|
|
|
|
// Any metadata set during InitMultipartUpload, including encryption headers.
|
|
UserDefined map[string]string
|
|
|
|
// ChecksumAlgorithm if set
|
|
ChecksumAlgorithm string
|
|
}
|
|
|
|
// Lookup - returns if uploadID is valid
|
|
func (lm ListMultipartsInfo) Lookup(uploadID string) bool {
|
|
for _, upload := range lm.Uploads {
|
|
if upload.UploadID == uploadID {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ListMultipartsInfo - represnets bucket resources for incomplete multipart uploads.
|
|
type ListMultipartsInfo struct {
|
|
// Together with upload-id-marker, this parameter specifies the multipart upload
|
|
// after which listing should begin.
|
|
KeyMarker string
|
|
|
|
// Together with key-marker, specifies the multipart upload after which listing
|
|
// should begin. If key-marker is not specified, the upload-id-marker parameter
|
|
// is ignored.
|
|
UploadIDMarker string
|
|
|
|
// When a list is truncated, this element specifies the value that should be
|
|
// used for the key-marker request parameter in a subsequent request.
|
|
NextKeyMarker string
|
|
|
|
// When a list is truncated, this element specifies the value that should be
|
|
// used for the upload-id-marker request parameter in a subsequent request.
|
|
NextUploadIDMarker string
|
|
|
|
// Maximum number of multipart uploads that could have been included in the
|
|
// response.
|
|
MaxUploads int
|
|
|
|
// Indicates whether the returned list of multipart uploads is truncated. A
|
|
// value of true indicates that the list was truncated. The list can be truncated
|
|
// if the number of multipart uploads exceeds the limit allowed or specified
|
|
// by max uploads.
|
|
IsTruncated bool
|
|
|
|
// List of all pending uploads.
|
|
Uploads []MultipartInfo
|
|
|
|
// When a prefix is provided in the request, The result contains only keys
|
|
// starting with the specified prefix.
|
|
Prefix string
|
|
|
|
// A character used to truncate the object prefixes.
|
|
// NOTE: only supported delimiter is '/'.
|
|
Delimiter string
|
|
|
|
// CommonPrefixes contains all (if there are any) keys between Prefix and the
|
|
// next occurrence of the string specified by delimiter.
|
|
CommonPrefixes []string
|
|
|
|
EncodingType string // Not supported yet.
|
|
}
|
|
|
|
// TransitionedObject transitioned object tier and status.
|
|
type TransitionedObject struct {
|
|
Name string
|
|
VersionID string
|
|
Tier string
|
|
FreeVersion bool
|
|
Status string
|
|
}
|
|
|
|
// DeletedObjectInfo - container for list objects versions deleted objects.
|
|
type DeletedObjectInfo struct {
|
|
// Name of the bucket.
|
|
Bucket string
|
|
|
|
// Name of the object.
|
|
Name string
|
|
|
|
// Date and time when the object was last modified.
|
|
ModTime time.Time
|
|
|
|
// Version ID of this object.
|
|
VersionID string
|
|
|
|
// Indicates the deleted marker is latest
|
|
IsLatest bool
|
|
}
|
|
|
|
// ListObjectVersionsInfo - container for list objects versions.
|
|
type ListObjectVersionsInfo struct {
|
|
// Indicates whether the returned list objects response is truncated. A
|
|
// value of true indicates that the list was truncated. The list can be truncated
|
|
// if the number of objects exceeds the limit allowed or specified
|
|
// by max keys.
|
|
IsTruncated bool
|
|
|
|
// When response is truncated (the IsTruncated element value in the response is true),
|
|
// you can use the key name in this field as marker in the subsequent
|
|
// request to get next set of objects.
|
|
//
|
|
// NOTE: AWS S3 returns NextMarker only if you have delimiter request parameter specified,
|
|
// MinIO always returns NextMarker.
|
|
NextMarker string
|
|
|
|
// NextVersionIDMarker may be set of IsTruncated is true
|
|
NextVersionIDMarker string
|
|
|
|
// List of objects info for this request.
|
|
Objects []ObjectInfo
|
|
|
|
// List of prefixes for this request.
|
|
Prefixes []string
|
|
}
|
|
|
|
// ListObjectsInfo - container for list objects.
|
|
type ListObjectsInfo struct {
|
|
// Indicates whether the returned list objects response is truncated. A
|
|
// value of true indicates that the list was truncated. The list can be truncated
|
|
// if the number of objects exceeds the limit allowed or specified
|
|
// by max keys.
|
|
IsTruncated bool
|
|
|
|
// When response is truncated (the IsTruncated element value in the response is true),
|
|
// you can use the key name in this field as marker in the subsequent
|
|
// request to get next set of objects.
|
|
//
|
|
// NOTE: AWS S3 returns NextMarker only if you have delimiter request parameter specified,
|
|
// MinIO always returns NextMarker.
|
|
NextMarker string
|
|
|
|
// List of objects info for this request.
|
|
Objects []ObjectInfo
|
|
|
|
// List of prefixes for this request.
|
|
Prefixes []string
|
|
}
|
|
|
|
// ListObjectsV2Info - container for list objects version 2.
|
|
type ListObjectsV2Info struct {
|
|
// Indicates whether the returned list objects response is truncated. A
|
|
// value of true indicates that the list was truncated. The list can be truncated
|
|
// if the number of objects exceeds the limit allowed or specified
|
|
// by max keys.
|
|
IsTruncated bool
|
|
|
|
// When response is truncated (the IsTruncated element value in the response
|
|
// is true), you can use the key name in this field as marker in the subsequent
|
|
// request to get next set of objects.
|
|
//
|
|
// NOTE: This element is returned only if you have delimiter request parameter
|
|
// specified.
|
|
ContinuationToken string
|
|
NextContinuationToken string
|
|
|
|
// List of objects info for this request.
|
|
Objects []ObjectInfo
|
|
|
|
// List of prefixes for this request.
|
|
Prefixes []string
|
|
}
|
|
|
|
// PartInfo - represents individual part metadata.
|
|
type PartInfo struct {
|
|
// Part number that identifies the part. This is a positive integer between
|
|
// 1 and 10,000.
|
|
PartNumber int
|
|
|
|
// Date and time at which the part was uploaded.
|
|
LastModified time.Time
|
|
|
|
// Entity tag returned when the part was initially uploaded.
|
|
ETag string
|
|
|
|
// Size in bytes of the part.
|
|
Size int64
|
|
|
|
// Real size of the object uploaded by client.
|
|
ActualSize int64
|
|
|
|
// Checksum values
|
|
ChecksumCRC32 string
|
|
ChecksumCRC32C string
|
|
ChecksumSHA1 string
|
|
ChecksumSHA256 string
|
|
}
|
|
|
|
// CompletePart - represents the part that was completed, this is sent by the client
|
|
// during CompleteMultipartUpload request.
|
|
type CompletePart struct {
|
|
// Part number identifying the part. This is a positive integer between 1 and
|
|
// 10,000
|
|
PartNumber int
|
|
|
|
// Entity tag returned when the part was uploaded.
|
|
ETag string
|
|
|
|
// Checksum values. Optional.
|
|
ChecksumCRC32 string
|
|
ChecksumCRC32C string
|
|
ChecksumSHA1 string
|
|
ChecksumSHA256 string
|
|
}
|
|
|
|
// CompleteMultipartUpload - represents list of parts which are completed, this is sent by the
|
|
// client during CompleteMultipartUpload request.
|
|
type CompleteMultipartUpload struct {
|
|
Parts []CompletePart `xml:"Part"`
|
|
}
|
|
|
|
// NewMultipartUploadResult contains information about a newly created multipart upload.
|
|
type NewMultipartUploadResult struct {
|
|
UploadID string
|
|
ChecksumAlgo string
|
|
}
|