Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ 06c2fb4a

History | View | Annotate | Download (15 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 8aa8f6b1 Thomas Thrainer
    instance_list = [all_info[name] for name in instance_names]
108 8aa8f6b1 Thomas Thrainer
    nodes = frozenset(itertools.chain(*(inst.all_nodes
109 8aa8f6b1 Thomas Thrainer
                                        for inst in instance_list)))
110 8aa8f6b1 Thomas Thrainer
    hv_list = list(set([inst.hypervisor for inst in instance_list]))
111 8aa8f6b1 Thomas Thrainer
    bad_nodes = []
112 8aa8f6b1 Thomas Thrainer
    offline_nodes = []
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 8aa8f6b1 Thomas Thrainer
      node_data = lu.rpc.call_all_instances_info(nodes, hv_list)
119 8aa8f6b1 Thomas Thrainer
      for name in nodes:
120 8aa8f6b1 Thomas Thrainer
        result = node_data[name]
121 8aa8f6b1 Thomas Thrainer
        if result.offline:
122 8aa8f6b1 Thomas Thrainer
          # offline nodes will be in both lists
123 8aa8f6b1 Thomas Thrainer
          assert result.fail_msg
124 8aa8f6b1 Thomas Thrainer
          offline_nodes.append(name)
125 8aa8f6b1 Thomas Thrainer
        if result.fail_msg:
126 8aa8f6b1 Thomas Thrainer
          bad_nodes.append(name)
127 8aa8f6b1 Thomas Thrainer
        elif result.payload:
128 8aa8f6b1 Thomas Thrainer
          for inst in result.payload:
129 8aa8f6b1 Thomas Thrainer
            if inst in all_info:
130 8aa8f6b1 Thomas Thrainer
              if all_info[inst].primary_node == name:
131 8aa8f6b1 Thomas Thrainer
                live_data.update(result.payload)
132 8aa8f6b1 Thomas Thrainer
              else:
133 8aa8f6b1 Thomas Thrainer
                wrongnode_inst.add(inst)
134 8aa8f6b1 Thomas Thrainer
            else:
135 8aa8f6b1 Thomas Thrainer
              # orphan instance; we don't list it here as we don't
136 8aa8f6b1 Thomas Thrainer
              # handle this case yet in the output of instance listing
137 8aa8f6b1 Thomas Thrainer
              logging.warning("Orphan instance '%s' found on node %s",
138 8aa8f6b1 Thomas Thrainer
                              inst, name)
139 8aa8f6b1 Thomas Thrainer
              # else no instance is alive
140 8aa8f6b1 Thomas Thrainer
    else:
141 8aa8f6b1 Thomas Thrainer
      live_data = {}
142 8aa8f6b1 Thomas Thrainer
143 8aa8f6b1 Thomas Thrainer
    if query.IQ_DISKUSAGE in self.requested_data:
144 8aa8f6b1 Thomas Thrainer
      gmi = ganeti.masterd.instance
145 8aa8f6b1 Thomas Thrainer
      disk_usage = dict((inst.name,
146 8aa8f6b1 Thomas Thrainer
                         gmi.ComputeDiskSize(inst.disk_template,
147 8aa8f6b1 Thomas Thrainer
                                             [{constants.IDISK_SIZE: disk.size}
148 8aa8f6b1 Thomas Thrainer
                                              for disk in inst.disks]))
149 8aa8f6b1 Thomas Thrainer
                        for inst in instance_list)
150 8aa8f6b1 Thomas Thrainer
    else:
151 8aa8f6b1 Thomas Thrainer
      disk_usage = None
152 8aa8f6b1 Thomas Thrainer
153 8aa8f6b1 Thomas Thrainer
    if query.IQ_CONSOLE in self.requested_data:
154 8aa8f6b1 Thomas Thrainer
      consinfo = {}
155 8aa8f6b1 Thomas Thrainer
      for inst in instance_list:
156 8aa8f6b1 Thomas Thrainer
        if inst.name in live_data:
157 8aa8f6b1 Thomas Thrainer
          # Instance is running
158 5eacbcae Thomas Thrainer
          consinfo[inst.name] = GetInstanceConsole(cluster, inst)
159 8aa8f6b1 Thomas Thrainer
        else:
160 8aa8f6b1 Thomas Thrainer
          consinfo[inst.name] = None
161 8aa8f6b1 Thomas Thrainer
      assert set(consinfo.keys()) == set(instance_names)
162 8aa8f6b1 Thomas Thrainer
    else:
163 8aa8f6b1 Thomas Thrainer
      consinfo = None
164 8aa8f6b1 Thomas Thrainer
165 8aa8f6b1 Thomas Thrainer
    if query.IQ_NODES in self.requested_data:
166 8aa8f6b1 Thomas Thrainer
      node_names = set(itertools.chain(*map(operator.attrgetter("all_nodes"),
167 8aa8f6b1 Thomas Thrainer
                                            instance_list)))
168 8aa8f6b1 Thomas Thrainer
      nodes = dict(lu.cfg.GetMultiNodeInfo(node_names))
169 8aa8f6b1 Thomas Thrainer
      groups = dict((uuid, lu.cfg.GetNodeGroup(uuid))
170 8aa8f6b1 Thomas Thrainer
                    for uuid in set(map(operator.attrgetter("group"),
171 8aa8f6b1 Thomas Thrainer
                                        nodes.values())))
172 8aa8f6b1 Thomas Thrainer
    else:
173 8aa8f6b1 Thomas Thrainer
      nodes = None
174 8aa8f6b1 Thomas Thrainer
      groups = None
175 8aa8f6b1 Thomas Thrainer
176 8aa8f6b1 Thomas Thrainer
    if query.IQ_NETWORKS in self.requested_data:
177 8aa8f6b1 Thomas Thrainer
      net_uuids = itertools.chain(*(lu.cfg.GetInstanceNetworks(i.name)
178 8aa8f6b1 Thomas Thrainer
                                    for i in instance_list))
179 8aa8f6b1 Thomas Thrainer
      networks = dict((uuid, lu.cfg.GetNetwork(uuid)) for uuid in net_uuids)
180 8aa8f6b1 Thomas Thrainer
    else:
181 8aa8f6b1 Thomas Thrainer
      networks = None
182 8aa8f6b1 Thomas Thrainer
183 8aa8f6b1 Thomas Thrainer
    return query.InstanceQueryData(instance_list, lu.cfg.GetClusterInfo(),
184 8aa8f6b1 Thomas Thrainer
                                   disk_usage, offline_nodes, bad_nodes,
185 8aa8f6b1 Thomas Thrainer
                                   live_data, wrongnode_inst, consinfo,
186 8aa8f6b1 Thomas Thrainer
                                   nodes, groups, networks)
187 8aa8f6b1 Thomas Thrainer
188 8aa8f6b1 Thomas Thrainer
189 8aa8f6b1 Thomas Thrainer
class LUInstanceQuery(NoHooksLU):
190 8aa8f6b1 Thomas Thrainer
  """Logical unit for querying instances.
191 8aa8f6b1 Thomas Thrainer

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

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

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

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

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

319 8aa8f6b1 Thomas Thrainer
    """
320 5eacbcae Thomas Thrainer
    (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg)
321 8aa8f6b1 Thomas Thrainer
322 8aa8f6b1 Thomas Thrainer
    return self._ComputeDiskStatusInner(instance, snode, anno_dev)
323 8aa8f6b1 Thomas Thrainer
324 8aa8f6b1 Thomas Thrainer
  def _ComputeDiskStatusInner(self, instance, snode, dev):
325 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
326 8aa8f6b1 Thomas Thrainer

327 8aa8f6b1 Thomas Thrainer
    @attention: The device has to be annotated already.
328 8aa8f6b1 Thomas Thrainer

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