예제 #1
0
 def check_ns(self, *args, **kwargs):
     if len(args) > 1:
         return None
     try:
         ip = socket.gethostbyname(str(args[0]))
         return ip
     except:
         log.warning(u'Fail checking dnsname {}'.format(args[0]))
         return False
예제 #2
0
    def check_n4d(self, *args, **kwargs):
        output = {}
        output[u'N4D_STATUS'] = {u'online': str(self.check_open_port(u'9779'))}
        output[u'N4D_STATUS'].update(
            {u'resolvable': str(self.check_ns(u'server'))})

        try:
            since = self.execute(
                run=
                'systemctl show --value --property=ActiveEnterTimestamp n4d',
                stderr=None)
            status = ''
            status = self.execute(run=[
                'journalctl', '-u', 'n4d', '-o', 'cat', '--no-pager', '-S',
                since, '-q'
            ],
                                  stderr=None,
                                  asroot=True)
            if status:
                status = status.split('\n')
            output['N4D_LAST_LOG'] = status
            if status:
                available = []
                failed = []
                into_plugins = False
                for line in status:
                    line = line.strip()
                    if not into_plugins and re.search(
                            '\[Core\] Initializing plugins', line):
                        into_plugins = True
                    if into_plugins:
                        if re.search('\[Core\] Executing startups', line):
                            break
                        m = re.search(
                            r'(?P<pluginname>\w+)\s+\.{3}\s+(?P<status>\w+)?$',
                            line)
                        if m:
                            d = m.groupdict()
                            if d[u'status'] and d[u'pluginname']:
                                if d[u'status'].lower() == u'ok':
                                    available.append(d[u'pluginname'])
                                else:
                                    failed.append(d[u'pluginname'])
                available = sorted(available)
                failed = sorted(failed)
                output[u'N4D_MODULES'] = {
                    u'available': dict(zip(available, available)),
                    u'failed': dict(zip(failed, failed))
                }
            else:
                log.warning('Cannot get n4d journal')
                output['N4D_MODULES'] = ''
        except Exception as e:
            output[u'N4D_STATUS'].update({u'initlog': u'not available'})
            output[u'N4D_STATUS'].update({u'initlog_error': str(e)})

        return output
예제 #3
0
    def run(self, *args, **kwargs):
        d = {}
        output = {}
        output.setdefault(u'LLIUREX_VERSION', None)
        output[u'ARCHITECTURE'] = self.execute(run=u'arch', stderr=None)
        try:
            os.stat('/usr/bin/lliurex-version')
        except:
            log.warning('/usr/bin/lliurex-version NOT INSTALLED')
            output.update({'LLIUREX_VERSION': 'Non lliurex'})
            output.update({'LLIUREX_RELEASE': 'Non lliurex'})
            output.update({'LLIUREX_SESSION_TYPE': 'Non lliurex'})
            output.update({'HAS_MIRROR': False})
            output.update({'LOGIN_TYPE': 'Unknown'})
            return output

        output.update({
            u'LLIUREX_VERSION':
            self.execute(run=u'lliurex-version -n', stderr=None)
        })
        try:
            for k, v in [
                    x.split(u'=') for x in self.execute(
                        run=u'lliurex-version -a -e', stderr=None).replace(
                            u'\n', u' ').split(u' ')
            ]:
                d[k] = v
        except:
            pass

        output.setdefault(u'LLIUREX_RELEASE', None)
        for x in [
                u'CLIENT', u'DESKTOP', u'SERVER', u'INFANTIL', u'MUSIC',
                u'PIME'
        ]:
            if x in d and d[x].lower() == u'yes':
                output[u'LLIUREX_RELEASE'] = x

        output.setdefault(u'LLIUREX_SESSION_TYPE', None)
        for x in [u'LIVE', u'SEMI', u'FAT', u'THIN']:
            if x in d and d[x].lower() == u'yes':
                output[u'LLIUREX_SESSION_TYPE'] = x

        if u'MIRROR' in d and d[u'MIRROR'].lower() == u'true':
            output[u'HAS_MIRROR'] = True
        else:
            output[u'HAS_MIRROR'] = False

        output.setdefault(u'LOGIN_TYPE', None)
        if u'LOGIN_TYPE' in d:
            output[u'LOGIN_TYPE'] = d[u'LOGIN_TYPE']

        output[u'ARCHITECTURE'] = self.execute(run=u'arch', stderr=None)

        return output
예제 #4
0
 def _kill_proc(self, *args, **kwargs):
     #self._close_stderr()
     try:
         while (args[0].is_alive()):
             args[0].terminate()
             time.sleep(0.01)
         self.nproc -= 1
         log.debug(u'Killed {} remaning procs={}'.format(
             args[0].name, self.nproc))
     except Exception as e:
         log.warning(u'Error while killing {}'.format(args[0]))
예제 #5
0
    def check_exports(self, *args, **kwargs):
        files = []
        if os.path.isfile(u'/etc/exports'):
            files.append(u'/etc/exports')

        if os.path.isdir(u'/etc/exports.d'):
            for file in os.listdir(u'/etc/exports.d/'):
                files.append(u'/etc/exports.d/' + file)
        content = []
        for file in files:
            with open(file, u'r') as f:
                content.extend(self.uncomment(f.read()))
        if content:
            content = u'\n'.join(content)
        else:
            content = None
        needed_services = [
            u'portmapper', u'mountd', u'nfs', u'nlockmgr', u'status'
        ]
        exitting = False
        try:
            os.stat('/usr/bin/rpcinfo')
        except:
            log.warning('/usr/bin/rpcinfo NOT INSTALLED')
            exported = None
            exitting = True

        if not exitting:
            services_running = self.execute(run=u'rpcinfo -p', stderr=None)
            if services_running:
                reg = re.compile(r'\s+\d+\s+\d+\s+\w+\s+\d+\s+(\w+)*',
                                 re.UNICODE)
                for s in services_running.split(u'\n'):
                    m = re.findall(reg, s)
                    if m:
                        if m[0] in needed_services:
                            needed_services.remove(m[0])
            if needed_services:
                needed_services = None
            else:
                needed_services = True
            if needed_services:
                exported = self.execute(run=u'showmount -e --no-headers',
                                        stderr=None)
                if exported:
                    exported = exported.split(u'\n')
                else:
                    exported = None
            else:
                exported = None

        return {u'FILES': files, u'CONTENT': content, u'EXPORTED': exported}
예제 #6
0
 def read_pass(self):
     self.pwd = None
     sfile = u'/etc/ldap.secret'
     try:
         if not os.path.exists(sfile):
             sfile = None
         else:
             with open(sfile, u'r') as f:
                 self.pwd = f.read().strip()
     except:
         if sfile:
             log.warning(
                 u'Running as user, secret file verification is not possible'
             )
         pass
예제 #7
0
 def compress_file(self, *args, **kwargs):
     file = kwargs.get(u'file')
     string = kwargs.get(u'string')
     if not (u'file' in kwargs or u'string' in kwargs):
         log.error(
             u'Compressing called without \'file\' or \'string\' keyparam')
     if file:
         if os.path.exists(file):
             try:
                 with open(file, u'r') as f:
                     try:
                         content = f.read()
                     except:
                         return None
                     try:
                         return (u'__gz__',
                                 base64.b64encode(
                                     zlib.compress(
                                         content.encode(u'utf-8').strip())))
                     except:
                         return (u'__gz__',
                                 base64.b64encode(
                                     zlib.compress(content.strip())))
             except Exception as e:
                 log.warning(u'Fail compressing file {} : {}'.format(
                     file,
                     str(e).decode('utf-8')))
                 return str(u'NOT_READABLE')
     if string:
         try:
             try:
                 return (u'__gz__',
                         base64.b64encode(
                             zlib.compress(
                                 string.encode(u'utf-8').strip())))
             except:
                 return (u'__gz__',
                         base64.b64encode(zlib.compress(string.strip())))
         except Exception as e:
             log.warning(u'Fail compressing string {} : {}'.format(
                 string, e))
             return None
예제 #8
0
    def uncomment(self, *args, **kwargs):
        r = u''
        comments = kwargs.get(u'comments', [u'#'])
        creg = []
        for c in comments:
            creg.append(c + u'.*')
        creg = u'|'.join(creg)
        try:
            is_file = os.path.isfile(args[0])
        except:
            is_file = False
        if is_file:
            reg = re.compile(r'^(\s*|{})*$'.format(creg), re.UNICODE)
            try:
                with open(args[0], u'r') as f:
                    for line in f.readlines():
                        #line=line.decode('utf-8')
                        line = line
                        m = re.match(reg, line)
                        if not m:
                            r += line
            except Exception as e:
                log.warning(u'Trying to read unreadable file {}'.format(
                    args[0]))
                r += str(u'NOT_READABLE')

        else:
            if isinstance(args[0], list):
                string = u''.join(str(args[0]))
            else:
                string = str(args[0])

            reg = re.compile(r'^(\s*|#.*)*$')
            for line in string.split(u'\n'):
                m = re.match(reg, line)
                if not m:
                    r += line + u'\n'
        try:
            r = r.decode(u'utf-8')
        except:
            r = r.encode(u'utf-8').decode(u'utf-8')
        return r.strip()
예제 #9
0
    def get_varlog(self,*args,**kwargs):
        varlog={}
        regexp=re.compile(r'^[^\.]+(\.log|(\.\d+)+)?$',re.UNICODE)
        #filter=lambda x: [ f for f in x if re.match(regexp,f)]

        try:
            #prefix=u'/var/log'
            #file_names=[]
            #for root,dirnames,filenames in os.walk(prefix):
            #    for filename in filter(filenames):
            #        file_names.append(os.path.join(root,filename))
            file_names=self.list_files(path=u'/var/log',regexp=regexp)
            exceptions=[u'/var/log/lastlog',u'/var/log/wtmp',u'/var/log/wtmp.1']
            file_names=[ x for x in file_names if x not in exceptions]
            for file in file_names:
                comp=self.compress_file(file=file)
                if comp:
                    varlog[file]=comp
                else:
                    log.warning(u'Fail compressing logfile {}'.format(file))
        except Exception as e:
            pass
        return varlog
예제 #10
0
    def parse_tree(self, *args, **kwargs):
        if not (isinstance(args[0], str) or isinstance(args[0], str)):
            return None
        output = {}
        lines = args[0].split(u'\n')

        path = output
        atrib = u''
        value = u''
        for line in lines:
            if line == u'':
                path = output
            else:
                if line.startswith(u'dn: '):
                    hierarchy = line[4:].split(u',')
                    hierarchy.reverse()
                    for level in hierarchy:
                        if level not in path:
                            path[level] = {}
                        path = path[level]
                elif line.startswith(u' '):
                    value = value + line[1:]
                    path[atrib][-1] = value
                else:
                    parts = line.split(u' ')
                    atrib = parts[0][:-1]
                    value = u' '.join(parts[1:])
                    if atrib in path:
                        path[atrib].append(value)
                    else:
                        path.update({atrib: [value]})
        if output:
            output = self.make_alias(output)
        else:
            log.warning(u'Can\'t parse ldap tree')
            raise Exception(u'No_ldap_tree')
        return output
예제 #11
0
    def check_open_port(self, *args, **kwargs):
        if len(args) > 2 or len(args) == 0:
            return
        if len(args) == 1:
            port = str(args[0])
            host = u'127.0.0.1'
            m = re.search(r'^\d+$', port)
            if m:
                port = int(args[0])
            else:
                log.warning(
                    u'Trying to check open port with no numerical value host=\'{}\' port\'{}\''
                    .format(host, port))
                return False
        else:
            host = str(args[0])
            #split protocol if there is something
            host = re.findall(r'(?:[^/]+/+)?(.*)$', host)[0]
            m = re.search(r'^(\d+(?:\.\d+){3})$', host)
            if not m:
                if not self.check_ns(host):
                    return False
            port = str(args[1])
            m = re.search(r'^\d+$', port)
            if m:
                port = int(port)
            else:
                log.warning(
                    u'Trying to check open port with no numerical value host=\'{}\' port\'{}\''
                    .format(host, port))
                return False

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(3)
        try:
            res = sock.connect_ex((host, port))
        except:
            log.warning(u'Timeout connection to {}:{}'.format(host, port))
            return None
        finally:
            sock.close()

        if res == 0:
            return True
        else:
            return False
예제 #12
0
 def run(self, *args, **kwargs):
     log.warning(u'Running fake run method from base class')
     pass
예제 #13
0
    def run(self, *args, **kwargs):
        out = {u'LDAP_MASTER_IP': None}
        output = {}
        release = kwargs[u'LLIUREX_RELEASE']
        vars = kwargs[u'N4D_VARS']
        mapping = {u'CLIENT_LDAP_URI': u'SERVER_LDAP'}
        server = None
        localldap = None

        # Guess server ldap uri
        for search_var in mapping:
            if search_var in vars and u'value' in vars[search_var]:
                out.update({mapping[search_var]: vars[search_var][u'value']})
                server = vars[search_var][u'value']
                out.setdefault(u'LOCAL_LDAP', True)
                localldap = True
        if not server:
            ip_server = self.check_ns(u'server')
            try:
                ip_server2 = kwargs[u'NETINFO'][u'gw'][u'via']
            except:
                ip_server2 = None

            if not ip_server:
                log.warning(u'\'server\' not resolvable')
                if ip_server2:
                    server = ip_server2
                    log.warning(
                        u'using gateway trying to guess \'server\' dnsname')
                else:
                    log.warning(u'not detected any gateway')
            else:
                server = ip_server
                if ip_server != ip_server2:
                    log.warning(u'\'server\' is not my gateway')
        if server:
            out.update({u'SERVER_LDAP': server})
            out.update({u'LOCAL_LDAP': False})
            localldap = False
        else:
            out.update({u'SERVER_LDAP': None})
            out.update({u'LOCAL_LDAP': None})
            localldap = None

        self.read_pass()

        output[u'PORTS'] = self.check_ports(server, localldap)
        mode = None

        if output[u'PORTS'][u'636']:
            output[u'CONFIG'] = self.get_ldap_config(release, server)
            mode = u'UNKNOWN'
            try:
                test = output[u'CONFIG'][u'INITIALIZED']
            except:
                mode = u'UNNINITIALIZED'
            try:
                test = output[u'CONFIG'][u'CONFIG'][u'config'][u'{1}mdb'][
                    u'olcSyncrepl']
                test = output[u'CONFIG'][u'CONFIG'][u'config'][u'{1}mdb'][
                    u'olcUpdateRef']
                mode = u'SLAVE'
                if output[u'CONFIG'][u'CONFIG'][u'config'][u'{1}mdb'][
                        u'olcSyncrepl'][0]:
                    m = re.search(
                        r'provider=ldapi?://(?P<LDAP_MASTER_IP>\d+\.\d+\.\d+\.\d+)u',
                        output['CONFIG']['CONFIG']['config']['{1}mdb']
                        ['olcSyncrepl'][0])
                    if m:
                        out.update(m.groupdict())
            except:  # indep or (master/slave(running without permissions))
                mode = u'INDEPENDENT'
                netinfo = kwargs[u'NETINFO']
                if netinfo:
                    aliased_interfaces = [
                        k for k in netinfo if isinstance(netinfo[k], dict) and
                        u'nalias' in netinfo[k] and netinfo[k][u'nalias'] > 0
                    ]

                    for i in aliased_interfaces:
                        for n in range(netinfo[i][u'nalias']):
                            if u'alias' + str(n +
                                              1) + u'_ifaddr' in netinfo[i]:
                                ip_alias = netinfo[i][
                                    u'alias' + str(n + 1) +
                                    u'_ifaddr'].split(u'.')[3].split(u'/')[0]
                                if ip_alias == u'1':
                                    mode = u'SLAVE'
                                elif ip_alias == u'254':
                                    mode = u'MASTER'
                            if not out['LDAP_MASTER_IP'] and mode in [
                                    'SLAVE', MASTER
                            ]:
                                out['LDAP_MASTER_IP'] = netinfo[i][
                                    u'alias' + str(n + 1) +
                                    u'_ifaddr'].split('/')[0]
                    if not aliased_interfaces:
                        phys_ifaces = [
                            dev for dev in netinfo
                            if isinstance(netinfo[dev], dict) and 'ifaddr' in
                            netinfo[dev] and netinfo[dev]['ifaddr']
                        ]
                        for dev in phys_ifaces:
                            ip = netinfo[dev]['ifaddr']
                            ip = ip.split('/')
                            octets = ip[0].split('.')
                            if octets[0] == '10' and octets[1] == '3':
                                if octets[3] == '1':
                                    mode = 'SLAVE'
                                elif octets[3] == '254':
                                    mode = 'MASTER'
                            if not out['LDAP_MASTER_IP'] and mode in [
                                    'SLAVE', 'MASTER'
                            ]:
                                out['LDAP_MASTER_IP'] = '.'.join(octets)

        output[u'FILES'] = self.check_files(release, mode, server)
        out.update({u'LDAP_INFO': output, u'LDAP_MODE': mode})

        return out
예제 #14
0
    def execute(self, timeout=3.0, shell=False, *args, **kwargs):
        params = {}
        if u'run' not in kwargs:
            log.error(u'Execute called without \'run\' key parameter')
            return None
        else:
            if not isinstance(kwargs[u'run'], list):
                runlist = kwargs[u'run'].split(u' ')
            else:
                runlist = kwargs[u'run']
        timeout_remaning = float(timeout)
        #Ready for python3
        #params.setdefault(u'timeout',int(timeout))
        #Python 2 code
        delay = 0.1
        if u'stderr' in kwargs:
            if kwargs[u'stderr'] == u'stdout':
                params.setdefault(u'stderr', subprocess.STDOUT)
            if kwargs[u'stderr'] == None or kwargs[u'stderr'] == u'no':
                params.setdefault(u'stderr', open(os.devnull, u'w'))
            else:
                params.setdefault(u'stderr', subprocess.PIPE)
        else:
            params.setdefault(u'stderr', subprocess.PIPE)
        params.setdefault(u'stdout', subprocess.PIPE)
        with_uncomment = False
        if u'nocomment' in kwargs:
            if kwargs[u'nocomment'] == True or kwargs[u'nocomment'] == u'yes':
                with_uncomment = True

        myinfo = pwd.getpwuid(os.geteuid())
        user = myinfo.pw_name
        group = grp.getgrgid(myinfo.pw_gid).gr_name
        root_mode = False
        if self.check_root():
            if u'asroot' in kwargs:
                if kwargs[u'asroot'] == True or kwargs[u'asroot'] == u'yes':
                    root_mode = True
            if not root_mode:
                params.setdefault(u'preexec_fn', self.demote)
                user = u'nobody'
                group = u'nogroup'
            else:
                params.setdefault(u'preexec_fn', self.set_root_ids)
        else:
            if kwargs.get('asroot') == True:
                log.warning('Can\'t use rootmote execution for: \'{}\''.format(
                    ' '.join(runlist)))

        params.setdefault(u'shell', shell)
        stdout = None
        stderr = None
        log.info(u'Executing command \'{}\' as {}:{}'.format(
            u' '.join(runlist), user, group))
        try:
            start = time.time()
            p = subprocess.Popen(runlist, **params)
            ret = p.poll()
            while ret is None and timeout_remaning > 0:
                time.sleep(delay)
                timeout_remaning -= delay
                stdout, stderr = p.communicate()
                ret = p.poll()
            if stdout is None:
                stdout, stderr = p.communicate()
            if timeout_remaning <= 0:
                raise Exception(
                    u'timeout({}) exceded while executing {}'.format(
                        timeout, kwargs[u'run']))
            if ret != 0:
                if stderr != u'':
                    stderr = u'stderr={}'.format(stderr)
                log.warning(
                    u'Execution with exit code {} (possible error) {}'.format(
                        ret, stderr))
        except Exception as e:
            log.error(u'Error executing: {}'.format(e))
            return None
        if stdout != None:
            if with_uncomment:
                out = self.uncomment(stdout.strip())
            else:
                out = stdout.strip()
            try:
                out = out.decode(u'utf-8')
            except UnicodeDecodeError:
                out = out.encode(u'utf-8')
            return out
        else:
            log.error(
                u'Execution of {} hasn\'t produced any result, returning None'.
                format(kwargs['run']))
            return None
예제 #15
0
    def run(self, *args, **kwargs):
        ret = True
        if not self.is_classified:
            if not self._classify(**kwargs):
                ret = False
        else:
            log.info(u'Running all plugins')

        if not self.START_RUNNING_TIME:
            self.START_RUNNING_TIME = time.time()

        procs = [None] * self.MAX_PROCESSES
        done = None
        remaning = copy.copy(self.order)
        started = []
        self.capabilities_stored = []
        if self.fake_capabilities:
            for x in self.fake_capabilities.keys():
                self.capabilities_stored.append(x)
        while done == None and not self.aborting:
            #start processes
            for plug in self.order:
                if done == False:  #recalculation in process
                    break
                if procs[self.order.index(plug)] == None:
                    can_start = False
                    if self.pm.classes[plug]._NEEDS:
                        for need in self.pm.classes[plug]._NEEDS:
                            if need:
                                if need in self.capabilities.keys(
                                ) and need in self.capabilities_stored:
                                    can_start = True
                                else:
                                    can_start = False
                                    break
                    else:
                        can_start = True

                    if can_start:
                        pipe_in, pipe_out = Pipe(duplex=False)
                        #kw = {u'out': pipe_out,u'stderr':open(os.devnull,u'w')}
                        kw = {u'out': pipe_out}
                        args = (pipe_out, )
                        obj = self.pm.classes[plug]()

                        for need in obj._NEEDS:
                            if need and need in self.capabilities.keys():
                                if need.lower()[0:6] == u'helper':
                                    f = pickle.loads(self.helpers[need])
                                    dummy_func = types.FunctionType(
                                        f[u'code'].__code__, f[u'glob'],
                                        f[u'code'].__code__.co_name)
                                    dummy_func.__globals__.update(
                                        {u'self': f[u'code'].__self__})
                                    obj.__dict__[f[u'code'].__code__.
                                                 co_name] = dummy_func
                                    setattr(obj, f[u'code'].__code__.co_name,
                                            f[u'code'])
                                    log.debug(
                                        u'Helper {} registered into {}'.format(
                                            need, obj.__class__.__name__))
                                else:
                                    if self.capabilities[need] == None:
                                        log.warning(
                                            u'Providing capability {} with an empty value to {} plugin'
                                            .format(need,
                                                    obj.__class__.__name__))
                                    kw.update({need: self.capabilities[need]})
                                    args = args + (self.capabilities[need], )

                        procs[self.order.index(plug)] = {
                            u'process':
                            Process(target=obj._run,
                                    name=plug,
                                    args=args,
                                    kwargs=kw),
                            u'name':
                            plug,
                            u'stime':
                            None,
                            u'rtime':
                            None,
                            u'pin':
                            pipe_in,
                            u'pout':
                            pipe_out
                        }
                        if not self.aborting:
                            procs[self.order.index(plug)][u'process'].start()
                            procs[self.order.index(
                                plug)][u'stime'] = time.time()
                            started.append(plug)
                            self.nproc += 1
                            self.nproc_started += 1
                            log.debug(u'Started process number={} ({})'.format(
                                self.nproc_started, plug))

            # check processes
            for pinfo in procs:
                if done == False:  # recalculation in progress
                    break
                if pinfo and pinfo[u'stime']:
                    t = time.time() - pinfo[u'stime']
                    if self.MAX_RUNNING_TIME and t > self.MAX_RUNNING_TIME and not pinfo[
                            u'rtime']:
                        self._kill_proc(pinfo[u'process'])
                        pinfo[u'rtime'] = t
                        log.error(
                            u'Plugin {} aborted, maximun running time ({}) exceded'
                            .format(pinfo[u'name'], self.MAX_RUNNING_TIME))
                        if self.all_plugins_are_needed:
                            log.error(
                                u'Unable to continue, all plugins are needed to run properly'
                            )
                            self.aborting = True
                        del self.pm.classes[pinfo[u'name']]
                        log.debug(
                            u'Plugin {} deactivated, recalculating dependencies & rerunning'
                            .format(pinfo[u'name']))
                        done = False
                        ret = False
                        break
                    if pinfo[u'pin'].poll():
                        pinfo[u'rtime'] = t
                        output = pinfo[u'pin'].recv()
                        pinfo[u'process'].join()
                        self.nproc -= 1
                        log.debug(u'Finished {}'.format(pinfo[u'name']))
                        for provide in self.pm.classes[
                                pinfo[u'name']]._PROVIDES:
                            if provide:
                                if output and type(output) == type(
                                        dict()) and provide in output.keys():
                                    #out_stripped=str(output[provide]).upper().replace(u'NULL',u'null').strip()
                                    out_stripped = output[provide]
                                    if provide[0:6].lower() == u'helper':
                                        self.helpers[provide] = out_stripped
                                        out_stripped = u'STORED'
                                    if provide in self.capabilities.keys(
                                    ) and self.capabilities[provide] != None:
                                        log.warning(
                                            u'Plugin {} overwrite {} capability'
                                            .format(pinfo[u'name'], provide))
                                    else:
                                        log.debug(
                                            u'Plugin {} set the capability \'{}\' with value \'{}\' in {}'
                                            .format(pinfo[u'name'], provide,
                                                    out_stripped,
                                                    pinfo[u'rtime']))
                                    if out_stripped == None:
                                        log.warning(
                                            u'Capability {} was stored with and empty value of {}'
                                            .format(provide,
                                                    str(out_stripped)))
                                    self.capabilities[provide] = out_stripped
                                    self.capabilities_stored.append(provide)
                                else:  # provide not in output
                                    if provide in self.capabilities_stored:
                                        log.info(
                                            u'Plugin {} was provided by unknown instead of {}, recalculate not needed'
                                            .format(provide, pinfo[u'name']))
                                    else:
                                        log.error(
                                            u'Plugin {} mus\'t provide {} which wasn\'t available into result'
                                            .format(pinfo[u'name'], provide))
                                        if self.all_plugins_are_needed:
                                            log.error(
                                                u'Unable to continue, all plugins are needed to run properly'
                                            )
                                            self.aborting = True
                                        del self.pm.classes[pinfo[u'name']]
                                        log.debug(
                                            u'Plugin {} deactivated, recalculating dependencies & rerunning'
                                            .format(pinfo[u'name']))
                                        done = False
                                        ret = False
                                        break
                        remaning.remove(pinfo[u'name'])

                    elif not pinfo[u'rtime'] and not pinfo[
                            u'process'].is_alive():
                        log.error(
                            u'Plugin {} dead without sending results'.format(
                                pinfo[u'name']))
                        if self.all_plugins_are_needed:
                            log.error(
                                u'Unable to continue, all plugins are needed to run properly'
                            )
                            self.aborting = True
                        self.nproc -= 1
                        del self.pm.classes[pinfo[u'name']]
                        log.debug(
                            u'Plugin {} deactivated, recalculating dependencies & rerunning'
                            .format(pinfo[u'name']))
                        done = False
                        ret = False

                    if done == False or self.aborting:
                        for pinfo2 in procs:
                            if pinfo2 and pinfo2[u'stime'] and pinfo2[
                                    u'process'].is_alive():
                                self._kill_proc(pinfo2[u'process'])
                                pinfo2[u'rtime'] = t
                                if self.aborting:
                                    log.debug(
                                        u'Aborting... terminating process {}'.
                                        format(pinfo2[u'name']))
                                else:
                                    log.debug(
                                        u'Terminating process {} due recalculation in process'
                                        .format(pinfo2[u'name']))

            if done != False:
                if len(remaning) > 0:
                    still = [p for p in remaning if p in started]
                    log.debug(u'Endloop plugins still running: {}'.format(
                        u','.join(still)))
                else:
                    log.debug(u'No more plugins to run!')
                #check all finished (done=True) or wait to next round for start & check (done=None)
                done = True
                for pinfo in procs:
                    if not pinfo or pinfo[u'rtime'] == None:
                        done = None
                        timesleep = 0.01
                        if log.level < 20:
                            timesleep = 0.5
                        time.sleep(timesleep)
                        break

        if done == False:
            # kill all plugins currently running
            for p in procs:
                if p and p[u'stime'] and p[u'process'].is_alive():
                    self._kill_proc(p[u'process'])
                    p[u'rtime'] = t
                    log.debug(
                        u'Terminating process {} before recalculation in process'
                        .format(p[u'name']))
            if not self.aborting:
                self._classify(**kwargs)
                self.run()
        else:
            # when loop start+check finish must have all process completed
            clasifying_success = [x for x in procs if x != None]
            if clasifying_success:
                for i in range(0, len(procs)):
                    #if procs[i] == None:
                    if not (procs[i] and procs[i][u'rtime']):
                        log.error(
                            u'Plugin {} can\'t be started, previous plugin fail providing dependencies'
                            .format(self.order[i]))
                        if self.all_plugins_are_needed:
                            log.error(
                                u'Unable to continue, all plugins are needed to run properly'
                            )
                            self.aborting = True
                        ret = False
                        break
        if not self.RUNNING_TIME:
            self.RUNNING_TIME = time.time() - self.START_RUNNING_TIME

        return ret
예제 #16
0
    def run(self, *args, **kwargs):
        output = {}
        LDAP_INFO = kwargs[u'LDAP_INFO']
        LLIUREX_RELEASE = str(kwargs[u'LLIUREX_RELEASE']).lower()
        logged_users = self.users_logged()
        myinfo = self.who_i_am()

        try:
            people = LDAP_INFO[u'CONFIG'][u'DB'][u'net'][u'lliurex'][u'ma5'][
                u'People']
            users = [(x, people[u'Students'][x])
                     for x in people[u'Students'].keys()
                     if isinstance(people[u'Students'][x], dict)]
            admins = [(x, people[u'Admins'][x])
                      for x in people[u'Admins'].keys()
                      if isinstance(people[u'Admins'][x], dict)]
            teachers = [(x, people[u'Teachers'][x])
                        for x in people[u'Teachers'].keys()
                        if isinstance(people[u'Teachers'][x], dict)]
        except Exception as e:
            log.warning(
                u'Fail getting needed ldap information, using fake information only for current user'
            )
            people = None  # NO LDAP ACCESS DO IT ONLY FOR ME
            fake_ldap_info = (myinfo[u'name'], {
                u'homeDirectory': [myinfo[u'user_info'][5]],
                u'uid': [myinfo[u'name']]
            })
            users = []
            admins = []
            teachers = []
            try:
                if str(kwargs[u'LOGIN_TYPE']).lower() == u'ldap':
                    if u'students' in myinfo[u'groups']:
                        users.append(fake_ldap_info)
                    elif u'teachers' in myinfo[u'groups']:
                        teachers.append(fake_ldap_info)
                    elif u'admins' in myinfo[u'groups']:
                        admins.append(fake_ldap_info)
            except Exception as e:
                log.error(e)

        # USER TEST FUNCTIONALITY

        homes = [u'/home/' + x for x in os.listdir(u'/home/')]
        cmd = [u'getfacl', u'-tp'] + homes
        perm_info = self.execute(run=cmd, stderr=None).split(u'\n')
        perm_dirs = {}
        i = -1
        file = None
        while i < len(perm_info) - 1:
            i += 1
            line = perm_info[i]
            if line.startswith(u'#'):
                # complete previous if exists
                if file:
                    if perm_dirs[file][u'group'] or perm_dirs[file][u'user']:
                        perm_dirs[file][u'USE_ACLS'] = True
                    else:
                        perm_dirs[file][u'USE_ACLS'] = False
                file = line[8:]
                perm_dirs[file] = {
                    u'USER': {},
                    u'GROUP': {},
                    u'user': {},
                    u'group': {},
                    u'other': {},
                    u'mask': {}
                }
                continue
            if line != u'':
                field = [x for x in line.split(u' ') if x != u'']
                if field[0] in [u'other', u'mask']:
                    perm_dirs[file][field[0]] = field[1]
                else:
                    perm_dirs[file][field[0]][field[1]] = field[2]
        if users:
            for (u, udata) in users:
                #TEST HOME
                if os.path.exists(udata[u'homeDirectory'][0]):
                    output[u] = {u'HAS_HOME': True}

                    homedir = udata[u'homeDirectory'][0]
                    user = udata[u'uid'][0]

                    try:
                        output[u][u'PERM_OK']=\
                            perm_dirs[homedir][u'USER'][user] == u'rwx' \
                            and perm_dirs[homedir][u'user'][user] == u'rwx' \
                            and perm_dirs[homedir][u'GROUP'][u'nogroup'] == u'r-x' \
                            and perm_dirs[homedir][u'group'][u'students'] == u'---' \
                            and perm_dirs[homedir][u'group'][u'teachers'] == u'rwx' \
                            and perm_dirs[homedir][u'group'][u'admins'] == u'rwx' \
                            and perm_dirs[homedir][u'other'] == u'---'
                    except:
                        output[u][u'PERM_OK'] = False

                    if u in logged_users:
                        output[u][u'MOUNTS_OK'] = self.check_mounts(
                            u, u'student', **kwargs)
                    else:
                        output[u][u'MOUNTS_OK'] = (None, [u'NOT_LOGGED_IN'])
                else:
                    output[u] = {u'HAS_HOME': False}

        # TEACHERS
        if teachers:
            for (u, udata) in teachers:
                #TEST HOME
                if os.path.exists(udata[u'homeDirectory'][0]):
                    output[u] = {u'HAS_HOME': True}

                    homedir = udata[u'homeDirectory'][0]
                    user = udata[u'uid'][0]

                    try:
                        output[u][u'PERM_OK']=\
                            perm_dirs[homedir][u'USER'][user] == u'rwx' \
                            and perm_dirs[homedir][u'user'][user] == u'rwx' \
                            and perm_dirs[homedir][u'GROUP'][u'nogroup'] == u'r-x' \
                            and perm_dirs[homedir][u'group'][u'teachers'] == u'---' \
                            and perm_dirs[homedir][u'group'][u'admins'] == u'rwx' \
                            and perm_dirs[homedir][u'other'] == u'---'
                    except:
                        output[u][u'PERM_OK'] = False

                    if u in logged_users:
                        output[u][u'MOUNTS_OK'] = self.check_mounts(
                            u, u'teacher', **kwargs)
                    else:
                        output[u][u'MOUNTS_OK'] = (None, [u'NOT_LOGGED_IN'])

                else:
                    output[u] = {u'HAS_HOME': False}

        # ADMINS
        if admins:
            for (u, udata) in admins:
                #TEST HOME
                if os.path.exists(udata[u'homeDirectory'][0]):
                    output[u] = {u'HAS_HOME': True}

                    homedir = udata[u'homeDirectory'][0]
                    user = udata[u'uid'][0]

                    try:
                        output[u][u'PERM_OK']=\
                            perm_dirs[homedir][u'USER'][user] == u'rwx' \
                            and perm_dirs[homedir][u'user'][user] == u'rwx' \
                            and perm_dirs[homedir][u'GROUP'][u'nogroup'] == u'r-x' \
                            and perm_dirs[homedir][u'group'][u'admins'] == u'rwx' \
                            and perm_dirs[homedir][u'other'] == u'---'
                    except:
                        output[u][u'PERM_OK'] = False

                    if u in logged_users:
                        output[u][u'MOUNTS_OK'] = self.check_mounts(
                            u, u'admin', **kwargs)
                    else:
                        output[u][u'MOUNTS_OK'] = (None, [u'NOT_LOGGED_IN'])

                else:
                    output[u] = {u'HAS_HOME': False}

        return {u'USERS_INFO': perm_dirs, u'USER_TEST': output}
예제 #17
0
    def _classify(self, *args, **kwargs):
        run_needs = []
        resolved_needs = []
        free_add_plugins = []
        self.all_needs = []
        self.all_provides = []

        if u'needs' in kwargs:
            run_needs = kwargs[u'needs']
            need_run_plugin = []

        self.capabilities = {}
        self.order = []
        pending = []

        empty_provides = []

        for classname in self.pm.classes:
            class_provides = self.pm.classes[classname]._PROVIDES
            class_needs = self.pm.classes[classname]._NEEDS

            log.debug(u'Class: {} needs {}'.format(classname, class_needs))
            log.debug(u'Class: {} provides {}'.format(classname,
                                                      class_provides))

            for x in class_provides:
                if x not in self.mapping:
                    self.mapping[x] = {u'PROVIDED': [classname], u'NEEDED': []}
                else:
                    self.mapping[x][u'PROVIDED'].append(classname)
            for x in class_needs:
                if x not in self.mapping:
                    self.mapping[x] = {u'PROVIDED': [], u'NEEDED': [classname]}
                else:
                    self.mapping[x][u'NEEDED'].append(classname)

            self.all_provides.extend(
                x for x in self.mapping
                if self.mapping[x][u'PROVIDED'] and x not in self.all_provides)
            self.all_needs.extend(
                x for x in self.mapping
                if self.mapping[x][u'NEEDED'] and x not in self.all_needs)
            #self.all_provides.extend([x for x in self.pm.classes[classname]._PROVIDES if x not in self.all_provides])
            #self.all_needs.extend([x for x in self.pm.classes[classname]._NEEDS if x not in self.all_needs])

            if class_provides == None or class_needs == None:
                log.warning(
                    u'Plugin {} with empty provides and needs, maybe it\'s using base class attributes !!! disabling plugin...'
                    .format(classname))
                if self.all_plugins_are_needed:
                    log.error(
                        u'Unable to continue, all plugins are needed to run properly'
                    )
                    self.aborting = True
                empty_provides.append(classname)
                continue
            # Disable plugins that not provides nothing
            if not class_provides:
                log.warning(
                    u'Plugin {} disabled because not providing anything!'.
                    format(classname))
                if self.all_plugins_are_needed:
                    log.error(
                        u'Unable to continue, all plugins are needed to run properly'
                    )
                    self.aborting = True
                empty_provides.append(classname)
                continue
            # Add plugins that only provides
            if not class_needs and class_provides:
                free_add_plugins.append(classname)
                if not run_needs:
                    add = True
                else:
                    add = False
                    for x in run_needs:
                        if x in class_provides:
                            add = True
                            break
                if add:
                    self.order.append(classname)
                    for x in class_provides:
                        if x:
                            self.capabilities[x] = None
                else:
                    pending.append(classname)
            else:
                for x in run_needs:
                    if x in class_provides:
                        need_run_plugin.append(classname)
                        resolved_needs.extend(class_needs)
                pending.append(classname)

        missing = [
            x for x in self.all_needs
            if x not in [y for y in self.all_provides]
        ]
        not_necessary = [
            x for x in self.all_provides
            if x not in [y for y in self.all_needs]
        ]

        if not_necessary:
            log.info(u'Provided {} not used by anybody'.format(
                u','.join(not_necessary)))

        for i in empty_provides:
            log.warning(u'Disabling class {} not providing anything'.format(i))
            if self.all_plugins_are_needed:
                log.error(
                    u'Unable to continue, all plugins are needed to run properly'
                )
                self.aborting = True
            del self.pm.classes[i]

        for x in missing:
            log.error(u'Need {} not provided by any plugin'.format(x))
            if self.all_plugins_are_needed:
                log.error(
                    u'Unable to continue, all plugins are needed to run properly'
                )
                self.aborting = True
            for pl in self.mapping[x][u'NEEDED']:
                if pl in self.pm.classes:
                    del self.pm.classes[pl]
                    self.mapping[x][u'NEEDED'].remove(pl)
                    pending.remove(pl)

        if self.fake_capabilities:
            for x in self.fake_capabilities:
                self.capabilities[x] = self.fake_capabilities[x]

        if run_needs:
            for nr in need_run_plugin:
                add = False
                class_needs = self.pm.classes[nr]._NEEDS
                class_provides = self.pm.classes[nr]._PROVIDES
                for need in class_needs:
                    if need not in self.capabilities:
                        for fp in free_add_plugins:
                            if fp not in self.order and need in class_provides:
                                add = fp
                                break
                        if add and add not in self.order:
                            self.order.append(add)
                            resolved_needs.extend(class_needs)
                            for x in class_provides:
                                if x:
                                    self.capabilities[x] = None
                            if add in pending:
                                pending.remove(add)

        #Resolve other dependencies
        still_ordering = True
        if not run_needs:
            still_missing_for_run = True
        else:
            still_missing_for_run = False
        for x in resolved_needs:
            if x not in self.capabilities:
                still_missing_for_run = True
                break

        while pending != [] and still_ordering and still_missing_for_run and not self.aborting:
            still_ordering = False  # Detect full loop without changing anything
            to_remove = []
            more_needs = []
            if not run_needs:
                for classname in pending:
                    add = classname
                    for need in self.pm.classes[classname]._NEEDS:
                        if need:  #avoid empty
                            if need not in self.capabilities:
                                add = None
                                break

                    if add:  # class has resolved all needs
                        #pending.remove(classname)
                        to_remove.append(add)
                        self.order.append(add)
                        #resolved_needs.extend(self.pm.classes[classname]._PROVIDES)
                        for x in self.pm.classes[add]._PROVIDES:
                            if x:
                                self.capabilities[x] = None
            else:
                for need in resolved_needs:
                    if need not in self.capabilities:
                        for classname in pending:
                            add = classname
                            if need in self.pm.classes[classname]._PROVIDES:
                                for x in self.pm.classes[classname]._NEEDS:
                                    if x:
                                        if x not in self.capabilities:
                                            add = None
                                            more_needs.append(x)

                                if add:
                                    to_remove.append(add)
                                    self.order.append(add)
                                    for x in self.pm.classes[add]._PROVIDES:
                                        if x:
                                            self.capabilities[x] = None
            log.debug(u'Endloop classifier')

            for r in to_remove:
                if r in pending:
                    pending.remove(r)
                    still_ordering = True

            for n in more_needs:
                if n not in resolved_needs:
                    resolved_needs.append(n)
                    still_ordering = True

            if still_ordering == False:  # none of pending plugins can satisfy more dependencies
                if run_needs:
                    not_found = []
                    for x in resolved_needs:
                        if x not in self.capabilities:
                            not_found.append(x)

                    if not_found:
                        if self.is_classified:
                            str = u'couldn\'t satisfy all dependencies for needed plugin'
                        else:
                            if self.pm.found_duplicates:
                                str = u'maybe missing dependency?'
                            else:
                                str = u'maybe ciclic dependency?'

                            # Get plugins related to cycle
                            related = []
                            for plug in self.pm.classes:
                                for prov in self.pm.classes[plug]._PROVIDES:
                                    if prov in not_found and plug not in related:
                                        related.append(plug)

                            str += u'\nPlugins related with cycle: {}'.format(
                                u','.join(related))

                        log.error(
                            u'Unable to continue, {} !!!\nNotFound providers for ({})'
                            .format(str, u','.join(not_found)))
                        self.aborting = True
                    else:
                        for pl in need_run_plugin:
                            add = pl
                            for need in self.pm.classes[pl]._NEEDS:
                                if need not in self.capabilities:
                                    add = None
                                    break
                            if not add:
                                log.error(
                                    u'Disabling class {} needed to run due to unresolved dependencies'
                                    .format(pending_class))
                                self.aborting = True
                                break
                            else:
                                self.order.append(add)
                else:
                    for pending_class in pending:
                        log.warning(
                            u'Disabling class {} due to unresolved dependencies'
                            .format(pending_class))
                        if self.all_plugins_are_needed:
                            log.error(
                                u'Unable to continue, all plugins are needed to run properly'
                            )
                            self.aborting = True
                            break
                        del self.pm.classes[pending_class]

        self.MAX_PROCESSES = len(self.order)
        log.info(u'Plugin order calculated: {}'.format(u','.join(self.order)))
        self.is_classified = True
        if self.aborting:
            return False
        else:
            return True