Package ganeti :: Package cmdlib :: Module instance_query
[hide private]
[frames] | no frames]

Source Code for Module ganeti.cmdlib.instance_query

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """Logical units for querying instances.""" 
 32   
 33  import itertools 
 34   
 35  from ganeti import compat 
 36  from ganeti import constants 
 37  from ganeti import locking 
 38  from ganeti.cmdlib.base import NoHooksLU 
 39  from ganeti.cmdlib.common import ShareAll, GetWantedInstances, \ 
 40    CheckInstancesNodeGroups, AnnotateDiskParams 
 41  from ganeti.cmdlib.instance_utils import NICListToTuple 
 42  from ganeti.hypervisor import hv_base 
 43   
 44   
45 -class LUInstanceQueryData(NoHooksLU):
46 """Query runtime instance data. 47 48 """ 49 REQ_BGL = False 50
51 - def ExpandNames(self):
52 self.needed_locks = {} 53 54 # Use locking if requested or when non-static information is wanted 55 if not (self.op.static or self.op.use_locking): 56 self.LogWarning("Non-static data requested, locks need to be acquired") 57 self.op.use_locking = True 58 59 if self.op.instances or not self.op.use_locking: 60 # Expand instance names right here 61 (_, self.wanted_names) = GetWantedInstances(self, self.op.instances) 62 else: 63 # Will use acquired locks 64 self.wanted_names = None 65 66 if self.op.use_locking: 67 self.share_locks = ShareAll() 68 69 if self.wanted_names is None: 70 self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET 71 else: 72 self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names 73 74 self.needed_locks[locking.LEVEL_NODEGROUP] = [] 75 self.needed_locks[locking.LEVEL_NODE] = [] 76 self.needed_locks[locking.LEVEL_NETWORK] = [] 77 self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
78
79 - def DeclareLocks(self, level):
80 if self.op.use_locking: 81 owned_instances = dict(self.cfg.GetMultiInstanceInfoByName( 82 self.owned_locks(locking.LEVEL_INSTANCE))) 83 if level == locking.LEVEL_NODEGROUP: 84 85 # Lock all groups used by instances optimistically; this requires going 86 # via the node before it's locked, requiring verification later on 87 self.needed_locks[locking.LEVEL_NODEGROUP] = \ 88 frozenset(group_uuid 89 for instance_uuid in owned_instances.keys() 90 for group_uuid in 91 self.cfg.GetInstanceNodeGroups(instance_uuid)) 92 93 elif level == locking.LEVEL_NODE: 94 self._LockInstancesNodes() 95 96 elif level == locking.LEVEL_NETWORK: 97 self.needed_locks[locking.LEVEL_NETWORK] = \ 98 frozenset(net_uuid 99 for instance_uuid in owned_instances.keys() 100 for net_uuid in 101 self.cfg.GetInstanceNetworks(instance_uuid))
102
103 - def CheckPrereq(self):
104 """Check prerequisites. 105 106 This only checks the optional instance list against the existing names. 107 108 """ 109 owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) 110 owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) 111 owned_node_uuids = frozenset(self.owned_locks(locking.LEVEL_NODE)) 112 owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK)) 113 114 if self.wanted_names is None: 115 assert self.op.use_locking, "Locking was not used" 116 self.wanted_names = owned_instances 117 118 instances = dict(self.cfg.GetMultiInstanceInfoByName(self.wanted_names)) 119 120 if self.op.use_locking: 121 CheckInstancesNodeGroups(self.cfg, instances, owned_groups, 122 owned_node_uuids, None) 123 else: 124 assert not (owned_instances or owned_groups or 125 owned_node_uuids or owned_networks) 126 127 self.wanted_instances = instances.values()
128
129 - def _ComputeBlockdevStatus(self, node_uuid, instance, dev):
130 """Returns the status of a block device 131 132 """ 133 if self.op.static or not node_uuid: 134 return None 135 136 result = self.rpc.call_blockdev_find(node_uuid, (dev, instance)) 137 if result.offline: 138 return None 139 140 result.Raise("Can't compute disk status for %s" % instance.name) 141 142 status = result.payload 143 if status is None: 144 return None 145 146 return (status.dev_path, status.major, status.minor, 147 status.sync_percent, status.estimated_time, 148 status.is_degraded, status.ldisk_status)
149
150 - def _ComputeDiskStatus(self, instance, node_uuid2name_fn, dev):
151 """Compute block device status. 152 153 """ 154 (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg) 155 156 return self._ComputeDiskStatusInner(instance, None, node_uuid2name_fn, 157 anno_dev)
158
159 - def _ComputeDiskStatusInner(self, instance, snode_uuid, node_uuid2name_fn, 160 dev):
161 """Compute block device status. 162 163 @attention: The device has to be annotated already. 164 165 """ 166 drbd_info = None 167 output_logical_id = dev.logical_id 168 if dev.dev_type in constants.DTS_DRBD: 169 # we change the snode then (otherwise we use the one passed in) 170 if dev.logical_id[0] == instance.primary_node: 171 snode_uuid = dev.logical_id[1] 172 snode_minor = dev.logical_id[4] 173 pnode_minor = dev.logical_id[3] 174 else: 175 snode_uuid = dev.logical_id[0] 176 snode_minor = dev.logical_id[3] 177 pnode_minor = dev.logical_id[4] 178 drbd_info = { 179 "primary_node": node_uuid2name_fn(instance.primary_node), 180 "primary_minor": pnode_minor, 181 "secondary_node": node_uuid2name_fn(snode_uuid), 182 "secondary_minor": snode_minor, 183 "port": dev.logical_id[2], 184 } 185 # replace the secret present at the end of the ids with None 186 output_logical_id = dev.logical_id[:-1] + (None,) 187 188 dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node, 189 instance, dev) 190 dev_sstatus = self._ComputeBlockdevStatus(snode_uuid, instance, dev) 191 192 if dev.children: 193 dev_children = map(compat.partial(self._ComputeDiskStatusInner, 194 instance, snode_uuid, 195 node_uuid2name_fn), 196 dev.children) 197 else: 198 dev_children = [] 199 200 return { 201 "iv_name": dev.iv_name, 202 "dev_type": dev.dev_type, 203 "logical_id": output_logical_id, 204 "drbd_info": drbd_info, 205 "pstatus": dev_pstatus, 206 "sstatus": dev_sstatus, 207 "children": dev_children, 208 "mode": dev.mode, 209 "size": dev.size, 210 "spindles": dev.spindles, 211 "name": dev.name, 212 "uuid": dev.uuid, 213 }
214
215 - def Exec(self, feedback_fn):
216 """Gather and return data""" 217 result = {} 218 219 cluster = self.cfg.GetClusterInfo() 220 221 node_uuids = itertools.chain(*(i.all_nodes for i in self.wanted_instances)) 222 nodes = dict(self.cfg.GetMultiNodeInfo(node_uuids)) 223 224 groups = dict(self.cfg.GetMultiNodeGroupInfo(node.group 225 for node in nodes.values())) 226 227 for instance in self.wanted_instances: 228 pnode = nodes[instance.primary_node] 229 hvparams = cluster.FillHV(instance, skip_globals=True) 230 231 if self.op.static or pnode.offline: 232 remote_state = None 233 if pnode.offline: 234 self.LogWarning("Primary node %s is marked offline, returning static" 235 " information only for instance %s" % 236 (pnode.name, instance.name)) 237 else: 238 remote_info = self.rpc.call_instance_info( 239 instance.primary_node, instance.name, instance.hypervisor, 240 cluster.hvparams[instance.hypervisor]) 241 remote_info.Raise("Error checking node %s" % pnode.name) 242 remote_info = remote_info.payload 243 244 allow_userdown = \ 245 cluster.enabled_user_shutdown and \ 246 (instance.hypervisor != constants.HT_KVM or 247 hvparams[constants.HV_KVM_USER_SHUTDOWN]) 248 249 if remote_info and "state" in remote_info: 250 if hv_base.HvInstanceState.IsShutdown(remote_info["state"]): 251 if allow_userdown: 252 remote_state = "user down" 253 else: 254 remote_state = "down" 255 else: 256 remote_state = "up" 257 else: 258 if instance.admin_state == constants.ADMINST_UP: 259 remote_state = "down" 260 elif instance.admin_state == constants.ADMINST_DOWN: 261 if instance.admin_state_source == constants.USER_SOURCE: 262 remote_state = "user down" 263 else: 264 remote_state = "down" 265 else: 266 remote_state = "offline" 267 268 group2name_fn = lambda uuid: groups[uuid].name 269 node_uuid2name_fn = lambda uuid: nodes[uuid].name 270 271 disks = map(compat.partial(self._ComputeDiskStatus, instance, 272 node_uuid2name_fn), 273 instance.disks) 274 275 snodes_group_uuids = [nodes[snode_uuid].group 276 for snode_uuid in instance.secondary_nodes] 277 278 result[instance.name] = { 279 "name": instance.name, 280 "config_state": instance.admin_state, 281 "run_state": remote_state, 282 "pnode": pnode.name, 283 "pnode_group_uuid": pnode.group, 284 "pnode_group_name": group2name_fn(pnode.group), 285 "snodes": map(node_uuid2name_fn, instance.secondary_nodes), 286 "snodes_group_uuids": snodes_group_uuids, 287 "snodes_group_names": map(group2name_fn, snodes_group_uuids), 288 "os": instance.os, 289 # this happens to be the same format used for hooks 290 "nics": NICListToTuple(self, instance.nics), 291 "disk_template": instance.disk_template, 292 "disks": disks, 293 "hypervisor": instance.hypervisor, 294 "network_port": instance.network_port, 295 "hv_instance": instance.hvparams, 296 "hv_actual": hvparams, 297 "be_instance": instance.beparams, 298 "be_actual": cluster.FillBE(instance), 299 "os_instance": instance.osparams, 300 "os_actual": cluster.SimpleFillOS(instance.os, instance.osparams), 301 "serial_no": instance.serial_no, 302 "mtime": instance.mtime, 303 "ctime": instance.ctime, 304 "uuid": instance.uuid, 305 } 306 307 return result
308