import repository from arizona
[raven.git] / apps / gacks / gackshandler_plc.py
1 import xmlrpclib
2 from gackshandler_base import GacksHandler
3
4 def slice_to_hrn(x):
5     parts = x.split("_",1)
6     return ".".join(["plc",parts[0],parts[1]])
7
8 def hrn_to_slice(x):
9     parts = x.split(".")
10     if len(parts)!=3:
11         return None
12     return parts[1] + "_" + parts[2]
13
14 class GacksPLCException(Exception):
15     def __init__(self, value):
16         self.value = value\r
17     def __str__(self):\r
18         return repr(self.value)
19
20 class GacksPLCConnectFailed(GacksPLCException):
21     pass
22
23 class GacksPLCAuthFailed(GacksPLCException):
24     pass
25
26 class GacksPLCHandler(GacksHandler):
27     def __init__(self, resourceDefinition):
28         GacksHandler.__init__(self, resourceDefinition)
29
30         self.password = self.resourceDefinition.plcPassword
31         if self.password.startswith("file://"):
32             fn = self.password[7:]
33             self.password = open(fn,"r").readline().strip()
34
35     def connectToPlc(self):
36         self.plcAuth = { 'Username': self.resourceDefinition.plcUser,
37                          'AuthMethod': 'password',
38                          'AuthString': self.password,
39                          'Role': 'admin'}
40
41         print "connecting to", self.resourceDefinition.plcServer
42
43         try:
44             self.plcServer = xmlrpclib.Server(self.resourceDefinition.plcServer, verbose = 0, allow_none=True)
45         except IOError, errormessage:
46             raise GacksPLCConnectFailed("connection to " + self.resourceDefinition.plcServer + " failed")
47
48         try:
49             self.plcServer.AuthCheck(self.plcAuth)
50         except xmlrpclib.Fault, errormessage:
51             raise GacksPLCAuthFailed(str(errormessage))
52
53         print "connection established"
54
55     def addReservation(self, hostName, consumer, index, rawIndex):
56         hostDict = self.hosts.get(hostName, {})
57         self.hosts[hostName] = hostDict
58
59         consumerDict = hostDict.get(consumer, {"items": [], "rawIndex": rawIndex, "applied": False})
60         hostDict[consumer] = consumerDict
61
62         consumerDict["items"].append(str(index))
63
64     def dumpReservations(self):
65         for hostName in self.hosts.keys():
66             hostDict = self.hosts[hostName]
67             for consumer in hostDict.keys():
68                 consumerDict = hostDict[consumer]
69                 print consumerDict["rawIndex"], hostName, consumer, consumerDict["items"]
70
71     def findReservation(self, hostName, consumer):
72         hostDict = self.hosts.get(hostName, None)
73         if not hostDict:
74             return None
75
76         consumerDict = hostDict.get(consumer, None)
77         return consumerDict
78
79     def applyReservations(self, resources):
80         self.connectToPlc()
81
82         filter = {"tagname": "cpu_cores"}
83         return_fields = ["name", "node_id", "value", "tagname", "slice_tag_id"]
84         tags = self.plcServer.GetSliceTags(self.plcAuth, filter, return_fields)
85
86         return_fields = ["site_id", "node_id", "hostname"]
87         nodes = self.plcServer.GetNodes(self.plcAuth, None, return_fields)
88
89         nodeIdMap = {}
90         nodeReverseMap = {}
91         for node in nodes:
92             nodeIdMap[node["node_id"]] = node
93             nodeReverseMap[node["hostname"]] = node
94
95         resDef = self.resourceDefinition
96
97         self.hosts={}
98
99         for consumer in resources.keys():
100             resource = resources[consumer]
101             for rec in resource["records"]:
102                 for i in range(rec.unitStart, rec.unitStop):
103                     (hostitem,offset) = resDef.inverse_map(i)
104                     if not hostitem:
105                         print "unable to map reservation", i
106                     else:
107                         hostname = hostitem.name
108                         self.addReservation(hostname, resource["consumer"], i-offset, i)
109
110         self.dumpReservations()
111
112         # remove and modify things in the PLC database
113         for tag in tags:
114             node_id = tag["node_id"]
115             if (not node_id in nodeIdMap):
116                 print "unable to map node_id", node_id
117                 continue
118
119             hostname = nodeIdMap[node_id]["hostname"]
120             consumer = slice_to_hrn(tag["name"])
121
122             reservation = self.findReservation(hostname, consumer)
123             if not reservation:
124                 print "remove slice attribute:", tag["slice_tag_id"], hostname, consumer
125                 self.plcServer.DeleteSliceTag(self.plcAuth, tag["slice_tag_id"])
126             else:
127                 resStr = ",".join(reservation["items"])
128                 if (tag["value"] != resStr):
129                     print "change slice attribute:", tag["slice_tag_id"], hostname, consumer, "from", tag["value"], "=", resStr
130                     self.plcServer.UpdateSliceTag(self.plcAuth, tag["slice_tag_id"], resStr)
131                     reservation["applied"] = True
132                 else:
133                     print "keeping slice attribute:", tag["slice_tag_id"], hostname, consumer, "from", tag["value"]
134                     reservation["applied"] = True
135
136         # add new things to the PLC database
137         for hostName in self.hosts.keys():
138             hostDict = self.hosts[hostName]
139             for consumer in hostDict.keys():
140                 reservation = hostDict[consumer]
141
142                 if reservation["applied"]:
143                     continue
144
145                 slicename = hrn_to_slice(consumer)
146                 if not slicename:
147                     print "failed to convert slicename from", consumer
148                     continue
149
150                 resStr = ",".join(reservation["items"])
151
152                 print "add tag", hostName, slicename, resStr
153
154                 self.plcServer.AddSliceTag(self.plcAuth, slicename, resDef.plcAttribute, resStr, hostName)
155
156     def getNodes(self):
157         self.connectToPlc()
158
159         # all_nodes_cores: build a dict of node_id->resvd_cores
160         filter = {"tagname": "cpu_cores"}
161         return_fields = ["name", "node_id", "slice_id", "value", "tagname", "slice_tag_id"]
162         tags = self.plcServer.GetSliceTags(self.plcAuth, filter, return_fields)
163         all_nodes_cores = {}
164         for tag in tags:
165             node_id = tag["node_id"]
166             if not (node_id) in all_nodes_cores:
167                 all_nodes_cores[node_id] = {}
168             all_nodes_cores[node_id][tag["name"]] = int(tag["value"])
169
170         # all_slices_names: build a dict of slice_id -> slice_name
171         return_fields = ["slice_id", "name"]
172         slices = self.plcServer.GetSlices(self.plcAuth, None, return_fields)
173         all_slices_names = {}
174         for slice in slices:
175             all_slices_names[slice["slice_id"]] = slice["name"]
176
177         return_fields = ["site_id", "name"]
178         sites = self.plcServer.GetSites(self.plcAuth, None, return_fields)
179         all_site_names = {}
180         for site in sites:
181             all_site_names[site["site_id"]] = site["name"]
182
183         nodes = []
184
185         plcNodes = self.plcServer.GetNodes(self.plcAuth)
186         for plcNode in plcNodes:
187             # convert the slice_ids to slice names
188             slice_names = []
189             for slice_id in plcNode["slice_ids"]:
190                 if slice_id in all_slices_names:
191                     slice_names.append(all_slices_names[slice_id])
192
193             reservations = all_nodes_cores.get(plcNode["node_id"],{})
194
195             site_name = all_site_names.get(plcNode["site_id"], "unknown")
196
197             node = {"name": plcNode["hostname"], "id": plcNode["node_id"], "slices": slice_names, "reservations": reservations, "group": site_name}
198             nodes.append(node)
199
200         return nodes
201
202     def addNodes(self, sliceName, nodes):
203         self.connectToPlc()
204
205         node_ids = [node["id"] for node in nodes]
206
207         self.plcServer.AddSliceToNodes(self.plcAuth, sliceName, node_ids)
208
209     def delNodes(self, sliceName, nodes):
210         self.connectToPlc()
211
212         node_ids = [node["id"] for node in nodes]
213
214         self.plcServer.DeleteSliceFromNodes(self.plcAuth, sliceName, node_ids)
215