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

     1  /*
     2   * MinIO Cloud Storage, (C) 2020 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"net/http"
    24  	"os"
    25  	"sync"
    26  	"syscall"
    27  
    28  	cpuhw "github.com/shirou/gopsutil/v3/cpu"
    29  	memhw "github.com/shirou/gopsutil/v3/mem"
    30  	"github.com/shirou/gopsutil/v3/process"
    31  
    32  	"storj.io/minio/pkg/disk"
    33  	"storj.io/minio/pkg/madmin"
    34  )
    35  
    36  func getLocalCPUInfo(ctx context.Context, r *http.Request) madmin.ServerCPUInfo {
    37  	addr := r.Host
    38  	if globalIsDistErasure {
    39  		addr = globalLocalNodeName
    40  	}
    41  
    42  	info, err := cpuhw.InfoWithContext(ctx)
    43  	if err != nil {
    44  		return madmin.ServerCPUInfo{
    45  			Addr:  addr,
    46  			Error: fmt.Sprintf("info: %v", err),
    47  		}
    48  	}
    49  
    50  	time, err := cpuhw.TimesWithContext(ctx, false)
    51  	if err != nil {
    52  		return madmin.ServerCPUInfo{
    53  			Addr:  addr,
    54  			Error: fmt.Sprintf("times: %v", err),
    55  		}
    56  	}
    57  
    58  	return madmin.ServerCPUInfo{
    59  		Addr:     addr,
    60  		CPUStat:  info,
    61  		TimeStat: time,
    62  	}
    63  
    64  }
    65  
    66  func getLocalDrives(ctx context.Context, parallel bool, endpointServerPools EndpointServerPools, r *http.Request) madmin.ServerDrivesInfo {
    67  	var drivesPerfInfo []madmin.DrivePerfInfo
    68  	var wg sync.WaitGroup
    69  	for _, ep := range endpointServerPools {
    70  		for _, endpoint := range ep.Endpoints {
    71  			// Only proceed for local endpoints
    72  			if endpoint.IsLocal {
    73  				if _, err := os.Stat(endpoint.Path); err != nil {
    74  					// Since this drive is not available, add relevant details and proceed
    75  					drivesPerfInfo = append(drivesPerfInfo, madmin.DrivePerfInfo{
    76  						Path:  endpoint.Path,
    77  						Error: fmt.Sprintf("stat: %v", err),
    78  					})
    79  					continue
    80  				}
    81  				measurePath := pathJoin(minioMetaTmpBucket, mustGetUUID())
    82  				measure := func(path string) {
    83  					defer wg.Done()
    84  					driveInfo := madmin.DrivePerfInfo{
    85  						Path: path,
    86  					}
    87  					latency, throughput, err := disk.GetHealthInfo(ctx, path, pathJoin(path, measurePath))
    88  					if err != nil {
    89  						driveInfo.Error = fmt.Sprintf("health-info: %v", err)
    90  					} else {
    91  						driveInfo.Latency = latency
    92  						driveInfo.Throughput = throughput
    93  					}
    94  					drivesPerfInfo = append(drivesPerfInfo, driveInfo)
    95  				}
    96  				wg.Add(1)
    97  
    98  				if parallel {
    99  					go measure(endpoint.Path)
   100  				} else {
   101  					measure(endpoint.Path)
   102  				}
   103  			}
   104  		}
   105  	}
   106  	wg.Wait()
   107  
   108  	addr := r.Host
   109  	if globalIsDistErasure {
   110  		addr = globalLocalNodeName
   111  	}
   112  	if parallel {
   113  		return madmin.ServerDrivesInfo{
   114  			Addr:     addr,
   115  			Parallel: drivesPerfInfo,
   116  		}
   117  	}
   118  	return madmin.ServerDrivesInfo{
   119  		Addr:   addr,
   120  		Serial: drivesPerfInfo,
   121  	}
   122  }
   123  
   124  func getLocalMemInfo(ctx context.Context, r *http.Request) madmin.ServerMemInfo {
   125  	addr := r.Host
   126  	if globalIsDistErasure {
   127  		addr = globalLocalNodeName
   128  	}
   129  
   130  	swap, err := memhw.SwapMemoryWithContext(ctx)
   131  	if err != nil {
   132  		return madmin.ServerMemInfo{
   133  			Addr:  addr,
   134  			Error: fmt.Sprintf("swap: %v", err),
   135  		}
   136  	}
   137  
   138  	vm, err := memhw.VirtualMemoryWithContext(ctx)
   139  	if err != nil {
   140  		return madmin.ServerMemInfo{
   141  			Addr:  addr,
   142  			Error: fmt.Sprintf("virtual-mem: %v", err),
   143  		}
   144  	}
   145  
   146  	return madmin.ServerMemInfo{
   147  		Addr:       addr,
   148  		SwapMem:    swap,
   149  		VirtualMem: vm,
   150  	}
   151  }
   152  
   153  func getLocalProcInfo(ctx context.Context, r *http.Request) madmin.ServerProcInfo {
   154  	addr := r.Host
   155  	if globalIsDistErasure {
   156  		addr = globalLocalNodeName
   157  	}
   158  
   159  	errProcInfo := func(tag string, err error) madmin.ServerProcInfo {
   160  		return madmin.ServerProcInfo{
   161  			Addr:  addr,
   162  			Error: fmt.Sprintf("%s: %v", tag, err),
   163  		}
   164  	}
   165  
   166  	selfPid := int32(syscall.Getpid())
   167  	self, err := process.NewProcess(selfPid)
   168  	if err != nil {
   169  		return errProcInfo("new-process", err)
   170  	}
   171  
   172  	processes := []*process.Process{self}
   173  
   174  	sysProcs := []madmin.SysProcess{}
   175  	for _, proc := range processes {
   176  		sysProc := madmin.SysProcess{}
   177  		sysProc.Pid = proc.Pid
   178  
   179  		bg, err := proc.BackgroundWithContext(ctx)
   180  		if err != nil {
   181  			return errProcInfo("background", err)
   182  		}
   183  		sysProc.Background = bg
   184  
   185  		cpuPercent, err := proc.CPUPercentWithContext(ctx)
   186  		if err != nil {
   187  			return errProcInfo("cpu-percent", err)
   188  		}
   189  		sysProc.CPUPercent = cpuPercent
   190  
   191  		children, _ := proc.ChildrenWithContext(ctx)
   192  
   193  		for _, c := range children {
   194  			sysProc.Children = append(sysProc.Children, c.Pid)
   195  		}
   196  		cmdLine, err := proc.CmdlineWithContext(ctx)
   197  		if err != nil {
   198  			return errProcInfo("cmdline", err)
   199  		}
   200  		sysProc.CmdLine = cmdLine
   201  
   202  		conns, err := proc.ConnectionsWithContext(ctx)
   203  		if err != nil {
   204  			return errProcInfo("conns", err)
   205  		}
   206  		sysProc.ConnectionCount = len(conns)
   207  
   208  		createTime, err := proc.CreateTimeWithContext(ctx)
   209  		if err != nil {
   210  			return errProcInfo("create-time", err)
   211  		}
   212  		sysProc.CreateTime = createTime
   213  
   214  		cwd, err := proc.CwdWithContext(ctx)
   215  		if err != nil {
   216  			return errProcInfo("cwd", err)
   217  		}
   218  		sysProc.Cwd = cwd
   219  
   220  		exe, err := proc.ExeWithContext(ctx)
   221  		if err != nil {
   222  			return errProcInfo("exe", err)
   223  		}
   224  		sysProc.Exe = exe
   225  
   226  		gids, err := proc.GidsWithContext(ctx)
   227  		if err != nil {
   228  			return errProcInfo("gids", err)
   229  		}
   230  		sysProc.Gids = gids
   231  
   232  		ioCounters, err := proc.IOCountersWithContext(ctx)
   233  		if err != nil {
   234  			return errProcInfo("iocounters", err)
   235  		}
   236  		sysProc.IOCounters = ioCounters
   237  
   238  		isRunning, err := proc.IsRunningWithContext(ctx)
   239  		if err != nil {
   240  			return errProcInfo("is-running", err)
   241  		}
   242  		sysProc.IsRunning = isRunning
   243  
   244  		memInfo, err := proc.MemoryInfoWithContext(ctx)
   245  		if err != nil {
   246  			return errProcInfo("mem-info", err)
   247  		}
   248  		sysProc.MemInfo = memInfo
   249  
   250  		memMaps, err := proc.MemoryMapsWithContext(ctx, true)
   251  		if err != nil {
   252  			return errProcInfo("mem-maps", err)
   253  		}
   254  		sysProc.MemMaps = memMaps
   255  
   256  		memPercent, err := proc.MemoryPercentWithContext(ctx)
   257  		if err != nil {
   258  			return errProcInfo("mem-percent", err)
   259  		}
   260  		sysProc.MemPercent = memPercent
   261  
   262  		name, err := proc.NameWithContext(ctx)
   263  		if err != nil {
   264  			return errProcInfo("name", err)
   265  		}
   266  		sysProc.Name = name
   267  
   268  		// Refer for more information on NetIOCounters
   269  		// is useless https://github.com/shirou/gopsutil/issues/429
   270  
   271  		nice, err := proc.NiceWithContext(ctx)
   272  		if err != nil {
   273  			return errProcInfo("nice", err)
   274  		}
   275  		sysProc.Nice = nice
   276  
   277  		numCtxSwitches, err := proc.NumCtxSwitchesWithContext(ctx)
   278  		if err != nil {
   279  			return errProcInfo("num-ctx-switches", err)
   280  		}
   281  		sysProc.NumCtxSwitches = numCtxSwitches
   282  
   283  		numFds, err := proc.NumFDsWithContext(ctx)
   284  		if err != nil {
   285  			return errProcInfo("num-fds", err)
   286  		}
   287  		sysProc.NumFds = numFds
   288  
   289  		numThreads, err := proc.NumThreadsWithContext(ctx)
   290  		if err != nil {
   291  			return errProcInfo("num-threads", err)
   292  		}
   293  		sysProc.NumThreads = numThreads
   294  
   295  		pageFaults, err := proc.PageFaultsWithContext(ctx)
   296  		if err != nil {
   297  			return errProcInfo("page-faults", err)
   298  		}
   299  		sysProc.PageFaults = pageFaults
   300  
   301  		parent, err := proc.ParentWithContext(ctx)
   302  		if err == nil {
   303  			sysProc.Parent = parent.Pid
   304  		}
   305  
   306  		ppid, err := proc.PpidWithContext(ctx)
   307  		if err == nil {
   308  			sysProc.Ppid = ppid
   309  		}
   310  
   311  		status, err := proc.StatusWithContext(ctx)
   312  		if err != nil {
   313  			return errProcInfo("status", err)
   314  		}
   315  		sysProc.Status = status[0]
   316  
   317  		tgid, err := proc.Tgid()
   318  		if err != nil {
   319  			return errProcInfo("tgid", err)
   320  		}
   321  		sysProc.Tgid = tgid
   322  
   323  		times, err := proc.TimesWithContext(ctx)
   324  		if err != nil {
   325  			return errProcInfo("times", err)
   326  		}
   327  		sysProc.Times = times
   328  
   329  		uids, err := proc.UidsWithContext(ctx)
   330  		if err != nil {
   331  			return errProcInfo("uids", err)
   332  		}
   333  		sysProc.Uids = uids
   334  
   335  		username, err := proc.UsernameWithContext(ctx)
   336  		if err != nil {
   337  			return errProcInfo("username", err)
   338  		}
   339  		sysProc.Username = username
   340  
   341  		sysProcs = append(sysProcs, sysProc)
   342  	}
   343  
   344  	return madmin.ServerProcInfo{
   345  		Addr:      addr,
   346  		Processes: sysProcs,
   347  	}
   348  }