Coverage for drivers/resetvdis.py : 7%
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# Clear the attach status for all VDIs in the given SR on this host.
19# Additionally, reset the paused state if this host is the master.
21import cleanup
22import util
23import lock
24import sys
25import XenAPI # pylint: disable=import-error
28def reset_sr(session, host_uuid, sr_uuid, is_sr_master):
29 cleanup.abort(sr_uuid)
31 gc_lock = lock.Lock(lock.LOCK_TYPE_GC_RUNNING, sr_uuid)
32 sr_lock = lock.Lock(lock.LOCK_TYPE_SR, sr_uuid)
33 gc_lock.acquire()
34 sr_lock.acquire()
36 sr_ref = session.xenapi.SR.get_by_uuid(sr_uuid)
38 host_ref = session.xenapi.host.get_by_uuid(host_uuid)
39 host_key = "host_%s" % host_ref
41 util.SMlog("RESET for SR %s (master: %s)" % (sr_uuid, is_sr_master))
43 vdi_recs = session.xenapi.VDI.get_all_records_where( \
44 "field \"SR\" = \"%s\"" % sr_ref)
46 for vdi_ref, vdi_rec in vdi_recs.items():
47 vdi_uuid = vdi_rec["uuid"]
48 sm_config = vdi_rec["sm_config"]
49 if sm_config.get(host_key):
50 util.SMlog("Clearing attached status for VDI %s" % vdi_uuid)
51 session.xenapi.VDI.remove_from_sm_config(vdi_ref, host_key)
52 if is_sr_master and sm_config.get("paused"):
53 util.SMlog("Clearing paused status for VDI %s" % vdi_uuid)
54 session.xenapi.VDI.remove_from_sm_config(vdi_ref, "paused")
56 sr_lock.release()
57 gc_lock.release()
60def log_msg(msg, term_output=False):
61 util.SMlog(msg)
62 if term_output:
63 print(msg)
66def clean_vdi_status(session, vdi_ref, vdi_uuid, sm_config):
67 for key in [cleanup.VDI.DB_VDI_ACTIVATING, cleanup.VDI.DB_VDI_PAUSED]:
68 if key in sm_config:
69 session.xenapi.VDI.remove_from_sm_config(vdi_ref, key)
70 sm_config.pop(key, None)
71 log_msg(f"Removed key {key} from VDI {vdi_uuid}")
74def reset_vdi(session, vdi_uuid, force, term_output=True, writable=True):
75 vdi_ref = session.xenapi.VDI.get_by_uuid(vdi_uuid)
76 vdi_rec = session.xenapi.VDI.get_record(vdi_ref)
77 sm_config = vdi_rec["sm_config"]
78 host_ref = None
79 clean = True
80 for key, val in sm_config.items():
81 if key.startswith("host_"):
82 host_ref = key[len("host_"):]
83 host_uuid = None
84 host_invalid = False
85 host_str = host_ref
86 try:
87 host_rec = session.xenapi.host.get_record(host_ref)
88 host_uuid = host_rec["uuid"]
89 host_str = "%s (%s)" % (host_uuid, host_rec["name_label"])
90 except XenAPI.Failure as e:
91 log_msg(f"Invalid host: {host_ref} ({e})", term_output)
92 host_invalid = True
94 if host_invalid:
95 session.xenapi.VDI.remove_from_sm_config(vdi_ref, key)
96 log_msg(f"Invalid host: Force-cleared {val} for {vdi_uuid} on host {host_str}", term_output)
97 # If the host was invalid, pretend we didn't find if after clearing it.
98 host_ref = None
99 continue
101 if force:
102 session.xenapi.VDI.remove_from_sm_config(vdi_ref, key)
103 log_msg(f"Force-cleared {val} for {vdi_uuid} on host {host_str}", term_output)
104 # If "force" was specified, pretend we didn't find the host after clearing it.
105 host_ref = None
106 continue
108 ret = session.xenapi.host.call_plugin(host_ref, "on-slave", "is_open", {"vdiUuid": vdi_uuid, "srRef": vdi_rec["SR"]})
109 if ret == "False":
110 session.xenapi.VDI.remove_from_sm_config(vdi_ref, key)
111 log_msg(f"Cleared {val} for {vdi_uuid} on host {host_str}", term_output)
112 clean_vdi_status(session, vdi_ref, vdi_uuid, sm_config)
113 else:
114 util.SMlog(f"VDI {vdi_uuid} is still open on host {host_str}, not resetting")
115 if term_output:
116 print(f"ERROR: VDI {vdi_uuid} is still open on host {host_str}")
117 if writable:
118 return False
119 else:
120 clean = False
122 if not host_ref:
123 # Either we genuinely did not find a host record, or it was invalid or forcibly removed.
124 # Therefore we can consider the VDI as not attached and clear the status
125 clean_vdi_status(session, vdi_ref, vdi_uuid, sm_config)
126 log_msg(f"VDI {vdi_uuid} is not marked as attached anywhere", term_output)
127 return clean
130def usage():
131 print("Usage:")
132 print("all <HOST UUID> <SR UUID> [--master]")
133 print("single <VDI UUID> [--force]")
134 print()
135 print("*WARNING!* calling with 'all' on an attached SR, or using " + \
136 "--force may cause DATA CORRUPTION if the VDI is still " + \
137 "attached somewhere. Always manually double-check that " + \
138 "the VDI is not in use before running this script.")
139 sys.exit(1)
141if __name__ == '__main__': 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true
142 import atexit
144 if len(sys.argv) not in [3, 4, 5]:
145 usage()
147 session = XenAPI.xapi_local()
148 session.xenapi.login_with_password('root', '', '', 'SM')
149 atexit.register(session.xenapi.session.logout)
151 mode = sys.argv[1]
152 if mode == "all":
153 if len(sys.argv) not in [4, 5]:
154 usage()
155 host_uuid = sys.argv[2]
156 sr_uuid = sys.argv[3]
157 is_master = False
158 if len(sys.argv) == 5:
159 if sys.argv[4] == "--master":
160 is_master = True
161 else:
162 usage()
163 reset_sr(session, host_uuid, sr_uuid, is_master)
164 elif mode == "single":
165 vdi_uuid = sys.argv[2]
166 force = False
167 if len(sys.argv) == 4 and sys.argv[3] == "--force":
168 force = True
169 reset_vdi(session, vdi_uuid, force)
170 elif len(sys.argv) in [3, 4]:
171 # backwards compatibility: the arguments for the "all" case used to be
172 # just host_uuid, sr_uuid, [is_master] (i.e., no "all" string, since it
173 # was the only mode available). To avoid having to change XAPI, accept
174 # the old format here as well.
175 host_uuid = sys.argv[1]
176 sr_uuid = sys.argv[2]
177 is_master = False
178 if len(sys.argv) == 4:
179 if sys.argv[3] == "--master":
180 is_master = True
181 else:
182 usage()
183 reset_sr(session, host_uuid, sr_uuid, is_master)
184 else:
185 usage()