Coverage for drivers/on_slave.py : 63%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/python3
2#
3# Copyright (C) Citrix Systems Inc.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published
7# by the Free Software Foundation; version 2.1 only.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17#
18# A plugin for synchronizing slaves when something changes on the Master
20import sys
21import os
22import time
23import errno
24sys.path.append("/opt/xensource/sm/")
25import util
26import lock
27from lvmcache import LVMCache
28import scsiutil
31def multi(session, args):
32 """Perform several actions in one call (to save on round trips)"""
33 util.SMlog("on-slave.multi: %s" % args)
34 vgName = args["vgName"]
35 lvmCache = LVMCache(vgName)
36 i = 1
37 while True:
38 action = args.get("action%d" % i)
39 if not action:
40 break
41 util.SMlog("on-slave.action %d: %s" % (i, action))
42 if action == "activate":
43 try:
44 lvmCache.activate(args["ns%d" % i], args["uuid%d" % i],
45 args["lvName%d" % i], False)
46 except util.CommandException:
47 util.SMlog("on-slave.activate failed")
48 raise
49 elif action == "deactivate":
50 try:
51 lvmCache.deactivate(args["ns%d" % i], args["uuid%d" % i],
52 args["lvName%d" % i], False)
53 except util.SMException:
54 util.SMlog("on-slave.deactivate failed")
55 raise
56 elif action == "deactivateNoRefcount":
57 try:
58 lvmCache.deactivateNoRefcount(args["lvName%d" % i])
59 except util.SMException:
60 util.SMlog("on-slave.deactivateNoRefcount failed")
61 raise
62 elif action == "refresh":
63 try:
64 lvmCache.activateNoRefcount(args["lvName%d" % i], True)
65 except util.CommandException:
66 util.SMlog("on-slave.refresh failed")
67 raise
68 elif action == "cleanupLockAndRefcount":
69 from refcounter import RefCounter
70 lock.Lock.cleanup(args["uuid%d" % i], args["ns%d" % i])
71 RefCounter.reset(args["uuid%d" % i], args["ns%d" % i])
72 else:
73 raise util.SMException("unrecognized action: %s" % action)
74 i += 1
75 return str(True)
78def _is_open(session, args):
79 """Check if VDI <args["vdiUuid"]> is open by a tapdisk on this host"""
80 import SRCommand
81 import SR
82 import CephFSSR
83 import EXTSR
84 import LargeBlockSR
85 import GlusterFSSR
86 import LinstorSR
87 import LVMSR
88 import MooseFSSR
89 import NFSSR
90 import XFSSR
91 import ZFSSR
92 import blktap2
94 util.SMlog("on-slave.is_open: %s" % args)
95 vdiUuid = args["vdiUuid"]
96 srRef = args["srRef"]
97 srRec = session.xenapi.SR.get_record(srRef)
98 srType = srRec["type"]
100 # FIXME: ugly hacks to create a VDI object without a real SRCommand to
101 # avoid having to refactor the core files
102 if srType.startswith("lvm"):
103 srType = "lvm"
104 cmd = SRCommand.SRCommand(None)
105 cmd.driver_info = {"capabilities": None}
106 cmd.dconf = {
107 "server": None,
108 "device": "/HACK",
109 # Hack for custom XCP-ng drivers.
110 "masterhost": None, # MooseFS
111 "rootpath": None, # MooseFS
112 "serverpath": None, # CephFS
113 "location": "/HACK" # ZFS
114 }
115 cmd.params = {"command": None}
117 sr_uuid = srRec["uuid"]
119 # Another ugly piece of code to load a real Linstor SR, otherwise
120 # we can't fetch the VDI path.
121 if srType == 'linstor': 121 ↛ 122line 121 didn't jump to line 122, because the condition on line 121 was never true
122 host_ref = util.get_this_host_ref(session)
123 sr_ref = session.xenapi.SR.get_by_uuid(sr_uuid)
125 pbd = util.find_my_pbd(session, host_ref, sr_ref)
126 if pbd is None:
127 raise util.SMException('Failed to find Linstor PBD')
129 cmd.dconf = session.xenapi.PBD.get_device_config(pbd)
131 driver = SR.driver(srType)
132 sr = driver(cmd, sr_uuid)
134 # session_ref param is required to have a valid session when SR object is created.
135 # It's not the case here, so attach the current session object to make LinstorSR happy.
136 if srType == 'linstor': 136 ↛ 137line 136 didn't jump to line 137, because the condition on line 136 was never true
137 sr.session = session
139 vdi = sr.vdi(vdiUuid)
140 tapdisk = blktap2.Tapdisk.find_by_path(vdi.path)
141 util.SMlog("Tapdisk for %s: %s" % (vdi.path, tapdisk))
142 if tapdisk:
143 return "True"
144 return "False"
147def is_open(session, args):
148 try:
149 return _is_open(session, args)
150 except:
151 util.logException("is_open")
152 raise
154def refresh_lun_size_by_SCSIid(session, args):
155 """Refresh the size of LUNs backing the SCSIid on the local node."""
156 util.SMlog("on-slave.refresh_lun_size_by_SCSIid(,%s)" % args)
157 if scsiutil.refresh_lun_size_by_SCSIid(args['SCSIid']):
158 util.SMlog("on-slave.refresh_lun_size_by_SCSIid with %s succeeded"
159 % args)
160 return "True"
161 else:
162 util.SMlog("on-slave.refresh_lun_size_by_SCSIid with %s failed" % args)
163 return "False"
165def _make_chain_RW(cowutil, leaf_path, write: bool):
166 def set_RW(path):
167 try:
168 util.pread2(["lvchange", "-p", "rw", path])
169 except:
170 pass
172 # if path.startswith("/dev/"):
173 # set_RW(leaf_path) # Not needed since it's a leaf
175 parent = cowutil.getParentNoCheck(leaf_path)
176 while parent:
177 if parent.startswith("/dev/"):
178 set_RW(parent)
179 parent = cowutil.getParentNoCheck(parent)
181def commit_tapdisk(session, args):
182 path: str = args["path"]
183 vdi_type = args["vdi_type"]
184 leaf_path: str = args["leaf_path"] # The path of the leaf used by the tapdisk
186 from cowutil import getCowUtil
187 cowutil = getCowUtil(vdi_type)
188 try:
189 if path.startswith("/dev/"):
190 # We need to make children RW or tapdisk will crash trying to do it
191 _make_chain_RW(cowutil, leaf_path, True)
192 return str(cowutil.coalesceOnline(path))
193 except:
194 util.logException("Couldn't coalesce online")
195 raise
197def commit_cancel(session, args):
198 path = args["path"]
199 vdi_type = args["vdi_type"]
200 from cowutil import getCowUtil
201 cowutil = getCowUtil(vdi_type)
202 try:
203 cowutil.cancelCoalesceOnline(path)
204 except:
205 return "False"
206 return "True"
208def cancel_coalesce_master(session, args):
209 sr_uuid = args["sr_uuid"]
210 vdi_uuid = args["vdi_uuid"]
212 # from ipc import IPCFlag
213 # flag = IPCFlag(sr_uuid)
215 # runningStr = "gc_running_{}".format(vdi_uuid)
216 # abortStr = "abort_{}".format(vdi_uuid)
218 # if not flag.test(runningStr):
219 # return "True"
221 # if not flag.test(abortStr):
222 # flag.set(abortStr)
224 # while flag.test(abortStr) or flag.test(runningStr):
225 # time.sleep(1)
227 # return "True"
229 util.SMlog("Running cancel_coalesce_master plugin: {}".format(vdi_uuid))
230 path = "/run/nonpersistent/sm/{}/gc_running_{}".format(sr_uuid, vdi_uuid)
232 try:
233 with open(path, "r+") as f:
234 f.truncate(0)
235 f.flush()
236 os.fsync(f.fileno())
237 except IOError as e:
238 if e.errno == errno.ENOENT:
239 return "True"
240 raise
242 while os.path.exists(path):
243 time.sleep(1)
245 return "True"
247def is_openers(session, args):
248 path = args["path"]
249 openers_pid= util.get_openers_pid(path)
250 return str(bool(openers_pid))
252if __name__ == "__main__": 252 ↛ 253line 252 didn't jump to line 253, because the condition on line 252 was never true
253 import XenAPIPlugin
254 XenAPIPlugin.dispatch({
255 "multi": multi,
256 "is_open": is_open,
257 "refresh_lun_size_by_SCSIid": refresh_lun_size_by_SCSIid,
258 "is_openers": is_openers,
259 "commit_tapdisk": commit_tapdisk,
260 "commit_cancel": commit_cancel,
261 "cancel_coalesce_master": cancel_coalesce_master,
262 })