Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / misc.py @ 8ac806e6

History | View | Annotate | Download (13.8 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 5eacbcae 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 5eacbcae 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 5eacbcae 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 5eacbcae 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 5eacbcae 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 5eacbcae 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