...

Source file src/github.com/prometheus/procfs/iscsi/get.go

Documentation: github.com/prometheus/procfs/iscsi

     1  // Copyright 2019 The Prometheus Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package iscsi
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"os"
    21  	"path/filepath"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/prometheus/procfs/internal/util"
    26  )
    27  
    28  // GetStats is the main iscsi status information func for
    29  // building the path and prepare info for enable iscsi.
    30  func GetStats(iqnPath string) (*Stats, error) {
    31  	var istats Stats
    32  
    33  	istats.Name = filepath.Base(iqnPath)
    34  	istats.RootPath = filepath.Dir(iqnPath)
    35  
    36  	matches, err := filepath.Glob(filepath.Join(iqnPath, "tpgt*"))
    37  	if err != nil {
    38  		return nil, fmt.Errorf("iscsi: GetStats: get TPGT path error %w", err)
    39  	}
    40  	istats.Tpgt = make([]TPGT, len(matches))
    41  
    42  	for i, tpgtPath := range matches {
    43  		istats.Tpgt[i].Name = filepath.Base(tpgtPath)
    44  		istats.Tpgt[i].TpgtPath = tpgtPath
    45  		istats.Tpgt[i].IsEnable, _ = isPathEnable(tpgtPath)
    46  		if istats.Tpgt[i].IsEnable {
    47  			matchesLunsPath, _ := filepath.Glob(filepath.Join(tpgtPath, "lun/lun*"))
    48  
    49  			for _, lunPath := range matchesLunsPath {
    50  				lun, err := getLunLinkTarget(lunPath)
    51  				if err == nil {
    52  					istats.Tpgt[i].Luns = append(istats.Tpgt[i].Luns, lun)
    53  				}
    54  			}
    55  		}
    56  	}
    57  	return &istats, nil
    58  }
    59  
    60  // isPathEnable checks if the file "enable" contain enable message.
    61  func isPathEnable(path string) (bool, error) {
    62  	enableReadout, err := os.ReadFile(filepath.Join(path, "enable"))
    63  	if err != nil {
    64  		return false, fmt.Errorf("iscsi: isPathEnable ReadFile error %w", err)
    65  	}
    66  	isEnable, err := strconv.ParseBool(strings.TrimSpace(string(enableReadout)))
    67  	if err != nil {
    68  		return false, fmt.Errorf("iscsi: isPathEnable ParseBool error %w", err)
    69  	}
    70  	return isEnable, nil
    71  }
    72  
    73  func getLunLinkTarget(lunPath string) (lunObject LUN, err error) {
    74  	lunObject.Name = filepath.Base(lunPath)
    75  	lunObject.LunPath = lunPath
    76  	files, err := os.ReadDir(lunPath)
    77  	if err != nil {
    78  		return lunObject, fmt.Errorf("getLunLinkTarget: ReadDir path %q: %w", lunPath, err)
    79  	}
    80  	for _, file := range files {
    81  		fileInfo, _ := os.Lstat(filepath.Join(lunPath, file.Name()))
    82  		if fileInfo.Mode()&os.ModeSymlink != 0 {
    83  			target, err := os.Readlink(filepath.Join(lunPath, fileInfo.Name()))
    84  			if err != nil {
    85  				return lunObject, fmt.Errorf("getLunLinkTarget: Readlink: %w", err)
    86  			}
    87  			targetPath, objectName := filepath.Split(target)
    88  			_, typeWithNumber := filepath.Split(filepath.Clean(targetPath))
    89  
    90  			underscore := strings.LastIndex(typeWithNumber, "_")
    91  
    92  			if underscore != -1 {
    93  				lunObject.Backstore = typeWithNumber[:underscore]
    94  				lunObject.TypeNumber = typeWithNumber[underscore+1:]
    95  			}
    96  
    97  			lunObject.ObjectName = objectName
    98  			return lunObject, nil
    99  		}
   100  	}
   101  	return lunObject, errors.New("iscsi: getLunLinkTarget: Lun Link does not exist")
   102  }
   103  
   104  // ReadWriteOPS read and return the stat of read and write in megabytes,
   105  // and total commands that send to the target.
   106  func ReadWriteOPS(iqnPath string, tpgt string, lun string) (readmb uint64,
   107  	writemb uint64, iops uint64, err error) {
   108  
   109  	readmbPath := filepath.Join(iqnPath, tpgt, "lun", lun,
   110  		"statistics/scsi_tgt_port/read_mbytes")
   111  	readmb, err = util.ReadUintFromFile(readmbPath)
   112  	if err != nil {
   113  		return 0, 0, 0, fmt.Errorf("iscsi: ReadWriteOPS: read_mbytes error file %q: %w", readmbPath, err)
   114  	}
   115  
   116  	writembPath := filepath.Join(iqnPath, tpgt, "lun", lun,
   117  		"statistics/scsi_tgt_port/write_mbytes")
   118  	writemb, err = util.ReadUintFromFile(writembPath)
   119  	if err != nil {
   120  		return 0, 0, 0, fmt.Errorf("iscsi: ReadWriteOPS: write_mbytes error file %q: %w", writembPath, err)
   121  	}
   122  
   123  	iopsPath := filepath.Join(iqnPath, tpgt, "lun", lun,
   124  		"statistics/scsi_tgt_port/in_cmds")
   125  	iops, err = util.ReadUintFromFile(iopsPath)
   126  	if err != nil {
   127  		return 0, 0, 0, fmt.Errorf("iscsi: ReadWriteOPS: in_cmds error file %q: %w", iopsPath, err)
   128  	}
   129  
   130  	return readmb, writemb, iops, nil
   131  }
   132  
   133  // GetFileioUdev is getting the actual info to build up
   134  // the FILEIO data and match with the enable target.
   135  func (fs FS) GetFileioUdev(fileioNumber string, objectName string) (*FILEIO, error) {
   136  	fileio := FILEIO{
   137  		Name:       "fileio_" + fileioNumber,
   138  		Fnumber:    fileioNumber,
   139  		ObjectName: objectName,
   140  	}
   141  	udevPath := fs.configfs.Path(targetCore, fileio.Name, fileio.ObjectName, "udev_path")
   142  
   143  	if _, err := os.Stat(udevPath); os.IsNotExist(err) {
   144  		return nil, fmt.Errorf("iscsi: GetFileioUdev: fileio_%s is missing file name", fileio.Fnumber)
   145  	}
   146  	filename, err := os.ReadFile(udevPath)
   147  	if err != nil {
   148  		return nil, fmt.Errorf("iscsi: GetFileioUdev: Cannot read filename from udev link %q", udevPath)
   149  	}
   150  	fileio.Filename = strings.TrimSpace(string(filename))
   151  
   152  	return &fileio, nil
   153  }
   154  
   155  // GetIblockUdev is getting the actual info to build up
   156  // the IBLOCK data and match with the enable target.
   157  func (fs FS) GetIblockUdev(iblockNumber string, objectName string) (*IBLOCK, error) {
   158  	iblock := IBLOCK{
   159  		Name:       "iblock_" + iblockNumber,
   160  		Bnumber:    iblockNumber,
   161  		ObjectName: objectName,
   162  	}
   163  	udevPath := fs.configfs.Path(targetCore, iblock.Name, iblock.ObjectName, "udev_path")
   164  
   165  	if _, err := os.Stat(udevPath); os.IsNotExist(err) {
   166  		return nil, fmt.Errorf("iscsi: GetIBlockUdev: iblock_%s is missing file name", iblock.Bnumber)
   167  	}
   168  	filename, err := os.ReadFile(udevPath)
   169  	if err != nil {
   170  		return nil, fmt.Errorf("iscsi: GetIBlockUdev: Cannot read iblock from udev link %q", udevPath)
   171  	}
   172  	iblock.Iblock = strings.TrimSpace(string(filename))
   173  
   174  	return &iblock, nil
   175  }
   176  
   177  // GetRBDMatch is getting the actual info to build up
   178  // the RBD data and match with the enable target.
   179  func (fs FS) GetRBDMatch(rbdNumber string, poolImage string) (*RBD, error) {
   180  	rbd := RBD{
   181  		Name:    "rbd_" + rbdNumber,
   182  		Rnumber: rbdNumber,
   183  	}
   184  	systemRbds, err := filepath.Glob(fs.sysfs.Path(devicePath, "[0-9]*"))
   185  	if err != nil {
   186  		return nil, fmt.Errorf("iscsi: GetRBDMatch: Cannot find any rbd block")
   187  	}
   188  
   189  	for systemRbdNumber, systemRbdPath := range systemRbds {
   190  		var systemPool, systemImage string
   191  		systemPoolPath := filepath.Join(systemRbdPath, "pool")
   192  		if _, err := os.Stat(systemPoolPath); os.IsNotExist(err) {
   193  			continue
   194  		}
   195  		bSystemPool, err := os.ReadFile(systemPoolPath)
   196  		if err != nil {
   197  			continue
   198  		}
   199  		systemPool = strings.TrimSpace(string(bSystemPool))
   200  
   201  		systemImagePath := filepath.Join(systemRbdPath, "name")
   202  		if _, err := os.Stat(systemImagePath); os.IsNotExist(err) {
   203  			continue
   204  		}
   205  		bSystemImage, err := os.ReadFile(systemImagePath)
   206  		if err != nil {
   207  			continue
   208  		}
   209  		systemImage = strings.TrimSpace(string(bSystemImage))
   210  
   211  		if strings.Compare(strconv.FormatInt(int64(systemRbdNumber), 10), rbdNumber) == 0 &&
   212  			matchPoolImage(systemPool, systemImage, poolImage) {
   213  			rbd.Pool = systemPool
   214  			rbd.Image = systemImage
   215  			return &rbd, nil
   216  		}
   217  	}
   218  	return nil, nil
   219  }
   220  
   221  // GetRDMCPPath is getting the actual info to build up RDMCP data.
   222  func (fs FS) GetRDMCPPath(rdmcpNumber string, objectName string) (*RDMCP, error) {
   223  	rdmcp := RDMCP{
   224  		Name:       "rd_mcp_" + rdmcpNumber,
   225  		ObjectName: objectName,
   226  	}
   227  	rdmcpPath := fs.configfs.Path(targetCore, rdmcp.Name, rdmcp.ObjectName)
   228  
   229  	if _, err := os.Stat(rdmcpPath); os.IsNotExist(err) {
   230  		return nil, fmt.Errorf("iscsi: GetRDMCPPath %q does not exist", rdmcpPath)
   231  	}
   232  	isEnable, err := isPathEnable(rdmcpPath)
   233  	if err != nil {
   234  		return nil, fmt.Errorf("iscsi: GetRDMCPPath: error %w", err)
   235  	}
   236  	if isEnable {
   237  		return &rdmcp, nil
   238  	}
   239  	return nil, nil
   240  }
   241  
   242  func matchPoolImage(pool string, image string, matchPoolImage string) (isEqual bool) {
   243  	var poolImage = fmt.Sprintf("%s-%s", pool, image)
   244  	return strings.Compare(poolImage, matchPoolImage) == 0
   245  }
   246  

View as plain text