Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / instance_query.py @ 809a055b

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