예제 #1
0
def Main():
    cgiEnv = lib_common.ScriptEnvironment()
    entity_id = cgiEnv.m_entity_id

    name_space, entity_type = cgiEnv.get_namespace_type()

    grph = cgiEnv.GetGraph()

    root_node = lib_util.RootUri()

    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    mode_disp = lib_util.GuessDisplayMode()
    logging.debug("entity_type=%s mode_disp=%s", entity_type, mode_disp)

    if not entity_type:
        lib_common.ErrorMessageHtml("entity_mime.py needs an object")

    entity_module = lib_util.GetEntityModule(entity_type)
    if not entity_module:
        lib_common.ErrorMessageHtml(
            "entity_mime.py entity_type=%s needs a module" % entity_type)

    try:
        entity_module.DisplayAsMime(grph, root_node, entity_ids_arr)
    except Exception as exc:
        lib_common.ErrorMessageHtml(
            __file__ + " DisplayAsMime fails: %s %s: %s. File=%s.\n" %
            (entity_type, entity_id, str(exc), entity_module.__file__))
예제 #2
0
def Main():
    cgiEnv = lib_common.CgiEnv()
    entity_id = cgiEnv.m_entity_id
    entity_host = cgiEnv.GetHost()

    (nameSpace, entity_type, entity_namespace_type) = cgiEnv.GetNamespaceType()

    grph = cgiEnv.GetGraph()

    rootNode = lib_util.RootUri()

    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    modeDisp = lib_util.GuessDisplayMode()
    sys.stderr.write("entity_mime.py entity_type=%s modeDisp=%s\n" %
                     (entity_type, modeDisp))

    if not entity_type:
        lib_common.ErrorMessageHtml("entity_mime.py needs an object")

    entity_module = lib_util.GetEntityModule(entity_type)
    if not entity_module:
        lib_common.ErrorMessageHtml(
            "entity_mime.py entity_type=%s needs a module" % (entity_type))

    try:
        entity_module.DisplayAsMime(grph, rootNode, entity_ids_arr)
    except:
        exc = sys.exc_info()[1]
        sys.stderr.write("entity_mime.py No DisplayAsMime for %s %s: %s\n" %
                         (entity_type, entity_id, str(exc)))
        lib_common.ErrorMessageHtml(
            "entity_mime.py No DisplayAsMime for %s %s: %s\n" %
            (entity_type, entity_id, str(exc)))
예제 #3
0
def AddInformation(grph, rootNode, entity_id, entity_type):
    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    # Each entity type ("process","file" etc... ) can have a small library
    # of its own, for displaying a rdf node of this type.
    if entity_type:
        entity_module = lib_util.GetEntityModule(entity_type)
        if entity_module:
            try:
                # On veut garder uniquement les informations textuelles
                # qu'on peut afficher dans une table. Et en plus ce doit etre tres rapide.
                # En fait il faudrait virer rdflib, le remplacer
                # par un simple container.
                # On peut se roder en passant un pseudo-grph ?
                class FilterLiteralRdfGraph:
                    #Init with a genuine rdflib graph.
                    def __init__(self, grph, destNode):
                        self.m_grph = grph
                        self.m_node = destNode

                    # If the information is not a literal, we could display the associated name.
                    # Also, consider recursive tables.
                    def Filter(self, subjRdf, objRdf):
                        return (subjRdf
                                == self.m_node) and lib_kbase.IsLiteral(
                                    (objRdf))

                    # This filters only literal properties which points to or from our node.
                    # This also ensures that theere is one node only, no links, because
                    # of the way json documents are generated.
                    # THE WHOLE SCRIPT MUST BE REPLACED BY A REAL JSON DOCUMENT,
                    # TRANSFORMED INTO HTML.
                    def add(self, trpl):
                        # sys.stderr.write("Trying %s %s %s\n"% trpl)
                        if self.Filter(trpl[0], trpl[2]):
                            # sys.stderr.write("Adding %s %s %s\n"%trpl)
                            self.m_grph.add(trpl)
                        if self.Filter(trpl[2], trpl[0]):
                            # sys.stderr.write("Adding %s %s %s\n"%trpl)
                            self.m_grph.add((trpl[2], trpl[1], trpl[0]))

                pseudoGraph = FilterLiteralRdfGraph(grph, rootNode)

                entity_module.AddInfo(pseudoGraph, rootNode, entity_ids_arr)

            except AttributeError:
                exc = sys.exc_info()[1]
                sys.stderr.write("No AddInfo for %s %s: %s\n" %
                                 (entity_type, entity_id, str(exc)))
    else:
        sys.stderr.write("No lib_entities for %s %s\n" %
                         (entity_type, entity_id))
예제 #4
0
def DirToMenu(callbackGrphAdd,parentNode,entity_type,entity_id,entity_host,flagShowAll):
	encodedEntityId=lib_util.EncodeUri(entity_id)
	entity_ids_arr = lib_util.EntityIdToArray( entity_type, entity_id )

	if entity_type:
		# entity_type might contain a slash, for example: "sqlite/table"
		relative_dir = "/sources_types/" + entity_type
	else:
		relative_dir = "/sources_types"

	directory = lib_util.gblTopScripts + relative_dir

	DirToMenuAux(callbackGrphAdd,parentNode,directory,relative_dir,entity_type,entity_ids_arr,encodedEntityId,entity_host,flagShowAll,depthCall = 1)
예제 #5
0
def _get_daemons_data():
    """
    This returns in a dictionary, the list of deamons.
    These daemons can then be displayed in plain HTML or in a Jinja2 template.
    Some control is also provided by the interface of supervisord library, so its link is displayed.
    Some CGI scripts can run in two modes: "web" mode (CGI or WSGI), as usual, but also in daemon mode:
    their daemon process runs endlessly and instead of returning their events to the caller of the CGI script,
    these events are inserted into a RDF triplestore.
    This RDF triplestore is defined as an URL in the credentials: Any type of triplestore
    is allowed as long as it is supported by rdflib persistence API,
    see details here: https://rdflib.readthedocs.io/en/stable/persistence.html .
    Then, when the script is later run in "normal", CGI mode, the events are returned from this triplestore database.
    This allows to accumulate a complete history of events stored as RDF triples.
    
    Each of these daemons is associated with a CGI script and also an object, defined with its class and the values 
    of the attributes listes in the ontology of the class.
    Of course, if this is a top-level script not associated with a class, there are no arguments.
    """

    urls_daemons_dict = lib_daemon.get_running_daemons()
    for daemon_url, daemon_object in urls_daemons_dict.items():
        logging.debug("daemon_url=%s" % daemon_url)

        url_label, entity_type, entity_id = lib_naming.ParseEntityUri(
            daemon_url, long_display=True)
        logging.debug("url_label=%s" % url_label)
        logging.debug("entity_type=%s" % entity_type)
        logging.debug("entity_id=%s" % entity_id)

        daemon_object['url_title'] = url_label

        # Now that we have the class and the key-value pairs of the object related to the script, builds its url.
        # TODO: Simplify this, because it splits the id path to join it afterwards.
        # It might help to reorder properly the key-value pairs.
        entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)
        entity_url = lib_util.EntityUri(entity_type, *entity_ids_arr)
        logging.debug("entity_url=%s" % entity_url)
        daemon_object['object_url'] = entity_url
        entity_label = lib_naming.entity_to_label(entity_type, entity_id,
                                                  lib_util.HostName())
        logging.debug("entity_label=%s" % entity_label)
        daemon_object['object_title'] = entity_label
        daemon_object['triples_number'] = lib_kbase.context_events_count(
            daemon_url)
        daemon_object['start_time'] = datetime.datetime.fromtimestamp(
            daemon_object['start']).strftime("%m/%d/%Y, %H:%M:%S")

    return urls_daemons_dict
예제 #6
0
def _add_information(grph, root_node, entity_id, entity_type):
    """
    This returns only literal information which can be displayed in a table.
    """
    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    # Each entity type ("process","file" etc... ) can have a small library
    # of its own, for displaying a rdf node of this type.
    if entity_type:
        entity_module = lib_util.GetEntityModule(entity_type)
        if entity_module:
            try:
                # On text information are kept. This must be very fast.
                class FilterLiteralRdfGraph:
                    # Init with a genuine rdflib graph.
                    def __init__(self, grph, destNode):
                        self.m_grph = grph
                        self.m_node = destNode

                    # If the information is not a literal, we could display the associated name.
                    # Also, consider recursive tables.
                    def _filter_subject_object(self, subj_rdf, obj_rdf):
                        return (subj_rdf == self.m_node
                                ) and lib_kbase.IsLiteral(obj_rdf)

                    # This filters only literal properties which points to or from our node.
                    # This also ensures that there is one node only, no links, because json documents generation.
                    # THE WHOLE SCRIPT MUST BE REPLACED BY A REAL JSON DOCUMENT, TRANSFORMED INTO HTML.
                    def add(self, trpl):
                        if self._filter_subject_object(trpl[0], trpl[2]):
                            self.m_grph.add(trpl)
                        if self._filter_subject_object(trpl[2], trpl[0]):
                            self.m_grph.add((trpl[2], trpl[1], trpl[0]))

                pseudo_graph = FilterLiteralRdfGraph(grph, root_node)

                entity_module.AddInfo(pseudo_graph, root_node, entity_ids_arr)

            except AttributeError as exc:
                logging.error("No AddInfo for %s %s: %s", entity_type,
                              entity_id, str(exc))
    else:
        logging.warning("No lib_entities for %s %s", entity_type, entity_id)
예제 #7
0
def Main():

    # This can process remote hosts because it does not call any script, just shows them.
    cgiEnv = lib_common.CgiEnv()
    entity_id = cgiEnv.m_entity_id

    name_space, entity_type = cgiEnv.get_namespace_type()

    grph = cgiEnv.GetGraph()

    # This receives an object type stored as a string, and a string made of the concatenation
    # of key-value pairs, defining an object. It returns the array of property values,
    # in the proper order of the ontology of the type.
    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    arr_triples = lib_event.data_retrieve(entity_type, entity_ids_arr)
    for tripl in arr_triples:
        grph.add(tripl)

    cgiEnv.OutCgiRdf()
예제 #8
0
def Main():

    # This can process remote hosts because it does not call any script, just shows them.
    cgiEnv = lib_common.CgiEnv()
    entity_id = cgiEnv.m_entity_id
    # entity_host = cgiEnv.GetHost()

    (nameSpace, entity_type, entity_namespace_type) = cgiEnv.GetNamespaceType()

    grph = cgiEnv.GetGraph()

    # rootNode = lib_util.RootUri()

    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    arrTriples = lib_event.data_retrieve(entity_type, entity_ids_arr)
    for tripl in arrTriples:
        grph.add(tripl)

    cgiEnv.OutCgiRdf()
예제 #9
0
def Main():

    # This can process remote hosts because it does not call any script, just shows them.
    cgiEnv = lib_common.CgiEnv(can_process_remote=True,
                               parameters={lib_util.paramkeyShowAll: False})
    entity_id = cgiEnv.m_entity_id
    entity_host = cgiEnv.GetHost()
    flagShowAll = int(cgiEnv.get_parameters(lib_util.paramkeyShowAll))

    nameSpace, entity_type = cgiEnv.get_namespace_type()

    if lib_util.IsLocalAddress(entity_host):
        entity_host = ""

    DEBUG("entity: entity_host=%s entity_type=%s entity_id=%s", entity_host,
          entity_type, entity_id)

    grph = cgiEnv.GetGraph()

    rootNode = lib_util.RootUri()

    if entity_id != "" or entity_type == "":
        entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

        # TODO: Plutot qu'attacher tous les sous-directory a node parent,
        # ce serait peut-etre mieux d'avoir un seul lien, et d'afficher
        # les enfants dans une table, un record etc...
        # OU: Certaines proprietes arborescentes seraient representees en mettant
        # les objets dans des boites imbriquees: Tables ou records.
        # Ca peut marcher quand la propriete forme PAR CONSTRUCTION
        # un DAG (Direct Acyclic Graph) qui serait alors traite de facon specifique.

        def CallbackGrphAdd(tripl, depthCall):
            grph.add(tripl)

        DirToMenu(CallbackGrphAdd, rootNode, entity_type, entity_id,
                  entity_host, flagShowAll)

    cgiEnv.OutCgiRdf("LAYOUT_RECT",
                     [pc.property_directory, pc.property_script])
예제 #10
0
def Main():

    # This can process remote hosts because it does not call any script, just shows them.
    cgiEnv = lib_common.CgiEnv(can_process_remote=True,
                               parameters={lib_util.paramkeyShowAll: False})
    entity_id = cgiEnv.m_entity_id
    entity_host = cgiEnv.GetHost()
    flagShowAll = int(cgiEnv.GetParameters(lib_util.paramkeyShowAll))

    (nameSpace, entity_type, entity_namespace_type) = cgiEnv.GetNamespaceType()

    grph = cgiEnv.GetGraph()

    rootNode = lib_util.RootUri()

    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)
    # entity_info_only.AddInformation(grph,rootNode,entity_id, entity_type)

    # Each entity type ("process","file" etc... ) can have a small library
    # of its own, for displaying a rdf node of this type.
    if entity_type:
        entity_module = lib_util.GetEntityModule(entity_type)
        if entity_module:
            try:
                entity_module.AddInfo(grph, rootNode, entity_ids_arr)
            except AttributeError:
                exc = sys.exc_info()[1]
                sys.stderr.write("No AddInfo for %s %s: %s\n" %
                                 (entity_type, entity_id, str(exc)))
    else:
        sys.stderr.write("No lib_entities for %s %s\n" %
                         (entity_type, entity_id))

    # When displaying in json mode, the scripts are shown with a contextual menu, not with D3 modes..
    if lib_util.GuessDisplayMode() not in ["json", "html"]:

        # This function is called for each script which applies to the given entity.
        # It receives a triplet: (subject,property,object) and the depth in the tree.
        # Here, this simply stores the scripts in a graph. The depth is not used yet,
        # but can help debugging.
        def CallbackGrphAdd(tripl, depthCall):
            grph.add(tripl)

        entity_dirmenu_only.DirToMenu(CallbackGrphAdd, rootNode, entity_type,
                                      entity_id, entity_host, flagShowAll)

        # This adds WBEM and WMI urls related to the current object.
        if entity_type != "":
            CIM_ComputerSystem.AddWbemWmiServers(grph, rootNode, entity_host,
                                                 nameSpace, entity_type,
                                                 entity_id)

        AddDefaultScripts(grph, rootNode, entity_host)

        # Special case if the currententity we are displaying, is a machine,
        # we might as well try to connect to its WMI or WBEM server, running on this machine.
        if entity_type == "CIM_ComputerSystem":
            AddDefaultScripts(grph, rootNode, entity_id)

    AddDefaultNodes(grph, rootNode, entity_host)

    cgiEnv.OutCgiRdf("LAYOUT_RECT",
                     [pc.property_directory, pc.property_script])
예제 #11
0
def Main():

    # This can process remote hosts because it does not call any script, just shows them.
    cgiEnv = lib_common.ScriptEnvironment(
        can_process_remote=True, parameters={lib_util.paramkeyShowAll: False})
    entity_id = cgiEnv.m_entity_id
    entity_host = cgiEnv.GetHost()
    logging.debug("entity_host=%s", entity_host)
    flag_show_all = int(cgiEnv.get_parameters(lib_util.paramkeyShowAll))

    # This optional parameter must not be edited.
    # It contains the name of an associator, and the associated objects must be displayed.
    associator_attribute = cgiEnv.get_parameters("__associator_attribute__")
    logging.debug("associator_attribute=%s", associator_attribute)
    if associator_attribute and associator_attribute.find(".") <= 0:
        lib_common.ErrorMessageHtml(
            "Associator attribute '%s' should be 'associator.role'" %
            associator_attribute)

    name_space, entity_type = cgiEnv.get_namespace_type()

    grph = cgiEnv.GetGraph()

    root_node = lib_util.RootUri()
    logging.debug("root_node=%s", root_node)

    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    # Each entity type ("process","file" etc... ) can have a small library
    # of its own, for displaying a rdf node of this type.
    if entity_type:
        entity_module = lib_util.GetEntityModule(entity_type)
        if entity_module:
            try:
                entity_module.AddInfo(grph, root_node, entity_ids_arr)
            except AttributeError as exc:
                logging.info("No AddInfo for %s %s: %s", entity_type,
                             entity_id, str(exc))
            except Exception as exc:
                logging.info("Unexpected exception for %s %s: %s", entity_type,
                             entity_id, str(exc))

        if associator_attribute:
            # Should we display the associated instances for this associator and role ?
            lib_associators.add_associated_instances(grph, root_node,
                                                     entity_type, entity_id,
                                                     associator_attribute)
    else:
        # This behaves as the top-level page, without instances to display.
        logging.info("No lib_entities for %s %s", entity_type, entity_id)

    # When displaying in json mode, the scripts are shown with a contextual menu, not with D3 modes..
    if lib_util.GuessDisplayMode() not in ["json", "html"]:

        # This function is called for each script which applies to the given entity.
        # It receives a triplet: (subject,property,object) and the depth in the tree.
        # Here, this simply stores the scripts in a graph. The depth is not used yet,
        # but can help debugging.
        def callback_grph_add(tripl, depthCall):
            try:
                grph.add(tripl)
            except Exception as exc:
                logging.error("callback_grph_add: tripl=%s exception=%s" %
                              (str(tripl), str(exc)))
                raise

        try:
            # This displays the scripts associated to this instance.
            entity_dirmenu_only.recursive_walk_on_scripts(
                callback_grph_add, root_node, entity_type, entity_id,
                entity_host, flag_show_all)
        except Exception as exc:
            logging.error("Caught in recursive_walk_on_scripts:%s. Trace=%s",
                          exc, traceback.format_exc())

        # This adds WBEM and WMI urls related to the current object.
        # They can display more information about this instance.
        if entity_type != "":
            # This solves the case where one of the values of the ontology predicates contains commas.
            # These commands were quoted, then separated of other arguments by a comma.
            # TODO: It would be probably be  simpler to encode predicates values just like CGI arguments.
            _add_wbem_wmi_servers(grph, root_node, entity_host, name_space,
                                  entity_type, entity_id)

        _add_default_scripts(grph, root_node, entity_host)

        # Special case if the current entity we are displaying, is a machine,
        # we might as well try to connect to its WMI or WBEM server, running on this machine.
        if entity_type == "CIM_ComputerSystem":
            _add_default_scripts(grph, root_node, entity_id)

    _add_default_nodes(grph, root_node, entity_host)

    cgiEnv.OutCgiRdf("LAYOUT_RECT",
                     [pc.property_directory, pc.property_script])
예제 #12
0
def recursive_walk_on_scripts(callback_grph_add, parent_node, entity_type, entity_id, entity_host, flag_show_all):
    """
    This adds to a RDF graph the tree of scripts which can be applied to an object (sometimes called entity)
    defined by its class and the values of its attributes.
    If the class is not defined, then it is a top-level script.
    Scripts are defined by a RDF node: The URL contains the script and the arguments.

    :param callback_grph_add: The graph to which the scripts are added.
    :param parent_node:
    :param entity_type:
    :param entity_id:
    :param entity_host:
    :param flag_show_all: If True, disabled scripts are also returned.
    :return:
    """

    # This is used when disabled script as returned.
    script_error_property = lib_common.MakeProp("Script error")

    def directory_usability_error_node(relative_dir, depth_call):
        # Maybe there is a usability test in the current module.
        # The goal is to control all scripts in the subdirectories, from here.
        try:
            entity_class = ".".join(relative_dir.split("/")[2:])

            imported_module = lib_util.GetEntityModule(entity_class)
            if imported_module:
                error_msg = _test_usability(imported_module, entity_type, entity_ids_arr)
                if error_msg:
                    # If set to True, the directory is displayed even if all its script are not usable.
                    return lib_util.NodeLiteral(error_msg)
        except IndexError:
            # If we are at the top-level, no interest for the module.
            pass

        return None

    def recursive_walk_aux(a_parent_node, grand_parent_node, curr_dir, relative_dir, depth_call=1):
        """This lists the scripts and generate RDF nodes. Returns True if something was added."""

        # In case there is nothing.
        dirs = None
        for path, dirs, files in os.walk(curr_dir):
            break

        # Maybe this class is not defined in our ontology.
        if dirs == None:
            logging.warning("dir_to_menu_aux(2) No content in %s", curr_dir)
            return False

        # Will still be None if nothing is added.
        rdf_node = None
        sub_path = path[len(curr_dir):]

        relative_dir_sub_path = relative_dir + sub_path

        arg_dir = relative_dir_sub_path.replace("/", ".")[1:]

        # If this is a remote host, all scripts are checked because they might have
        # the flag CanProcessRemote which is defined at the script level, not the directory level.
        if not entity_host:
            err_dir_node = directory_usability_error_node(relative_dir, depth_call)
            if err_dir_node:
                if flag_show_all:
                    arg_dir_split = arg_dir.split(".")
                    curr_dir_node = lib_util.DirDocNode(".".join(arg_dir_split[:-1]), arg_dir_split[-1])
                    if not curr_dir_node:
                        curr_dir_node = lib_util.NodeLiteral("Cannot parse relative dir:%s" % arg_dir)
                    callback_grph_add((grand_parent_node, pc.property_script, curr_dir_node), depth_call)
                    callback_grph_add((curr_dir_node, script_error_property, err_dir_node), depth_call)
                # The directory is not usable, so leave immediately.
                return False

        contains_something = False
        for dir in dirs:
            # This directory may be generated by our Python interpreter.
            if dir == "__pycache__":
                continue

            full_sub_dir = os.path.join(curr_dir, dir)

            try:
                curr_dir_node = lib_util.DirDocNode(arg_dir, dir)
            except Exception as exc:
                logging.error("exc=%s", exc)
                raise

            if not curr_dir_node:
                logging.warning("curr_dir_node is None: arg_dir=%s dir=%s", arg_dir, dir)
                continue

            sub_relative_dir = relative_dir + "/" + dir

            sub_entity_class = ".".join(sub_relative_dir.split("/")[2:])
            onto_keys = lib_util.OntologyClassKeys(sub_entity_class)

            # TODO: Beware, if not ontology, returns empty array. Why not returning None ?
            if onto_keys != []:
                # Maybe this is a subclass with its own ontology.
                # So its scripts do not apply to the current class.
                logging.info("sub_entity_class=%s onto_keys=%s", sub_entity_class, onto_keys)
                continue

            something_added = recursive_walk_aux(
                curr_dir_node, a_parent_node, full_sub_dir, sub_relative_dir, depth_call + 1)
            # This adds the directory name only if it contains a script.
            if something_added:
                # It works both ways, possibly with different properties.
                callback_grph_add((a_parent_node, pc.property_script, curr_dir_node), depth_call)
            contains_something = contains_something | something_added

        for fil in files:
            # We want to list only the usable Python scripts.
            if not fil.endswith(".py") or fil == "__init__.py":
                continue

            script_path = relative_dir_sub_path + "/" + fil

            rdf_node = gen_obj.node_from_script_path(script_path, entity_type, encoded_entity_id)

            error_msg = None

            try:
                imported_mod = lib_util.GetScriptModule(arg_dir, fil)
            except Exception as exc:
                logging.warning("Caught:%s", exc)
                error_msg = exc
                imported_mod = None
                if not flag_show_all:
                    continue

            if not error_msg:
                # Show only scripts which want to be shown. Each script can have an optional function
                # called Usable(): If it is there and returns False, the script is not displayed.
                error_msg = _test_usability(imported_mod, entity_type, entity_ids_arr)
                if error_msg:
                    pass

            # If this is a local host
            if not flag_show_all and error_msg and not entity_host:
                continue

            # If the entity is on another host, does the script run on remote entities ?
            # The concept of "CanProcessRemote" is a short-hand to avoid checking
            # if the remote is in the entity ids. This flag means:
            # "It is worth anyway investigating on a remote host, if the entity exists there."
            if entity_host:
                try:
                    # Script can be used on a remote entity.
                    can_process_remote = imported_mod.CanProcessRemote
                except AttributeError:
                    can_process_remote = False

                if not can_process_remote:
                    if not error_msg:
                        error_msg = "%s is local" % entity_host

                    if not flag_show_all:
                        continue
                else:
                    logging.debug("Script %s %s CAN work on remote entities", arg_dir, fil)

            # Here, we are sure that the script is added.
            # TODO: If no script is added, should not add the directory?
            callback_grph_add((a_parent_node, pc.property_script, rdf_node), depth_call)

            # Default doc text is file name minus the ".py" extension.
            nod_modu = lib_util.module_doc_string(imported_mod, fil[:-3])

            # nod_modu contains a literal of a str.
            if not isinstance(nod_modu, rdflib.term.Literal):
                logging.error("nod_modu=%s should be Literal instead of %s", nod_modu, type(nod_modu))

            callback_grph_add((rdf_node, pc.property_information, nod_modu), depth_call)

            if error_msg:
                callback_grph_add((rdf_node, script_error_property, lib_util.NodeLiteral(error_msg)), depth_call)

        # This tells if a script was added in this directory or one of the subdirs.
        return (rdf_node is not None) | contains_something

    if entity_host:
        logging.debug("entity_host=%s", entity_host)
    # This will not be needed anymore when node_from_script_path properly encode chars like node_from_dict.
    # TODO: Use base64 for urls, everywhere. Use appropriate encoding for XML, SVG or HTML text.
    encoded_entity_id = lib_util.EncodeUri(entity_id)
    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    if entity_type:
        # entity_type might contain a slash, for example: "sqlite/table"
        relative_dir = "/sources_types/" + entity_type
    else:
        relative_dir = "/sources_types"

    directory = lib_util.gblTopScripts + relative_dir

    gen_obj = lib_uris.MachineBox(entity_host)

    recursive_walk_aux(parent_node, None, directory, relative_dir, depth_call=1)

    if entity_type:
        _add_cim_links(callback_grph_add, parent_node, entity_type, entity_id, gen_obj)
예제 #13
0
def DirToMenu(callbackGrphAdd, parentNode, entity_type, entity_id, entity_host,
              flagShowAll):
    def DirectoryUsabilityErrorNode(relative_dir, depthCall):
        # Maybe there is a usability test in the current module.
        # The goal is to control all scripts in the subdirectories, from here.
        try:
            entity_class = ".".join(relative_dir.split("/")[2:])
            #DirMenuReport( depthCall, "entity_class=%s\n"%(entity_class))

            importedMod = lib_util.GetEntityModule(entity_class)
            if importedMod:
                errorMsg = TestUsability(importedMod, entity_type,
                                         entity_ids_arr)
                # if flagShowAll and errorMsg ???
                if errorMsg:
                    DEBUG("IsDirectoryUsable errorMsg(1)=%s", errorMsg)
                    # If set to True, the directory is displayed even if all its scripts
                    # are not usable. Surprisingly, the message is not displayed as a subdirectory, but in a separate square.
                    return lib_common.NodeLiteral(errorMsg)
        except IndexError:
            # If we are at the top-level, no interest for the module.
            pass

        return None

    # This lists the scripts and generate RDF nodes.
    # Returns True if something was added.
    def DirToMenuAux(aParentNode,
                     grandParentNode,
                     curr_dir,
                     relative_dir,
                     depthCall=1):
        #DirMenuReport( depthCall, "curr_dir=%s relative_dir=%s\n"%(curr_dir,relative_dir))
        # In case there is nothing.
        dirs = None
        for path, dirs, files in os.walk(curr_dir):
            break

        # Maybe this class is not defined in our ontology.
        if dirs == None:
            WARNING("DirToMenuAux(2) No content in %s", curr_dir)
            return False

        # Will still be None if nothing is added.
        rdfNode = None
        sub_path = path[len(curr_dir):]

        relative_dir_sub_path = relative_dir + sub_path

        argDir = relative_dir_sub_path.replace("/", ".")[1:]

        # If this is a remote host, all scripts are checked because they might have
        # the flag CanProcessRemote which is defined at the script level, not the directory level.
        if not entity_host:
            errDirNode = DirectoryUsabilityErrorNode(relative_dir, depthCall)
            if errDirNode:
                if flagShowAll:
                    argDirSplit = argDir.split(".")
                    currDirNode = lib_util.DirDocNode(
                        ".".join(argDirSplit[:-1]), argDirSplit[-1])
                    if not currDirNode:
                        currDirNode = lib_util.NodeLiteral(
                            "Cannot parse relative dir:%s" % argDir)
                    callbackGrphAdd(
                        (grandParentNode, pc.property_script, currDirNode),
                        depthCall)
                    callbackGrphAdd((currDirNode, lib_common.MakeProp("Error"),
                                     errDirNode), depthCall)
                # The directory is not usable, so leave immediately.
                return False

        containsSomething = False
        for dir in dirs:
            #DirMenuReport( depthCall, "dir=%s\n"%(dir))
            # Might be generated by our Python interpreter.
            if dir == "__pycache__":
                continue

            full_sub_dir = os.path.join(curr_dir, dir)

            currDirNode = lib_util.DirDocNode(argDir, dir)

            if not currDirNode:
                #DirMenuReport( depthCall, "currDirNode NONE: argDir=%s dir=%s\n"%(argDir,dir))
                continue

            sub_relative_dir = relative_dir + "/" + dir

            sub_entity_class = ".".join(sub_relative_dir.split("/")[2:])
            ontoKeys = lib_util.OntologyClassKeys(sub_entity_class)
            #DirMenuReport( depthCall, "Checked ontology of %s: ontoKeys=%s\n"%(sub_entity_class,str(ontoKeys)))

            # TODO: Beware, if not ontology, returns empty array. Why not returning None ?
            if ontoKeys != []:
                #DirMenuReport( depthCall, "Module %s has an ontology so it is a class. Skipping\n"%(sub_relative_dir))
                # BEWARE: NO MORE DEFAULT ONTOLOGY ["Id"]
                continue

            somethingAdded = DirToMenuAux(currDirNode, aParentNode,
                                          full_sub_dir, sub_relative_dir,
                                          depthCall + 1)
            # This adds the directory name only if it contains a script.
            if somethingAdded:
                # It works both ways, possibly with different properties.
                callbackGrphAdd((aParentNode, pc.property_script, currDirNode),
                                depthCall)
            containsSomething = containsSomething | somethingAdded

        for fil in files:
            # We want to list only the usable Python scripts.
            if not fil.endswith(".py") or fil == "__init__.py":
                continue

            script_path = relative_dir_sub_path + "/" + fil

            #DirMenuReport( depthCall, "DirToMenu encodedEntityId=%s\n" % encodedEntityId)

            url_rdf = genObj.MakeTheNodeFromScript(script_path, entity_type,
                                                   encodedEntityId)

            errorMsg = None

            try:
                importedMod = lib_util.GetScriptModule(argDir, fil)
            except Exception:
                errorMsg = sys.exc_info()[1]
                #DirMenuReport( depthCall, "DirToMenuAux Cannot import=%s. Caught: %s\n" % (script_path, errorMsg ) )
                importedMod = None
                if not flagShowAll:
                    continue

            if not errorMsg:
                # Show only scripts which want to be shown. Each script can have an optional function
                # called Usable(): If it is there and returns False, the script is not displayed.
                errorMsg = TestUsability(importedMod, entity_type,
                                         entity_ids_arr)
                if errorMsg:
                    pass
                    #DEBUG("DirToMenuAux errorMsg(2)=%s",errorMsg)

            # If this is a local host
            if not flagShowAll and errorMsg and not entity_host:
                continue

            # If the entity is on another host, does the script run on remote entities ?
            # The concept of "CanProcessRemote" is a short-hand to avoid checking
            # if the remote is in the entity ids. This flag means:
            # "It is worth anyway investigating on a remote host, if the entity exists there."
            if entity_host:
                try:
                    # Script can be used on a remote entity.
                    can_process_remote = importedMod.CanProcessRemote
                except AttributeError:
                    can_process_remote = False

                # can_process_remote = True
                DEBUG(
                    "entity_dir_menu.py DirToMenuAux entity_host=%s can_process_remote=%d",
                    entity_host, can_process_remote)

                if not can_process_remote:
                    if not errorMsg:
                        errorMsg = "%s is local" % (entity_host)
                    # DirMenuReport( depthCall, "Script %s %s cannot work on remote entities: %s at %s\n" % ( argDir, fil, encodedEntityId , entity_host ) )
                    #DirMenuReport( depthCall, "Script %s %s cannot work on remote entities\n" % ( argDir, fil ) )

                    if not flagShowAll:
                        continue
                else:
                    DirMenuReport(
                        depthCall,
                        "Script %s %s CAN work on remote entities\n" %
                        (argDir, fil))

            # Here, we are sure that the script is added.
            # TODO: If no script is added, should not add the directory?
            rdfNode = lib_common.NodeUrl(url_rdf)
            callbackGrphAdd((aParentNode, pc.property_script, rdfNode),
                            depthCall)

            # Default doc text is file name minus the ".py" extension.
            nodModu = lib_util.FromModuleToDoc(importedMod, fil[:-3])

            callbackGrphAdd((rdfNode, pc.property_information, nodModu),
                            depthCall)

            if errorMsg:
                callbackGrphAdd((rdfNode, lib_common.MakeProp("Error"),
                                 lib_common.NodeLiteral(errorMsg)), depthCall)

        # This tells if a script was added in this directory or one of the subdirs.
        return (rdfNode is not None) | containsSomething

    if entity_host:
        DEBUG("entity_dir_menu.py DirToMenu entity_host=%s", entity_host)
    encodedEntityId = lib_util.EncodeUri(entity_id)
    entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id)

    if entity_type:
        # entity_type might contain a slash, for example: "sqlite/table"
        relative_dir = "/sources_types/" + entity_type
    else:
        relative_dir = "/sources_types"

    directory = lib_util.gblTopScripts + relative_dir

    if entity_host:
        genObj = lib_common.RemoteBox(entity_host)
    else:
        genObj = lib_common.gUriGen

    DirToMenuAux(parentNode, None, directory, relative_dir, depthCall=1)