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

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

Added regenerate_imageWS

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