root / doc / examples / dumb-allocator @ a2d32034
History | View | Annotate | Download (2.9 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 | 298fe380 | Iustin Pop | import simplejson |
29 | 298fe380 | Iustin Pop | import sys |
30 | 298fe380 | Iustin Pop | |
31 | 298fe380 | Iustin Pop | |
32 | 298fe380 | Iustin Pop | def SelectNode(nodes, request, to_skip): |
33 | 298fe380 | Iustin Pop | """Select a node for the given instance |
34 | 298fe380 | Iustin Pop | |
35 | 298fe380 | Iustin Pop | """ |
36 | 298fe380 | Iustin Pop | disk_size = request["disk_space_total"] |
37 | 298fe380 | Iustin Pop | selected = None |
38 | 298fe380 | Iustin Pop | for nname, ninfo in nodes.iteritems(): |
39 | 298fe380 | Iustin Pop | if nname in to_skip: |
40 | 298fe380 | Iustin Pop | continue |
41 | 298fe380 | Iustin Pop | if request["memory"] > ninfo["free_memory"]: |
42 | 298fe380 | Iustin Pop | continue |
43 | 298fe380 | Iustin Pop | if disk_size > ninfo["free_disk"]: |
44 | 298fe380 | Iustin Pop | continue |
45 | 298fe380 | Iustin Pop | selected = nname |
46 | 298fe380 | Iustin Pop | break |
47 | 298fe380 | Iustin Pop | return selected |
48 | 298fe380 | Iustin Pop | |
49 | 298fe380 | Iustin Pop | |
50 | 538475ca | Iustin Pop | def OutputError(text, exit_code=1): |
51 | 298fe380 | Iustin Pop | """Builds an error response with a given info message. |
52 | 298fe380 | Iustin Pop | |
53 | 298fe380 | Iustin Pop | """ |
54 | 298fe380 | Iustin Pop | error = { |
55 | 298fe380 | Iustin Pop | "success": False, |
56 | 298fe380 | Iustin Pop | "info": text, |
57 | 538475ca | Iustin Pop | "nodes": [], |
58 | 298fe380 | Iustin Pop | } |
59 | 298fe380 | Iustin Pop | print simplejson.dumps(error, indent=2) |
60 | 538475ca | Iustin Pop | return exit_code |
61 | 298fe380 | Iustin Pop | |
62 | 298fe380 | Iustin Pop | |
63 | 298fe380 | Iustin Pop | def main(): |
64 | 298fe380 | Iustin Pop | """Main function. |
65 | 298fe380 | Iustin Pop | |
66 | 298fe380 | Iustin Pop | """ |
67 | 298fe380 | Iustin Pop | if len(sys.argv) < 2: |
68 | 298fe380 | Iustin Pop | print >> sys.stderr, "Usage: %s cluster.json" % (sys.argv[0]) |
69 | 298fe380 | Iustin Pop | return 1 |
70 | 298fe380 | Iustin Pop | |
71 | 298fe380 | Iustin Pop | data = simplejson.load(open(sys.argv[1])) |
72 | 298fe380 | Iustin Pop | |
73 | 298fe380 | Iustin Pop | nodes = data["nodes"] |
74 | 298fe380 | Iustin Pop | request = data["request"] |
75 | 298fe380 | Iustin Pop | req_type = request["type"] |
76 | eb0994e7 | Iustin Pop | if req_type == "allocate": |
77 | eb0994e7 | Iustin Pop | forbidden_nodes = [] |
78 | eb0994e7 | Iustin Pop | inst_data = request |
79 | 2a139bb0 | Iustin Pop | elif req_type == "relocate": |
80 | eb0994e7 | Iustin Pop | idict = data["instances"][request["name"]] |
81 | eb0994e7 | Iustin Pop | forbidden_nodes = idict["nodes"] |
82 | eb0994e7 | Iustin Pop | inst_data = idict |
83 | eb0994e7 | Iustin Pop | inst_data["disk_space_total"] = request["disk_space_total"] |
84 | eb0994e7 | Iustin Pop | else: |
85 | 27579978 | Iustin Pop | return OutputError("Unsupported allocator mode '%s'" % req_type) |
86 | 27579978 | Iustin Pop | |
87 | 27579978 | Iustin Pop | result_nodes = [] |
88 | 27579978 | Iustin Pop | while len(result_nodes) < request["required_nodes"]: |
89 | eb0994e7 | Iustin Pop | new_selection = SelectNode(nodes, inst_data, result_nodes+forbidden_nodes) |
90 | 27579978 | Iustin Pop | if new_selection is None: |
91 | 27579978 | Iustin Pop | return OutputError("Can't find a suitable node for position %s" |
92 | 27579978 | Iustin Pop | " (already selected: %s)" % |
93 | 27579978 | Iustin Pop | (len(result_nodes) + 1, ", ".join(result_nodes)), |
94 | 27579978 | Iustin Pop | exit_code=0) |
95 | 27579978 | Iustin Pop | result_nodes.append(new_selection) |
96 | 298fe380 | Iustin Pop | |
97 | 298fe380 | Iustin Pop | result = { |
98 | 298fe380 | Iustin Pop | "success": True, |
99 | 298fe380 | Iustin Pop | "info": "Allocation successful", |
100 | 298fe380 | Iustin Pop | "nodes": result_nodes, |
101 | 298fe380 | Iustin Pop | } |
102 | 298fe380 | Iustin Pop | print simplejson.dumps(result, indent=2) |
103 | 298fe380 | Iustin Pop | return 0 |
104 | 298fe380 | Iustin Pop | |
105 | 298fe380 | Iustin Pop | if __name__ == "__main__": |
106 | 298fe380 | Iustin Pop | sys.exit(main()) |