From 27579978966f3fa3cf3c935b5bcd797259107f96 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Wed, 23 Apr 2008 11:03:58 +0000
Subject: [PATCH] Send required_nodes field to the iallocator scripts

This patch adds the 'required_nodes' field in the request dict for the
iallocator.

This means that the handmade-checks in the create instance can be
simplified, and that the dumb allocator can be made simple. Therefore
the patch also modifies it.

The patch also sends the disk_space_total to the script in realocate
mode and a small fix for showing errors (include stderr too).

Reviewed-by: ultrotter
---
 doc/examples/dumb-allocator | 25 +++++++++++-------------
 lib/cmdlib.py               | 38 +++++++++++++++++++++++++++----------
 2 files changed, 39 insertions(+), 24 deletions(-)

diff --git a/doc/examples/dumb-allocator b/doc/examples/dumb-allocator
index 641c41835..53b9cd2da 100755
--- a/doc/examples/dumb-allocator
+++ b/doc/examples/dumb-allocator
@@ -74,20 +74,17 @@ def main():
   request = data["request"]
   req_type = request["type"]
   if req_type != "allocate":
-    print >> sys.stderr, "Unsupported allocator mode '%s'" % req_type
-    return 1
-
-  npri = SelectNode(nodes, request, [])
-  if npri is None:
-    return OutputError("Can't find a suitable primary node", exit_code=0)
-
-  result_nodes = [npri]
-  if request["disk_template"] == "drbd":
-    nsec = SelectNode(nodes, request, result_nodes)
-    if nsec is None:
-      return OutputError("Can't find a suitable secondary node (%s selected"
-                         " as primary)" % npri, exit_code=0)
-    result_nodes.append(nsec)
+    return OutputError("Unsupported allocator mode '%s'" % req_type)
+
+  result_nodes = []
+  while len(result_nodes) < request["required_nodes"]:
+    new_selection = SelectNode(nodes, request, result_nodes)
+    if new_selection is None:
+      return OutputError("Can't find a suitable node for position %s"
+                         " (already selected: %s)" %
+                         (len(result_nodes) + 1, ", ".join(result_nodes)),
+                         exit_code=0)
+    result_nodes.append(new_selection)
 
   result = {
           "success": True,
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index c56877dcb..58b6404d7 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -3159,20 +3159,16 @@ class LUCreateInstance(LogicalUnit):
       raise errors.OpPrereqError("Can't compute nodes using"
                                  " iallocator '%s': %s" % (self.op.iallocator,
                                                            ial.info))
-    req_nodes = 1
-    if self.op.disk_template in constants.DTS_NET_MIRROR:
-      req_nodes += 1
-
-    if len(ial.nodes) != req_nodes:
+    if len(ial.nodes) != ial.required_nodes:
       raise errors.OpPrereqError("iallocator '%s' returned invalid number"
                                  " of nodes (%s), required %s" %
-                                 (len(ial.nodes), req_nodes))
+                                 (len(ial.nodes), ial.required_nodes))
     self.op.pnode = ial.nodes[0]
     logger.ToStdout("Selected nodes for the instance: %s" %
                     (", ".join(ial.nodes),))
     logger.Info("Selected nodes for instance %s via iallocator %s: %s" %
                 (self.op.instance_name, self.op.iallocator, ial.nodes))
-    if req_nodes == 2:
+    if ial.required_nodes == 2:
       self.op.snode = ial.nodes[1]
 
   def BuildHooksEnv(self):
@@ -4742,6 +4738,8 @@ class IAllocator(object):
     self.mode = self.name = None
     self.mem_size = self.disks = self.disk_template = None
     self.os = self.tags = self.nics = self.vcpus = None
+    # computed fields
+    self.required_nodes = None
     # init result fields
     self.success = self.info = self.nodes = None
     for key in kwargs:
@@ -4842,6 +4840,10 @@ class IAllocator(object):
     disk_space = _ComputeDiskSize(self.disk_template,
                                   self.disks[0]["size"], self.disks[1]["size"])
 
+    if self.disk_template in constants.DTS_NET_MIRROR:
+      self.required_nodes = 2
+    else:
+      self.required_nodes = 1
     request = {
       "type": "allocate",
       "name": self.name,
@@ -4853,6 +4855,7 @@ class IAllocator(object):
       "disks": self.disks,
       "disk_space_total": disk_space,
       "nics": self.nics,
+      "required_nodes": self.required_nodes,
       }
     data["request"] = request
 
@@ -4866,12 +4869,27 @@ class IAllocator(object):
     done.
 
     """
-    data = self.in_data
+    instance = self.cfg.GetInstanceInfo(self.name)
+    if instance is None:
+      raise errors.ProgrammerError("Unknown instance '%s' passed to"
+                                   " IAllocator" % self.name)
+
+    if instance.disk_template not in constants.DTS_NET_MIRROR:
+      raise errors.OpPrereqError("Can't relocate non-mirrored instances")
+
+    self.required_nodes = 1
+
+    disk_space = _ComputeDiskSize(instance.disk_template,
+                                  instance.disks[0].size,
+                                  instance.disks[1].size)
+
     request = {
       "type": "replace_secondary",
       "name": self.name,
+      "disk_space_total": disk_space,
+      "required_nodes": self.required_nodes,
       }
-    data["request"] = request
+    self.in_data["request"] = request
 
   def _BuildInputData(self):
     """Build input data structures.
@@ -4905,7 +4923,7 @@ class IAllocator(object):
       if result.failed:
         raise errors.OpExecError("Instance allocator call failed: %s,"
                                  " output: %s" %
-                                 (result.fail_reason, result.stdout))
+                                 (result.fail_reason, result.output))
     finally:
       os.unlink(fin_name)
     self.out_text = result.stdout
-- 
GitLab