示例#1
0
 def test_add_actions(self):
     """Test the possibility to add multiple actions at the same time"""
     service = Service('SERV')
     act_a = Action('start', command='/bin/true')
     act_b = Action('stop', command='/bin/true')
     act_c = Action('status', command='/bin/true')
     service.add_actions(act_a, act_b, act_c)
     self.assertTrue(service.has_action('start'))
     self.assertTrue(service.has_action('stop'))
     self.assertTrue(service.has_action('status'))
示例#2
0
 def test_add_actions(self):
     """Test the possibility to add multiple actions at the same time"""
     service = Service('SERV')
     act_a = Action('start', command='/bin/true')
     act_b = Action('stop', command='/bin/true')
     act_c = Action('status', command='/bin/true')
     service.add_actions(act_a, act_b, act_c)
     self.assertTrue(service.has_action('start'))
     self.assertTrue(service.has_action('stop'))
     self.assertTrue(service.has_action('status'))
示例#3
0
 def test_remove_action(self):
     """Test remove_action behaviour."""
     service = Service('brutus')
     service.add_action(Action('start'))
     service.remove_action('start')
     self.assertFalse(service.has_action('start'))
     self.assertRaises(ActionNotFoundError, service.remove_action, 'start')
示例#4
0
 def test_add_action(self):
     """Test add_action's behaviour."""
     service = Service('brutus')
     service.add_action(Action('start'))
     self.assertTrue(service.has_action('start'))
     self.assertRaises(ActionAlreadyReferencedError, service.add_action,
                       Action('start'))
     self.assertRaises(TypeError, service.add_action, None)
示例#5
0
 def test_remove_action(self):
     """Test remove_action behaviour."""
     service = Service('brutus')
     service.add_action(Action('start'))
     service.remove_action('start')
     self.assertFalse(service.has_action('start'))
     self.assertRaises(ActionNotFoundError,
         service.remove_action, 'start')
示例#6
0
 def test_add_action(self):
     """Test add_action's behaviour."""
     service = Service('brutus')
     service.add_action(Action('start'))
     self.assertTrue(service.has_action('start'))
     self.assertRaises(ActionAlreadyReferencedError,
             service.add_action,Action('start'))
     self.assertRaises(TypeError,
             service.add_action,None)
示例#7
0
class ServiceManager(EntityManager):
    '''
    The service manager has to handle call to services. It implements
    features allowing us to get dependencies of service and so on.
    '''

    def __init__(self):
        EntityManager.__init__(self)
        # Variables declared in the global scope
        self.variables = {}
        # Top service
        self.source = Service('root')
        self.source.simulate = True

    def __refresh_graph(self, reverse):
        '''Reinitialize the right values for the graph of services'''
        for service in self.entities.values():
            service.reset()
        if reverse:
            self.source.clear_child_deps()
        else:
            self.source.clear_parent_deps()

    def has_service(self, service):
        '''Determine if the service is registered within the manager'''
        return service in self.entities.values()

    def has_warnings(self):
        '''Determine if the service has one action with the WARNING status'''
        for ent in self.entities.values():
            if ent.status is WARNING:
                return True
        return False

    def add_var(self, varname, value):
        '''Add a symbol within the service manager'''
        if varname not in self.variables:
            self.variables[varname] = value
        else:
            raise VariableAlreadyExistError("'%s' already defined" % varname)

    def remove_var(self, varname):
        '''Remove var from the the service manager'''
        if varname in self.variables:
            del self.variables[varname]

    def reset(self):
        '''Clean object service manager.'''
        self.variables.clear()
        self.entities.clear()

    def register_service(self, service):
        '''Add a new service to the manager.'''
        assert service, 'service added cannot be None'
        if service.name in self.entities:
            raise ServiceAlreadyReferencedError(service.name)
        else:
            self.entities[service.name] = service

    def register_services(self, *args):
        '''Add all services referenced by args'''
        for service in args:
            self.register_service(service)
        
    def forget_service(self, service):
        '''
        Remove the service from the manager. It takes care of the relations
        with others services in order to avoid to get a graph with a bad format.
        '''
        assert service, 'The service that you want to forget cannot be None'
        if not self.has_service(service):
            raise ServiceNotFoundError
        else:
            dependencies = []
            switch = len(service.children)
            dependencies.extend(service.children.values())
            dependencies.extend(service.parents.values())
            for dep in dependencies:
                switch -= 1
                if switch > 0:
                    service.remove_dep(dep.target.name, parent=False)
                else:
                    service.remove_dep(dep.target.name)
            del self.entities[service.name]

    def forget_services(self, *args):
        '''Remove all specified services from the manager'''
        for service in args:
            self.forget_service(service)

    def _variable_config(self, conf):
        '''Automatic variables based on MilckCheck configuration.'''
        if conf:
            # -n NODES
            self.add_var('SELECTED_NODES', str(conf.get('only_nodes', '')))
            # -x NODES
            self.add_var('EXCLUDED_NODES', str(conf.get('excluded_nodes', '')))

            # Add command line variable
            for defines in conf.get('defines', []):
                for define in defines.split():
                    key, value = define.split('=', 1)
                    self.add_var(key, value)
        else:
            for varname in ('selected_node', 'excluded_nodes'):
                self.add_var(varname.upper(), '')

    def _apply_config(self, conf):
        '''
        This apply a sequence of modifications on the graph. A modification
        can be an update of the nodes usable by the services or whatever that
        is referenced within configuration.
        '''

        # Load the configuration located within the directory
        if conf.get('config_dir'):
            self.entities.clear()
            self.load_config(conf['config_dir'])

        # Avoid some of the services referenced in the graph
        if conf.get('excluded_svc'):
            self.__lock_services(conf['excluded_svc'])

        # Use just those nodes 
        if conf.get('only_nodes') is not None:
            self.__update_usable_nodes(conf['only_nodes'], 'INT')
        # Avoid those nodes
        elif conf.get('excluded_nodes') is not None:
            self.__update_usable_nodes(conf['excluded_nodes'], 'DIF')

    def __lock_services(self, services):
        '''
        Lock all services specified in the list. This will assign the LOCKED
        status on the services. A soon as a service is locked it will never be
        processed.
        '''
        for service in services:
            if service in self.entities:
                self.entities[service].status = LOCKED

    def _lock_services_except(self, services):
        """Lock all services except those provided."""
        for service in self.entities:
            if service not in services:
                self.entities[service].status = LOCKED

    def __update_usable_nodes(self, nodeset, mode=None):
        '''
        Update target value used by the service and the elements linked to
        the service.
        '''
        assert mode in (None, 'DIF', 'INT'), \
            'Invalid mode, should be DIF, INT or None'
        for service in self.entities.values():
            service.update_target(nodeset, mode)

    def call_services(self, services, action, conf=None):
        '''Allow the user to call one or multiple services.'''
        assert action, 'action name cannot be None'

        # Manage reverse mode based on configuration
        reverse = False
        if conf:
            reverse = action in conf.get('reverse_actions')

        self.variables.clear()

        # Create global variable from configuration
        self._variable_config(conf)

        # Make sure that the graph is usable
        self.__refresh_graph(reverse)
        # Apply configuration over the graph
        if conf:
            self._apply_config(conf)

        self.source.reset()
        # Enable reverse mode if needed
        self._reverse_mod(reverse)
        self.source.algo_reversed = reverse

        if not self.source.has_action(action):
            self.source.add_action(Action(name=action, command=':'))
        # Perform all services
        if not services:
            for service in self.entities.values():
                if reverse and not service.parents:
                    service.add_dep(target=self.source)
                elif not reverse and not service.children:
                    self.source.add_dep(target=service)
        # Perform required services
        else:
            for service_name in services:
                if service_name in self.entities:
                    if reverse:
                        self.entities[service_name].add_dep(target=self.source)
                    else:
                        self.source.add_dep(target=self.entities[service_name])
                else:
                    raise ServiceNotFoundError('Undefined service [%s]'
                        % service_name)

        if conf and conf.get('nodeps'):
            self._lock_services_except(self.source.deps().keys())

        self.source.run(action)

    def output_graph(self, services=None, excluded=None):
        """Return entities graph (DOT format)"""
        grph = "digraph dependency {\n"
        grph += "compound=true;\n"
        #grph += "node [shape=circle];\n"
        grph += "node [style=filled];\n"
        for service in (services or self.entities):
            if not self.entities[service].excluded(excluded):
                grph += self.entities[service].graph(excluded)
        grph += '}\n'
        return grph

    def load_config(self, conf):
        '''
        Load the configuration within the manager thanks to MilkCheckConfig
        '''
        from MilkCheck.Config.Configuration import MilkCheckConfig
        config = MilkCheckConfig()
        config.load_from_dir(directory=conf)
        config.build_graph()
示例#8
0
class ServiceManager(EntityManager):
    '''
    The service manager has to handle call to services. It implements
    features allowing us to get dependencies of service and so on.
    '''
    def __init__(self):
        EntityManager.__init__(self)
        # Variables declared in the global scope
        self.variables = {}
        # Top service
        self.source = Service('root')
        self.source.simulate = True

    def __refresh_graph(self, reverse):
        '''Reinitialize the right values for the graph of services'''
        for service in self.entities.values():
            service.reset()
        if reverse:
            self.source.clear_child_deps()
        else:
            self.source.clear_parent_deps()

    def has_service(self, service):
        '''Determine if the service is registered within the manager'''
        return service in self.entities.values()

    def has_warnings(self):
        '''Determine if the service has one action with the WARNING status'''
        for ent in self.entities.values():
            if ent.status is WARNING:
                return True
        return False

    def add_var(self, varname, value):
        '''Add a symbol within the service manager'''
        if varname not in self.variables:
            self.variables[varname] = value
        else:
            raise VariableAlreadyExistError("'%s' already defined" % varname)

    def remove_var(self, varname):
        '''Remove var from the the service manager'''
        if varname in self.variables:
            del self.variables[varname]

    def reset(self):
        '''Clean object service manager.'''
        self.variables.clear()
        self.entities.clear()

    def register_service(self, service):
        '''Add a new service to the manager.'''
        assert service, 'service added cannot be None'
        if service.name in self.entities:
            raise ServiceAlreadyReferencedError(service.name)
        else:
            self.entities[service.name] = service

    def register_services(self, *args):
        '''Add all services referenced by args'''
        for service in args:
            self.register_service(service)

    def forget_service(self, service):
        '''
        Remove the service from the manager. It takes care of the relations
        with others services in order to avoid to get a graph with a bad format.
        '''
        assert service, 'The service that you want to forget cannot be None'
        if not self.has_service(service):
            raise ServiceNotFoundError
        else:
            dependencies = []
            switch = len(service.children)
            dependencies.extend(service.children.values())
            dependencies.extend(service.parents.values())
            for dep in dependencies:
                switch -= 1
                if switch > 0:
                    service.remove_dep(dep.target.name, parent=False)
                else:
                    service.remove_dep(dep.target.name)
            del self.entities[service.name]

    def forget_services(self, *args):
        '''Remove all specified services from the manager'''
        for service in args:
            self.forget_service(service)

    def _variable_config(self, conf):
        '''Automatic variables based on MilckCheck configuration.'''
        if conf:
            # -n NODES
            self.add_var('SELECTED_NODES', str(conf.get('only_nodes', '')))
            # -x NODES
            self.add_var('EXCLUDED_NODES', str(conf.get('excluded_nodes', '')))

            # Add command line variable
            for defines in conf.get('defines', []):
                for define in defines.split():
                    key, value = define.split('=', 1)
                    self.add_var(key, value)
        else:
            for varname in ('selected_node', 'excluded_nodes'):
                self.add_var(varname.upper(), '')

    def _apply_config(self, conf):
        '''
        This apply a sequence of modifications on the graph. A modification
        can be an update of the nodes usable by the services or whatever that
        is referenced within configuration.
        '''

        # Load the configuration located within the directory
        if conf.get('config_dir'):
            self.entities.clear()
            self.load_config(conf['config_dir'])

        # Avoid some of the services referenced in the graph
        if conf.get('excluded_svc'):
            self.__lock_services(conf['excluded_svc'])

        # Use just those nodes
        if conf.get('only_nodes') is not None:
            self.__update_usable_nodes(conf['only_nodes'], 'INT')
        # Avoid those nodes
        elif conf.get('excluded_nodes') is not None:
            self.__update_usable_nodes(conf['excluded_nodes'], 'DIF')

    def __lock_services(self, services):
        '''
        Lock all services specified in the list. This will assign the LOCKED
        status on the services. A soon as a service is locked it will never be
        processed.
        '''
        for service in services:
            if service in self.entities:
                self.entities[service].status = LOCKED

    def _lock_services_except(self, services):
        """Lock all services except those provided."""
        for service in self.entities:
            if service not in services:
                self.entities[service].status = LOCKED

    def __update_usable_nodes(self, nodeset, mode=None):
        '''
        Update target value used by the service and the elements linked to
        the service.
        '''
        assert mode in (None, 'DIF', 'INT'), \
            'Invalid mode, should be DIF, INT or None'
        for service in self.entities.values():
            service.update_target(nodeset, mode)

    def call_services(self, services, action, conf=None):
        '''Allow the user to call one or multiple services.'''
        assert action, 'action name cannot be None'

        # Manage reverse mode based on configuration
        reverse = False
        if conf:
            reverse = action in conf.get('reverse_actions')

        self.variables.clear()

        # Create global variable from configuration
        self._variable_config(conf)

        # Make sure that the graph is usable
        self.__refresh_graph(reverse)
        # Apply configuration over the graph
        if conf:
            self._apply_config(conf)

        self.source.reset()
        # Enable reverse mode if needed
        self._reverse_mod(reverse)
        self.source.algo_reversed = reverse

        if not self.source.has_action(action):
            self.source.add_action(Action(name=action, command=':'))
        # Perform all services
        if not services:
            for service in self.entities.values():
                if reverse and not service.parents:
                    service.add_dep(target=self.source)
                elif not reverse and not service.children:
                    self.source.add_dep(target=service)
        # Perform required services
        else:
            for service_name in services:
                if service_name in self.entities:
                    if reverse:
                        self.entities[service_name].add_dep(target=self.source)
                    else:
                        self.source.add_dep(target=self.entities[service_name])
                else:
                    raise ServiceNotFoundError('Undefined service [%s]' %
                                               service_name)

        if conf and conf.get('nodeps'):
            self._lock_services_except(self.source.deps().keys())

        self.source.run(action)

    def output_graph(self, services=None, excluded=None):
        """Return entities graph (DOT format)"""
        grph = "digraph dependency {\n"
        grph += "compound=true;\n"
        #grph += "node [shape=circle];\n"
        grph += "node [style=filled];\n"
        for service in (services or self.entities):
            if not self.entities[service].excluded(excluded):
                grph += self.entities[service].graph(excluded)
        grph += '}\n'
        return grph

    def load_config(self, conf):
        '''
        Load the configuration within the manager thanks to MilkCheckConfig
        '''
        from MilkCheck.Config.Configuration import MilkCheckConfig
        config = MilkCheckConfig()
        config.load_from_dir(directory=conf)
        config.build_graph()