source: lmd/trunk/fuentes/lmd-server.install/usr/share/n4d/python-plugins/LmdServer.py @ 1894

Last change on this file since 1894 was 1894, checked in by joamuran, 5 years ago

fixed

File size: 31.9 KB
Line 
1import socket
2import subprocess
3import sys
4
5import threading
6import time
7import datetime
8
9import json
10
11import os
12import signal
13
14import shutil
15import tempfile
16
17import tarfile
18import apt_pkg
19
20import lliurex.net
21
22class LmdServer:
23        def __init__(self):
24
25                self.last_job_id=0;
26                self.joblist=[]
27                self.global_listeners = {}
28                self.thread_jobs = {}
29                # Threading Multicast process to all listeners
30                self.multicast_thread = threading.Thread()
31                self.logfolder = '/run/lmdserver'
32                self.ltsp_path = '/opt/ltsp'
33                self.locks = {}
34                # Clean log folder and create
35                if (os.path.exists(self.logfolder)):
36                        shutil.rmtree(self.logfolder)
37                os.mkdir(self.logfolder)
38               
39                pass
40        #def __init__
41       
42        def set_default_boot(self,imgid):
43                dbm = objects['LmdBootManager'].getDefaultBootImage()
44                if dbm['default_boot'] == "":
45                        objects['LmdBootManager'].setDefaultBootImage(imgid)
46
47
48        def check_chroot_exists(self, name):
49                '''
50                Check if exists chroot /opt/ltsp/name and /opt/ltsp/images/name.img
51                DATE: 03/04/2014
52                '''
53                path=os.path.join("/opt/ltsp",name)
54                imagepath=os.path.join("/opt/ltsp/images",name+".img")
55               
56                #print "cheking "+name
57                if(os.path.isdir(path)):
58                        #print "111"
59                        return {"status": True, "error": 'chroot_exists'}
60               
61                if (os.path.isfile(imagepath)):
62                        #print "22222"
63                        return {"status": True, "error": 'image_exists'}
64                return {"status": False}
65
66               
67        def create_imageWS(self, imgid, name, template, description='', bgimg=''):
68                try:
69                        # creates an image from an specified template
70               
71                        # Check if template exists
72                        path="/etc/ltsp/templates/"+template;
73                        if(os.path.isfile(path)):
74                                extraLliurexOpts="--accept-unsigned-packages --purge-chroot"
75                                # if template exists, create an image
76                                print "[LmdServer] Create_imageWS from "+path
77                                command="ltsp-build-client --config "+path+" "+extraLliurexOpts+" --chroot "+imgid+"&& service nbd-server restart";
78                               
79                                ret=objects['TaskMan'].newTask(command);
80                                                               
81                                if ret["status"]==True: ## Task has launched ok
82                                                               
83                                        metadata = {'id':imgid, 'name' : name,
84                                                        'desc' : description ,
85                                                        "template" : template,
86                                                        'img': bgimg,
87                                                        'taskid': ret["msg"],
88                                                        'ltsp_fatclient': 'undefined',
89                                                        'ldm_session': 'default',
90                                                        'fat_ram_threshold': 'default',
91                                                        'lmd_extra_params':'' }
92                                        metadata_string = unicode(json.dumps(metadata,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
93                                        objects['LmdImageManager'].setImage(imgid,metadata_string)
94                                        self.set_default_boot(imgid)
95
96                                        # Registering imgid for boot PXE MEnu
97                               
98                                        objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
99                               
100                                        return {"status": True, "msg": ret["msg"]}
101
102                                else:
103                                        if ret["msg"]=="SERVER_BUSY":
104                                                return {'status':False, 'msg':'SERVER_BUSY'}
105                                        else:
106                                                return {'status':False, 'msg':'EXCEPTION'}
107                               
108                        else:
109                                return {'status':False, 'msg':'TEMPLATE_NOT:EXISTS'}
110                       
111                        pass
112                except Exception as e:
113                        print "Except: "+str(e)
114                        return e
115       
116       
117       
118       
119        def create_image(self, ip, port, imgid, name, template, description='', bgimg='', srv_ip='127.0.0.1'):
120                try:
121                        # creates an image from an specified template
122               
123                        # Check if template exists
124                        path="/etc/ltsp/templates/"+template;
125                        if(os.path.isfile(path)):
126                                extraLliurexOpts="--accept-unsigned-packages --purge-chroot"
127                                # if template exists, create an image
128                                print "[LmdServer] Create_image from "+path
129                                command="ltsp-build-client --config "+path+" "+extraLliurexOpts+" --chroot "+imgid+"&& service nbd-server restart";
130                               
131                                metadata = {'id':imgid, 'name' : name,
132                                                        'desc' : description ,
133                                                        "template" : template,
134                                                        'img': bgimg,
135                                                        'ltsp_fatclient': 'undefined',
136                                                        'ldm_session': 'default',
137                                                        'fat_ram_threshold': 'default',
138                                                        'lmd_extra_params':'' }
139                               
140                                metadata_string = unicode(json.dumps(metadata,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
141                                objects['LmdImageManager'].setImage(imgid,metadata_string)
142                                self.set_default_boot(imgid)
143                                #command="cat "+path+"; sleep 15; cat "+path+"; echo 'command is: ltsp-build-client --config "+path+" "+extraLliurexOpts+" --chroot "+imgid+"'";
144                                #command="/tmp/miscript"
145                                #command="tree /"
146                                result=self.do_command(ip, port, command, srv_ip,target=imgid)
147                               
148                                # Registering imgid for boot PXE MEnu
149                               
150                                if (result==0):
151                                        objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
152                                else:
153                                        # Image has not been built correctly
154                                        metadata = {'id':imgid, 'name' : name,
155                                                'desc' : description ,
156                                                "template" : template,
157                                                'img': bgimg,
158                                                'ltsp_fatclient': 'undefined',
159                                                'ldm_session': 'default',
160                                                'fat_ram_threshold': 'default',
161                                                'status':'broken',
162                                                'lmd_extra_params':'' }
163                                       
164                               
165                                return result
166
167                        else:
168                                return "{'status':'false', 'error':'template does not exists'}"
169                       
170                        pass
171                except Exception as e:
172                        print "Except: "+str(e)
173                        return e
174               
175       
176        def refresh_image(self, ip, username, password, port, imgid, srv_ip='127.0.0.1'):
177               
178                # Rebuild img file for imgid
179                import xmlrpclib
180
181                try:
182                        # umount anything
183                        path="/opt/ltsp/"+imgid
184                       
185                        server = xmlrpclib.ServerProxy("https://localhost:9779")
186                        server.umount_chroot((username,password),'LmdImageManager',path);
187                       
188                        # Let's rebuild image
189                        print "[LmdServer] Refreshing image for "+str(imgid)
190
191                        # Trying to solve the non-zenity problem
192                        #
193                        command="ltsp-chroot -p -m -a "+imgid+" dpkg-reconfigure libgl1-mesa-dri ;  "
194                       
195                       
196                        command=command + "ltsp-chroot -p -m -a "+imgid+" /usr/share/ltsp/update-kernels && "
197                        command=command + "ltsp-update-kernels "+imgid+" && ltsp-update-image "+imgid+"&& service nbd-server restart"; 
198                        result=self.do_command(ip, port, command, srv_ip,target=imgid)
199                        objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
200                        return {"status": True, "msg": 'Image Updated'}
201
202                               
203                        pass
204                except Exception as e:
205                        print "Except: "+str(e)
206                        return {"False": True, "msg": str(e)}
207
208       
209               
210        def refresh_imageWS(self, imgid):
211               
212                try:
213                       
214                        # umount anything
215                        path="/opt/ltsp/"+imgid                                         
216                        objects['LmdImageManager'].umount_chroot(path);
217                       
218                        command="ltsp-chroot -p -m -a "+imgid+" dpkg-reconfigure libgl1-mesa-dri ;  "
219                        command=command + "ltsp-chroot -p -m -a "+imgid+" /usr/share/ltsp/update-kernels && "
220                        command=command + "ltsp-update-kernels "+imgid+" && ltsp-update-image "+imgid+"&& service nbd-server restart";
221                               
222                        # Let's rebuild image
223                       
224                        ret=objects['TaskMan'].newTask(command);
225                        if ret["status"]==True: ## Task has launched ok
226                               
227                               
228                                print "[LmdServer] Refreshing image for "+str(imgid)
229                               
230                                objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
231                               
232                                # Setting new taskid to the image, so we know that it is refreshing
233                                objects['LmdImageManager'].setNewTaskIdForImage(imgid, ret["msg"]);
234                                return {"status": True, "msg": ret["msg"]} # Returns task id!!
235                               
236       
237                        else:
238                                if ret["msg"]=="SERVER_BUSY":
239                                        return {'status':False, 'msg':'SERVER_BUSY'}
240                                else:
241                                        return {'status':False, 'msg':'EXCEPTION'}
242                       
243                       
244                except Exception as e:
245                        print "Except: "+str(e)
246                        return {"False": True, "msg": str(e)}
247
248       
249               
250       
251       
252        def export_image(self, ip, port, imgid, srv_ip='127.0.0.1'):
253                try:
254                        # creates an image from an specified template
255               
256                        # Check if template exists
257                        print "[LmdServer] Export_image from "+imgid
258                       
259                        name_file = str(imgid) + "_" + time.strftime("%Hh%Mm%Ss_%d%m%Y") + '.tgz'
260
261                        command="ltsp-import-export export /tmp/"+ name_file +" "+str(imgid);
262
263                        result=self.do_command(ip, port, command, srv_ip,target=imgid)
264                        return {"status": True, "msg": str(result)}
265                        pass
266                except Exception as e:
267                        print "Except: "+str(e)
268                        return {"status": False, "msg": str(e)}
269
270        def import_image(self, ip, port, imgid, path, srv_ip='127.0.0.1'):
271                try:
272                       
273                        import xmlrpclib
274                        client=xmlrpclib.ServerProxy("https://127.0.0.1:9779")
275                        n4d_server_ip=client.get_variable("", "VariablesManager", "SRV_IP")
276
277               
278                        #if(ip==srv_ip)
279                        print ("COMPARING: "+lliurex.net.get_ip_from_host(ip)+ "and "+ n4d_server_ip);
280                        if(lliurex.net.get_ip_from_host(ip)==n4d_server_ip or ip==srv_ip):
281                                print "[LmdServer] Import_image from ",path, " to ", imgid
282
283                                tar = tarfile.open(path)
284                                l = tar.getnames()
285                                folder = l[0]
286                                imgid = folder
287                                f = tar.extractfile(folder + '/' + folder + '.json')
288                                exec("json_content="+"".join(f.readlines()))
289                                try:
290                                        new_name = folder
291                                        count = 1
292                                        while os.path.exists(os.path.join(self.ltsp_path,new_name)):
293                                                        new_name = folder + "_" + str(count)
294                                                        count += 1
295
296                                        extra_opts = ""
297                                        if folder != new_name:
298                                                extra_opts = new_name
299                                except Exception as e:
300                                        extra_opts = ""
301                                command="ltsp-import-export import "+str(path)+" "+folder+" "+extra_opts+" && service nbd-server restart";
302                               
303                                if extra_opts != "":
304                                        imgid = extra_opts
305                                        json_content['id'] = imgid
306                                        json_content['name'] = imgid
307                                json_file = open('/etc/ltsp/images/' + imgid + '.json','w')
308                                data = unicode(json.dumps(json_content,indent=4,encoding='utf-8',ensure_ascii=False)).encode('utf-8')
309                                json_file.write(data)
310                                json_file.close()
311                                self.set_default_boot(imgid)
312                                result=self.do_command(ip, port, command, srv_ip,target=imgid)
313                                return {"status": True, "msg": str(result)}
314                                pass
315                        else:
316                                print "[LmdServer] ERROR. Trying to import image from out of server";
317                                return {"status": False, "msg": "Not in server"}
318                except Exception as e:
319                        print "Except: "+str(e)
320                        return {"status": False, "msg": str(e)}
321       
322        def deploy_minimal_client(self, ip, port, srv_ip='127.0.0.1'):
323                try:
324                        command="/usr/sbin/mini-light-client.py";
325                        imgid="mini-light-client"
326                       
327                        lng="es_ES.UTF-8"
328                        language="es_ES"
329       
330                        # After that, set image as available
331                        metadata = {'status':'enabled-non-editable',
332                                                'id':'mini-light-client',
333                                                'name':'Client Lleuger Minim',
334                                                'template':'Default by LMD',
335                                                'desc':'Minimal thin client -not fat- for Lliurex LTSP.',
336                                                'img':'llx-client16.png',
337                                                'ltsp_fatclient': 'false',
338                                                'ldm_session': 'startxfce4',
339                                                'fat_ram_threshold': 'default',
340                                                'lmd_extra_params':'XKBLAYOUT=es LDM_LANGUAGE="%s" LOCALE_DIR=%s'%(lng,language)}
341                        metadata_string = unicode(json.dumps(metadata,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
342                        objects['LmdImageManager'].setImage('mini-light-client',metadata_string)
343                        self.set_default_boot(imgid)
344                        result=self.do_command(ip, port, command, srv_ip,target=imgid)
345                                       
346                        if result==0:
347                                # Step 2. Writing lts.conf for mini-light-client
348                               
349                                print "[LMDServer] Writing lts.conf for mini-light-client"
350                               
351                                if not os.path.exists('/var/lib/tftpboot/ltsp/mini-light-client'):
352                                        os.makedirs('/var/lib/tftpboot/ltsp/mini-light-client')
353                               
354                                f=open('/var/lib/tftpboot/ltsp/mini-light-client/lts.conf', 'w')
355                                f.write('[Default]\n')
356                                f.write('LDM_LANGUAGE=es_ES.UTF-8\n')
357                                f.write('LTSP_FATCLIENT=false\n')
358                                f.close()
359                               
360                                # Step 3. Registering imgid for boot PXE menu
361                                objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
362                               
363                                try:
364                                        f=open("/etc/default/locale")
365                                        lines=f.readlines()
366                                        f.close()
367                                        for line in lines:
368                                                if "LANG=" in line:
369                                                        lng=line.strip().split("=")[1].strip("'").strip('"')
370                                                        if "es_ES" in lng:
371                                                                language="es"
372                                                        if "ca_ES" in lng:
373                                                                language="ca_ES@valencia"
374                                                       
375                                except:
376                                        return {"status": False, "msg": str(result)}
377                                        pass
378                               
379                                return {"status": True, "msg": str(result)}
380                                pass
381               
382                        else:
383                                # result is not 0 -> Image creation cancelled
384                                return {"status": True, "msg": str(result)}
385                                pass
386                       
387                except Exception as e:
388                        print "Except: "+str(e)
389                        return {"status": False, "msg": str(e)}
390       
391
392        #def deploy_minimal_clientWS(self, ws):
393        def deploy_minimal_clientWS(self):
394                #ws=objects['TaskMan'].getWS() -> no cal??
395                try:
396                        command="/usr/sbin/mini-light-client.py";
397                        #command="tasktest hola";
398                       
399                       
400                        #result=self.do_command(ip, port, command, srv_ip,target=imgid)
401                        ret=objects['TaskMan'].newTask(command);
402                        if ret["status"]==True: ## Task has launched ok
403                                #print ret["status"]
404                               
405                                # Writing  json metadata in /etc/ltsp/images/
406                                imgid="mini-light-client"
407                               
408                                lng="es_ES.UTF-8"
409                                language="es_ES"
410                                # After that, set image as available
411                                metadata = {'status':'enabled-non-editable',
412                                                        'taskid': ret["msg"],
413                                                        'id':'mini-light-client',
414                                                        'name':'Client Lleuger Minim',
415                                                        'template':'Default by LMD',
416                                                        'desc':'Minimal thin client -not fat- for Lliurex LTSP.',
417                                                        'img':'llx-client16.png',
418                                                        'ltsp_fatclient': 'false',
419                                                        'ldm_session': 'startxfce4',
420                                                        'fat_ram_threshold': 'default',
421                                                        'lmd_extra_params':'XKBLAYOUT=es LDM_LANGUAGE="%s" LOCALE_DIR=%s'%(lng,language)}
422                                metadata_string = unicode(json.dumps(metadata,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
423                                objects['LmdImageManager'].setImage('mini-light-client',metadata_string)
424                                self.set_default_boot(imgid)
425                               
426                                # Writing lts.conf
427                                print "[LMDServer] Writing lts.conf for mini-light-client"
428                                if not os.path.exists('/var/lib/tftpboot/ltsp/mini-light-client'):
429                                        os.makedirs('/var/lib/tftpboot/ltsp/mini-light-client')
430                                f=open('/var/lib/tftpboot/ltsp/mini-light-client/lts.conf', 'w')
431                                f.write('[Default]\n')
432                                f.write('LDM_LANGUAGE=es_ES.UTF-8\n')
433                                f.write('LTSP_FATCLIENT=false\n')
434                                f.close()
435                                # Step 3. Registering imgid for boot PXE menu
436                                objects['LlxBootManager'].pushToBootList("ltsp_label"+str(imgid));
437                                try:
438                                        f=open("/etc/default/locale")
439                                        lines=f.readlines()
440                                        f.close()
441                                        for line in lines:
442                                                if "LANG=" in line:
443                                                        lng=line.strip().split("=")[1].strip("'").strip('"')
444                                                        if "es_ES" in lng:
445                                                                language="es"
446                                                        if "ca_ES" in lng:
447                                                                language="ca_ES@valencia"
448                                                       
449                                except:
450                                        return {"status": False, "msg": ret["msg"]}
451                                        pass
452                                                               
453                                # Returns true and ret.msg, that is job id
454                                return {"status": True, "msg": ret["msg"]}
455                                pass
456                       
457                        else:
458                                if ret["msg"]=="SERVER_BUSY":
459                                        return {'status':False, 'msg':'SERVER_BUSY'}
460                                else:
461                                        return {'status':False, 'msg':'EXCEPTION'}
462               
463                       
464                except Exception as e:
465                        print "Except: "+str(e)
466                        return {"status": False, "msg": str(e)}
467       
468
469
470        def do_command(self, ip, port, command, srv_ip='127.0.0.1',target=None):
471                try:
472                        # Add Job
473                        '''job={
474                                'job_id':str(self.last_job_id),
475                                'srv_ip': None,                                         #  Server (me) IP addr
476                                'process': None,
477                                'status':'started',
478                                'msg':'',                               # Error code
479                                'target':'None',
480                                'command':command,
481                                'started_by':None,
482                                'listeners': [{'ip':ip,
483                                                'port':port,
484                                                'socket':None}],
485                                'filepipe': ''
486                                }'''
487                        call_info = _n4d_get_user()
488                        job={
489                                'job_id':str(self.last_job_id),
490                                'srv_ip': srv_ip,
491                                'process': None,
492                                'status':'started',
493                                'msg':None,
494                                'target': target,
495                                'command':command,
496                                'started_by':str(ip),
497                                'listeners': [],
498                                'filepipe': '',
499                                'seek' : 0,
500                                'method':call_info['method'],
501                                'class': call_info['class']
502                               
503                        }
504                       
505                        lock = threading.Lock()
506                        self.locks[job['job_id']]={}
507                        self.locks[job['job_id']]['lock'] = lock
508                       
509                        self.locks[job['job_id']]['lock'].acquire()
510                        # Exec command
511                        # proc = subprocess.Popen([command],  shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, preexec_fn=os.setsid)
512                       
513                        # Prepare file pipe
514                        temp = tempfile.NamedTemporaryFile(prefix='pipe_', dir=self.logfolder, delete=False)
515                       
516                        # New exec command, ignoring stderr stdin for now
517                        proc = subprocess.Popen([command],  shell=True, stdout=temp, preexec_fn=os.setsid)
518                       
519                       
520                        # Add job to tasklist
521                        job['process']=proc                                     # Assotiate process to job
522                        job['status']="running"
523                        job['filepipe'] = temp.name
524
525                       
526                        self.joblist.append(job)                                #Adding job
527                        self.add_listener_to_job(ip, port, job) # Adding the client ip:port to listeners list
528                       
529                        ## PAUSA PARA PROVOCAR UNA CONDICION DE CARRERA
530                        ##
531                        ## time.sleep(2)
532                        ## FIN DE LA PAUSA
533                        ##
534                        #self.joblist.append(job)                               #Adding job  # Moved before add_listener_to_job
535               
536                        # Increase last_job_id
537                        self.last_job_id=self.last_job_id+1
538                        # Multicast process to all listeners
539                        print "[LmdServer] WAITING ...:"+str(datetime.datetime.now())
540                        ret=job['process'].poll()
541                       
542                        while ret is None:
543                                time.sleep(1)
544                                ret=job['process'].poll()
545                       
546                       
547                        #temp.close()
548                        if (str(ret)=='0'):
549                                job['status']="finished"
550                        elif (str(ret)=='-9'):                 
551                                job['status']="cancelled"
552                        else: # return code 1 when install fails
553                                job['msg']="broken"
554                        print "[LmdServer] END WAIT AT"+str(datetime.datetime.now())
555                        print "[LmdServer] FINISHING!!!, return code: "+str(ret)
556                               
557                        # Force umount (to avoid morrir destruction in mirrononnet)
558                        proc=subprocess.call(["/usr/share/lmd-scripts/umount-chroot.sh"])
559
560                        # Sending last line to log for all listeners
561                        line="<b>Finished with status:"+job['status']+" and Response: "+job['msg']+" </b>\n"
562                        aux = open(job['filepipe'],'a')
563                        aux.writelines(line)
564                        aux.close()
565
566                        # Append result of job and release mutex. Now all inform_me return finish
567                        self.locks[job['job_id']]['result'] = str(ret)
568                        self.locks[job['job_id']]['lock'].release()
569                        print  str(ret)
570                        return str(ret)
571               
572                except Exception as e:
573                        job['status']="Error"
574                        print '[LmdServer]',e
575                        if (ret is None):
576                                job['msg']="Err code None (running)"
577                        elif (ret<0):
578                                job['msg']="Interrupted by signal: "+str(ret)
579                        else:
580                                job['msg']="Aparently all went well: "+str(ret)
581                       
582       
583                        # Append result of job and release mutex. Now all inform_me return finish
584                        self.locks[job['jobid']]['result'] = str(ret)
585                        self.locks[job['jobid']]['lock'].release()
586
587                        return str(e)
588               
589               
590        def inform_me(self,job_id):
591                '''
592                        Return result of job when finish
593                '''
594
595                self.locks[job_id]['lock'].acquire()
596                self.locks[job_id]['lock'].release()
597               
598                return {'status':True,'msg':self.locks[job_id]['result']}
599
600
601        def add_listener_to_job(self, ip, port, job):
602                '''
603                Description:
604                * Internal Function
605                * Adds a listener identified by an ip and a port to a job object
606               
607                How it Works:
608                * Creates a socket to send information to a listening socket in any client
609               
610                Last update:
611                    * 5/02/2014: Added Functionality
612                    * 2/04/2014: Add reference with job_id
613                '''
614               
615                try:
616                        # Create a socket for new listener
617                        srv=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
618                       
619                        # connection to socket to send log
620                        srv.connect((ip, int(port)))
621                       
622                        # Defines a new listener
623                        listener={'ip':ip,
624                                'port':port,
625                                'socket':srv}
626               
627                        # Add listener to job
628                        job['listeners'].append(listener)
629                        print "[LmdServer] add_listener_to_job: adding "+str(listener)+"to listeners for job "+str(job['job_id'])
630                       
631                        # Sending status of job
632                        listener['socket'].send("<b>Start listening on "+str(listener['port'])+"</b>")                 
633                        listener['socket'].send("<b> Task:"+str(job['command'])+"</b>")
634                        listener['socket'].send("<b> Started by: "+str(job['started_by'])+"</b>")
635                       
636                       
637                               
638                        # Add reference with job_id
639                        tuple_ip_port = (str(ip),str(port))
640                        self.global_listeners[tuple_ip_port] = job['job_id']
641                        #print "Len",len(self.global_listeners)
642                        #print "isAlive",self.multicast_thread.isAlive()
643                        if not self.multicast_thread.isAlive():
644                                #print "lanzando el thread"
645                                self.multicast_thread = threading.Thread(target=self.Multicast, args=())
646                                self.multicast_thread.daemon = True
647                                self.multicast_thread.start()
648                                pass
649                       
650                        return port
651                       
652                except Exception as e:
653                        print("[LmdServer] add_listener_to_job Exception: "+str(e))
654                        return -1
655               
656                pass
657               
658        def add_listener(self, ip, port, job_id):
659                '''
660                Description:
661                * n4d method
662                * Adds a listener identified by an ip and a port to a job object identified by its id
663               
664                How it Works:
665                * Search whic job has certain job_id and adds a listener to it
666               
667                Last update:
668                    * 5/02/2014: Added Functionality
669                '''
670                from operator import itemgetter
671               
672                #print ("[add_listener DEBUG] address: "+str(ip)+":"+str(port)+" job id: "+str(job_id))
673                try:
674                        # Get job identified by job_id
675                        current_job_index=map(itemgetter('job_id'), self.joblist).index(str(job_id))
676                        current_job=self.joblist[current_job_index]
677                        # Add listener to current_job
678                        self.add_listener_to_job(ip, port, current_job)
679                except Exception as e:
680                        print ("[LmdServer] add_listener Exception "+str(e))
681                pass
682
683
684        def send(self, ip, job_id, info):
685                '''
686                receives info to send to stdin
687                '''
688                from operator import itemgetter
689
690                try:
691                        current_job_index=map(itemgetter('job_id'), self.joblist).index(str(job_id))
692                        current_job=self.joblist[current_job_index]
693                        # Get listener identified by (ip:port)
694                       
695                        #current_job['process'].stdin.writelines(str(info))
696                        if(current_job['status']=='running'):
697                                current_job['process'].stdin.write(str(info)+"\n")
698                        #current_job['process'].write(info);
699                except Exception as e:
700                        print ("ERROR writing to process: "+str(e));
701               
702               
703
704        def remove_listener(self, ip, port, job_id):
705                '''
706                Description:
707                * n4d method
708                * Removes listener identified by an ip and a port to a job object identified by its id
709               
710                How it Works:
711                * Searches which job has certain job_id (if specified) and removes it
712                * If job_id is not specified, get it from ip:port
713               
714                Last update:
715                    * 6/02/2014: Added Functionality
716                    * 2/04/2014: Added checking for job_id and close socket
717                '''
718               
719                       
720                from operator import itemgetter
721                try:
722                        # If job_id is None, search job_ib by ip and port
723                        tuple_ip_port = (str(ip),str(port))
724                        if job_id == None:
725                                job_id = self.global_listeners[tuple_ip_port]
726                        # Get job identified by job_id
727                        print self.joblist
728                        print tuple_ip_port
729                        print jobid
730                        current_job_index=map(itemgetter('job_id'), self.joblist).index(job_id)
731                        current_job=self.joblist[current_job_index]
732                        # Get listener identified by (ip:port)
733                        current_listener_index=map(itemgetter('ip','port'), current_job['listeners']).index((ip,int (port, base=10)))
734
735                        # Close port and remove listener to current_job
736                        current_job['listeners'][current_listener_index]['socket'].close()
737                        current_job['listeners'].remove(current_job['listeners'][current_listener_index])
738                        #remove listener reference
739                        self.global_listeners.pop(tuple_ip_port)
740                        return True
741                       
742                except Exception as e:
743                        print ("[LmdServer] remove_listener Exception "+str(e))
744                        return False
745                pass
746               
747       
748        def cancel_job(self, ip, port, job_id):
749                '''
750                Description:
751                * n4d method
752                *
753               
754                TO DO ...               
755                Same functionality that remove_listener and in addition, kills process identified by job
756               
757                '''
758                # Remove listener
759                from operator import itemgetter
760                try:
761                        # If job_id is None, search job_ib by ip and port
762                        tuple_ip_port = (str(ip),str(port))
763                        print (tuple_ip_port)
764                        if job_id == None:
765                                print self.global_listeners
766                                job_id = self.global_listeners[tuple_ip_port]
767                                print str(job_id)
768                               
769                        # Get job identified by job_id
770                        current_job_index=map(itemgetter('job_id'), self.joblist).index(job_id)
771                        print current_job_index
772                        current_job=self.joblist[current_job_index]
773                        print current_job
774                        # Get listener identified by (ip:port)
775                        try:
776                                current_listener_index=map(itemgetter('ip','port'), current_job['listeners']).index((ip,int (port, base=10)))
777                                print current_listener_index
778                        except:
779                                #print "*** jobid: ***"
780                                #print port
781                                print "*** port: ***"
782                                print port
783                                print "*** current_job: ***"
784                                print current_job['listeners']
785                                print "*** joblist: ***"
786                                print self.getJobList();
787                                current_listener_index=None
788                                for listener in current_job['listeners']:
789                                        self.remove_listener(str(ip),str(port), job_id);
790
791                        # Kill process (only addition to remove_listener)
792                        os.killpg(current_job['process'].pid,signal.SIGKILL)
793                       
794                        # Removes target
795                        print "Removing target "+ str (current_job['target']) 
796                        r=objects['LmdImageManager'].deleteImage(current_job['target']);
797                        print str(r);
798                        print "Removied target"
799                       
800                        current_job['status']='broken'
801                       
802                        if current_listener_index!=None:
803                                # Close port and remove listener to current_job
804                                current_job['listeners'][current_listener_index]['socket'].close()
805                                current_job['listeners'].remove(current_job['listeners'][current_listener_index])
806                                #remove listener reference
807                                self.global_listeners.pop(tuple_ip_port)
808                       
809                        return True
810                       
811                except Exception as e:
812                        print ("[LmdServer] cancel_job Exception "+str(e))
813                        return False
814                pass
815
816               
817               
818               
819               
820       
821        def getJobList(self):
822                '''
823                Description:
824                * N4D Method
825                * Return JSON with the job list
826                '''
827                #import urllib
828               
829                #ret= urllib.quote(str(self.joblist)[1:-1])
830                #ret= (str(self.joblist)[1:-1]).replace("'", "\"");
831                #ret= (str(self.joblist)).replace("'", "\"");
832                '''ret=ret.replace("<", "\"");
833                ret=ret.replace(">", "\"");'''
834                ret='[';
835                count=0;
836                for job in self.joblist:
837                        if (count>0):
838                                ret=ret+','
839                        ret=ret+'{"job_id":"'+str(job['job_id'])+'"'
840                        ret=ret+', "srv_ip":"'+str(job['srv_ip'])+'"'                   
841                        ret=ret+', "status":"'+str(job['status'])+'"'
842                        ret=ret+', "msg":"'+str(job['msg'])+'"'
843                        ret=ret+', "target":"'+str(job['target'])+'"'
844                        ret=ret+', "command":"'+str(job['command'])+'"'
845                        ret=ret+', "started_by":"'+str(job['started_by'])+'"}'
846                        count=count+1
847                        #print "*********************"
848                        #print "Local listeners"
849                        #print job['listeners']
850                        #print "*********************"
851                       
852                       
853               
854                ret=ret+']'
855                #print (ret)
856                #print "*********************"
857                #print "globals listeners"
858                #print self.global_listeners
859                #print "*********************"
860                return str(ret)
861               
862        def Multicast(self):
863                '''
864                Description:
865                * Internam method
866                * Multicast the output of all processes to its listeners
867               
868                How it works:
869                * Traverses the list of jobs and write its output to all its listeners
870               
871                * Last Update: 13/02/2014
872                '''
873                try:
874                        while len(self.global_listeners) > 0 :
875                                counter = 0
876                                #print "joblist",self.joblist
877                                #print "global_listeners",self.global_listeners
878                                for job in self.joblist:
879                                        if True : #job['status'] != "finished":
880                                                counter += 1
881                                                try:
882                                                        if not self.thread_jobs.has_key(job['job_id']):
883                                                                self.thread_jobs[job['job_id']] = threading.Thread(target=self.send_info_by_socket, args=(job,))
884                                                                self.thread_jobs[job['job_id']].daemon = True
885                                                                self.thread_jobs[job['job_id']].start()
886                                                except Exception as e:
887                                                        print e
888                                if counter == 0:
889                                        break
890                                time.sleep(1)
891                except Exception as e:
892                        print "[LmdServer] EXCEPTION in Multicast: "+str(e)
893                       
894        def send_info_by_socket(self,job):
895                try:
896                        if not os.path.exists(job['filepipe']):
897                                return False
898                        pipe = open(job['filepipe'],'r')
899                        pipe.seek(job['seek'],0)
900                        try:
901                                line = pipe.readline()
902                                while (line and len(self.global_listeners)>0):
903                                        for listener in job['listeners']:
904                                                if(listener['socket']!=None):
905                                                        try:
906                                                                listener['socket'].send(line)
907                                                        except Exception as e:
908                                                                print "[LmdServer] EXCEPTION in Multicast internal loop: "+str(e)
909                                                        continue
910                                        line=pipe.readline()
911                                        job['seek'] = pipe.tell()
912                        except Exception as e:
913                                print "[LMDServer] Exception wghile reading pipe "+str(e)
914                                pass
915                       
916                        if self.thread_jobs.has_key(job['job_id']):
917                                self.thread_jobs.pop(job['job_id'])
918                               
919                except Exception as e:
920                                print "[LMDServer] Exception wghile reading pipe "+str(e)
921                                pass
922        def getLastJobId(self):
923                return self.last_job_id
924
925       
926        def getJobStatus(self, jobid):
927                for i in self.joblist:
928                        if i['job_id']==jobid:
929                                return {"status": True, "msg": str(i['status'])}
930               
931                return {"status": False, "msg": 'bad luck, guy'}
932
933        def check_lmd_status(self):
934                '''
935                Description:
936                * N4D Method
937                * check status of lmd
938                '''
939                import os.path
940                if (os.path.isfile("/tmp/.lmd-editing-chroot")):
941                        return {"status": True, "lmd_status": 'lmd-editing-chroot'}
942                else:
943                        return {"status": True, "lmd_status": 'lmd-chroot-available'}
944               
945        def chek_minimal_client(self):
946                if (os.path.isfile("/etc/ltsp/images/mini-light-client.json") and os.path.isfile("/opt/ltsp/images/mini-light-client.img") ):
947                        return {"status": True}
948                else:
949                        return {"status": False}
950               
951
952        def get_versions_13(self):
953                '''
954                Checks if there is any old image un system (13.06)
955                '''
956               
957                ltsp_dir="/opt/ltsp/"
958                nbd_dir="/etc/nbd-server/conf.d/"
959               
960                ret_list=[];
961
962                #OBSOLETE REMOVED METHOD
963                #RETURN EMPTY LIST TO LMD-GUI TO AVOID LLIUREX 13 WARNING
964                #for name in os.listdir(ltsp_dir):
965                #       dir=ltsp_dir+name
966                #       
967                #       needs_update=False
968                #       if (name!='images' and os.path.isdir(dir)):
969                #               proc = subprocess.Popen(["chroot "+dir +" lliurex-version"], stdout=subprocess.PIPE, shell=True)
970                #               (out, err) = proc.communicate()
971                #               
972                #               if ((not "16.05" in out) and out!="" ):
973                #                       # check nbd...
974                #                       for nbd_descriptor in os.listdir(nbd_dir):
975                #                               if (self.line_in_file("["+ltsp_dir+name+"]", nbd_dir+nbd_descriptor)):
976                #                                       needs_update=True
977                #       if (needs_update==True):
978                #               ret_list.append(name)
979                #
980                return ret_list
981
982        def line_in_file(self, line_to_find, filename):
983                '''
984                Aux function: ask for if certain line is contained in a file
985                '''
986                fd = open(filename, 'r')
987                lines = fd.readlines()
988                fd.close()
989                for line in lines:
990                        if str(line_to_find) in line:
991                                return True
992                               
993                return False
994       
995        def update_images(self, ip, port, imagelist, srv_ip):
996               
997                try:
998               
999                        imagelist_string = " ".join(imagelist)
1000                        ##print imagelist," is ", type(imagelist)
1001                        ### n4d-client -c LmdServer -m update_images -u joamuran -p lliurex -a  2 3 "['pajarito', 'perro']"
1002                       
1003                        # Prepare and launch command
1004                        command="/usr/share/lmd-scripts/lmd-upgrade-images.sh "+imagelist_string;
1005                        result=self.do_command(ip, port, command, srv_ip, None)
1006                       
1007                        # Add image description
1008                        #imagelist=imagelist_string.replace("[","").replace("]","").replace(" ","").replace("'", "").replace(","," ");
1009                        #print imagelist_string;
1010                        print imagelist;
1011                        #print imagelist.split(" ");
1012                        for i in imagelist:
1013                                metadata = {'id':i,
1014                                        'name' : i,
1015                                        'desc' : 'Upgraded from Lliurex 13.06',
1016                                        'template' : 'none',
1017                                        'ltsp_fatclient': 'undefined',
1018                                        'ldm_session': 'default',
1019                                        'fat_ram_threshold':'default',
1020                                        'lmd_extra_params':''}
1021                               
1022                                metadata_string = unicode(json.dumps(metadata,indent=4,encoding="utf-8",ensure_ascii=False)).encode("utf-8")
1023                               
1024                                objects['LmdImageManager'].setImage(i,metadata_string)
1025                                self.set_default_boot(imgid)
1026                        return {"status": True}
1027                except Exception as e:
1028                        print "Exception", e
1029                        return {"status": False, 'msg':str(e)}
1030
1031
1032        def delete_images(self,imagelist):
1033               
1034                try:
1035               
1036                        for img in imagelist:
1037                                print img
1038                                path_chroot=os.path.join("/opt/ltsp/", img)
1039                                path_tftpboot=os.path.join("/var/lib/tftpboot/ltsp/", img)
1040                                path_img=os.path.join("/opt/ltsp/images/", img+".img")
1041                                path_nbd=os.path.join("/etc/nbd-server/conf.d/", "ltsp_"+img+".conf")
1042                                if (os.path.exists(path_chroot)):
1043                                        shutil.rmtree(path_chroot)
1044                                        #print "deleting: ",path_chroot
1045                                if (os.path.exists(path_tftpboot)):
1046                                        shutil.rmtree(path_tftpboot)
1047                                if (os.path.exists(path_img)):
1048                                        #print "deleting: ",path_img
1049                                        shutil.rmtree(path_img);
1050                                if (os.path.exists(path_nbd)):
1051                                        #print "deleting: ",path_nbd
1052                                        shutil.rmtree(path_nbd);
1053                               
1054                        return {"status": True, 'msg':'Finished'}
1055
1056                except Exception as e:
1057                        print "Exception", e
1058                        return {"status": False, 'msg':str(e)}
1059
1060        def LmdServerVersion(self):
1061                info=subprocess.check_output(["apt-cache","policy","lmd-server"])
1062                lines=str(info).split('\n')
1063                version=lines[1][13:]
1064                return (version)
1065
1066        def check_update_images(self):
1067                list_dirs = [ os.path.join(self.ltsp_path,x) for x in os.listdir(self.ltsp_path) if os.path.isdir(os.path.join(self.ltsp_path,x)) ]
1068                list_need_update = []
1069                for chroot in list_dirs:
1070                        available_file = os.path.join(chroot,'var','lib','dpkg','available')
1071                        if os.path.exists(available_file):
1072                                available_fd = open(available_file,'r')
1073                                available_content = available_fd.readlines()
1074                                try:
1075                                        pos = available_content.index('Package: lmd-client\n')
1076                                        version = None
1077                                        for i in range(pos + 1 ,len(available_content)):
1078                                                if available_content[i] == '\n':
1079                                                        break
1080                                                if available_content[i].startswith('Version'):
1081                                                        version = available_content[i][8:].strip()
1082                                        if version != None :
1083                                                apt_pkg.init()
1084                                                if apt_pkg.version_compare(version,'0.15') < 0 :
1085                                                        list_need_update.append(os.path.basename(chroot))
1086                                except Exception as e:
1087                                        pass
1088                if len(list_need_update) > 0:
1089                        return [True,list_need_update]
1090                else:
1091                        return [False,[]]
Note: See TracBrowser for help on using the repository browser.