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