Revision b44bd844

b/lib/cli.py
83 83
  "IDENTIFY_DEFAULTS_OPT",
84 84
  "IGNORE_CONSIST_OPT",
85 85
  "IGNORE_FAILURES_OPT",
86
  "IGNORE_OFFLINE_OPT",
86 87
  "IGNORE_REMOVE_FAILURES_OPT",
87 88
  "IGNORE_SECONDARIES_OPT",
88 89
  "IGNORE_SIZE_OPT",
......
585 586
CONFIRM_OPT = cli_option("--yes", dest="confirm", action="store_true",
586 587
                         default=False, help="Do not require confirmation")
587 588

  
589
IGNORE_OFFLINE_OPT = cli_option("--ignore-offline", dest="ignore_offline",
590
                                  action="store_true", default=False,
591
                                  help=("Ignore offline nodes and do as much"
592
                                        " as possible"))
593

  
588 594
TAG_SRC_OPT = cli_option("--from", dest="tags_source",
589 595
                         default=None, help="File with tag names")
590 596

  
b/lib/cmdlib.py
73 73
#: a required instance name (for single-instance LUs)
74 74
_PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString)
75 75

  
76
#: Whether to ignore offline nodes
77
_PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool)
76 78

  
77 79
#: a required node name (for single-node LUs)
78 80
_PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString)
......
4413 4415
  _OP_PARAMS = [
4414 4416
    _PInstanceName,
4415 4417
    _PForce,
4418
    _PIgnoreOfflineNodes,
4416 4419
    ("hvparams", ht.EmptyDict, ht.TDict),
4417 4420
    ("beparams", ht.EmptyDict, ht.TDict),
4418 4421
    ]
......
4461 4464
      hv_type.CheckParameterSyntax(filled_hvp)
4462 4465
      _CheckHVParams(self, instance.all_nodes, instance.hypervisor, filled_hvp)
4463 4466

  
4464
    _CheckNodeOnline(self, instance.primary_node)
4467
    self.primary_offline = self.cfg.GetNodeInfo(instance.primary_node).offline
4465 4468

  
4466
    bep = self.cfg.GetClusterInfo().FillBE(instance)
4467
    # check bridges existence
4468
    _CheckInstanceBridgesExist(self, instance)
4469
    if self.primary_offline and self.op.ignore_offline_nodes:
4470
      self.proc.LogWarning("Ignoring offline primary node")
4471

  
4472
      if self.op.hvparams or self.op.beparams:
4473
        self.proc.LogWarning("Overridden parameters are ignored")
4474
    else:
4475
      _CheckNodeOnline(self, instance.primary_node)
4476

  
4477
      bep = self.cfg.GetClusterInfo().FillBE(instance)
4469 4478

  
4470
    remote_info = self.rpc.call_instance_info(instance.primary_node,
4471
                                              instance.name,
4472
                                              instance.hypervisor)
4473
    remote_info.Raise("Error checking node %s" % instance.primary_node,
4474
                      prereq=True, ecode=errors.ECODE_ENVIRON)
4475
    if not remote_info.payload: # not running already
4476
      _CheckNodeFreeMemory(self, instance.primary_node,
4477
                           "starting instance %s" % instance.name,
4478
                           bep[constants.BE_MEMORY], instance.hypervisor)
4479
      # check bridges existence
4480
      _CheckInstanceBridgesExist(self, instance)
4481

  
4482
      remote_info = self.rpc.call_instance_info(instance.primary_node,
4483
                                                instance.name,
4484
                                                instance.hypervisor)
4485
      remote_info.Raise("Error checking node %s" % instance.primary_node,
4486
                        prereq=True, ecode=errors.ECODE_ENVIRON)
4487
      if not remote_info.payload: # not running already
4488
        _CheckNodeFreeMemory(self, instance.primary_node,
4489
                             "starting instance %s" % instance.name,
4490
                             bep[constants.BE_MEMORY], instance.hypervisor)
4479 4491

  
4480 4492
  def Exec(self, feedback_fn):
4481 4493
    """Start the instance.
......
4486 4498

  
4487 4499
    self.cfg.MarkInstanceUp(instance.name)
4488 4500

  
4489
    node_current = instance.primary_node
4501
    if self.primary_offline:
4502
      assert self.op.ignore_offline_nodes
4503
      self.proc.LogInfo("Primary node offline, marked instance as started")
4504
    else:
4505
      node_current = instance.primary_node
4490 4506

  
4491
    _StartInstanceDisks(self, instance, force)
4507
      _StartInstanceDisks(self, instance, force)
4492 4508

  
4493
    result = self.rpc.call_instance_start(node_current, instance,
4494
                                          self.op.hvparams, self.op.beparams)
4495
    msg = result.fail_msg
4496
    if msg:
4497
      _ShutdownInstanceDisks(self, instance)
4498
      raise errors.OpExecError("Could not start instance: %s" % msg)
4509
      result = self.rpc.call_instance_start(node_current, instance,
4510
                                            self.op.hvparams, self.op.beparams)
4511
      msg = result.fail_msg
4512
      if msg:
4513
        _ShutdownInstanceDisks(self, instance)
4514
        raise errors.OpExecError("Could not start instance: %s" % msg)
4499 4515

  
4500 4516

  
4501 4517
class LURebootInstance(LogicalUnit):
......
4587 4603
  HTYPE = constants.HTYPE_INSTANCE
4588 4604
  _OP_PARAMS = [
4589 4605
    _PInstanceName,
4606
    _PIgnoreOfflineNodes,
4590 4607
    ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TPositiveInt),
4591 4608
    ]
4592 4609
  REQ_BGL = False
......
4614 4631
    self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
4615 4632
    assert self.instance is not None, \
4616 4633
      "Cannot retrieve locked instance %s" % self.op.instance_name
4617
    _CheckNodeOnline(self, self.instance.primary_node)
4634

  
4635
    self.primary_offline = \
4636
      self.cfg.GetNodeInfo(self.instance.primary_node).offline
4637

  
4638
    if self.primary_offline and self.op.ignore_offline_nodes:
4639
      self.proc.LogWarning("Ignoring offline primary node")
4640
    else:
4641
      _CheckNodeOnline(self, self.instance.primary_node)
4618 4642

  
4619 4643
  def Exec(self, feedback_fn):
4620 4644
    """Shutdown the instance.
......
4623 4647
    instance = self.instance
4624 4648
    node_current = instance.primary_node
4625 4649
    timeout = self.op.timeout
4650

  
4626 4651
    self.cfg.MarkInstanceDown(instance.name)
4627
    result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
4628
    msg = result.fail_msg
4629
    if msg:
4630
      self.proc.LogWarning("Could not shutdown instance: %s" % msg)
4631 4652

  
4632
    _ShutdownInstanceDisks(self, instance)
4653
    if self.primary_offline:
4654
      assert self.op.ignore_offline_nodes
4655
      self.proc.LogInfo("Primary node offline, marked instance as stopped")
4656
    else:
4657
      result = self.rpc.call_instance_shutdown(node_current, instance, timeout)
4658
      msg = result.fail_msg
4659
      if msg:
4660
        self.proc.LogWarning("Could not shutdown instance: %s" % msg)
4661

  
4662
      _ShutdownInstanceDisks(self, instance)
4633 4663

  
4634 4664

  
4635 4665
class LUReinstallInstance(LogicalUnit):
b/lib/opcodes.py
519 519
  OP_ID = "OP_INSTANCE_STARTUP"
520 520
  OP_DSC_FIELD = "instance_name"
521 521
  __slots__ = [
522
    "instance_name", "force", "hvparams", "beparams",
522
    "instance_name", "force", "hvparams", "beparams", "ignore_offline_nodes",
523 523
    ]
524 524

  
525 525

  
......
527 527
  """Shutdown an instance."""
528 528
  OP_ID = "OP_INSTANCE_SHUTDOWN"
529 529
  OP_DSC_FIELD = "instance_name"
530
  __slots__ = ["instance_name", "timeout"]
530
  __slots__ = [
531
    "instance_name", "timeout", "ignore_offline_nodes",
532
    ]
531 533

  
532 534

  
533 535
class OpRebootInstance(OpCode):
b/man/gnt-instance.sgml
1741 1741
          <command>startup</command>
1742 1742
          <sbr>
1743 1743
          <arg>--force</arg>
1744
          <arg>--ignore-offline</arg>
1744 1745
          <sbr>
1745 1746
          <arg>--force-multiple</arg>
1746 1747
          <sbr>
......
1848 1849

  
1849 1850
        <para>
1850 1851
          Use <option>--force</option> to start even if secondary disks are
1851
          failing.
1852
          failing. <option>--ignore-offline</option> can be used to ignore
1853
          offline primary nodes and mark the instance as started even if
1854
          the primary is not available.
1852 1855
        </para>
1853 1856

  
1854 1857
        <para>
......
1904 1907
          <arg>--timeout=<replaceable>N</replaceable></arg>
1905 1908
          <sbr>
1906 1909
          <arg>--force-multiple</arg>
1910
          <arg>--ignore-offline</arg>
1907 1911
          <sbr>
1908 1912
          <group choice="opt">
1909 1913
            <arg>--instance</arg>
......
1954 1958
          <command>gnt-job info</command>.
1955 1959
        </para>
1956 1960

  
1961
        <para>
1962
          <option>--ignore-offline</option> can be used to ignore offline
1963
          primary nodes and force the instance to be marked as stopped. This
1964
          option should be used with care as it can lead to an
1965
          inconsistent cluster state.
1966
        </para>
1957 1967

  
1958 1968
        <para>
1959 1969
          Example:
b/scripts/gnt-instance
744 744

  
745 745
  """
746 746
  op = opcodes.OpStartupInstance(instance_name=name,
747
                                 force=opts.force)
747
                                 force=opts.force,
748
                                 ignore_offline_nodes=opts.ignore_offline)
748 749
  # do not add these parameters to the opcode unless they're defined
749 750
  if opts.hvparams:
750 751
    op.hvparams = opts.hvparams
......
782 783

  
783 784
  """
784 785
  return opcodes.OpShutdownInstance(instance_name=name,
785
                                    timeout=opts.timeout)
786
                                    timeout=opts.timeout,
787
                                    ignore_offline_nodes=opts.ignore_offline)
786 788

  
787 789

  
788 790
def ReplaceDisks(opts, args):
......
1487 1489
    [m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt,
1488 1490
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1489 1491
     m_inst_tags_opt, m_inst_opt, m_force_multi, TIMEOUT_OPT, SUBMIT_OPT,
1490
     DRY_RUN_OPT, PRIORITY_OPT],
1492
     DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT],
1491 1493
    "<instance>", "Stops an instance"),
1492 1494
  'startup': (
1493 1495
    GenericManyOps("startup", _StartupInstance), [ArgInstance()],
1494 1496
    [FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt,
1495 1497
     m_node_tags_opt, m_pri_node_tags_opt, m_sec_node_tags_opt,
1496 1498
     m_inst_tags_opt, m_clust_opt, m_inst_opt, SUBMIT_OPT, HVOPTS_OPT,
1497
     BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1499
     BACKEND_OPT, DRY_RUN_OPT, PRIORITY_OPT, IGNORE_OFFLINE_OPT],
1498 1500
    "<instance>", "Starts an instance"),
1499 1501
  'reboot': (
1500 1502
    GenericManyOps("reboot", _RebootInstance), [ArgInstance()],

Also available in: Unified diff