root / lib / cmdlib / misc.py @ 31d3b918
History | View | Annotate | Download (14.1 kB)
1 | 814386b7 | Thomas Thrainer | #
|
---|---|---|---|
2 | 814386b7 | Thomas Thrainer | #
|
3 | 814386b7 | Thomas Thrainer | |
4 | 814386b7 | Thomas Thrainer | # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
|
5 | 814386b7 | Thomas Thrainer | #
|
6 | 814386b7 | Thomas Thrainer | # This program is free software; you can redistribute it and/or modify
|
7 | 814386b7 | Thomas Thrainer | # it under the terms of the GNU General Public License as published by
|
8 | 814386b7 | Thomas Thrainer | # the Free Software Foundation; either version 2 of the License, or
|
9 | 814386b7 | Thomas Thrainer | # (at your option) any later version.
|
10 | 814386b7 | Thomas Thrainer | #
|
11 | 814386b7 | Thomas Thrainer | # This program is distributed in the hope that it will be useful, but
|
12 | 814386b7 | Thomas Thrainer | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 814386b7 | Thomas Thrainer | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 814386b7 | Thomas Thrainer | # General Public License for more details.
|
15 | 814386b7 | Thomas Thrainer | #
|
16 | 814386b7 | Thomas Thrainer | # You should have received a copy of the GNU General Public License
|
17 | 814386b7 | Thomas Thrainer | # along with this program; if not, write to the Free Software
|
18 | 814386b7 | Thomas Thrainer | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 814386b7 | Thomas Thrainer | # 02110-1301, USA.
|
20 | 814386b7 | Thomas Thrainer | |
21 | 814386b7 | Thomas Thrainer | |
22 | 814386b7 | Thomas Thrainer | """Miscellaneous logical units that don't fit into any category."""
|
23 | 814386b7 | Thomas Thrainer | |
24 | 814386b7 | Thomas Thrainer | import logging |
25 | 814386b7 | Thomas Thrainer | import time |
26 | 814386b7 | Thomas Thrainer | |
27 | 814386b7 | Thomas Thrainer | from ganeti import compat |
28 | 814386b7 | Thomas Thrainer | from ganeti import constants |
29 | 814386b7 | Thomas Thrainer | from ganeti import errors |
30 | 814386b7 | Thomas Thrainer | from ganeti import locking |
31 | 814386b7 | Thomas Thrainer | from ganeti import qlang |
32 | 814386b7 | Thomas Thrainer | from ganeti import query |
33 | 814386b7 | Thomas Thrainer | from ganeti import utils |
34 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.base import NoHooksLU, QueryBase |
35 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.common import GetWantedNodes, SupportsOob |
36 | 814386b7 | Thomas Thrainer | |
37 | 814386b7 | Thomas Thrainer | |
38 | 814386b7 | Thomas Thrainer | class LUOobCommand(NoHooksLU): |
39 | 814386b7 | Thomas Thrainer | """Logical unit for OOB handling.
|
40 | 814386b7 | Thomas Thrainer |
|
41 | 814386b7 | Thomas Thrainer | """
|
42 | 814386b7 | Thomas Thrainer | REQ_BGL = False
|
43 | 814386b7 | Thomas Thrainer | _SKIP_MASTER = (constants.OOB_POWER_OFF, constants.OOB_POWER_CYCLE) |
44 | 814386b7 | Thomas Thrainer | |
45 | 814386b7 | Thomas Thrainer | def ExpandNames(self): |
46 | 814386b7 | Thomas Thrainer | """Gather locks we need.
|
47 | 814386b7 | Thomas Thrainer |
|
48 | 814386b7 | Thomas Thrainer | """
|
49 | 814386b7 | Thomas Thrainer | if self.op.node_names: |
50 | 1c3231aa | Thomas Thrainer | (self.op.node_uuids, self.op.node_names) = \ |
51 | 1c3231aa | Thomas Thrainer | GetWantedNodes(self, self.op.node_names) |
52 | 1c3231aa | Thomas Thrainer | lock_node_uuids = self.op.node_uuids
|
53 | 814386b7 | Thomas Thrainer | else:
|
54 | 1c3231aa | Thomas Thrainer | lock_node_uuids = locking.ALL_SET |
55 | 814386b7 | Thomas Thrainer | |
56 | 814386b7 | Thomas Thrainer | self.needed_locks = {
|
57 | 1c3231aa | Thomas Thrainer | locking.LEVEL_NODE: lock_node_uuids, |
58 | 814386b7 | Thomas Thrainer | } |
59 | 814386b7 | Thomas Thrainer | |
60 | 814386b7 | Thomas Thrainer | self.share_locks[locking.LEVEL_NODE_ALLOC] = 1 |
61 | 814386b7 | Thomas Thrainer | |
62 | 814386b7 | Thomas Thrainer | if not self.op.node_names: |
63 | 814386b7 | Thomas Thrainer | # Acquire node allocation lock only if all nodes are affected
|
64 | 814386b7 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODE_ALLOC] = locking.ALL_SET
|
65 | 814386b7 | Thomas Thrainer | |
66 | 814386b7 | Thomas Thrainer | def CheckPrereq(self): |
67 | 814386b7 | Thomas Thrainer | """Check prerequisites.
|
68 | 814386b7 | Thomas Thrainer |
|
69 | 814386b7 | Thomas Thrainer | This checks:
|
70 | 814386b7 | Thomas Thrainer | - the node exists in the configuration
|
71 | 814386b7 | Thomas Thrainer | - OOB is supported
|
72 | 814386b7 | Thomas Thrainer |
|
73 | 814386b7 | Thomas Thrainer | Any errors are signaled by raising errors.OpPrereqError.
|
74 | 814386b7 | Thomas Thrainer |
|
75 | 814386b7 | Thomas Thrainer | """
|
76 | 814386b7 | Thomas Thrainer | self.nodes = []
|
77 | 1c3231aa | Thomas Thrainer | self.master_node_uuid = self.cfg.GetMasterNode() |
78 | 1c3231aa | Thomas Thrainer | master_node_obj = self.cfg.GetNodeInfo(self.master_node_uuid) |
79 | 814386b7 | Thomas Thrainer | |
80 | 814386b7 | Thomas Thrainer | assert self.op.power_delay >= 0.0 |
81 | 814386b7 | Thomas Thrainer | |
82 | 1c3231aa | Thomas Thrainer | if self.op.node_uuids: |
83 | 814386b7 | Thomas Thrainer | if (self.op.command in self._SKIP_MASTER and |
84 | 1c3231aa | Thomas Thrainer | master_node_obj.uuid in self.op.node_uuids): |
85 | 5eacbcae | Thomas Thrainer | master_oob_handler = SupportsOob(self.cfg, master_node_obj)
|
86 | 814386b7 | Thomas Thrainer | |
87 | 814386b7 | Thomas Thrainer | if master_oob_handler:
|
88 | 814386b7 | Thomas Thrainer | additional_text = ("run '%s %s %s' if you want to operate on the"
|
89 | 814386b7 | Thomas Thrainer | " master regardless") % (master_oob_handler,
|
90 | 814386b7 | Thomas Thrainer | self.op.command,
|
91 | 1c3231aa | Thomas Thrainer | master_node_obj.name) |
92 | 814386b7 | Thomas Thrainer | else:
|
93 | 814386b7 | Thomas Thrainer | additional_text = "it does not support out-of-band operations"
|
94 | 814386b7 | Thomas Thrainer | |
95 | 814386b7 | Thomas Thrainer | raise errors.OpPrereqError(("Operating on the master node %s is not" |
96 | 814386b7 | Thomas Thrainer | " allowed for %s; %s") %
|
97 | 1c3231aa | Thomas Thrainer | (master_node_obj.name, self.op.command,
|
98 | 814386b7 | Thomas Thrainer | additional_text), errors.ECODE_INVAL) |
99 | 814386b7 | Thomas Thrainer | else:
|
100 | 1c3231aa | Thomas Thrainer | self.op.node_uuids = self.cfg.GetNodeList() |
101 | 814386b7 | Thomas Thrainer | if self.op.command in self._SKIP_MASTER: |
102 | 1c3231aa | Thomas Thrainer | self.op.node_uuids.remove(master_node_obj.uuid)
|
103 | 814386b7 | Thomas Thrainer | |
104 | 814386b7 | Thomas Thrainer | if self.op.command in self._SKIP_MASTER: |
105 | 1c3231aa | Thomas Thrainer | assert master_node_obj.uuid not in self.op.node_uuids |
106 | 814386b7 | Thomas Thrainer | |
107 | 1c3231aa | Thomas Thrainer | for node_uuid in self.op.node_uuids: |
108 | 1c3231aa | Thomas Thrainer | node = self.cfg.GetNodeInfo(node_uuid)
|
109 | 814386b7 | Thomas Thrainer | if node is None: |
110 | 1c3231aa | Thomas Thrainer | raise errors.OpPrereqError("Node %s not found" % node_uuid, |
111 | 814386b7 | Thomas Thrainer | errors.ECODE_NOENT) |
112 | 1c3231aa | Thomas Thrainer | |
113 | 1c3231aa | Thomas Thrainer | self.nodes.append(node)
|
114 | 814386b7 | Thomas Thrainer | |
115 | 814386b7 | Thomas Thrainer | if (not self.op.ignore_status and |
116 | 814386b7 | Thomas Thrainer | (self.op.command == constants.OOB_POWER_OFF and not node.offline)): |
117 | 814386b7 | Thomas Thrainer | raise errors.OpPrereqError(("Cannot power off node %s because it is" |
118 | 1c3231aa | Thomas Thrainer | " not marked offline") % node.name,
|
119 | 814386b7 | Thomas Thrainer | errors.ECODE_STATE) |
120 | 814386b7 | Thomas Thrainer | |
121 | 814386b7 | Thomas Thrainer | def Exec(self, feedback_fn): |
122 | 814386b7 | Thomas Thrainer | """Execute OOB and return result if we expect any.
|
123 | 814386b7 | Thomas Thrainer |
|
124 | 814386b7 | Thomas Thrainer | """
|
125 | 814386b7 | Thomas Thrainer | ret = [] |
126 | 814386b7 | Thomas Thrainer | |
127 | 814386b7 | Thomas Thrainer | for idx, node in enumerate(utils.NiceSort(self.nodes, |
128 | 814386b7 | Thomas Thrainer | key=lambda node: node.name)):
|
129 | 814386b7 | Thomas Thrainer | node_entry = [(constants.RS_NORMAL, node.name)] |
130 | 814386b7 | Thomas Thrainer | ret.append(node_entry) |
131 | 814386b7 | Thomas Thrainer | |
132 | 5eacbcae | Thomas Thrainer | oob_program = SupportsOob(self.cfg, node)
|
133 | 814386b7 | Thomas Thrainer | |
134 | 814386b7 | Thomas Thrainer | if not oob_program: |
135 | 814386b7 | Thomas Thrainer | node_entry.append((constants.RS_UNAVAIL, None))
|
136 | 814386b7 | Thomas Thrainer | continue
|
137 | 814386b7 | Thomas Thrainer | |
138 | 814386b7 | Thomas Thrainer | logging.info("Executing out-of-band command '%s' using '%s' on %s",
|
139 | 814386b7 | Thomas Thrainer | self.op.command, oob_program, node.name)
|
140 | 1c3231aa | Thomas Thrainer | result = self.rpc.call_run_oob(self.master_node_uuid, oob_program, |
141 | 814386b7 | Thomas Thrainer | self.op.command, node.name,
|
142 | 814386b7 | Thomas Thrainer | self.op.timeout)
|
143 | 814386b7 | Thomas Thrainer | |
144 | 814386b7 | Thomas Thrainer | if result.fail_msg:
|
145 | 814386b7 | Thomas Thrainer | self.LogWarning("Out-of-band RPC failed on node '%s': %s", |
146 | 814386b7 | Thomas Thrainer | node.name, result.fail_msg) |
147 | 814386b7 | Thomas Thrainer | node_entry.append((constants.RS_NODATA, None))
|
148 | 814386b7 | Thomas Thrainer | else:
|
149 | 814386b7 | Thomas Thrainer | try:
|
150 | 814386b7 | Thomas Thrainer | self._CheckPayload(result)
|
151 | 814386b7 | Thomas Thrainer | except errors.OpExecError, err:
|
152 | 814386b7 | Thomas Thrainer | self.LogWarning("Payload returned by node '%s' is not valid: %s", |
153 | 814386b7 | Thomas Thrainer | node.name, err) |
154 | 814386b7 | Thomas Thrainer | node_entry.append((constants.RS_NODATA, None))
|
155 | 814386b7 | Thomas Thrainer | else:
|
156 | 814386b7 | Thomas Thrainer | if self.op.command == constants.OOB_HEALTH: |
157 | 814386b7 | Thomas Thrainer | # For health we should log important events
|
158 | 814386b7 | Thomas Thrainer | for item, status in result.payload: |
159 | 814386b7 | Thomas Thrainer | if status in [constants.OOB_STATUS_WARNING, |
160 | 814386b7 | Thomas Thrainer | constants.OOB_STATUS_CRITICAL]: |
161 | 814386b7 | Thomas Thrainer | self.LogWarning("Item '%s' on node '%s' has status '%s'", |
162 | 814386b7 | Thomas Thrainer | item, node.name, status) |
163 | 814386b7 | Thomas Thrainer | |
164 | 814386b7 | Thomas Thrainer | if self.op.command == constants.OOB_POWER_ON: |
165 | 814386b7 | Thomas Thrainer | node.powered = True
|
166 | 814386b7 | Thomas Thrainer | elif self.op.command == constants.OOB_POWER_OFF: |
167 | 814386b7 | Thomas Thrainer | node.powered = False
|
168 | 814386b7 | Thomas Thrainer | elif self.op.command == constants.OOB_POWER_STATUS: |
169 | 814386b7 | Thomas Thrainer | powered = result.payload[constants.OOB_POWER_STATUS_POWERED] |
170 | 814386b7 | Thomas Thrainer | if powered != node.powered:
|
171 | 814386b7 | Thomas Thrainer | logging.warning(("Recorded power state (%s) of node '%s' does not"
|
172 | 814386b7 | Thomas Thrainer | " match actual power state (%s)"), node.powered,
|
173 | 814386b7 | Thomas Thrainer | node.name, powered) |
174 | 814386b7 | Thomas Thrainer | |
175 | 814386b7 | Thomas Thrainer | # For configuration changing commands we should update the node
|
176 | 814386b7 | Thomas Thrainer | if self.op.command in (constants.OOB_POWER_ON, |
177 | 814386b7 | Thomas Thrainer | constants.OOB_POWER_OFF): |
178 | 814386b7 | Thomas Thrainer | self.cfg.Update(node, feedback_fn)
|
179 | 814386b7 | Thomas Thrainer | |
180 | 814386b7 | Thomas Thrainer | node_entry.append((constants.RS_NORMAL, result.payload)) |
181 | 814386b7 | Thomas Thrainer | |
182 | 814386b7 | Thomas Thrainer | if (self.op.command == constants.OOB_POWER_ON and |
183 | 814386b7 | Thomas Thrainer | idx < len(self.nodes) - 1): |
184 | 814386b7 | Thomas Thrainer | time.sleep(self.op.power_delay)
|
185 | 814386b7 | Thomas Thrainer | |
186 | 814386b7 | Thomas Thrainer | return ret
|
187 | 814386b7 | Thomas Thrainer | |
188 | 814386b7 | Thomas Thrainer | def _CheckPayload(self, result): |
189 | 814386b7 | Thomas Thrainer | """Checks if the payload is valid.
|
190 | 814386b7 | Thomas Thrainer |
|
191 | 814386b7 | Thomas Thrainer | @param result: RPC result
|
192 | 814386b7 | Thomas Thrainer | @raises errors.OpExecError: If payload is not valid
|
193 | 814386b7 | Thomas Thrainer |
|
194 | 814386b7 | Thomas Thrainer | """
|
195 | 814386b7 | Thomas Thrainer | errs = [] |
196 | 814386b7 | Thomas Thrainer | if self.op.command == constants.OOB_HEALTH: |
197 | 814386b7 | Thomas Thrainer | if not isinstance(result.payload, list): |
198 | 814386b7 | Thomas Thrainer | errs.append("command 'health' is expected to return a list but got %s" %
|
199 | 814386b7 | Thomas Thrainer | type(result.payload))
|
200 | 814386b7 | Thomas Thrainer | else:
|
201 | 814386b7 | Thomas Thrainer | for item, status in result.payload: |
202 | 814386b7 | Thomas Thrainer | if status not in constants.OOB_STATUSES: |
203 | 814386b7 | Thomas Thrainer | errs.append("health item '%s' has invalid status '%s'" %
|
204 | 814386b7 | Thomas Thrainer | (item, status)) |
205 | 814386b7 | Thomas Thrainer | |
206 | 814386b7 | Thomas Thrainer | if self.op.command == constants.OOB_POWER_STATUS: |
207 | 814386b7 | Thomas Thrainer | if not isinstance(result.payload, dict): |
208 | 814386b7 | Thomas Thrainer | errs.append("power-status is expected to return a dict but got %s" %
|
209 | 814386b7 | Thomas Thrainer | type(result.payload))
|
210 | 814386b7 | Thomas Thrainer | |
211 | 814386b7 | Thomas Thrainer | if self.op.command in [ |
212 | 814386b7 | Thomas Thrainer | constants.OOB_POWER_ON, |
213 | 814386b7 | Thomas Thrainer | constants.OOB_POWER_OFF, |
214 | 814386b7 | Thomas Thrainer | constants.OOB_POWER_CYCLE, |
215 | 814386b7 | Thomas Thrainer | ]: |
216 | 814386b7 | Thomas Thrainer | if result.payload is not None: |
217 | 814386b7 | Thomas Thrainer | errs.append("%s is expected to not return payload but got '%s'" %
|
218 | 814386b7 | Thomas Thrainer | (self.op.command, result.payload))
|
219 | 814386b7 | Thomas Thrainer | |
220 | 814386b7 | Thomas Thrainer | if errs:
|
221 | 814386b7 | Thomas Thrainer | raise errors.OpExecError("Check of out-of-band payload failed due to %s" % |
222 | 814386b7 | Thomas Thrainer | utils.CommaJoin(errs)) |
223 | 814386b7 | Thomas Thrainer | |
224 | 814386b7 | Thomas Thrainer | |
225 | 5eacbcae | Thomas Thrainer | class ExtStorageQuery(QueryBase): |
226 | 814386b7 | Thomas Thrainer | FIELDS = query.EXTSTORAGE_FIELDS |
227 | 814386b7 | Thomas Thrainer | |
228 | 814386b7 | Thomas Thrainer | def ExpandNames(self, lu): |
229 | 814386b7 | Thomas Thrainer | # Lock all nodes in shared mode
|
230 | 814386b7 | Thomas Thrainer | # Temporary removal of locks, should be reverted later
|
231 | 814386b7 | Thomas Thrainer | # TODO: reintroduce locks when they are lighter-weight
|
232 | 814386b7 | Thomas Thrainer | lu.needed_locks = {} |
233 | 814386b7 | Thomas Thrainer | #self.share_locks[locking.LEVEL_NODE] = 1
|
234 | 814386b7 | Thomas Thrainer | #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
|
235 | 814386b7 | Thomas Thrainer | |
236 | 814386b7 | Thomas Thrainer | # The following variables interact with _QueryBase._GetNames
|
237 | 814386b7 | Thomas Thrainer | if self.names: |
238 | 1c3231aa | Thomas Thrainer | self.wanted = [lu.cfg.GetNodeInfoByName(name).uuid for name in self.names] |
239 | 814386b7 | Thomas Thrainer | else:
|
240 | 814386b7 | Thomas Thrainer | self.wanted = locking.ALL_SET
|
241 | 814386b7 | Thomas Thrainer | |
242 | 814386b7 | Thomas Thrainer | self.do_locking = self.use_locking |
243 | 814386b7 | Thomas Thrainer | |
244 | 814386b7 | Thomas Thrainer | def DeclareLocks(self, lu, level): |
245 | 814386b7 | Thomas Thrainer | pass
|
246 | 814386b7 | Thomas Thrainer | |
247 | 814386b7 | Thomas Thrainer | @staticmethod
|
248 | 814386b7 | Thomas Thrainer | def _DiagnoseByProvider(rlist): |
249 | 814386b7 | Thomas Thrainer | """Remaps a per-node return list into an a per-provider per-node dictionary
|
250 | 814386b7 | Thomas Thrainer |
|
251 | 1c3231aa | Thomas Thrainer | @param rlist: a map with node uuids as keys and ExtStorage objects as values
|
252 | 814386b7 | Thomas Thrainer |
|
253 | 814386b7 | Thomas Thrainer | @rtype: dict
|
254 | 814386b7 | Thomas Thrainer | @return: a dictionary with extstorage providers as keys and as
|
255 | 1c3231aa | Thomas Thrainer | value another map, with node uuids as keys and tuples of
|
256 | 814386b7 | Thomas Thrainer | (path, status, diagnose, parameters) as values, eg::
|
257 | 814386b7 | Thomas Thrainer |
|
258 | 1c3231aa | Thomas Thrainer | {"provider1": {"node_uuid1": [(/usr/lib/..., True, "", [])]
|
259 | 1c3231aa | Thomas Thrainer | "node_uuid2": [(/srv/..., False, "missing file")]
|
260 | 1c3231aa | Thomas Thrainer | "node_uuid3": [(/srv/..., True, "", [])]
|
261 | 814386b7 | Thomas Thrainer | }
|
262 | 814386b7 | Thomas Thrainer |
|
263 | 814386b7 | Thomas Thrainer | """
|
264 | 814386b7 | Thomas Thrainer | all_es = {} |
265 | 814386b7 | Thomas Thrainer | # we build here the list of nodes that didn't fail the RPC (at RPC
|
266 | 814386b7 | Thomas Thrainer | # level), so that nodes with a non-responding node daemon don't
|
267 | 814386b7 | Thomas Thrainer | # make all OSes invalid
|
268 | 1c3231aa | Thomas Thrainer | good_nodes = [node_uuid for node_uuid in rlist |
269 | 1c3231aa | Thomas Thrainer | if not rlist[node_uuid].fail_msg] |
270 | 1c3231aa | Thomas Thrainer | for node_uuid, nr in rlist.items(): |
271 | 814386b7 | Thomas Thrainer | if nr.fail_msg or not nr.payload: |
272 | 814386b7 | Thomas Thrainer | continue
|
273 | 814386b7 | Thomas Thrainer | for (name, path, status, diagnose, params) in nr.payload: |
274 | 814386b7 | Thomas Thrainer | if name not in all_es: |
275 | 814386b7 | Thomas Thrainer | # build a list of nodes for this os containing empty lists
|
276 | 814386b7 | Thomas Thrainer | # for each node in node_list
|
277 | 814386b7 | Thomas Thrainer | all_es[name] = {} |
278 | 1c3231aa | Thomas Thrainer | for nuuid in good_nodes: |
279 | 1c3231aa | Thomas Thrainer | all_es[name][nuuid] = [] |
280 | 814386b7 | Thomas Thrainer | # convert params from [name, help] to (name, help)
|
281 | 814386b7 | Thomas Thrainer | params = [tuple(v) for v in params] |
282 | 1c3231aa | Thomas Thrainer | all_es[name][node_uuid].append((path, status, diagnose, params)) |
283 | 814386b7 | Thomas Thrainer | return all_es
|
284 | 814386b7 | Thomas Thrainer | |
285 | 814386b7 | Thomas Thrainer | def _GetQueryData(self, lu): |
286 | 814386b7 | Thomas Thrainer | """Computes the list of nodes and their attributes.
|
287 | 814386b7 | Thomas Thrainer |
|
288 | 814386b7 | Thomas Thrainer | """
|
289 | 814386b7 | Thomas Thrainer | # Locking is not used
|
290 | 814386b7 | Thomas Thrainer | assert not (compat.any(lu.glm.is_owned(level) |
291 | 814386b7 | Thomas Thrainer | for level in locking.LEVELS |
292 | 814386b7 | Thomas Thrainer | if level != locking.LEVEL_CLUSTER) or |
293 | 814386b7 | Thomas Thrainer | self.do_locking or self.use_locking) |
294 | 814386b7 | Thomas Thrainer | |
295 | 1c3231aa | Thomas Thrainer | valid_nodes = [node.uuid |
296 | 814386b7 | Thomas Thrainer | for node in lu.cfg.GetAllNodesInfo().values() |
297 | 814386b7 | Thomas Thrainer | if not node.offline and node.vm_capable] |
298 | 814386b7 | Thomas Thrainer | pol = self._DiagnoseByProvider(lu.rpc.call_extstorage_diagnose(valid_nodes))
|
299 | 814386b7 | Thomas Thrainer | |
300 | 814386b7 | Thomas Thrainer | data = {} |
301 | 814386b7 | Thomas Thrainer | |
302 | 814386b7 | Thomas Thrainer | nodegroup_list = lu.cfg.GetNodeGroupList() |
303 | 814386b7 | Thomas Thrainer | |
304 | 814386b7 | Thomas Thrainer | for (es_name, es_data) in pol.items(): |
305 | 814386b7 | Thomas Thrainer | # For every provider compute the nodegroup validity.
|
306 | 814386b7 | Thomas Thrainer | # To do this we need to check the validity of each node in es_data
|
307 | 814386b7 | Thomas Thrainer | # and then construct the corresponding nodegroup dict:
|
308 | 814386b7 | Thomas Thrainer | # { nodegroup1: status
|
309 | 814386b7 | Thomas Thrainer | # nodegroup2: status
|
310 | 814386b7 | Thomas Thrainer | # }
|
311 | 814386b7 | Thomas Thrainer | ndgrp_data = {} |
312 | 814386b7 | Thomas Thrainer | for nodegroup in nodegroup_list: |
313 | 814386b7 | Thomas Thrainer | ndgrp = lu.cfg.GetNodeGroup(nodegroup) |
314 | 814386b7 | Thomas Thrainer | |
315 | 814386b7 | Thomas Thrainer | nodegroup_nodes = ndgrp.members |
316 | 814386b7 | Thomas Thrainer | nodegroup_name = ndgrp.name |
317 | 814386b7 | Thomas Thrainer | node_statuses = [] |
318 | 814386b7 | Thomas Thrainer | |
319 | 814386b7 | Thomas Thrainer | for node in nodegroup_nodes: |
320 | 814386b7 | Thomas Thrainer | if node in valid_nodes: |
321 | 814386b7 | Thomas Thrainer | if es_data[node] != []:
|
322 | 814386b7 | Thomas Thrainer | node_status = es_data[node][0][1] |
323 | 814386b7 | Thomas Thrainer | node_statuses.append(node_status) |
324 | 814386b7 | Thomas Thrainer | else:
|
325 | 814386b7 | Thomas Thrainer | node_statuses.append(False)
|
326 | 814386b7 | Thomas Thrainer | |
327 | 814386b7 | Thomas Thrainer | if False in node_statuses: |
328 | 814386b7 | Thomas Thrainer | ndgrp_data[nodegroup_name] = False
|
329 | 814386b7 | Thomas Thrainer | else:
|
330 | 814386b7 | Thomas Thrainer | ndgrp_data[nodegroup_name] = True
|
331 | 814386b7 | Thomas Thrainer | |
332 | 814386b7 | Thomas Thrainer | # Compute the provider's parameters
|
333 | 814386b7 | Thomas Thrainer | parameters = set()
|
334 | 814386b7 | Thomas Thrainer | for idx, esl in enumerate(es_data.values()): |
335 | 814386b7 | Thomas Thrainer | valid = bool(esl and esl[0][1]) |
336 | 814386b7 | Thomas Thrainer | if not valid: |
337 | 814386b7 | Thomas Thrainer | break
|
338 | 814386b7 | Thomas Thrainer | |
339 | 814386b7 | Thomas Thrainer | node_params = esl[0][3] |
340 | 814386b7 | Thomas Thrainer | if idx == 0: |
341 | 814386b7 | Thomas Thrainer | # First entry
|
342 | 814386b7 | Thomas Thrainer | parameters.update(node_params) |
343 | 814386b7 | Thomas Thrainer | else:
|
344 | 814386b7 | Thomas Thrainer | # Filter out inconsistent values
|
345 | 814386b7 | Thomas Thrainer | parameters.intersection_update(node_params) |
346 | 814386b7 | Thomas Thrainer | |
347 | 814386b7 | Thomas Thrainer | params = list(parameters)
|
348 | 814386b7 | Thomas Thrainer | |
349 | 814386b7 | Thomas Thrainer | # Now fill all the info for this provider
|
350 | 814386b7 | Thomas Thrainer | info = query.ExtStorageInfo(name=es_name, node_status=es_data, |
351 | 814386b7 | Thomas Thrainer | nodegroup_status=ndgrp_data, |
352 | 814386b7 | Thomas Thrainer | parameters=params) |
353 | 814386b7 | Thomas Thrainer | |
354 | 814386b7 | Thomas Thrainer | data[es_name] = info |
355 | 814386b7 | Thomas Thrainer | |
356 | 814386b7 | Thomas Thrainer | # Prepare data in requested order
|
357 | 814386b7 | Thomas Thrainer | return [data[name] for name in self._GetNames(lu, pol.keys(), None) |
358 | 814386b7 | Thomas Thrainer | if name in data] |
359 | 814386b7 | Thomas Thrainer | |
360 | 814386b7 | Thomas Thrainer | |
361 | 814386b7 | Thomas Thrainer | class LUExtStorageDiagnose(NoHooksLU): |
362 | 814386b7 | Thomas Thrainer | """Logical unit for ExtStorage diagnose/query.
|
363 | 814386b7 | Thomas Thrainer |
|
364 | 814386b7 | Thomas Thrainer | """
|
365 | 814386b7 | Thomas Thrainer | REQ_BGL = False
|
366 | 814386b7 | Thomas Thrainer | |
367 | 814386b7 | Thomas Thrainer | def CheckArguments(self): |
368 | 5eacbcae | Thomas Thrainer | self.eq = ExtStorageQuery(qlang.MakeSimpleFilter("name", self.op.names), |
369 | 814386b7 | Thomas Thrainer | self.op.output_fields, False) |
370 | 814386b7 | Thomas Thrainer | |
371 | 814386b7 | Thomas Thrainer | def ExpandNames(self): |
372 | 814386b7 | Thomas Thrainer | self.eq.ExpandNames(self) |
373 | 814386b7 | Thomas Thrainer | |
374 | 814386b7 | Thomas Thrainer | def Exec(self, feedback_fn): |
375 | 814386b7 | Thomas Thrainer | return self.eq.OldStyleQuery(self) |
376 | 814386b7 | Thomas Thrainer | |
377 | 814386b7 | Thomas Thrainer | |
378 | 814386b7 | Thomas Thrainer | class LURestrictedCommand(NoHooksLU): |
379 | 814386b7 | Thomas Thrainer | """Logical unit for executing restricted commands.
|
380 | 814386b7 | Thomas Thrainer |
|
381 | 814386b7 | Thomas Thrainer | """
|
382 | 814386b7 | Thomas Thrainer | REQ_BGL = False
|
383 | 814386b7 | Thomas Thrainer | |
384 | 814386b7 | Thomas Thrainer | def ExpandNames(self): |
385 | 814386b7 | Thomas Thrainer | if self.op.nodes: |
386 | 1c3231aa | Thomas Thrainer | (self.op.node_uuids, self.op.nodes) = GetWantedNodes(self, self.op.nodes) |
387 | 814386b7 | Thomas Thrainer | |
388 | 814386b7 | Thomas Thrainer | self.needed_locks = {
|
389 | 1c3231aa | Thomas Thrainer | locking.LEVEL_NODE: self.op.node_uuids,
|
390 | 814386b7 | Thomas Thrainer | } |
391 | 814386b7 | Thomas Thrainer | self.share_locks = {
|
392 | 814386b7 | Thomas Thrainer | locking.LEVEL_NODE: not self.op.use_locking, |
393 | 814386b7 | Thomas Thrainer | } |
394 | 814386b7 | Thomas Thrainer | |
395 | 814386b7 | Thomas Thrainer | def CheckPrereq(self): |
396 | 814386b7 | Thomas Thrainer | """Check prerequisites.
|
397 | 814386b7 | Thomas Thrainer |
|
398 | 814386b7 | Thomas Thrainer | """
|
399 | 814386b7 | Thomas Thrainer | |
400 | 814386b7 | Thomas Thrainer | def Exec(self, feedback_fn): |
401 | 814386b7 | Thomas Thrainer | """Execute restricted command and return output.
|
402 | 814386b7 | Thomas Thrainer |
|
403 | 814386b7 | Thomas Thrainer | """
|
404 | 814386b7 | Thomas Thrainer | owned_nodes = frozenset(self.owned_locks(locking.LEVEL_NODE)) |
405 | 814386b7 | Thomas Thrainer | |
406 | 814386b7 | Thomas Thrainer | # Check if correct locks are held
|
407 | 1c3231aa | Thomas Thrainer | assert set(self.op.node_uuids).issubset(owned_nodes) |
408 | 814386b7 | Thomas Thrainer | |
409 | 1c3231aa | Thomas Thrainer | rpcres = self.rpc.call_restricted_command(self.op.node_uuids, |
410 | 1c3231aa | Thomas Thrainer | self.op.command)
|
411 | 814386b7 | Thomas Thrainer | |
412 | 814386b7 | Thomas Thrainer | result = [] |
413 | 814386b7 | Thomas Thrainer | |
414 | 1c3231aa | Thomas Thrainer | for node_uuid in self.op.node_uuids: |
415 | 1c3231aa | Thomas Thrainer | nres = rpcres[node_uuid] |
416 | 814386b7 | Thomas Thrainer | if nres.fail_msg:
|
417 | 814386b7 | Thomas Thrainer | msg = ("Command '%s' on node '%s' failed: %s" %
|
418 | 1c3231aa | Thomas Thrainer | (self.op.command, self.cfg.GetNodeName(node_uuid), |
419 | 1c3231aa | Thomas Thrainer | nres.fail_msg)) |
420 | 814386b7 | Thomas Thrainer | result.append((False, msg))
|
421 | 814386b7 | Thomas Thrainer | else:
|
422 | 814386b7 | Thomas Thrainer | result.append((True, nres.payload))
|
423 | 814386b7 | Thomas Thrainer | |
424 | 814386b7 | Thomas Thrainer | return result |