Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / misc.py @ 5cbf7832

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