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

Last change on this file since 3135 was 3135, checked in by hectorgh, 3 years ago

added linux32

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