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