Пример #1
0
def script_url_to_source(callingUrl):

    parse_url = lib_util.survol_urlparse(callingUrl)
    query = parse_url.query

    params = parse_qs(query)

    xidParam = params['xid'][0]
    # sys.stdout.write("script_url_to_source xidParam=%s\n"%xidParam)
    (entity_type,entity_id,entity_host) = lib_util.ParseXid(xidParam)
    # sys.stdout.write("script_url_to_source entity_id=%s\n"%entity_id)
    entity_id_dict = lib_util.SplitMoniker(entity_id)
    # sys.stdout.write("entity_id_dict=%s\n"%str(entity_id_dict))

    # parse_url.path=/LocalExecution/sources_types/Win32_UserAccount/Win32_NetUserGetInfo.py
    # This is a very simple method to differentiate local from remote scripts
    if parse_url.path.startswith(lib_util.prefixLocalExecution):
        # This also chops the leading slash.
        pathScript = parse_url.path[len(lib_util.prefixLocalExecution) + 1:]
        objSource = SourceLocal(pathScript,entity_type,**entity_id_dict)

        # Note: This should be True: parse_url.netloc.startswith("LOCAL_MODE")
    else:
        objSource = SourceRemote(callingUrl,entity_type,**entity_id_dict)

    return objSource
Пример #2
0
	def GetId(self):
		sys.stderr.write("GetId m_entity_type=%s m_entity_id=%s\n" % ( self.m_entity_type, str( self.m_entity_id ) ) )
		try:
			# If this is a top-level url, no object type, therefore no id.
			if self.m_entity_type == "":
				return ""

			splitKV = lib_util.SplitMoniker(self.m_entity_id)
			sys.stderr.write("GetId splitKV=%s\n" % ( str( splitKV ) ) )

			# If this class is defined in our ontology, then we know the first property.
			entOnto = lib_util.OntologyClassKeys(self.m_entity_type)
			if entOnto:
				keyFirst = entOnto[0]
				# Only if this mandatory key is in the dict.
				try:
					return splitKV[keyFirst]
				except KeyError:
					# This is a desperate case...
					pass
			# Returns the first value but this is not reliable at all.
			for key in splitKV:
				return splitKV[key]
		except KeyError:
			pass

		# If no parameters although one was requested.
		self.EditionMode()
		return ""
Пример #3
0
def entity_id_to_instance(agent_url, class_name, entity_id):
    """This receives the URL of an object, its class and the moniker.
    It splits the moniker in key-value pairs.
    These are used to create a CIM object with key-value pairs transformed in attributes.
    Example: xid="CIM_Process.Handle=2092"
    BEWARE: Some arguments should be decoded from Base64."""

    xid_dict = lib_util.SplitMoniker(entity_id)

    new_instance = create_CIM_class(agent_url, class_name, **xid_dict)
    return new_instance
Пример #4
0
def WmiReadWithQuery(cgiEnv, connWmi, className):
    """
		Maybe reading with the moniker does not work because not all properties.
		This splits the moniker into key value paris, and uses a WQL query.
	"""
    splitMonik = lib_util.SplitMoniker(cgiEnv.m_entity_id)
    aQry = lib_util.SplitMonikToWQL(splitMonik, className)

    try:
        return connWmi.query(aQry)
    except Exception:
        exc = sys.exc_info()[1]
        lib_common.ErrorMessageHtml("Query=%s Caught:%s" % (aQry, str(exc)))
Пример #5
0
    def get_instance_bag_of_words(self):
        # TODO: And the host ?
        bagOfWords = set(self.__class__.__name__)

        # This is the minimal set of words.
        dictIds = lib_util.SplitMoniker( self.m_entity_id )
        for keyId in dictIds:
            bagOfWords.add(keyId)
            valId = dictIds[keyId]
            bagOfWords.add(valId)

        # TODO: Call AddInfo()

        return bagOfWords
Пример #6
0
    def _define_class_in_ontology(url_node):
        """This takes the class from an Url and defines it in the RDF ontology.
        This returns the class name as a string."""
        entity_label, class_name, entity_id = lib_naming.ParseEntityUri(
            url_node)

        # This could be: ("http://the_host", "http://primhillcomputers.com/survol/____Information", "HTTP url")
        if not class_name:
            return None

        # TODO: Define base classes with rdfs:subClassOf / RDFS.subClassOf
        # "base_class" and "class_description' ???

        # A class name with the WMI namespace might be produced with this kind of URL:
        # "http://www.primhillcomputers.com/survol#root\CIMV2:CIM_Process"
        class_name = class_name.replace("\\", "%5C")
        assert isinstance(class_name, str)

        if class_name not in map_classes:
            if class_name == "":
                raise Exception("No class name for url=%s type=%s" %
                                (str(url_node), str(type(url_node))))

            # Maybe this CIM class is not defined as an RDFS class.
            # This function might also filter duplicate and redundant insertions.
            lib_util.AppendClassSurvolOntology(class_name, map_classes,
                                               map_attributes)

        # The entity_id is a concatenation of CIM property-value paris, and define an unique object.
        # They are different of the triples, but might overlap.
        entity_id_dict = lib_util.SplitMoniker(entity_id)
        for predicate_key in entity_id_dict:
            if predicate_key not in map_attributes:
                # This function might also filter a duplicate and redundant insertion.
                lib_util.append_property_survol_ontology(
                    predicate_key, "CIM key predicate %s" % predicate_key,
                    class_name, None, map_attributes)

            # This value is explicitly added to the node.
            predicate_value = entity_id_dict[predicate_key]
            new_grph.add((url_node, lib_properties.MakeProp(predicate_key),
                          rdflib.Literal(predicate_value)))

        # This adds a triple specifying that this node belongs to this RDFS class.
        lib_kbase.add_node_to_rdfs_class(new_grph, url_node, class_name,
                                         entity_label)

        return class_name
Пример #7
0
def entity_to_label(entity_type, entity_ids_concat, force_entity_ip_addr):
    """
    This returns the label of an URL which is a script plus CGI arguments defining an object.

    For an association, we might have:
    entity_id=Dependent=root/cimv2:LMI_StorageExtent.CreationClassName="LMI_StorageExtent",SystemCreationClassName="PG_ComputerSystem" Antecedent=root/cimv2:LMI_DiskDrive.CreationClassName="LMI_DiskDrive",DeviceID="/dev/sda"
    This is not easy to manage but avoids ambiguities.
    """

    # Specific case of objtypes.py
    if not entity_ids_concat:
        return entity_type

    # TODO: Robust logic as long as the value does not contain an '=' sign.
    split_kv = lib_util.SplitMoniker(entity_ids_concat)

    # Now build the array of values in the ontology order.
    onto_keys = lib_util.OntologyClassKeys(entity_type)

    # Default value if key is missing.
    entity_ids_arr = [split_kv.get(key_onto, key_onto + "?") for key_onto in onto_keys]

    if force_entity_ip_addr:
        entity_label = _entity_array_to_alias(entity_type, entity_ids_arr, force_entity_ip_addr)
    else:
        entity_label = _entity_array_to_label(entity_type, entity_ids_arr)

    # There might be extra properties which are not in our ontology.
    # This happens if duplicates from WBEM or WMI. MAKE THIS FASTER ?
    # Both must be sets, otherwise unsupported operation.

    # TODO: This set could be created once and for all. But the original order must be kept.
    set_onto_keys = set(onto_keys)

    # This appends the keys which are not part of the normal ontology, therefore bring extra information.
    # This is rather slow and should normally not happen.
    for ext_prp_key, ext_prp_val in split_kv.items():
        if not ext_prp_key in set_onto_keys:
            entity_label += " %s=%s" % (ext_prp_key, ext_prp_val)

    return entity_label
Пример #8
0
def EntityToLabel(entity_type, entity_ids_concat, entity_host,
                  force_entity_ip_addr):
    # sys.stderr.write("EntityToLabel entity_id=%s entity_type=%s\n" % ( entity_ids_concat, entity_type ) )

    # Specific case of objtypes.py
    if not entity_ids_concat:
        return entity_type

    # TODO: Robust logic as long as the value does ot contain an '=' sign.
    splitKV = lib_util.SplitMoniker(entity_ids_concat)

    # Now build the array of values in the ontology order.
    ontoKeys = lib_util.OntologyClassKeys(entity_type)

    # Default value if key is missing.
    entity_ids_arr = [
        splitKV.get(keyOnto, keyOnto + "?") for keyOnto in ontoKeys
    ]

    if force_entity_ip_addr:
        entity_label = EntityArrToAlias(entity_type, entity_ids_arr,
                                        entity_host, force_entity_ip_addr)
    else:
        entity_label = EntityArrToLabel(entity_type, entity_ids_arr,
                                        entity_host)
    # sys.stderr.write("EntityToLabel entity_label=%s\n" % entity_label )

    # There might be extra properties which are not in our ontology.
    # This happens if duplicates from WBEM or WMI. MAKE THIS FASTER ?
    # Both must be sets, otherwise unsupported operation.

    # TODO: This set could be created once and for all. But the original order must be kept.
    setOntoKeys = set(ontoKeys)

    # This appends the keys which are not part of the normal ontology, therefore bring extra information.
    # This is rather slow and should normally not happen.
    for (extPrpKey, extPrpVal) in splitKV.items():
        if not extPrpKey in setOntoKeys:
            entity_label += " %s=%s" % (extPrpKey, extPrpVal)

    return entity_label
Пример #9
0
if className == "":
    lib_common.ErrorMessageHtml("No class name. entity_id=%s" % entity_id)

grph = cgiEnv.GetGraph()

conn = lib_wbem.WbemConnection(cimomUrl)

rootNode = lib_util.EntityClassNode(className, nameSpace, cimomUrl, "WBEM")
klaDescrip = lib_wbem.WbemClassDescription(conn, className, nameSpace)
if not klaDescrip:
    klaDescrip = "Undefined class %s %s" % (nameSpace, className)
grph.add(
    (rootNode, pc.property_information, lib_common.NodeLiteral(klaDescrip)))

splitMonik = lib_util.SplitMoniker(cgiEnv.m_entity_id)

sys.stderr.write("entity_wbem.py nameSpace=%s className=%s cimomUrl=%s\n" %
                 (nameSpace, className, cimomUrl))

# This works:
# conn = pywbem.WBEMConnection("http://192.168.0.17:5988",("pegasus","toto"))
# conn.ExecQuery("WQL","select * from CIM_System","root/cimv2")
# conn.ExecQuery("WQL",'select * from CIM_Process  where Handle="4125"',"root/cimv2")
#
# select * from CIM_Directory or CIM_DataFile does not return anything.


# If ExecQuery is not supported like on OpenPegasus, try to build one instance.
def WbemPlainExecQuery(conn, className, splitMonik, nameSpace):
    aQry = lib_util.SplitMonikToWQL(splitMonik, className)
Пример #10
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()
Пример #11
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)
Пример #12
0
def Main():

	cgiEnv = lib_common.CgiEnv(can_process_remote = True)

	entity_id = cgiEnv.GetId()
	DEBUG("entity_id=%s", entity_id)
	if entity_id == "":
		lib_common.ErrorMessageHtml("No entity_id")


	# Just the path, shorter than cgiEnv.get_parameters("xid")
	cimomUrl = cgiEnv.GetHost()

	nameSpace, className = cgiEnv.get_namespace_type()
	DEBUG("entity_wbem.py cimomUrl=%s nameSpace=%s className=%s", cimomUrl,nameSpace,className)

	if nameSpace == "":
		nameSpace = "root/cimv2"
		INFO("Setting namespace to default value\n")


	if className == "":
		lib_common.ErrorMessageHtml("No class name. entity_id=%s" % entity_id)

	grph = cgiEnv.GetGraph()

	conn = lib_wbem.WbemConnection(cimomUrl)

	rootNode = lib_util.EntityClassNode( className, nameSpace, cimomUrl, "WBEM" )
	klaDescrip = lib_wbem.WbemClassDescription(conn,className,nameSpace)
	if not klaDescrip:
		klaDescrip = "Undefined class %s %s" % ( nameSpace, className )
	grph.add( ( rootNode, pc.property_information, lib_common.NodeLiteral(klaDescrip ) ) )

	splitMonik = lib_util.SplitMoniker( cgiEnv.m_entity_id )

	DEBUG("entity_wbem.py nameSpace=%s className=%s cimomUrl=%s",nameSpace,className,cimomUrl)

	# This works:
	# conn = pywbem.WBEMConnection("http://192.168.0.17:5988",("pegasus","toto"))
	# conn.ExecQuery("WQL","select * from CIM_System","root/cimv2")
	# conn.ExecQuery("WQL",'select * from CIM_Process  where Handle="4125"',"root/cimv2")
	#
	# select * from CIM_Directory or CIM_DataFile does not return anything.


	instLists = WbemPlainExecQuery( conn, className, splitMonik, nameSpace )
	DEBUG("entity_wbem.py instLists=%s",str(instLists))
	if instLists is None:
		instLists = WbemNoQueryOneInst( conn, className, splitMonik, nameSpace )
		if instLists is None:
			instLists = WbemNoQueryFilterInstances( conn, className, splitMonik, nameSpace )

	# TODO: Some objects are duplicated.
	# 'CSCreationClassName'   CIM_UnitaryComputerSystem Linux_ComputerSystem
	# 'CreationClassName'     PG_UnixProcess            TUT_UnixProcess
	numInsts = len(instLists)

	# If there are duplicates, adds a property which we hope is different.
	propDiscrim = "CreationClassName"

	# TODO!! WHAT OF THIS IS NOT THE RIGHT ORDER ???
	# Remove the double-quotes around the argument. WHAT IF THEY ARE NOT THERE ??
	# arrVals = [ ChopEnclosingParentheses( splitMonik[qryKey] ) for qryKey in splitMonik ]

	for anInst in instLists:

		# TODO: Use the right accessor for better performance.
		# On peut peut etre mettre tout ca dans une fonction sauf l execution de la query.
		dictInst = dict(anInst)

		# This differentiates several instance with the same properties.


		if numInsts > 1:
			# TODO: Should check if this property is different for all instances !!!
			withExtraArgs = { propDiscrim : dictInst[ propDiscrim ] }
			allArgs = splitMonik.copy()
			allArgs.update(withExtraArgs)
			dictProps = allArgs
		else:
			dictProps = splitMonik

		hostOnly = lib_util.EntHostToIp(cimomUrl)
		if lib_util.IsLocalAddress(hostOnly):
			uriInst = lib_common.gUriGen.UriMakeFromDict(className, dictProps)
		else:
			uriInst = lib_common.RemoteBox(hostOnly).UriMakeFromDict(className, dictProps)

		grph.add( ( rootNode, lib_common.MakeProp(className), uriInst ) )

		AddNamespaceLink(grph, rootNode, nameSpace, cimomUrl, className)

		# None properties are not printed.
		for inameKey in dictInst:
			# Do not print twice values which are in the name.
			if inameKey in splitMonik:
				continue
			inameVal = dictInst[inameKey]
			# TODO: If this is a reference, create a Node !!!!!!!
			if not inameVal is None:
				grph.add( ( uriInst, lib_common.MakeProp(inameKey), lib_common.NodeLiteral(inameVal) ) )

		# TODO: Should call Associators(). Same for References().

	cgiEnv.OutCgiRdf()