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

Source Code for Module ganeti.cmdlib.instance_operation

  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 dealing with instance operations (start/stop/...). 
 32   
 33  Those operations have in common that they affect the operating system in a 
 34  running instance directly. 
 35   
 36  """ 
 37   
 38  import logging 
 39   
 40  from ganeti import constants 
 41  from ganeti import errors 
 42  from ganeti import hypervisor 
 43  from ganeti import locking 
 44  from ganeti import objects 
 45  from ganeti import utils 
 46  from ganeti.cmdlib.base import LogicalUnit, NoHooksLU 
 47  from ganeti.cmdlib.common import INSTANCE_ONLINE, INSTANCE_DOWN, \ 
 48    CheckHVParams, CheckInstanceState, CheckNodeOnline, GetUpdatedParams, \ 
 49    CheckOSParams, ShareAll 
 50  from ganeti.cmdlib.instance_storage import StartInstanceDisks, \ 
 51    ShutdownInstanceDisks 
 52  from ganeti.cmdlib.instance_utils import BuildInstanceHookEnvByObject, \ 
 53    CheckInstanceBridgesExist, CheckNodeFreeMemory, CheckNodeHasOS 
 54   
 55   
56 -class LUInstanceStartup(LogicalUnit):
57 """Starts an instance. 58 59 """ 60 HPATH = "instance-start" 61 HTYPE = constants.HTYPE_INSTANCE 62 REQ_BGL = False 63
64 - def CheckArguments(self):
65 # extra beparams 66 if self.op.beparams: 67 # fill the beparams dict 68 objects.UpgradeBeParams(self.op.beparams) 69 utils.ForceDictType(self.op.beparams, constants.BES_PARAMETER_TYPES)
70
71 - def ExpandNames(self):
72 self._ExpandAndLockInstance() 73 self.recalculate_locks[locking.LEVEL_NODE_RES] = constants.LOCKS_REPLACE
74
75 - def DeclareLocks(self, level):
76 if level == locking.LEVEL_NODE_RES: 77 self._LockInstancesNodes(primary_only=True, level=locking.LEVEL_NODE_RES)
78
79 - def BuildHooksEnv(self):
80 """Build hooks env. 81 82 This runs on master, primary and secondary nodes of the instance. 83 84 """ 85 env = { 86 "FORCE": self.op.force, 87 } 88 89 env.update(BuildInstanceHookEnvByObject(self, self.instance)) 90 91 return env
92
93 - def BuildHooksNodes(self):
94 """Build hooks nodes. 95 96 """ 97 nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) 98 return (nl, nl)
99
100 - def CheckPrereq(self):
101 """Check prerequisites. 102 103 This checks that the instance is in the cluster. 104 105 """ 106 self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid) 107 assert self.instance is not None, \ 108 "Cannot retrieve locked instance %s" % self.op.instance_name 109 110 cluster = self.cfg.GetClusterInfo() 111 # extra hvparams 112 if self.op.hvparams: 113 # check hypervisor parameter syntax (locally) 114 utils.ForceDictType(self.op.hvparams, constants.HVS_PARAMETER_TYPES) 115 filled_hvp = cluster.FillHV(self.instance) 116 filled_hvp.update(self.op.hvparams) 117 hv_type = hypervisor.GetHypervisorClass(self.instance.hypervisor) 118 hv_type.CheckParameterSyntax(filled_hvp) 119 CheckHVParams(self, self.instance.all_nodes, self.instance.hypervisor, 120 filled_hvp) 121 122 CheckInstanceState(self, self.instance, INSTANCE_ONLINE) 123 124 self.primary_offline = \ 125 self.cfg.GetNodeInfo(self.instance.primary_node).offline 126 127 if self.primary_offline and self.op.ignore_offline_nodes: 128 self.LogWarning("Ignoring offline primary node") 129 130 if self.op.hvparams or self.op.beparams: 131 self.LogWarning("Overridden parameters are ignored") 132 else: 133 CheckNodeOnline(self, self.instance.primary_node) 134 135 bep = self.cfg.GetClusterInfo().FillBE(self.instance) 136 bep.update(self.op.beparams) 137 138 # check bridges existence 139 CheckInstanceBridgesExist(self, self.instance) 140 141 remote_info = self.rpc.call_instance_info( 142 self.instance.primary_node, self.instance.name, 143 self.instance.hypervisor, cluster.hvparams[self.instance.hypervisor]) 144 remote_info.Raise("Error checking node %s" % 145 self.cfg.GetNodeName(self.instance.primary_node), 146 prereq=True, ecode=errors.ECODE_ENVIRON) 147 if not remote_info.payload: # not running already 148 CheckNodeFreeMemory( 149 self, self.instance.primary_node, 150 "starting instance %s" % self.instance.name, 151 bep[constants.BE_MINMEM], self.instance.hypervisor, 152 self.cfg.GetClusterInfo().hvparams[self.instance.hypervisor])
153
154 - def Exec(self, feedback_fn):
155 """Start the instance. 156 157 """ 158 if not self.op.no_remember: 159 self.cfg.MarkInstanceUp(self.instance.uuid) 160 161 if self.primary_offline: 162 assert self.op.ignore_offline_nodes 163 self.LogInfo("Primary node offline, marked instance as started") 164 else: 165 StartInstanceDisks(self, self.instance, self.op.force) 166 167 result = \ 168 self.rpc.call_instance_start(self.instance.primary_node, 169 (self.instance, self.op.hvparams, 170 self.op.beparams), 171 self.op.startup_paused, self.op.reason) 172 msg = result.fail_msg 173 if msg: 174 ShutdownInstanceDisks(self, self.instance) 175 raise errors.OpExecError("Could not start instance: %s" % msg)
176 177
178 -class LUInstanceShutdown(LogicalUnit):
179 """Shutdown an instance. 180 181 """ 182 HPATH = "instance-stop" 183 HTYPE = constants.HTYPE_INSTANCE 184 REQ_BGL = False 185
186 - def ExpandNames(self):
188
189 - def BuildHooksEnv(self):
190 """Build hooks env. 191 192 This runs on master, primary and secondary nodes of the instance. 193 194 """ 195 env = BuildInstanceHookEnvByObject(self, self.instance) 196 env["TIMEOUT"] = self.op.timeout 197 return env
198
199 - def BuildHooksNodes(self):
200 """Build hooks nodes. 201 202 """ 203 nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) 204 return (nl, nl)
205
206 - def CheckPrereq(self):
207 """Check prerequisites. 208 209 This checks that the instance is in the cluster. 210 211 """ 212 self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid) 213 assert self.instance is not None, \ 214 "Cannot retrieve locked instance %s" % self.op.instance_name 215 216 if not self.op.force: 217 CheckInstanceState(self, self.instance, INSTANCE_ONLINE) 218 else: 219 self.LogWarning("Ignoring offline instance check") 220 221 self.primary_offline = \ 222 self.cfg.GetNodeInfo(self.instance.primary_node).offline 223 224 if self.primary_offline and self.op.ignore_offline_nodes: 225 self.LogWarning("Ignoring offline primary node") 226 else: 227 CheckNodeOnline(self, self.instance.primary_node)
228
229 - def Exec(self, feedback_fn):
230 """Shutdown the instance. 231 232 """ 233 # If the instance is offline we shouldn't mark it as down, as that 234 # resets the offline flag. 235 if not self.op.no_remember and self.instance.admin_state in INSTANCE_ONLINE: 236 self.cfg.MarkInstanceDown(self.instance.uuid) 237 238 if self.primary_offline: 239 assert self.op.ignore_offline_nodes 240 self.LogInfo("Primary node offline, marked instance as stopped") 241 else: 242 result = self.rpc.call_instance_shutdown( 243 self.instance.primary_node, 244 self.instance, 245 self.op.timeout, self.op.reason) 246 msg = result.fail_msg 247 if msg: 248 self.LogWarning("Could not shutdown instance: %s", msg) 249 250 ShutdownInstanceDisks(self, self.instance)
251 252
253 -class LUInstanceReinstall(LogicalUnit):
254 """Reinstall an instance. 255 256 """ 257 HPATH = "instance-reinstall" 258 HTYPE = constants.HTYPE_INSTANCE 259 REQ_BGL = False 260
261 - def ExpandNames(self):
263
264 - def BuildHooksEnv(self):
265 """Build hooks env. 266 267 This runs on master, primary and secondary nodes of the instance. 268 269 """ 270 return BuildInstanceHookEnvByObject(self, self.instance)
271
272 - def BuildHooksNodes(self):
273 """Build hooks nodes. 274 275 """ 276 nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) 277 return (nl, nl)
278
279 - def CheckPrereq(self):
280 """Check prerequisites. 281 282 This checks that the instance is in the cluster and is not running. 283 284 """ 285 instance = self.cfg.GetInstanceInfo(self.op.instance_uuid) 286 assert instance is not None, \ 287 "Cannot retrieve locked instance %s" % self.op.instance_name 288 CheckNodeOnline(self, instance.primary_node, "Instance primary node" 289 " offline, cannot reinstall") 290 291 if instance.disk_template == constants.DT_DISKLESS: 292 raise errors.OpPrereqError("Instance '%s' has no disks" % 293 self.op.instance_name, 294 errors.ECODE_INVAL) 295 CheckInstanceState(self, instance, INSTANCE_DOWN, msg="cannot reinstall") 296 297 if self.op.os_type is not None: 298 # OS verification 299 CheckNodeHasOS(self, instance.primary_node, self.op.os_type, 300 self.op.force_variant) 301 instance_os = self.op.os_type 302 else: 303 instance_os = instance.os 304 305 node_uuids = list(instance.all_nodes) 306 307 if self.op.osparams: 308 i_osdict = GetUpdatedParams(instance.osparams, self.op.osparams) 309 CheckOSParams(self, True, node_uuids, instance_os, i_osdict) 310 self.os_inst = i_osdict # the new dict (without defaults) 311 else: 312 self.os_inst = None 313 314 self.instance = instance
315
316 - def Exec(self, feedback_fn):
317 """Reinstall the instance. 318 319 """ 320 if self.op.os_type is not None: 321 feedback_fn("Changing OS to '%s'..." % self.op.os_type) 322 self.instance.os = self.op.os_type 323 # Write to configuration 324 self.cfg.Update(self.instance, feedback_fn) 325 326 StartInstanceDisks(self, self.instance, None) 327 try: 328 feedback_fn("Running the instance OS create scripts...") 329 # FIXME: pass debug option from opcode to backend 330 result = self.rpc.call_instance_os_add(self.instance.primary_node, 331 (self.instance, self.os_inst), 332 True, self.op.debug_level) 333 result.Raise("Could not install OS for instance %s on node %s" % 334 (self.instance.name, 335 self.cfg.GetNodeName(self.instance.primary_node))) 336 finally: 337 ShutdownInstanceDisks(self, self.instance)
338 339
340 -class LUInstanceReboot(LogicalUnit):
341 """Reboot an instance. 342 343 """ 344 HPATH = "instance-reboot" 345 HTYPE = constants.HTYPE_INSTANCE 346 REQ_BGL = False 347
348 - def ExpandNames(self):
350
351 - def BuildHooksEnv(self):
352 """Build hooks env. 353 354 This runs on master, primary and secondary nodes of the instance. 355 356 """ 357 env = { 358 "IGNORE_SECONDARIES": self.op.ignore_secondaries, 359 "REBOOT_TYPE": self.op.reboot_type, 360 "SHUTDOWN_TIMEOUT": self.op.shutdown_timeout, 361 } 362 363 env.update(BuildInstanceHookEnvByObject(self, self.instance)) 364 365 return env
366
367 - def BuildHooksNodes(self):
368 """Build hooks nodes. 369 370 """ 371 nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) 372 return (nl, nl)
373
374 - def CheckPrereq(self):
375 """Check prerequisites. 376 377 This checks that the instance is in the cluster. 378 379 """ 380 self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid) 381 assert self.instance is not None, \ 382 "Cannot retrieve locked instance %s" % self.op.instance_name 383 CheckInstanceState(self, self.instance, INSTANCE_ONLINE) 384 CheckNodeOnline(self, self.instance.primary_node) 385 386 # check bridges existence 387 CheckInstanceBridgesExist(self, self.instance)
388
389 - def Exec(self, feedback_fn):
390 """Reboot the instance. 391 392 """ 393 cluster = self.cfg.GetClusterInfo() 394 remote_info = self.rpc.call_instance_info( 395 self.instance.primary_node, self.instance.name, 396 self.instance.hypervisor, cluster.hvparams[self.instance.hypervisor]) 397 remote_info.Raise("Error checking node %s" % 398 self.cfg.GetNodeName(self.instance.primary_node)) 399 instance_running = bool(remote_info.payload) 400 401 current_node_uuid = self.instance.primary_node 402 403 if instance_running and \ 404 self.op.reboot_type in [constants.INSTANCE_REBOOT_SOFT, 405 constants.INSTANCE_REBOOT_HARD]: 406 result = self.rpc.call_instance_reboot(current_node_uuid, self.instance, 407 self.op.reboot_type, 408 self.op.shutdown_timeout, 409 self.op.reason) 410 result.Raise("Could not reboot instance") 411 else: 412 if instance_running: 413 result = self.rpc.call_instance_shutdown(current_node_uuid, 414 self.instance, 415 self.op.shutdown_timeout, 416 self.op.reason) 417 result.Raise("Could not shutdown instance for full reboot") 418 ShutdownInstanceDisks(self, self.instance) 419 else: 420 self.LogInfo("Instance %s was already stopped, starting now", 421 self.instance.name) 422 StartInstanceDisks(self, self.instance, self.op.ignore_secondaries) 423 result = self.rpc.call_instance_start(current_node_uuid, 424 (self.instance, None, None), False, 425 self.op.reason) 426 msg = result.fail_msg 427 if msg: 428 ShutdownInstanceDisks(self, self.instance) 429 raise errors.OpExecError("Could not start instance for" 430 " full reboot: %s" % msg) 431 432 self.cfg.MarkInstanceUp(self.instance.uuid)
433 434
435 -def GetInstanceConsole(cluster, instance, primary_node):
436 """Returns console information for an instance. 437 438 @type cluster: L{objects.Cluster} 439 @type instance: L{objects.Instance} 440 @type primary_node: L{objects.Node} 441 @rtype: dict 442 443 """ 444 hyper = hypervisor.GetHypervisorClass(instance.hypervisor) 445 # beparams and hvparams are passed separately, to avoid editing the 446 # instance and then saving the defaults in the instance itself. 447 hvparams = cluster.FillHV(instance) 448 beparams = cluster.FillBE(instance) 449 console = hyper.GetInstanceConsole(instance, primary_node, hvparams, beparams) 450 451 assert console.instance == instance.name 452 assert console.Validate() 453 454 return console.ToDict()
455 456
457 -class LUInstanceConsole(NoHooksLU):
458 """Connect to an instance's console. 459 460 This is somewhat special in that it returns the command line that 461 you need to run on the master node in order to connect to the 462 console. 463 464 """ 465 REQ_BGL = False 466
467 - def ExpandNames(self):
468 self.share_locks = ShareAll() 469 self._ExpandAndLockInstance()
470
471 - def CheckPrereq(self):
472 """Check prerequisites. 473 474 This checks that the instance is in the cluster. 475 476 """ 477 self.instance = self.cfg.GetInstanceInfo(self.op.instance_uuid) 478 assert self.instance is not None, \ 479 "Cannot retrieve locked instance %s" % self.op.instance_name 480 CheckNodeOnline(self, self.instance.primary_node)
481
482 - def Exec(self, feedback_fn):
483 """Connect to the console of an instance 484 485 """ 486 node_uuid = self.instance.primary_node 487 488 cluster_hvparams = self.cfg.GetClusterInfo().hvparams 489 node_insts = self.rpc.call_instance_list( 490 [node_uuid], [self.instance.hypervisor], 491 cluster_hvparams)[node_uuid] 492 node_insts.Raise("Can't get node information from %s" % 493 self.cfg.GetNodeName(node_uuid)) 494 495 if self.instance.name not in node_insts.payload: 496 if self.instance.admin_state == constants.ADMINST_UP: 497 state = constants.INSTST_ERRORDOWN 498 elif self.instance.admin_state == constants.ADMINST_DOWN: 499 state = constants.INSTST_ADMINDOWN 500 else: 501 state = constants.INSTST_ADMINOFFLINE 502 raise errors.OpExecError("Instance %s is not running (state %s)" % 503 (self.instance.name, state)) 504 505 logging.debug("Connecting to console of %s on %s", self.instance.name, 506 self.cfg.GetNodeName(node_uuid)) 507 508 return GetInstanceConsole(self.cfg.GetClusterInfo(), self.instance, 509 self.cfg.GetNodeInfo(self.instance.primary_node))
510