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

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

added new features for lmdserver that includes TaskMan? working

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