remove unnecessary references to old-style sfa.storage.record
[sface.git] / sface / sfiprocess.py
1
2 import os
3 import json
4 import pickle
5 import sys
6 import tempfile
7 import time
8
9 from PyQt4.QtCore import *
10 from sface.config import config
11 from sface.xmlrpcwindow import get_tracker, XmlrpcReader
12
13 def find_executable(exec_name):
14     """find the given executable in $PATH"""
15     paths = os.getenv("PATH").split(':')
16     for p in paths:
17         exec_path = os.path.join(p, exec_name)
18         if os.path.exists(exec_path) and os.access(exec_path,os.X_OK):
19             return exec_path
20     return None
21
22
23 class SfiProcess(QObject):
24     def __init__(self, parent=None):
25         QObject.__init__(self, parent)
26
27         env = QProcess.systemEnvironment()
28         env << "PYTHONPATH=%s" % ":".join(sys.path)
29         self.process = QProcess()
30         self.process.setEnvironment(env)
31         self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"),
32                      self.processFinished)
33
34         self.xmlrpcreader = XmlrpcReader() # this one is for parsing XMLRPC responses
35
36         # holds aggregate output from processStandardOutput(); used by xmlrpc
37         # tracker.
38         self.output = ""
39
40         self.do_raw = True   # xxx should check version of sfa
41
42         self.connect(self.process, SIGNAL("readyReadStandardOutput()"),
43                      self.processStandardOutput)
44         self.connect(self.process, SIGNAL("readyReadStandardError()"),
45                      self.processStandardError)
46
47     def __init_command(self, args, save_filename=None):
48         self.args = QStringList()
49         self.args << "-d"
50         self.args << config.get_dirname()
51
52         # this shows xmlrpc conversation, see sfi.py docs.
53         # always do this, so we can parse the XML result for faults and show
54         # then to the users.
55         self.args << QString('-D')
56
57         if self.do_raw:
58             self.raw_filename = tempfile.mktemp(suffix=".raw")
59             self.args << QString('-R')
60             self.args << QString(self.raw_filename)
61             self.args << QString('--rawformat')
62             self.args << QString('json')
63         else:
64             self.raw_filename = None
65
66         self.save_filename = save_filename
67
68         for arg in args:
69             self.args << QString(arg)
70
71         self.exe = find_executable("sfi.py")
72         if not self.exe:
73             print "FATAL.. Could not locate binary sfi.py - not much we can do without that"
74
75     def isRunning(self):
76         return self.process.state() != QProcess.NotRunning
77
78     def processStandardOutput(self):
79         output = self.process.readAllStandardOutput()
80         self.output = self.output + output
81         if config.debug:
82             try:
83                 print output
84             except IOError, e:
85                 if (e.errno == 4):
86                     # XXX why is this happening??
87                     print "*** caught EINTR"
88                 else:
89                     raise
90
91
92     def processStandardError(self):
93         print self.process.readAllStandardError()
94
95     def processFinished(self):
96         if self.process.exitStatus() == QProcess.CrashExit:
97             print self.readOutput()
98             print "Process exited with errors:",
99             err = self.process.error()
100             if err == QProcess.FailedToStart:
101                 print "FailedToStart"
102             elif err == QProcess.Crashed:
103                 print "Crashed"
104             elif err == QProcess.Timedout:
105                 print "Timedout"
106             elif err == QProcess.WriteError:
107                 print "WriteError"
108             elif err == QProcess.ReadError:
109                 print "ReadError"
110             elif err == QProcess.UnknownError:
111                 print "UnknownError"
112
113         self.raw_data = None
114         if (self.raw_filename != None) and os.path.exists(self.raw_filename):
115             if hasattr(json, "loads"):
116                 self.raw_data = json.loads(open(self.raw_filename,"r").read()) # python 2.6
117             else:
118                 self.raw_data = json.read(open(self.raw_filename,"r").read()) # python 2.5
119
120             os.remove(self.raw_filename)
121
122         self.geni_code=None
123         self.geni_output=None
124         if (self.raw_data!=None) and (type(self.raw_data)==dict):
125             code = self.raw_data.get("code",{})
126             self.geni_code = code.get("geni_code",None)
127             self.geni_output = self.raw_data.get("output","")
128
129             if self.save_filename:
130                 value = self.raw_data.get("value", None)
131                 if value == None:
132                     if os.path.exists(self.save_filename):
133                         os.remove(self.save_filename)
134                 elif type(value) == str:
135                     open(self.save_filename, "w").write(value)
136                 elif hasattr(json, "dumps"):
137                     open(self.save_filename, "w").write(json.dumps(value))  # python 2.6
138                 else:
139                     open(self.save_filename, "w").write(json.write(value))  # python 2.5
140
141         # extract any faults from the XMLRPC response(s)
142         self.xmlrpcreader.responses = []
143         self.xmlrpcreader.store(self.output)
144         self.xmlrpcreader.extractXml()
145         self.responses = self.xmlrpcreader.responses
146         self.faults = [x for x in self.responses if (x["kind"]=="fault")]
147
148         # if we got a nonzero
149         if (self.geni_code!=None) and (self.geni_code!=0):
150             x = {"kind": "bad_geni_code"}
151             x["faultCode"] = str(self.geni_code)
152             faultString = "Nonzero geni_code: " + str(self.geni_code)
153             if self.geni_output:
154                 faultString = faultString + " output: " + str(self.geni_output)
155             x["faultString"] = faultString
156             self.faults.append(x)
157
158         self.trace_end()
159         self.emit(SIGNAL("finished()"))
160
161     def getFaultString(self):
162         if self.faults == []:
163             return None
164
165         return self.faults[0].get("faultString","") + " (" + self.faults[0].get("faultCode","") + ")"
166
167     def retrieveRspec(self):
168         slice = config.getSlice()
169         mgr = config.getSlicemgr()
170         # Write RSpec to file
171         filename = config.fullpath ("%s.rspec"%slice)
172         try:
173             os.remove(filename)
174         except:
175             pass
176         args = ["-u", config.getUser(), "-a", config.getAuthority(), 
177                 "-r", config.getRegistry(), "-s", mgr, "resources", 
178                 "-o", filename, slice]
179
180         self.__init_command(args)
181         self.start()
182         return filename
183
184     def retrieveResources(self):
185         mgr = config.getSlicemgr()
186         # Write RSpec to file
187         filename = config.getResourcesRSpecFile()
188         try:
189             os.remove(filename)
190         except:
191             pass
192         args = ["-u", config.getUser(), "-a", config.getAuthority(),
193                 "-r", config.getRegistry(), "-s", mgr, "resources",
194                 "-o", filename]
195
196         self.__init_command(args)
197         self.start()
198         return filename
199
200
201     def listRecords(self, hrn, rectype=None, filename=None):
202         args = ["-u", config.getUser(), "-a", config.getAuthority(),
203                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "list", "-F", "xmllist", hrn]
204
205         if not filename:
206             filename = config.getAuthorityListFile()
207
208         # we can't tell whether SFI will create one file or many, so delete
209         # leftovers from last time, then we'll know what we got, after we get it.
210         if os.path.exists(filename):
211             os.remove(filename)
212         if os.path.exists(filename + ".1"):
213             os.remove(filename + ".1")
214         args.append("-o")
215         args.append(filename)
216
217         if rectype:
218             args.append("-t")
219             args.append(rectype)
220
221         self.__init_command(args)
222         self.start()
223
224     def getRecord(self, hrn, filename=None):
225         args = ["-u", config.getUser(), "-a", config.getAuthority(),
226                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "show", hrn]
227         if filename:
228             args.append("-o")
229             args.append(filename)
230         self.__init_command(args)
231         self.start()
232
233     def getSliceRecord(self):
234         self.getRecord(config.getSlice(), config.getSliceRecordFile())
235
236     def getAuthorityRecord(self):
237         self.getRecord(config.getAuthority(), config.getAuthorityRecordFile())
238
239     def applyRSpec(self, rspec, aggAddr=None, aggPort=None, saveObtained=True):
240         # that's what we pass, like in what we'd like to get
241         requested = config.getSliceRSpecFile() + "_new"
242         # that's what we actually receive
243         # just overwrite the slice file as if we'd used 'resources'
244         obtained = config.getSliceRSpecFile()
245         rspec.save(requested)
246         args = ["-u", config.getUser(), "-a", config.getAuthority(),
247                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "create"]
248
249         if saveObtained:
250             args = args + ["-o", obtained]
251
252         if aggAddr:
253             args = args + ["-a", aggAddr, "-p", str(aggPort)]
254
255         args = args + [config.getSlice(), requested]
256
257         self.__init_command(args)
258         self.start()
259
260     def deleteSlivers(self, slice=None, aggAddr=None, aggPort=None):
261         if not slice:
262             slice = config.getSlice()
263
264         args = ["-u", config.getUser(), "-a", config.getAuthority(),
265                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "delete"]
266
267         if aggAddr:
268             args = args + ["-a", aggAddr, "-p", str(aggPort)]
269
270         args = args + [slice]
271
272         self.__init_command(args)
273         self.start()
274
275     def updateRecord(self, filename):
276         args = ["-u", config.getUser(), "-a", config.getAuthority(),
277                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "update", filename]
278         self.__init_command(args)
279         self.start()
280
281     def addRecord(self, filename):
282         args = ["-u", config.getUser(), "-a", config.getAuthority(),
283                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "add", filename]
284         self.__init_command(args)
285         self.start()
286
287     def removeRecord(self, hrn):
288         args = ["-u", config.getUser(), "-a", config.getAuthority(),
289                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "remove", hrn]
290         self.__init_command(args)
291         self.start()
292
293     def renewSlivers(self, expiration, slice=None):
294         if not slice:
295             slice = config.getSlice()
296
297         args = ["-u", config.getUser(), "-a", config.getAuthority(),
298                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "renew",
299                 slice, expiration]
300         self.__init_command(args)
301         self.start()
302
303     def sliverStatus(self, slice=None, filename=None):
304         if not slice:
305             slice = config.getSlice()
306
307         if not filename:
308             filename = config.fullpath(slice+".sliverstatus")
309
310         args = ["-u", config.getUser(), "-a", config.getAuthority(),
311                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "status",
312                 slice]
313         self.__init_command(args, save_filename = filename)
314         self.start()
315
316     def getSliceMgrVersion(self, filename=None):
317         if not filename:
318             filename = config.fullpath("slicemgr.version")
319
320         args = ["-u", config.getUser(), "-a", config.getAuthority(),
321                 "-r", config.getRegistry(), "-s", config.getSlicemgr(), "version",
322                 "-o", filename, "-F", "pickled",]
323         self.__init_command(args)
324         self.start()
325
326     def start(self):
327         self.respones = []
328         self.faults = []
329         self.output = ""
330         self.trace_command()
331         self.process.start(self.exe, self.args)
332
333     def readOutput(self):
334         if self.process.state() == QProcess.NotRunning:
335             return self.process.readAll()
336
337     def trace_command (self):
338         if config.verbose:
339             self._trace=time.time()
340             command = "%s %s" % (self.exe, self.args.join(" "))
341             print time.strftime('%H:%M:%S'),'Invoking',command
342
343     def trace_end (self):
344         if config.verbose:
345 #            command = "%s %s" % (self.exe, self.args.join(" "))
346             print time.strftime('%H:%M:%S'),"Done [%.3f s]"%(time.time()-self._trace)
347         if config.debug:
348             get_tracker().getAndPrint(self.output)
349