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

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

Fix code to new features

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