Commit 312ac745 authored by Iustin Pop's avatar Iustin Pop
Browse files

Allow start/stop of multiple instances at once

This is an initial version of the multi-instance start/stop, which
allows the gnt-instance startup and shutdown subcommands to work on
multiple instances at once.

The available selections are:
  - "gnt-instance startup --instance name..." which is the default, and
    if passed only one argument it behaves like the original command)
  - "gnt-instance startup --node name..." will work on all instances
    having either primary or secondary one of the passed names
  - "gnt-instance startup --primary name..." will work on all instances
    having primary node one of the passed names
  - "gnt-instance startup --secondary name..." will work on all
    instances having as secondary node one of the passed names
  - "gnt-instance startup --all" will work on all instances

This allows a simple cluster-wide shutdown or node shutdown (or
startup).

Note that this version stops at the first error - it will not try to
start the 2nd instance selected if there is a critical error with the
1st one.

Also note that this version is not faster than simply running manually
"gnt-instance shutdown NAME", because it doesn't parallelize the
shutdown/startup actions.

Reviewed-by: imsnah,roman.marxer
parent fc95f88f
......@@ -424,12 +424,69 @@
<cmdsynopsis>
<command>startup</command>
<arg>--extra=<replaceable>PARAMS</replaceable></arg>
<arg choice="req"><replaceable>instance</replaceable></arg>
<sbr>
<group choice="opt">
<arg>--instance</arg>
<arg>--node</arg>
<arg>--primary</arg>
<arg>--secondary</arg>
<arg>--all</arg>
</group>
<sbr>
<arg choice="opt"
rep="repeat"><replaceable>name</replaceable></arg>
</cmdsynopsis>
<para>
Starts an instance. The node where to start the instance is
taken from the configuration.
Starts one or more instances, depending on the
<option>--by-*</option> mode. The four available modes are:
<variablelist>
<varlistentry>
<term><option>--instance</option></term>
<listitem>
<simpara>will start the instances given as arguments
(at least one argument required); this is the default
selection</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>--node</term>
<listitem>
<simpara>will start the instances who have the given
node as either primary or secondary</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--primary</option></term>
<listitem>
<simpara>will start all instances whose primary node
is in the list of nodes passed as arguments (at least
one node required)</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--secondary</option></term>
<listitem>
<simpara>will start all instances whose secondary node
is in the list of nodes passed as arguments (at least
one node required)</simpara>
</listitem>
</varlistentry>
<varlistentry>
<term>--all</term>
<listitem>
<simpara>will start all instances in the cluster (no
arguments accepted)</simpara>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Note that although you can pass more than one
<option>--by-</option> option, the last one wins, so in
order to guarantee the desired result, don't pass more than
one such option.
</para>
<para>
......@@ -446,6 +503,8 @@
<screen>
# gnt-instance start instance1.example.com
# gnt-instance start --extra single test1.example.com
# gnt-instance start --by-node node1.example.com node2.example.com
# gnt-instance start --by-cluster
</screen>
</para>
</refsect3>
......@@ -455,20 +514,40 @@
<cmdsynopsis>
<command>shutdown</command>
<arg choice="req"><replaceable>instance</replaceable></arg>
<sbr>
<group choice="opt">
<arg>--instance</arg>
<arg>--node</arg>
<arg>--primary</arg>
<arg>--secondary</arg>
<arg>--all</arg>
</group>
<sbr>
<arg choice="opt"
rep="repeat"><replaceable>name</replaceable></arg>
</cmdsynopsis>
<para>
Stops the instance. If the instance cannot be cleanly
stopped during a hardcoded interval (currently 2 minutes),
it will forcibly stop the instance (equivalent to switching
off the power on a physical machine).
Stops one or more instances. If the instance cannot be
cleanly stopped during a hardcoded interval (currently 2
minutes), it will forcibly stop the instance (equivalent to
switching off the power on a physical machine).
</para>
<para>
The <option>--instance</option>, <option>--node</option>,
<option>--primary</option>, <option>--secondary</option> and
<option>--all</option> options are similar as for the
<command>startup</command> command and they influence the
actual instances being shutodnw.
</para>
<para>
Example:
<screen>
# gnt-instance shutdown instance1.example.com
# gnt-instance shutdown --by-cluster
</screen>
</para>
</refsect3>
......
......@@ -21,6 +21,7 @@
import sys
import os
import itertools
from optparse import make_option
from cStringIO import StringIO
......@@ -29,6 +30,73 @@ from ganeti import opcodes
from ganeti import logger
from ganeti import constants
from ganeti import utils
from ganeti import errors
_SHUTDOWN_CLUSTER = "cluster"
_SHUTDOWN_NODES_BOTH = "nodes"
_SHUTDOWN_NODES_PRI = "nodes-pri"
_SHUTDOWN_NODES_SEC = "nodes-sec"
_SHUTDOWN_INSTANCES = "instances"
def _ExpandMultiNames(mode, names):
"""Expand the given names using the passed mode.
Args:
- mode, which can be one of _SHUTDOWN_CLUSTER, _SHUTDOWN_NODES_BOTH,
_SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC or _SHUTDOWN_INSTANCES
- names, which is a list of names; for cluster, it must be empty,
and for node and instance it must be a list of valid item
names (short names are valid as usual, e.g. node1 instead of
node1.example.com)
For _SHUTDOWN_CLUSTER, all instances will be returned. For
_SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
primary/secondary will be shutdown. For _SHUTDOWN_NODES_BOTH, all
instances having those nodes as either primary or secondary will be
returned. For _SHUTDOWN_INSTANCES, the given instances will be
returned.
"""
if mode == _SHUTDOWN_CLUSTER:
if names:
raise errors.OpPrereqError("Cluster filter mode takes no arguments")
op = opcodes.OpQueryInstances(output_fields=["name"], names=[])
idata = SubmitOpCode(op)
inames = [row[0] for row in idata]
elif mode in (_SHUTDOWN_NODES_BOTH,
_SHUTDOWN_NODES_PRI,
_SHUTDOWN_NODES_SEC):
if not names:
raise errors.OpPrereqError("No node names passed")
op = opcodes.OpQueryNodes(output_fields=["name", "pinst_list",
"sinst_list"], names=names)
ndata = SubmitOpCode(op)
ipri = [row[1] for row in ndata]
pri_names = list(itertools.chain(*ipri))
isec = [row[2] for row in ndata]
sec_names = list(itertools.chain(*isec))
if mode == _SHUTDOWN_NODES_BOTH:
inames = pri_names + sec_names
elif mode == _SHUTDOWN_NODES_PRI:
inames = pri_names
elif mode == _SHUTDOWN_NODES_SEC:
inames = sec_names
else:
raise errors.ProgrammerError("Unhandled shutdown type")
elif mode == _SHUTDOWN_INSTANCES:
if not names:
raise errors.OpPrereqError("No instance names passed")
op = opcodes.OpQueryInstances(output_fields=["name"], names=names)
idata = SubmitOpCode(op)
inames = [row[0] for row in idata]
else:
raise errors.OpPrereqError("Unknown mode '%s'" % mode)
return inames
def ListInstances(opts, args):
......@@ -209,10 +277,17 @@ def StartupInstance(opts, args):
args - list containing a single element, the instance name
"""
instance_name = args[0]
op = opcodes.OpStartupInstance(instance_name=instance_name, force=opts.force,
extra_args=opts.extra_args)
SubmitOpCode(op)
if opts.multi_mode is None:
opts.multi_mode = _SHUTDOWN_INSTANCES
inames = _ExpandMultiNames(opts.multi_mode, args)
multi_on = len(inames) > 1
for name in inames:
op = opcodes.OpStartupInstance(instance_name=name,
force=opts.force,
extra_args=opts.extra_args)
if multi_on:
logger.ToStdout("Starting up %s" % name)
SubmitOpCode(op)
return 0
......@@ -224,9 +299,15 @@ def ShutdownInstance(opts, args):
args - list containing a single element, the instance name
"""
instance_name = args[0]
op = opcodes.OpShutdownInstance(instance_name=instance_name)
SubmitOpCode(op)
if opts.multi_mode is None:
opts.multi_mode = _SHUTDOWN_INSTANCES
inames = _ExpandMultiNames(opts.multi_mode, args)
multi_on = len(inames) > 1
for name in inames:
op = opcodes.OpShutdownInstance(instance_name=name)
if multi_on:
logger.ToStdout("Shutting down %s" % name)
SubmitOpCode(op)
return 0
......@@ -455,6 +536,28 @@ node_opt = make_option("-n", "--node", dest="node", help="Target node",
os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
metavar="<os>")
# multi-instance selection options
m_pri_node_opt = make_option("--primary", dest="multi_mode",
help="Filter by nodes (primary only)",
const=_SHUTDOWN_NODES_PRI, action="store_const")
m_sec_node_opt = make_option("--secondary", dest="multi_mode",
help="Filter by nodes (secondary only)",
const=_SHUTDOWN_NODES_SEC, action="store_const")
m_node_opt = make_option("--node", dest="multi_mode",
help="Filter by nodes (primary and secondary)",
const=_SHUTDOWN_NODES_BOTH, action="store_const")
m_clust_opt = make_option("--all", dest="multi_mode",
help="Select all instances in the cluster",
const=_SHUTDOWN_CLUSTER, action="store_const")
m_inst_opt = make_option("--instance", dest="multi_mode",
help="Filter by instance name [default]",
const=_SHUTDOWN_INSTANCES, action="store_const")
# this is defined separately due to readability only
add_opts = [
DEBUG_OPT,
......@@ -555,13 +658,17 @@ commands = {
default=None, type="string", metavar="<bridge>")
],
"<instance>", "Alters the parameters of an instance"),
'shutdown': (ShutdownInstance, ARGS_ONE, [DEBUG_OPT],
'shutdown': (ShutdownInstance, ARGS_ANY,
[DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
m_clust_opt, m_inst_opt],
"<instance>", "Stops an instance"),
'startup': (StartupInstance, ARGS_ONE,
'startup': (StartupInstance, ARGS_ANY,
[DEBUG_OPT, FORCE_OPT,
make_option("-e", "--extra", dest="extra_args",
help="Extra arguments for the instance's kernel",
default=None, type="string", metavar="<PARAMS>"),
m_node_opt, m_pri_node_opt, m_sec_node_opt,
m_clust_opt, m_inst_opt,
],
"<instance>", "Starts an instance"),
'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment