Coverage for drivers/on_slave.py : 64%
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 commit_tapdisk(session, args):
166 path: str = args["path"]
167 vdi_type = args["vdi_type"]
168 #TODO: naming should reflect that it does more than coalesceing, like setting volume RW
170 def set_RW(path):
171 try:
172 util.pread2(["lvchange", "-p", "rw", path])
173 except:
174 pass
175 #TODO: need to make children RW. Or we let the relink happen with a refresh on master and hope it doesn't corrupt the disk
176 if path.startswith("/dev/"):
177 set_RW(path)
179 from cowutil import getCowUtil
180 cowutil = getCowUtil(vdi_type)
181 try:
182 parent = cowutil.getParentNoCheck(path)
183 if parent.startswith("/dev/"):
184 set_RW(parent)
185 return str(cowutil.coalesceOnline(path))
186 except:
187 util.logException("Couldn't coalesce online")
188 raise
190def commit_cancel(session, args):
191 path = args["path"]
192 vdi_type = args["vdi_type"]
193 from cowutil import getCowUtil
194 cowutil = getCowUtil(vdi_type)
195 try:
196 cowutil.cancelCoalesceOnline(path)
197 except:
198 return "False"
199 return "True"
201def cancel_coalesce_master(session, args):
202 sr_uuid = args["sr_uuid"]
203 vdi_uuid = args["vdi_uuid"]
205 # from ipc import IPCFlag
206 # flag = IPCFlag(sr_uuid)
208 # runningStr = "gc_running_{}".format(vdi_uuid)
209 # abortStr = "abort_{}".format(vdi_uuid)
211 # if not flag.test(runningStr):
212 # return "True"
214 # if not flag.test(abortStr):
215 # flag.set(abortStr)
217 # while flag.test(abortStr) or flag.test(runningStr):
218 # time.sleep(1)
220 # return "True"
222 util.SMlog("Running cancel_coalesce_master plugin: {}".format(vdi_uuid))
223 path = "/run/nonpersistent/sm/{}/gc_running_{}".format(sr_uuid, vdi_uuid)
225 try:
226 with open(path, "r+") as f:
227 f.truncate(0)
228 f.flush()
229 os.fsync(f.fileno())
230 except IOError as e:
231 if e.errno == errno.ENOENT:
232 return "True"
233 raise
235 while os.path.exists(path):
236 time.sleep(1)
238 return "True"
240def is_openers(session, args):
241 path = args["path"]
242 openers_pid= util.get_openers_pid(path)
243 return str(bool(openers_pid))
245if __name__ == "__main__": 245 ↛ 246line 245 didn't jump to line 246, because the condition on line 245 was never true
246 import XenAPIPlugin
247 XenAPIPlugin.dispatch({
248 "multi": multi,
249 "is_open": is_open,
250 "refresh_lun_size_by_SCSIid": refresh_lun_size_by_SCSIid,
251 "is_openers": is_openers,
252 "commit_tapdisk": commit_tapdisk,
253 "commit_cancel": commit_cancel,
254 "cancel_coalesce_master": cancel_coalesce_master,
255 })