Create a Python 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 XSUAA service
Prerequisites
- You have a trial or productive account for SAP Business Technology Platform (SAP BTP). If you don’t have such yet, you can create one so you can try out services for free.
- You have created a subaccount and a space on Cloud Foundry Environment.
- You have created a service instance for SAP HANA Cloud. To learn how to set it up, watch the first half of this video: SAP HANA Cloud Trial Setup
- 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 3.11.1.
- 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
virtualenv
tool. It creates a folder, which contains all the necessary executables to use the packages that your Python project would need. To install it locally, execute 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 an SAP BTP 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
First, you need to connect to the SAP BTP, Cloud Foundry environment with your 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
eu20.hana.ondemand.com
as an example.-
Open a command-line console.
-
Set the Cloud Foundry API endpoint for your subaccount. Execute (using your actual region URL):
Bash/ShellCopycf api https://api.cf.eu20.hana.ondemand.com
- Log in to SAP BTP, Cloud Foundry environment: Bash/ShellCopy
cf login
-
When prompted, enter your user credentials – 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).
Log in to complete tutorial -
- Step 2
You’re going to create a simple Python application.
In your local file system, create a new directory (folder). For example:
python-tutorial
From your Visual Studio Code, open the
python-tutorial
folder.In this folder, create a file
manifest.yml
with the following content:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpack: python_buildpack command: python server.py
The
manifest.yml
file 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
myapp
in 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.txt
file with the following content:TXTCopypython-3.11.1
This application will be a web server utilizing the Flask web framework. To specify Flask as an application dependency, create a
requirements.txt
file with the following content:TXTCopyFlask==2.0.1
Create a
server.py
file 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-tutorial
directory, execute:Bash/ShellCopycf push
Make sure you always execute
cf push
in the directory where themanifest.yml
file is located! In this case, that’spython-tutorial
.When the staging and deployment steps are completed, the
myapp
application should be successfully started and its details displayed in the command console.Open a browser window and enter the generated URL of the
myapp
application (seeroutes
).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?
Log in to complete tutorial - Step 3
You have created a service instance for SAP HANA Cloud (see Prerequisites at the beginning). 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
hana
service instance namedpyhana
with service planhdi-shared
. Execute:Bash/ShellCopycf create-service hana hdi-shared pyhana
Bind this service instance to the application. Add
pyhana
in themanifest.yml
file so that its content looks like this:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpack: 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, use the
cfenv
Python module. Add two more lines to therequirements.txt
file so that its content looks like this:TXTCopyFlask==2.0.1 cfenv==0.5.3 hdbcli==2.9.23
Modify the
server.py
file to include additional lines of code - for reading the service information from the environment, and for executing a query with thehdbcli
driver. After being requested, the application will now return a SAP HANA-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-tutorial
directory, execute:Bash/ShellCopycf push
Refresh the URL of the
myapp
application (previously loaded in a browser window).
RESULT
The current SAP HANA time is displayed, in UTC time zone.
Log in to complete tutorial - Step 4
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/approuter
package. To do that, a separate Node.js micro-service will be created, acting as an entry point for the application.In the
python-tutorial
folder, create anxs-security.json
file for your application with the following content:JSONCopy{ "xsappname" : "myapp", "tenant-mode" : "dedicated" }
IMPORTANT: For trial accounts, enter the following additional
oauth2-configuration
code in yourxs-security.json
file:JSONCopy{ "xsappname" : "myapp", "tenant-mode" : "dedicated", "oauth2-configuration": { "redirect-uris": [ "https://*.cfapps.eu20.hana.ondemand.com/**" ] } }
Create an
xsuaa
service instance namedpyuaa
with planapplication
, by executing the following command:BashCopycf create-service xsuaa application pyuaa -c xs-security.json
Add the
pyuaa
service inmanifest.yml
so the file looks like this:YAMLCopy--- applications: - name: myapp random-route: true path: ./ memory: 128M buildpack: python_buildpack command: python server.py services: - pyhana - pyuaa
The
pyuaa
service instance will be bound to themyapp
application during deployment.To create a microservice (the application router), go to the
python-tutorial
folder and create a subfolder namedweb
.IMPORTANT: Make sure you don’t have another application with the name
web
in your space! If you do, use a different name and adjust the rest of the tutorial according to it.Inside the
web
folder, create a subfolderresources
. This folder will provide the business application’s static resources.Inside the
resources
folder, create anindex.html
file 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
myapp
application start page.In the
web
directory, execute:Bash/ShellCopynpm init
Press Enter on every step. This process will walk you through creating a
package.json
file in theweb
folder.Now you need to create a directory
web/node_modules/@sap
and install anapprouter
package in it. To do that, in theweb
directory execute:Bash/ShellCopynpm install @sap/approuter --save
In the
web
folder, open thepackage.json
file and replace the scripts section with the following:JSONCopy"scripts": { "start": "node node_modules/@sap/approuter/approuter.js" },
Now you need to add the
web
application to your project and bind the XSUAA service instance (pyuaa
) to it. To do that, insert the following content at the end of yourmanifest.yml
file.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: - pyuaa
For the
url
value, enter your generated URL for themyapp
application.In the
web
folder, create anxs-app.json
file with the following content:JSONCopy{ "routes": [ { "source": "^/myapp/(.*)$", "target": "$1", "destination": "myapp" } ] }
With this configuration, the incoming request is forwarded to the
myapp
application, 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-tutorial
directory and execute:Bash/ShellCopycf push
This command will update the
myapp
application and deploy theweb
application.What’s going on?
At this point of the tutorial, the URL of the
web
application will be requested instead of themyapp
URL. It will then forward the requests to themyapp
application.When the staging and deployment steps are completed, the
web
application 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
web
application.For example:
https://web-unexpected-cheetah.cfapps.eu20.hana.ondemand.com
Enter the credentials for your SAP BTP user.
RESULT
A simple application page with title Python Tutorial is displayed. When you click the
My Application
link, the current SAP HANA time is displayed, in UTC time zone.If you directly access the
myapp
URL, it displays the same result - the current SAP HANA time in UTC time zone.
- Step 5
Authorization in the SAP BTP, Cloud Foundry environment is also provided by the XSUAA service. In the previous example, the
@sap/approuter
package 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-xssec
security library to therequirements.txt
file, to place restrictions on the content you serve. The file should look like this:TXTCopyFlask==2.0.1 cfenv==0.5.3 hdbcli==2.9.23 sap-xssec==3.0.0
Modify the
server.py
file to use the SAPxssec
library. Replace the current content with the following: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-tutorial
folder and execute:Bash/ShellCopycf push
This command will update both myapp and web.
Try to access
myapp
again (in a browser) in both ways – directly, and through theweb
application router.
RESULT
Accessing the
myapp
application results in the following:If you try to access it directly, a
403 Forbidden
response 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
web
application router, the current SAP HANA time is displayed (in UTC time zone) – provided that you have theopenid
scope assigned to your user. Since the OAuth 2.0 client is used, theopenid
scope is assigned to your user by default, the correct authorization header is declared, and thus you are allowed to access themyapp
application.
> In order for the new result to take effect immediately, you might need to clear the cache of your browser. Or just open the
web
application URL in a private/incognito browser tab.