fix: admin info output and improve overall performance (#10015)

- admin info node offline check is now quicker
- admin info now doesn't duplicate the code
  across doing the same checks for disks
- rely on StorageInfo to return appropriate errors
  instead of calling locally.
- diskID checks now return proper errors when
  disk not found v/s format.json missing.
- add more disk states for more clarity on the
  underlying disk errors.
This commit is contained in:
Harshavardhana 2020-07-13 09:51:07 -07:00 committed by GitHub
parent 1d65ef3201
commit e7d7d5232c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 244 additions and 372 deletions

View File

@ -1419,23 +1419,12 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
// Fetching the Storage information, ignore any errors. // Fetching the Storage information, ignore any errors.
storageInfo, _ := objectAPI.StorageInfo(ctx, false) storageInfo, _ := objectAPI.StorageInfo(ctx, false)
var OnDisks int
var OffDisks int
var backend interface{} var backend interface{}
if storageInfo.Backend.Type == BackendType(madmin.Erasure) { if storageInfo.Backend.Type == BackendType(madmin.Erasure) {
for _, v := range storageInfo.Backend.OnlineDisks {
OnDisks += v
}
for _, v := range storageInfo.Backend.OfflineDisks {
OffDisks += v
}
backend = madmin.ErasureBackend{ backend = madmin.ErasureBackend{
Type: madmin.ErasureType, Type: madmin.ErasureType,
OnlineDisks: OnDisks, OnlineDisks: storageInfo.Backend.OnlineDisks.Sum(),
OfflineDisks: OffDisks, OfflineDisks: storageInfo.Backend.OfflineDisks.Sum(),
StandardSCData: storageInfo.Backend.StandardSCData, StandardSCData: storageInfo.Backend.StandardSCData,
StandardSCParity: storageInfo.Backend.StandardSCParity, StandardSCParity: storageInfo.Backend.StandardSCParity,
RRSCData: storageInfo.Backend.RRSCData, RRSCData: storageInfo.Backend.RRSCData,
@ -1456,38 +1445,6 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
servers := globalNotificationSys.ServerInfo() servers := globalNotificationSys.ServerInfo()
servers = append(servers, server) servers = append(servers, server)
for _, sp := range servers {
for i, di := range sp.Disks {
path := ""
if globalIsErasure {
path = di.DrivePath
}
if globalIsDistErasure {
path = sp.Endpoint + di.DrivePath
}
// For distributed
for a := range storageInfo.Backend.Sets {
for b := range storageInfo.Backend.Sets[a] {
ep := storageInfo.Backend.Sets[a][b].Endpoint
if globalIsDistErasure {
if strings.Replace(ep, "http://", "", -1) == path || strings.Replace(ep, "https://", "", -1) == path {
sp.Disks[i].State = storageInfo.Backend.Sets[a][b].State
sp.Disks[i].UUID = storageInfo.Backend.Sets[a][b].UUID
}
}
if globalIsErasure {
if ep == path {
sp.Disks[i].State = storageInfo.Backend.Sets[a][b].State
sp.Disks[i].UUID = storageInfo.Backend.Sets[a][b].UUID
}
}
}
}
}
}
domain := globalDomainNames domain := globalDomainNames
services := madmin.Services{ services := madmin.Services{
Vault: vault, Vault: vault,
@ -1497,6 +1454,21 @@ func (a adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Reque
Notifications: notifyTarget, Notifications: notifyTarget,
} }
// find all disks which belong to each respective endpoints
for i := range servers {
for _, disk := range storageInfo.Disks {
if strings.Contains(disk.Endpoint, servers[i].Endpoint) {
servers[i].Disks = append(servers[i].Disks, disk)
}
}
}
// add all the disks local to this server.
for _, disk := range storageInfo.Disks {
if disk.Endpoint == disk.DrivePath {
servers[len(servers)-1].Disks = append(servers[len(servers)-1].Disks, disk)
}
}
infoMsg := madmin.InfoMessage{ infoMsg := madmin.InfoMessage{
Mode: mode, Mode: mode,
Domain: domain, Domain: domain,

View File

@ -18,16 +18,13 @@ package cmd
import ( import (
"net/http" "net/http"
"os"
"github.com/minio/minio/pkg/disk"
"github.com/minio/minio/pkg/madmin" "github.com/minio/minio/pkg/madmin"
) )
// getLocalServerProperty - returns madmin.ServerProperties for only the // getLocalServerProperty - returns madmin.ServerProperties for only the
// local endpoints from given list of endpoints // local endpoints from given list of endpoints
func getLocalServerProperty(endpointZones EndpointZones, r *http.Request) madmin.ServerProperties { func getLocalServerProperty(endpointZones EndpointZones, r *http.Request) madmin.ServerProperties {
var disks []madmin.Disk
addr := r.Host addr := r.Host
if globalIsDistErasure { if globalIsDistErasure {
addr = GetLocalPeer(endpointZones) addr = GetLocalPeer(endpointZones)
@ -42,33 +39,14 @@ func getLocalServerProperty(endpointZones EndpointZones, r *http.Request) madmin
if endpoint.IsLocal { if endpoint.IsLocal {
// Only proceed for local endpoints // Only proceed for local endpoints
network[nodeName] = "online" network[nodeName] = "online"
var di = madmin.Disk{ continue
DrivePath: endpoint.Path, }
} _, present := network[nodeName]
diInfo, err := disk.GetInfo(endpoint.Path) if !present {
if err != nil { if err := IsServerResolvable(endpoint); err == nil {
if os.IsNotExist(err) || isSysErrPathNotFound(err) { network[nodeName] = "online"
di.State = madmin.DriveStateMissing
} else {
di.State = madmin.DriveStateCorrupt
}
} else { } else {
di.State = madmin.DriveStateOk network[nodeName] = "offline"
di.DrivePath = endpoint.Path
di.TotalSpace = diInfo.Total
di.UsedSpace = diInfo.Total - diInfo.Free
di.Utilization = float64((diInfo.Total - diInfo.Free) / diInfo.Total * 100)
}
disks = append(disks, di)
} else {
_, present := network[nodeName]
if !present {
err := IsServerResolvable(endpoint)
if err == nil {
network[nodeName] = "online"
} else {
network[nodeName] = "offline"
}
} }
} }
} }
@ -81,6 +59,5 @@ func getLocalServerProperty(endpointZones EndpointZones, r *http.Request) madmin
Version: Version, Version: Version,
CommitID: CommitID, CommitID: CommitID,
Network: network, Network: network,
Disks: disks,
} }
} }

View File

@ -395,10 +395,7 @@ func (s *erasureSets) StorageUsageInfo(ctx context.Context) StorageInfo {
g.Wait() g.Wait()
for _, lstorageInfo := range storageInfos { for _, lstorageInfo := range storageInfos {
storageInfo.Used = append(storageInfo.Used, lstorageInfo.Used...) storageInfo.Disks = append(storageInfo.Disks, lstorageInfo.Disks...)
storageInfo.Total = append(storageInfo.Total, lstorageInfo.Total...)
storageInfo.Available = append(storageInfo.Available, lstorageInfo.Available...)
storageInfo.MountPaths = append(storageInfo.MountPaths, lstorageInfo.MountPaths...)
storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks) storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks)
storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks) storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks)
} }
@ -438,10 +435,7 @@ func (s *erasureSets) StorageInfo(ctx context.Context, local bool) (StorageInfo,
g.Wait() g.Wait()
for _, lstorageInfo := range storageInfos { for _, lstorageInfo := range storageInfos {
storageInfo.Used = append(storageInfo.Used, lstorageInfo.Used...) storageInfo.Disks = append(storageInfo.Disks, lstorageInfo.Disks...)
storageInfo.Total = append(storageInfo.Total, lstorageInfo.Total...)
storageInfo.Available = append(storageInfo.Available, lstorageInfo.Available...)
storageInfo.MountPaths = append(storageInfo.MountPaths, lstorageInfo.MountPaths...)
storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks) storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks)
storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks) storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks)
} }
@ -457,57 +451,12 @@ func (s *erasureSets) StorageInfo(ctx context.Context, local bool) (StorageInfo,
storageInfo.Backend.RRSCData = s.drivesPerSet - rrSCParity storageInfo.Backend.RRSCData = s.drivesPerSet - rrSCParity
storageInfo.Backend.RRSCParity = rrSCParity storageInfo.Backend.RRSCParity = rrSCParity
storageInfo.Backend.Sets = make([][]madmin.DriveInfo, s.setCount)
for i := range storageInfo.Backend.Sets {
storageInfo.Backend.Sets[i] = make([]madmin.DriveInfo, s.drivesPerSet)
}
if local { if local {
// if local is true, we are not interested in the drive UUID info. // if local is true, we are not interested in the drive UUID info.
// this is called primarily by prometheus // this is called primarily by prometheus
return storageInfo, nil return storageInfo, nil
} }
for i, set := range s.sets {
storageDisks := set.getDisks()
endpointStrings := set.getEndpoints()
for j, storageErr := range storageInfoErrs[i] {
if storageDisks[j] == OfflineDisk {
storageInfo.Backend.Sets[i][j] = madmin.DriveInfo{
State: madmin.DriveStateOffline,
Endpoint: endpointStrings[j],
}
continue
}
var diskID string
if storageErr == nil {
// No errors returned by storage, look for its DiskID()
diskID, storageErr = storageDisks[j].GetDiskID()
}
if storageErr == nil {
storageInfo.Backend.Sets[i][j] = madmin.DriveInfo{
State: madmin.DriveStateOk,
Endpoint: storageDisks[j].String(),
UUID: diskID,
}
continue
}
if storageErr == errUnformattedDisk {
storageInfo.Backend.Sets[i][j] = madmin.DriveInfo{
State: madmin.DriveStateUnformatted,
Endpoint: storageDisks[j].String(),
UUID: "",
}
} else {
storageInfo.Backend.Sets[i][j] = madmin.DriveInfo{
State: madmin.DriveStateCorrupt,
Endpoint: storageDisks[j].String(),
UUID: "",
}
}
}
}
var errs []error var errs []error
for i := range s.sets { for i := range s.sets {
errs = append(errs, storageInfoErrs[i]...) errs = append(errs, storageInfoErrs[i]...)
@ -1195,8 +1144,8 @@ else
fi fi
*/ */
func formatsToDrivesInfo(endpoints Endpoints, formats []*formatErasureV3, sErrs []error) (beforeDrives []madmin.DriveInfo) { func formatsToDrivesInfo(endpoints Endpoints, formats []*formatErasureV3, sErrs []error) (beforeDrives []madmin.HealDriveInfo) {
beforeDrives = make([]madmin.DriveInfo, len(endpoints)) beforeDrives = make([]madmin.HealDriveInfo, len(endpoints))
// Existing formats are available (i.e. ok), so save it in // Existing formats are available (i.e. ok), so save it in
// result, also populate disks to be healed. // result, also populate disks to be healed.
for i, format := range formats { for i, format := range formats {
@ -1210,7 +1159,7 @@ func formatsToDrivesInfo(endpoints Endpoints, formats []*formatErasureV3, sErrs
case sErrs[i] == errDiskNotFound: case sErrs[i] == errDiskNotFound:
state = madmin.DriveStateOffline state = madmin.DriveStateOffline
} }
beforeDrives[i] = madmin.DriveInfo{ beforeDrives[i] = madmin.HealDriveInfo{
UUID: func() string { UUID: func() string {
if format != nil { if format != nil {
return format.Erasure.This return format.Erasure.This

View File

@ -149,12 +149,10 @@ func (z *erasureZones) getZonesAvailableSpace(ctx context.Context, size int64) z
for i, zinfo := range storageInfos { for i, zinfo := range storageInfos {
var available uint64 var available uint64
for _, davailable := range zinfo.Available {
available += davailable
}
var total uint64 var total uint64
for _, dtotal := range zinfo.Total { for _, disk := range zinfo.Disks {
total += dtotal total += disk.TotalSpace
available += disk.TotalSpace - disk.UsedSpace
} }
// Make sure we can fit "size" on to the disk without getting above the diskFillFraction // Make sure we can fit "size" on to the disk without getting above the diskFillFraction
if available < uint64(size) { if available < uint64(size) {
@ -260,13 +258,9 @@ func (z *erasureZones) StorageInfo(ctx context.Context, local bool) (StorageInfo
g.Wait() g.Wait()
for _, lstorageInfo := range storageInfos { for _, lstorageInfo := range storageInfos {
storageInfo.Used = append(storageInfo.Used, lstorageInfo.Used...) storageInfo.Disks = append(storageInfo.Disks, lstorageInfo.Disks...)
storageInfo.Total = append(storageInfo.Total, lstorageInfo.Total...)
storageInfo.Available = append(storageInfo.Available, lstorageInfo.Available...)
storageInfo.MountPaths = append(storageInfo.MountPaths, lstorageInfo.MountPaths...)
storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks) storageInfo.Backend.OnlineDisks = storageInfo.Backend.OnlineDisks.Merge(lstorageInfo.Backend.OnlineDisks)
storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks) storageInfo.Backend.OfflineDisks = storageInfo.Backend.OfflineDisks.Merge(lstorageInfo.Backend.OfflineDisks)
storageInfo.Backend.Sets = append(storageInfo.Backend.Sets, lstorageInfo.Backend.Sets...)
} }
storageInfo.Backend.Type = storageInfos[0].Backend.Type storageInfo.Backend.Type = storageInfos[0].Backend.Type

View File

@ -79,17 +79,36 @@ func (er erasureObjects) Shutdown(ctx context.Context) error {
} }
// byDiskTotal is a collection satisfying sort.Interface. // byDiskTotal is a collection satisfying sort.Interface.
type byDiskTotal []DiskInfo type byDiskTotal []madmin.Disk
func (d byDiskTotal) Len() int { return len(d) } func (d byDiskTotal) Len() int { return len(d) }
func (d byDiskTotal) Swap(i, j int) { d[i], d[j] = d[j], d[i] } func (d byDiskTotal) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d byDiskTotal) Less(i, j int) bool { func (d byDiskTotal) Less(i, j int) bool {
return d[i].Total < d[j].Total return d[i].TotalSpace < d[j].TotalSpace
}
func diskErrToDriveState(err error) (state string) {
state = madmin.DriveStateUnknown
switch err {
case errDiskNotFound:
state = madmin.DriveStateOffline
case errCorruptedFormat:
state = madmin.DriveStateCorrupt
case errUnformattedDisk:
state = madmin.DriveStateUnformatted
case errDiskAccessDenied:
state = madmin.DriveStatePermission
case errFaultyDisk:
state = madmin.DriveStateFaulty
case nil:
state = madmin.DriveStateOk
}
return
} }
// getDisksInfo - fetch disks info across all other storage API. // getDisksInfo - fetch disks info across all other storage API.
func getDisksInfo(disks []StorageAPI, endpoints []string) (disksInfo []DiskInfo, errs []error, onlineDisks, offlineDisks madmin.BackendDisks) { func getDisksInfo(disks []StorageAPI, endpoints []string) (disksInfo []madmin.Disk, errs []error, onlineDisks, offlineDisks madmin.BackendDisks) {
disksInfo = make([]DiskInfo, len(disks)) disksInfo = make([]madmin.Disk, len(disks))
onlineDisks = make(madmin.BackendDisks) onlineDisks = make(madmin.BackendDisks)
offlineDisks = make(madmin.BackendDisks) offlineDisks = make(madmin.BackendDisks)
@ -107,6 +126,10 @@ func getDisksInfo(disks []StorageAPI, endpoints []string) (disksInfo []DiskInfo,
index := index index := index
g.Go(func() error { g.Go(func() error {
if disks[index] == OfflineDisk { if disks[index] == OfflineDisk {
disksInfo[index] = madmin.Disk{
State: diskErrToDriveState(errDiskNotFound),
Endpoint: endpoints[index],
}
// Storage disk is empty, perhaps ignored disk or not available. // Storage disk is empty, perhaps ignored disk or not available.
return errDiskNotFound return errDiskNotFound
} }
@ -117,10 +140,20 @@ func getDisksInfo(disks []StorageAPI, endpoints []string) (disksInfo []DiskInfo,
ctx := logger.SetReqInfo(GlobalContext, reqInfo) ctx := logger.SetReqInfo(GlobalContext, reqInfo)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
} }
return err
} }
disksInfo[index] = info di := madmin.Disk{
return nil Endpoint: endpoints[index],
DrivePath: info.MountPath,
TotalSpace: info.Total,
UsedSpace: info.Used,
UUID: info.ID,
State: diskErrToDriveState(err),
}
if info.Total > 0 {
di.Utilization = float64(info.Used / info.Total * 100)
}
disksInfo[index] = di
return err
}, index) }, index)
} }
@ -146,24 +179,8 @@ func getStorageInfo(disks []StorageAPI, endpoints []string) (StorageInfo, []erro
// Sort so that the first element is the smallest. // Sort so that the first element is the smallest.
sort.Sort(byDiskTotal(disksInfo)) sort.Sort(byDiskTotal(disksInfo))
// Combine all disks to get total usage
usedList := make([]uint64, len(disksInfo))
totalList := make([]uint64, len(disksInfo))
availableList := make([]uint64, len(disksInfo))
mountPaths := make([]string, len(disksInfo))
for i, di := range disksInfo {
usedList[i] = di.Used
totalList[i] = di.Total
availableList[i] = di.Free
mountPaths[i] = di.MountPath
}
storageInfo := StorageInfo{ storageInfo := StorageInfo{
Used: usedList, Disks: disksInfo,
Total: totalList,
Available: availableList,
MountPaths: mountPaths,
} }
storageInfo.Backend.Type = BackendErasure storageInfo.Backend.Type = BackendErasure

View File

@ -53,9 +53,6 @@ var defaultEtag = "00000000000000000000000000000000-1"
type FSObjects struct { type FSObjects struct {
GatewayUnsupported GatewayUnsupported
// Disk usage metrics
totalUsed uint64 // ref: https://golang.org/pkg/sync/atomic/#pkg-note-BUG
// The count of concurrent calls on FSObjects API // The count of concurrent calls on FSObjects API
activeIOCount int64 activeIOCount int64
// The active IO count ceiling for crawling to work // The active IO count ceiling for crawling to work
@ -215,15 +212,15 @@ func (fs *FSObjects) StorageInfo(ctx context.Context, _ bool) (StorageInfo, []er
return StorageInfo{}, []error{err} return StorageInfo{}, []error{err}
} }
used := di.Total - di.Free used := di.Total - di.Free
if !fs.diskMount {
used = atomic.LoadUint64(&fs.totalUsed)
}
storageInfo := StorageInfo{ storageInfo := StorageInfo{
Used: []uint64{used}, Disks: []madmin.Disk{
Total: []uint64{di.Total}, {
Available: []uint64{di.Free}, TotalSpace: di.Total,
MountPaths: []string{fs.fsPath}, UsedSpace: used,
AvailableSpace: di.Free,
DrivePath: fs.fsPath,
},
},
} }
storageInfo.Backend.Type = BackendFS storageInfo.Backend.Type = BackendFS
return storageInfo, nil return storageInfo, nil

View File

@ -39,6 +39,7 @@ import (
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/env" "github.com/minio/minio/pkg/env"
"github.com/minio/minio/pkg/madmin"
xnet "github.com/minio/minio/pkg/net" xnet "github.com/minio/minio/pkg/net"
krb "gopkg.in/jcmturner/gokrb5.v7/client" krb "gopkg.in/jcmturner/gokrb5.v7/client"
"gopkg.in/jcmturner/gokrb5.v7/config" "gopkg.in/jcmturner/gokrb5.v7/config"
@ -210,7 +211,9 @@ func (n *hdfsObjects) StorageInfo(ctx context.Context, _ bool) (si minio.Storage
if err != nil { if err != nil {
return minio.StorageInfo{}, []error{err} return minio.StorageInfo{}, []error{err}
} }
si.Used = []uint64{fsInfo.Used} si.Disks = []madmin.Disk{{
UsedSpace: fsInfo.Used,
}}
si.Backend.Type = minio.BackendGateway si.Backend.Type = minio.BackendGateway
si.Backend.GatewayOnline = true si.Backend.GatewayOnline = true
return si, nil return si, nil

View File

@ -464,10 +464,7 @@ func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
float64(totalDisks.Sum()), float64(totalDisks.Sum()),
) )
for i := 0; i < len(storageInfo.Total); i++ { for _, disk := range storageInfo.Disks {
mountPath, total, free := storageInfo.MountPaths[i], storageInfo.Total[i],
storageInfo.Available[i]
// Total disk usage by the disk // Total disk usage by the disk
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc( prometheus.NewDesc(
@ -475,8 +472,8 @@ func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
"Total disk storage used on the disk", "Total disk storage used on the disk",
[]string{"disk"}, nil), []string{"disk"}, nil),
prometheus.GaugeValue, prometheus.GaugeValue,
float64(total-free), float64(disk.UsedSpace),
mountPath, disk.DrivePath,
) )
// Total available space in the disk // Total available space in the disk
@ -486,8 +483,8 @@ func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
"Total available space left on the disk", "Total available space left on the disk",
[]string{"disk"}, nil), []string{"disk"}, nil),
prometheus.GaugeValue, prometheus.GaugeValue,
float64(free), float64(disk.AvailableSpace),
mountPath, disk.DrivePath,
) )
// Total storage space of the disk // Total storage space of the disk
@ -497,8 +494,8 @@ func storageMetricsPrometheus(ch chan<- prometheus.Metric) {
"Total space on the disk", "Total space on the disk",
[]string{"disk"}, nil), []string{"disk"}, nil),
prometheus.GaugeValue, prometheus.GaugeValue,
float64(total), float64(disk.TotalSpace),
mountPath, disk.DrivePath,
) )
} }
} }

View File

@ -43,13 +43,7 @@ const (
// StorageInfo - represents total capacity of underlying storage. // StorageInfo - represents total capacity of underlying storage.
type StorageInfo struct { type StorageInfo struct {
Used []uint64 // Used total used per disk. Disks []madmin.Disk
Total []uint64 // Total disk space per disk.
Available []uint64 // Total disk space available per disk.
MountPaths []string // Disk mountpoints
// Backend type. // Backend type.
Backend struct { Backend struct {
@ -66,9 +60,6 @@ type StorageInfo struct {
StandardSCParity int // Parity disks for currently configured Standard storage class. StandardSCParity int // Parity disks for currently configured Standard storage class.
RRSCData int // Data disks for currently configured Reduced Redundancy storage class. RRSCData int // Data disks for currently configured Reduced Redundancy storage class.
RRSCParity int // Parity disks for currently configured Reduced Redundancy storage class. RRSCParity int // Parity disks for currently configured Reduced Redundancy storage class.
// List of all disk status, this is only meaningful if BackendType is Erasure.
Sets [][]madmin.DriveInfo
} }
} }

View File

@ -30,7 +30,6 @@ import (
"github.com/minio/minio/cmd/config" "github.com/minio/minio/cmd/config"
xhttp "github.com/minio/minio/cmd/http" xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
"github.com/minio/minio/cmd/rest"
"github.com/minio/minio/pkg/sync/errgroup" "github.com/minio/minio/pkg/sync/errgroup"
) )
@ -183,7 +182,21 @@ func IsServerResolvable(endpoint Endpoint) error {
} }
httpClient := &http.Client{ httpClient := &http.Client{
Transport: newCustomHTTPTransport(tlsConfig, rest.DefaultRESTTimeout)(), Transport:
// For more details about various values used here refer
// https://golang.org/pkg/net/http/#Transport documentation
&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: xhttp.NewCustomDialContext(3 * time.Second),
ResponseHeaderTimeout: 5 * time.Second,
TLSHandshakeTimeout: 5 * time.Second,
ExpectContinueTimeout: 5 * time.Second,
TLSClientConfig: tlsConfig,
// Go net/http automatically unzip if content-type is
// gzip disable this feature, as we are always interested
// in raw stream.
DisableCompression: true,
},
} }
defer httpClient.CloseIdleConnections() defer httpClient.CloseIdleConnections()

View File

@ -190,7 +190,13 @@ func (client *storageRESTClient) DiskInfo() (info DiskInfo, err error) {
} }
defer http.DrainBody(respBody) defer http.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info) err = gob.NewDecoder(respBody).Decode(&info)
return info, err if err != nil {
return info, err
}
if info.Error != "" {
return info, toStorageErr(errors.New(info.Error))
}
return info, nil
} }
// MakeVolBulk - create multiple volumes in a bulk operation. // MakeVolBulk - create multiple volumes in a bulk operation.

View File

@ -134,8 +134,7 @@ func (s *storageRESTServer) DiskInfoHandler(w http.ResponseWriter, r *http.Reque
} }
info, err := s.storage.DiskInfo() info, err := s.storage.DiskInfo()
if err != nil { if err != nil {
s.writeErrorResponse(w, err) info.Error = err.Error()
return
} }
defer w.(http.Flusher).Flush() defer w.(http.Flusher).Flush()
gob.NewEncoder(w).Encode(info) gob.NewEncoder(w).Encode(info)

View File

@ -36,16 +36,10 @@ import (
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
func testStorageAPIDiskInfo(t *testing.T, storage StorageAPI) { func testStorageAPIDiskInfo(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
testCases := []struct { testCases := []struct {
expectErr bool expectErr bool
}{ }{
{false}, {true},
} }
for i, testCase := range testCases { for i, testCase := range testCases {
@ -55,16 +49,13 @@ func testStorageAPIDiskInfo(t *testing.T, storage StorageAPI) {
if expectErr != testCase.expectErr { if expectErr != testCase.expectErr {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr) t.Fatalf("case %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
} }
if err != errUnformattedDisk {
t.Fatalf("case %v: error: expected: %v, got: %v", i+1, errUnformattedDisk, err)
}
} }
} }
func testStorageAPIMakeVol(t *testing.T, storage StorageAPI) { func testStorageAPIMakeVol(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
testCases := []struct { testCases := []struct {
volumeName string volumeName string
expectErr bool expectErr bool
@ -85,12 +76,6 @@ func testStorageAPIMakeVol(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIListVols(t *testing.T, storage StorageAPI) { func testStorageAPIListVols(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
testCases := []struct { testCases := []struct {
volumeNames []string volumeNames []string
expectedResult []VolInfo expectedResult []VolInfo
@ -124,12 +109,6 @@ func testStorageAPIListVols(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIStatVol(t *testing.T, storage StorageAPI) { func testStorageAPIStatVol(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -161,12 +140,6 @@ func testStorageAPIStatVol(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIDeleteVol(t *testing.T, storage StorageAPI) { func testStorageAPIDeleteVol(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -192,12 +165,6 @@ func testStorageAPIDeleteVol(t *testing.T, storage StorageAPI) {
} }
func testStorageAPICheckFile(t *testing.T, storage StorageAPI) { func testStorageAPICheckFile(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -228,12 +195,6 @@ func testStorageAPICheckFile(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIListDir(t *testing.T, storage StorageAPI) { func testStorageAPIListDir(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -271,12 +232,6 @@ func testStorageAPIListDir(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIReadAll(t *testing.T, storage StorageAPI) { func testStorageAPIReadAll(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -314,12 +269,6 @@ func testStorageAPIReadAll(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIReadFile(t *testing.T, storage StorageAPI) { func testStorageAPIReadFile(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -361,12 +310,6 @@ func testStorageAPIReadFile(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) { func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -395,12 +338,6 @@ func testStorageAPIAppendFile(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) { func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -434,12 +371,6 @@ func testStorageAPIDeleteFile(t *testing.T, storage StorageAPI) {
} }
func testStorageAPIRenameFile(t *testing.T, storage StorageAPI) { func testStorageAPIRenameFile(t *testing.T, storage StorageAPI) {
tmpGlobalServerConfig := globalServerConfig
defer func() {
globalServerConfig = tmpGlobalServerConfig
}()
globalServerConfig = newServerConfig()
err := storage.MakeVol("foo") err := storage.MakeVol("foo")
if err != nil { if err != nil {
t.Fatalf("unexpected error %v", err) t.Fatalf("unexpected error %v", err)
@ -518,9 +449,11 @@ func newStorageRESTHTTPServerClient(t *testing.T) (*httptest.Server, *storageRES
Endpoints: Endpoints{endpoint}, Endpoints: Endpoints{endpoint},
}}) }})
restClient := newStorageRESTClient(endpoint)
prevGlobalServerConfig := globalServerConfig prevGlobalServerConfig := globalServerConfig
globalServerConfig = newServerConfig() globalServerConfig = newServerConfig()
lookupConfigs(globalServerConfig)
restClient := newStorageRESTClient(endpoint)
return httpServer, restClient, prevGlobalServerConfig, endpointPath return httpServer, restClient, prevGlobalServerConfig, endpointPath
} }

View File

@ -48,8 +48,8 @@ func (p *xlStorageDiskIDCheck) Hostname() string {
} }
func (p *xlStorageDiskIDCheck) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCache) (dataUsageCache, error) { func (p *xlStorageDiskIDCheck) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCache) (dataUsageCache, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return dataUsageCache{}, errDiskNotFound return dataUsageCache{}, err
} }
return p.storage.CrawlAndGetDataUsage(ctx, cache) return p.storage.CrawlAndGetDataUsage(ctx, cache)
} }
@ -66,157 +66,178 @@ func (p *xlStorageDiskIDCheck) SetDiskID(id string) {
p.diskID = id p.diskID = id
} }
func (p *xlStorageDiskIDCheck) isDiskStale() bool { func (p *xlStorageDiskIDCheck) checkDiskStale() error {
if p.diskID == "" { if p.diskID == "" {
// For empty disk-id we allow the call as the server might be coming up and trying to read format.json // For empty disk-id we allow the call as the server might be
// or create format.json // coming up and trying to read format.json or create format.json
return false return nil
} }
storedDiskID, err := p.storage.GetDiskID() storedDiskID, err := p.storage.GetDiskID()
if err == nil && p.diskID == storedDiskID { if err != nil {
return false // return any error generated while reading `format.json`
return err
} }
return true if err == nil && p.diskID == storedDiskID {
return nil
}
// not the same disk we remember, take it offline.
return errDiskNotFound
} }
func (p *xlStorageDiskIDCheck) DiskInfo() (info DiskInfo, err error) { func (p *xlStorageDiskIDCheck) DiskInfo() (info DiskInfo, err error) {
if p.isDiskStale() { info, err = p.storage.DiskInfo()
if err != nil {
return info, err
}
if p.diskID != info.ID {
return info, errDiskNotFound return info, errDiskNotFound
} }
return p.storage.DiskInfo() return info, nil
} }
func (p *xlStorageDiskIDCheck) MakeVolBulk(volumes ...string) (err error) { func (p *xlStorageDiskIDCheck) MakeVolBulk(volumes ...string) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.MakeVolBulk(volumes...) return p.storage.MakeVolBulk(volumes...)
} }
func (p *xlStorageDiskIDCheck) MakeVol(volume string) (err error) { func (p *xlStorageDiskIDCheck) MakeVol(volume string) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.MakeVol(volume) return p.storage.MakeVol(volume)
} }
func (p *xlStorageDiskIDCheck) ListVols() ([]VolInfo, error) { func (p *xlStorageDiskIDCheck) ListVols() ([]VolInfo, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.ListVols() return p.storage.ListVols()
} }
func (p *xlStorageDiskIDCheck) StatVol(volume string) (vol VolInfo, err error) { func (p *xlStorageDiskIDCheck) StatVol(volume string) (vol VolInfo, err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return vol, errDiskNotFound return vol, err
} }
return p.storage.StatVol(volume) return p.storage.StatVol(volume)
} }
func (p *xlStorageDiskIDCheck) DeleteVol(volume string, forceDelete bool) (err error) { func (p *xlStorageDiskIDCheck) DeleteVol(volume string, forceDelete bool) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.DeleteVol(volume, forceDelete) return p.storage.DeleteVol(volume, forceDelete)
} }
func (p *xlStorageDiskIDCheck) WalkVersions(volume, dirPath string, marker string, recursive bool, endWalkCh <-chan struct{}) (chan FileInfoVersions, error) { func (p *xlStorageDiskIDCheck) WalkVersions(volume, dirPath string, marker string, recursive bool, endWalkCh <-chan struct{}) (chan FileInfoVersions, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.WalkVersions(volume, dirPath, marker, recursive, endWalkCh) return p.storage.WalkVersions(volume, dirPath, marker, recursive, endWalkCh)
} }
func (p *xlStorageDiskIDCheck) Walk(volume, dirPath string, marker string, recursive bool, endWalkCh <-chan struct{}) (chan FileInfo, error) { func (p *xlStorageDiskIDCheck) Walk(volume, dirPath string, marker string, recursive bool, endWalkCh <-chan struct{}) (chan FileInfo, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.Walk(volume, dirPath, marker, recursive, endWalkCh) return p.storage.Walk(volume, dirPath, marker, recursive, endWalkCh)
} }
func (p *xlStorageDiskIDCheck) WalkSplunk(volume, dirPath string, marker string, endWalkCh <-chan struct{}) (chan FileInfo, error) { func (p *xlStorageDiskIDCheck) WalkSplunk(volume, dirPath string, marker string, endWalkCh <-chan struct{}) (chan FileInfo, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.WalkSplunk(volume, dirPath, marker, endWalkCh) return p.storage.WalkSplunk(volume, dirPath, marker, endWalkCh)
} }
func (p *xlStorageDiskIDCheck) ListDir(volume, dirPath string, count int) ([]string, error) { func (p *xlStorageDiskIDCheck) ListDir(volume, dirPath string, count int) ([]string, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.ListDir(volume, dirPath, count) return p.storage.ListDir(volume, dirPath, count)
} }
func (p *xlStorageDiskIDCheck) ReadFile(volume string, path string, offset int64, buf []byte, verifier *BitrotVerifier) (n int64, err error) { func (p *xlStorageDiskIDCheck) ReadFile(volume string, path string, offset int64, buf []byte, verifier *BitrotVerifier) (n int64, err error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return 0, errDiskNotFound return 0, err
} }
return p.storage.ReadFile(volume, path, offset, buf, verifier) return p.storage.ReadFile(volume, path, offset, buf, verifier)
} }
func (p *xlStorageDiskIDCheck) AppendFile(volume string, path string, buf []byte) (err error) { func (p *xlStorageDiskIDCheck) AppendFile(volume string, path string, buf []byte) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.AppendFile(volume, path, buf) return p.storage.AppendFile(volume, path, buf)
} }
func (p *xlStorageDiskIDCheck) CreateFile(volume, path string, size int64, reader io.Reader) error { func (p *xlStorageDiskIDCheck) CreateFile(volume, path string, size int64, reader io.Reader) error {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.CreateFile(volume, path, size, reader) return p.storage.CreateFile(volume, path, size, reader)
} }
func (p *xlStorageDiskIDCheck) ReadFileStream(volume, path string, offset, length int64) (io.ReadCloser, error) { func (p *xlStorageDiskIDCheck) ReadFileStream(volume, path string, offset, length int64) (io.ReadCloser, error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.ReadFileStream(volume, path, offset, length) return p.storage.ReadFileStream(volume, path, offset, length)
} }
func (p *xlStorageDiskIDCheck) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) error { func (p *xlStorageDiskIDCheck) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) error {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.RenameFile(srcVolume, srcPath, dstVolume, dstPath) return p.storage.RenameFile(srcVolume, srcPath, dstVolume, dstPath)
} }
func (p *xlStorageDiskIDCheck) RenameData(srcVolume, srcPath, dataDir, dstVolume, dstPath string) error { func (p *xlStorageDiskIDCheck) RenameData(srcVolume, srcPath, dataDir, dstVolume, dstPath string) error {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.RenameData(srcVolume, srcPath, dataDir, dstVolume, dstPath) return p.storage.RenameData(srcVolume, srcPath, dataDir, dstVolume, dstPath)
} }
func (p *xlStorageDiskIDCheck) CheckParts(volume string, path string, fi FileInfo) (err error) { func (p *xlStorageDiskIDCheck) CheckParts(volume string, path string, fi FileInfo) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.CheckParts(volume, path, fi) return p.storage.CheckParts(volume, path, fi)
} }
func (p *xlStorageDiskIDCheck) CheckFile(volume string, path string) (err error) { func (p *xlStorageDiskIDCheck) CheckFile(volume string, path string) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.CheckFile(volume, path) return p.storage.CheckFile(volume, path)
} }
func (p *xlStorageDiskIDCheck) DeleteFile(volume string, path string) (err error) { func (p *xlStorageDiskIDCheck) DeleteFile(volume string, path string) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.DeleteFile(volume, path) return p.storage.DeleteFile(volume, path)
} }
func (p *xlStorageDiskIDCheck) DeleteVersions(volume string, versions []FileInfo) (errs []error) { func (p *xlStorageDiskIDCheck) DeleteVersions(volume string, versions []FileInfo) (errs []error) {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
errs = make([]error, len(versions)) errs = make([]error, len(versions))
for i := range errs { for i := range errs {
errs[i] = errDiskNotFound errs[i] = err
} }
return errs return errs
} }
@ -224,43 +245,49 @@ func (p *xlStorageDiskIDCheck) DeleteVersions(volume string, versions []FileInfo
} }
func (p *xlStorageDiskIDCheck) VerifyFile(volume, path string, fi FileInfo) error { func (p *xlStorageDiskIDCheck) VerifyFile(volume, path string, fi FileInfo) error {
if p.isDiskStale() { if err := p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.VerifyFile(volume, path, fi) return p.storage.VerifyFile(volume, path, fi)
} }
func (p *xlStorageDiskIDCheck) WriteAll(volume string, path string, reader io.Reader) (err error) { func (p *xlStorageDiskIDCheck) WriteAll(volume string, path string, reader io.Reader) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.WriteAll(volume, path, reader) return p.storage.WriteAll(volume, path, reader)
} }
func (p *xlStorageDiskIDCheck) DeleteVersion(volume, path string, fi FileInfo) (err error) { func (p *xlStorageDiskIDCheck) DeleteVersion(volume, path string, fi FileInfo) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.DeleteVersion(volume, path, fi) return p.storage.DeleteVersion(volume, path, fi)
} }
func (p *xlStorageDiskIDCheck) WriteMetadata(volume, path string, fi FileInfo) (err error) { func (p *xlStorageDiskIDCheck) WriteMetadata(volume, path string, fi FileInfo) (err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return errDiskNotFound return err
} }
return p.storage.WriteMetadata(volume, path, fi) return p.storage.WriteMetadata(volume, path, fi)
} }
func (p *xlStorageDiskIDCheck) ReadVersion(volume, path, versionID string) (fi FileInfo, err error) { func (p *xlStorageDiskIDCheck) ReadVersion(volume, path, versionID string) (fi FileInfo, err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return fi, errDiskNotFound return fi, err
} }
return p.storage.ReadVersion(volume, path, versionID) return p.storage.ReadVersion(volume, path, versionID)
} }
func (p *xlStorageDiskIDCheck) ReadAll(volume string, path string) (buf []byte, err error) { func (p *xlStorageDiskIDCheck) ReadAll(volume string, path string) (buf []byte, err error) {
if p.isDiskStale() { if err = p.checkDiskStale(); err != nil {
return nil, errDiskNotFound return nil, err
} }
return p.storage.ReadAll(volume, path) return p.storage.ReadAll(volume, path)
} }

View File

@ -86,9 +86,6 @@ func isValidVolname(volname string) bool {
// xlStorage - implements StorageAPI interface. // xlStorage - implements StorageAPI interface.
type xlStorage struct { type xlStorage struct {
// Disk usage metrics
totalUsed uint64 // ref: https://golang.org/pkg/sync/atomic/#pkg-note-BUG
maxActiveIOCount int32 maxActiveIOCount int32
activeIOCount int32 activeIOCount int32
@ -408,7 +405,10 @@ func (s *xlStorage) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCac
var totalSize int64 var totalSize int64
for _, version := range fivs.Versions { for _, version := range fivs.Versions {
size := item.applyActions(ctx, objAPI, actionMeta{numVersions: len(fivs.Versions), oi: version.ToObjectInfo(item.bucket, item.objectPath())}) size := item.applyActions(ctx, objAPI, actionMeta{
numVersions: len(fivs.Versions),
oi: version.ToObjectInfo(item.bucket, item.objectPath()),
})
if !version.Deleted { if !version.Deleted {
totalSize += size totalSize += size
} }
@ -422,12 +422,6 @@ func (s *xlStorage) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCac
} }
dataUsageInfo.Info.LastUpdate = time.Now() dataUsageInfo.Info.LastUpdate = time.Now()
total := dataUsageInfo.sizeRecursive(dataUsageInfo.Info.Name)
if total == nil {
total = &dataUsageEntry{}
}
atomic.StoreUint64(&s.totalUsed, uint64(total.Size))
return dataUsageInfo, nil return dataUsageInfo, nil
} }
@ -438,8 +432,10 @@ type DiskInfo struct {
Free uint64 Free uint64
Used uint64 Used uint64
RootDisk bool RootDisk bool
Endpoint string
MountPath string MountPath string
Error string // reports any error returned by underlying disk ID string
Error string // carries the error over the network
} }
// DiskInfo provides current information about disk space usage, // DiskInfo provides current information about disk space usage,
@ -455,23 +451,22 @@ func (s *xlStorage) DiskInfo() (info DiskInfo, err error) {
return info, err return info, err
} }
used := di.Total - di.Free
if !s.diskMount {
used = atomic.LoadUint64(&s.totalUsed)
}
rootDisk, err := disk.IsRootDisk(s.diskPath) rootDisk, err := disk.IsRootDisk(s.diskPath)
if err != nil { if err != nil {
return info, err return info, err
} }
return DiskInfo{ info = DiskInfo{
Total: di.Total, Total: di.Total,
Free: di.Free, Free: di.Free,
Used: used, Used: di.Total - di.Free,
RootDisk: rootDisk, RootDisk: rootDisk,
MountPath: s.diskPath, MountPath: s.diskPath,
}, nil }
diskID, err := s.GetDiskID()
info.ID = diskID
return info, err
} }
// getVolDir - will convert incoming volume names to // getVolDir - will convert incoming volume names to
@ -512,7 +507,17 @@ func (s *xlStorage) GetDiskID() (string, error) {
if err != nil { if err != nil {
// If the disk is still not initialized. // If the disk is still not initialized.
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "", errUnformattedDisk _, err = os.Stat(s.diskPath)
if err == nil {
// Disk is present by missing `format.json`
return "", errUnformattedDisk
}
if os.IsNotExist(err) {
return "", errDiskNotFound
} else if os.IsPermission(err) {
return "", errDiskAccessDenied
}
return "", err
} }
return "", errCorruptedFormat return "", errCorruptedFormat
} }

View File

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2017, 2018 MinIO, Inc. * MinIO Cloud Storage, (C) 2017-2020 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -99,6 +99,9 @@ const (
DriveStateOffline = "offline" DriveStateOffline = "offline"
DriveStateCorrupt = "corrupt" DriveStateCorrupt = "corrupt"
DriveStateMissing = "missing" DriveStateMissing = "missing"
DriveStatePermission = "permission-denied"
DriveStateFaulty = "faulty"
DriveStateUnknown = "unknown"
DriveStateUnformatted = "unformatted" // only returned by disk DriveStateUnformatted = "unformatted" // only returned by disk
) )

View File

@ -39,19 +39,9 @@ const (
// Add your own backend. // Add your own backend.
) )
// DriveInfo - represents each drive info, describing
// status, uuid and endpoint.
type DriveInfo HealDriveInfo
// StorageInfo - represents total capacity of underlying storage. // StorageInfo - represents total capacity of underlying storage.
type StorageInfo struct { type StorageInfo struct {
Used []uint64 // Used total used per disk. Disks []Disk
Total []uint64 // Total disk space per disk.
Available []uint64 // Total disk space available per disk.
MountPaths []string // Disk mountpoints
// Backend type. // Backend type.
Backend struct { Backend struct {
@ -65,9 +55,6 @@ type StorageInfo struct {
StandardSCParity int // Parity disks for currently configured Standard storage class. StandardSCParity int // Parity disks for currently configured Standard storage class.
RRSCData int // Data disks for currently configured Reduced Redundancy storage class. RRSCData int // Data disks for currently configured Reduced Redundancy storage class.
RRSCParity int // Parity disks for currently configured Reduced Redundancy storage class. RRSCParity int // Parity disks for currently configured Reduced Redundancy storage class.
// List of all disk status, this is only meaningful if BackendType is Erasure.
Sets [][]DriveInfo
} }
} }
@ -282,12 +269,14 @@ type ServerProperties struct {
// Disk holds Disk information // Disk holds Disk information
type Disk struct { type Disk struct {
Endpoint string `json:"endpoint,omitempty"`
DrivePath string `json:"path,omitempty"` DrivePath string `json:"path,omitempty"`
State string `json:"state,omitempty"` State string `json:"state,omitempty"`
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Model string `json:"model,omitempty"` Model string `json:"model,omitempty"`
TotalSpace uint64 `json:"totalspace,omitempty"` TotalSpace uint64 `json:"totalspace,omitempty"`
UsedSpace uint64 `json:"usedspace,omitempty"` UsedSpace uint64 `json:"usedspace,omitempty"`
AvailableSpace uint64 `json:"availspace,omitempty"`
ReadThroughput float64 `json:"readthroughput,omitempty"` ReadThroughput float64 `json:"readthroughput,omitempty"`
WriteThroughPut float64 `json:"writethroughput,omitempty"` WriteThroughPut float64 `json:"writethroughput,omitempty"`
ReadLatency float64 `json:"readlatency,omitempty"` ReadLatency float64 `json:"readlatency,omitempty"`