Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
bmcdonn2
Participant
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:

  1. UI Theme Designer

  2. Job Scheduling Service

  3. Cloud Portal Service

  4. Connectivity/Destinations

  5. 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!
6 Comments
Labels in this area