Revision 298fe380

b/configure.ac
50 50
  [os_search_path="'/srv/ganeti/os'"])
51 51
AC_SUBST(OS_SEARCH_PATH, $os_search_path)
52 52

  
53
# --with-iallocator-search-path=...
54
# do a bit of black sed magic to for quoting of the strings in the list
55
AC_ARG_WITH([iallocator-search-path],
56
  [AS_HELP_STRING([--with-iallocator-search-path=LIST],
57
    [comma separated list of directories to]
58
    [ search for instance allocators (default is $libdir/ganeti/iallocators)]
59
  )],
60
  [iallocator_search_path=`echo -n "$withval" | sed -e "s/\([[^,]]*\)/'\1'/g"`],
61
  [iallocator_search_path="'$libdir/$PACKAGE_NAME/iallocators'"])
62
AC_SUBST(IALLOCATOR_SEARCH_PATH, $iallocator_search_path)
63

  
53 64
# --with-xen-kernel=...
54 65
AC_ARG_WITH([xen-kernel],
55 66
  [AS_HELP_STRING([--with-xen-kernel=PATH],
b/doc/examples/dumb-allocator
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2008 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21
"""Simple first-fit allocator for ganeti instance allocation framework.
22

  
23
This allocator just iterates over the nodes and selects the first one
24
that fits in both memory and disk space, without any consideration for
25
equal spread or VCPU oversubscription.
26

  
27
"""
28
import simplejson
29
import sys
30

  
31

  
32
def SelectNode(nodes, request, to_skip):
33
  """Select a node for the given instance
34

  
35
  """
36
  disk_size = request["disk_space_total"]
37
  selected = None
38
  for nname, ninfo in nodes.iteritems():
39
    if nname in to_skip:
40
      continue
41
    if request["memory"] > ninfo["free_memory"]:
42
      continue
43
    if disk_size > ninfo["free_disk"]:
44
      continue
45
    selected = nname
46
    break
47
  return selected
48

  
49

  
50
def OutputError(text):
51
  """Builds an error response with a given info message.
52

  
53
  """
54
  error = {
55
    "success": False,
56
    "info": text,
57
    }
58
  print simplejson.dumps(error, indent=2)
59
  return 1
60

  
61

  
62
def main():
63
  """Main function.
64

  
65
  """
66
  if len(sys.argv) < 2:
67
    print >> sys.stderr, "Usage: %s cluster.json" % (sys.argv[0])
68
    return 1
69

  
70
  data = simplejson.load(open(sys.argv[1]))
71

  
72
  nodes =  data["nodes"]
73
  request = data["request"]
74
  req_type = request["type"]
75
  if req_type != "allocate":
76
    print >> sys.stderr, "Unsupported allocator mode '%s'" % req_type
77
    return 1
78

  
79
  npri = SelectNode(nodes, request, [])
80
  if npri is None:
81
    return OutputError("Can't find a suitable primary node")
82

  
83
  result_nodes = [npri]
84
  if request["disk_template"] == "drbd":
85
    nsec = SelectNode(nodes, request, result_nodes)
86
    if nsec is None:
87
      return OutputError("Can't find a suitable secondary node (%s selected"
88
                         " as primary)" % npri)
89
    result_nodes.append(nsec)
90

  
91
  result = {
92
          "success": True,
93
          "info": "Allocation successful",
94
          "nodes": result_nodes,
95
          }
96
  print simplejson.dumps(result, indent=2)
97
  return 0
98

  
99
if __name__ == "__main__":
100
    sys.exit(main())
b/lib/Makefile.am
25 25
	  echo "XEN_KERNEL = '$(XEN_KERNEL)'"; \
26 26
	  echo "XEN_INITRD = '$(XEN_INITRD)'"; \
27 27
	  echo "FILE_STORAGE_DIR = '$(FILE_STORAGE_DIR)'"; \
28
	  echo "IALLOCATOR_SEARCH_PATH = [$(IALLOCATOR_SEARCH_PATH)]"; \
28 29
	} > $@
29 30

  
30 31
pre-check: all
b/lib/cmdlib.py
4650 4650
                                   " result: %s" % (node, node_result))
4651 4651

  
4652 4652

  
4653
def _AllocatorGetClusterData(cfg, sstore):
4653
def _IAllocatorGetClusterData(cfg, sstore):
4654 4654
  """Compute the generic allocator input data.
4655 4655

  
4656 4656
  This is the data that is independent of the actual operation.
......
4720 4720
  return data
4721 4721

  
4722 4722

  
4723
def _AllocatorAddNewInstance(data, op):
4723
def _IAllocatorAddNewInstance(data, op):
4724 4724
  """Add new instance data to allocator structure.
4725 4725

  
4726 4726
  This in combination with _AllocatorGetClusterData will create the
......
4730 4730
  done.
4731 4731

  
4732 4732
  """
4733
  if len(op.disks) != 2:
4734
    raise errors.OpExecError("Only two-disk configurations supported")
4735

  
4736
  disk_space = _ComputeDiskSize(op.disk_template,
4737
                                op.disks[0]["size"], op.disks[1]["size"])
4738

  
4733 4739
  request = {
4734 4740
    "type": "allocate",
4735 4741
    "name": op.name,
......
4739 4745
    "vcpus": op.vcpus,
4740 4746
    "memory": op.mem_size,
4741 4747
    "disks": op.disks,
4748
    "disk_space_total": disk_space,
4742 4749
    "nics": op.nics,
4743 4750
    }
4744 4751
  data["request"] = request
4745 4752

  
4746 4753

  
4747
def _AllocatorAddRelocateInstance(data, op):
4754
def _IAllocatorAddRelocateInstance(data, op):
4748 4755
  """Add relocate instance data to allocator structure.
4749 4756

  
4750
  This in combination with _AllocatorGetClusterData will create the
4757
  This in combination with _IAllocatorGetClusterData will create the
4751 4758
  correct structure needed as input for the allocator.
4752 4759

  
4753 4760
  The checks for the completeness of the opcode must have already been
......
4761 4768
  data["request"] = request
4762 4769

  
4763 4770

  
4771
def _IAllocatorRun(name, data):
4772
  """Run an instance allocator and return the results.
4773

  
4774
  """
4775
  alloc_script = utils.FindFile(name, constants.IALLOCATOR_SEARCH_PATH,
4776
                                os.path.isfile)
4777
  if alloc_script is None:
4778
    raise errors.OpExecError("Can't find allocator")
4779

  
4780
  fd, fin_name = tempfile.mkstemp(prefix="ganeti-iallocator.")
4781
  try:
4782
    os.write(fd, data)
4783
    os.close(fd)
4784
    result = utils.RunCmd([alloc_script, fin_name])
4785
    if result.failed:
4786
      raise errors.OpExecError("Instance allocator call failed: %s,"
4787
                               " output: %s" %
4788
                               (result.fail_reason, result.stdout))
4789
  finally:
4790
    os.unlink(fin_name)
4791
  return result.stdout
4792

  
4793

  
4764 4794
class LUTestAllocator(NoHooksLU):
4765 4795
  """Run allocator tests.
4766 4796

  
......
4775 4805
    This checks the opcode parameters depending on the director and mode test.
4776 4806

  
4777 4807
    """
4778
    if self.op.mode == constants.ALF_MODE_ALLOC:
4808
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
4779 4809
      for attr in ["name", "mem_size", "disks", "disk_template",
4780 4810
                   "os", "tags", "nics", "vcpus"]:
4781 4811
        if not hasattr(self.op, attr):
......
4796 4826
                                     " 'nics' parameter")
4797 4827
      if not isinstance(self.op.disks, list):
4798 4828
        raise errors.OpPrereqError("Invalid parameter 'disks'")
4829
      if len(self.op.disks) != 2:
4830
        raise errors.OpPrereqError("Only two-disk configurations supported")
4799 4831
      for row in self.op.disks:
4800 4832
        if (not isinstance(row, dict) or
4801 4833
            "size" not in row or
......
4804 4836
            row["mode"] not in ['r', 'w']):
4805 4837
          raise errors.OpPrereqError("Invalid contents of the"
4806 4838
                                     " 'disks' parameter")
4807
    elif self.op.mode == constants.ALF_MODE_RELOC:
4839
    elif self.op.mode == constants.IALLOCATOR_MODE_RELOC:
4808 4840
      if not hasattr(self.op, "name"):
4809 4841
        raise errors.OpPrereqError("Missing attribute 'name' on opcode input")
4810 4842
      fname = self.cfg.ExpandInstanceName(self.op.name)
......
4816 4848
      raise errors.OpPrereqError("Invalid test allocator mode '%s'" %
4817 4849
                                 self.op.mode)
4818 4850

  
4819
    if self.op.direction == constants.ALF_DIR_OUT:
4820
      if not hasattr(self.op, "allocator"):
4851
    if self.op.direction == constants.IALLOCATOR_DIR_OUT:
4852
      if not hasattr(self.op, "allocator") or self.op.allocator is None:
4821 4853
        raise errors.OpPrereqError("Missing allocator name")
4822
      raise errors.OpPrereqError("Allocator out mode not supported yet")
4823
    elif self.op.direction != constants.ALF_DIR_IN:
4854
    elif self.op.direction != constants.IALLOCATOR_DIR_IN:
4824 4855
      raise errors.OpPrereqError("Wrong allocator test '%s'" %
4825 4856
                                 self.op.direction)
4826 4857

  
......
4828 4859
    """Run the allocator test.
4829 4860

  
4830 4861
    """
4831
    data = _AllocatorGetClusterData(self.cfg, self.sstore)
4832
    if self.op.mode == constants.ALF_MODE_ALLOC:
4833
      _AllocatorAddNewInstance(data, self.op)
4862
    data = _IAllocatorGetClusterData(self.cfg, self.sstore)
4863
    if self.op.mode == constants.IALLOCATOR_MODE_ALLOC:
4864
      _IAllocatorAddNewInstance(data, self.op)
4834 4865
    else:
4835
      _AllocatorAddRelocateInstance(data, self.op)
4866
      _IAllocatorAddRelocateInstance(data, self.op)
4836 4867

  
4837 4868
    if _JSON_INDENT is None:
4838 4869
      text = simplejson.dumps(data)
4839 4870
    else:
4840 4871
      text = simplejson.dumps(data, indent=_JSON_INDENT)
4841
    return text
4872
    if self.op.direction == constants.IALLOCATOR_DIR_IN:
4873
      result = text
4874
    else:
4875
      result = _IAllocatorRun(self.op.allocator, text)
4876
    return result
b/lib/constants.py
185 185
VERIFY_OPTIONAL_CHECKS = frozenset([VERIFY_NPLUSONE_MEM])
186 186

  
187 187
# Allocator framework constants
188
ALF_DIR_IN = "in"
189
ALF_DIR_OUT = "out"
190
ALF_MODE_ALLOC = "allocate"
191
ALF_MODE_RELOC = "relocate"
188
IALLOCATOR_DIR_IN = "in"
189
IALLOCATOR_DIR_OUT = "out"
190
IALLOCATOR_MODE_ALLOC = "allocate"
191
IALLOCATOR_MODE_RELOC = "relocate"
192
IALLOCATOR_SEARCH_PATH = _autoconf.IALLOCATOR_SEARCH_PATH

Also available in: Unified diff