Revision 874f6148
b/lib/backend.py | ||
---|---|---|
1394 | 1394 |
return |
1395 | 1395 |
|
1396 | 1396 |
try: |
1397 |
hyper.StopInstance(instance, retry=self.tried_once) |
|
1397 |
hyper.StopInstance(instance, retry=self.tried_once, timeout=timeout)
|
|
1398 | 1398 |
if store_reason: |
1399 | 1399 |
_StoreInstReasonTrail(instance.name, reason) |
1400 | 1400 |
except errors.HypervisorError, err: |
b/lib/hypervisor/hv_base.py | ||
---|---|---|
173 | 173 |
"""Start an instance.""" |
174 | 174 |
raise NotImplementedError |
175 | 175 |
|
176 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
176 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
177 |
timeout=None): |
|
177 | 178 |
"""Stop an instance |
178 | 179 |
|
179 | 180 |
@type instance: L{objects.Instance} |
... | ... | |
186 | 187 |
@param name: if this parameter is passed, the the instance object |
187 | 188 |
should not be used (will be passed as None), and the shutdown |
188 | 189 |
must be done by name only |
190 |
@type timeout: int or None |
|
191 |
@param timeout: if the parameter is not None, a soft shutdown operation will |
|
192 |
be killed after the specified number of seconds. A hard (forced) |
|
193 |
shutdown cannot have a timeout |
|
189 | 194 |
|
190 | 195 |
""" |
191 | 196 |
raise NotImplementedError |
b/lib/hypervisor/hv_chroot.py | ||
---|---|---|
167 | 167 |
raise HypervisorError("Can't run the chroot start script: %s" % |
168 | 168 |
result.output) |
169 | 169 |
|
170 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
170 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
171 |
timeout=None): |
|
171 | 172 |
"""Stop an instance. |
172 | 173 |
|
173 | 174 |
This method has complicated cleanup tests, as we must: |
... | ... | |
176 | 177 |
- finally unmount the instance dir |
177 | 178 |
|
178 | 179 |
""" |
180 |
assert(timeout is None or force is not None) |
|
181 |
|
|
179 | 182 |
if name is None: |
180 | 183 |
name = instance.name |
181 | 184 |
|
... | ... | |
183 | 186 |
if not os.path.exists(root_dir) or not self._IsDirLive(root_dir): |
184 | 187 |
return |
185 | 188 |
|
189 |
timeout_cmd = [] |
|
190 |
if timeout is not None: |
|
191 |
timeout_cmd.extend(["timeout", str(timeout)]) |
|
192 |
|
|
186 | 193 |
# Run the chroot stop script only once |
187 | 194 |
if not retry and not force: |
188 |
result = utils.RunCmd(["chroot", root_dir, "/ganeti-chroot", "stop"]) |
|
195 |
result = utils.RunCmd(timeout_cmd.extend(["chroot", root_dir, |
|
196 |
"/ganeti-chroot", "stop"])) |
|
189 | 197 |
if result.failed: |
190 | 198 |
raise HypervisorError("Can't run the chroot stop script: %s" % |
191 | 199 |
result.output) |
b/lib/hypervisor/hv_fake.py | ||
---|---|---|
165 | 165 |
raise errors.HypervisorError("Failed to start instance %s: %s" % |
166 | 166 |
(instance.name, err)) |
167 | 167 |
|
168 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
168 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
169 |
timeout=None): |
|
169 | 170 |
"""Stop an instance. |
170 | 171 |
|
171 | 172 |
For the fake hypervisor, this just removes the file in the base |
172 | 173 |
dir, if it exist, otherwise we raise an exception. |
173 | 174 |
|
174 | 175 |
""" |
176 |
assert(timeout is None or force is not None) |
|
177 |
|
|
175 | 178 |
if name is None: |
176 | 179 |
name = instance.name |
177 | 180 |
if not self._IsAlive(name): |
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
1696 | 1696 |
# 500ms and likely more: socat can't detect the end of the reply and waits |
1697 | 1697 |
# for 500ms of no data received before exiting (500 ms is the default for |
1698 | 1698 |
# the "-t" parameter). |
1699 |
socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" % |
|
1699 |
socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
|
|
1700 | 1700 |
(utils.ShellQuote(command), |
1701 |
timeout_cmd, |
|
1701 | 1702 |
constants.SOCAT_PATH, |
1702 | 1703 |
utils.ShellQuote(self._InstanceMonitor(instance_name)))) |
1704 |
|
|
1703 | 1705 |
result = utils.RunCmd(socat) |
1704 | 1706 |
if result.failed: |
1705 | 1707 |
msg = ("Failed to send command '%s' to instance '%s', reason '%s'," |
... | ... | |
1776 | 1778 |
else: |
1777 | 1779 |
return "pc" |
1778 | 1780 |
|
1779 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
1781 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
1782 |
timeout=None): |
|
1780 | 1783 |
"""Stop an instance. |
1781 | 1784 |
|
1782 | 1785 |
""" |
1786 |
assert(timeout is None or force is not None) |
|
1787 |
|
|
1783 | 1788 |
if name is not None and not force: |
1784 | 1789 |
raise errors.HypervisorError("Cannot shutdown cleanly by name only") |
1785 | 1790 |
if name is None: |
... | ... | |
1792 | 1797 |
if force or not acpi: |
1793 | 1798 |
utils.KillProcess(pid) |
1794 | 1799 |
else: |
1795 |
self._CallMonitorCommand(name, "system_powerdown") |
|
1800 |
self._CallMonitorCommand(name, "system_powerdown", timeout)
|
|
1796 | 1801 |
|
1797 | 1802 |
def CleanupInstance(self, instance_name): |
1798 | 1803 |
"""Cleanup after a stopped instance |
b/lib/hypervisor/hv_lxc.py | ||
---|---|---|
325 | 325 |
raise HypervisorError("Running the lxc-start script failed: %s" % |
326 | 326 |
result.output) |
327 | 327 |
|
328 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
328 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
329 |
timeout=None): |
|
329 | 330 |
"""Stop an instance. |
330 | 331 |
|
331 | 332 |
This method has complicated cleanup tests, as we must: |
... | ... | |
334 | 335 |
- finally unmount the instance dir |
335 | 336 |
|
336 | 337 |
""" |
338 |
assert(timeout is None or force is not None) |
|
339 |
|
|
337 | 340 |
if name is None: |
338 | 341 |
name = instance.name |
339 | 342 |
|
343 |
timeout_cmd = [] |
|
344 |
if timeout is not None: |
|
345 |
timeout_cmd.extend(["timeout", str(timeout)]) |
|
346 |
|
|
340 | 347 |
root_dir = self._InstanceDir(name) |
341 | 348 |
if not os.path.exists(root_dir): |
342 | 349 |
return |
... | ... | |
349 | 356 |
raise HypervisorError("Running 'poweroff' on the instance" |
350 | 357 |
" failed: %s" % result.output) |
351 | 358 |
time.sleep(2) |
352 |
result = utils.RunCmd(["lxc-stop", "-n", name])
|
|
359 |
result = utils.RunCmd(timeout_cmd.extend(["lxc-stop", "-n", name]))
|
|
353 | 360 |
if result.failed: |
354 | 361 |
logging.warning("Error while doing lxc-stop for %s: %s", name, |
355 | 362 |
result.output) |
... | ... | |
358 | 365 |
return |
359 | 366 |
|
360 | 367 |
for mpath in self._GetMountSubdirs(root_dir): |
361 |
result = utils.RunCmd(["umount", mpath])
|
|
368 |
result = utils.RunCmd(timeout_cmd.extend(["umount", mpath]))
|
|
362 | 369 |
if result.failed: |
363 | 370 |
logging.warning("Error while umounting subpath %s for instance %s: %s", |
364 | 371 |
mpath, name, result.output) |
365 | 372 |
|
366 |
result = utils.RunCmd(["umount", root_dir])
|
|
373 |
result = utils.RunCmd(timeout_cmd.extend(["umount", root_dir]))
|
|
367 | 374 |
if result.failed and force: |
368 | 375 |
msg = ("Processes still alive in the chroot: %s" % |
369 | 376 |
utils.RunCmd("fuser -vm %s" % root_dir).output) |
b/lib/hypervisor/hv_xen.py | ||
---|---|---|
519 | 519 |
(instance.name, result.fail_reason, |
520 | 520 |
result.output, stashed_config)) |
521 | 521 |
|
522 |
def StopInstance(self, instance, force=False, retry=False, name=None): |
|
522 |
def StopInstance(self, instance, force=False, retry=False, name=None, |
|
523 |
timeout=None): |
|
523 | 524 |
"""Stop an instance. |
524 | 525 |
|
526 |
A soft shutdown can be interrupted. A hard shutdown tries forever. |
|
527 |
|
|
525 | 528 |
""" |
529 |
assert(timeout is None or force is not None) |
|
530 |
|
|
526 | 531 |
if name is None: |
527 | 532 |
name = instance.name |
528 | 533 |
|
529 |
return self._StopInstance(name, force) |
|
534 |
return self._StopInstance(name, force, timeout)
|
|
530 | 535 |
|
531 |
def _ShutdownInstance(self, name): |
|
536 |
def _ShutdownInstance(self, name, timeout):
|
|
532 | 537 |
"""Shutdown an instance if the instance is running. |
533 | 538 |
|
534 | 539 |
The '-w' flag waits for shutdown to complete which avoids the need |
... | ... | |
537 | 542 |
|
538 | 543 |
@type name: string |
539 | 544 |
@param name: name of the instance to stop |
545 |
@type timeout: int or None |
|
546 |
@param timeout: a timeout after which the shutdown command should be killed, |
|
547 |
or None for no timeout |
|
540 | 548 |
|
541 | 549 |
""" |
542 | 550 |
instance_info = self.GetInstanceInfo(name) |
... | ... | |
545 | 553 |
logging.info("Failed to shutdown instance %s, not running", name) |
546 | 554 |
return None |
547 | 555 |
|
548 |
return self._RunXen(["shutdown", "-w", name]) |
|
556 |
return self._RunXen(["shutdown", "-w", name], timeout)
|
|
549 | 557 |
|
550 | 558 |
def _DestroyInstance(self, name): |
551 | 559 |
"""Destroy an instance if the instance if the instance exists. |
... | ... | |
562 | 570 |
|
563 | 571 |
return self._RunXen(["destroy", name]) |
564 | 572 |
|
565 |
def _StopInstance(self, name, force): |
|
573 |
def _StopInstance(self, name, force, timeout):
|
|
566 | 574 |
"""Stop an instance. |
567 | 575 |
|
568 | 576 |
@type name: string |
... | ... | |
571 | 579 |
@type force: boolean |
572 | 580 |
@param force: whether to do a "hard" stop (destroy) |
573 | 581 |
|
582 |
@type timeout: int or None |
|
583 |
@param timeout: a timeout after which the shutdown command should be killed, |
|
584 |
or None for no timeout |
|
585 |
|
|
574 | 586 |
""" |
575 | 587 |
if force: |
576 | 588 |
result = self._DestroyInstance(name) |
577 | 589 |
else: |
578 |
self._ShutdownInstance(name) |
|
590 |
self._ShutdownInstance(name, timeout)
|
|
579 | 591 |
result = self._DestroyInstance(name) |
580 | 592 |
|
581 | 593 |
if result is not None and result.failed and \ |
b/test/py/ganeti.hypervisor.hv_xen_unittest.py | ||
---|---|---|
555 | 555 |
extra = inst.hvparams[constants.HV_KERNEL_ARGS] |
556 | 556 |
self.assertTrue(("extra = '%s'" % extra) in lines) |
557 | 557 |
|
558 |
def _StopInstanceCommand(self, instance_name, force, fail, cmd): |
|
558 |
def _StopInstanceCommand(self, instance_name, force, fail, full_cmd): |
|
559 |
# Remove the timeout (and its number of seconds) if it's there |
|
560 |
if full_cmd[:1][0] == "timeout": |
|
561 |
cmd = full_cmd[2:] |
|
562 |
else: |
|
563 |
cmd = full_cmd |
|
564 |
|
|
565 |
# Test the actual command |
|
559 | 566 |
if (cmd == [self.CMD, "list"]): |
560 | 567 |
output = "Name ID Mem VCPUs State Time(s)\n" \ |
561 | 568 |
"Domain-0 0 1023 1 r----- 142691.0\n" \ |
... | ... | |
592 | 599 |
|
593 | 600 |
if fail: |
594 | 601 |
try: |
595 |
hv._StopInstance(name, force) |
|
602 |
hv._StopInstance(name, force, constants.DEFAULT_SHUTDOWN_TIMEOUT)
|
|
596 | 603 |
except errors.HypervisorError, err: |
597 | 604 |
self.assertTrue(str(err).startswith("xm list failed"), |
598 | 605 |
msg=str(err)) |
... | ... | |
602 | 609 |
msg=("Configuration was removed when stopping" |
603 | 610 |
" instance failed")) |
604 | 611 |
else: |
605 |
hv._StopInstance(name, force) |
|
612 |
hv._StopInstance(name, force, constants.DEFAULT_SHUTDOWN_TIMEOUT)
|
|
606 | 613 |
self.assertFalse(os.path.exists(cfgfile)) |
607 | 614 |
|
608 | 615 |
def _MigrateNonRunningInstCmd(self, cmd): |
Also available in: Unified diff