1
2
3
4
5
6
7
8
9
10
11
12
13
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
29
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
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
105
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
134
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
156
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
178
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
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