SAP Business Suite Discovery Capabilities in Tideway Foundation: a technical overview
This blog will go through the technical steps that Tideway Foundation takes when modeling an SAP Suite instance, be it on a single host, or across multiple hosts.
We’re going to start from the SAP Application Server, then explain the modeling of an SAP Suite instance, and finally go in-depth, into the Database queries that we employ, and how we interpret their results.
SAP Application Server
The first step is taken when the SAP Application Server is recognized as running on a given host. This is the case when Tideway discovers the sapstartsrv.exe or sapstartsrv process running. The pattern will then parse the process arguments, and will infer:
Instance Name: The instance of the running Application Server
System Name: The SAP SID, or name of the SAP system
Profile Directory: the directory containing the configuration profiles
This is an example of the process arguments: pf=C:\usr\sap\SBX\SYS\profile\START_DVEBMGS01_SALSA
This is the code that allows these attributes to be retrieved:
if “args” in process then instance_name := regex.extract(process.args,regex '(?i)pf=.*(?:/|\\)START_([^_]*)_',raw ‘\1’); system_name := regex.extract(process.args, regex “(?i)[/\\]([^/\\]+)[/\\]SYS[/\\]profile[/\\]”, raw “\1”); profile_dir := regex.extract(process.args, regex “(?i)pf=(.*[/\\])START_”, raw “\1”); end if;
The pattern will then proceed to model an SAP Application Server Software Instance. Afterwards, it will retrieve 3 configuration profiles:
Default Profile: a profile common to all the SAP Application Servers belonging to the same System (SID). Example filename: DEFAULT.PFL
Instance Profile: a profile unique to the specific Application Server instance. Example filename: SID_INSTANCE_HOSTNAME
Startup Profile: a profile unique to the specific Application Server instance, containing Startup information. Example filename: START_INSTANCE_HOSTNAME
Each file is stored in a File Node, and linked directly to the relevant SAP Application Server Software Instance. The Default Profile is going to be especially useful in identifying which Database is supporting the SAP Suite instance. This is the Database that we’re going to query, and collect relevant data from.
The following is the code that allows the Instance Profile file to be retrieved, stored as a File Node, and linked to the SI. Note that system_name, instance_name and profile_dir, the key variables which allow us to retrieve the file location and name, were all retrieved from the process arguments, in the code section illustrated above.
if system_name then instance_profile_relative_path := “system_name_%instance_name%_%host.name%”; instance_profile_path := “profile_dir%instance_profile_relative_path%”; log.debug(“Going to extract the following file: instance_profile_path.”); instance_profile_file := discovery.fileGet(process, “instance_profile_path“); if not instance_profile_file then instance_profile_relative_path := text.upper(instance_profile_relative_path); instance_profile_path := “profile_dir%instance_profile_relative_path%”; log.debug(“Going to extract the following file: instance_profile_path.”); instance_profile_file := discovery.fileGet(process, “instance_profile_path“); end if; if instance_profile_file and “content” in instance_profile_file then if_node := model.File(key := “instance_profile_path/%host.key%”, type := “SAP Instance Profile”, name := “File instance_profile_path on host.name“, path := instance_profile_path, size := instance_profile_file.size, md5sum := instance_profile_file.md5sum, last_modified := instance_profile_file.last_modified, content := instance_profile_file.content); file_list := file_list + [if_node]; end if; end if; […] if file_list then model.rel.RelatedFile(ElementUsingFile := app_si, File := file_list); log.debug(“Profile File(s) related to app_si.name.”); end if;
Note: the 3 profile files are stored in a File Node, so that they are easily browsable and readable. Should you want to extract specific information from them, and store them in a specific attribute, please let us know.
Identifying the supporting Database
The pattern responsible for modeling the SAP Suite Software Instance triggers as soon as the SAP Application Server SI is modeled.
This pattern retrieves the Default Profile file – which was stored as a File node – and extracts DB location from it.
This is the code used to retrieve the Default Profile file from the SAP Application Server SI:
default_profile_files := search(in sap_app_si traverse ElementUsingFile:RelatedFile:File:File where type = “SAP Default Profile”);for dpf in default_profile_files do if dpf and “content” in dpf then default_profile_file := dpf; end if;
end for;
These are the attributes that are extracted:
j2ee/dbtype: the DB type. We are currently supporting MS SQL DB and Oracle DB. Work for IBM DB2 is under way
j2ee/dbhost: the Hostname where the DB is running
j2ee/dbname: the DB Name or SID, depending on the DB type.
These attributes are extracted using the following code:
db_type_short := regex.extract(default_profile_file.content, regex “j2ee/dbtype *= *(\S+)”, raw “\1”);
db_type := DBTypes[db_type_short];
log.debug(“DB Type: db_type.”);if db_type = “MS SQL” then db_host := regex.extract(default_profile_file.content, regex “j2ee/dbhost *= *(\S+)”, raw “\1”); log.debug(“DB Host: db_host.”);
db_name := regex.extract(default_profile_file.content, regex “j2ee/dbname *= *(\S+)”, raw “\1”); […] elif db_type = “Oracle” then db_host := regex.extract(default_profile_file.content, regex “j2ee/dbhost *= *(\S+)”, raw “\1”); log.debug(“DB Host: db_host.”); db_sid := regex.extract(default_profile_file.content, regex “j2ee/dbname *= *(\S+)”, raw “\1”); […] end if;
The pattern will then perform a search for Software Instances of a specific DB Type, with a specific Name/SID, and running on a specific Host, based on the retrieved attributes.
Querying the Database
Once the DB location is known, the pattern retrieves the port that the DB is listening on. The first place it looks in is the port attribute in the DB Software Instance. If that attribute isn’t present, the pattern looks for the value entered in the SAP Configuration Section for the pattern. The value in this section is defined by the user.
After the port is known, the pattern proceeds to run a set of queries. We’re reporting the 3 most relevant of them.
Versioning Query
select * from CVERS_TXT
This query returns the version of SAP Suite, and it also returns the application/system type that is running. Typical examples are: ERP, CRM, Netweaver…
Licensing Query
select * from MLICHECK
This query returns Licensing data for an SAP Suite instance. The attributes returned are:
- License Key
- Start Date
- Expiration Date
- Max Users allowed
This is an example of a Licensing Query call from the pattern:
if db_type = "MS SQL" then
rows := MSSQLQueries.LicensingQuery(endpoint := remote_db_server,
port := port,
database := db_name);
elif db_type = "Oracle" then
rows := OracleQueries.LicensingQuery(endpoint := remote_db_server,
port := port,
sid := db_name);
else
rows := none;
end if;
All the resulting data is stored in a Licensing Detail, which is linked to and easily accessible from the SAP Suite Software Instance.
Components Query
select * from CVERS
This is a key query: it returns a list of all the installed components in an SAP Suite instance, such as EA-FINSERV (Financial Services) and EA-HR (Human Resources). This should make the purpose of an SAP Suite instance immediately clear to the user. The query is also going to return Release and Extended Release.
The attributes returned from the Components Query are initially stored in a list, using this code:
if rows then
for row in rows do
components := components + [["%row.component%", "%row.release%", "%row.extrelease%", ""]];
log.debug("Component: %row.component%, Release: %row.release%, Ext Release: %row.extrelease%");
end for;
end if;
Note: The empty string at the end of the list will be later filled in with the results from another query, which returns a description for each component.
Subsequently, each component is modeled into a Detail Node, using the following code:
for component in components doif component[0] thendt_name := component[0];dt_type := “Installed Software Component”; dt_key := “dt_name/%dt_type%/%sap_si.key%”; component_dt := model.Detail(key := dt_key, type := dt_type, name := dt_name,release := component[1],extended_release := component[2]);if component[3] thencomponent_dt.description := component[3];end if; component_dt_list := component_dt_list + [component_dt]; end if; end for;
Finally, the modeled Detail Nodes are related to the SAP Suite Software Instance:
model.rel.Detail(ElementWithDetail := sap_si, Detail := component_dt_list);
log.debug("Components added as Details to %sap_si.type% SI.");
Conclusions
This approach models an instance of SAP Suite, comprising its supporting Application Servers and Database, its license key, and installed software components. It encloses them in an organic model, which is easily browsable from the Tideway UI.
For a more comprehensive description and outline of the pattern, please refer to the SAP Business Suite Configipedia page.
For a more problem oriented view, please refer to the SAP Business Suite Discovery Capabilities from Tideway Foundation blog.
Edoardo L’Astorina

