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

Last change on this file since 3514 was 3514, checked in by jrpelegrina, 3 years ago

Fix code

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