github.com/minio/madmin-go/v3@v3.0.51/info-commands.go (about)

     1  //
     2  // Copyright (c) 2015-2022 MinIO, Inc.
     3  //
     4  // This file is part of MinIO Object Storage stack
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU Affero General Public License as
     8  // published by the Free Software Foundation, either version 3 of the
     9  // License, or (at your option) any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU Affero General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU Affero General Public License
    17  // along with this program. If not, see <http://www.gnu.org/licenses/>.
    18  //
    19  
    20  package madmin
    21  
    22  import (
    23  	"context"
    24  	"encoding/json"
    25  	"net/http"
    26  	"net/url"
    27  	"strconv"
    28  	"time"
    29  )
    30  
    31  // BackendType - represents different backend types.
    32  type BackendType int
    33  
    34  // Enum for different backend types.
    35  const (
    36  	Unknown BackendType = iota
    37  	// Filesystem backend.
    38  	FS
    39  	// Multi disk Erasure (single, distributed) backend.
    40  	Erasure
    41  	// Gateway to other storage
    42  	Gateway
    43  
    44  	// Add your own backend.
    45  )
    46  
    47  // ItemState - represents the status of any item in offline,init,online state
    48  type ItemState string
    49  
    50  const (
    51  
    52  	// ItemOffline indicates that the item is offline
    53  	ItemOffline = ItemState("offline")
    54  	// ItemInitializing indicates that the item is still in initialization phase
    55  	ItemInitializing = ItemState("initializing")
    56  	// ItemOnline indicates that the item is online
    57  	ItemOnline = ItemState("online")
    58  )
    59  
    60  // StorageInfo - represents total capacity of underlying storage.
    61  type StorageInfo struct {
    62  	Disks []Disk
    63  
    64  	// Backend type.
    65  	Backend BackendInfo
    66  }
    67  
    68  // BackendInfo - contains info of the underlying backend
    69  type BackendInfo struct {
    70  	// Represents various backend types, currently on FS, Erasure and Gateway
    71  	Type BackendType
    72  
    73  	// Following fields are only meaningful if BackendType is Gateway.
    74  	GatewayOnline bool
    75  
    76  	// Following fields are only meaningful if BackendType is Erasure.
    77  	OnlineDisks  BackendDisks // Online disks during server startup.
    78  	OfflineDisks BackendDisks // Offline disks during server startup.
    79  
    80  	// Following fields are only meaningful if BackendType is Erasure.
    81  	StandardSCData     []int // Data disks for currently configured Standard storage class.
    82  	StandardSCParities []int // Parity disks per pool for currently configured Standard storage class
    83  	RRSCData           []int // Data disks for currently configured Reduced Redundancy storage class.
    84  	RRSCParities       []int // Parity disks per pool for currently configured Reduced Redundancy storage class.
    85  
    86  	// Adds number of erasure sets and drives per set.
    87  	TotalSets    []int // Each index value corresponds to per pool
    88  	DrivesPerSet []int // Each index value corresponds to per pool
    89  
    90  	// Deprecated Aug 2023
    91  	StandardSCParity int // Parity disks for currently configured Standard storage class.
    92  	RRSCParity       int // Parity disks for currently configured Reduced Redundancy storage class.
    93  }
    94  
    95  // BackendDisks - represents the map of endpoint-disks.
    96  type BackendDisks map[string]int
    97  
    98  // Sum - Return the sum of the disks in the endpoint-disk map.
    99  func (d1 BackendDisks) Sum() (sum int) {
   100  	for _, count := range d1 {
   101  		sum += count
   102  	}
   103  	return sum
   104  }
   105  
   106  // Merge - Reduces two endpoint-disk maps.
   107  func (d1 BackendDisks) Merge(d2 BackendDisks) BackendDisks {
   108  	if len(d2) == 0 {
   109  		d2 = make(BackendDisks)
   110  	}
   111  	merged := make(BackendDisks)
   112  	for i1, v1 := range d1 {
   113  		if v2, ok := d2[i1]; ok {
   114  			merged[i1] = v2 + v1
   115  			continue
   116  		}
   117  		merged[i1] = v1
   118  	}
   119  	return merged
   120  }
   121  
   122  // StorageInfo - Connect to a minio server and call Storage Info Management API
   123  // to fetch server's information represented by StorageInfo structure
   124  func (adm *AdminClient) StorageInfo(ctx context.Context) (StorageInfo, error) {
   125  	resp, err := adm.executeMethod(ctx, http.MethodGet, requestData{relPath: adminAPIPrefix + "/storageinfo"})
   126  	defer closeResponse(resp)
   127  	if err != nil {
   128  		return StorageInfo{}, err
   129  	}
   130  
   131  	// Check response http status code
   132  	if resp.StatusCode != http.StatusOK {
   133  		return StorageInfo{}, httpRespToErrorResponse(resp)
   134  	}
   135  
   136  	// Unmarshal the server's json response
   137  	var storageInfo StorageInfo
   138  	if err = json.NewDecoder(resp.Body).Decode(&storageInfo); err != nil {
   139  		return StorageInfo{}, err
   140  	}
   141  
   142  	return storageInfo, nil
   143  }
   144  
   145  // BucketUsageInfo - bucket usage info provides
   146  // - total size of the bucket
   147  // - total objects in a bucket
   148  // - object size histogram per bucket
   149  type BucketUsageInfo struct {
   150  	Size                    uint64 `json:"size"`
   151  	ReplicationPendingSize  uint64 `json:"objectsPendingReplicationTotalSize"`
   152  	ReplicationFailedSize   uint64 `json:"objectsFailedReplicationTotalSize"`
   153  	ReplicatedSize          uint64 `json:"objectsReplicatedTotalSize"`
   154  	ReplicaSize             uint64 `json:"objectReplicaTotalSize"`
   155  	ReplicationPendingCount uint64 `json:"objectsPendingReplicationCount"`
   156  	ReplicationFailedCount  uint64 `json:"objectsFailedReplicationCount"`
   157  
   158  	VersionsCount           uint64            `json:"versionsCount"`
   159  	ObjectsCount            uint64            `json:"objectsCount"`
   160  	DeleteMarkersCount      uint64            `json:"deleteMarkersCount"`
   161  	ObjectSizesHistogram    map[string]uint64 `json:"objectsSizesHistogram"`
   162  	ObjectVersionsHistogram map[string]uint64 `json:"objectsVersionsHistogram"`
   163  }
   164  
   165  // DataUsageInfo represents data usage stats of the underlying Object API
   166  type DataUsageInfo struct {
   167  	// LastUpdate is the timestamp of when the data usage info was last updated.
   168  	// This does not indicate a full scan.
   169  	LastUpdate time.Time `json:"lastUpdate"`
   170  
   171  	// Objects total count across all buckets
   172  	ObjectsTotalCount uint64 `json:"objectsCount"`
   173  
   174  	// Objects total size across all buckets
   175  	ObjectsTotalSize uint64 `json:"objectsTotalSize"`
   176  
   177  	// Total Size for objects that have not yet been replicated
   178  	ReplicationPendingSize uint64 `json:"objectsPendingReplicationTotalSize"`
   179  
   180  	// Total size for objects that have witness one or more failures and will be retried
   181  	ReplicationFailedSize uint64 `json:"objectsFailedReplicationTotalSize"`
   182  
   183  	// Total size for objects that have been replicated to destination
   184  	ReplicatedSize uint64 `json:"objectsReplicatedTotalSize"`
   185  
   186  	// Total size for objects that are replicas
   187  	ReplicaSize uint64 `json:"objectsReplicaTotalSize"`
   188  
   189  	// Total number of objects pending replication
   190  	ReplicationPendingCount uint64 `json:"objectsPendingReplicationCount"`
   191  
   192  	// Total number of objects that failed replication
   193  	ReplicationFailedCount uint64 `json:"objectsFailedReplicationCount"`
   194  
   195  	// Total number of buckets in this cluster
   196  	BucketsCount uint64 `json:"bucketsCount"`
   197  
   198  	// Buckets usage info provides following information across all buckets
   199  	// - total size of the bucket
   200  	// - total objects in a bucket
   201  	// - object size histogram per bucket
   202  	BucketsUsage map[string]BucketUsageInfo `json:"bucketsUsageInfo"`
   203  
   204  	// TierStats holds per-tier stats like bytes tiered, etc.
   205  	TierStats map[string]TierStats `json:"tierStats"`
   206  
   207  	// Deprecated kept here for backward compatibility reasons.
   208  	BucketSizes map[string]uint64 `json:"bucketsSizes"`
   209  
   210  	// Server capacity related data
   211  	TotalCapacity     uint64 `json:"capacity"`
   212  	TotalFreeCapacity uint64 `json:"freeCapacity"`
   213  	TotalUsedCapacity uint64 `json:"usedCapacity"`
   214  }
   215  
   216  // DataUsageInfo - returns data usage of the current object API
   217  func (adm *AdminClient) DataUsageInfo(ctx context.Context) (DataUsageInfo, error) {
   218  	values := make(url.Values)
   219  	values.Set("capacity", "true") // We can make this configurable in future but for now its fine.
   220  
   221  	resp, err := adm.executeMethod(ctx, http.MethodGet, requestData{
   222  		relPath:     adminAPIPrefix + "/datausageinfo",
   223  		queryValues: values,
   224  	})
   225  	defer closeResponse(resp)
   226  	if err != nil {
   227  		return DataUsageInfo{}, err
   228  	}
   229  
   230  	// Check response http status code
   231  	if resp.StatusCode != http.StatusOK {
   232  		return DataUsageInfo{}, httpRespToErrorResponse(resp)
   233  	}
   234  
   235  	// Unmarshal the server's json response
   236  	var dataUsageInfo DataUsageInfo
   237  	if err = json.NewDecoder(resp.Body).Decode(&dataUsageInfo); err != nil {
   238  		return DataUsageInfo{}, err
   239  	}
   240  
   241  	return dataUsageInfo, nil
   242  }
   243  
   244  // ErasureSetInfo provides information per erasure set
   245  type ErasureSetInfo struct {
   246  	ID                 int    `json:"id"`
   247  	RawUsage           uint64 `json:"rawUsage"`
   248  	RawCapacity        uint64 `json:"rawCapacity"`
   249  	Usage              uint64 `json:"usage"`
   250  	ObjectsCount       uint64 `json:"objectsCount"`
   251  	VersionsCount      uint64 `json:"versionsCount"`
   252  	DeleteMarkersCount uint64 `json:"deleteMarkersCount"`
   253  	HealDisks          int    `json:"healDisks"`
   254  }
   255  
   256  // InfoMessage container to hold server admin related information.
   257  type InfoMessage struct {
   258  	Mode          string             `json:"mode,omitempty"`
   259  	Domain        []string           `json:"domain,omitempty"`
   260  	Region        string             `json:"region,omitempty"`
   261  	SQSARN        []string           `json:"sqsARN,omitempty"`
   262  	DeploymentID  string             `json:"deploymentID,omitempty"`
   263  	Buckets       Buckets            `json:"buckets,omitempty"`
   264  	Objects       Objects            `json:"objects,omitempty"`
   265  	Versions      Versions           `json:"versions,omitempty"`
   266  	DeleteMarkers DeleteMarkers      `json:"deletemarkers,omitempty"`
   267  	Usage         Usage              `json:"usage,omitempty"`
   268  	Services      Services           `json:"services,omitempty"`
   269  	Backend       ErasureBackend     `json:"backend,omitempty"`
   270  	Servers       []ServerProperties `json:"servers,omitempty"`
   271  
   272  	Pools map[int]map[int]ErasureSetInfo `json:"pools,omitempty"`
   273  }
   274  
   275  func (info InfoMessage) BackendType() BackendType {
   276  	// MinIO server type default
   277  	switch info.Backend.Type {
   278  	case "Erasure":
   279  		return Erasure
   280  	case "FS":
   281  		return FS
   282  	default:
   283  		return Unknown
   284  	}
   285  }
   286  
   287  func (info InfoMessage) StandardParity() int {
   288  	switch info.BackendType() {
   289  	case Erasure:
   290  		return info.Backend.StandardSCParity
   291  	default:
   292  		return -1
   293  	}
   294  }
   295  
   296  // Services contains different services information
   297  type Services struct {
   298  	KMS           KMS                           `json:"kms,omitempty"` // deprecated july 2023
   299  	KMSStatus     []KMS                         `json:"kmsStatus,omitempty"`
   300  	LDAP          LDAP                          `json:"ldap,omitempty"`
   301  	Logger        []Logger                      `json:"logger,omitempty"`
   302  	Audit         []Audit                       `json:"audit,omitempty"`
   303  	Notifications []map[string][]TargetIDStatus `json:"notifications,omitempty"`
   304  }
   305  
   306  // Buckets contains the number of buckets
   307  type Buckets struct {
   308  	Count uint64 `json:"count"`
   309  	Error string `json:"error,omitempty"`
   310  }
   311  
   312  // Objects contains the number of objects
   313  type Objects struct {
   314  	Count uint64 `json:"count"`
   315  	Error string `json:"error,omitempty"`
   316  }
   317  
   318  // Versions contains the number of versions
   319  type Versions struct {
   320  	Count uint64 `json:"count"`
   321  	Error string `json:"error,omitempty"`
   322  }
   323  
   324  // DeleteMarkers contains the number of delete markers
   325  type DeleteMarkers struct {
   326  	Count uint64 `json:"count"`
   327  	Error string `json:"error,omitempty"`
   328  }
   329  
   330  // Usage contains the total size used
   331  type Usage struct {
   332  	Size  uint64 `json:"size"`
   333  	Error string `json:"error,omitempty"`
   334  }
   335  
   336  // TierStats contains per-tier statistics like total size, number of
   337  // objects/versions transitioned, etc.
   338  type TierStats struct {
   339  	TotalSize   uint64 `json:"totalSize"`
   340  	NumVersions int    `json:"numVersions"`
   341  	NumObjects  int    `json:"numObjects"`
   342  }
   343  
   344  // KMS contains KMS status information
   345  type KMS struct {
   346  	Status   string `json:"status,omitempty"`
   347  	Encrypt  string `json:"encrypt,omitempty"`
   348  	Decrypt  string `json:"decrypt,omitempty"`
   349  	Endpoint string `json:"endpoint,omitempty"`
   350  	Version  string `json:"version,omitempty"`
   351  }
   352  
   353  // LDAP contains ldap status
   354  type LDAP struct {
   355  	Status string `json:"status,omitempty"`
   356  }
   357  
   358  // Status of endpoint
   359  type Status struct {
   360  	Status string `json:"status,omitempty"`
   361  }
   362  
   363  // Audit contains audit logger status
   364  type Audit map[string]Status
   365  
   366  // Logger contains logger status
   367  type Logger map[string]Status
   368  
   369  // TargetIDStatus containsid and status
   370  type TargetIDStatus map[string]Status
   371  
   372  // backendType - indicates the type of backend storage
   373  type backendType string
   374  
   375  const (
   376  	// FsType - Backend is FS Type
   377  	FsType = backendType("FS")
   378  	// ErasureType - Backend is Erasure type
   379  	ErasureType = backendType("Erasure")
   380  )
   381  
   382  // FSBackend contains specific FS storage information
   383  type FSBackend struct {
   384  	Type backendType `json:"backendType"`
   385  }
   386  
   387  // ErasureBackend contains specific erasure storage information
   388  type ErasureBackend struct {
   389  	Type         backendType `json:"backendType"`
   390  	OnlineDisks  int         `json:"onlineDisks"`
   391  	OfflineDisks int         `json:"offlineDisks"`
   392  	// Parity disks for currently configured Standard storage class.
   393  	StandardSCParity int `json:"standardSCParity"`
   394  	// Parity disks for currently configured Reduced Redundancy storage class.
   395  	RRSCParity int `json:"rrSCParity"`
   396  
   397  	// Per pool information
   398  	TotalSets    []int `json:"totalSets"`
   399  	DrivesPerSet []int `json:"totalDrivesPerSet"`
   400  }
   401  
   402  // ServerProperties holds server information
   403  type ServerProperties struct {
   404  	State          string            `json:"state,omitempty"`
   405  	Endpoint       string            `json:"endpoint,omitempty"`
   406  	Scheme         string            `json:"scheme,omitempty"`
   407  	Uptime         int64             `json:"uptime,omitempty"`
   408  	Version        string            `json:"version,omitempty"`
   409  	CommitID       string            `json:"commitID,omitempty"`
   410  	Network        map[string]string `json:"network,omitempty"`
   411  	Disks          []Disk            `json:"drives,omitempty"`
   412  	PoolNumber     int               `json:"poolNumber,omitempty"` // Only set if len(PoolNumbers) == 1
   413  	PoolNumbers    []int             `json:"poolNumbers,omitempty"`
   414  	MemStats       MemStats          `json:"mem_stats"`
   415  	GoMaxProcs     int               `json:"go_max_procs,omitempty"`
   416  	NumCPU         int               `json:"num_cpu,omitempty"`
   417  	RuntimeVersion string            `json:"runtime_version,omitempty"`
   418  	GCStats        *GCStats          `json:"gc_stats,omitempty"`
   419  	MinioEnvVars   map[string]string `json:"minio_env_vars,omitempty"`
   420  }
   421  
   422  // DiskMetrics has the information about XL Storage APIs
   423  // the number of calls of each API and the moving average of
   424  // the duration, in nanosecond, of each API.
   425  type DiskMetrics struct {
   426  	LastMinute map[string]TimedAction `json:"lastMinute,omitempty"`
   427  	APICalls   map[string]uint64      `json:"apiCalls,omitempty"`
   428  
   429  	// TotalTokens set per drive max concurrent I/O.
   430  	TotalTokens uint32 `json:"totalTokens,omitempty"`
   431  	// TotalWaiting the amount of concurrent I/O waiting on disk
   432  	TotalWaiting uint32 `json:"totalWaiting,omitempty"`
   433  
   434  	// Captures all data availability errors such as
   435  	// permission denied, faulty disk and timeout errors.
   436  	TotalErrorsAvailability uint64 `json:"totalErrorsAvailability,omitempty"`
   437  	// Captures all timeout only errors
   438  	TotalErrorsTimeout uint64 `json:"totalErrorsTimeout,omitempty"`
   439  
   440  	// Total writes on disk (could be empty if the feature
   441  	// is not enabled on the server)
   442  	TotalWrites uint64 `json:"totalWrites,omitempty"`
   443  	// Total deletes on disk (could be empty if the feature
   444  	// is not enabled on the server)
   445  	TotalDeletes uint64 `json:"totalDeletes,omitempty"`
   446  
   447  	// Deprecated: Use LastMinute instead. Not populated from servers after July 2022.
   448  	APILatencies map[string]interface{} `json:"apiLatencies,omitempty"`
   449  }
   450  
   451  // Disk holds Disk information
   452  type Disk struct {
   453  	Endpoint        string       `json:"endpoint,omitempty"`
   454  	RootDisk        bool         `json:"rootDisk,omitempty"`
   455  	DrivePath       string       `json:"path,omitempty"`
   456  	Healing         bool         `json:"healing,omitempty"`
   457  	Scanning        bool         `json:"scanning,omitempty"`
   458  	State           string       `json:"state,omitempty"`
   459  	UUID            string       `json:"uuid,omitempty"`
   460  	Major           uint32       `json:"major"`
   461  	Minor           uint32       `json:"minor"`
   462  	Model           string       `json:"model,omitempty"`
   463  	TotalSpace      uint64       `json:"totalspace,omitempty"`
   464  	UsedSpace       uint64       `json:"usedspace,omitempty"`
   465  	AvailableSpace  uint64       `json:"availspace,omitempty"`
   466  	ReadThroughput  float64      `json:"readthroughput,omitempty"`
   467  	WriteThroughPut float64      `json:"writethroughput,omitempty"`
   468  	ReadLatency     float64      `json:"readlatency,omitempty"`
   469  	WriteLatency    float64      `json:"writelatency,omitempty"`
   470  	Utilization     float64      `json:"utilization,omitempty"`
   471  	Metrics         *DiskMetrics `json:"metrics,omitempty"`
   472  	HealInfo        *HealingDisk `json:"heal_info,omitempty"`
   473  	UsedInodes      uint64       `json:"used_inodes"`
   474  	FreeInodes      uint64       `json:"free_inodes,omitempty"`
   475  	Local           bool         `json:"local,omitempty"`
   476  
   477  	// Indexes, will be -1 until assigned a set.
   478  	PoolIndex int `json:"pool_index"`
   479  	SetIndex  int `json:"set_index"`
   480  	DiskIndex int `json:"disk_index"`
   481  }
   482  
   483  // ServerInfoOpts ask for additional data from the server
   484  type ServerInfoOpts struct {
   485  	Metrics bool
   486  }
   487  
   488  // WithDriveMetrics asks server to return additional metrics per drive
   489  func WithDriveMetrics(metrics bool) func(*ServerInfoOpts) {
   490  	return func(opts *ServerInfoOpts) {
   491  		opts.Metrics = metrics
   492  	}
   493  }
   494  
   495  // ServerInfo - Connect to a minio server and call Server Admin Info Management API
   496  // to fetch server's information represented by infoMessage structure
   497  func (adm *AdminClient) ServerInfo(ctx context.Context, options ...func(*ServerInfoOpts)) (InfoMessage, error) {
   498  	srvOpts := &ServerInfoOpts{}
   499  
   500  	for _, o := range options {
   501  		o(srvOpts)
   502  	}
   503  
   504  	values := make(url.Values)
   505  	values.Set("metrics", strconv.FormatBool(srvOpts.Metrics))
   506  
   507  	resp, err := adm.executeMethod(ctx,
   508  		http.MethodGet,
   509  		requestData{
   510  			relPath:     adminAPIPrefix + "/info",
   511  			queryValues: values,
   512  		})
   513  	defer closeResponse(resp)
   514  	if err != nil {
   515  		return InfoMessage{}, err
   516  	}
   517  
   518  	// Check response http status code
   519  	if resp.StatusCode != http.StatusOK {
   520  		return InfoMessage{}, httpRespToErrorResponse(resp)
   521  	}
   522  
   523  	// Unmarshal the server's json response
   524  	var message InfoMessage
   525  	if err = json.NewDecoder(resp.Body).Decode(&message); err != nil {
   526  		return InfoMessage{}, err
   527  	}
   528  
   529  	return message, nil
   530  }