summaryrefslogtreecommitdiffstats
path: root/src/lib/Client/Gentoo.py
blob: 695dbe57f112d243217dc1ae80e63b83afbe4eda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
'''This provides bcfg2 support for Gentoo'''
__revision__ = '$Revision: 1.6 $'

from os import popen, system, stat
from popen2 import Popen4
from glob import glob
from re import compile, match

from Bcfg2.Client.Toolset import Toolset

class Gentoo(Toolset):
    '''This class implelements support for Gentoo binary packages and standard /etc/init.d services'''
    pkgtool = {'emerge':("/usr/bin/emerge --quiet --nospinner --usepkg --getbinpkg %s", ("%s-%s", ['name', 'version']))}

    def __init__(self, cfg, setup):
        Toolset.__init__(self, cfg, setup)
        self.cfg = cfg
        self.pkgwork = {'add':[], 'update':[], 'remove':[]}
        self.installed = {}
        self.extra_services = []
        self.Refresh()
        system("emerge sync")

    def Refresh(self):
        '''Refresh memory hashes of packages'''
        self.installed = {}

        splitter = compile('([\w\-\+]+)-([\d].*)')

        # Build list of packages
        instp =  [splitter.match(f.split('/')[-1].replace('.ebuild','')).groups() for f in glob('/var/db/pkg/*/*/*.ebuild')]
        for name,version in instp:
            self.installed["%s-%s" % (name, version)] = version

    def VerifyService(self, entry):
        '''Verify Service status for entry'''
        runlevels = popen("/bin/rc-status --list").readlines()
        try:
            crunlevels = popen("/sbin/rc-update show | grep %s" % entry.attrib['name']).readlines()[0].split()[2:]
        except IndexError:
            # Ocurrs when no lines are returned (service not installed)
            return False

        if entry.get('status') == 'off':
            if len(crunlevels) == 0:
                return True
        elif entry.get('status') == 'on':
            if len(crunlevels) > 0:
                return True
        return False
                
    def InstallService(self, entry):
        '''Install Service entry'''
        
        self.CondPrint('verbose', "Installing Service %s" % (entry.get('name')))
        try:
            stat('/etc/init.d/%s' % entry.get('name'))
        except OSError:
            self.CondPrint('debug', "Init script for service %s does not exist" % entry.get('name'))
            return False
        
        if entry.attrib['status'] == 'off':
            if self.setup['dryrun']:
                print "Disabling Service %s" % (entry.get('name'))
            else:
                cmdrc = system("/sbin/rc-update del %s %s" % (entry.attrib['name'], entry.attrib['runlevels']))
        else:
            if self.setup['dryrun']:
                print "Enabling Service %s" % (entry.attrib['name'])
            else:
                cmdrc = system("/sbin/rc-update add %s %s" % (entry.attrib['name'], entry.attrib['runlevels']))
        if cmdrc:
            return False
        return True

    def VerifyPackage(self, entry, modlist):
	'''Verify Package status for entry'''
        if not (entry.get('name') and entry.get('version')):
            print "Can't verify package, not enough data."
            return False

        installed_package = popen("/usr/bin/qpkg --no-color --installed --verbose %s-%s" % (entry.get('name'), entry.get('version'))).readlines()
        if installed_package:
            installed_package = installed_package[0].strip("\n").split('/')[-1]
            if installed_package != "%s-%s" % (entry.get('name'), entry.get('version')):
                self.CondPrint('debug', "Package %s-%s version incorrect" % (entry.get('name'), entry.get('version')))
            if entry.attrib.get('verify', 'true') == 'true':
                if self.setup['quick']:
                    return True
                verp = Popen4("/usr/bin/qpkg --no-color --check %s-%s" % (entry.get('name'), entry.get('version')), bufsize=16384)
                odata = verp.fromchild.read()
                vstat = verp.poll()
                while vstat == -1:
                    odata += verp.fromchild.read()
                    vstat = verp.poll()
                output = [line for line in odata.split("\n") if line]
                differences = output[-1]
                
                if match("^0/", differences):
                    return True
                else:
                    for line in output[1:-1]:
                        if line.split()[0] not in modlist:
                            self.CondPrint('debug', "Package %s content verification failed" % (entry.get('name')))
                            return False
                    return True
        return False

    def Inventory(self):
        '''Do standard inventory plus debian extra service check'''
        Toolset.Inventory(self)
        allsrv = [ x.split('/')[-1] for x in glob('/etc/init.d/*')]
        csrv = self.cfg.findall(".//Service")
        [allsrv.remove(svc.get('name')) for svc in csrv if svc.get('status') == 'on' and svc.get('name') in allsrv]
        self.extra_services = allsrv

    def HandleExtra(self):
        '''Deal with extra configuration detected'''
        if len(self.pkgwork) > 0:
            if self.setup['remove'] in ['all', 'packages']:
                self.CondPrint('verbose', "Removing packages: %s" % (self.pkgwork['remove']))
                system("/usr/bin/emerge --quiet --nospinner unmerge %s" % " ".join(self.pkgwork['remove']))
            else:
                self.CondPrint('verbose', "Need to remove packages: %s" % (self.pkgwork['remove']))
                if len(self.extra_services) > 0:
                    if self.setup['remove'] in ['all', 'services']:
                        self.CondPrint('verbose', "Removing services: %s" % (self.extra_services))
                        for service in self.extra_services:
                            system("/sbin/rc-update del %s" % service)
                    else:
                        self.CondPrint('verbose', "Need to remove services: %s" % (self.extra_services))