import repository from arizona
[raven.git] / apps / gacks / gacksnodepicker.py
1 import functools
2 from gacksexcep import *
3 from gackshandler_plc import GacksPLCHandler
4
5 from sfa.util.plxrn import hrn_to_pl_slicename
6
7 def NodeSortKey(node, sliceName):
8     name = node["name"]
9     slices = node["slices"][:]
10     reservations = node["reservations"].copy()
11
12     # For sorting purposes, we want to pretend that sliceName isn't in use
13     # on the node.
14
15     if sliceName in slices:
16         slices.remove(sliceName)
17
18     if sliceName in reservations.keys():
19         del reservations[sliceName]
20
21     sliceCount = len(slices)
22
23     resvCount = 0
24     for resv in reservations.keys():
25         resvCount += reservations[resv]
26
27     # Our sort key (from most primary key to least primary key)
28     #   sliceCount  ... ensures that nodes with few slices get preference
29     #   name        ... puts them in alphabetic order
30
31     return (sliceCount, name)
32
33
34 class GacksNodePicker():
35     def __init__(self, resources):
36         self.resources = resources
37
38     def get_handler(self, resource):
39         if resource.handler == "plc":
40             return GacksPLCHandler(resource)
41         else:
42             return None
43
44     def filter_nodes(self, nodes, pool):
45         pool_names = [resource.name for resource in pool]
46         if (pool!=None) and (pool!=[]):
47             return [node for node in nodes if node["name"] in pool_names]
48         else:
49             return nodes
50
51     def sort_nodes(self, nodes, sliceName):
52         nodes = sorted(nodes, key=functools.partial(NodeSortKey, sliceName=sliceName))
53         return nodes
54
55     def expand_nodes(self, nodes, sliceName, amount):
56         addSet = []
57         for node in nodes:
58             if sliceName in node["slices"]:
59                 pass
60             elif amount>0:
61                 addSet.append(node)
62                 amount -= 1
63
64         if (amount > 0):
65             raise "not enough nodes to choose from"
66
67         return ([], addSet)
68
69     def replace_nodes(self, nodes, sliceName, amount):
70         addSet = []
71         delSet = []
72         for node in nodes:
73             if (amount>0):
74                 if sliceName in node["slices"]:
75                     pass
76                 else:
77                     addSet.append(node)
78                 amount -= 1
79             else:
80                 if sliceName in node["slices"]:
81                     delSet.append(node)
82
83         if (amount > 0):
84             raise "not enough nodes to choose from"
85
86         return (delSet, addSet)
87
88     def pick(self, sliceHRN, resourceName, resourceGroup, amount, expand=False):
89         sliceName = hrn_to_pl_slicename(sliceHRN)
90
91         resource = self.resources.get_resource(resourceName)
92         if resourceGroup==None:
93             pool = resource.resources
94         else:
95             # XXX: error checking here
96             pool = resource.get_subgroups_dict()[resourceGroup]
97
98         handler = self.get_handler(resource)
99
100         nodes = handler.getNodes()
101
102         nodes = self.filter_nodes(nodes, pool)
103
104         nodes = self.sort_nodes(nodes, sliceName)
105
106         if expand:
107             (delSet, addSet) = self.expand_nodes(nodes, sliceName, amount)
108         else:
109             (delSet, addSet) = self.replace_nodes(nodes, sliceName, amount)
110
111         print "delSet:\n", "\n".join(["  "+x["name"] for x in delSet])
112         print "addSet:\n", "\n".join(["  "+x["name"] for x in addSet])
113
114         handler.delNodes(sliceName, delSet)
115         handler.addNodes(sliceName, addSet)
116
117         return (delSet, addSet)
118
119
120