Revision 6f547f96

b/Makefile.am
402 402
	doc/examples/ganeti-kvm-poweroff.initd.in \
403 403
	doc/examples/ganeti.cron.in \
404 404
	doc/examples/gnt-config-backup.in \
405
	doc/examples/dumb-allocator \
406 405
	doc/examples/ganeti.default \
407 406
	doc/examples/ganeti.default-debug \
408 407
	doc/examples/hooks/ethers \
/dev/null
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

  
29
import simplejson
30
import sys
31

  
32

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

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

  
50

  
51
def OutputError(text, exit_code=1):
52
  """Builds an error response with a given info message.
53

  
54
  """
55
  error = {
56
    "success": False,
57
    "info": text,
58
    "nodes": [],
59
    }
60
  print simplejson.dumps(error, indent=2)
61
  return exit_code
62

  
63

  
64
def main():
65
  """Main function.
66

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

  
72
  data = simplejson.load(open(sys.argv[1]))
73

  
74
  nodes =  data["nodes"]
75
  request = data["request"]
76
  req_type = request["type"]
77
  offline_nodes = [name for name in nodes if nodes[name]["offline"]]
78
  drained_nodes = [name for name in nodes if nodes[name]["offline"]]
79
  if req_type == "allocate":
80
    forbidden_nodes = offline_nodes + drained_nodes
81
    inst_data = request
82
  elif req_type == "relocate":
83
    idict = data["instances"][request["name"]]
84
    forbidden_nodes = idict["nodes"] + offline_nodes + drained_nodes
85
    inst_data = idict
86
    inst_data["disk_space_total"] = request["disk_space_total"]
87
  else:
88
    return OutputError("Unsupported allocator mode '%s'" % req_type)
89

  
90
  result_nodes = []
91
  while len(result_nodes) < request["required_nodes"]:
92
    new_selection = SelectNode(nodes, inst_data, result_nodes+forbidden_nodes)
93
    if new_selection is None:
94
      return OutputError("Can't find a suitable node for position %s"
95
                         " (already selected: %s)" %
96
                         (len(result_nodes) + 1, ", ".join(result_nodes)),
97
                         exit_code=0)
98
    result_nodes.append(new_selection)
99

  
100
  result = {
101
    "success": True,
102
    "info": "Allocation successful",
103
    "nodes": result_nodes,
104
    }
105
  print simplejson.dumps(result, indent=2)
106
  return 0
107

  
108

  
109
if __name__ == "__main__":
110
    sys.exit(main())
b/doc/iallocator.rst
322 322
      "disk_template": "drbd",
323 323
      "memory": 2048,
324 324
      "disk_space_total": 3328,
325
      "os": "etch-image"
325
      "os": "debootstrap+default"
326 326
    },
327 327
    "cluster_name": "cluster1.example.com",
328 328
    "instances": {
......
352 352
        "nodes": [
353 353
          "nodee1.com"
354 354
        ],
355
        "os": "etch-image"
355
        "os": "debootstrap+default"
356 356
      },
357 357
      "instance2.example.com": {
358 358
        "tags": [],
......
381 381
          "node2.example.com",
382 382
          "node3.example.com"
383 383
        ],
384
        "os": "etch-image"
384
        "os": "debootstrap+default"
385 385
      }
386 386
    },
387 387
    "version": 1,
......
483 483
~~~~~~~~~~~~~~~~~~~~~
484 484
::
485 485

  
486
  # gnt-instance add -t plain -m 2g --os-size 1g --swap-size 512m --iallocator dumb-allocator -o etch-image instance3
486
  # gnt-instance add -t plain -m 2g --os-size 1g --swap-size 512m --iallocator hail -o debootstrap+default instance3
487 487
  Selected nodes for the instance: node1.example.com
488 488
  * creating instance disks...
489 489
  [...]
490 490

  
491
  # gnt-instance add -t plain -m 3400m --os-size 1g --swap-size 512m --iallocator dumb-allocator -o etch-image instance4
491
  # gnt-instance add -t plain -m 3400m --os-size 1g --swap-size 512m --iallocator hail -o debootstrap+default instance4
492 492
  Failure: prerequisites not met for this operation:
493
  Can't compute nodes using iallocator 'dumb-allocator': Can't find a suitable node for position 1 (already selected: )
493
  Can't compute nodes using iallocator 'hail': Can't find a suitable node for position 1 (already selected: )
494 494

  
495
  # gnt-instance add -t drbd -m 1400m --os-size 1g --swap-size 512m --iallocator dumb-allocator -o etch-image instance5
495
  # gnt-instance add -t drbd -m 1400m --os-size 1g --swap-size 512m --iallocator hail -o debootstrap+default instance5
496 496
  Failure: prerequisites not met for this operation:
497
  Can't compute nodes using iallocator 'dumb-allocator': Can't find a suitable node for position 2 (already selected: node1.example.com)
497
  Can't compute nodes using iallocator 'hail': Can't find a suitable node for position 2 (already selected: node1.example.com)
498

  
499
Reference implementation
500
~~~~~~~~~~~~~~~~~~~~~~~~
501

  
502
Ganeti's default iallocator is "hail" which is part of the separate
503
ganeti-htools project. In order to see its source code please clone
504
``git://git.ganeti.org/htools.git``. Note that htools is implemented
505
using the Haskell programming language.
498 506

  
499 507
.. vim: set textwidth=72 :
500 508
.. Local Variables:

Also available in: Unified diff