Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ 1c3231aa

History | View | Annotate | Download (15.8 kB)

1 8aa8f6b1 Thomas Thrainer
#
2 8aa8f6b1 Thomas Thrainer
#
3 8aa8f6b1 Thomas Thrainer
4 8aa8f6b1 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 8aa8f6b1 Thomas Thrainer
#
6 8aa8f6b1 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 8aa8f6b1 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 8aa8f6b1 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 8aa8f6b1 Thomas Thrainer
# (at your option) any later version.
10 8aa8f6b1 Thomas Thrainer
#
11 8aa8f6b1 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 8aa8f6b1 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 8aa8f6b1 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 8aa8f6b1 Thomas Thrainer
# General Public License for more details.
15 8aa8f6b1 Thomas Thrainer
#
16 8aa8f6b1 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 8aa8f6b1 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 8aa8f6b1 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 8aa8f6b1 Thomas Thrainer
# 02110-1301, USA.
20 8aa8f6b1 Thomas Thrainer
21 8aa8f6b1 Thomas Thrainer
22 8aa8f6b1 Thomas Thrainer
"""Logical units for querying instances."""
23 8aa8f6b1 Thomas Thrainer
24 8aa8f6b1 Thomas Thrainer
import itertools
25 8aa8f6b1 Thomas Thrainer
import logging
26 8aa8f6b1 Thomas Thrainer
import operator
27 8aa8f6b1 Thomas Thrainer
28 8aa8f6b1 Thomas Thrainer
from ganeti import compat
29 8aa8f6b1 Thomas Thrainer
from ganeti import constants
30 8aa8f6b1 Thomas Thrainer
from ganeti import locking
31 8aa8f6b1 Thomas Thrainer
from ganeti import qlang
32 8aa8f6b1 Thomas Thrainer
from ganeti import query
33 5eacbcae Thomas Thrainer
from ganeti.cmdlib.base import QueryBase, NoHooksLU
34 5eacbcae Thomas Thrainer
from ganeti.cmdlib.common import ShareAll, GetWantedInstances, \
35 5eacbcae Thomas Thrainer
  CheckInstanceNodeGroups, CheckInstancesNodeGroups, AnnotateDiskParams
36 5eacbcae Thomas Thrainer
from ganeti.cmdlib.instance_operation import GetInstanceConsole
37 5eacbcae Thomas Thrainer
from ganeti.cmdlib.instance_utils import NICListToTuple
38 8aa8f6b1 Thomas Thrainer
39 8aa8f6b1 Thomas Thrainer
import ganeti.masterd.instance
40 8aa8f6b1 Thomas Thrainer
41 8aa8f6b1 Thomas Thrainer
42 5eacbcae Thomas Thrainer
class InstanceQuery(QueryBase):
43 8aa8f6b1 Thomas Thrainer
  FIELDS = query.INSTANCE_FIELDS
44 8aa8f6b1 Thomas Thrainer
45 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self, lu):
46 8aa8f6b1 Thomas Thrainer
    lu.needed_locks = {}
47 5eacbcae Thomas Thrainer
    lu.share_locks = ShareAll()
48 8aa8f6b1 Thomas Thrainer
49 8aa8f6b1 Thomas Thrainer
    if self.names:
50 5eacbcae Thomas Thrainer
      self.wanted = GetWantedInstances(lu, self.names)
51 8aa8f6b1 Thomas Thrainer
    else:
52 8aa8f6b1 Thomas Thrainer
      self.wanted = locking.ALL_SET
53 8aa8f6b1 Thomas Thrainer
54 8aa8f6b1 Thomas Thrainer
    self.do_locking = (self.use_locking and
55 8aa8f6b1 Thomas Thrainer
                       query.IQ_LIVE in self.requested_data)
56 8aa8f6b1 Thomas Thrainer
    if self.do_locking:
57 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
58 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODEGROUP] = []
59 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODE] = []
60 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NETWORK] = []
61 8aa8f6b1 Thomas Thrainer
      lu.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
62 8aa8f6b1 Thomas Thrainer
63 8aa8f6b1 Thomas Thrainer
    self.do_grouplocks = (self.do_locking and
64 8aa8f6b1 Thomas Thrainer
                          query.IQ_NODES in self.requested_data)
65 8aa8f6b1 Thomas Thrainer
66 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, lu, level):
67 8aa8f6b1 Thomas Thrainer
    if self.do_locking:
68 8aa8f6b1 Thomas Thrainer
      if level == locking.LEVEL_NODEGROUP and self.do_grouplocks:
69 8aa8f6b1 Thomas Thrainer
        assert not lu.needed_locks[locking.LEVEL_NODEGROUP]
70 8aa8f6b1 Thomas Thrainer
71 8aa8f6b1 Thomas Thrainer
        # Lock all groups used by instances optimistically; this requires going
72 8aa8f6b1 Thomas Thrainer
        # via the node before it's locked, requiring verification later on
73 8aa8f6b1 Thomas Thrainer
        lu.needed_locks[locking.LEVEL_NODEGROUP] = \
74 8aa8f6b1 Thomas Thrainer
          set(group_uuid
75 8aa8f6b1 Thomas Thrainer
              for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
76 8aa8f6b1 Thomas Thrainer
              for group_uuid in lu.cfg.GetInstanceNodeGroups(instance_name))
77 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NODE:
78 8aa8f6b1 Thomas Thrainer
        lu._LockInstancesNodes() # pylint: disable=W0212
79 8aa8f6b1 Thomas Thrainer
80 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NETWORK:
81 8aa8f6b1 Thomas Thrainer
        lu.needed_locks[locking.LEVEL_NETWORK] = \
82 8aa8f6b1 Thomas Thrainer
          frozenset(net_uuid
83 8aa8f6b1 Thomas Thrainer
                    for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
84 8aa8f6b1 Thomas Thrainer
                    for net_uuid in lu.cfg.GetInstanceNetworks(instance_name))
85 8aa8f6b1 Thomas Thrainer
86 8aa8f6b1 Thomas Thrainer
  @staticmethod
87 8aa8f6b1 Thomas Thrainer
  def _CheckGroupLocks(lu):
88 8aa8f6b1 Thomas Thrainer
    owned_instances = frozenset(lu.owned_locks(locking.LEVEL_INSTANCE))
89 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(lu.owned_locks(locking.LEVEL_NODEGROUP))
90 8aa8f6b1 Thomas Thrainer
91 8aa8f6b1 Thomas Thrainer
    # Check if node groups for locked instances are still correct
92 8aa8f6b1 Thomas Thrainer
    for instance_name in owned_instances:
93 5eacbcae Thomas Thrainer
      CheckInstanceNodeGroups(lu.cfg, instance_name, owned_groups)
94 8aa8f6b1 Thomas Thrainer
95 8aa8f6b1 Thomas Thrainer
  def _GetQueryData(self, lu):
96 8aa8f6b1 Thomas Thrainer
    """Computes the list of instances and their attributes.
97 8aa8f6b1 Thomas Thrainer

98 8aa8f6b1 Thomas Thrainer
    """
99 8aa8f6b1 Thomas Thrainer
    if self.do_grouplocks:
100 8aa8f6b1 Thomas Thrainer
      self._CheckGroupLocks(lu)
101 8aa8f6b1 Thomas Thrainer
102 8aa8f6b1 Thomas Thrainer
    cluster = lu.cfg.GetClusterInfo()
103 8aa8f6b1 Thomas Thrainer
    all_info = lu.cfg.GetAllInstancesInfo()
104 8aa8f6b1 Thomas Thrainer
105 8aa8f6b1 Thomas Thrainer
    instance_names = self._GetNames(lu, all_info.keys(), locking.LEVEL_INSTANCE)
106 8aa8f6b1 Thomas Thrainer
107 1c3231aa Thomas Thrainer
    instance_list = [all_info[node] for node in instance_names]
108 1c3231aa Thomas Thrainer
    node_uuids = frozenset(itertools.chain(*(inst.all_nodes
109 1c3231aa Thomas Thrainer
                                             for inst in instance_list)))
110 8aa8f6b1 Thomas Thrainer
    hv_list = list(set([inst.hypervisor for inst in instance_list]))
111 1c3231aa Thomas Thrainer
    bad_node_uuids = []
112 1c3231aa Thomas Thrainer
    offline_node_uuids = []
113 8aa8f6b1 Thomas Thrainer
    wrongnode_inst = set()
114 8aa8f6b1 Thomas Thrainer
115 8aa8f6b1 Thomas Thrainer
    # Gather data as requested
116 8aa8f6b1 Thomas Thrainer
    if self.requested_data & set([query.IQ_LIVE, query.IQ_CONSOLE]):
117 8aa8f6b1 Thomas Thrainer
      live_data = {}
118 1c3231aa Thomas Thrainer
      node_data = lu.rpc.call_all_instances_info(node_uuids, hv_list,
119 0200a1af Helga Velroyen
                                                 cluster.hvparams)
120 1c3231aa Thomas Thrainer
      for node_uuid in node_uuids:
121 1c3231aa Thomas Thrainer
        result = node_data[node_uuid]
122 8aa8f6b1 Thomas Thrainer
        if result.offline:
123 8aa8f6b1 Thomas Thrainer
          # offline nodes will be in both lists
124 8aa8f6b1 Thomas Thrainer
          assert result.fail_msg
125 1c3231aa Thomas Thrainer
          offline_node_uuids.append(node_uuid)
126 8aa8f6b1 Thomas Thrainer
        if result.fail_msg:
127 1c3231aa Thomas Thrainer
          bad_node_uuids.append(node_uuid)
128 8aa8f6b1 Thomas Thrainer
        elif result.payload:
129 8aa8f6b1 Thomas Thrainer
          for inst in result.payload:
130 8aa8f6b1 Thomas Thrainer
            if inst in all_info:
131 1c3231aa Thomas Thrainer
              if all_info[inst].primary_node == node_uuid:
132 8aa8f6b1 Thomas Thrainer
                live_data.update(result.payload)
133 8aa8f6b1 Thomas Thrainer
              else:
134 8aa8f6b1 Thomas Thrainer
                wrongnode_inst.add(inst)
135 8aa8f6b1 Thomas Thrainer
            else:
136 8aa8f6b1 Thomas Thrainer
              # orphan instance; we don't list it here as we don't
137 8aa8f6b1 Thomas Thrainer
              # handle this case yet in the output of instance listing
138 8aa8f6b1 Thomas Thrainer
              logging.warning("Orphan instance '%s' found on node %s",
139 1c3231aa Thomas Thrainer
                              inst, lu.cfg.GetNodeName(node_uuid))
140 8aa8f6b1 Thomas Thrainer
              # else no instance is alive
141 8aa8f6b1 Thomas Thrainer
    else:
142 8aa8f6b1 Thomas Thrainer
      live_data = {}
143 8aa8f6b1 Thomas Thrainer
144 8aa8f6b1 Thomas Thrainer
    if query.IQ_DISKUSAGE in self.requested_data:
145 8aa8f6b1 Thomas Thrainer
      gmi = ganeti.masterd.instance
146 8aa8f6b1 Thomas Thrainer
      disk_usage = dict((inst.name,
147 8aa8f6b1 Thomas Thrainer
                         gmi.ComputeDiskSize(inst.disk_template,
148 8aa8f6b1 Thomas Thrainer
                                             [{constants.IDISK_SIZE: disk.size}
149 8aa8f6b1 Thomas Thrainer
                                              for disk in inst.disks]))
150 8aa8f6b1 Thomas Thrainer
                        for inst in instance_list)
151 8aa8f6b1 Thomas Thrainer
    else:
152 8aa8f6b1 Thomas Thrainer
      disk_usage = None
153 8aa8f6b1 Thomas Thrainer
154 8aa8f6b1 Thomas Thrainer
    if query.IQ_CONSOLE in self.requested_data:
155 8aa8f6b1 Thomas Thrainer
      consinfo = {}
156 8aa8f6b1 Thomas Thrainer
      for inst in instance_list:
157 8aa8f6b1 Thomas Thrainer
        if inst.name in live_data:
158 8aa8f6b1 Thomas Thrainer
          # Instance is running
159 1c3231aa Thomas Thrainer
          consinfo[inst.name] = \
160 1c3231aa Thomas Thrainer
            GetInstanceConsole(cluster, inst,
161 1c3231aa Thomas Thrainer
                               lu.cfg.GetNodeInfo(inst.primary_node))
162 8aa8f6b1 Thomas Thrainer
        else:
163 8aa8f6b1 Thomas Thrainer
          consinfo[inst.name] = None
164 8aa8f6b1 Thomas Thrainer
      assert set(consinfo.keys()) == set(instance_names)
165 8aa8f6b1 Thomas Thrainer
    else:
166 8aa8f6b1 Thomas Thrainer
      consinfo = None
167 8aa8f6b1 Thomas Thrainer
168 8aa8f6b1 Thomas Thrainer
    if query.IQ_NODES in self.requested_data:
169 1c3231aa Thomas Thrainer
      nodes = dict(lu.cfg.GetMultiNodeInfo(node_uuids))
170 8aa8f6b1 Thomas Thrainer
      groups = dict((uuid, lu.cfg.GetNodeGroup(uuid))
171 8aa8f6b1 Thomas Thrainer
                    for uuid in set(map(operator.attrgetter("group"),
172 8aa8f6b1 Thomas Thrainer
                                        nodes.values())))
173 8aa8f6b1 Thomas Thrainer
    else:
174 8aa8f6b1 Thomas Thrainer
      nodes = None
175 8aa8f6b1 Thomas Thrainer
      groups = None
176 8aa8f6b1 Thomas Thrainer
177 8aa8f6b1 Thomas Thrainer
    if query.IQ_NETWORKS in self.requested_data:
178 8aa8f6b1 Thomas Thrainer
      net_uuids = itertools.chain(*(lu.cfg.GetInstanceNetworks(i.name)
179 8aa8f6b1 Thomas Thrainer
                                    for i in instance_list))
180 8aa8f6b1 Thomas Thrainer
      networks = dict((uuid, lu.cfg.GetNetwork(uuid)) for uuid in net_uuids)
181 8aa8f6b1 Thomas Thrainer
    else:
182 8aa8f6b1 Thomas Thrainer
      networks = None
183 8aa8f6b1 Thomas Thrainer
184 8aa8f6b1 Thomas Thrainer
    return query.InstanceQueryData(instance_list, lu.cfg.GetClusterInfo(),
185 1c3231aa Thomas Thrainer
                                   disk_usage, offline_node_uuids,
186 1c3231aa Thomas Thrainer
                                   bad_node_uuids, live_data, wrongnode_inst,
187 1c3231aa Thomas Thrainer
                                   consinfo, nodes, groups, networks)
188 8aa8f6b1 Thomas Thrainer
189 8aa8f6b1 Thomas Thrainer
190 8aa8f6b1 Thomas Thrainer
class LUInstanceQuery(NoHooksLU):
191 8aa8f6b1 Thomas Thrainer
  """Logical unit for querying instances.
192 8aa8f6b1 Thomas Thrainer

193 8aa8f6b1 Thomas Thrainer
  """
194 8aa8f6b1 Thomas Thrainer
  # pylint: disable=W0142
195 8aa8f6b1 Thomas Thrainer
  REQ_BGL = False
196 8aa8f6b1 Thomas Thrainer
197 8aa8f6b1 Thomas Thrainer
  def CheckArguments(self):
198 5eacbcae Thomas Thrainer
    self.iq = InstanceQuery(qlang.MakeSimpleFilter("name", self.op.names),
199 8aa8f6b1 Thomas Thrainer
                             self.op.output_fields, self.op.use_locking)
200 8aa8f6b1 Thomas Thrainer
201 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self):
202 8aa8f6b1 Thomas Thrainer
    self.iq.ExpandNames(self)
203 8aa8f6b1 Thomas Thrainer
204 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, level):
205 8aa8f6b1 Thomas Thrainer
    self.iq.DeclareLocks(self, level)
206 8aa8f6b1 Thomas Thrainer
207 8aa8f6b1 Thomas Thrainer
  def Exec(self, feedback_fn):
208 8aa8f6b1 Thomas Thrainer
    return self.iq.OldStyleQuery(self)
209 8aa8f6b1 Thomas Thrainer
210 8aa8f6b1 Thomas Thrainer
211 8aa8f6b1 Thomas Thrainer
class LUInstanceQueryData(NoHooksLU):
212 8aa8f6b1 Thomas Thrainer
  """Query runtime instance data.
213 8aa8f6b1 Thomas Thrainer

214 8aa8f6b1 Thomas Thrainer
  """
215 8aa8f6b1 Thomas Thrainer
  REQ_BGL = False
216 8aa8f6b1 Thomas Thrainer
217 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self):
218 8aa8f6b1 Thomas Thrainer
    self.needed_locks = {}
219 8aa8f6b1 Thomas Thrainer
220 8aa8f6b1 Thomas Thrainer
    # Use locking if requested or when non-static information is wanted
221 8aa8f6b1 Thomas Thrainer
    if not (self.op.static or self.op.use_locking):
222 8aa8f6b1 Thomas Thrainer
      self.LogWarning("Non-static data requested, locks need to be acquired")
223 8aa8f6b1 Thomas Thrainer
      self.op.use_locking = True
224 8aa8f6b1 Thomas Thrainer
225 8aa8f6b1 Thomas Thrainer
    if self.op.instances or not self.op.use_locking:
226 8aa8f6b1 Thomas Thrainer
      # Expand instance names right here
227 5eacbcae Thomas Thrainer
      self.wanted_names = GetWantedInstances(self, self.op.instances)
228 8aa8f6b1 Thomas Thrainer
    else:
229 8aa8f6b1 Thomas Thrainer
      # Will use acquired locks
230 8aa8f6b1 Thomas Thrainer
      self.wanted_names = None
231 8aa8f6b1 Thomas Thrainer
232 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
233 5eacbcae Thomas Thrainer
      self.share_locks = ShareAll()
234 8aa8f6b1 Thomas Thrainer
235 8aa8f6b1 Thomas Thrainer
      if self.wanted_names is None:
236 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
237 8aa8f6b1 Thomas Thrainer
      else:
238 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names
239 8aa8f6b1 Thomas Thrainer
240 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = []
241 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = []
242 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NETWORK] = []
243 8aa8f6b1 Thomas Thrainer
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
244 8aa8f6b1 Thomas Thrainer
245 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, level):
246 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
247 8aa8f6b1 Thomas Thrainer
      owned_instances = self.owned_locks(locking.LEVEL_INSTANCE)
248 8aa8f6b1 Thomas Thrainer
      if level == locking.LEVEL_NODEGROUP:
249 8aa8f6b1 Thomas Thrainer
250 8aa8f6b1 Thomas Thrainer
        # Lock all groups used by instances optimistically; this requires going
251 8aa8f6b1 Thomas Thrainer
        # via the node before it's locked, requiring verification later on
252 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODEGROUP] = \
253 8aa8f6b1 Thomas Thrainer
          frozenset(group_uuid
254 8aa8f6b1 Thomas Thrainer
                    for instance_name in owned_instances
255 8aa8f6b1 Thomas Thrainer
                    for group_uuid in
256 8aa8f6b1 Thomas Thrainer
                    self.cfg.GetInstanceNodeGroups(instance_name))
257 8aa8f6b1 Thomas Thrainer
258 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NODE:
259 8aa8f6b1 Thomas Thrainer
        self._LockInstancesNodes()
260 8aa8f6b1 Thomas Thrainer
261 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NETWORK:
262 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NETWORK] = \
263 8aa8f6b1 Thomas Thrainer
          frozenset(net_uuid
264 8aa8f6b1 Thomas Thrainer
                    for instance_name in owned_instances
265 8aa8f6b1 Thomas Thrainer
                    for net_uuid in
266 8aa8f6b1 Thomas Thrainer
                    self.cfg.GetInstanceNetworks(instance_name))
267 8aa8f6b1 Thomas Thrainer
268 8aa8f6b1 Thomas Thrainer
  def CheckPrereq(self):
269 8aa8f6b1 Thomas Thrainer
    """Check prerequisites.
270 8aa8f6b1 Thomas Thrainer

271 8aa8f6b1 Thomas Thrainer
    This only checks the optional instance list against the existing names.
272 8aa8f6b1 Thomas Thrainer

273 8aa8f6b1 Thomas Thrainer
    """
274 8aa8f6b1 Thomas Thrainer
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
275 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
276 1c3231aa Thomas Thrainer
    owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE))
277 8aa8f6b1 Thomas Thrainer
    owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK))
278 8aa8f6b1 Thomas Thrainer
279 8aa8f6b1 Thomas Thrainer
    if self.wanted_names is None:
280 8aa8f6b1 Thomas Thrainer
      assert self.op.use_locking, "Locking was not used"
281 8aa8f6b1 Thomas Thrainer
      self.wanted_names = owned_instances
282 8aa8f6b1 Thomas Thrainer
283 8aa8f6b1 Thomas Thrainer
    instances = dict(self.cfg.GetMultiInstanceInfo(self.wanted_names))
284 8aa8f6b1 Thomas Thrainer
285 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
286 1c3231aa Thomas Thrainer
      CheckInstancesNodeGroups(self.cfg, instances, owned_groups,
287 1c3231aa Thomas Thrainer
                               owned_node_uuids, None)
288 8aa8f6b1 Thomas Thrainer
    else:
289 8aa8f6b1 Thomas Thrainer
      assert not (owned_instances or owned_groups or
290 1c3231aa Thomas Thrainer
                  owned_node_uuids or owned_networks)
291 8aa8f6b1 Thomas Thrainer
292 8aa8f6b1 Thomas Thrainer
    self.wanted_instances = instances.values()
293 8aa8f6b1 Thomas Thrainer
294 1c3231aa Thomas Thrainer
  def _ComputeBlockdevStatus(self, node_uuid, instance, dev):
295 8aa8f6b1 Thomas Thrainer
    """Returns the status of a block device
296 8aa8f6b1 Thomas Thrainer

297 8aa8f6b1 Thomas Thrainer
    """
298 1c3231aa Thomas Thrainer
    if self.op.static or not node_uuid:
299 8aa8f6b1 Thomas Thrainer
      return None
300 8aa8f6b1 Thomas Thrainer
301 1c3231aa Thomas Thrainer
    self.cfg.SetDiskID(dev, node_uuid)
302 8aa8f6b1 Thomas Thrainer
303 1c3231aa Thomas Thrainer
    result = self.rpc.call_blockdev_find(node_uuid, dev)
304 8aa8f6b1 Thomas Thrainer
    if result.offline:
305 8aa8f6b1 Thomas Thrainer
      return None
306 8aa8f6b1 Thomas Thrainer
307 8aa8f6b1 Thomas Thrainer
    result.Raise("Can't compute disk status for %s" % instance.name)
308 8aa8f6b1 Thomas Thrainer
309 8aa8f6b1 Thomas Thrainer
    status = result.payload
310 8aa8f6b1 Thomas Thrainer
    if status is None:
311 8aa8f6b1 Thomas Thrainer
      return None
312 8aa8f6b1 Thomas Thrainer
313 8aa8f6b1 Thomas Thrainer
    return (status.dev_path, status.major, status.minor,
314 8aa8f6b1 Thomas Thrainer
            status.sync_percent, status.estimated_time,
315 8aa8f6b1 Thomas Thrainer
            status.is_degraded, status.ldisk_status)
316 8aa8f6b1 Thomas Thrainer
317 1c3231aa Thomas Thrainer
  def _ComputeDiskStatus(self, instance, node_uuid2name_fn, dev):
318 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
319 8aa8f6b1 Thomas Thrainer

320 8aa8f6b1 Thomas Thrainer
    """
321 5eacbcae Thomas Thrainer
    (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg)
322 8aa8f6b1 Thomas Thrainer
323 1c3231aa Thomas Thrainer
    return self._ComputeDiskStatusInner(instance, None, node_uuid2name_fn,
324 1c3231aa Thomas Thrainer
                                        anno_dev)
325 8aa8f6b1 Thomas Thrainer
326 1c3231aa Thomas Thrainer
  def _ComputeDiskStatusInner(self, instance, snode_uuid, node_uuid2name_fn,
327 1c3231aa Thomas Thrainer
                              dev):
328 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
329 8aa8f6b1 Thomas Thrainer

330 8aa8f6b1 Thomas Thrainer
    @attention: The device has to be annotated already.
331 8aa8f6b1 Thomas Thrainer

332 8aa8f6b1 Thomas Thrainer
    """
333 1c3231aa Thomas Thrainer
    drbd_info = None
334 8aa8f6b1 Thomas Thrainer
    if dev.dev_type in constants.LDS_DRBD:
335 8aa8f6b1 Thomas Thrainer
      # we change the snode then (otherwise we use the one passed in)
336 8aa8f6b1 Thomas Thrainer
      if dev.logical_id[0] == instance.primary_node:
337 1c3231aa Thomas Thrainer
        snode_uuid = dev.logical_id[1]
338 8aa8f6b1 Thomas Thrainer
      else:
339 1c3231aa Thomas Thrainer
        snode_uuid = dev.logical_id[0]
340 1c3231aa Thomas Thrainer
      drbd_info = {
341 1c3231aa Thomas Thrainer
        "primary_node": node_uuid2name_fn(instance.primary_node),
342 1c3231aa Thomas Thrainer
        "primary_minor": dev.logical_id[3],
343 1c3231aa Thomas Thrainer
        "secondary_node": node_uuid2name_fn(snode_uuid),
344 1c3231aa Thomas Thrainer
        "secondary_minor": dev.logical_id[4],
345 1c3231aa Thomas Thrainer
        "port": dev.logical_id[2],
346 1c3231aa Thomas Thrainer
        "secret": dev.logical_id[5],
347 1c3231aa Thomas Thrainer
      }
348 8aa8f6b1 Thomas Thrainer
349 8aa8f6b1 Thomas Thrainer
    dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
350 8aa8f6b1 Thomas Thrainer
                                              instance, dev)
351 1c3231aa Thomas Thrainer
    dev_sstatus = self._ComputeBlockdevStatus(snode_uuid, instance, dev)
352 8aa8f6b1 Thomas Thrainer
353 8aa8f6b1 Thomas Thrainer
    if dev.children:
354 8aa8f6b1 Thomas Thrainer
      dev_children = map(compat.partial(self._ComputeDiskStatusInner,
355 1c3231aa Thomas Thrainer
                                        instance, snode_uuid,
356 1c3231aa Thomas Thrainer
                                        node_uuid2name_fn),
357 8aa8f6b1 Thomas Thrainer
                         dev.children)
358 8aa8f6b1 Thomas Thrainer
    else:
359 8aa8f6b1 Thomas Thrainer
      dev_children = []
360 8aa8f6b1 Thomas Thrainer
361 8aa8f6b1 Thomas Thrainer
    return {
362 8aa8f6b1 Thomas Thrainer
      "iv_name": dev.iv_name,
363 8aa8f6b1 Thomas Thrainer
      "dev_type": dev.dev_type,
364 8aa8f6b1 Thomas Thrainer
      "logical_id": dev.logical_id,
365 1c3231aa Thomas Thrainer
      "drbd_info": drbd_info,
366 8aa8f6b1 Thomas Thrainer
      "physical_id": dev.physical_id,
367 8aa8f6b1 Thomas Thrainer
      "pstatus": dev_pstatus,
368 8aa8f6b1 Thomas Thrainer
      "sstatus": dev_sstatus,
369 8aa8f6b1 Thomas Thrainer
      "children": dev_children,
370 8aa8f6b1 Thomas Thrainer
      "mode": dev.mode,
371 8aa8f6b1 Thomas Thrainer
      "size": dev.size,
372 75a6c8be Bernardo Dal Seno
      "spindles": dev.spindles,
373 8aa8f6b1 Thomas Thrainer
      "name": dev.name,
374 8aa8f6b1 Thomas Thrainer
      "uuid": dev.uuid,
375 8aa8f6b1 Thomas Thrainer
      }
376 8aa8f6b1 Thomas Thrainer
377 8aa8f6b1 Thomas Thrainer
  def Exec(self, feedback_fn):
378 8aa8f6b1 Thomas Thrainer
    """Gather and return data"""
379 8aa8f6b1 Thomas Thrainer
    result = {}
380 8aa8f6b1 Thomas Thrainer
381 8aa8f6b1 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
382 8aa8f6b1 Thomas Thrainer
383 1c3231aa Thomas Thrainer
    node_uuids = itertools.chain(*(i.all_nodes for i in self.wanted_instances))
384 1c3231aa Thomas Thrainer
    nodes = dict(self.cfg.GetMultiNodeInfo(node_uuids))
385 8aa8f6b1 Thomas Thrainer
386 8aa8f6b1 Thomas Thrainer
    groups = dict(self.cfg.GetMultiNodeGroupInfo(node.group
387 8aa8f6b1 Thomas Thrainer
                                                 for node in nodes.values()))
388 8aa8f6b1 Thomas Thrainer
389 8aa8f6b1 Thomas Thrainer
    for instance in self.wanted_instances:
390 8aa8f6b1 Thomas Thrainer
      pnode = nodes[instance.primary_node]
391 8aa8f6b1 Thomas Thrainer
392 8aa8f6b1 Thomas Thrainer
      if self.op.static or pnode.offline:
393 8aa8f6b1 Thomas Thrainer
        remote_state = None
394 8aa8f6b1 Thomas Thrainer
        if pnode.offline:
395 8aa8f6b1 Thomas Thrainer
          self.LogWarning("Primary node %s is marked offline, returning static"
396 8aa8f6b1 Thomas Thrainer
                          " information only for instance %s" %
397 8aa8f6b1 Thomas Thrainer
                          (pnode.name, instance.name))
398 8aa8f6b1 Thomas Thrainer
      else:
399 0bbec3af Helga Velroyen
        remote_info = self.rpc.call_instance_info(
400 0bbec3af Helga Velroyen
            instance.primary_node, instance.name, instance.hypervisor,
401 0bbec3af Helga Velroyen
            cluster.hvparams[instance.hypervisor])
402 1c3231aa Thomas Thrainer
        remote_info.Raise("Error checking node %s" % pnode.name)
403 8aa8f6b1 Thomas Thrainer
        remote_info = remote_info.payload
404 8aa8f6b1 Thomas Thrainer
        if remote_info and "state" in remote_info:
405 8aa8f6b1 Thomas Thrainer
          remote_state = "up"
406 8aa8f6b1 Thomas Thrainer
        else:
407 8aa8f6b1 Thomas Thrainer
          if instance.admin_state == constants.ADMINST_UP:
408 8aa8f6b1 Thomas Thrainer
            remote_state = "down"
409 8aa8f6b1 Thomas Thrainer
          else:
410 8aa8f6b1 Thomas Thrainer
            remote_state = instance.admin_state
411 8aa8f6b1 Thomas Thrainer
412 1c3231aa Thomas Thrainer
      group2name_fn = lambda uuid: groups[uuid].name
413 1c3231aa Thomas Thrainer
      node_uuid2name_fn = lambda uuid: nodes[uuid].name
414 1c3231aa Thomas Thrainer
415 1c3231aa Thomas Thrainer
      disks = map(compat.partial(self._ComputeDiskStatus, instance,
416 1c3231aa Thomas Thrainer
                                 node_uuid2name_fn),
417 8aa8f6b1 Thomas Thrainer
                  instance.disks)
418 8aa8f6b1 Thomas Thrainer
419 1c3231aa Thomas Thrainer
      snodes_group_uuids = [nodes[snode_uuid].group
420 1c3231aa Thomas Thrainer
                            for snode_uuid in instance.secondary_nodes]
421 8aa8f6b1 Thomas Thrainer
422 8aa8f6b1 Thomas Thrainer
      result[instance.name] = {
423 8aa8f6b1 Thomas Thrainer
        "name": instance.name,
424 8aa8f6b1 Thomas Thrainer
        "config_state": instance.admin_state,
425 8aa8f6b1 Thomas Thrainer
        "run_state": remote_state,
426 1c3231aa Thomas Thrainer
        "pnode": pnode.name,
427 8aa8f6b1 Thomas Thrainer
        "pnode_group_uuid": pnode.group,
428 8aa8f6b1 Thomas Thrainer
        "pnode_group_name": group2name_fn(pnode.group),
429 1c3231aa Thomas Thrainer
        "snodes": map(node_uuid2name_fn, instance.secondary_nodes),
430 8aa8f6b1 Thomas Thrainer
        "snodes_group_uuids": snodes_group_uuids,
431 8aa8f6b1 Thomas Thrainer
        "snodes_group_names": map(group2name_fn, snodes_group_uuids),
432 8aa8f6b1 Thomas Thrainer
        "os": instance.os,
433 8aa8f6b1 Thomas Thrainer
        # this happens to be the same format used for hooks
434 5eacbcae Thomas Thrainer
        "nics": NICListToTuple(self, instance.nics),
435 8aa8f6b1 Thomas Thrainer
        "disk_template": instance.disk_template,
436 8aa8f6b1 Thomas Thrainer
        "disks": disks,
437 8aa8f6b1 Thomas Thrainer
        "hypervisor": instance.hypervisor,
438 8aa8f6b1 Thomas Thrainer
        "network_port": instance.network_port,
439 8aa8f6b1 Thomas Thrainer
        "hv_instance": instance.hvparams,
440 8aa8f6b1 Thomas Thrainer
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
441 8aa8f6b1 Thomas Thrainer
        "be_instance": instance.beparams,
442 8aa8f6b1 Thomas Thrainer
        "be_actual": cluster.FillBE(instance),
443 8aa8f6b1 Thomas Thrainer
        "os_instance": instance.osparams,
444 8aa8f6b1 Thomas Thrainer
        "os_actual": cluster.SimpleFillOS(instance.os, instance.osparams),
445 8aa8f6b1 Thomas Thrainer
        "serial_no": instance.serial_no,
446 8aa8f6b1 Thomas Thrainer
        "mtime": instance.mtime,
447 8aa8f6b1 Thomas Thrainer
        "ctime": instance.ctime,
448 8aa8f6b1 Thomas Thrainer
        "uuid": instance.uuid,
449 8aa8f6b1 Thomas Thrainer
        }
450 8aa8f6b1 Thomas Thrainer
451 8aa8f6b1 Thomas Thrainer
    return result