Statistics
| Branch: | Tag: | Revision:

root / doc / examples / dumb-allocator @ 752a8ca8

History | View | Annotate | Download (3.1 kB)

1 298fe380 Iustin Pop
#!/usr/bin/python
2 298fe380 Iustin Pop
#
3 298fe380 Iustin Pop
4 298fe380 Iustin Pop
# Copyright (C) 2008 Google Inc.
5 298fe380 Iustin Pop
#
6 298fe380 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 298fe380 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 298fe380 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 298fe380 Iustin Pop
# (at your option) any later version.
10 298fe380 Iustin Pop
#
11 298fe380 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 298fe380 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 298fe380 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 298fe380 Iustin Pop
# General Public License for more details.
15 298fe380 Iustin Pop
#
16 298fe380 Iustin Pop
# You should have received a copy of the GNU General Public License
17 298fe380 Iustin Pop
# along with this program; if not, write to the Free Software
18 298fe380 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 298fe380 Iustin Pop
# 02110-1301, USA.
20 298fe380 Iustin Pop
21 298fe380 Iustin Pop
"""Simple first-fit allocator for ganeti instance allocation framework.
22 298fe380 Iustin Pop
23 298fe380 Iustin Pop
This allocator just iterates over the nodes and selects the first one
24 298fe380 Iustin Pop
that fits in both memory and disk space, without any consideration for
25 298fe380 Iustin Pop
equal spread or VCPU oversubscription.
26 298fe380 Iustin Pop
27 298fe380 Iustin Pop
"""
28 b3a447ef Michael Hanselmann
29 298fe380 Iustin Pop
import simplejson
30 298fe380 Iustin Pop
import sys
31 298fe380 Iustin Pop
32 298fe380 Iustin Pop
33 298fe380 Iustin Pop
def SelectNode(nodes, request, to_skip):
34 298fe380 Iustin Pop
  """Select a node for the given instance
35 298fe380 Iustin Pop
36 298fe380 Iustin Pop
  """
37 298fe380 Iustin Pop
  disk_size = request["disk_space_total"]
38 298fe380 Iustin Pop
  selected = None
39 298fe380 Iustin Pop
  for nname, ninfo in nodes.iteritems():
40 298fe380 Iustin Pop
    if nname in to_skip:
41 298fe380 Iustin Pop
      continue
42 298fe380 Iustin Pop
    if request["memory"] > ninfo["free_memory"]:
43 298fe380 Iustin Pop
      continue
44 298fe380 Iustin Pop
    if disk_size > ninfo["free_disk"]:
45 298fe380 Iustin Pop
      continue
46 298fe380 Iustin Pop
    selected = nname
47 298fe380 Iustin Pop
    break
48 298fe380 Iustin Pop
  return selected
49 298fe380 Iustin Pop
50 298fe380 Iustin Pop
51 538475ca Iustin Pop
def OutputError(text, exit_code=1):
52 298fe380 Iustin Pop
  """Builds an error response with a given info message.
53 298fe380 Iustin Pop
54 298fe380 Iustin Pop
  """
55 298fe380 Iustin Pop
  error = {
56 298fe380 Iustin Pop
    "success": False,
57 298fe380 Iustin Pop
    "info": text,
58 538475ca Iustin Pop
    "nodes": [],
59 298fe380 Iustin Pop
    }
60 298fe380 Iustin Pop
  print simplejson.dumps(error, indent=2)
61 538475ca Iustin Pop
  return exit_code
62 298fe380 Iustin Pop
63 298fe380 Iustin Pop
64 298fe380 Iustin Pop
def main():
65 298fe380 Iustin Pop
  """Main function.
66 298fe380 Iustin Pop
67 298fe380 Iustin Pop
  """
68 298fe380 Iustin Pop
  if len(sys.argv) < 2:
69 298fe380 Iustin Pop
    print >> sys.stderr, "Usage: %s cluster.json" % (sys.argv[0])
70 298fe380 Iustin Pop
    return 1
71 298fe380 Iustin Pop
72 298fe380 Iustin Pop
  data = simplejson.load(open(sys.argv[1]))
73 298fe380 Iustin Pop
74 298fe380 Iustin Pop
  nodes =  data["nodes"]
75 298fe380 Iustin Pop
  request = data["request"]
76 298fe380 Iustin Pop
  req_type = request["type"]
77 1325da74 Iustin Pop
  offline_nodes = [name for name in nodes if nodes[name]["offline"]]
78 7d26425f Iustin Pop
  drained_nodes = [name for name in nodes if nodes[name]["offline"]]
79 eb0994e7 Iustin Pop
  if req_type == "allocate":
80 5c562aa4 Guido Trotter
    forbidden_nodes = offline_nodes + drained_nodes
81 eb0994e7 Iustin Pop
    inst_data = request
82 2a139bb0 Iustin Pop
  elif req_type == "relocate":
83 eb0994e7 Iustin Pop
    idict = data["instances"][request["name"]]
84 7d26425f Iustin Pop
    forbidden_nodes = idict["nodes"] + offline_nodes + drained_nodes
85 eb0994e7 Iustin Pop
    inst_data = idict
86 eb0994e7 Iustin Pop
    inst_data["disk_space_total"] = request["disk_space_total"]
87 eb0994e7 Iustin Pop
  else:
88 27579978 Iustin Pop
    return OutputError("Unsupported allocator mode '%s'" % req_type)
89 27579978 Iustin Pop
90 27579978 Iustin Pop
  result_nodes = []
91 27579978 Iustin Pop
  while len(result_nodes) < request["required_nodes"]:
92 eb0994e7 Iustin Pop
    new_selection = SelectNode(nodes, inst_data, result_nodes+forbidden_nodes)
93 27579978 Iustin Pop
    if new_selection is None:
94 27579978 Iustin Pop
      return OutputError("Can't find a suitable node for position %s"
95 27579978 Iustin Pop
                         " (already selected: %s)" %
96 27579978 Iustin Pop
                         (len(result_nodes) + 1, ", ".join(result_nodes)),
97 27579978 Iustin Pop
                         exit_code=0)
98 27579978 Iustin Pop
    result_nodes.append(new_selection)
99 298fe380 Iustin Pop
100 298fe380 Iustin Pop
  result = {
101 b3a447ef Michael Hanselmann
    "success": True,
102 b3a447ef Michael Hanselmann
    "info": "Allocation successful",
103 b3a447ef Michael Hanselmann
    "nodes": result_nodes,
104 b3a447ef Michael Hanselmann
    }
105 298fe380 Iustin Pop
  print simplejson.dumps(result, indent=2)
106 298fe380 Iustin Pop
  return 0
107 298fe380 Iustin Pop
108 b3a447ef Michael Hanselmann
109 298fe380 Iustin Pop
if __name__ == "__main__":
110 298fe380 Iustin Pop
    sys.exit(main())