Technical Articles
Understanding Dependencies in SaaS Provisioning
If you operate a multitenant application in SAP BTP’s Cloud Foundry environment, you’re probably familiar with the Saas Provisioning service. This service allows you, the application operator, to control customer subscriptions by specifying endpoints that SAP BTP will call during subscription events. Tasks like setting up database artifacts, mapping routes and initializing default configuration can be defined in these callbacks allowing for automation of certain aspects of customer onboarding. In fact, the CAP Framework has standardized part of this onboarding processes including the provisioning of HDI containers.
But beyond subscription management, there is a third aspect to the SaaS Provisioning service responsible for allowing subscribers to access services instantiated in your provider account. This is the governed by the getDependencies
callback and is the focus of this post.
Get Dependencies
When do you need to use getDependencies
? The official documentation gives us a hint:
If your application consumes any reuse services provided by SAP, you must implement the getDependencies callback 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.
[emphasis mine]
The key term from that snippet is reuse services. If you use a reuse service and want your subscribers to have access, getDependencies
must return it. But how do you know if a service is a reuse service, is there a list somewhere? As far as I know, the answer is no. Still, experience has shown these services fit the description:
- UI Theme Designer
- Job Scheduling Service
- Cloud Portal Service
- Connectivity/Destinations
- UI5 Flexibility for Key Users
[Note: this is not an exhaustive list]
What these services have in common is that they have a certain amount of customer specificity. Each customer could have their own defined themes or scheduled jobs or destinations. Absent a complete list or even an indicator in the service documentation itself, this is the primary signal we have to include a service in the callback response.
Dependency Relevant Events
Now that we have an understanding of when we need to define getDependencies
and what services we need to included in its response, the next step is to understand when SAP BTP will attempt to getDependencies
. As you might expect, it accesses this endpoint during subscription creation and update events.
Creating a Subscription
The create event is an obvious place to retrieve a list of dependencies that need to be accessible by a new customer. Indeed, in addition to the onSubscription
endpoint, the getDependencies
endpoint is also accessed. So when activating the new subscription from the customer subaccount, SAP BTP calls both onSubscription
and getDependencies
to complete the subscription.
Update Subscription
The update event is naturally the next place that needs access to a list of dependencies. In the operation of any application, there’s a good chance you’ll want to add new services to enhance existing functionality. In these cases, you need a mechanism to re-trigger the getDependencies
call so SAP BTP can retrieve an updated list of services needed by the subscribed customer.
While the initial subscription has an obvious mechanism to trigger the create event (creating a subscription within the subaccount cockpit), there is no corresponding obvious mechanism to trigger an update. It’s at this point that we need to consult the SaaS Provisioning API.
In the section labeled Application Opeartions for App Providers, we find this endpoint:
PATCH /saas-manager/v1/application/tenants/{tenantId}/subscriptions
With the description:
Update the dependencies of a multitenant application.
This is precisely what we’re looking for. To refresh the dependencies, all we need to do is update the response to the getDependencies
endpoint to include the new service and then execute that PATCH
request against the tenant to update.
But there is a wrinkle to this endpoint that is not documented. While it does indeed trigger a new call to getDependencies
it also triggers a new call to onSubcription
. This can be problematic if you assumed onSubscription
will only be accessed during the subscription creation.
Luckily, there is a field included in the onSubscription
request body that allows us to distinguish which event this is, the eventType
field. For new subscriptions, the value is CREATE
while in subscription updates the value is UPDATE
. So, if you have logic in onSubscription
you only wanted executed on subscription creation, just check the eventType
.
Summary
The main takeaway here is that there are two places getDependencies
is relevant: during subscription creations and updates. Both events result in calls to both onSubscription
and getDependencies
so it is important that your onSubscription
logic can account for this.
Create
Triggered by creating a subscription in the customer subaccount. Results in these callbacks:
PUT {onSubscription}/{tenantId}
{
...
"eventType": "CREATE"
}
GET {getDependencies}?tenantId={tenantId}
Update
Triggered by accessing the PATCH
endpoint in the SaaS Provisioning API. Results in these callbacks:
PUT {onSubscription}/{tenantId}
{
...
"eventType": "UPDATE"
}
GET {getDependencies}?tenantId={tenantId}
Closing Thoughts
Part of my motivation for this post was my inability to find a centralized source of documentation on the specifics of how getDependencies
works within the Saas Provisioning service. Maybe this documentation exists and I’m just not good enough to find it and if that’s the case, I invite any readers to share where I can find that. If it does not actually exists, I hope this post can help others that have struggled with the same issues I have.
Thanks!
Great information, Brian! I had a tough time with this when I first started with multitenancy and this lays it out very clearly.
Thanks!
Very well written!
This is extremely valuable information! I was trying to find if Portal, UI Theme Designer and UI5 Flexibility for Key Users are multitenancy reuse services and here is the only place that actually tells this.
Many, many thanks for the blog post and shared knowledge!
Thanks Brian. This is very informative. I had to update dependencies related to the Document Management service and this guided me through the process.
Hi Brian,
thank you for this post. It's a pitty that SAP isn't able to provide this information in the first place. I would suggest that you also add the destination service to the list. Maybe you find way how I've implemented the content for the destinations call interresting: Documentation: Deploy SaaS Solutions (MTX) - Dependencies to Destination / Connectivity Service.
CU
Gregor
Gregor,
Thank you for your comments and suggestion.
I originally considered destinations to be under the umbrella of connectivity functionality given that is how it is presented in the standard docs but I've edited the post to make that fact more clear.
As for your implementation with MTX, that certainly looks like a clean way to handle this. We originally developed our logic for SaaS in early 2019(!) though so our logic to handle the dependencies callback is a little hackier as MTX didn't exist back then 😅.
Thanks again!
Brian