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

Last change on this file since 3072 was 3072, checked in by joamuran, 3 years ago

Fixed create_imageWS method to store architecture in image json

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