Skip to content
Search

    Deploy as Multitenant SaaS Application

    This guide explains how to deploy CAP multitenant SaaS applications to SAP BTP Cloud Foundry environment, and how SaaS Customers would subscribe to them.

    This guide is also available as CAP Notebook.

    Intro & Overview

    Software-as-a-Service (SaaS) solutions are deployed once by a SaaS provider, and then used by multiple SaaS customers subscribing to the software.

    SaaS applications need to register with the SaaS Provisioning Service to handle subscribe and unsubscribe events. In contrast to single-tenant deployments, databases or other tenant-specific resources aren’t created and bootstrapped upon deployment, but upon subscription per tenant.

    CAP includes the MTX services, which provide out-of-the-box handlers for subscribe/unsubscribe events, with automatic creation of SAP HANA database containers or SAP Event Mesh instances.

    If everything is set up, the following graphic shows what’s happening when a user subscribes to a SaaS application:

    saas-overview.drawio

    1. The SaaS Provisioning Service sends a subscribe event to the CAP application.
    2. The CAP application delegates the request to the MTX services.
    3. The MTX services use Service Manager to create the database tenant.
    4. The CAP Application connects to this tenant at runtime using Service Manager.

    Prepare for Production

    The detailed procedure is described in the Deploy to Cloud Foundry guide. To start with this guide, you fulfill all Prerequisites and went through Prepare for Production, or instead run this command to fast-forward:

    cds add hana,xsuaa,approuter,mta --for production
    

    Add MTX

    To enable MTX services for your project, run the following command:

    cds add mtx --for production
    

    This modifies the modules and resources in mta.yaml for multitenant deployment.

    Learn more about MTX services.

    Build & Deploy

    You know the build and deploy steps from the Deploy to Cloud Foundry guide.

    mbt build -t gen --mtar mta.tar
    

    Learn more about Build & Assemble

    cf deploy gen/mta.tar
    

    Learn more about Deploy to Cloud Foundry.

    Subscribe

    Create a BTP subaccount to subscribe to your deployed application. This subaccount has to be in the same region, for example, us10.

    Global Account view

    In your subscriber account go to Instances and Subscription and select Create. subscriber account

    Select bookshop and use the only available plan default. Inst

    Go to Application. subscribed bookshop

    As you can see, your route doesn’t exist yet. You need to create and map it first.

    Leave the window open. You need the information to create the route.

    route doesn't exist

    Switch to your provider account and go to your space → Routes Route Screen

    Click New Route New Route wizard

    Use the broken route to fill the fields. For the following explanations let’s use this route as example: https://my-account.cfapps.acme.com

    • As Domain, use the part that usually starts with cfapps… and ends with .com

      In our example, the domain is: cfapps.acme.com

    • As Host Name, use the part between https:// and .cfapps

      In our example, host name is: my-account

    • Click Save

    You can now see the route is created but not mapped yet (none). Overview

    Click Map Route Map Route

    Select bookshop, which is the App Router application we just deployed, and save. Overview with new mapped route

    You’ve successfully created the route for your subscribed bookshop multitenant application. Refresh the browser tab of the bookshop application and log in.

    Behind the Scenes

    With adding the MTX services, your project configuration is adapted at all relevant places. Configuration and dependencies are added to your package.json and an xs-security.json containing MTX-specific scopes and roles is created.

    For the MTA deployment service dependencies are added to the mta.yaml file. Each SaaS application will have bindings to at least three SAP BTP service instances.

    Service Description
    Service Manager (service-manager) CAP uses this service for creating a new SAP HANA Deployment Infrastructure (HDI) container for each tenant and for retrieving tenant-specific database connections.
    SaaS Provisioning Service (saas-registry) To make a SaaS application available for subscription to SaaS consumer tenants, the application provider must register the application in the SAP BTP Cloud Foundry environment through the SaaS Provisioning Service.
    User Account and Authentication Service (xsuaa) Binding information contains the OAuth client ID and client credentials. The XSUAA service can be used to validate the JSON Web Token (JWT) from requests and to retrieve the tenant context from the JWT.

    If you’re interested, use version control to spot the exact changes.

    Appendix — Configuration

    SaaS Service Dependencies

    If you require SAP reuse services, that need subscriptions, use cds.mtx.dependencies in your package.json and pass an array of their xsappnames.

    The SaaS Provisioning service (getDependencies handler) needs this information.

    "mtx": {
      "dependencies": ["xsappname-1", "xsappname-2"]
    }
    

    Maven Dependencies

    Multitenancy support is available as optional application feature of the CAP Java SDK. It’s already included when you use the cds-starter-cloudfoundry dependency. Otherwise, you can add the following Maven dependency to apply the feature:

    <dependency>
        <groupId>com.sap.cds</groupId>
        <artifactId>cds-feature-mt</artifactId>
    </dependency>
    

    Having added this dependency to your project, multitenancy support becomes only active when additional services are configured as described in Configuring Required Platform Services and Adding the MTX Sidecar Module.

    Configuring Platform Services

    To enable multitenancy on SAP BTP, three services are involved:

    Only when these services are bound to your application, the multitenancy feature is turned on. You can either create and configure these services manually. See section Developing Multitenant Applications in SAP BTP, Cloud Foundry Environment for more details. The following sections describe how to configure and bind these services by means of an mta.yaml file.

    XSUAA

    A special configuration of the application’s XSUAA service instance is required to enable authorization between the SaaS Provisioning service, CAP Java application, and MTX sidecar.

    The service can be configured in the mta.yaml by adding an xsuaa resource as follows:

    resources:
      [...]
      - name: xsuaa
        type: com.sap.xs.uaa
        parameters:
          service-plan: application
          path: ./xs-security.json
          config:
            xsappname: <appname>
    

    Choose a value for property xsappname that is unique globally.

    Also, you have to create an Application Security Descriptor (xs-security.json) file, which must include two scopes:

    • mtcallback
    • mtdeployment

    You can also use custom scope names by configuring them. Use the following application configuration properties:

    • mtcallback: cds.multitenancy.security.subscription-scope
    • mtdeployment: cds.multitenancy.security.deployment-scope

    The mtcallback scope is required by the onboarding process. The mtdeployment scope is required to redeploy database artifacts at runtime.

    An example xs-security.json file looks like this:

    {
        "xsappname": "<appname>",
        "tenant-mode": "shared",
        "scopes": [
            {
                "name": "$XSAPPNAME.mtcallback",
                "description": "Multi Tenancy Callback Access",
                "grant-as-authority-to-apps": [
                    "$XSAPPNAME(application, sap-provisioning, tenant-onboarding)"
                ]
            },
            {
                "name": "$XSAPPNAME.mtdeployment",
                "description": "Scope to trigger a re-deployment of the database artifacts"
            }
        ],
        "authorities": [
            "$XSAPPNAME.mtdeployment"
        ]
    }
    

    In this example, the grant-as-authority-to-apps section is used to grant the mtcallback scope to the applications sap-provisioning and tenant-onboarding. These are services provided by SAP BTP involved in the onboarding process.

    It isn’t necessary to have the security configuration in a separate file. It can also be added to the mta.yaml file directly.

    ❗ Warning The mtcallback and mtdeployment scopes must not be exposed to any business user, for example, using a role template. Else a malicious user could update or even delete the artifacts of arbitrary tenants. In addition, if you implement a service broker in order to expose your service API for (technical) users of SaaS tenants, you must ensure that both scopes cannot be consumed as authorities in cloned service instances created by clients. To achieve that, set authorities-inheritance: false. It is strongly recommended to explicitly enumerate all authorities that should be exposed in the the broker configuration (allow-list).

    Service Manager

    A service instance of the Service Manager (service-manager) is required for CAP Java to create database containers per tenant at application runtime. It doesn’t require special parameters and can be added as a resource in mta.yaml as follows:

    resources:
      [...]
      - name: service-manager
        type: org.cloudfoundry.managed-service
        parameters:
          service: service-manager
          service-plan: container
    

    SaaS Provisioning Service

    A service instance of the SaaS Provisioning service (type saas-registry) is required to make your application known to the SAP BTP Provisioning Service and to register the endpoints that should be called when tenants are added or removed. The service can be configured as a resource in mta.yaml as follows. See section Register the Multitenant Application to the SaaS Provisioning Service for more details.

    resources:
      [...]
      - name: saas-registry
        type: org.cloudfoundry.managed-service
        parameters:
          service: saas-registry
          service-plan: application
          config:
            appName: <app display name>
            xsappname: <appname>
            appUrls:
              getDependencies: ~{srv/url}/mt/v1.0/subscriptions/dependencies
              onSubscription: ~{srv/url}/mt/v1.0/subscriptions/tenants/{tenantId}
              onSubscriptionAsync: true
              onUnSubscriptionAsync: true
              callbackTimeoutMillis: 3600000
        requires:
          - name: srv
    

    It’s required to configure the parameters:

    • appName: Choose an appropriate application display name.
    • xsappname: Use the value for xsappname you configured at your UAA service instance.
    • appUrls: Configure the callback URLs used by the SaaS Provisioning service to get the dependencies of the application and to trigger a subscription. In the above example, the property ~{srv/url} is used, which is provided by the srv module. See section Configuring the Java Service for more details. If you use different module and property names for your CAP Java backend module, you have to adapt these properties here accordingly.

    Make sure to choose the asynchronous subscription (onSubscriptionAsync: true) and unsubscription mode (onUnSubscriptionAsync: true). Always keep callbackTimeoutMillis in sync with cds.multitenancy.provisioningservice.pollingTimeout (default: 10min).

    Adding the MTX Sidecar

    This section describes how to use the cds-mtxs Node.js module and add the MTX sidecar microservice to the mta.yaml file.

    To define the dependencies and start command, create a subfolder named mtx/sidecar, and within that folder create a file named package.json :

    {
      "cds": {
        "requires": {
          "[production]": {
            "db": "hana-mt",
            "auth": "xsuaa"
          },
          "[development]": {
            "db": "sqlite",
            "auth": "dummy"
          },
          "cds.xt.ModelProviderService": "in-sidecar",
          "cds.xt.DeploymentService": true,
          "cds.xt.SaasProvisioningService": true
        }
      },
      "devDependencies": {
        "sqlite3": "^5.0.2"
      },
      "engines": {
        "node": "^16.15.0"
      },
      "scripts": {
        "start": "cds run",
        "build": "npm install && cds build ../.. --for mtx-sidecar && cd gen && npm install"
      }
    }
    

    Please note, that it’s required to activate the ModelProviderService in the sidecar application so that tenant-specific CDS models are served at runtime.

    Activate multitenancy in the main application’s .cdsrc.json. If required, activate extensibility and/or feature toggles as well:

    {
      "requires": {
        ...
        "multitenancy": true,
        "extensibility": true,
        "toggles": true,
        ...
      }
    }
    

    Learn more about MTX services and their configuration.

    Next, add the required dependencies by calling the below command in the mtx/sidecar directory:

    npm add @sap/cds @sap/cds-mtxs @sap/xssec hdb express passport
    

    The cds-mtxs module requires @sap/cds version 6 at least.

    Because the MTX sidecar needs to know the base CDS model and features, you additionally need to configure the build task by means of the .cdsrc.json file in the root folder of your project:

    {
        "requires": {
            "multitenancy": true,
            "toggles": true
        },
        "build": {
            "target": ".",
            "tasks": [
                {
                    "for": "java"
                },
                {
                    "for": "mtx-sidecar"
                },
                {
                    "for": "hana"
                }
            ]
        },
        "hana": {
            "deploy-format": "hdbtable"
        }
    }
    

    This configuration relates to the default project folder layout with app, db, srv, fts and mtx/sidecar. If you have a different layout, please adapt the configuration accordingly.

    Make sure to run cds build with @sap/cds-dk version 6 at least.

    A detailed description of this configuration file can be found in section Build Configuration.

    Now, add the mtx-sidecar module to your mta.yaml file:

    modules:
      [...]
      - name: mtx-sidecar
        type: nodejs
        path: mtx/sidecar
        build-parameters:
          builder: custom
          build-result: gen
          commands:
            - npm run build
        parameters:
          memory: 256M
          disk-quota: 512M
        requires:
          - name: xsuaa
          - name: service-manager
        provides:
          - name: mtx-sidecar
            properties:
              url: ${default-url}
    

    The mtx-sidecar module requires the XSUAA and Service Manager services. Also the sidecar exposes its own URL (note that ${default-url} is a placeholder for the own URL) which is required to configure the service module. The Cloud MTA Build Tool executes the build script which is provided in mtx/sidecar/package.json to build the MTX Sidecar application.

    Configuring the Java Service

    To make use of the previously mentioned services and the MTX sidecar in your CAP Java multitenant application, you need to enhance the srv module in the mta.yaml file:

    modules:
      [...]
      - name: srv
        type: java
        path: srv
        parameters:
          [...]
        requires:
          - name: service-manager
          - name: xsuaa
          - name: saas-registry
          - name: mtx-sidecar
            properties:
              CDS_MULTITENANCY_MTXS_ENABLED: true
              CDS_MULTITENANCY_SIDECAR_URL: ~{url}
          - name: app
            properties:
              CDS_MULTITENANCY_APPUI_URL: ~{url}
              CDS_MULTITENANCY_APPUI_TENANTSEPARATOR: "."
        provides:
          - name: srv
            properties:
              url: '${default-url}'
    
    • The environment variable CDS_MULTITENANCY_MTXS_ENABLED sets application property cds.multitenancy.mtxs.enabled and is used to activate streamlined MTX (default is classic MTX).
    • CDS_MULTITENANCY_SIDECAR_URL sets the application property cds.multitenancy.sidecar.url. This URL is required by the CAP Java runtime to connect to the MTX Sidecar application and is derived from the property url of the mtx-sidecar module.
    • Similarly, CDS_MULTITENANCY_APPUI_URL configures the URL that is shown in the SAP BTP Cockpit. Usually it points to the app providing the UI, which is the module app in this example.

    The tenant application requests are separated by the tenant specific app URLs. The tenant specific URL is made up of:

    https://<subaccount subdomain><CDS_MULTITENANCY_APPUI_TENANTSEPARATOR><CDS_MULTITENANCY_APPUI_URL>
    

    Currently only the value "." is allowed for CDS_MULTITENANCY_APPUI_TENANTSEPARATOR. The actual URL shown in the SAP BTP Cockpit is then composed of:

    https://<subaccount subdomain>.<CDS_MULTITENANCY_APPUI_URL>
    

    Adding Custom Handlers

    The SaaS Provisioning service in SAP BTP sends specific requests to applications when tenants are subscribed or unsubscribed. For these requests, CAP Java internally generates CAP events on the technical service MtSubscriptionService.

    For a general introduction to CAP events, see Service Provisioning API.

    Register event handlers for the following CAP events to add custom logic for requests sent by the SaaS Provisioning service. Each event passes a special type of EventContext object to the event handler method and provides event-specific information:

    Event Name Event Context Use Case  
    EVENT_GET_DEPENDENCIES MtGetDependenciesEventContext Dependencies  
    EVENT_ASYNC_SUBSCRIBE MtAsyncSubscribeEventContext Add a tenant  
    EVENT_ASYNC_SUBSCRIBE_FINISHED MtAsyncSubscribeFinishedEventContext Add a tenant  
    EVENT_ASYNC_UNSUBSCRIBE MtAsyncUnsubscribeEventContext Remove a tenant  
    EVENT_ASYNC_UNSUBSCRIBE_FINISHED MtAsyncUnsubscribeFinishedEventContext Remove a tenant  

    You only need to register event handlers to override the default behavior.

    Default behaviors:

    • A new tenant-specific database container is created through the Service Manager during subscription.
    • A tenant-specific database container is not deleted during unsubscription.

    The following sections describe how to register to these events in more detail.

    Subscribe Tenant

    Subscription events are generated when a new tenant is added. By default, subscription creates a new database container for a newly subscribed tenant.

    You need to configure asynchronous subscription in your saas-registry service instance and you can consume EVENT_ASYNC_SUBSCRIBE and EVENT_ASYNC_SUBSCRIBE_FINISHED events which are sent when a tenant is subscribed. See section SaaS Provisioning Service documentation for more details.

    The onboarding events are fired in the following order:

    1. The event EVENT_ASYNC_SUBSCRIBE is emitted when the SaaS Provisioning Service calls the CAP application. The default implementation of this event calls MTX Sidecar asynchronously to deploy the database artifacts. When this event finishes, the database schema isn’t yet fully deployed!

    2. When the database deployment is finished, the event EVENT_ASYNC_SUBSCRIBE_FINISHED is emitted. The default implementation of this event notifies the SaaS Provisioning Service that the onboarding is finished.

    The following examples show how to register custom handlers for these events:

    @Before(event = MtSubscriptionService.EVENT_ASYNC_SUBSCRIBE)
    public void beforeSubscription(MtAsyncSubscribeEventContext context) {
        // Activities before tenant database container is created
    }
    
    @After(event = MtSubscriptionService.EVENT_ASYNC_SUBSCRIBE_FINISHED)
    public void afterSubscribe(MtAsyncSubscribeFinishedEventContext context) {
        // For example, send notification, ...
    }
    

    Tenant Unsubscription

    Unsubscription events are generated, when a tenant is off-boarded. By default, the tenant-specific database container is not deleted during off-boarding. You can change this behavior by registering a custom event handler as illustrated in the following examples.

    If need to configure asynchronous unsubscription in your saas registry service instance and you can consume events EVENT_ASYNC_UNSUBSCRIBE and EVENT_UNSUBSCRIBE_FINISHED. The following example shows how to add custom logic for these events:

    @Before(event = MtSubscriptionService.EVENT_ASYNC_UNSUBSCRIBE)
    public void beforeUnsubscribe(MtAsyncUnsubscribeEventContext context) {
        // Activities before off-boarding
    }
    
    @After(event = MtSubscriptionService.EVENT_ASYNC_UNSUBSCRIBE_FINISHED)
    public void beforeUnsubscribe(MtAsyncUnsubscribeFinishedEventContext context) {
        // Notify off-boarding finished
    }
    

    Deleting Tenant Containers During Tenant Unsubscription

    By default, tenant-specific database containers aren’t deleted during removal. However, you can register a customer handler change this behavior. For example:

    @Before(event = MtSubscriptionService.EVENT_ASYNC_UNSUBSCRIBE)
    public void beforeUnsubscribe(MtAsyncUnsubscribeEventContext context) {
        // Trigger deletion of database container of off-boarded tenant
        context.setDelete(true);
    }
    

    Returning a Custom Application URL

    The following example shows how to return a custom application URL that is shown in SAP BTP Cockpit:

    @After(event = MtSubscriptionService.EVENT_ASYNC_SUBSCRIBE)
    public void afterSubscribe(MtAsyncSubscribeEventContext context) {
        if (context.getResult() == null) {
            context.setResult(
              "https://" +
              context.getSubscriptionPayload().subscribedSubdomain +
              ".myapp.com");
        }
    }
    

    By default, the application URL is constructed by configuration as described in Configuring the Java Service.

    Returning Dependencies

    The event EVENT_GET_DEPENDENCIES fires when the SaaS Provisioning service calls the getDependencies callback. Hence, if your application consumes any reuse services provided by SAP, you must implement the EVENT_GET_DEPENDENCIES to return the service dependencies of the application. The callback must return a 200 response code and a JSON file with the dependent services’ appName and appId, or just the xsappname.

    The xsappname of an SAP reuse service that is bound to your application can be found as part of the VCAP_SERVICES JSON structure under the path VCAP_SERVICES.<service>.credentials.xsappname.

    The following example shows this in more detail:

    import com.sap.cloud.mt.subscription.json.ApplicationDependency;
    
    @Value("${vcap.services.<my-service-instance>.credentials.xsappname}")
    private String xsappname;
    
    @On(event = MtSubscriptionService.EVENT_GET_DEPENDENCIES)
    public void onGetDependencies(MtGetDependenciesEventContext context) {
        ApplicationDependency dependency = new ApplicationDependency();
        dependency.xsappname = xsappname;
        List<ApplicationDependency> dependencies = new ArrayList<>();
        dependencies.add(dependency);
        context.setResult(dependencies);
    }
    

    Returning a Database ID

    When you’ve registered exactly one SAP HANA instance in your SAP BTP space, a new tenant-specific database container is created automatically. However, if you’ve registered more than one SAP HANA instances in your SAP BTP space, you have to pass the target database ID for the new database container in a customer handler, as illustrated in the following example:

    @Before(event = MtSubscriptionService.EVENT_ASYNC_SUBSCRIBE)
    public void beforeSubscription(MtSubscribeEventContext context) {
        context.setInstanceCreationOptions(
          new InstanceCreationOptions().withProvisioningParameters(
            Collections.singletonMap("database_id", "<database ID>")));
    }
    

    Logging Support

    Logging service support gives you the capability to observe properly correlated requests between the different components of your CAP application in Kibana. This is especially useful for multi-tenant aware applications that use the MTX sidecar. Just enable the Cloud Foundry application-logs service for both, the Java service (see details in Observability > Logging) as well as for the MTX sidecar, to get correlated log messages from these components.

    This can easily be seen in Kibana, which is part of the ELK Stack (Elasticsearch/Logstash/Kibana) on Cloud Foundry and available by default with the application-logs service:

    Kibana screenshot

    Database Schema Update

    When shipping a new application version with an updated CDS model, the database schema for each subscribed tenant needs an update. The database schema update needs to be triggered explicitly, as described in the following sections.

    When the database schema update is triggered, the following CAP events are sent. By registering custom handlers for these events, you can add custom logic to influence the deployment process. By default, the CAP Java SDK notifies the MTX Sidecar to perform any schema upgrade if necessary.

    Event Name Event Context
    EVENT_ASYNC_DEPLOY MtAsyncDeployEventContext
    EVENT_ASYNC_DEPLOY_STATUS MtAsyncDeployStatusEventContext

    It’s often desired to update the whole service in a zero downtime manner. This section doesn’t deal with the details about updating a service productively, but describes tool support the CAP Java SDK offers to update database schemas.

    The following sections describe how to trigger the database schema upgrade for tenants.

    Deploy Endpoint

    When multitenancy is configured, the CAP Java SDK exposes a REST endpoint to update database schemata.

    ❗ Warning You must use the scope mtdeployment for the following requests!

    Deployment Request

    Send this request when a new version of your application with an updated database schema was deployed. This call triggers updating the persistence of each tenant.

    Route
    POST /mt/v1.0/subscriptions/deploy/async
    

    This is the default endpoint. One or more endpoints might differ if you configure different endpoints through properties.

    Body

    The POST request must contain the following body:

    {
      "tenants": [ "all" ]
    }
    

    Alternatively, you can also update single tenants:

    {
      "tenants": ["<tenant-id-1>", "<tenant-id-2>", ...]
    }
    
    Response

    The deploy endpoint is asynchronous, so it returns immediately with status code 202 and JSON structure containing a jobID value:

    {
      "jobID": "<jobID>"
    }
    

    Job Status Request

    You can use this jobID to check the progress of the operation by means of the following REST endpoint:

    Route
    GET /mt/v1.0/subscriptions/deploy/async/status/<jobID> HTTP/1.1
    
    Response

    The server responds with status code 200. During processing, the response looks like:

    {
      "error": null,
      "status": "RUNNING",
      "result": null
    }
    

    Once a job is finished, the collective status is reported like this:

    {
      "error": null,
      "status": "FINISHED",
      "result": {
          "tenants": {
              "<tenantId1>": {
                  "status": "SUCCESS",
                  "message": "",
                  "buildLogs": "<build logs>"
              },
              "<tenantId2>": {
                  "status": "FAILURE",
                  "message": "<error log output>",
                  "buildLogs": "<build logs>"
              }
          }
      }
    }
    

    Logs are persisted for a period of 30 minutes before they get deleted automatically. If you’re requesting the job status after the 30-minute period expired, you get a 404 Not Found response.

    Deploy Main Method

    As an alternative to calling the deploy REST endpoints, the CAP Java SDK also offers a main method in the class com.sap.cds.framework.spring.utils.Deploy that can be called from the command line while the CAP Java application is still stopped. This way, you can run the database deployment for all tenants before you start a new version of the Java application. This prevents new application code to access database artifacts that aren’t yet deployed.

    While the CAP Java backend might be stopped when you call this method, the MTX Sidecar application must be running!

    This synchronization can also be automated, for example using Cloud Foundry Tasks on SAP BTP and Module Hooks in your MTA.

    The main method takes an optional list of tenant IDs as input arguments. If tenant IDs are specified, only these tenants are updated. If no input parameters are specified, all tenants are updated. The method waits until all deployments are finished and then prints the result.

    The method returns the following exit codes

    Exit Code Result
    0 All tenants updated successfully.
    3 Failed to update at least one tenant. Re-run the procedure to make sure that all tenants are updated.

    To run this method locally, use the following command where <jar-file> is the one of your application:

    java -cp <jar-file> -Dloader.main=com.sap.cds.framework.spring.utils.Deploy org.springframework.boot.loader.PropertiesLauncher [<tenant 1>] ... [<tenant n>]
    

    In the SAP BTP, Cloud Foundry environment it can be tricky to construct such a command. The reason is, that the JAR file is extracted by the Java Buildpack and the place of the Java executable isn’t easy to determine. Also the place differs for different Java versions. Therefore, we recommend to adapt the start command that is generated by the buildpack and run the adapted command:

    sed -i 's/org.springframework.boot.loader.JarLauncher/-Dloader.main=com.sap.cds.framework.spring.utils.Deploy org.springframework.boot.loader.PropertiesLauncher/g' /home/vcap/staging_info.yml && jq -r .start_command /home/vcap/staging_info.yml | bash
    

    If you use Java 8, you need to use the following command:

    sed -i 's/org.springframework.boot.loader.JarLauncher/org.springframework.boot.loader.PropertiesLauncher/g' /home/vcap/staging_info.yml && sed -i 's/-Dsun.net.inetaddr.negative.ttl=0/-Dsun.net.inetaddr.negative.ttl=0 -Dloader.main=com.sap.cds.framework.spring.utils.Deploy/g' /home/vcap/staging_info.yml && jq -r .start_command /home/vcap/staging_info.yml | bash
    

    Configuration Properties

    A number of multitenancy settings can be configured through application configuration properties. See section Application Configuration for more details. They can be found in the following table. The prefix for multitenancy-related settings is cds.multitenancy.

    Name Description Default
    servlet.path Path of the subscription and deployment endpoints /mt/v1.0/subscriptions
    servlet.enabled Flag to deactivate the endpoints true
    datasource.pool Pool to use for the tenant-dependent data source. Possible values are: hikari, tomcat, atomikos hikari
    datasource.<pool>.<property> Pool-specific properties. See the tools documentation for HikariCP, Apache Tomcat, and Atomikos for more details. Default depends on the pool and property
    datasource.combinePools.enabled Only one data source pool per database is created. false
    servicemanager.timeout Timeout for requests to the Service Manager in seconds 3600
    security.subscriptionScope Scope necessary to call the subscription endpoints mtcallback
    security.deploymentScope Scope necessary to call the deployment endpoints mtdeployment
    sidecar.url URL of the MTX sidecar Not set by default
    app-ui.url URL of the application UI Not set by default
    app-ui.tenantSeparator Separator of the tenant in the URL, for example, “.” or “-“ Not set by default
    mtxs Enables the usage of @sap/cds-mtxs module (MTX streamlined) false
    provisioning.pollingTimeout The maximum waiting time for the provisioning operation to finish 10 minutes
    deploy.component-scan Specifies the package to be included in component scan of Deploy Main Method with custom handlers. Not set by default