+from ganeti import errors
+
+
+_SHUTDOWN_CLUSTER = "cluster"
+_SHUTDOWN_NODES_BOTH = "nodes"
+_SHUTDOWN_NODES_PRI = "nodes-pri"
+_SHUTDOWN_NODES_SEC = "nodes-sec"
+_SHUTDOWN_INSTANCES = "instances"
+
+
+_VALUE_TRUE = "true"
+
+#: default list of options for L{ListInstances}
+_LIST_DEF_FIELDS = [
+ "name", "hypervisor", "os", "pnode", "status", "oper_ram",
+ ]
+
+
+def _ExpandMultiNames(mode, names, client=None):
+ """Expand the given names using the passed mode.
+
+ For _SHUTDOWN_CLUSTER, all instances will be returned. For
+ _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
+ primary/secondary will be returned. 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.
+
+ @param mode: one of L{_SHUTDOWN_CLUSTER}, L{_SHUTDOWN_NODES_BOTH},
+ L{_SHUTDOWN_NODES_PRI}, L{_SHUTDOWN_NODES_SEC} or
+ L{_SHUTDOWN_INSTANCES}
+ @param names: 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)
+ @rtype: list
+ @return: the list of names after the expansion
+ @raise errors.ProgrammerError: for unknown selection type
+ @raise errors.OpPrereqError: for invalid input parameters
+
+ """
+ if client is None:
+ client = GetClient()
+ if mode == _SHUTDOWN_CLUSTER:
+ if names:
+ raise errors.OpPrereqError("Cluster filter mode takes no arguments")
+ idata = client.QueryInstances([], ["name"], False)
+ 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")
+ ndata = client.QueryNodes(names, ["name", "pinst_list", "sinst_list"],
+ False)
+ 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")
+ idata = client.QueryInstances(names, ["name"], False)
+ inames = [row[0] for row in idata]
+
+ else:
+ raise errors.OpPrereqError("Unknown mode '%s'" % mode)
+
+ return inames
+
+
+def _ConfirmOperation(inames, text, extra=""):
+ """Ask the user to confirm an operation on a list of instances.
+
+ This function is used to request confirmation for doing an operation
+ on a given list of instances.
+
+ @type inames: list
+ @param inames: the list of names that we display when
+ we ask for confirmation
+ @type text: str
+ @param text: the operation that the user should confirm
+ (e.g. I{shutdown} or I{startup})
+ @rtype: boolean
+ @return: True or False depending on user's confirmation.
+
+ """
+ count = len(inames)
+ msg = ("The %s will operate on %d instances.\n%s"
+ "Do you want to continue?" % (text, count, extra))
+ affected = ("\nAffected instances:\n" +
+ "\n".join([" %s" % name for name in inames]))
+
+ choices = [('y', True, 'Yes, execute the %s' % text),
+ ('n', False, 'No, abort the %s' % text)]
+
+ if count > 20:
+ choices.insert(1, ('v', 'v', 'View the list of affected instances'))
+ ask = msg
+ else:
+ ask = msg + affected
+
+ choice = AskUser(ask, choices)
+ if choice == 'v':
+ choices.pop(1)
+ choice = AskUser(msg + affected, choices)
+ return choice
+
+
+def _EnsureInstancesExist(client, names):
+ """Check for and ensure the given instance names exist.
+
+ This function will raise an OpPrereqError in case they don't
+ exist. Otherwise it will exit cleanly.
+
+ @type client: L{luxi.Client}
+ @param client: the client to use for the query
+ @type names: list
+ @param names: the list of instance names to query
+ @raise errors.OpPrereqError: in case any instance is missing
+
+ """
+ # TODO: change LUQueryInstances to that it actually returns None
+ # instead of raising an exception, or devise a better mechanism
+ result = client.QueryInstances(names, ["name"], False)
+ for orig_name, row in zip(names, result):
+ if row[0] is None:
+ raise errors.OpPrereqError("Instance '%s' does not exist" % orig_name)