Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ 44ffd981

History | View | Annotate | Download (16.6 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 0d3f52da Jose A. Lopes
from ganeti.hypervisor import hv_base
39 8aa8f6b1 Thomas Thrainer
40 8aa8f6b1 Thomas Thrainer
import ganeti.masterd.instance
41 8aa8f6b1 Thomas Thrainer
42 8aa8f6b1 Thomas Thrainer
43 5eacbcae Thomas Thrainer
class InstanceQuery(QueryBase):
44 8aa8f6b1 Thomas Thrainer
  FIELDS = query.INSTANCE_FIELDS
45 8aa8f6b1 Thomas Thrainer
46 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self, lu):
47 8aa8f6b1 Thomas Thrainer
    lu.needed_locks = {}
48 5eacbcae Thomas Thrainer
    lu.share_locks = ShareAll()
49 8aa8f6b1 Thomas Thrainer
50 8aa8f6b1 Thomas Thrainer
    if self.names:
51 da4a52a3 Thomas Thrainer
      (_, self.wanted) = GetWantedInstances(lu, self.names)
52 8aa8f6b1 Thomas Thrainer
    else:
53 8aa8f6b1 Thomas Thrainer
      self.wanted = locking.ALL_SET
54 8aa8f6b1 Thomas Thrainer
55 8aa8f6b1 Thomas Thrainer
    self.do_locking = (self.use_locking and
56 8aa8f6b1 Thomas Thrainer
                       query.IQ_LIVE in self.requested_data)
57 8aa8f6b1 Thomas Thrainer
    if self.do_locking:
58 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
59 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODEGROUP] = []
60 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NODE] = []
61 8aa8f6b1 Thomas Thrainer
      lu.needed_locks[locking.LEVEL_NETWORK] = []
62 8aa8f6b1 Thomas Thrainer
      lu.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
63 8aa8f6b1 Thomas Thrainer
64 8aa8f6b1 Thomas Thrainer
    self.do_grouplocks = (self.do_locking and
65 8aa8f6b1 Thomas Thrainer
                          query.IQ_NODES in self.requested_data)
66 8aa8f6b1 Thomas Thrainer
67 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, lu, level):
68 8aa8f6b1 Thomas Thrainer
    if self.do_locking:
69 8aa8f6b1 Thomas Thrainer
      if level == locking.LEVEL_NODEGROUP and self.do_grouplocks:
70 8aa8f6b1 Thomas Thrainer
        assert not lu.needed_locks[locking.LEVEL_NODEGROUP]
71 8aa8f6b1 Thomas Thrainer
72 8aa8f6b1 Thomas Thrainer
        # Lock all groups used by instances optimistically; this requires going
73 8aa8f6b1 Thomas Thrainer
        # via the node before it's locked, requiring verification later on
74 8aa8f6b1 Thomas Thrainer
        lu.needed_locks[locking.LEVEL_NODEGROUP] = \
75 8aa8f6b1 Thomas Thrainer
          set(group_uuid
76 8aa8f6b1 Thomas Thrainer
              for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
77 da4a52a3 Thomas Thrainer
              for group_uuid in
78 da4a52a3 Thomas Thrainer
                lu.cfg.GetInstanceNodeGroups(
79 da4a52a3 Thomas Thrainer
                  lu.cfg.GetInstanceInfoByName(instance_name).uuid))
80 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NODE:
81 8aa8f6b1 Thomas Thrainer
        lu._LockInstancesNodes() # pylint: disable=W0212
82 8aa8f6b1 Thomas Thrainer
83 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NETWORK:
84 8aa8f6b1 Thomas Thrainer
        lu.needed_locks[locking.LEVEL_NETWORK] = \
85 8aa8f6b1 Thomas Thrainer
          frozenset(net_uuid
86 8aa8f6b1 Thomas Thrainer
                    for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
87 da4a52a3 Thomas Thrainer
                    for net_uuid in
88 da4a52a3 Thomas Thrainer
                      lu.cfg.GetInstanceNetworks(
89 da4a52a3 Thomas Thrainer
                        lu.cfg.GetInstanceInfoByName(instance_name).uuid))
90 8aa8f6b1 Thomas Thrainer
91 8aa8f6b1 Thomas Thrainer
  @staticmethod
92 8aa8f6b1 Thomas Thrainer
  def _CheckGroupLocks(lu):
93 da4a52a3 Thomas Thrainer
    owned_instance_names = frozenset(lu.owned_locks(locking.LEVEL_INSTANCE))
94 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(lu.owned_locks(locking.LEVEL_NODEGROUP))
95 8aa8f6b1 Thomas Thrainer
96 8aa8f6b1 Thomas Thrainer
    # Check if node groups for locked instances are still correct
97 da4a52a3 Thomas Thrainer
    for instance_name in owned_instance_names:
98 da4a52a3 Thomas Thrainer
      instance = lu.cfg.GetInstanceInfoByName(instance_name)
99 da4a52a3 Thomas Thrainer
      CheckInstanceNodeGroups(lu.cfg, instance.uuid, owned_groups)
100 8aa8f6b1 Thomas Thrainer
101 8aa8f6b1 Thomas Thrainer
  def _GetQueryData(self, lu):
102 8aa8f6b1 Thomas Thrainer
    """Computes the list of instances and their attributes.
103 8aa8f6b1 Thomas Thrainer

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

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

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

283 8aa8f6b1 Thomas Thrainer
    This only checks the optional instance list against the existing names.
284 8aa8f6b1 Thomas Thrainer

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

309 8aa8f6b1 Thomas Thrainer
    """
310 1c3231aa Thomas Thrainer
    if self.op.static or not node_uuid:
311 8aa8f6b1 Thomas Thrainer
      return None
312 8aa8f6b1 Thomas Thrainer
313 0c3d9c7c Thomas Thrainer
    result = self.rpc.call_blockdev_find(node_uuid, (dev, instance))
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 66a37e7a Helga Velroyen
    if dev.dev_type in constants.DTS_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
      "pstatus": dev_pstatus,
377 8aa8f6b1 Thomas Thrainer
      "sstatus": dev_sstatus,
378 8aa8f6b1 Thomas Thrainer
      "children": dev_children,
379 8aa8f6b1 Thomas Thrainer
      "mode": dev.mode,
380 8aa8f6b1 Thomas Thrainer
      "size": dev.size,
381 75a6c8be Bernardo Dal Seno
      "spindles": dev.spindles,
382 8aa8f6b1 Thomas Thrainer
      "name": dev.name,
383 8aa8f6b1 Thomas Thrainer
      "uuid": dev.uuid,
384 8aa8f6b1 Thomas Thrainer
      }
385 8aa8f6b1 Thomas Thrainer
386 8aa8f6b1 Thomas Thrainer
  def Exec(self, feedback_fn):
387 8aa8f6b1 Thomas Thrainer
    """Gather and return data"""
388 8aa8f6b1 Thomas Thrainer
    result = {}
389 8aa8f6b1 Thomas Thrainer
390 8aa8f6b1 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
391 8aa8f6b1 Thomas Thrainer
392 1c3231aa Thomas Thrainer
    node_uuids = itertools.chain(*(i.all_nodes for i in self.wanted_instances))
393 1c3231aa Thomas Thrainer
    nodes = dict(self.cfg.GetMultiNodeInfo(node_uuids))
394 8aa8f6b1 Thomas Thrainer
395 8aa8f6b1 Thomas Thrainer
    groups = dict(self.cfg.GetMultiNodeGroupInfo(node.group
396 8aa8f6b1 Thomas Thrainer
                                                 for node in nodes.values()))
397 8aa8f6b1 Thomas Thrainer
398 8aa8f6b1 Thomas Thrainer
    for instance in self.wanted_instances:
399 8aa8f6b1 Thomas Thrainer
      pnode = nodes[instance.primary_node]
400 8aa8f6b1 Thomas Thrainer
401 8aa8f6b1 Thomas Thrainer
      if self.op.static or pnode.offline:
402 8aa8f6b1 Thomas Thrainer
        remote_state = None
403 8aa8f6b1 Thomas Thrainer
        if pnode.offline:
404 8aa8f6b1 Thomas Thrainer
          self.LogWarning("Primary node %s is marked offline, returning static"
405 8aa8f6b1 Thomas Thrainer
                          " information only for instance %s" %
406 8aa8f6b1 Thomas Thrainer
                          (pnode.name, instance.name))
407 8aa8f6b1 Thomas Thrainer
      else:
408 0bbec3af Helga Velroyen
        remote_info = self.rpc.call_instance_info(
409 0bbec3af Helga Velroyen
            instance.primary_node, instance.name, instance.hypervisor,
410 0bbec3af Helga Velroyen
            cluster.hvparams[instance.hypervisor])
411 1c3231aa Thomas Thrainer
        remote_info.Raise("Error checking node %s" % pnode.name)
412 8aa8f6b1 Thomas Thrainer
        remote_info = remote_info.payload
413 8aa8f6b1 Thomas Thrainer
        if remote_info and "state" in remote_info:
414 0d3f52da Jose A. Lopes
          if hv_base.HvInstanceState.IsShutdown(remote_info["state"]):
415 0d3f52da Jose A. Lopes
            remote_state = "user down"
416 0d3f52da Jose A. Lopes
          else:
417 0d3f52da Jose A. Lopes
            remote_state = "up"
418 8aa8f6b1 Thomas Thrainer
        else:
419 8aa8f6b1 Thomas Thrainer
          if instance.admin_state == constants.ADMINST_UP:
420 8aa8f6b1 Thomas Thrainer
            remote_state = "down"
421 8aa8f6b1 Thomas Thrainer
          else:
422 8aa8f6b1 Thomas Thrainer
            remote_state = instance.admin_state
423 8aa8f6b1 Thomas Thrainer
424 1c3231aa Thomas Thrainer
      group2name_fn = lambda uuid: groups[uuid].name
425 1c3231aa Thomas Thrainer
      node_uuid2name_fn = lambda uuid: nodes[uuid].name
426 1c3231aa Thomas Thrainer
427 1c3231aa Thomas Thrainer
      disks = map(compat.partial(self._ComputeDiskStatus, instance,
428 1c3231aa Thomas Thrainer
                                 node_uuid2name_fn),
429 8aa8f6b1 Thomas Thrainer
                  instance.disks)
430 8aa8f6b1 Thomas Thrainer
431 1c3231aa Thomas Thrainer
      snodes_group_uuids = [nodes[snode_uuid].group
432 1c3231aa Thomas Thrainer
                            for snode_uuid in instance.secondary_nodes]
433 8aa8f6b1 Thomas Thrainer
434 8aa8f6b1 Thomas Thrainer
      result[instance.name] = {
435 8aa8f6b1 Thomas Thrainer
        "name": instance.name,
436 8aa8f6b1 Thomas Thrainer
        "config_state": instance.admin_state,
437 8aa8f6b1 Thomas Thrainer
        "run_state": remote_state,
438 1c3231aa Thomas Thrainer
        "pnode": pnode.name,
439 8aa8f6b1 Thomas Thrainer
        "pnode_group_uuid": pnode.group,
440 8aa8f6b1 Thomas Thrainer
        "pnode_group_name": group2name_fn(pnode.group),
441 1c3231aa Thomas Thrainer
        "snodes": map(node_uuid2name_fn, instance.secondary_nodes),
442 8aa8f6b1 Thomas Thrainer
        "snodes_group_uuids": snodes_group_uuids,
443 8aa8f6b1 Thomas Thrainer
        "snodes_group_names": map(group2name_fn, snodes_group_uuids),
444 8aa8f6b1 Thomas Thrainer
        "os": instance.os,
445 8aa8f6b1 Thomas Thrainer
        # this happens to be the same format used for hooks
446 5eacbcae Thomas Thrainer
        "nics": NICListToTuple(self, instance.nics),
447 8aa8f6b1 Thomas Thrainer
        "disk_template": instance.disk_template,
448 8aa8f6b1 Thomas Thrainer
        "disks": disks,
449 8aa8f6b1 Thomas Thrainer
        "hypervisor": instance.hypervisor,
450 8aa8f6b1 Thomas Thrainer
        "network_port": instance.network_port,
451 8aa8f6b1 Thomas Thrainer
        "hv_instance": instance.hvparams,
452 8aa8f6b1 Thomas Thrainer
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
453 8aa8f6b1 Thomas Thrainer
        "be_instance": instance.beparams,
454 8aa8f6b1 Thomas Thrainer
        "be_actual": cluster.FillBE(instance),
455 8aa8f6b1 Thomas Thrainer
        "os_instance": instance.osparams,
456 8aa8f6b1 Thomas Thrainer
        "os_actual": cluster.SimpleFillOS(instance.os, instance.osparams),
457 8aa8f6b1 Thomas Thrainer
        "serial_no": instance.serial_no,
458 8aa8f6b1 Thomas Thrainer
        "mtime": instance.mtime,
459 8aa8f6b1 Thomas Thrainer
        "ctime": instance.ctime,
460 8aa8f6b1 Thomas Thrainer
        "uuid": instance.uuid,
461 8aa8f6b1 Thomas Thrainer
        }
462 8aa8f6b1 Thomas Thrainer
463 8aa8f6b1 Thomas Thrainer
    return result