Create an Application with Cloud Foundry Python Buildpack
- How to create a simple “Hello World” application in Python
- How to consume an SAP BTP service from it
- How to run authentication and authorization checks via the Authorization and Trust Management (XSUAA) service
Prerequisites
- You have a trial or an enterprise (productive) account for SAP Business Technology Platform (SAP BTP).
- Python is installed locally. To check which Python versions are supported in the current buildpack, see: Developing Python in the Cloud Foundry Environment. In this tutorial, we use Python version 3.13.x.
- cf CLI is installed locally.
- npm is installed locally.
- You have installed an integrated development environment, for example Visual Studio Code.
- You have installed the
virtualenvtool. It creates a folder, which contains all the necessary executables to use the packages that your Python project would need. To install it locally, run the following command in the Python installation path:
<Python_installation_path>\Python311\Scripts>pip install virtualenv
This tutorial will guide you through creating and setting up a simple Python application by using cf CLI. You will start by building and deploying a web application that returns simple data – a Hello World! message. This simple app will consume the SAP HANA Cloud service, and then will be invoked through a web microservice (application router). Finally, you will set authentication and authorization checks to properly access your web application.
- Step 1
You need to fulfill this prerequisite step first in order to create an SAP HANA Cloud service instance later.
-
Open the SAP BTP cockpit.
-
Navigate to your global account. If you’re using a trial SAP BTP account, just go the main screen.
-
From the left-side menu, choose
Boosters. -
Find the Set Up SAP HANA Cloud Administration Tools tile and choose
Start.Your SAP HANA Cloud database is created for you.
-
Now go to your subaccount. If you’re using a trial SAP BTP account, choose
trial. -
From the left-side menu, choose
Services->Instances and Subscriptions.The top table shows that you’re subscribed for the
SAP HANA Cloudapplication with plantools. -
Choose
Go to Application.The
SAP HANA Cloud Centralportal is opened. -
Now you need to create an SAP HANA Cloud instance. Choose
Create Instance. -
Choose
SAP HANA Cloud, SAP HANA Databaseand thenNext Step. -
Enter an instance name and a password for your
DBADMINuser. ChooseNext Step. -
For the next two screens of the wizard, keep choosing
Next Stepwithout making any changes. -
On the
SAP HANA Database Advanced Settingswizard page:-
Select
Allow all IP addresses. -
In the
Instance Mappingsection, chooseAdd Mapping. -
For
Environment Instance ID, enter your org ID. You can find it on your subaccount (ortrial) page in the cockpit. -
Choose
Next Step.
-
-
Skip
Data Lakeand chooseReview and Create. -
If everything looks fine to you, choose
Create Instance.Your new SAP HANA Cloud instance is in status
Starting. Wait until it changes toRunning.
Next Steps You can move on with the rest of the tutorial. From now on, you will only need a command-line console and IDE.
-
- Step 2
First, you need to connect to the SAP BTP, Cloud Foundry environment with your trial or enterprise (productive) subaccount. Your Cloud Foundry URL depends on the region where the API endpoint belongs to. To find out which one is yours, see: Regions and API Endpoints Available for the CF Environment
In this tutorial, we use
eu20as an example.-
Open a command-line console.
-
Set the Cloud Foundry API endpoint for your subaccount. Run the following command (using your actual region URL):
Bash/ShellCopycf api https://api.cf.eu20.hana.ondemand.com - Log on to the SAP BTP, Cloud Foundry environment:
Bash/ShellCopy
cf login -
When prompted, enter your user credentials. These are the email and password you have used to register your trial or productive SAP BTP account.
IMPORTANT: If the authentication fails, even though you’ve entered correct credentials, try logging in via single sign-on.
-
Choose the org name and space where you want to create your application.
If you’re using a trial account, you don’t need to choose anything. You can use only one org name, and your default space is
dev.
RESULT
Details about your personal SAP BTP subaccount are displayed (API endpoint, user, organization, space).
-
- Step 3
You’re going to create a simple Python application.
-
In your local file system, create a new folder. For example:
python-tutorial -
From your Visual Studio Code, open the
python-tutorialfolder. -
Create a file
manifest.ymlwith the following content:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpacks: - python_buildpack command: python server.pyThe
manifest.ymlfile represents the configuration describing your application and how it will be deployed to Cloud Foundry.IMPORTANT: Make sure you don’t have another application with the name
myappin your space. If you do, use a different name and adjust the whole tutorial according to it. -
Specify the Python runtime version that your application will run on. To do that, create a
runtime.txtfile with the following content:TXTCopypython-3.13.x -
This application will be a web server utilizing the Flask web framework. To specify Flask as an application dependency, create a
requirements.txtfile with the following content:TXTCopyFlask==2.3.* -
Create a
server.pyfile with the following application logic:PythonCopyimport os from flask import Flask app = Flask(__name__) port = int(os.environ.get('PORT', 3000)) @app.route('/') def hello(): return "Hello World!" if __name__ == '__main__': app.run(host='0.0.0.0', port=port)This is a simple server, which will return a Hello World! message when requested.
-
Deploy the application on Cloud Foundry. To do that, in the
python-tutorialdirectory, run:Bash/ShellCopycf pushMake sure you always run
cf pushin the directory where themanifest.ymlfile is located! In this case, that’spython-tutorial. -
When the staging and deployment steps are completed, the
myappapplication should be successfully started and its details displayed in the command console. -
Open a browser window and enter the generated URL of the application (see
routes).For example:
https://myapp-grouchy-rabbit.cfapps.eu20.hana.ondemand.com
RESULT
Your Python application is successfully deployed and running on the SAP BTP, Cloud Foundry environment. A Hello World! message is displayed in the browser.
Which file contains information about the buildpack that provides the runtime on which you deploy your application?
-
- Step 4
You have created a service instance for SAP HANA Cloud (see STEP 1). Now you’re going to make a connection to your SAP HANA database from SAP HANA Schemas & HDI Containers - a service that runs on the SAP BTP, Cloud Foundry environment - and consume this service in your application.
-
Create a
hanaservice instance namedpyhanawith service planhdi-shared. Run:Bash/ShellCopycf create-service hana hdi-shared pyhana -
Bind this service instance to the application. Add
pyhanain themanifest.ymlfile so that its content looks like this:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpacks: - python_buildpack command: python server.py services: - pyhana -
To consume the service inside the application, you need to read the service settings and credentials from the application. To do that, you need to use the
cfenvPython module. Add two more lines to therequirements.txtfile so that its content looks like this:TXTCopyFlask==2.3.* cfenv==0.5.3 hdbcli==2.17.* -
Modify the
server.pyfile to include additional lines of code - for reading the service information from the environment, and for executing a query with thehdbclidriver. After being requested, the application will now return an SAP HANA Cloud related result. Replace the current content with the following:PythonCopyimport os from flask import Flask from cfenv import AppEnv from hdbcli import dbapi app = Flask(__name__) env = AppEnv() hana_service = 'hana' hana = env.get_service(label=hana_service) port = int(os.environ.get('PORT', 3000)) @app.route('/') def hello(): if hana is None: return "Can't connect to HANA service '{}' – check service name?".format(hana_service) else: conn = dbapi.connect(address=hana.credentials['host'], port=int(hana.credentials['port']), user=hana.credentials['user'], password=hana.credentials['password'], encrypt='true', sslTrustStore=hana.credentials['certificate']) cursor = conn.cursor() cursor.execute("select CURRENT_UTCTIMESTAMP from DUMMY") ro = cursor.fetchone() cursor.close() conn.close() return "Current time is: " + str(ro["CURRENT_UTCTIMESTAMP"]) if __name__ == '__main__': app.run(host='0.0.0.0', port=port) -
In the
python-tutorialdirectory, run:Bash/ShellCopycf push -
Refresh the URL of the
myappapplication (previously loaded in a browser window).
RESULT
The current time is displayed, in the UTC time zone.
-
- Step 5
Authentication in the SAP BTP, Cloud Foundry environment is provided by the Authorization and Trust Management (XSUAA) service. In this example, OAuth 2.0 is used as the authentication mechanism. The simplest way to add authentication is to use the Node.js
@sap/approuterpackage. To do that, a separate Node.js microservice will be created, acting as an entry point for the application.-
In the
python-tutorialfolder, create anxs-security.jsonfile for your application with the following content:JSONCopy{ "xsappname" : "myapp", "tenant-mode" : "dedicated", "oauth2-configuration": { "redirect-uris": [ "https://*.cfapps.eu20.hana.ondemand.com/**" ] } }NOTE: Instead of
eu20, use the technical key of your actual region. -
Create an
xsuaaservice instance namedpyuaawith planapplication. To do that, run:BashCopycf create-service xsuaa application pyuaa -c xs-security.json -
Add the
pyuaaservice in themanifest.ymlfile so that its content looks like this:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpacks: - python_buildpack command: python server.py services: - pyhana - pyuaaThe
pyuaaservice instance will be bound to themyappapplication during deployment. -
Now you need to create a microservice (the application router). To do that, go to the
python-tutorialfolder and create a subfolder namedweb.IMPORTANT: Make sure you don’t have another application with the name
webin your space! If you do, use a different name and adjust the rest of the tutorial according to it. -
In the
webfolder, create a subfolderresources. This folder will provide the business application’s static resources. -
In the
resourcesfolder, create anindex.htmlfile with the following content:HTMLCopy<html> <head> <title>Python Tutorial</title> </head> <body> <h1>Python Tutorial</h1> <a href="/myapp/">My Python Application</a> </body> </html>This will be the
myappapplication start page. -
In the
webdirectory, run:Bash/ShellCopynpm initPress Enter on every step. This process will walk you through creating a
package.jsonfile in thewebfolder. -
Now you need to create a directory
web/node_modules/@sapand install anapprouterpackage in it. To do that, in thewebdirectory run:Bash/ShellCopynpm install @sap/approuter --save -
In the
webfolder, open thepackage.jsonfile and replace the scripts section with the following:JSONCopy"scripts": { "start": "node node_modules/@sap/approuter/approuter.js" }, -
Now you need to add the
webapplication to your project and bind the XSUAA service instance (pyuaa) to it. To do that, insert the following content at the end of yourmanifest.ymlfile.YAMLCopy- name: web random-route: true path: web memory: 128M env: destinations: > [ { "name":"myapp", "url":"https://myapp-grouchy-rabbit.cfapps.eu20.hana.ondemand.com/", "forwardAuthToken": true } ] services: - pyuaaNOTE: For the
urlvalue, enter your actual generated URL for themyappapplication. -
In the
webfolder, create anxs-app.jsonfile with the following content:JSONCopy{ "routes": [ { "source": "^/myapp/(.*)$", "target": "$1", "destination": "myapp" } ] }With this configuration, the incoming request is forwarded to the
myappapplication, configured as a destination. By default, every route requires OAuth authentication, so the requests to this path will require an authenticated user. -
Go to the
python-tutorialdirectory and run:Bash/ShellCopycf pushThis command will update the
myappapplication and deploy thewebapplication.What’s going on?
At this point of the tutorial, the URL of the
webapplication will be requested instead of themyappURL. It will then forward the requests to themyappapplication. -
When the staging and deployment steps are completed, the
webapplication should be successfully started, and its details displayed in the command console. -
Open a new browser tab or window and enter the generated URL of the
webapplication.For example:
https://web-unexpected-cheetah.cfapps.eu20.hana.ondemand.com -
Enter the credentials for your SAP BTP user.
TIP:
If you experience an authentication issue, go back to your
xs-security.jsonfile and double-check if all the data is correct. If you need to fix something, proceed as follows:- Do the corrections in the file and save your changes.
- Update your
pyuaaservice, by running:cf update-service pyuaa -c xs-security.json - Deploy your applications again, by running:
cf push
RESULT
-
A simple application page with title Python Tutorial is displayed. When you click the
My Python Applicationlink, the current time is displayed, in the UTC time zone. -
If you directly access the
myappURL, it displays the same result - the current time in the UTC time zone.
Which service provides the authentication for your application?
-
- Step 6
Authorization in the SAP BTP, Cloud Foundry environment is also provided by the Authorization and Trust Management (XSUAA) service. In the previous example, the
@sap/approuterpackage was added to provide a central entry point for the business application and to enable authentication. Now, to extend the example, authorization will be added.-
Add the
sap-xssecsecurity library to therequirements.txtfile, to place restrictions on the content you serve. The file should look like this:TXTCopyFlask==2.3.* cfenv==0.5.3 hdbcli==2.17.* sap-xssec==4.* -
Modify the
server.pyfile to use the SAPxsseclibrary. Replace the current content with the following code. (Forport, you can use 3000, 8000, or 8080).PythonCopyimport os from flask import Flask from cfenv import AppEnv from flask import request from flask import abort from sap import xssec from hdbcli import dbapi app = Flask(__name__) env = AppEnv() port = int(os.environ.get('PORT', 3000)) hana = env.get_service(label='hana') uaa_service = env.get_service(name='pyuaa').credentials @app.route('/') def hello(): if 'authorization' not in request.headers: abort(403) access_token = request.headers.get('authorization')[7:] security_context = xssec.create_security_context(access_token, uaa_service) isAuthorized = security_context.check_scope('openid') if not isAuthorized: abort(403) conn = dbapi.connect(address=hana.credentials['host'], port=int(hana.credentials['port']), user=hana.credentials['user'], password=hana.credentials['password'], encrypt='true', sslTrustStore=hana.credentials['certificate']) cursor = conn.cursor() cursor.execute("select CURRENT_UTCTIMESTAMP from DUMMY") ro = cursor.fetchone() cursor.close() conn.close() return "Current time is: " + str(ro["CURRENT_UTCTIMESTAMP"]) if __name__ == '__main__': app.run(host='0.0.0.0', port=port) -
Go to the
python-tutorialfolder and run:Bash/ShellCopycf pushThis command will update both myapp and web.
-
Try to access
myappagain (in a browser) in both ways – directly, and through thewebapplication router.
RESULT
-
If you try to access it directly, a
403 Forbiddenresponse is displayed due to lack of permissions (lack of authorization header). This is a correct and expected behavior. -
If you try to access it through the
webapplication router, the current time is displayed (in the UTC time zone) – provided that you have theopenidscope assigned to your user. Since the OAuth 2.0 client is used, theopenidscope is assigned to your user by default, the correct authorization header is declared, and thus you are allowed to access themyappapplication.
Tip: For the new result to take effect immediately, you might need to clear the cache of your browser. Or just open the
webapplication URL in a private/incognito browser tab.Which of the following statements are correct?
-