Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (16.4 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 da4a52a3 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 da4a52a3 Thomas Thrainer
              for group_uuid in
77 da4a52a3 Thomas Thrainer
                lu.cfg.GetInstanceNodeGroups(
78 da4a52a3 Thomas Thrainer
                  lu.cfg.GetInstanceInfoByName(instance_name).uuid))
79 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NODE:
80 8aa8f6b1 Thomas Thrainer
        lu._LockInstancesNodes() # pylint: disable=W0212
81 8aa8f6b1 Thomas Thrainer
82 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NETWORK:
83 8aa8f6b1 Thomas Thrainer
        lu.needed_locks[locking.LEVEL_NETWORK] = \
84 8aa8f6b1 Thomas Thrainer
          frozenset(net_uuid
85 8aa8f6b1 Thomas Thrainer
                    for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
86 da4a52a3 Thomas Thrainer
                    for net_uuid in
87 da4a52a3 Thomas Thrainer
                      lu.cfg.GetInstanceNetworks(
88 da4a52a3 Thomas Thrainer
                        lu.cfg.GetInstanceInfoByName(instance_name).uuid))
89 8aa8f6b1 Thomas Thrainer
90 8aa8f6b1 Thomas Thrainer
  @staticmethod
91 8aa8f6b1 Thomas Thrainer
  def _CheckGroupLocks(lu):
92 da4a52a3 Thomas Thrainer
    owned_instance_names = frozenset(lu.owned_locks(locking.LEVEL_INSTANCE))
93 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(lu.owned_locks(locking.LEVEL_NODEGROUP))
94 8aa8f6b1 Thomas Thrainer
95 8aa8f6b1 Thomas Thrainer
    # Check if node groups for locked instances are still correct
96 da4a52a3 Thomas Thrainer
    for instance_name in owned_instance_names:
97 da4a52a3 Thomas Thrainer
      instance = lu.cfg.GetInstanceInfoByName(instance_name)
98 da4a52a3 Thomas Thrainer
      CheckInstanceNodeGroups(lu.cfg, instance.uuid, owned_groups)
99 8aa8f6b1 Thomas Thrainer
100 8aa8f6b1 Thomas Thrainer
  def _GetQueryData(self, lu):
101 8aa8f6b1 Thomas Thrainer
    """Computes the list of instances and their attributes.
102 8aa8f6b1 Thomas Thrainer

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

202 8aa8f6b1 Thomas Thrainer
  """
203 8aa8f6b1 Thomas Thrainer
  # pylint: disable=W0142
204 8aa8f6b1 Thomas Thrainer
  REQ_BGL = False
205 8aa8f6b1 Thomas Thrainer
206 8aa8f6b1 Thomas Thrainer
  def CheckArguments(self):
207 5eacbcae Thomas Thrainer
    self.iq = InstanceQuery(qlang.MakeSimpleFilter("name", self.op.names),
208 8aa8f6b1 Thomas Thrainer
                             self.op.output_fields, self.op.use_locking)
209 8aa8f6b1 Thomas Thrainer
210 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self):
211 8aa8f6b1 Thomas Thrainer
    self.iq.ExpandNames(self)
212 8aa8f6b1 Thomas Thrainer
213 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, level):
214 8aa8f6b1 Thomas Thrainer
    self.iq.DeclareLocks(self, level)
215 8aa8f6b1 Thomas Thrainer
216 8aa8f6b1 Thomas Thrainer
  def Exec(self, feedback_fn):
217 8aa8f6b1 Thomas Thrainer
    return self.iq.OldStyleQuery(self)
218 8aa8f6b1 Thomas Thrainer
219 8aa8f6b1 Thomas Thrainer
220 8aa8f6b1 Thomas Thrainer
class LUInstanceQueryData(NoHooksLU):
221 8aa8f6b1 Thomas Thrainer
  """Query runtime instance data.
222 8aa8f6b1 Thomas Thrainer

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

281 8aa8f6b1 Thomas Thrainer
    This only checks the optional instance list against the existing names.
282 8aa8f6b1 Thomas Thrainer

283 8aa8f6b1 Thomas Thrainer
    """
284 8aa8f6b1 Thomas Thrainer
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
285 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
286 1c3231aa Thomas Thrainer
    owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE))
287 8aa8f6b1 Thomas Thrainer
    owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK))
288 8aa8f6b1 Thomas Thrainer
289 8aa8f6b1 Thomas Thrainer
    if self.wanted_names is None:
290 8aa8f6b1 Thomas Thrainer
      assert self.op.use_locking, "Locking was not used"
291 8aa8f6b1 Thomas Thrainer
      self.wanted_names = owned_instances
292 8aa8f6b1 Thomas Thrainer
293 da4a52a3 Thomas Thrainer
    instances = dict(self.cfg.GetMultiInstanceInfoByName(self.wanted_names))
294 8aa8f6b1 Thomas Thrainer
295 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
296 1c3231aa Thomas Thrainer
      CheckInstancesNodeGroups(self.cfg, instances, owned_groups,
297 1c3231aa Thomas Thrainer
                               owned_node_uuids, None)
298 8aa8f6b1 Thomas Thrainer
    else:
299 8aa8f6b1 Thomas Thrainer
      assert not (owned_instances or owned_groups or
300 1c3231aa Thomas Thrainer
                  owned_node_uuids or owned_networks)
301 8aa8f6b1 Thomas Thrainer
302 8aa8f6b1 Thomas Thrainer
    self.wanted_instances = instances.values()
303 8aa8f6b1 Thomas Thrainer
304 1c3231aa Thomas Thrainer
  def _ComputeBlockdevStatus(self, node_uuid, instance, dev):
305 8aa8f6b1 Thomas Thrainer
    """Returns the status of a block device
306 8aa8f6b1 Thomas Thrainer

307 8aa8f6b1 Thomas Thrainer
    """
308 1c3231aa Thomas Thrainer
    if self.op.static or not node_uuid:
309 8aa8f6b1 Thomas Thrainer
      return None
310 8aa8f6b1 Thomas Thrainer
311 1c3231aa Thomas Thrainer
    self.cfg.SetDiskID(dev, node_uuid)
312 8aa8f6b1 Thomas Thrainer
313 1c3231aa Thomas Thrainer
    result = self.rpc.call_blockdev_find(node_uuid, dev)
314 8aa8f6b1 Thomas Thrainer
    if result.offline:
315 8aa8f6b1 Thomas Thrainer
      return None
316 8aa8f6b1 Thomas Thrainer
317 8aa8f6b1 Thomas Thrainer
    result.Raise("Can't compute disk status for %s" % instance.name)
318 8aa8f6b1 Thomas Thrainer
319 8aa8f6b1 Thomas Thrainer
    status = result.payload
320 8aa8f6b1 Thomas Thrainer
    if status is None:
321 8aa8f6b1 Thomas Thrainer
      return None
322 8aa8f6b1 Thomas Thrainer
323 8aa8f6b1 Thomas Thrainer
    return (status.dev_path, status.major, status.minor,
324 8aa8f6b1 Thomas Thrainer
            status.sync_percent, status.estimated_time,
325 8aa8f6b1 Thomas Thrainer
            status.is_degraded, status.ldisk_status)
326 8aa8f6b1 Thomas Thrainer
327 1c3231aa Thomas Thrainer
  def _ComputeDiskStatus(self, instance, node_uuid2name_fn, dev):
328 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
329 8aa8f6b1 Thomas Thrainer

330 8aa8f6b1 Thomas Thrainer
    """
331 5eacbcae Thomas Thrainer
    (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg)
332 8aa8f6b1 Thomas Thrainer
333 1c3231aa Thomas Thrainer
    return self._ComputeDiskStatusInner(instance, None, node_uuid2name_fn,
334 1c3231aa Thomas Thrainer
                                        anno_dev)
335 8aa8f6b1 Thomas Thrainer
336 1c3231aa Thomas Thrainer
  def _ComputeDiskStatusInner(self, instance, snode_uuid, node_uuid2name_fn,
337 1c3231aa Thomas Thrainer
                              dev):
338 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
339 8aa8f6b1 Thomas Thrainer

340 8aa8f6b1 Thomas Thrainer
    @attention: The device has to be annotated already.
341 8aa8f6b1 Thomas Thrainer

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