Searching the Help
To search for information in the Help, type a word or phrase in the Search box. When you enter a group of words, OR is inferred. You can use Boolean operators to refine your search.
Results returned are case insensitive. However, results ranking takes case into account and assigns higher scores to case matches. Therefore, a search for "cats" followed by a search for "Cats" would return the same number of Help topics, but the order in which the topics are listed would be different.
Search for | Example | Results |
---|---|---|
A single word | cat
|
Topics that contain the word "cat". You will also find its grammatical variations, such as "cats". |
A phrase. You can specify that the search results contain a specific phrase. |
"cat food" (quotation marks) |
Topics that contain the literal phrase "cat food" and all its grammatical variations. Without the quotation marks, the query is equivalent to specifying an OR operator, which finds topics with one of the individual words instead of the phrase. |
Search for | Operator | Example |
---|---|---|
Two or more words in the same topic |
|
|
Either word in a topic |
|
|
Topics that do not contain a specific word or phrase |
|
|
Topics that contain one string and do not contain another | ^ (caret) |
cat ^ mouse
|
A combination of search types | ( ) parentheses |
|
Plug-Ins
Application Signatures plug-ins are ways of dynamically adding or removing functionality . Usually plug-ins are independent of each other and perform a single task.
In Universal Discovery, there is always a flow of execution similar to the following:
-
Discovery job starts
-
Job performs some activity (that is, executes commands)
-
Job formats results as a vector of Object State Holders
-
Job returns results and the execution ends
To add plug-ins to this job, the job at some point should pass control to the plug-ins and allow them to affect the results. This can be seen in the following diagram, where the arrow represents execution flow:
In general, for this mechanism to work at the point where the main module passes control to plug-ins, the answers to the following questions must be known:
-
What plug-ins exist in the system?
-
What plug-ins, from the whole set of plug-ins, should run along with this module?
-
What is the order of plug-ins?
-
Where is the plug-in’s code, and how can it be instantiated?
-
How does a plug-in pass its results to main module?
AutoDiscoveryContent package includes the python library plugins.py. This library contains the following classes that are used by the plug-ins feature:
-
Plugin
This is a base class for plug-ins. You should extend it to create a new plug-in. It contains the following methods:
-
isApplicable(context) – Method that is called by the plug-ins' framework, where the plug-in has a chance to perform a runtime check against a passed data in order to verify that required conditions are met. For example, in Application Signatures you can verify that a found application has information about a process with a specific name, and this process has a non-empty command line. Method should return True(1) if requirements are met. Implementation of this method is optional.
-
process(context) - Main method of the plug-in; where the main functionality should reside.
-
-
PluginContext
This class represents an object that allows sharing data between the main module and a plug-in, and between plug-ins. The main module can pass relevant data and support objects to the plug-in, such as a Discovery Framework object, and initialized clients. In turn, the plug-in can use these objects for its work and store the results in the same context. Both methods of the Plugin class - isApplicable() and process() - accept single parameter context.
Note The base class PluginContext does not have any methods out-of-the-box, since such methods are mostly defined by the data that plug-ins want to use and may differ from module to module. If you who want to add support for plug-ins to a module, you must create the appropriate context class.
-
PluginEngine
This is a main class that encapsulates all work with plug-ins. Its purpose is to find appropriate plug-ins, instantiate them, and run them when the client code passes control to it. The client module should create this object and use it without being concerned how the plug-in mechanisms are implemented. This class has one public method:
-
process(context, filter) – Main method of the plug-ins engine. In this method, engine forms a chain of plug-ins using the provided filter object. (See "PluginFilter", below.) For each such plug-in, it calls the isApplicable() method while passing context. If the plug-in returns true, the plug-in’s method process() is called with the same context. This way the context is passed from plug-in to plug-in.
-
-
PluginFilter
This represents a class encapsulating the logic of filtering plug-ins: selecting only the required plug-ins from the pool of all available plug-ins. PluginFilter defines asingle method:
filterPlugins(pluginDescriptors) – method that accepts the list of plug-in descriptors(described further) and returns the list of only those descriptors that satisfy some criteria. This method is called from PluginEngine.
-
QualifyingFilter
This is an implementation of PluginFilter, where the decision whether some plug-in should be included in the chain, is based on qualifiers defined in the plug-in descriptor and qualifiers of the filter itself. (See Qualifiers.) This class has the additional method: addQualifier(type, value) which adds a qualifier to this filter with a specific type and value.
Plug-ins are organized into plug-in packages. Each such package is a collection of plug-ins that usually have a common theme. For example: all discover SQL database version by shell. Usually the code for plug-ins is in one python module (a .py file) but it is possible to use multiple scripts if required.
Each plug-in package contains the following files:
- package configuration file
- one or more python scripts containing code for the plug-ins (one subclass of Plugin class per plug-in)
The plug-in package configuration file is an XML file with meta information describing the plug-ins. For example:
db_versions.package.xml
<?xml version="1.0" encoding="UTF-8" ?> <package parserClassName="com.hp.ucmdb.discovery. library.communication.downloader.cfgfiles.PluginsPackageConfigFile"> <plugins> <plugin id="mysql_version_by_shell"> <name>MySql version by shell</name> <description>Sets MySQL version attribute for discovered MySQL Server CI</description> <module>plugins_appsignature_dbversion_by_shell</module> <class>MySQLVersionShellPlugin</class> <qualifiers> <qualifier type="application">MySQL DB</qualifier> <qualifier type="protocol">ntadmin</qualifier> <qualifier type="protocol">ssh</qualifier> <qualifier type="protocol">uda</qualifier> <qualifier type="protocol">telnet</qualifier> </qualifiers> <dependencies> <module>file_ver_lib</module> <module>mysql_version_by_shell</module> </dependencies> </plugin> ... </plugins> </package>
<?xml version="1.0" encoding="UTF-8" ?> <package parserClassName="com.hp.ucmdb.discovery. library.communication.downloader.cfgfiles.PluginsPackageConfigFile"> <plugins> <plugin id="mysql_version_by_shell"> <name>MySql version by shell</name> <description>Sets MySQL version attribute for discovered MySQL Server CI</description> <module>plugins_appsignature_dbversion_by_shell</module> <class>MySQLVersionShellPlugin</class> <qualifiers> <qualifier type="application">MySQL DB</qualifier> <qualifier type="protocol">ntadmin</qualifier> <qualifier type="protocol">ssh</qualifier> <qualifier type="protocol">uda</qualifier> <qualifier type="protocol">telnet</qualifier> </qualifiers> <dependencies> <module>file_ver_lib</module> <module>mysql_version_by_shell</module> </dependencies> </plugin> ... </plugins> </package>
The format of this configuration file is as follows:
-
Attribute id of the plugin element defines the unique identification string for this plug-in. It is required to uniquely maintain the scope in all deployed packages.
-
Element name contains the user-friendly name of this plug-in, which may appear in the UI.
-
Element description contains a user-friendly description of the plug-in.
-
Element module defines the name of python module (.py file) with the code of the plug-in.
-
Element class defines the name of class that extends Plugin class, and which the plug-ins engine tries to instantiate.
-
Elements qualifier defines all qualifiers of plug-in; each such element has the attribute type, which is a type of qualifier.
-
Elements module enclosed in dependencies elements, defines the modules that should be loaded before loading the module of the plugin, and which are used by this plugin module.
The plug-ins python module is a regular python script that contains the code for plug-ins. Each plug-in should extend the Plugin class from plugins.py. You can have more than one plug-in in one python script, and you can have more than one script in one plug-ins package. Also, you are not limited in adding your own methods or classes.
Taking the Plug-in Package Configuration File, the corresponding script follows:
plugins_appsignature_dbversion_by_shell.py
#coding=utf-8 import re import sys import logger import mysql_version_by_shell from file_ver_lib import getLinuxFileVer
from plugins import Plugin
class MySQLVersionShellPlugin(Plugin): """ Plugin set MySQL version by shell, depends on OS type. """ def __init__(self): Plugin.__init__(self) self.__client = None self.__process = None self.__isWinOs = None self.__cmd = None def isApplicable(self, context): self.__client = context.client try: if self.__client.isWinOs(): self.__isWinOs = 1 self.__process = context.application.getProcess ('mysqld-nt.exe') if not self.__process: self.__process = context.application.getProcess ('mysqld.exe') else: self.__process = context.application.getProcess ('mysqld') if self.__process: return 1 except: logger.errorException(sys.exc_info()[1]) def process(self, context): applicationOsh = context.application.getOsh() mysql_version_by_shell.setVersion(applicationOsh, self.__ process.executablePath, self.__client) ...
class MySQLVersionShellPlugin(Plugin): """ Plugin set MySQL version by shell, depends on OS type. """ def __init__(self): Plugin.__init__(self) self.__client = None self.__process = None self.__isWinOs = None self.__cmd = None def isApplicable(self, context): self.__client = context.client try: if self.__client.isWinOs(): self.__isWinOs = 1 self.__process = context.application.getProcess ('mysqld-nt.exe') if not self.__process: self.__process = context.application.getProcess ('mysqld.exe') else: self.__process = context.application.getProcess ('mysqld') if self.__process: return 1 except: logger.errorException(sys.exc_info()[1]) def process(self, context): applicationOsh = context.application.getOsh() mysql_version_by_shell.setVersion(applicationOsh, self.__ process.executablePath, self.__client) ...
Notice that script name and class name correspond to data in the configuration file.
Qualifiers is the way to specify meta information for plug-in, which others can query and use. For example, you can say that a plug-in can run only on Windows, or is using a shell protocol. Qualifiers are like tags, but they contain two bits of information: qualifier type and qualifier value. Qualifiers are not limited in any way, so it is possible to use arbitrary textual values.
We use the qualifiers mechanism to select which plug-ins should run at a particular time. We create the QualifyingFilter instance and specify qualifiers on that filter. This filter selects only those plug-ins which specify qualifiers of the same type and the same values, or do not have qualifier of that type at all.
For example, in the Plug-in Package Configuration File, there are 2 qualifiers:
-
The qualifier application specifies that the plug-in should run only for applications with the name “MySQL DB”.
-
The qualifier protocol specifies that the plug-in works with the following protocols: NTCMD, SSH, UDA, and Telnet.
Qualifiers information is accessible from the plug-in configuration file before the plug-in is even instantiated. This enables the static filtering of plug-ins.
-
You must become familiar with specific implementations of the PluginContext class in order to know what data a plug-in passes on. For Application Signatures, refer to applications.py where the ApplicationSignatureContext class is located.
-
Create a new python module and add an implementation of the Plugin class there. In particular, you should write the code for methods isApplicable() and process() which accept context instance. The results of plug-in work should be saved to context.
-
Create a new plug-ins package configuration file with meta information about the plug-in; you should specify there information such as the python module name, class name , and so on. See Application Signatures Configuration File.
Note In particular, if necessary, you should specify the qualifiers for your plug-in which will be used to decide whether this plug-in should be run. You should know which qualifiers are actually used. For example, in Application Signatures, only 'application’ and ‘protocol’ qualifiers are specified.
-
Add the newly created file to a discovery package - either new or existing.
The downside of qualifiers and pluggability is that it can be difficult to determine how many plug-ins exist, and which of them run for any particular discovered RunningSoftware.