import repository from arizona
[raven.git] / apps / gui1 / storkcurlfuncs.py
1 #!/usr/bin/python
2
3
4 # provides curl functions for the gui to use
5 import os
6 import sys
7 import tempfile
8 import shutil
9 import urllib
10 import re
11
12 rep = "https://stork-repository.cs.arizona.edu:8081/"
13
14 scversion = "$Revision: 1.31 $"
15
16 storksite = "http://www.cs.arizona.edu/stork/"
17
18
19 #trys to log the user in
20 #   returns:
21 #     true on succussful login
22 #     false on failure
23 def login( username, password,site ):
24
25    if site == "www.planet-lab.org":
26       authtype = "PLauthenticate"
27    elif site == "www.planet-lab.eu":
28       authtype = "PLEauthenticate"
29    elif site == "local":
30       authtype = "passfileauthenticate"
31    else:
32       raise ValueError, "Unrecognized site: "+site
33
34
35    # the curl command to login
36    command = "/usr/bin/curl -L -k -d \"%USERINFO%\" -D GetCookie https://stork-repository.cs.arizona.edu:8081/stork/login.php?"
37
38    # build the user info string
39    info = "username="+urllib.quote(username)+"&password="+urllib.quote(password)+"&authmethod="+urllib.quote(authtype)
40    command  = command.replace( "%USERINFO%", info )
41
42    #DEBUG -remove when we go live
43    #command  = command.replace("https://stork-repository.cs.arizona.edu", "http://jplichta.ipupdater.com:8080")
44
45    # try to run the command and see what we get
46    (sin, sout, serr) = os.popen3( command )
47
48    outstring = sout.read()
49    errstring = serr.read()
50
51    sout.close()
52    serr.close()
53
54    print "XXXXX:",outstring
55    if "incorrect username" not in outstring:
56       return True
57
58    else:
59       return False
60
61 # call the autosetup for the user with the specified set of nodes
62 # (this will add the nodes to the slice and will set the initscript to stork
63 def autoSetup( username, password, slice, nodes,site ):
64    if site == "www.planet-lab.org":
65       authtype = "PLauthenticate"
66    elif site == "www.planet-lab.eu":
67       authtype = "PLEauthenticate"
68    elif site == "local":
69       authtype = "passfileauthenticate"
70    else:
71       raise ValueError, "Unrecognized site: "+site
72
73
74    command = "/usr/bin/curl -L -k -d \"username="+urllib.quote(username)+"&password="+urllib.quote(password)+"&slice="+urllib.quote(slice)+"&authmethod="+urllib.quote(authtype)+"&nodes="+urllib.quote_plus(" ".join(nodes))+"\""
75    command = command + " https://stork-repository.cs.arizona.edu:8081/stork/autosetup.php"
76
77    #print "DEBUG: about to run", command
78
79    (sin,sout,serr) = os.popen3(command)
80    #out = sout.read()
81
82
83
84 # gets the slices for the user
85 # this will automatically call the login functino
86 # and will return None if it cannot login
87
88 # if it can login it will return a list of slices 
89 # that the user has access to
90 def getslices( username, password,site ):
91
92    if not login(username, password,site):
93       return None
94
95
96    command = "/usr/bin/curl -L -k -b GetCookie https://stork-repository.cs.arizona.edu:8081/stork/gui_getslices.php"
97  
98    #DEBUG -remove when we go live
99    #command  = command.replace("https://stork-repository.cs.arizona.edu", "http://jplichta.ipupdater.com:8080")
100
101    print "DEBUG: about to run: "+command
102
103    (sin, sout, serr) = os.popen3( command )
104
105    outstring = sout.read()
106    errstring = serr.read()
107
108    sout.close()
109    serr.close()
110
111    #print "DEBUG: "+outstring
112    #print "ERROR: "+errstring
113
114    return outstring.rstrip().rstrip("\n").split("\n") 
115
116
117
118 # upload a file to the repository.
119 #  the type of file being uploaded must be specified
120 #  in the type param and must be one of:
121 #     package
122 #     tp
123 #     pacman
124 #     pk 
125 #     conf
126 def upload_file(username, password, file, type, slice,site):
127    print  "upload_file initiated for file: "+file
128
129    ok_types = ["package","tp","pacman","pk","conf"]
130    if type not in ok_types:
131       print type+" not in "+str(ok_types)+" , skipping"
132       return None
133
134    if not login(username,password,site):
135       print "ERROR: Not logged in and unable to login. Aborting file upload."
136       return None
137
138    if not os.path.isfile(file):
139       print "WARNING: ",file," is not a file, skipping."
140       return None
141
142    command = "/usr/bin/curl -L -k -b GetCookie %SLICE% -F \"type=%TYPE%\" -F \"numfiles=1\" -F \"uploadbutton=Upload File\" -F \"file_0=@%FILE%\" https://stork-repository.cs.arizona.edu:8081/stork/upload_handler.php"
143    command = command.replace("%FILE%", file).replace("%TYPE%", type)
144
145    if type in ["pk", "conf"]  and slice!=None:
146       command = command.replace("%SLICE%", "-F \"slice="+slice+"\"")
147    else:
148       command = command.replace("%SLICE%", "")
149    
150
151    #DEBUG -remove when we go live
152    #command  = command.replace("https://stork-repository.cs.arizona.edu", "http://jplichta.ipupdater.com:8080")
153
154    print "DEBUG: about to run: "+command
155
156    (sin, sout, serr) = os.popen3( command )
157
158    outstring = sout.read()
159    errstring = serr.read()
160
161    #print outstring
162
163
164
165 def get_file(relative_path,outputfile):
166    tmptuple = tempfile.mkstemp("curldownload")
167    tmp      = tmptuple[1]
168    try:
169       tmptuple[0].close()
170    except:
171       pass
172
173    command = "/usr/bin/curl -L -w '%{http_code}' -k -o "+tmp+" "+rep
174    if not command.endswith("/"):
175       command = command + "/"
176    command = command + relative_path
177  
178    print "DEBUG: about to run: ",command
179
180    (sin, sout, serr) = os.popen3( command )
181
182    outline = sout.read()
183    sout.close()
184    serr.close()
185
186    if outline == "" or outline != "200":
187       try:
188          os.unlink(tmp)
189       except:
190          pass
191       return False
192    else:
193       try:
194          shutil.move(tmp, outputfile)
195       except:
196          pass
197       return True
198
199 def url_exists(relative_path):
200    command = "/usr/bin/curl -L -w '%{http_code}' -k --head "+rep+"/"+relative_path
201  
202    print "DEBUG: about to run: ",command
203
204    (sin, sout, serr) = os.popen3( command )
205
206    outline = sout.read()
207    sout.close()
208    serr.close()
209
210    if outline == "" or outline != "200":
211       return False
212    else:
213       return True
214
215
216
217
218 def is_latest_version(version_string):
219    """
220       Returns a tuple (Boolean,String, String). The first part of the tuple
221       is true if this version of the gui is the latest one as reported
222       by the website, the second part of the tuple will always be None if
223       the first part is True, if the first part is False it will be a string
224       indicating the most recent version from the repository. The third part
225       of the tuple will be a string, either storkslicemanager or storkcurlfuncs
226       to indicate which file is out of date. If both are out of date, only
227       storkslicemanager will be indicated.
228    """
229    version = "gui-version"
230    command = "/usr/bin/curl -L -w '%{http_code}' -k -o "+version+" "+storksite+"gui-version"
231    print "DEBUG: about to run: ",command
232
233    (sin, sout, serr) = os.popen3( command )
234    outline = sout.read()
235    sout.close()
236    serr.close()
237
238    if outline == "" or outline != "200":
239       # version page did not exist, or could not connect
240       return (False, "unknown", "unknown")
241    else:
242       # try to open the downloaded version page to check the version number
243       try:
244          f = open(version, "r")
245          # Id cvs tag of storkslicemanager should be on first line
246          line1 = f.readline().rstrip("\n").rstrip(" ")
247          line2 = f.readline().rstrip("\n").rstrip(" ")
248
249          f.close()
250  
251          if line1 == version_string and line2 == scversion:
252             return (True, None, None)
253          elif line1 == version_string and line2 != scversion:
254             return (False, line2, "storkcurlfuncs")
255          elif line1 != version_string and line2 == scversion:
256             return (False, line1, "storkslicemanager")
257          else:
258             return (False, line1, "storkslicemanager")
259
260       except IOError, OSError:
261          return (False, "unknown", "unknown")          
262  
263 def update_gui(put_files_here):
264    command1 = "/usr/bin/curl -L -o "+os.path.join(put_files_here,"storkslicemanager.py")+" "+storksite+"gui/storkslicemanager.py"
265    command2 = "/usr/bin/curl -L -o "+os.path.join(put_files_here,"storkcurlfuncs.py")+" "+storksite+"gui/storkcurlfuncs.py"
266
267
268    (sin, sout, serr) = os.popen3( command1 )
269    (sin, sout, serr) = os.popen3( command2 )
270    #SHUTDOWN THE GUI
271    # TODO: open it back up for the user again
272    sys.exit(0)
273    
274
275
276
277
278 def fetch_configuration(slicename, defaultconf=False):
279    if defaultconf:
280        confurl = "http://www.cs.arizona.edu/stork/downloads/sample-stork.conf"
281    else:
282        confurl = rep+"user-upload/conf/"+slicename+".stork.conf"
283        
284    destinationfile = slicename+".stork.conf"
285    command = "/usr/bin/curl -L -w '%{http_code}' -k -o "+destinationfile+" "+confurl
286  
287    print "DEBUG: about to run: ",command
288
289    (sin, sout, serr) = os.popen3( command )
290    outline = sout.read()
291    sout.close()
292    serr.close()
293
294    if outline == "" or outline != "200":
295       os.remove(destinationfile)
296       return False
297    else:
298       return True
299
300
301
302 def clean_configuration(conffile):
303    """
304    Perform mandatory cleaning of the configuration file for proper
305    functionality.
306    
307    """
308    writerequired = False
309    # read the file in
310    lines = []
311    try:
312       conf = open(conffile, "r")
313    except:
314       return False
315       
316    readlines = conf.readlines()
317    conf.close()
318    for line in readlines:
319       origline = line.rstrip("\n")
320       pair = read_config_line(line)
321       if not pair:
322           lines.append(origline)
323       else:
324           (directive, value) = pair
325           # comment out pacmanpackagefile
326           if directive == 'pacmanpackagefile':
327              lines.append("#pacmanpackagefile = "+value)
328              writerequired = True
329           # comment out pacmangroupfile
330           elif directive == 'pacmangroupfile':
331              lines.append("#pacmangroupfile = "+value)
332              writerequired = True
333           else:
334              lines.append(origline)
335                         
336    # now write file file back, if necessary
337    if writerequired:
338       try:
339          conf = open(conffile, "w")
340       except:
341          return False
342       for line in lines:
343          conf.write(line+"\n")
344
345    conf.close()
346    return True
347   
348   
349
350 def alter_configuration(conffile, username, publickey, ignoreconflicts=False):
351    if not os.path.isfile(conffile): return False
352
353    # read the file in
354    lines = []
355    try:
356       conf = open(conffile, "r")
357    except:
358       return False
359       
360    readlines = conf.readlines()
361    conf.close()
362    for line in readlines:
363       origline = line.rstrip("\n")
364       pair = read_config_line(line)
365       if not pair:
366           lines.append(origline)
367       else:
368           (directive, value) = pair
369           if directive == 'username':
370              curuser = value
371              if curuser != username and not ignoreconflicts:
372                 return False
373              else:
374                 lines.append("username = "+username)
375           elif directive == "publickeyfile":
376               pass # do nothing
377 # SMBAKER: gui-generated config files do not need a publickeyfile, so let's
378 # strip it out.
379 #
380 #             curkey = os.path.basename(value)
381 #             if curkey != publickey and not ignoreconflicts:
382 #                return False
383 #             else:
384 #                lines.append("publickeyfile = /usr/local/stork/var/keys/"+publickey)
385           else:
386                lines.append(origline)
387                         
388    #TODO detect if username or publickeyfile were completely missing and add
389    # them in if the were.
390                         
391    # now write file file back
392    try:
393       conf = open(conffile, "w")
394    except:
395       return False
396
397    for line in lines:
398       conf.write(line+"\n")
399
400    conf.close()
401    return True
402          
403          
404
405 # returns a tuple (username, pubkey)
406 def parse_config(conffile):
407    try:
408       conf = open(conffile, "r")
409    except:
410       return (None, None)
411
412    username = None
413    keyfile  = None
414
415    lines = conf.readlines()
416    for line in lines:
417       pair = read_config_line(line)
418       if pair:
419           (directive, value) = pair
420           if directive == 'username':
421              username = value
422           elif directive == "publickeyfile":
423              keyfile = os.path.basename(value)  
424
425    conf.close()
426    return (username, keyfile)
427
428
429
430 configlineregex = re.compile(r"(\S+)\s*=\s*(\S+)")
431
432 def read_config_line(line):
433    """Extract the directive and value from a config file line."""    
434    global configlineregex
435    line = line[:line.find("#")]
436    matches = configlineregex.match(line.strip())
437    if matches:
438        return matches.groups()
439    else:
440        return None