source: lliurex-up/trunk/fuentes/python-lliurex-up/lliurex/lliurexup/__init__.py @ 3735

Last change on this file since 3735 was 3735, checked in by jrpelegrina, 4 years ago

Fix code

File size: 17.3 KB
Line 
1import xmlrpclib 
2import os
3import shutil
4import subprocess
5import socket
6import distutils.dir_util
7import urllib2
8
9class LliurexUpCore(object):
10        """docstring for LliurexUpCore"""
11        def __init__(self):
12                super(LliurexUpCore, self).__init__()
13                self.flavourReference=["lliurex-meta-server","lliurex-meta-client", "lliurex-meta-desktop", "lliurex-meta-music", "lliurex-meta-pyme", "lliurex-meta-infantil"] 
14                self.defaultMirror = 'llx16'
15                self.defaultVersion = 'xenial'
16                self.lockTokenPath="/var/run/lliurexUp.lock"
17                self.processPath = '/var/run/lliurex-up'
18                self.sourcesListPath='/etc/apt/'
19                self.changelogsPath = os.path.join(self.processPath,'changelogs')
20                self.processSourceslist = os.path.join(self.processPath,'sourceslist')
21                self.origsourcesfile=os.path.join(self.sourcesListPath,"sources.list")
22                self.origsourcesfileback=os.path.join(self.sourcesListPath,"lliurexup_sources.list")
23                self.targetMetapackagePath=os.path.join(self.processPath,"targetMetapackage")
24                self.previousflavourspath = os.path.join(self.processPath,'previousflavours')
25                self.errorpostaction_token=os.path.join(self.processPath,'errorpostaction_token')
26                self.errorupgrade_token=os.path.join(self.processPath,'errorupgrade_token')
27                self.finalupgrade_token=os.path.join(self.processPath,'finalupgrade_token')
28
29                self.initActionsPath='/usr/share/lliurex-up/initActions'
30                self.preActionsPath = '/usr/share/lliurex-up/preActions'
31                self.postActionsPath = '/usr/share/lliurex-up/postActions'
32
33                self.createLockToken()
34                self.n4d = xmlrpclib.ServerProxy('https://localhost:9779')
35                self.haveLliurexMirror = False
36                self.metapackageRef=[]
37                self.previousFlavours = []
38
39                self.getTargetMetapackage()
40                self.flavours = []
41                self.getPreviousFlavours()
42                if len(self.n4d.get_methods('MirrorManager')) > 0:
43                        self.haveLliurexMirror = True
44                self.prepareEnvironment()
45
46
47        def createLockToken(self):
48
49                if not os.path.exists(self.lockTokenPath):
50                        f=open(self.lockTokenPath,'w')
51                        f.close
52
53        def getPreviousFlavours(self):
54               
55                if os.path.exists(self.previousflavourspath):
56                        aux = open(self.previousflavourspath,'r')
57                        lines = aux.readlines()
58                        for x in lines:
59                                self.previousFlavours.append(x.strip())
60                        aux.close()
61
62
63        def getTargetMetapackage(self):
64
65                if os.path.exists(self.targetMetapackagePath):
66                        aux = open(self.targetMetapackagePath,'r')
67                        lines = aux.readlines()
68                        for x in lines:
69                                self.metapackageRef.append(x.strip())
70                        aux.close()             
71
72        def saveTargetMetapackage(self,targetMetapackage):
73
74                aux=open(self.targetMetapackagePath,'w')
75                x=targetMetapackage.split("-")[2]
76                aux.write(x+"\n")
77                x="edu"
78                aux.write(x+"\n")
79                aux.close()
80
81
82        def checkInitialFlavour(self):
83
84                self.targetMetapackage=self.checkFlavour()
85                       
86                if len(self.metapackageRef)==0:
87                        self.getTargetMetapackage()
88               
89                self.metapackageRef=sorted(self.metapackageRef) 
90                         
91                if len(self.previousFlavours)==0:
92                        self.getPreviousFlavours()
93               
94
95                self.writeDefaultSourceslist()
96                self.writeDefaultSourceslistMirror()
97                self.addSourcesListLliurex()
98
99                return self.targetMetapackage
100               
101
102        def updateFlavoursList(self):
103               
104                self.flavours = [ x.strip() for x in self.n4d.lliurex_version('','LliurexVersion','-v')[1].split(',') ]
105                if len(self.flavours) > 0:
106                        aux = open(self.previousflavourspath,'w')
107                        for x in self.flavours:
108                                aux.write(x+"\n")
109                        aux.close()
110
111        def writeDefaultSourceslist(self):
112
113                f = open(os.path.join(self.processSourceslist,'default'),'w')
114                f.write('deb http://lliurex.net/{version} {version} main restricted universe multiverse\n'.format(version=self.defaultVersion))
115                f.write('deb http://lliurex.net/{version} {version}-updates main restricted universe multiverse\n'.format(version=self.defaultVersion))
116                f.write('deb http://lliurex.net/{version} {version}-security main restricted universe multiverse\n'.format(version=self.defaultVersion))
117                f.close()
118
119        def writeDefaultSourceslistMirror(self):
120               
121                f = open(os.path.join(self.processSourceslist,'default_mirror'),'w')
122                f.write('deb http://mirror/{version_mirror} {version} main restricted universe multiverse\n'.format(version_mirror=self.defaultMirror,version=self.defaultVersion))
123                f.write('deb http://mirror/{version_mirror} {version}-updates main restricted universe multiverse\n'.format(version_mirror=self.defaultMirror,version=self.defaultVersion))
124                f.write('deb http://mirror/{version_mirror} {version}-security main restricted universe multiverse\n'.format(version_mirror=self.defaultMirror,version=self.defaultVersion))
125                f.close()       
126
127        def prepareEnvironment(self):
128                '''
129                        This funcion delete all environment and rebuild environment
130
131                '''
132                self.cleanEnvironment()
133                if not os.path.exists(self.processPath):
134                        os.mkdir(self.processPath)
135                if not os.path.exists(self.processSourceslist):
136                        os.mkdir(self.processSourceslist)
137                if not os.path.exists(self.changelogsPath):
138                        os.mkdir(self.changelogsPath)
139
140                #self.writeDefaultSourceslist()
141                #self.writeDefaultSourceslistMirror()
142
143        def addSourcesListLliurex(self):
144               
145                #sourcesrefmirror=os.path.join(self.processSourceslist, 'default_mirror')
146
147                newsourcesfile=os.path.join(self.sourcesListPath,'sources.list')
148                extrasources=[]
149
150
151                if self.targetMetapackage=="lliurex-meta-client" or "client" in self.previousFlavours or "client" in self.metapackageRef:
152                        textsearch="/mirror/"+str(self.defaultMirror)
153                        sourcesref=os.path.join(self.processSourceslist, 'default_mirror')
154
155                else:
156                        textsearch="/lliurex.net/"+str(self.defaultVersion)
157                        sourcesref=os.path.join(self.processSourceslist, 'default')     
158
159                if os.path.exists(self.origsourcesfile):
160                        os.rename(self.origsourcesfile,self.origsourcesfileback)
161                        origsources=open(self.origsourcesfileback,'r')
162                        for line in origsources:
163                                if not textsearch in line:
164                                        extrasources.append(line.strip())
165                        origsources.close()
166                               
167                        if os.path.exists(sourcesref):
168                                shutil.copy(sourcesref,self.origsourcesfile)
169                                if len(extrasources)>0: 
170                                        newsourcesedit=open(newsourcesfile,'a')
171                                        for line in extrasources:
172                                                newsourcesedit.write(line+'\n')
173                                        newsourcesedit.close()
174                        else:
175                                os.rename(self.origsourcesfileback,self.origsourcesfile)                                       
176                       
177
178        def restoreOrigSourcesList(self):
179               
180                if os.path.exists(self.origsourcesfileback):
181                        os.rename(self.origsourcesfileback,self.origsourcesfile)
182
183        def readSourcesList(self):
184               
185                count=0
186                if os.path.exists(self.origsourcesfile):
187                        sources=open(self.origsourcesfile,'r')
188                        ref="/lliurex.net/"+str(self.defaultVersion)
189                        for line in sources:
190                                if ref in line:
191                                        if not "#" in line:
192                                                count=count+1
193                return count           
194
195        def cleanEnvironment(self):
196               
197                if os.path.exists(self.processPath):
198                        shutil.rmtree(os.path.join(self.processPath))
199
200                self.restoreOrigSourcesList()   
201
202        def cleanLliurexUpLock(self):
203
204                if os.path.exists(self.lockTokenPath):
205                        os.remove(self.lockTokenPath)
206
207        def updateCacheApt(self,options=""):
208               
209                command = "LANG=C LANGUAGE=en apt-get update {options}".format(options=options)
210                subprocess.Popen(command,shell=True).communicate()
211
212
213        def getPackageVersionAvailable(self,package,options=""):
214                '''
215                        Args :
216                                package String
217                                options String
218
219                        return dictionary => result
220                        result : {'installed':String,'candidate':String}
221
222                        Options are Apt options
223                '''
224                command = "LANG=C LANGUAGE=en apt-cache policy {package} {options}".format(package=package,options=options)
225                p = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE)
226                installed = None
227                candidate = None
228                for line in iter(p.stdout.readline,""):
229                        stripedline = line.strip()
230                        if stripedline.startswith("Installed"):
231                                installed = stripedline.replace("Installed: ","")
232                        if stripedline.startswith("Candidate"):
233                                candidate = stripedline.replace("Candidate: ","")
234                return {"installed":installed,"candidate":candidate}
235
236        def isLliurexUpIsUpdated(self):
237                '''
238                        return Boolean
239                '''
240                sourceslistDefaultPath = os.path.join(self.processSourceslist,'default')
241
242                if "client" in self.previousFlavours or "lliurex-meta-client"==self.targetMetapackage:
243                        sources=self.readSourcesList()
244                        if sources==0:
245                                sourceslistDefaultPath = os.path.join(self.processSourceslist,'default_mirror')
246
247
248                options = ""
249                if self.canConnectToLliurexNet():
250                        options = "-o Dir::Etc::sourcelist={sourceslistOnlyLliurex} -o Dir::Etc::sourceparts=/dev/null".format(sourceslistOnlyLliurex=sourceslistDefaultPath)
251
252                self.updateCacheApt(options)
253                result = self.getPackageVersionAvailable('lliurex-up',options)
254
255                if result['installed'] != result['candidate']:
256                        return False
257                return True
258
259        def installLliurexUp(self,options=""):
260                '''
261                        Args :
262                                options String
263                        return dictionary => result
264                        result : {'returncode':Int,'stdout':String,'stderr':String}
265
266                        options are Apt options
267                       
268
269                        This function install lliurex-up
270                '''
271                self.updateCacheApt(options)
272                command = "LANG=C LANGUAGE=en apt-get install --force-yes --yes lliurex-up {options}".format(options=options)
273                p = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE)
274                poutput,perror = p.communicate()
275                return {'returncode':p.returncode,'stdout':poutput,'stderrs':perror}
276
277        def lliurexMirrorIsUpdated(self):
278                '''
279                        return None | dictionary => result
280                        result : {'status':Boolean,'msg':String,'action':String}
281                        result.msg : message of status
282                        result.action : Action to launch
283                '''
284                if self.haveLliurexMirror and ('server' in self.flavours or 'lliurex-meta-server'==self.targetMetapackage):
285                        result = self.n4d.is_update_available('','MirrorManager',self.defaultMirror)
286                        return result
287                return None
288
289        def lliurexMirrorIsRunning(self):
290                '''
291                        return Boolean
292                '''
293                if self.haveLliurexMirror and ('server' in self.flavours or 'lliurex-meta-server'==self.targetMetapackage):
294                        result = self.n4d.is_alive('','MirrorManager')
295                        return result['status']
296                return False
297
298        def clientCheckingMirrorIsRunning(self):
299
300                if self.targetMetapackage=="lliurex-meta-client" or "client" in self.previousFlavours or "client" in self.metapackageRef:
301                       
302                        try:
303                                client=xmlrpclib.ServerProxy('https://server:9779')
304                                result=client.is_alive('','MirrorManager')
305                                return {'ismirrorrunning':result['status'],'exception':False}
306                       
307                        except Exception as e:
308                                return {'ismirrorrunning':None,'exception':str(e)}     
309
310                return {'ismirrorrunning':False,'exception':False}     
311
312        def getPercentageLliurexMirror(self):
313                '''
314                        return int | None
315                '''
316                if self.haveLliurexMirror and ('server' in self.flavours or 'lliurex-meta-server'==self.targetMetapackage):
317                        result = self.n4d.get_percentage('','MirrorManager',self.defaultMirror)
318                        if result['status']:
319                                return result['msg']
320                return None
321       
322        def checkFlavour(self):
323                '''
324                        return None|String
325                        If metapackages has been uninstalled, this function return
326                        package to must install. If return None, you are ok and don't need
327                        install anything.
328                '''
329                self.updateFlavoursList()
330                targetMetapackage = None
331                if 'None' in self.flavours:
332                        # get last flavour
333                        result = self.n4d.lliurex_version('','LliurexVersion','--history')
334                        if result[0]:
335                                history = [ x.strip().split('\t')[0].strip() for x in result[1].split('\n') ]
336                                history = [ x for x in history if not 'lliurex-meta-live' in x ]
337                                for x in reversed(history):
338                                        if x.startswith('-'):
339                                                targetMetapackage = x[2:]
340                                                break
341
342                if targetMetapackage !=None:
343                        self.saveTargetMetapackage(targetMetapackage)                           
344                return targetMetapackage
345
346        def canConnectToLliurexNet(self):
347                '''
348                        return Boolean
349                '''
350                # s =  socket.socket(socket.AF_INET, socket.SOCK_STREAM)
351                # host = socket.gethostbyname('lliurex.net')
352                # result = s.connect_ex((host, 80))
353                # s.close()
354                # if result:
355                #       return False
356                # return True
357
358                try:
359                        req=urllib2.Request("http://lliurex.net/xenial")
360                        res=urllib2.urlopen(req)
361                        return True
362                except:
363                        return False
364                               
365        def getLliurexVersionLliurexNet(self):
366                '''
367                        return dictionary => result
368                        result : {'installed':String,'candidate':String}
369                '''
370                sourceslistDefaultPath = os.path.join(self.processSourceslist,'default')
371                options = ""
372                if self.canConnectToLliurexNet():
373                        options = "-o Dir::Etc::sourcelist={sourceslistOnlyLliurex} -o Dir::Etc::sourceparts=/dev/null".format(sourceslistOnlyLliurex=sourceslistDefaultPath)
374                self.updateCacheApt(options)
375                return self.getPackageVersionAvailable('lliurex-version-timestamp',options)
376
377        def getLliurexVersionLocal(self):
378               
379                self.updateCacheApt('')
380                return self.getPackageVersionAvailable('lliurex-version-timestamp','')         
381
382        def initActionsScript(self,arg):
383               
384                #return 'run-parts --arg="initActions" ' + self.initActionsPath
385                return 'run-parts --arg=' +str(arg) + ' ' + self.initActionsPath
386
387
388        def preActionsScript(self):
389               
390                return 'run-parts --arg="preActions" ' + self.preActionsPath
391
392        def postActionsScript(self):
393               
394                return 'run-parts --arg="postActions" ' + self.postActionsPath
395
396
397        # def requiresInstallFlavour(self):
398               
399        #       flavourToInstall=None
400               
401        #       if not 'None' in self.previuosFlavours:
402        #               if self.previuosFlavours !=self.flavours:
403        #                       flavourToInstall=self.parseFlavourToInstall(self.previousFlavours)
404                                                                               
405        #       else:
406                       
407        #               if self.metapackageRef != self.flavours:
408        #                       flavourToInstall=self.parseFlavourToInstall(self.metapackageRef)
409                                                       
410
411        #       return flavourToInstall                                 
412
413               
414        # def parseFlavourToInstall(self,flavours):
415       
416        #       parse_flavour=""
417
418        #       for item in flavours:
419        #               if item != "edu":
420        #                       parse_flavour=parse_flavour + " " + "lliurex-meta-" + item
421
422        #       return parse_flavour
423                       
424        #def parseFlavourToInstall(
425
426
427        def installInitialFlavour(self,flavourToInstall,options=""):
428                '''
429                        Args :
430                                flavourToInstall String
431                                options String
432                        return dictionary => result
433                        result : {'returncode':Int,'stdout':String,'stderr':String}
434
435                        options are Apt options
436                       
437
438                        This function install lliurex-up
439                '''
440                self.updateCacheApt(options)
441                command = "LANG=C LANGUAGE=en apt-get install --force-yes --yes " + flavourToInstall + "{options} ".format(options=options)
442                p = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE)
443                poutput,perror = p.communicate()
444                return {'returncode':p.returncode,'stdout':poutput,'stderrs':perror}   
445
446        def getPackagesToUpdate(self):
447                '''
448                        packageInfo definition
449                        {
450                                'PACKAGENAME' : {
451                                                'install' : 'INSTALLEDVERSION',
452                                                'candidate' : 'CANDIDATEVERSION',
453                                                'icon' : 'ICONNAME',
454                                                'changelog' : 'CHANGELOGTEXT'
455                                }
456                        }
457                '''
458                self.packageInfo = {}
459                self.updateCacheApt("")
460                psimulate = subprocess.Popen('LANG=C LANGUAGE=en apt-get dist-upgrade -sV',shell=True,stdout=subprocess.PIPE)
461                rawoutputpsimulate = psimulate.stdout.readlines()
462                rawpackagestoinstall = [ aux.strip() for aux in rawoutputpsimulate if aux.startswith('Inst') ]
463                r = [ aux.replace('Inst ','') for aux in rawpackagestoinstall ]
464                for allinfo in r :
465                        self.packageInfo[allinfo.split(' ')[0]] = {}
466                        self.packageInfo[allinfo.split(' ')[0]]['raw'] = ' '.join(allinfo.split(' ')[1:])
467
468                for package in self.packageInfo:
469                        raw = self.packageInfo[package]['raw'].split(' ')
470                        if raw[0].startswith('['):
471                                self.packageInfo[package]['install'] = raw[0][1:-1]
472                                self.packageInfo[package]['candidate'] = raw[1][1:]
473                        elif raw[0].startswith('('):
474                                self.packageInfo[package]['install'] = None
475                                self.packageInfo[package]['candidate'] = raw[0][1:]
476                        self.packageInfo[package].pop('raw')
477                        #packageInfo[package]['changelog'] = os.path.join(self.changelogsPath,package)
478                        #os.system('LANG=C LANGUAGE=en apt-get changelog %s > %s%s'%(package,self.changelogsPath,package))
479                        #packageInfo[package]['icon'] =
480                return self.packageInfo
481
482
483        def checkIncorrectFlavours(self):
484               
485                self.incorrect_flavours=[]
486                count=0
487
488                for item in self.packageInfo:
489                        if item in self.flavourReference:
490                                self.incorrect_flavours.append(item)
491
492
493                if len(self.incorrect_flavours)>0:
494
495                        for item in self.incorrect_flavours:
496                                if self.targetMetapackage != None:
497                                        if item != self.targetMetapackage:
498                                                count=count+1
499                                else:
500                                        meta=item.split("-")[2]
501                                        if 'None' in self.previousFlavours:
502                                                if not meta in self.metapackageRef:
503                                                        count=count+1
504                                        else:           
505                                                if not meta in self.previousFlavours:
506                                                        count=count+1
507
508                if count>0:
509                        return True
510
511                else:
512                        return False   
513
514
515        def distUpgradeProcess(self):
516       
517                return 'apt-get dist-upgrade --yes --force-yes'
518
519
520
521        def checkErrorDistUpgrade(self):
522
523                count=0
524                error=False
525
526                if os.path.exists(self.errorpostaction_token):
527                        aux = open(self.errorpostaction_token,'r')
528                        lines = aux.readlines()
529                        for x in lines:
530                                if 'E: ' in x:
531                                        count=count+1
532                        aux.close()
533
534                if count==0:
535                        cmd='dpkg -l | grep "^i[^i]" >' + self.errorupgrade_token
536                        os.system(cmd)
537               
538                        if os.path.exists(self.errorupgrade_token):
539                                aux = open(self.errorupgrade_token,'r')
540                                lines = aux.readlines()
541                                aux.close()
542                       
543                                if len(lines)>0:
544                                        error=True
545                                        #log_msg="Dist-upgrade process ending with errors"
546                                        #self.log(log_msg)
547                                else:
548                                        j=0
549                                        cmd='apt-get dist-upgrade -sV >' + self.finalupgrade_token
550                                        os.system(cmd)
551                                        if os.path.exists(self.finalupgrade_token):
552                                                aux = open(self.finalupgrade_token,'r')
553                                                lines = aux.readlines()
554                                                aux.close()
555
556                                                for x in lines:
557                                                        if 'Inst' in x:
558                                                                j=j+1
559
560                                                if j>0:
561                                                        error=True             
562                else:
563                        error=True
564
565                return error   
566
567
568        def checkFinalFlavour(self):
569               
570                flavourToInstall=None
571               
572                self.targetMetapackage=self.checkFlavour()
573                if self.targetMetapackage!=None:
574                        #flavourToInstall=self.requiresInstallFlavour()
575                #else:
576                        flavourToInstall=self.targetMetapackage         
577
578                return flavourToInstall         
579
580
581        def installFinalFlavour(self,flavourToInstall):
582
583                return 'apt-get install ' + flavourToInstall + ' --yes --force-yes'
584               
585       
586
587if __name__ == '__main__':
588        x = LliurexUpCore()
Note: See TracBrowser for help on using the repository browser.