Beispiel #1
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)))
def _add_survol_node(grph, host_survol, url_survol_clean):
    logging.debug("AddSurvolNode hostSurvol=%s", host_survol)
    survol_host_node = lib_uris.gUriGen.HostnameUri(host_survol)

    curr_disp_mode = lib_util.GuessDisplayMode()

    # Several possibilities:
    # - Open a new HTML page with this URL. Or SVG, passed on the current mode.
    # - If we are in D3 mode, this should return a JSON object from the other agent.
    if curr_disp_mode == "json":
        server_box = lib_uris.OtherAgentBox(host_survol)

        # This is the URL of the remote host, on the remote agent.
        node_remote_host = server_box.HostnameUri(host_survol)
        grph.add((survol_host_node, lib_common.MakeProp("Survol host"), node_remote_host))

        node_survol_url = lib_common.NodeUrl(url_survol_clean)
        grph.add((survol_host_node, lib_common.MakeProp("Survol agent"), node_survol_url))
    else:
        url_survol_moded = lib_util.AnyUriModed(url_survol_clean, curr_disp_mode)

        node_survol_url = lib_common.NodeUrl(url_survol_moded)

        # Should check the URL to be sure it is valid.
        grph.add((survol_host_node, lib_common.MakeProp("Survol agent"), node_survol_url))

    return node_survol_url
Beispiel #3
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__))
Beispiel #4
0
	def OutCgiRdf(self, dot_layout = "", collapsed_properties=[] ):
		global globalCgiEnvList
		# sys.stderr.write("OutCgiRdf globalMergeMode=%d len(globalCgiEnvList)=%d\n"%(globalMergeMode,len(globalCgiEnvList)))
		sys.stderr.write("OutCgiRdf m_calling_url=%s m_page_title=%s\n"%(self.m_calling_url,self.m_page_title))

		self.m_layoutParams = MakeDotLayout( dot_layout, collapsed_properties )

		mode = lib_util.GuessDisplayMode()

		topUrl = lib_util.TopUrl( self.m_entity_type, self.m_entity_id )

		if self.m_page_title is None:
			self.m_page_title = "PAGE TITLE SHOULD BE SET"

		if globalMergeMode:
			# At the end, only one call to OutCgiMode() will be made.
			globalCgiEnvList.append(self)
		else:
			OutCgiMode( self, topUrl, mode )
def AddSurvolNode(grph, hostSurvol, urlSurvolClean):
    sys.stderr.write("AddSurvolNode hostSurvol=%s\n" % (hostSurvol))
    survolHostNode = lib_common.gUriGen.HostnameUri(hostSurvol)

    currDispMode = lib_util.GuessDisplayMode()

    # Several possibilities:
    # - Open a new HTML page with this URL. Or SVG, passed on the current mode.
    # - If we are in D3 mode, this should return a JSON object from the other agent.
    if currDispMode == "json":

        if lib_util.IsLocalAddress(hostSurvol):
            machName_or_None = None
            serverBox = lib_common.gUriGen
        else:
            machName_or_None = hostSurvol
            serverBox = lib_common.OtherAgentBox(urlSurvolClean)

        # This is the URL of the remote host, on the remote agent.
        nodeRemoteHost = serverBox.HostnameUri(hostSurvol)
        grph.add((survolHostNode, lib_common.MakeProp("Survol host"),
                  nodeRemoteHost))

        nodeSurvolUrl = lib_common.NodeUrl(urlSurvolClean)
        grph.add((survolHostNode, lib_common.MakeProp("Survol agent"),
                  nodeSurvolUrl))

    else:
        urlSurvolModed = lib_util.AnyUriModed(urlSurvolClean, currDispMode)

        nodeSurvolUrl = lib_common.NodeUrl(urlSurvolModed)

        # Should check the URL to be sure it is valid.

        # sys.stderr.write("AddSurvolNode urlSurvolModed=%s\n"%(urlSurvolModed))
        grph.add((survolHostNode, lib_common.MakeProp("Survol agent"),
                  nodeSurvolUrl))

    return nodeSurvolUrl
Beispiel #6
0
    def OutCgiRdf(self, dot_layout="", collapsed_properties=[]):
        global globalCgiEnvList
        DEBUG("OutCgiRdf globalMergeMode=%d m_calling_url=%s m_page_title=%s",
              globalMergeMode, self.m_calling_url,
              self.m_page_title.replace("\n", "<NL>"))

        self.m_layoutParams = make_dot_layout(dot_layout, collapsed_properties)

        mode = lib_util.GuessDisplayMode()

        top_url = lib_util.TopUrl(self.m_entity_type, self.m_entity_id)

        if self.m_page_title is None:
            self.m_page_title = "PAGE TITLE SHOULD BE SET"
            self.m_page_subtitle = "PAGE SUBTITLE SHOULD BE SET"

        # See if this can be used in lib_client.py and merge_scritps.py.
        if globalMergeMode:
            # At the end, only one call to OutCgiMode() will be made.
            globalCgiEnvList.append(self)
        else:
            OutCgiMode(self, top_url, mode)
Beispiel #7
0
    def OutCgiRdf(self, layout_style="", collapsed_properties=[]):
        global _global_cgi_env_list
        logging.debug("OutCgiRdf globalMergeMode=%d m_calling_url=%s m_page_title=%s",
              _global_merge_mode, self.m_calling_url, self.m_page_title.replace("\n", "<NL>"))

        # TODO: Get these values from the RDF document, if these were added on-the-fly by CGI scripts.
        if layout_style:
            self.m_layout_style = layout_style
        self.m_collapsed_properties.extend(collapsed_properties)

        mode = lib_util.GuessDisplayMode()

        top_url = lib_util.TopUrl(self.m_entity_type, self.m_entity_id)

        if self.m_page_title is None:
            self.m_page_title = "PAGE TITLE SHOULD BE SET"
            self.m_page_subtitle = "PAGE SUBTITLE SHOULD BE SET"

        # TODO: See if this can be used in lib_client.py and merge_scripts.py.
        if _global_merge_mode:
            # At the end, only one call to _out_cgi_mode() will be made.
            _global_cgi_env_list.append(self)
        else:
            _out_cgi_mode(self, top_url, mode)
Beispiel #8
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])
Beispiel #9
0
def DoTheJob(TheEngine,
             Deserializer,
             AppName,
             Title,
             dot_layout="",
             collapsed_properties=[]):
    srvSingle = SrvSingleton(AppName)

    PortNum = srvSingle.m_PortNumber

    run_word = "run"
    GblLog("DoTheJob:" + str(sys.argv) + " title=" + Title + " dot_layout=" +
           dot_layout)

    if srvSingle.m_PortNumber != None:
        GblLog("Title=%s PortNum=%d" % (Title, PortNum))
    else:
        GblLog("Title=%s PortNum not defined yet" % (Title))

    # So we can answer immediately to "info" requests, without creating the subserver.
    cgiEnv = lib_common.CgiEnv(Title, "", {"port_number": PortNum})

    # This is the subprocess of the specialised http server.
    if (len(sys.argv) > 1) and (sys.argv[1] == run_word):
        if srvSingle.GetRunning():
            GblLog("Subprocess: Race condition: Port " + str(PortNum) +
                   " allocated. Leaving.")
            sys.exit(0)

        # Called before creating the subserver because we will be stuck into it.
        if not srvSingle.SetRunning():
            GblLog("CANNOT SET RUNNING STATE: Race condition ?")
            return

        # This time the port must be valid.
        PortNum = srvSingle.m_PortNumber
        GblLog("Subprocess: Port %d free. About to create subserver." %
               PortNum)
        try:
            # Normally we are stuck in this, answering HTTP requests and accumulating data.
            # TODO: It is probably not necessary to send Title and DotLayout.
            layoutParams = lib_common.make_dot_layout(dot_layout,
                                                      collapsed_properties)

            # Now, will append log at the end.
            srvSingle.m_logFd.close()
            gServer = RdfStreamServer(PortNum, TheEngine, Deserializer, Title,
                                      layoutParams, srvSingle.m_logFilNam)

            GblLog("Should never be here")
        except Exception:
            exc = sys.exc_info()[1]
            msg = Task() + " Caught when starting RdfStreamServer:" + str(exc)
            GblLog(msg)
            srvSingle.CancelRunning()
            lib_common.ErrorMessageHtml("From RDFStreamServer, caught:" + msg)

        sys.exit(0)

    # if the subserver is not running, we start it, then redirects the browser
    # to initiate a new connection. After that, we exit() but this will never really
    # exit until our subserver subprocess, exits first.

    if not srvSingle.GetRunning():
        GblLog("About to start:" + AppName)
        try:
            # Do not pipe the output otherwise it would not run in the background.

            # Si necessaire, on pourrait lancer un process avec l'user root ?
            # sub_proc = lib_common.SubProcPOpen( [ "python", AppName, run_word ] )
            # Share standard error.
            sub_proc = lib_common.SubProcPOpen(["python", AppName, run_word],
                                               stderr=sys.stderr)

            GblLog("Started sub http server:" + AppName + " subpid=" +
                   str(sub_proc.pid))

            # We need the cgi arguments, especially the entity id.
            origUrl = os.environ["REQUEST_URI"]

            GblLog("About to redirect browser to:" + origUrl)

            # IMPORTANT: We leave time enough for the subprocess to start,
            # otherwise it will be started TWICE.
            time.sleep(0.1)

            GblLog("After pause")

            SendRedirection(sys.stdout, origUrl)

            # This blocks until the subprocess exists.
            GblLog("Waiting for end of subpid=" + str(sub_proc.pid))
            sys.exit(0)

        except Exception:
            exc = sys.exc_info()[1]
            lib_common.ErrorMessageHtml("When starting server=" + AppName +
                                        ", caught:" + str(exc))

    GblLog("Service exists. Port=" + str(PortNum))

    # Here, we know that the subserver is running.
    url = SubServerUrl(PortNum, cgiEnv)

    # Do we have to stop the subserver ?
    if MustStop():
        # Equivalent to 'ModedUrl("stop")'
        url_stop = lib_util.ConcatenateCgi(url, "mode=stop")
        # TODO: We could also load this URL, this would be nicer.
        SendRedirection(sys.stdout, url_stop)
        sys.exit(0)

    mode = lib_util.GuessDisplayMode()
    GblLog("mode:" + mode)
    # Equivalent to 'ModedUrl(mode)'
    url_mode = lib_util.ConcatenateCgi(url, "mode=" + mode)

    GblLog("url_mode:" + url_mode)
    SendRedirection(sys.stdout, url_mode)

    GblLog("Finished:" + AppName)
Beispiel #10
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])
Beispiel #11
0
	def __init__(self, parameters = {}, can_process_remote = False ):
		# TODO: This value is read again in OutCgiRdf, we could save time by making this object global.
		sys.stderr.write( "CgiEnv parameters=%s\n" % ( str(parameters) ) )

		# TODO: When running from cgiserver.py, and if QUERY_STRING is finished by a dot ".", this dot
		# TODO: is removed. Workaround: Any CGI variable added after.
		# TODO: Also: Several slashes "/" are merged into one.
		# TODO: Example: "xid=http://192.168.1.83:5988/." becomes "xid=http:/192.168.1.83:5988/"
		# TODO: ... or "xx.py?xid=smbshr.Id=////WDMyCloudMirror///rchateau" become "xx.py?xid=smbshr.Id=/WDMyCloudMirror/rchateau"
		# TODO: Replace by "xid=http:%2F%2F192.168.1.83:5988/."
		# Maybe a bad collapsing of URL ?
		# sys.stderr.write("QUERY_STRING=%s\n" % os.environ['QUERY_STRING'] )
		mode = lib_util.GuessDisplayMode()

		# Contains the optional arguments, needed by calling scripts.
		self.m_parameters = parameters

		self.m_parameterized_links = dict()


		# When in merge mode, the display parameters must be stored in a place accessible by the graph.

		docModuAll = GetCallingModuleDoc()

		# Take only the first non-empty line. See lib_util.FromModuleToDoc()
		docModuSplit = docModuAll.split("\n")
		self.m_page_title = docModuSplit[0]

		# Title page contains __doc__ plus object label.
		callingUrl = lib_util.RequestUri()
		self.m_calling_url = callingUrl
		sys.stderr.write("CgiEnv m_page_title=%s m_calling_url=%s\n"%(self.m_page_title,self.m_calling_url))
		parsedEntityUri = lib_naming.ParseEntityUri(callingUrl,longDisplay=False,force_entity_ip_addr=None)
		if parsedEntityUri[2]:
			# If there is an object to display.
			# Practically, we are in the script "entity.py" and the single doc string is "Overview"
			fullTitle = parsedEntityUri[0]
			self.m_page_title += " " + fullTitle

			# We assume there is an object, and therefore a class and its description.
			entity_class = parsedEntityUri[1]

			# Similar code in objtypes.py
			entity_module = lib_util.GetEntityModule(entity_class)
			entDoc = entity_module.__doc__
			# The convention is the first line treated as a title.
			if entDoc:
				self.m_page_title += "\n" + entDoc

		# If we can talk to a remote host to get the desired values.

		# Global CanProcessRemote has precedence over parameter can_process_remote
		# whcih should probably be deprecated, although they do not have exactly the same role:
		# * Global CanProcessRemote is used by entity.py to display scripts which have this capability.
		# * Parameter can_process_remote is used to inform, at execution time, of this capability.
		# Many scripts are not enumerated by entity.py so a global CanProcessRemote is not necessary.
		# For clarity, it might be fine to replace the parameter can_process_remote by the global value.
		# There cannot be nasty consequences except that some scripts might not be displayed
		# when they should be, and vice-versa.
		try:
			globalCanProcessRemote = globals()["CanProcessRemote"]
		except KeyError:
			globalCanProcessRemote = False

		if can_process_remote != globalCanProcessRemote:
			# sys.stderr.write("INCONSISTENCY CanProcessRemote\n") # ... which is not an issue.
			can_process_remote = True

		self.m_can_process_remote = can_process_remote

		self.m_arguments = cgi.FieldStorage()

		(self.m_entity_type,self.m_entity_id,self.m_entity_host) = self.GetXid()
		sys.stderr.write("CgiEnv m_entity_type=%s m_entity_id=%s m_entity_host=%s\n"%(self.m_entity_type,self.m_entity_id,self.m_entity_host))
		self.m_entity_id_dict = lib_util.SplitMoniker(self.m_entity_id)

		# Depending on the caller module, maybe the arguments should be 64decoded. See "sql/query".
		# As the entity type is available, it is possible to import it and check if it encodes it arguments.
		# See presence of source_types.sql.query.DecodeCgiArg(keyWord,cgiArg) for example.

		# This is probably too generous to indicate a local host.
		self.TestRemoteIfPossible(can_process_remote)

		# TODO: HOW WILL WE RESTORE THE ORIGINAL DISPLAY MODE ?
		if mode == "edit":
			self.EditionMode()
Beispiel #12
0
def Main():
    orig_req_uri = lib_util.RequestUri()

    # It initialises an implicit global object similar.
    # When in the mode of global merging, the method "cgiEnv.OutCgiRdf()" does not generate anything,
    # but simply stores the new cgiEnv in a global list..
    # The script loops on the URLs passed as CGI parameters.
    # The URLs are loaded and their content merged into the container lib_common.globalGraph
    lib_common.CgiEnvMergeMode()

    arguments = cgi.FieldStorage()

    # The display mode is read now, otherwise the CGI arguments are later destroyed, in this script.
    the_mode = lib_util.GuessDisplayMode()
    logging.debug("the_mode=%s", the_mode)

    # Concatenation of error messages of each script.
    cumulated_error = ""

    # This logic might be needed in lib_client.py
    for urlfil in arguments.getlist("url"):
        # The parameters are coded in base64, although we leave the possibility not to encode them,
        # for compatibility with test scripts.

        complete_url = lib_util.Base64Decode(urlfil)

        logging.debug("complete_url=%s", complete_url)

        # Only the URL without the arguments.
        url_split = complete_url.split("?")
        url_no_args = url_split[0]
        if len(url_split) > 1:
            cgi_query_string = url_split[1]
        else:
            cgi_query_string = ""

        # The URL might be absolute or relative. Example:
        # "survol/sources_types/enumerate_CIM_Process.py?xid=."
        idx_htbin = url_no_args.find("sources_types/")
        if idx_htbin == -1:
            # This may be the main presentation page of a Survol, WMI or WBEM object. Example:
            # "http://127.0.0.1:80/Survol/survol/entity.py?xid=CIM_Process.Handle=640"
            survol_prefix = "survol/"
            idx_survol = url_no_args.find(survol_prefix)
            if idx_survol == -1:
                # TODO: This happens if the URL is a main presentation page of an object,
                # instead of a script: Something like "survol/entity.py/entity.py?xid=..."
                # This should be fixed but is not an issue.
                logging.warning("merge: SHOULD NOT HAPPEN url=%s",
                                complete_url)
                url_path_short = "INVALID_MERGED_URL"
            else:
                # Just starts at the beginning of the script name: "entity.py", "entity_wmi.py", "entity_wbem.py".
                url_path_short = url_no_args[idx_survol + len(survol_prefix):]
        else:
            url_path_short = url_no_args[idx_htbin:]

        # url_path_short is the actual script to load.
        url_dir_nam = os.path.dirname(url_path_short)

        # The directory of the script is used to build a Python module name.
        modu_nam = url_dir_nam.replace("/", ".")

        url_fil_nam = os.path.basename(url_path_short)

        logging.debug(
            "url_path_short=%s url_dir_nam=%s modu_nam=%s url_fil_nam=%s",
            url_path_short, url_dir_nam, modu_nam, url_fil_nam)
        try:
            # argDir="sources_types.win32" urlFileNam="enumerate_top_level_windows.py"
            imported_mod = lib_util.GetScriptModule(modu_nam, url_fil_nam)
        except Exception as exc:
            logging.warning(
                "Caught %s when loading modu_nam=%s url_fil_nam=%s", exc,
                modu_nam, url_fil_nam)
            continue

        if not imported_mod:
            cumulated_error = "merge_scripts.py Cannot import complete_url=%s" % complete_url
            continue

        try:
            # The entire URL must be "injected" so the parameters will be properly parsed,
            # when Main() call lib_util.RequestUri().
            # The script passed as CGI parameter, believes that it is loaded as a plain URL.
            url_unquote = lib_util.urllib_unquote(complete_url)
            os.environ["REQUEST_URI"] = url_unquote

            os.environ['SCRIPT_NAME'] = url_fil_nam
            # "xid=EURO%5CLONL00111310@process:16580"
            os.environ['QUERY_STRING'] = cgi_query_string

            lib_common.enable_error_message(False)

            # This executes the script: The new nodes and links are merged in a global RDF container.
            imported_mod.Main()
        except Exception as exc:
            logging.warning(
                "Caught %s when executing Main in modu_nam=%s url_fil_nam=%s",
                exc, modu_nam, url_fil_nam)
            if cumulated_error != "":
                cumulated_error += " ; "
            cumulated_error += " url=" + url_no_args + " / " + url_fil_nam + ":" + str(
                exc)

            continue
        lib_common.enable_error_message(True)

    os.environ["REQUEST_URI"] = orig_req_uri

    # OutCgiRdf has been called by each script without writing anything,
    # but the specific parameters per script are stored inside.

    # Here, all the RDF nodes and links, loaded from each URL, and then merged in lib_common.globalGraph,
    # are then transformed into the chosen output format.
    lib_common.MergeOutCgiRdf(the_mode, cumulated_error)
Beispiel #13
0
def Main():
    origReqUri = lib_util.RequestUri()

    # There is only one cgiEnv and "cgiEnv.OutCgiRdf()" does not generate anything.
    lib_common.CgiEnvMergeMode()

    arguments = cgi.FieldStorage()

    # The display mode is read now, otherwise the CGI arguments are later destroyed, in this script.
    theMode = lib_util.GuessDisplayMode()
    sys.stderr.write("merge_scripts.py theMode=%s\n" % (theMode))

    # Concatenation of error messages of each script.
    cumulatedError = ""

    for urlfil in arguments.getlist("url"):
        # The parameters are coded in base64, although we leave the possibility not to encode them,
        # for compatibility with test scripts.

        complete_url = lib_util.Base64Decode(urlfil)

        sys.stderr.write("complete_url=%s\n" % complete_url)

        # Only the URL without the arguments.
        urlSplit = complete_url.split("?")
        urlNoArgs = urlSplit[0]
        if len(urlSplit) > 1:
            cgiQueryString = urlSplit[1]
        else:
            cgiQueryString = ""

        # The URL might be absolute or relative. Example:
        # "survol/sources_types/enumerate_CIM_Process.py?xid=."
        idxHtbin = urlNoArgs.find("sources_types/")
        if idxHtbin == -1:
            # This may be the main presentation page of a Survol, WMI or WBEM object. Example:
            # "http://127.0.0.1:80/Survol/survol/entity.py?xid=CIM_Process.Handle=640"
            survolPrefix = "survol/"
            idxSurvol = urlNoArgs.find(survolPrefix)
            if idxSurvol == -1:
                # TODO: This happens if the URL is a main presentation page of an object,
                # instead of a script: Something like "survol/entity.py/entity.py?xid=..."
                # This should be fixed but is not an issue.
                sys.stderr.write("merge: SHOULD NOT HAPPEN url=%s\n" %
                                 complete_url)
                urlPathShort = "INVALID_MERGED_URL"
            else:
                # Just starts at the beginning of the script name: "entity.py", "entity_wmi.py", "entity_wbem.py".
                urlPathShort = urlNoArgs[idxSurvol + len(survolPrefix):]
        else:
            urlPathShort = urlNoArgs[idxHtbin:]

        # urlPathShort is the actual script to load.
        urlDirNam = os.path.dirname(urlPathShort)
        moduNam = urlDirNam.replace("/", ".")

        urlFilNam = os.path.basename(urlPathShort)

        sys.stderr.write(
            "urlPathShort=%s urlDirNam=%s moduNam=%s urlFilNam=%s\n" %
            (urlPathShort, urlDirNam, moduNam, urlFilNam))
        try:
            # argDir="sources_types.win32" urlFileNam="enumerate_top_level_windows.py"
            importedMod = lib_util.GetScriptModule(moduNam, urlFilNam)
        except Exception:
            errorMsg = sys.exc_info()[1]
            sys.stderr.write(
                "Caught %s when loading moduNam=%s urlFilNam=%s\n" %
                (errorMsg, moduNam, urlFilNam))
            continue

        if not importedMod:
            cumulatedError = "merge_scripts.py Cannot import complete_url=%s" % (
                complete_url)
            continue

        try:
            # The entire URL must be "injected" so the parameters will be properly parsed,
            # when Main() call lib_util.RequestUri().
            urlUnquote = lib_util.urllib_unquote(complete_url)
            os.environ["REQUEST_URI"] = urlUnquote

            os.environ['SCRIPT_NAME'] = urlFilNam
            # "xid=EURO%5CLONL00111310@process:16580"
            os.environ['QUERY_STRING'] = cgiQueryString

            lib_common.ErrorMessageEnable(False)
            importedMod.Main()
        except Exception:
            errorMsg = sys.exc_info()[1]
            sys.stderr.write(
                "Caught %s when executing Main in moduNam=%s urlFilNam=%s\n" %
                (errorMsg, moduNam, urlFilNam))
            if cumulatedError != "":
                cumulatedError += " ; "
            cumulatedError += " url=" + urlNoArgs + " / " + urlFilNam + ":" + str(
                errorMsg)

            continue
        lib_common.ErrorMessageEnable(True)

    os.environ["REQUEST_URI"] = origReqUri

    # OutCgiRdf has been called by each script without writing anything,
    # but the specific parameters per script are stored inside.

    # TESTER AVEC CA:
    # http://127.0.0.1:8000/survol/merge_scripts.py?url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9ob3N0LnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBc3No&url=aHRiaW4vc291cmNlc190eXBlcy9DSU1fQ29tcHV0ZXJTeXN0ZW0vaG9zdG5hbWVfbm1hcC5weT94aWQ9Q0lNX0NvbXB1dGVyU3lzdGVtLk5hbWUlM0RVbmtub3duLTMwLWI1LWMyLTAyLTBjLWI1LTI&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9ob3N0LnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBc3ZybG9j&url=aHRiaW4vZW50aXR5LnB5P3hpZD1zbWJzaHIuSWQ9Ly8vL1dETXlDbG91ZE1pcnJvci9yY2hhdGVhdQ&url=aHRiaW4vc291cmNlc190eXBlcy9DSU1fQ29tcHV0ZXJTeXN0ZW0vY29ubmVjdGVkX3NvY2tldHMucHk_eGlkPUNJTV9Db21wdXRlclN5c3RlbS5OYW1lJTNEVW5rbm93bi0zMC1iNS1jMi0wMi0wYy1iNS0y&url=aHRiaW4vc291cmNlc190eXBlcy9DSU1fQ29tcHV0ZXJTeXN0ZW0vaG9zdG5hbWVfbm1hcC5weT94aWQ9Q0lNX0NvbXB1dGVyU3lzdGVtLk5hbWUlM0RVbmtub3duLTMwLWI1LWMyLTAyLTBjLWI1LTI&url=aHRiaW4vc291cmNlc190eXBlcy9ncm91cC9saW51eF91c2VyX2dyb3VwLnB5P3hpZD1ncm91cC5OYW1lJTNEYXBhY2hl&url=aHRiaW4vc291cmNlc190eXBlcy91c2VyL3VzZXJfbGludXhfaWQucHk_eGlkPXVzZXIuRG9tYWluJTNETG9jYWxIb3N0JTJDTmFtZSUzRGFwYWNoZQ&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9jb25uZWN0ZWRfcHJvY2Vzc2VzLnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBdGVsbmV0&url=aHRiaW4vc291cmNlc190eXBlcy91c2VyL3VzZXJfcHJvY2Vzc2VzLnB5P3hpZD11c2VyLkRvbWFpbiUzRExvY2FsSG9zdCUyQ05hbWUlM0RhcGFjaGU&url=aHRiaW4vc291cmNlc190eXBlcy9DSU1fUHJvY2Vzcy9wcm9jZXNzX2N3ZC5weT94aWQ9Q0lNX1Byb2Nlc3MuSGFuZGxlJTNEMTQ3MDU&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9jb25uZWN0ZWRfcHJvY2Vzc2VzLnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBc3No&url=aHRiaW4vc291cmNlc190eXBlcy9DSU1fUHJvY2Vzcy9wcm9jZXNzX2N3ZC5weT94aWQ9Q0lNX1Byb2Nlc3MuSGFuZGxlJTNEMTQ3MDU&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9jb25uZWN0ZWRfcHJvY2Vzc2VzLnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBdGVsbmV0&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9jb25uZWN0ZWRfcHJvY2Vzc2VzLnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBdGVsbmV0&url=aHRiaW4vc291cmNlc190eXBlcy9hZGRyL3NvY2tldF9jb25uZWN0ZWRfcHJvY2Vzc2VzLnB5P3hpZD1hZGRyLklkJTNEMTkyLjE2OC4xLjg4JTNBc3No&url=aHR0cDovLzE5Mi4xNjguMS44ODo4MC9TdXJ2b2wvaHRiaW4vZW50aXR5LnB5P3hpZD1DSU1fUHJvY2Vzcy5IYW5kbGU9MjA1MTI
    lib_common.MergeOutCgiRdf(theMode, cumulatedError)
Beispiel #14
0
    def __init__(self,
                 parameters=None,
                 can_process_remote=False,
                 layout_style="",
                 collapsed_properties=None):
        # It is possible to run these scripts as CGI scripts, so this transforms
        # command line arguments into CGI arguments. This is very helpful for debugging.

        # The HTTP server can set the logging level with the environment variable SURVOL_LOGGING_LEVEL.
        try:
            logging_level = os.environ["SURVOL_LOGGING_LEVEL"]
            logging.getLogger().setLevel(logging_level)
            logging.info("logging_level set with SURVOL_LOGGING_LEVEL=%s" % logging_level)
        except KeyError:
            logging.info("logging_level is not forced with SURVOL_LOGGING_LEVEL.")

        lib_command_line.command_line_to_cgi_args()
        assert "QUERY_STRING" in os.environ

        # Some limitations of cgiserver.py and Python2:
        # TODO: When running from cgiserver.py, and if QUERY_STRING is finished by a dot ".", this dot
        # TODO: is removed. Workaround: Any CGI variable added after.
        # TODO: Also: Several slashes "/" are merged into one.
        # TODO: Example: "xid=http://192.168.1.83:5988/." becomes "xid=http:/192.168.1.83:5988/"
        # TODO: ... or "xx.py?xid=smbshr.Id=////WDMyCloudMirror///jsmith" ...
        # TODO: ... becomes "xx.py?xid=smbshr.Id=/WDMyCloudMirror/jsmith"
        # TODO: Replace by "xid=http:%2F%2F192.168.1.83:5988/."

        mode = lib_util.GuessDisplayMode()
        logging.debug("mode=%s" % mode)

        # Contains the optional arguments of the script, entered as CGI arguments..
        self.m_parameters = parameters if parameters else {}

        self.m_parameterized_links = dict()

        self.m_layout_style = layout_style
        self.m_collapsed_properties = collapsed_properties if collapsed_properties else []

        # When in merge mode, the display parameters must be stored in a place accessible by the graph.

        doc_modu_all = _get_calling_module_doc()

        # Take only the first non-empty line. See lib_util.FromModuleToDoc()
        self.m_page_title, self.m_page_subtitle = lib_util.SplitTextTitleRest(doc_modu_all)

        # Title page contains __doc__ plus object label.

        # Example: REQUEST_URI=/Survol/survol/print_environment_variables.py
        # This does NOT contain the host and the port, which implies a confusion if severl Survol agents
        # use the same database. It makes sense, because the result should not depend in the agent.
        self.m_calling_url = lib_util.RequestUri()
        self.m_url_without_mode = lib_util.url_mode_replace(self.m_calling_url, "")

        full_title, entity_class, entity_id, entity_host = lib_naming.parse_entity_uri_with_host(
            self.m_calling_url,
            long_display=False,
            force_entity_ip_addr=None)
        # Here, the commas separating the CGI arguments are intact, but the commas in the arguments are encoded.
        entity_id_dict = lib_util.SplitMoniker(entity_id)

        self._concatenate_entity_documentation(full_title, entity_class, entity_id)

        # Global CanProcessRemote has precedence over parameter can_process_remote
        # which should probably be deprecated, although they do not have exactly the same role:
        # * Global CanProcessRemote is used by entity.py to display scripts which have this capability.
        # * Parameter can_process_remote is used to inform, at execution time, of this capability.
        # Many scripts are not enumerated by entity.py so a global CanProcessRemote is not necessary.
        # For clarity, it might be fine to replace the parameter can_process_remote by the global value.
        # There cannot be nasty consequences except that some scripts might not be displayed
        # when they should be, and vice-versa.
        try:
            globalCanProcessRemote = globals()["CanProcessRemote"]
        except KeyError:
            globalCanProcessRemote = False

        if can_process_remote != globalCanProcessRemote:
            # "INCONSISTENCY CanProcessRemote ... which is not an issue.
            can_process_remote = True

        self.m_can_process_remote = can_process_remote

        self.m_arguments = cgi.FieldStorage()

        self.m_entity_type = entity_class
        self.m_entity_id = entity_id
        self.m_entity_host = entity_host
        self.m_entity_id_dict = entity_id_dict

        self._create_or_get_graph()

        # Depending on the caller module, maybe the arguments should be 64decoded. See "sql/query".
        # As the entity type is available, it is possible to import it and check if it encodes it arguments.
        # See presence of source_types.sql.query.DecodeCgiArg(keyWord,cgiArg) for example.

        # This is probably too generous to indicate a local host.
        self.test_remote_if_possible(can_process_remote)

        if mode == "edit":
            self.enter_edition_mode()
            logging.critical("Should not be here because the HTML form is displayed.")
            assert False

        # Scripts which can run as events feeders must have their name starting with "events_feeder_".
        # This allows to use CGI programs as events genetors not written in Python.
        # TODO: Using the script name is enough, the module is not necessary.
        full_script_path, _, _ = self.m_calling_url.partition("?")
        script_basename = os.path.basename(full_script_path)
        daemonizable_script = os.path.basename(script_basename).startswith("events_feeder_")

        if not daemonizable_script:
            # This would be absurd to have a normal CGI script started in this mode.
            assert mode != "daemon", "Script is not an events generator:" + self.m_calling_url
            # Runs as usual as a CGI script. The script will fill the graph.
            return

        # The events graph must be specified because, from here, everything will access the events graph.
        set_events_credentials()

        # Maybe this is in the daemon.
        if mode == "daemon":
            # Just runs as usual. At the end of the script, OutCgiRdf will write the RDF graph in the events.
            # Here, this process is started by the supervisor process; It is not started by the HTTP server,
            # in CGI or WSGI.
            return

        try:
            # This may throw "[Errno 111] Connection refused"
            is_daemon_running = lib_daemon.is_events_feeder_daemon_running(self.m_url_without_mode)
        except Exception as exc:
            # Then display the content in snapshot mode, which is better than nothing.
            self.report_error_message("Cannot start daemon, caught:%s\n" % exc)
            logging.error("Cannot start daemon: When getting daemon status, caught:%s" % exc)
            return

        if not is_daemon_running:
            # This is the case of a daemonizable script, normally run.
            # TODO: Slight ambiguity here: The daemon could be intentionally stopped, and the user
            # TODO: would like to see the existing events stored in the persistent triplestore,
            # TODO: without restarting the daemon. We do not know how to do this yet.
            lib_daemon.start_events_feeder_daemon(self.m_url_without_mode)
            # After that, whether the daemon dedicated to the script and its parameters is started or not,
            # the script is then executed in normal, snapshot mode, as a CGI script.
        else:
            # Events are probably stored in the big events graph. The host and port are not used in the URL.
            lib_kbase.read_events_to_graph(self.m_url_without_mode, self.m_graph)

            # TODO: The layout parameters and any other display parameters of the calling script
            # TODO: must be in the constructor.
            # TODO: This, because the rest of the script is not executed.
            self.OutCgiRdf()

            # The rest of the script must not be executed because daemon scripts are organised so that
            # when the daemon is started, it writes all events in the database, to be read by the same script
            # run in CGI or WSGI.
            # The snapshot part of a daemon script is executed only when the deamon is not started.
            logging.info("Events are read from the events database because the deamon is running.")
            if _is_wsgi():
                logging.info("Leaving the execution of the script run in a WSGI server.")
                # This is not an error.
            else:
                logging.info("Exiting the process of the script run in snapshot mode and CGI server.")
            # This raises SystemExit which can be handled.
            exit(0)