Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ a57e502a

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 0c3d9c7c Thomas Thrainer
    result = self.rpc.call_blockdev_find(node_uuid, (dev, instance))
312 8aa8f6b1 Thomas Thrainer
    if result.offline:
313 8aa8f6b1 Thomas Thrainer
      return None
314 8aa8f6b1 Thomas Thrainer
315 8aa8f6b1 Thomas Thrainer
    result.Raise("Can't compute disk status for %s" % instance.name)
316 8aa8f6b1 Thomas Thrainer
317 8aa8f6b1 Thomas Thrainer
    status = result.payload
318 8aa8f6b1 Thomas Thrainer
    if status is None:
319 8aa8f6b1 Thomas Thrainer
      return None
320 8aa8f6b1 Thomas Thrainer
321 8aa8f6b1 Thomas Thrainer
    return (status.dev_path, status.major, status.minor,
322 8aa8f6b1 Thomas Thrainer
            status.sync_percent, status.estimated_time,
323 8aa8f6b1 Thomas Thrainer
            status.is_degraded, status.ldisk_status)
324 8aa8f6b1 Thomas Thrainer
325 1c3231aa Thomas Thrainer
  def _ComputeDiskStatus(self, instance, node_uuid2name_fn, dev):
326 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
327 8aa8f6b1 Thomas Thrainer

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

338 8aa8f6b1 Thomas Thrainer
    @attention: The device has to be annotated already.
339 8aa8f6b1 Thomas Thrainer

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