In the previous post I showed the complete end-to-end scenario of using synonyms in XS Advanced. In this post I will show, how more flexibility can be achieved.
The flexibility options do not really depend on whether accessing a classical schema or a generated HDI Container. Everything that is different was explained in the previous post. I will therefore only use a classical schema OR an HDI container as target, not both. And I will focus on the things that are different with flexible synonym targets.
When the target schema of a synonym is not known during design time or if you want to be able to easily switch to another schema as target, we need a mechanism to replace some symbolic or default schema by a concrete schema during deployment. Configuration files and a templating mechanism provide the required functionality. Configuration files also provide the functionality to change the targets of synonyms at a central place.
Since I do not want to hard-code the target objects in the .hdbsynonym files anymore, I remove the targets from those files. What remains can be seen as "declaration only" of a synonym, without defining any specific target:
Now I move the information about the target objects into an .hdbsynonymconfig file. Those configuration files have to be located in a folder cfg, which must be a subfolder of the db module’s root folder. The cfg folder can contain subfolders to reflect the project structure. The location of the .hdbsynonym files remain unchanged.
If existing, the configuration file is the place, where the target of a synonym is defined. Optionally, we could leave a default configuration in the .hdbsynonym files, which would then be overwritten by a configuration in the .hdbsynonymconfig files. But I find it much clearer it the configuration is only present in one place and therefore did not use any default configuration.
The syntax of the .hdbsynonymconfig file is almost identical to the .hdbsynonym file, but allows to use "schema.configure", followed by "<service_name>/schema" instead of a fixed schema name. During deployment (or build in Web IDE) the schema will then be replaced by the actual schema of the referenced service. This means, that we do not have to know the schema we are referencing in advance!
During deployment the cfg folder is scanned recursively for all synonym configurations found. Those define the targets of the synonyms (or replace an existing default configuration).
For compatibility reasons with older versions, there is also the possibility to use an .hdbsynonymtemplate file. An example for synonym SNWD_SO_SL is included in project repo.
Before building the project, I copy the .hdiconfig file from the src folder to the cfg folder, in case it is not already there.
I build the project in the Web IDE and check the synonyms in the DB Explorer. The schema name is EPM_DEV, even though we did not mention it explicitly anywhere in the project:
If we want to deploy the project to another system or another space, all we have to do is create a service “EPM_XXX-table-grantor” via “xs cups” in that system and space, pointing to the schema we want to access. Accessing another HDI Container works the same way. A HDI Container with the same service name we use in our project has to be available in the target organization/space of the deployment.
Using Service Replacement
Sometimes it is not wanted or not possible to create a grantor service with the name used in the development descriptor mta.yaml and the other files, like .hdbsynonymconfig or .hdbgrants files. Instead, an existing service shall be used, either in the Web IDE or during deployment. In order to support such use cases, a service replacement mechanism is offered. This feature is available starting with HANA 2.0 SPS0. To use this mechanism, we have to adapt the files using the service names and mta.yaml file of our project slightly.
First, I move the information about the target objects into an .hdbsynonymconfig file in a cfg folder. This is identical as in the previous chapter and I will not explain it further.
Different is, that I donot use a physical service name within the .hdbgrants and .hdbsynonymconfig files. Instead, I use a logical service name ("EPM_log-table-grantor").
Within the development descriptor mta.yaml file I define a mapping between the logical service name and a physical service name.
The development descriptor first defines a mapping from the logical service with key "EPM_log-table-grantor" to a resource "EPM_XXX-table-grantor". The resource name "EPM_XXX-table-grantor" is also the default value for the physical service name. This default service name is used when no replacement is provided. It can be overwritten with a parameter "service-name" of that resource. I highlighted the lines that create the mapping between logical service name, resource name (default physical service), and optional replacement via properties and parameter "service-name".
This gives us a lot of flexibility. I will show three different use cases.
1. Targeting the default service
An example is a deployed HDI Container containing the test data of a development system, that shall be accessed by an application during development.
For this use case, I can deploy/build the project with the mta.yaml file as shown above. Before deploying/building, I deployed the target HDI Container with the service name "EPM_XXX-table-grantor":
After building the project within Web IDE the target of the synonyms is this generated schema:
2. Targeting a Web IDE generated service
An example is an HDI Container that is developed in parallel with an application accessing objects in this HDI Container.
For this usecase I insert the service name of the target HDI container generated by the Web IDE as parameter in the last two lines of the mta.yaml file:
changed lines of mta.yaml file, providing a fixed parameter for use in Web IDE:
After building the project within Web IDE the target of the synonyms is now a schema generated by Web IDE:
3. Targeting a service, where the name is not known before deployment
An example is promoting to production, where you do not know the names of the production services during development.
To simulate this, I build the whole project without changing the mta.yaml file, download the mtar archive file, create an mta-extension file and deploy the mtar archive file using this mta-extension to a different space TST (development space is DEV). A template for the mta extension file is included in the repo.
syn-hdi-hdi-1.mtaext file with target service name supplied via parameter:
I did not want to change the service- and schema-name of the HDI Container containing the synonyms. Therefore I commented those lines in the mta extension file.
Target service in space TST:
Deployment in space TST
New service HDI Container with name "hdi-container" (admittedly not the best name...):
To check the deployed service with synonyms in space TST, I first have to assign my user as a developer to that space, using XSA Administration UI or XS CLI commands. Until now I was only working in space DEV.
Public synonyms can be defined from HDI using an .hdbpublicsynonym file. They should be used with special care since a public synonym can only be defined once in the whole database (singleton). Special configuration is needed to be able to create public synonyms, which can be looked up in the official documentation.
Synonyms can point to a different database container in a MDC enabled system. The synonym definition has to include the target database additionally to the target schema in this case. Configuration file templating can use "database.configure" to derive the database from a service.
I would like to draw your attention to some security aspects that are important when accessing other schemas using synonyms, without intention to cover this topic completely.
Every service in an XSA space can be accessed from any other service running in the same XSA space. Organizations and spaces are the concept that ensure, that only services can accessed, that are allowed to be accessed. This concept is not XSA specific, but originates in cloud-foundry.
If security considerations play a role during development, you should already use multiple spaces during development (available since SP12). E.g. you could create a space per project or even a space per developer. Within the XSA Admin tool you only assign the developer role to developers in those spaces that they are allowed to work in. In both, Web IDE and the HRTT (DB Browser in HANA 2.0) only those spaces can be accessed by a user, for which the user has the developer role.
When you create the services for accessing objects in other schemas via “xs cups”, you should create them very specific only for those objects you want to give access to. If you use a user with too many privileges in your services, those services could be (mis-) used to gain access to more objects than needed.
I would like to give a simple example:
For legal reasons there is a requirement within your company, that only project “VERY SECURE” is allowed to access employee data of a classical DB schema “HR”. In principle this could be solved int the following way:
Create a specific development space “Very_Secure”,
Give only specific developers the developer role in that space
Create a role in schema “HR” that allows to read the employee tables (only the tables that shall be exposed, not the whole schema!)
A special service user is created that can grant this role to other users
A service is created via xs cups in development space “Very_Secure”
This service is used to access the employee tables
Important: DO NOT CREATE general services via xs cups in any other space that allow granting arbitrary existing roles via system privilege “Role Admin”. This would allow anyone with access to that service and knowledge of the roles to gain access to the employee data
This example simplifies a little and is also not complete.
For more details on security in XS Advanced check the chapter "Security for SAP HANA Extended Application Services, Advanced Model" in the SAP HANA Security Guide
In this post I showed, how maximum flexibility regarding the target schema and service can be achieved, and how it is possible to change synonym targets at a central place. Since it cost only a very few lines of configuration in the development descriptor (mta.yaml) and an additional configuration file, I would always use this approach.