Hide keyboard shortcuts

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. 

20 

21import cleanup 

22import util 

23import lock 

24import sys 

25import XenAPI # pylint: disable=import-error 

26 

27 

28def reset_sr(session, host_uuid, sr_uuid, is_sr_master): 

29 cleanup.abort(sr_uuid) 

30 

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() 

35 

36 sr_ref = session.xenapi.SR.get_by_uuid(sr_uuid) 

37 

38 host_ref = session.xenapi.host.get_by_uuid(host_uuid) 

39 host_key = "host_%s" % host_ref 

40 

41 util.SMlog("RESET for SR %s (master: %s)" % (sr_uuid, is_sr_master)) 

42 

43 vdi_recs = session.xenapi.VDI.get_all_records_where( \ 

44 "field \"SR\" = \"%s\"" % sr_ref) 

45 

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") 

55 

56 sr_lock.release() 

57 gc_lock.release() 

58 

59 

60def log_msg(msg, term_output=False): 

61 util.SMlog(msg) 

62 if term_output: 

63 print(msg) 

64 

65 

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}") 

72 

73 

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 

93 

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 

100 

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 

107 

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 

121 

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 

128 

129 

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) 

140 

141if __name__ == '__main__': 141 ↛ 142line 141 didn't jump to line 142, because the condition on line 141 was never true

142 import atexit 

143 

144 if len(sys.argv) not in [3, 4, 5]: 

145 usage() 

146 

147 session = XenAPI.xapi_local() 

148 session.xenapi.login_with_password('root', '', '', 'SM') 

149 atexit.register(session.xenapi.session.logout) 

150 

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()