Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ 31d3b918

History | View | Annotate | Download (9.8 kB)

1 8aa8f6b1 Thomas Thrainer
#
2 8aa8f6b1 Thomas Thrainer
#
3 8aa8f6b1 Thomas Thrainer
4 8aa8f6b1 Thomas Thrainer
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 8aa8f6b1 Thomas Thrainer
#
6 8aa8f6b1 Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 8aa8f6b1 Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 8aa8f6b1 Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 8aa8f6b1 Thomas Thrainer
# (at your option) any later version.
10 8aa8f6b1 Thomas Thrainer
#
11 8aa8f6b1 Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 8aa8f6b1 Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 8aa8f6b1 Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 8aa8f6b1 Thomas Thrainer
# General Public License for more details.
15 8aa8f6b1 Thomas Thrainer
#
16 8aa8f6b1 Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 8aa8f6b1 Thomas Thrainer
# along with this program; if not, write to the Free Software
18 8aa8f6b1 Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 8aa8f6b1 Thomas Thrainer
# 02110-1301, USA.
20 8aa8f6b1 Thomas Thrainer
21 8aa8f6b1 Thomas Thrainer
22 8aa8f6b1 Thomas Thrainer
"""Logical units for querying instances."""
23 8aa8f6b1 Thomas Thrainer
24 8aa8f6b1 Thomas Thrainer
import itertools
25 8aa8f6b1 Thomas Thrainer
26 8aa8f6b1 Thomas Thrainer
from ganeti import compat
27 8aa8f6b1 Thomas Thrainer
from ganeti import constants
28 8aa8f6b1 Thomas Thrainer
from ganeti import locking
29 5c98b73e Helga Velroyen
from ganeti.cmdlib.base import NoHooksLU
30 5eacbcae Thomas Thrainer
from ganeti.cmdlib.common import ShareAll, GetWantedInstances, \
31 2a02d6fe Helga Velroyen
  CheckInstancesNodeGroups, AnnotateDiskParams
32 5eacbcae Thomas Thrainer
from ganeti.cmdlib.instance_utils import NICListToTuple
33 0d3f52da Jose A. Lopes
from ganeti.hypervisor import hv_base
34 8aa8f6b1 Thomas Thrainer
35 8aa8f6b1 Thomas Thrainer
36 8aa8f6b1 Thomas Thrainer
class LUInstanceQueryData(NoHooksLU):
37 8aa8f6b1 Thomas Thrainer
  """Query runtime instance data.
38 8aa8f6b1 Thomas Thrainer

39 8aa8f6b1 Thomas Thrainer
  """
40 8aa8f6b1 Thomas Thrainer
  REQ_BGL = False
41 8aa8f6b1 Thomas Thrainer
42 8aa8f6b1 Thomas Thrainer
  def ExpandNames(self):
43 8aa8f6b1 Thomas Thrainer
    self.needed_locks = {}
44 8aa8f6b1 Thomas Thrainer
45 8aa8f6b1 Thomas Thrainer
    # Use locking if requested or when non-static information is wanted
46 8aa8f6b1 Thomas Thrainer
    if not (self.op.static or self.op.use_locking):
47 8aa8f6b1 Thomas Thrainer
      self.LogWarning("Non-static data requested, locks need to be acquired")
48 8aa8f6b1 Thomas Thrainer
      self.op.use_locking = True
49 8aa8f6b1 Thomas Thrainer
50 8aa8f6b1 Thomas Thrainer
    if self.op.instances or not self.op.use_locking:
51 8aa8f6b1 Thomas Thrainer
      # Expand instance names right here
52 da4a52a3 Thomas Thrainer
      (_, self.wanted_names) = GetWantedInstances(self, self.op.instances)
53 8aa8f6b1 Thomas Thrainer
    else:
54 8aa8f6b1 Thomas Thrainer
      # Will use acquired locks
55 8aa8f6b1 Thomas Thrainer
      self.wanted_names = None
56 8aa8f6b1 Thomas Thrainer
57 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
58 5eacbcae Thomas Thrainer
      self.share_locks = ShareAll()
59 8aa8f6b1 Thomas Thrainer
60 8aa8f6b1 Thomas Thrainer
      if self.wanted_names is None:
61 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
62 8aa8f6b1 Thomas Thrainer
      else:
63 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names
64 8aa8f6b1 Thomas Thrainer
65 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODEGROUP] = []
66 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NODE] = []
67 8aa8f6b1 Thomas Thrainer
      self.needed_locks[locking.LEVEL_NETWORK] = []
68 8aa8f6b1 Thomas Thrainer
      self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
69 8aa8f6b1 Thomas Thrainer
70 8aa8f6b1 Thomas Thrainer
  def DeclareLocks(self, level):
71 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
72 da4a52a3 Thomas Thrainer
      owned_instances = dict(self.cfg.GetMultiInstanceInfoByName(
73 da4a52a3 Thomas Thrainer
                               self.owned_locks(locking.LEVEL_INSTANCE)))
74 8aa8f6b1 Thomas Thrainer
      if level == locking.LEVEL_NODEGROUP:
75 8aa8f6b1 Thomas Thrainer
76 8aa8f6b1 Thomas Thrainer
        # Lock all groups used by instances optimistically; this requires going
77 8aa8f6b1 Thomas Thrainer
        # via the node before it's locked, requiring verification later on
78 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NODEGROUP] = \
79 8aa8f6b1 Thomas Thrainer
          frozenset(group_uuid
80 da4a52a3 Thomas Thrainer
                    for instance_uuid in owned_instances.keys()
81 8aa8f6b1 Thomas Thrainer
                    for group_uuid in
82 da4a52a3 Thomas Thrainer
                    self.cfg.GetInstanceNodeGroups(instance_uuid))
83 8aa8f6b1 Thomas Thrainer
84 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NODE:
85 8aa8f6b1 Thomas Thrainer
        self._LockInstancesNodes()
86 8aa8f6b1 Thomas Thrainer
87 8aa8f6b1 Thomas Thrainer
      elif level == locking.LEVEL_NETWORK:
88 8aa8f6b1 Thomas Thrainer
        self.needed_locks[locking.LEVEL_NETWORK] = \
89 8aa8f6b1 Thomas Thrainer
          frozenset(net_uuid
90 da4a52a3 Thomas Thrainer
                    for instance_uuid in owned_instances.keys()
91 8aa8f6b1 Thomas Thrainer
                    for net_uuid in
92 da4a52a3 Thomas Thrainer
                    self.cfg.GetInstanceNetworks(instance_uuid))
93 8aa8f6b1 Thomas Thrainer
94 8aa8f6b1 Thomas Thrainer
  def CheckPrereq(self):
95 8aa8f6b1 Thomas Thrainer
    """Check prerequisites.
96 8aa8f6b1 Thomas Thrainer

97 8aa8f6b1 Thomas Thrainer
    This only checks the optional instance list against the existing names.
98 8aa8f6b1 Thomas Thrainer

99 8aa8f6b1 Thomas Thrainer
    """
100 8aa8f6b1 Thomas Thrainer
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
101 8aa8f6b1 Thomas Thrainer
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
102 1c3231aa Thomas Thrainer
    owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE))
103 8aa8f6b1 Thomas Thrainer
    owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK))
104 8aa8f6b1 Thomas Thrainer
105 8aa8f6b1 Thomas Thrainer
    if self.wanted_names is None:
106 8aa8f6b1 Thomas Thrainer
      assert self.op.use_locking, "Locking was not used"
107 8aa8f6b1 Thomas Thrainer
      self.wanted_names = owned_instances
108 8aa8f6b1 Thomas Thrainer
109 da4a52a3 Thomas Thrainer
    instances = dict(self.cfg.GetMultiInstanceInfoByName(self.wanted_names))
110 8aa8f6b1 Thomas Thrainer
111 8aa8f6b1 Thomas Thrainer
    if self.op.use_locking:
112 1c3231aa Thomas Thrainer
      CheckInstancesNodeGroups(self.cfg, instances, owned_groups,
113 1c3231aa Thomas Thrainer
                               owned_node_uuids, None)
114 8aa8f6b1 Thomas Thrainer
    else:
115 8aa8f6b1 Thomas Thrainer
      assert not (owned_instances or owned_groups or
116 1c3231aa Thomas Thrainer
                  owned_node_uuids or owned_networks)
117 8aa8f6b1 Thomas Thrainer
118 8aa8f6b1 Thomas Thrainer
    self.wanted_instances = instances.values()
119 8aa8f6b1 Thomas Thrainer
120 1c3231aa Thomas Thrainer
  def _ComputeBlockdevStatus(self, node_uuid, instance, dev):
121 8aa8f6b1 Thomas Thrainer
    """Returns the status of a block device
122 8aa8f6b1 Thomas Thrainer

123 8aa8f6b1 Thomas Thrainer
    """
124 1c3231aa Thomas Thrainer
    if self.op.static or not node_uuid:
125 8aa8f6b1 Thomas Thrainer
      return None
126 8aa8f6b1 Thomas Thrainer
127 0c3d9c7c Thomas Thrainer
    result = self.rpc.call_blockdev_find(node_uuid, (dev, instance))
128 8aa8f6b1 Thomas Thrainer
    if result.offline:
129 8aa8f6b1 Thomas Thrainer
      return None
130 8aa8f6b1 Thomas Thrainer
131 8aa8f6b1 Thomas Thrainer
    result.Raise("Can't compute disk status for %s" % instance.name)
132 8aa8f6b1 Thomas Thrainer
133 8aa8f6b1 Thomas Thrainer
    status = result.payload
134 8aa8f6b1 Thomas Thrainer
    if status is None:
135 8aa8f6b1 Thomas Thrainer
      return None
136 8aa8f6b1 Thomas Thrainer
137 8aa8f6b1 Thomas Thrainer
    return (status.dev_path, status.major, status.minor,
138 8aa8f6b1 Thomas Thrainer
            status.sync_percent, status.estimated_time,
139 8aa8f6b1 Thomas Thrainer
            status.is_degraded, status.ldisk_status)
140 8aa8f6b1 Thomas Thrainer
141 1c3231aa Thomas Thrainer
  def _ComputeDiskStatus(self, instance, node_uuid2name_fn, dev):
142 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
143 8aa8f6b1 Thomas Thrainer

144 8aa8f6b1 Thomas Thrainer
    """
145 5eacbcae Thomas Thrainer
    (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg)
146 8aa8f6b1 Thomas Thrainer
147 1c3231aa Thomas Thrainer
    return self._ComputeDiskStatusInner(instance, None, node_uuid2name_fn,
148 1c3231aa Thomas Thrainer
                                        anno_dev)
149 8aa8f6b1 Thomas Thrainer
150 1c3231aa Thomas Thrainer
  def _ComputeDiskStatusInner(self, instance, snode_uuid, node_uuid2name_fn,
151 1c3231aa Thomas Thrainer
                              dev):
152 8aa8f6b1 Thomas Thrainer
    """Compute block device status.
153 8aa8f6b1 Thomas Thrainer

154 8aa8f6b1 Thomas Thrainer
    @attention: The device has to be annotated already.
155 8aa8f6b1 Thomas Thrainer

156 8aa8f6b1 Thomas Thrainer
    """
157 1c3231aa Thomas Thrainer
    drbd_info = None
158 66a37e7a Helga Velroyen
    if dev.dev_type in constants.DTS_DRBD:
159 8aa8f6b1 Thomas Thrainer
      # we change the snode then (otherwise we use the one passed in)
160 8aa8f6b1 Thomas Thrainer
      if dev.logical_id[0] == instance.primary_node:
161 1c3231aa Thomas Thrainer
        snode_uuid = dev.logical_id[1]
162 8aa8f6b1 Thomas Thrainer
      else:
163 1c3231aa Thomas Thrainer
        snode_uuid = dev.logical_id[0]
164 1c3231aa Thomas Thrainer
      drbd_info = {
165 1c3231aa Thomas Thrainer
        "primary_node": node_uuid2name_fn(instance.primary_node),
166 1c3231aa Thomas Thrainer
        "primary_minor": dev.logical_id[3],
167 1c3231aa Thomas Thrainer
        "secondary_node": node_uuid2name_fn(snode_uuid),
168 1c3231aa Thomas Thrainer
        "secondary_minor": dev.logical_id[4],
169 1c3231aa Thomas Thrainer
        "port": dev.logical_id[2],
170 1c3231aa Thomas Thrainer
        "secret": dev.logical_id[5],
171 1c3231aa Thomas Thrainer
      }
172 8aa8f6b1 Thomas Thrainer
173 8aa8f6b1 Thomas Thrainer
    dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
174 8aa8f6b1 Thomas Thrainer
                                              instance, dev)
175 1c3231aa Thomas Thrainer
    dev_sstatus = self._ComputeBlockdevStatus(snode_uuid, instance, dev)
176 8aa8f6b1 Thomas Thrainer
177 8aa8f6b1 Thomas Thrainer
    if dev.children:
178 8aa8f6b1 Thomas Thrainer
      dev_children = map(compat.partial(self._ComputeDiskStatusInner,
179 1c3231aa Thomas Thrainer
                                        instance, snode_uuid,
180 1c3231aa Thomas Thrainer
                                        node_uuid2name_fn),
181 8aa8f6b1 Thomas Thrainer
                         dev.children)
182 8aa8f6b1 Thomas Thrainer
    else:
183 8aa8f6b1 Thomas Thrainer
      dev_children = []
184 8aa8f6b1 Thomas Thrainer
185 8aa8f6b1 Thomas Thrainer
    return {
186 8aa8f6b1 Thomas Thrainer
      "iv_name": dev.iv_name,
187 8aa8f6b1 Thomas Thrainer
      "dev_type": dev.dev_type,
188 8aa8f6b1 Thomas Thrainer
      "logical_id": dev.logical_id,
189 1c3231aa Thomas Thrainer
      "drbd_info": drbd_info,
190 8aa8f6b1 Thomas Thrainer
      "pstatus": dev_pstatus,
191 8aa8f6b1 Thomas Thrainer
      "sstatus": dev_sstatus,
192 8aa8f6b1 Thomas Thrainer
      "children": dev_children,
193 8aa8f6b1 Thomas Thrainer
      "mode": dev.mode,
194 8aa8f6b1 Thomas Thrainer
      "size": dev.size,
195 75a6c8be Bernardo Dal Seno
      "spindles": dev.spindles,
196 8aa8f6b1 Thomas Thrainer
      "name": dev.name,
197 8aa8f6b1 Thomas Thrainer
      "uuid": dev.uuid,
198 8aa8f6b1 Thomas Thrainer
      }
199 8aa8f6b1 Thomas Thrainer
200 8aa8f6b1 Thomas Thrainer
  def Exec(self, feedback_fn):
201 8aa8f6b1 Thomas Thrainer
    """Gather and return data"""
202 8aa8f6b1 Thomas Thrainer
    result = {}
203 8aa8f6b1 Thomas Thrainer
204 8aa8f6b1 Thomas Thrainer
    cluster = self.cfg.GetClusterInfo()
205 8aa8f6b1 Thomas Thrainer
206 1c3231aa Thomas Thrainer
    node_uuids = itertools.chain(*(i.all_nodes for i in self.wanted_instances))
207 1c3231aa Thomas Thrainer
    nodes = dict(self.cfg.GetMultiNodeInfo(node_uuids))
208 8aa8f6b1 Thomas Thrainer
209 8aa8f6b1 Thomas Thrainer
    groups = dict(self.cfg.GetMultiNodeGroupInfo(node.group
210 8aa8f6b1 Thomas Thrainer
                                                 for node in nodes.values()))
211 8aa8f6b1 Thomas Thrainer
212 8aa8f6b1 Thomas Thrainer
    for instance in self.wanted_instances:
213 8aa8f6b1 Thomas Thrainer
      pnode = nodes[instance.primary_node]
214 8aa8f6b1 Thomas Thrainer
215 8aa8f6b1 Thomas Thrainer
      if self.op.static or pnode.offline:
216 8aa8f6b1 Thomas Thrainer
        remote_state = None
217 8aa8f6b1 Thomas Thrainer
        if pnode.offline:
218 8aa8f6b1 Thomas Thrainer
          self.LogWarning("Primary node %s is marked offline, returning static"
219 8aa8f6b1 Thomas Thrainer
                          " information only for instance %s" %
220 8aa8f6b1 Thomas Thrainer
                          (pnode.name, instance.name))
221 8aa8f6b1 Thomas Thrainer
      else:
222 0bbec3af Helga Velroyen
        remote_info = self.rpc.call_instance_info(
223 0bbec3af Helga Velroyen
            instance.primary_node, instance.name, instance.hypervisor,
224 0bbec3af Helga Velroyen
            cluster.hvparams[instance.hypervisor])
225 1c3231aa Thomas Thrainer
        remote_info.Raise("Error checking node %s" % pnode.name)
226 8aa8f6b1 Thomas Thrainer
        remote_info = remote_info.payload
227 8aa8f6b1 Thomas Thrainer
        if remote_info and "state" in remote_info:
228 afa0fca4 Jose A. Lopes
          if hv_base.HvInstanceState.IsShutdown(remote_info["state"]) \
229 afa0fca4 Jose A. Lopes
                and (instance.hypervisor != constants.HT_KVM
230 afa0fca4 Jose A. Lopes
                       or instance.hvparams[constants.HV_KVM_USER_SHUTDOWN]):
231 0d3f52da Jose A. Lopes
            remote_state = "user down"
232 0d3f52da Jose A. Lopes
          else:
233 0d3f52da Jose A. Lopes
            remote_state = "up"
234 8aa8f6b1 Thomas Thrainer
        else:
235 8aa8f6b1 Thomas Thrainer
          if instance.admin_state == constants.ADMINST_UP:
236 8aa8f6b1 Thomas Thrainer
            remote_state = "down"
237 8aa8f6b1 Thomas Thrainer
          else:
238 8aa8f6b1 Thomas Thrainer
            remote_state = instance.admin_state
239 8aa8f6b1 Thomas Thrainer
240 1c3231aa Thomas Thrainer
      group2name_fn = lambda uuid: groups[uuid].name
241 1c3231aa Thomas Thrainer
      node_uuid2name_fn = lambda uuid: nodes[uuid].name
242 1c3231aa Thomas Thrainer
243 1c3231aa Thomas Thrainer
      disks = map(compat.partial(self._ComputeDiskStatus, instance,
244 1c3231aa Thomas Thrainer
                                 node_uuid2name_fn),
245 8aa8f6b1 Thomas Thrainer
                  instance.disks)
246 8aa8f6b1 Thomas Thrainer
247 1c3231aa Thomas Thrainer
      snodes_group_uuids = [nodes[snode_uuid].group
248 1c3231aa Thomas Thrainer
                            for snode_uuid in instance.secondary_nodes]
249 8aa8f6b1 Thomas Thrainer
250 8aa8f6b1 Thomas Thrainer
      result[instance.name] = {
251 8aa8f6b1 Thomas Thrainer
        "name": instance.name,
252 8aa8f6b1 Thomas Thrainer
        "config_state": instance.admin_state,
253 8aa8f6b1 Thomas Thrainer
        "run_state": remote_state,
254 1c3231aa Thomas Thrainer
        "pnode": pnode.name,
255 8aa8f6b1 Thomas Thrainer
        "pnode_group_uuid": pnode.group,
256 8aa8f6b1 Thomas Thrainer
        "pnode_group_name": group2name_fn(pnode.group),
257 1c3231aa Thomas Thrainer
        "snodes": map(node_uuid2name_fn, instance.secondary_nodes),
258 8aa8f6b1 Thomas Thrainer
        "snodes_group_uuids": snodes_group_uuids,
259 8aa8f6b1 Thomas Thrainer
        "snodes_group_names": map(group2name_fn, snodes_group_uuids),
260 8aa8f6b1 Thomas Thrainer
        "os": instance.os,
261 8aa8f6b1 Thomas Thrainer
        # this happens to be the same format used for hooks
262 5eacbcae Thomas Thrainer
        "nics": NICListToTuple(self, instance.nics),
263 8aa8f6b1 Thomas Thrainer
        "disk_template": instance.disk_template,
264 8aa8f6b1 Thomas Thrainer
        "disks": disks,
265 8aa8f6b1 Thomas Thrainer
        "hypervisor": instance.hypervisor,
266 8aa8f6b1 Thomas Thrainer
        "network_port": instance.network_port,
267 8aa8f6b1 Thomas Thrainer
        "hv_instance": instance.hvparams,
268 8aa8f6b1 Thomas Thrainer
        "hv_actual": cluster.FillHV(instance, skip_globals=True),
269 8aa8f6b1 Thomas Thrainer
        "be_instance": instance.beparams,
270 8aa8f6b1 Thomas Thrainer
        "be_actual": cluster.FillBE(instance),
271 8aa8f6b1 Thomas Thrainer
        "os_instance": instance.osparams,
272 8aa8f6b1 Thomas Thrainer
        "os_actual": cluster.SimpleFillOS(instance.os, instance.osparams),
273 8aa8f6b1 Thomas Thrainer
        "serial_no": instance.serial_no,
274 8aa8f6b1 Thomas Thrainer
        "mtime": instance.mtime,
275 8aa8f6b1 Thomas Thrainer
        "ctime": instance.ctime,
276 8aa8f6b1 Thomas Thrainer
        "uuid": instance.uuid,
277 8aa8f6b1 Thomas Thrainer
        }
278 8aa8f6b1 Thomas Thrainer
279 8aa8f6b1 Thomas Thrainer
    return result