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

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

Add log in n cli and add sources for client

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