15
15
# along with this program; if not, write to the Free Software Foundation, Inc.,
16
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18
- from sm .core import util
19
18
import os
20
19
import sys
21
20
import re
22
- from sm .core import xs_errors
23
- from sm .core import mpath_cli
24
21
import json
25
22
import subprocess
26
23
27
- supported = ['iscsi' , 'lvmoiscsi' , 'rawhba' , 'lvmohba' , 'ocfsohba' , 'ocfsoiscsi' , 'netapp' , 'gfs2' ]
28
-
29
- LOCK_TYPE_HOST = "host"
30
- LOCK_NS1 = "mpathcount1"
31
- LOCK_NS2 = "mpathcount2"
32
-
33
- MAPPER_DIR = "/dev/mapper"
34
- MPATHS_DIR = "/dev/shm"
35
- MPATH_FILE_NAME = "/dev/shm/mpath_status"
36
- match_bySCSIid = False
37
- mpath_enabled = True
38
- SCSIid = 'NOTSUPPLIED'
39
- XAPI_HEALTH_CHECK = '/opt/xensource/libexec/xapi-health-check'
40
-
41
- cached_DM_maj = None
42
-
43
- def get_dm_major ():
44
- global cached_DM_maj
45
- if not cached_DM_maj :
46
- try :
47
- line = [x for x in open ('/proc/devices' ).readlines () if x .endswith ('device-mapper\n ' )]
48
- cached_DM_maj = int (line [0 ].split ()[0 ])
49
- except :
50
- pass
51
- return cached_DM_maj
52
-
53
-
54
- def mpc_exit (session , code ):
55
- if session is not None :
56
- try :
57
- session .xenapi .session .logout ()
58
- except :
59
- pass
60
- sys .exit (code )
61
-
62
-
63
- def match_host_id (s ):
64
- regex = re .compile ("^INSTALLATION_UUID" )
65
- return regex .search (s , 0 )
66
-
67
-
68
- def get_localhost_uuid ():
69
- filename = '/etc/xensource-inventory'
70
- try :
71
- f = open (filename , 'r' )
72
- except :
73
- raise xs_errors .XenError ('EIO' , \
74
- opterr = "Unable to open inventory file [%s]" % filename )
75
- domid = ''
76
- for line in filter (match_host_id , f .readlines ()):
77
- domid = line .split ("'" )[1 ]
78
- return domid
79
-
80
-
81
- def match_dmpLUN (s ):
82
- regex = re .compile ("[0-9]*:[0-9]*:[0-9]*:[0-9]*" )
83
- return regex .search (s , 0 )
84
-
85
-
86
- def match_pathup (s ):
87
- path_status = None
88
- match = re .match (r'.*\d+:\d+:\d+:\d+\s+\S+\s+\S+\s+\S+\s+(\S+)' , s )
89
- if match :
90
- path_status = match .group (1 )
91
- if path_status in ['faulty' , 'shaky' , 'failed' ]:
92
- return False
93
- return True
94
-
95
-
96
- def _tostring (l ):
97
- return str (l )
98
-
99
-
100
- def get_path_count (SCSIid ):
101
- count = 0
102
- total = 0
103
- lines = mpath_cli .get_topology (SCSIid )
104
- for line in filter (match_dmpLUN , lines ):
105
- total += 1
106
- if match_pathup (line ):
107
- count += 1
108
- return (count , total )
109
-
110
-
111
- def get_root_dev_major ():
112
- buf = os .stat ('/' )
113
- devno = buf .st_dev
114
- return os .major (devno )
115
-
116
-
117
- # @key: key to update
118
- # @SCSIid: SCSI id of multipath map
119
- # @entry: string representing previous value
120
- # @remove: callback to remove key
121
- # @add: callback to add key/value pair
122
- # @mpath_status: map to record multipath status
123
- def update_config (key , SCSIid , entry , remove , add , mpath_status = None ):
124
- path = os .path .join (MAPPER_DIR , SCSIid )
125
- util .SMlog ("MPATH: Updating entry for [%s], current: %s" % (SCSIid , entry ))
126
- if os .path .exists (path ):
127
- count , total = get_path_count (SCSIid )
128
- max = 0
129
- if len (entry ) != 0 :
130
- try :
131
- p = entry .strip ('[' )
132
- p = p .strip (']' )
133
- q = p .split (',' )
134
- max = int (q [1 ])
135
- except :
136
- pass
137
- if total > max :
138
- max = total
139
- newentry = [count , max ]
140
- if str (newentry ) != entry :
141
- remove ('multipathed' )
142
- remove (key )
143
- add ('multipathed' , 'true' )
144
- add (key , str (newentry ))
145
- util .SMlog ("MPATH: Set val: %s" % str (newentry ))
146
- if mpath_status != None :
147
- mpath_status .update ({str (key ): f"{ count } /{ max } " })
148
- else :
149
- util .SMlog ('MPATH: device %s gone' % (SCSIid ))
150
- remove ('multipathed' )
151
- remove (key )
152
-
153
-
154
- def get_SCSIidlist (devconfig , sm_config ):
155
- SCSIidlist = []
156
- if 'SCSIid' in sm_config :
157
- SCSIidlist = sm_config ['SCSIid' ].split (',' )
158
- elif 'SCSIid' in devconfig :
159
- SCSIidlist .append (devconfig ['SCSIid' ])
160
- elif 'provider' in devconfig :
161
- SCSIidlist .append (devconfig ['ScsiId' ])
162
- else :
163
- for key in sm_config :
164
- if util ._isSCSIid (key ):
165
- SCSIidlist .append (re .sub ("^scsi-" , "" , key ))
166
- return SCSIidlist
167
-
168
-
169
- def check_root_disk (config , maps , remove , add ):
170
- if get_root_dev_major () == get_dm_major ():
171
- # Ensure output headers are not in the list
172
- if 'name' in maps :
173
- maps .remove ('name' )
174
- # first map will always correspond to the root dev, dm-0
175
- assert (len (maps ) > 0 )
176
- i = maps [0 ]
177
- if (not match_bySCSIid ) or i == SCSIid :
178
- util .SMlog ("Matched SCSIid %s, updating " \
179
- " Host.other-config:mpath-boot " % i )
180
- key = "mpath-boot"
181
- if key not in config :
182
- update_config (key , i , "" , remove , add )
183
- else :
184
- update_config (key , i , config [key ], remove , add )
185
-
186
-
187
- def check_devconfig (devconfig , sm_config , config , remove , add , mpath_status = None ):
188
- SCSIidlist = get_SCSIidlist (devconfig , sm_config )
189
- if not len (SCSIidlist ):
190
- return
191
- for i in SCSIidlist :
192
- if match_bySCSIid and i != SCSIid :
193
- continue
194
- util .SMlog ("Matched SCSIid, updating %s" % i )
195
- key = "mpath-" + i
196
- if not mpath_enabled :
197
- remove (key )
198
- remove ('multipathed' )
199
- else :
200
- if key not in config :
201
- update_config (key , i , "" , remove , add , mpath_status )
202
- else :
203
- update_config (key , i , config [key ], remove , add , mpath_status )
204
-
205
- def check_xapi_is_enabled ():
206
- """Check XAPI health status"""
207
- def _run_command (command , timeout ):
208
- try :
209
- process = subprocess .Popen (
210
- command ,
211
- stdout = subprocess .PIPE ,
212
- stderr = subprocess .PIPE ,
213
- universal_newlines = True
214
- )
215
- try :
216
- stdout , stderr = process .communicate (timeout = timeout )
217
- return process .returncode , stdout , stderr
218
- except subprocess .TimeoutExpired :
219
- process .kill ()
220
- util .SMlog (f"Command execution timeout after { timeout } s: { ' ' .join (command )} " )
221
- return - 1 , "" , "Timeout"
222
- except Exception as e :
223
- util .SMlog (f"Error executing command: { e } " )
224
- return - 1 , "" , str (e )
225
-
226
- returncode , _ , stderr = _run_command ([XAPI_HEALTH_CHECK ], timeout = 120 )
227
- if returncode != 0 :
228
- util .SMlog (f"XAPI health check failed: { stderr } " )
229
- return returncode == 0
24
+ from sm .core import util
25
+ from sm .core import xs_errors
26
+ from sm .core import mpath_cli
27
+ from sm import mpathcount
230
28
231
29
if __name__ == '__main__' :
232
30
try :
@@ -235,16 +33,16 @@ if __name__ == '__main__':
235
33
print ("Unable to open local XAPI session" )
236
34
sys .exit (- 1 )
237
35
238
- localhost = session .xenapi .host .get_by_uuid (get_localhost_uuid ())
239
- check_xapi_is_enabled ()
36
+ localhost = session .xenapi .host .get_by_uuid (mpathcount . get_localhost_uuid ())
37
+ mpathcount . check_xapi_is_enabled ()
240
38
# Check whether multipathing is enabled (either for root dev or SRs)
241
39
try :
242
- if get_root_dev_major () != get_dm_major ():
40
+ if mpathcount . get_root_dev_major () != mpathcount . get_dm_major ():
243
41
hconf = session .xenapi .host .get_other_config (localhost )
244
42
assert (hconf ['multipathing' ] == 'true' )
245
- mpath_enabled = True
43
+ mpathcount . mpath_enabled = True
246
44
except :
247
- mpath_enabled = False
45
+ mpathcount . mpath_enabled = False
248
46
249
47
# Check root disk if multipathed
250
48
try :
@@ -256,16 +54,16 @@ if __name__ == '__main__':
256
54
session .xenapi .host .add_to_other_config (localhost , key , val )
257
55
config = session .xenapi .host .get_other_config (localhost )
258
56
maps = mpath_cli .list_maps ()
259
- check_root_disk (config , maps , _remove , _add )
57
+ mpathcount . check_root_disk (config , maps , _remove , _add )
260
58
261
59
except :
262
60
util .SMlog ("MPATH: Failure updating Host.other-config:mpath-boot db" )
263
- mpc_exit (session , - 1 )
61
+ mpathcount . mpc_exit (session , - 1 )
264
62
265
63
try :
266
64
pbds = session .xenapi .PBD .get_all_records_where ("field \" host\" = \" %s\" " % localhost )
267
65
except :
268
- mpc_exit (session , - 1 )
66
+ mpathcount . mpc_exit (session , - 1 )
269
67
270
68
try :
271
69
mpath_status = {}
@@ -280,17 +78,17 @@ if __name__ == '__main__':
280
78
config = record ['other_config' ]
281
79
SR = record ['SR' ]
282
80
srtype = session .xenapi .SR .get_type (SR )
283
- if srtype in supported :
81
+ if srtype in mpathcount . supported :
284
82
devconfig = record ["device_config" ]
285
83
sm_config = session .xenapi .SR .get_sm_config (SR )
286
- check_devconfig (devconfig , sm_config , config , remove , add , mpath_status )
287
- mpath_status = mpath_status if mpath_enabled else {}
288
- util .atomicFileWrite (MPATH_FILE_NAME , MPATHS_DIR , json .dumps (mpath_status ))
289
- os .chmod (MPATH_FILE_NAME , 0o0644 )
84
+ mpathcount . check_devconfig (devconfig , sm_config , config , remove , add , mpath_status )
85
+ mpath_status = mpath_status if mpathcount . mpath_enabled else {}
86
+ util .atomicFileWrite (mpathcount . MPATH_FILE_NAME , mpathcount . MPATHS_DIR , json .dumps (mpath_status ))
87
+ os .chmod (mpathcount . MPATH_FILE_NAME , 0o0644 )
290
88
except :
291
89
util .SMlog ("MPATH: Failure updating db. %s" % sys .exc_info ())
292
- mpc_exit (session , - 1 )
90
+ mpathcount . mpc_exit (session , - 1 )
293
91
294
92
util .SMlog ("MPATH: Update done" )
295
93
296
- mpc_exit (session , 0 )
94
+ mpathcount . mpc_exit (session , 0 )
0 commit comments