source: lliurex-mirror/trunk/fuentes/n4d-lliurex-mirror.install/usr/share/n4d/python-plugins/MirrorManager.py @ 2588

Last change on this file since 2588 was 2588, checked in by kbut, 3 years ago

write log

File size: 20.3 KB
Line 
1from jinja2 import Environment
2from jinja2.loaders import FileSystemLoader
3from jinja2 import Template
4
5import tempfile
6
7import os
8import threading
9import datetime
10import pexpect
11import re
12import json
13
14import BaseHTTPServer
15from SimpleHTTPServer import SimpleHTTPRequestHandler
16from multiprocessing import Process
17import socket
18from urllib2 import urlopen
19import string
20
21class MirrorManager:
22
23
24        def __init__(self):
25                #Default values
26                self.defaultpath = '/etc/lliurex-mirror/'
27                self.debmirrorconfpath = os.path.join(self.defaultpath,'debmirror')
28                self.configpath = os.path.join(self.defaultpath,'conf')
29                self.distro="llx16"
30                self.httpd = {}
31                self.debmirrorprocess = None
32
33                self.tpl_env = Environment(loader=FileSystemLoader('/usr/share/n4d/templates/lliurex-mirror'))
34                self.update_thread=threading.Thread()
35                self.get_mirror_thread = threading.Thread()
36                self.percentage=(0,None)
37                self.exportpercentage = 0
38                self.mirrorworking = None
39                self.webserverprocess = {}
40                self.defaultmirrorinfo = {"status_mirror":"New","last_mirror_date":None,"mirror_size":0,"progress":0}
41                self.valid_chars = "-_.%s%s" % (string.ascii_letters, string.digits)
42                self.default_mirror_config = '''
43{
44        "NAME": "",
45        "BANNER": "",
46        "ORIGS" : {"1":"lliruex.net/xenial","2":"","3":""},
47        "ARCHITECTURES": [ "amd64", "i386"],
48        "SECTIONS": ["main", "main/debian-installer", "universe", "restricted", "multiverse", "partner"],
49        "MIRROR_PATH": "/net/mirror/llx16",
50        "DISTROS": ["xenial","xenial-updates","xenial-security"],
51        "IGN_GPG":1,
52        "IGN_RELEASE":0,
53        "CHK_MD5":0,
54        "CURRENT_UPDATE_OPTION":"1"
55}'''
56               
57        #def init
58       
59        def startup(self,options):
60                self.n4d_vars=objects["VariablesManager"]
61                self.variable=objects["VariablesManager"].get_variable("LLIUREXMIRROR")
62               
63               
64                if self.variable==None:
65                        try:
66                                self.n4d_vars.add_variable("LLIUREXMIRROR",{},"","Lliurex Mirror info variable","n4d-lliurex-mirror")
67                        except Exception as e:
68                                pass
69                       
70                if type(self.variable)!=type({}):
71                        self.variable={}
72               
73                try:
74                        for repo in self.get_available_mirrors()['msg']:
75                                if self.variable.has_key(repo) and self.variable[repo].has_key("status_mirror") and self.variable[repo]["status_mirror"] == "Working":
76                                        if not self.update_thread.isAlive():
77                                                self.variable[repo]["status_mirror"] = "Error"
78                                                self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
79                                else:
80                                        if not self.variable.has_key(repo):
81                                                self.variable[repo] = self.defaultmirrorinfo
82                except Exception as e:
83                        pass
84        #def startup
85
86        def apt(self):
87                # executed after apt operations
88                pass
89               
90        #def apt
91       
92        # service test and backup functions #
93       
94        def test(self):
95
96                pass
97               
98        #def test
99       
100        def backup(self):
101
102                pass
103               
104        #def backup
105
106        def restore(self):
107                pass
108        #def restore
109
110        def set_cname(self):
111                #Get template
112                template = self.tpl_env.get_template("cname")
113                list_variables = {}
114               
115                list_variables = self.n4d_vars.get_variable_list(['INTERNAL_DOMAIN','HOSTNAME'])
116                for x in list_variables.keys():
117                        if list_variables[x] == None:
118                                return {'status':False,'msg':'Variable ' + x + ' not defined'}
119                       
120                #Encode vars to UTF-8
121                string_template = template.render(list_variables).encode('UTF-8')
122                #Open template file
123                fd, tmpfilepath = tempfile.mkstemp()
124                new_export_file = open(tmpfilepath,'w')
125                new_export_file.write(string_template)
126                new_export_file.close()
127                os.close(fd)
128                #Write template values
129                n4d_mv(tmpfilepath,'/var/lib/dnsmasq/config/cname-mirror',True,'root','root','0644',False )
130               
131                return {'status':True,'msg':'Set mirror cname'}
132        #def set_cname
133       
134        def update(self,ip,distro=None,callback_args=None):
135
136                if distro==None:
137                        distro=self.distro
138       
139                if self.update_thread.is_alive():
140                        return {'status':False,'msg':'Lliurex-mirror (n4d instance) is running'}
141               
142                self.percentage=(0,None)
143                self.update_thread=threading.Thread(target=self._update,args=(ip,distro,callback_args,))
144                self.update_thread.daemon=True
145                self.update_thread.start()
146               
147                return {'status':True,'msg':'running'}
148
149        #def update
150       
151        def _update(self,ip,distro,callback_args):
152                if not self.variable.has_key(distro):
153                        self.variable[distro]=self.defaultmirrorinfo
154                # link config debmirror to correct path with distro name
155                self.variable[distro]['status_mirror'] = "Working"
156                self.variable[distro]['progress'] = 0
157                self.variable[distro]['exception_msg'] = ""
158                self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
159                self.build_debmirror_config(distro)
160                if os.path.lexists('/etc/debmirror.conf'):
161                        os.remove('/etc/debmirror.conf')
162                os.symlink(os.path.join(self.debmirrorconfpath,distro),'/etc/debmirror.conf')
163                self.mirrorworking = distro
164                fd = open('/var/log/lliurex-mirror.log','a')
165                import datetime
166                fd.write("************************* " + str(datetime.datetime.now())+ " ***********************************\n")
167                errors_found = False   
168                self.debmirrorprocess=pexpect.spawn("/usr/bin/debmirror")
169                try:
170                        objects["ZCenterVariables"].add_pulsating_color("lliurexmirror")
171                except:
172                        pass
173                while True:
174                        try:
175                                self.debmirrorprocess.expect('\n',timeout=480)
176                                line =self.debmirrorprocess.before
177
178                                line1=line.strip("\n")
179                                fd.write(line)
180                                if line1.startswith("[") and line1[5] == "]":
181                                        self.percentage=(int(line1[1:4].strip()),self.debmirrorprocess.exitstatus)
182                                        self.variable[distro]['progress'] = self.percentage[0]
183                                        self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
184                                if line1.startswith("Everything OK"):
185                                        self.percentage=(100,self.debmirrorprocess.exitstatus)
186                                        self.variable[distro]['progress'] = 100
187                                        self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
188                               
189                                if errors_found:
190                                        e=Exception(line1)
191                                        raise e
192                                if line1.startswith("Errors"):
193                                        errors_found = True
194       
195
196                        except pexpect.EOF:
197                                        line1 = self.debmirrorprocess.before
198                                        if line1 != "" and line1.startswith("[") and line1[5] == "]":
199                                                        self.percentage=(int(line1[1:4].strip()),self.debmirrorprocess.exitstatus)
200                                        self.debmirrorprocess.close()
201                                        status = self.debmirrorprocess.exitstatus
202                                        self.percentage=(self.percentage[0],status)
203                                        self.variable[distro]['progress'] = self.percentage[0]
204                                        self.variable[distro]['status_mirror'] = "Ok" if status == 0 else "Error"
205                                        self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
206                                        break
207                        except Exception as e:
208                                print e
209                                self.variable[distro]['status_mirror'] = "Error"
210                                self.variable[distro]["exception_msg"] = str(e)
211                                status = self.debmirrorprocess.exitstatus
212                                self.percentage=(self.percentage[0],str(e))
213                                self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
214                                break
215                fd.close()
216                if type(callback_args) != type(None):
217                        if callback_args.has_key('port'):
218                                import xmlrpclib as x
219                                c = x.ServerProxy('https://' + ip + ':9779')
220                                c.stop_webserver('','MirrorManager',callback_args['port'])
221
222                self.download_time_file(distro)
223                self.set_mirror_info(distro)
224                self.mirrorworking = None
225                try:
226                        objects["ZCenterVariables"].remove_pulsating_color("lliurexmirror")
227                except:
228                        pass
229
230        #def _update
231       
232        def is_alive(self):
233
234                return {'status':self.update_thread.is_alive(),'msg':self.mirrorworking}
235        #def is_alive
236
237        def set_mirror_info(self,distro=None):
238               
239                if distro!=None:
240                        distro=distro
241                else:
242                        distro=self.distro
243               
244                configpath = os.path.join(self.configpath, distro + ".json")
245                config = json.load(open(configpath,'r'))
246
247                mirrorpath = config["MIRROR_PATH"]
248                #self.n4d_vars.set_variable("ZEROCENTERINTERNAL",self.internal_variable)
249               
250                MIRROR_DATE=datetime.date.today().strftime("%d/%m/%Y")
251                MIRROR_SIZE=self.get_size(mirrorpath)
252               
253                self.variable[distro]["last_mirror_date"]=MIRROR_DATE
254                self.variable[distro]["mirror_size"]=str(MIRROR_SIZE)
255                self.variable[distro]["progress"]=self.percentage[0]
256               
257                self.n4d_vars.set_variable("LLIUREXMIRROR",self.variable)
258               
259                #set_custom_text(self,app,text):
260                txt="Updated on: " + str(MIRROR_DATE)
261                txt+=" # Size: %.2fGB"%MIRROR_SIZE
262                try:
263                        objects["ZCenterVariables"].set_custom_text("lliurexmirror",txt)
264                        abstract=open('/var/log/lliurex/lliurex-mirror.log','w')
265                        abstract.write(txt+"\n")
266                        abstract.close()
267                except Exception as e:
268                        pass
269
270        #def set_mirror_info(self):
271
272        def get_size(self,start_path = '.'):
273       
274                total_size = 0
275                try:
276                        for dirpath, dirnames, filenames in os.walk(start_path):
277                                for f in filenames:
278                                        fp = os.path.join(dirpath, f)
279                                        total_size += os.path.getsize(fp)
280                                       
281                        total_size/=1024*1024*1024.0
282                        return total_size
283                except:
284                        return 0
285       
286        #def get_size(start_path = '.'):
287       
288        def search_field(self,filepath,fieldname):
289                try:
290                        f = open(filepath,'r')
291                        needle = None
292                        lines = f.readlines()
293                        for x in lines:
294                                        if re.match('\s*'+fieldname,x):
295                                                        needle = x.strip()
296                        return needle
297                except:
298                        return None
299        # def search_field
300       
301        def get_mirror_architecture(self,distro):
302
303                configpath = os.path.join(self.configpath,distro + ".json")
304                config = json.load(open(configpath,'r'))
305                if not os.path.lexists(configpath):
306                        return {'status':False,'msg':'not exists debmirror.conf to '+ distro }
307
308                if "ARCHITECTURES" in config.keys():
309                        return {'status':True,'msg':config["ARCHITECTURES"] }
310
311                return {'status':False,'msg':"debmirror.conf hasn't architecture variable" }
312        #def get_mirror_architecture
313       
314        def set_mirror_architecture(self,distro,archs):
315                configpath = os.path.join(self.configpath,distro + ".json")
316               
317                config = json.load(open(configpath,'r'))
318               
319                config['ARCHITECTURES'] = archs
320
321
322                f=open(configpath,"w")
323
324                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
325                f.write(data)
326                f.close()
327
328                self.build_debmirror_config(distro)
329                return {'status':True,'msg':'set architecture'}
330               
331        #def set_mirror_architecture
332       
333        def get_mirror_orig(self,distro,option):
334
335                configpath = os.path.join(self.configpath,distro + ".json")
336                config = json.load(open(configpath,'r'))
337                if not os.path.lexists(configpath):
338                        return {'status':False,'msg':'not exists debmirror.conf to '+ distro }
339
340                if "ORIGS" in config.keys():
341                        return {'status':True,'msg':config["ORIGS"][option] }
342                       
343                return {'status':False,'msg':"debmirror.conf hasn't orig variable" }   
344        #def get_mirror_from
345
346        def set_mirror_orig(self,distro,url,option):
347                if url == None:
348                        return {'status':False,'msg':'url is None'}
349                configpath = os.path.join(self.configpath, distro + ".json")
350                config = json.load(open(configpath,'r'))
351                config['ORIGS'][option] = url
352
353                f=open(configpath,"w")
354                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
355                f.write(data)
356                f.close()
357
358                self.build_debmirror_config(distro)
359                return {'status':True,'msg':'set orig'}
360        #def set_mirror_architecture
361
362        def get_option_update(self,distro):
363                configpath = os.path.join(self.configpath,distro + ".json")
364                config = json.load(open(configpath,'r'))
365                if not os.path.lexists(configpath):
366                        return {'status':False,'msg':'not exists debmirror.conf to '+ distro }
367
368                if "CURRENT_UPDATE_OPTION" in config.keys():
369                        return {'status':True,'msg':config["CURRENT_UPDATE_OPTION"] }
370                       
371                return {'status':False,'msg':"debmirror.conf hasn't option update variable" }
372        #def get_option_update
373
374        def set_option_update(self,distro,option):
375                configpath = os.path.join(self.configpath, distro + ".json")
376                config = json.load(open(configpath,'r'))
377                config['CURRENT_UPDATE_OPTION'] = str(option)
378
379                f=open(configpath,"w")
380                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
381                f.write(data)
382                f.close()
383
384                self.build_debmirror_config(distro)
385                return {'status':True,'msg':'set update option'}
386        #def set_option_update
387
388        def get_percentage(self,distro):
389                if self.variable.has_key(distro):
390                        return {'status':True,'msg':self.variable[distro]['progress']}
391                else:
392                        return {'status':False,'msg':'this repo nos has been configured'}
393        #def get_percentage
394
395
396        def build_debmirror_config(self,distro):
397                result = self.render_debmirror_config(distro)
398                string_template = result['msg']
399                f = open(os.path.join(self.debmirrorconfpath,distro),'w')
400                f.write(string_template)
401                f.close()
402        #def build_debmirror_config
403
404        def render_debmirror_config(self,arg):
405                if type(arg) == type(""):
406                        return self._render_debmirror_config_distro(arg)
407                if type(arg) == type({}):
408                        return self._render_debmirror_config_values(arg)
409        #def render_debmirror_config
410
411        def _render_debmirror_config_distro(self,distro):
412                template = self.tpl_env.get_template('debmirror.conf')
413                configpath = os.path.join(self.configpath,distro + ".json")
414                config = json.load(open(configpath,'r'))
415                return {'status':True,'msg':template.render(config).encode('utf-8')}
416        #def render_debmirror_config
417
418        def _render_debmirror_config_values(self,config):
419                template = self.tpl_env.get_template('debmirror.conf')
420                return {'status':True,'msg':template.render(config).encode('utf-8')}
421        #def _render_debmirror_config_values
422
423        def enable_webserver_into_folder(self,path):
424               
425                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
426                s.bind(('localhost', 0))
427                addr, port = s.getsockname()
428                s.close()
429                self.webserverprocess[str(port)] = Process(target=self._enable_webserver_into_folder,args=(port,path,))
430                self.webserverprocess[str(port)].start()
431                return {'status':True,'msg':port}
432        #enable_webserver_into_folder
433
434        def _enable_webserver_into_folder(self,port,path):
435                try:
436                        iface = '127.0.0.1'
437                        sock = (iface,port)
438                        proto = "HTTP/1.0"
439                        os.chdir(path)
440                        handler = SimpleHTTPRequestHandler
441                        handler.protocol_version = proto
442                        self.httpd[str(port)] = BaseHTTPServer.HTTPServer(sock,handler)
443                        self.httpd[str(port)].serve_forever()
444                except Exception, e:
445                        return None
446        #_enable_webserver_into_folder
447
448        def stop_webserver(self,port):
449                if self.webserverprocess.has_key(port):
450                        self.webserverprocess[port].terminate()
451                        self.webserverprocess.pop(port)
452                        return {'status':True,'msg':'Server stopped'}
453                return {'status':False,'msg':'Server not exists'}
454        #stop_webserver
455       
456        def set_checksum_validation(self,distro,status):
457                configpath = os.path.join(self.configpath, distro + ".json")
458                config = json.load(open(configpath,'r'))
459                config['CHK_MD5'] = status
460
461                f=open(configpath,"w")
462                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
463                f.write(data)
464                f.close()
465
466                self.build_debmirror_config(distro)
467                return {'status':True,'msg':'set checksum validation'}
468        #set_checksum_validation
469       
470        def get_checksum_validation(self,distro):
471
472                configpath = os.path.join(self.configpath,distro + ".json")
473                config = json.load(open(configpath,'r'))
474                if not os.path.lexists(configpath):
475                        return {'status':False,'msg':'not exists debmirror.conf to '+ distro }
476                if "IGN_GPG" in config.keys():
477                        return {'status':True,'msg':config["CHK_MD5"] }
478
479                return {'status':False,'msg':"debmirror.conf hasn't orig variable" }
480        #get_checksum_validation
481       
482        def get_available_mirrors(self):
483                versions = os.listdir(self.configpath)
484                versions = [ version.replace('.json','') for version in versions if version.endswith('.json')]
485                return {'status':True,'msg':versions}
486
487        def stopupdate(self):
488                try:
489                        self.debmirrorprocess.terminate()
490                        return {'status':True,'msg':'debmirror stopped'}
491                except Exception as e:
492                        return {'status':False,'msg':str(e)}
493
494        def stopgetmirror(self):
495                try:
496                        self.get_mirror_process.terminate()
497                        return {'status':True,'msg':'debmirror stopped'}
498                except Exception as e:
499                        return {'status':False,'msg':str(e)}
500
501        def download_time_file(self,distro):
502               
503                configpath = os.path.join(self.configpath,distro + ".json")
504                config = json.load(open(configpath,'r'))
505                path=config["MIRROR_PATH"]
506                f="time-of-last-update"
507                dest=os.path.join(path,f)
508
509                orig_mirror=self.get_mirror_orig(distro,"1")
510                url_mirror="http://"+os.path.join(orig_mirror['msg'],f)
511
512                return self.get_time_file(url_mirror,dest)
513
514        # # def download_time_file                     
515
516               
517        def get_time_file(self,url,dest):
518               
519                try:
520                        r=urlopen(url)
521                        f=open(dest,"wb")
522                        f.write(r.read())
523                        f.close()
524                        r.close()
525                        return {'status':True,'msg':dest + 'successfully downloaded.'}
526               
527                except Exception as e:
528                        return {'status':False,'msg':'Error downloading' + dest + ':' + str(e)}                 
529
530        # def get_time_file             
531
532        def is_update_available(self,distro):
533
534                configpath = os.path.join(self.configpath,distro + ".json")
535                config = json.load(open(configpath,'r'))
536                path = config["MIRROR_PATH"]
537                file_time_name = "time-of-last-update"
538                file_local_mirror = os.path.join(path,file_time_name)
539
540               
541                if os.path.isfile(file_local_mirror):
542                        url_pool = "http://"+os.path.join(config["ORIGS"]['1'],file_time_name)
543                        file_pool = os.path.join("/tmp",file_time_name)
544
545                        exist_file_pool = self.get_time_file(url_pool,file_pool)
546                        if exist_file_pool['status']:
547                                file_local_mirror_content=open(file_local_mirror,"r")
548                                file_local_miror_datetime=(file_local_mirror_content.readline().strip()).split("_")
549                                file_pool_content=open(file_pool,'r')
550                                file_pool_datetime=(file_pool_content.readline().strip()).split("_")
551                                file_local_mirror_content.close()
552                                file_pool_content.close()
553
554                                date_local_mirror=datetime.datetime.strptime(file_local_miror_datetime[0],"%Y/%m/%d")
555                                date_pool=datetime.datetime.strptime(file_pool_datetime[0],"%Y/%m/%d")
556
557                                if date_local_mirror==date_pool:
558                                        time_local_mirror=datetime.datetime.strptime(file_local_miror_datetime[1],"%H:%M")     
559                                        time_pool=datetime.datetime.strptime(file_pool_datetime[1],"%H:%M")
560
561                                        if time_local_mirror<time_pool:
562                                                return {'status':False,'msg':'Mirror not updated','action':'update'}
563                                        else:
564                                                return {'status':True,'msg':'Mirror is updated','action':'nothing'}
565
566                                elif date_local_mirror<date_pool:
567                                        return {'status':False,'msg':'Mirror not updated','action':'update'}
568                                else:
569                                        return {'status':True,'msg':'Mirror is updated','action':'nothing'}     
570                        else:
571                                return {'status':False,'msg':exist_file_pool['msg'],'action':'nothing'} 
572
573                else:
574                        return {'status':False,'msg':file_local_mirror + ' does not exist.','action':'nothing'}
575
576        # def is_update_available
577
578        def new_mirror_config(self,config):
579                name = config["NAME"].lower().strip()
580                name = ''.join(c for c in name if c in self.valid_chars)
581
582                # Checks
583                if name == "":
584                        return {'status':False,'msg':"Name can't void"}
585                while True:
586                        newconfigpath = os.path.join(self.configpath,name + '.json')
587                        if not os.path.lexists(newconfigpath):
588                                break
589                        name = name + "1"
590
591                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
592                f = open(newconfigpath,'w')
593                f.write(data)
594                f.close()
595                self.variable[name] = self.defaultmirrorinfo
596                return {'status':True,'msg':name}
597        #def new_mirror_config
598
599        def get_all_configs(self):
600                versions = os.listdir(self.configpath)
601                allconfigs = {}
602                for version in versions:
603                        configfile = os.path.join(self.configpath,version)
604                        f = open(configfile,'r')
605                        allconfigs[version.replace('.json','')] = json.load(f)
606                        f.close()
607                return {'status':True,'msg':allconfigs}
608        #def get_all_configs
609
610        def update_mirror_config(self,mirror,config):
611                configpath = os.path.join(self.configpath,mirror + ".json")
612
613                f=open(configpath,"w")
614
615                data=unicode(json.dumps(config,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
616                f.write(data)
617                f.close()
618
619                return {'status':True,'msg':'Updated config'}
620        #def update_mirror_config
621
622        def get_client_ip(self,ip):
623                return {'status':True,'msg':ip}
624        #def get_client_ip
625
626        def is_alive_get_mirror(self):
627                return {'status':self.get_mirror_thread.is_alive(),'msg':self.exportpercentage}
628        #def is_alive_get_mirror
629
630        def get_mirror(self,config_path,callback_args):
631                self.get_mirror_thread = threading.Thread(target=self._get_mirror,args=(config_path,callback_args,))
632                self.get_mirror_thread.daemon = True
633                self.get_mirror_thread.start()
634        #def get_mirror
635
636        def _get_mirror(self,config_path,callback_args):
637                self.get_mirror_process = pexpect.spawn("/usr/bin/debmirror --config-file="+config_path)
638                while True:
639                        try:
640                                self.get_mirror_process.expect('\n')
641                                line =self.get_mirror_process.before
642                                line1=line.strip("\n")
643                                if line1.startswith("[") and line1[5] == "]":
644                                        self.exportpercentage = (int(line1[1:4].strip()),self.get_mirror_process.exitstatus)
645                        except pexpect.EOF:
646                                        line1 = self.get_mirror_process.before
647                                        if line1 != "" and line1.startswith("[") and line1[5] == "]":
648                                                        self.exportpercentage=(int(line1[1:4].strip()),self.get_mirror_process.exitstatus)
649                                        self.get_mirror_process.close()
650                                        status = self.get_mirror_process.exitstatus
651                                        self.exportpercentage=(self.exportpercentage[0],status)
652                                        break
653                        except Exception as e:
654                                break
655                if callback_args.has_key('port') and callback_args.has_key('ip'):
656                        import xmlrpclib as x
657                        c = x.ServerProxy('https://' + callback_args['ip'] + ':9779')
658                        c.stop_webserver('','MirrorManager',callback_args['port'])
659        #def _get
Note: See TracBrowser for help on using the repository browser.