Skip to main content

Guide

Introduction

This guide walks through deploying the cloud-cap-samples-java to a Cloud Foundry environment on SAP Business Technology Platform (BTP) — using Infrastructure as Data.

"The Cloud Application Programming Model (CAP) is a framework of languages, libraries, and tools for building enterprise-grade cloud applications." - https://cap.cloud.sap/docs/get-started/features#what-is-cap

Rather than repeating what the individual Crossplane provider documentation already covers, it links to the relevant sections and adds additional context where needed. For convenience, each step includes a collapsible section with example YAML resources taken directly from the referenced documentation.

info

cloud-cap-samples-java can also be deployed to a Kyma runtime on SAP BTP. This is not yet covered in this guide. Please don't hesitate to contribute!

🚧 Prerequisites

Procedure

BTP

Before we can provision a Cloud Foundry environment and a SAP HANA Cloud service instance, we need to set up the required resources on the BTP side, such as a subaccount and the corresponding entitlements.

  1. Install and configure the BTP provider
Provider, Secret (×2) and ProviderConfig
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: btp-provider
spec:
package: ghcr.io/sap/crossplane-provider-btp/crossplane/provider-btp:<version> # replace <version> with the desired version, e.g. 1.0.2
packagePullSecrets:
- name: artifactory-readonly-docker
---
apiVersion: v1
kind: Secret
metadata:
namespace: default
name: cis-provider-secret
type: Opaque
stringData:
data: |
{
"endpoints": {
"accounts_service_url": "...",
"cloud_automation_url": "...",
"entitlements_service_url": "...",
"events_service_url": "...",
"external_provider_registry_url": "...",
"metadata_service_url": "...",
"order_processing_url": "...",
"provisioning_service_url": "...",
"saas_registry_service_url": "..."
},
"grant_type": "client_credentials",
"sap.cloud.service": "com.sap.core.commercial.service.central",
"uaa": {
"apiurl": "...",
"clientid": "...",
"clientsecret": "...",
"credential-type": "binding-secret",
"identityzone": "...",
"identityzoneid": "...",
"sburl": "...",
"subaccountid": "...",
"tenantid": "...",
"tenantmode": "shared",
"uaadomain": "...",
"url": "...",
"verificationkey": "...",
"xsappname": "...",
"xsmasterappname": "...",
"zoneid": "..."
}
}
---
apiVersion: v1
kind: Secret
metadata:
namespace: default
name: sa-provider-secret
type: Opaque
stringData:
credentials: |
{
"email": "<technical-user-email>",
"username": "<technical-user-username>",
"password": "<technical-user-password>"
}
---
apiVersion: btp.sap.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
name: account-provider-config
spec:
globalAccount: <global-account-subdomain>
cliServerUrl: https://cli.btp.cloud.sap
cisCredentials:
secretRef:
name: cis-provider-secret
namespace: default
key: data
source: Secret
serviceAccountSecret:
secretRef:
key: credentials
name: sa-provider-secret
namespace: default
source: Secret
  1. Create and set up a subaccount
Subaccount, ServiceManager, Entitlement and CloudManagement
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Subaccount
metadata:
name: my-subaccount
spec:
forProvider:
betaEnabled: true
description: hello subaccount
displayName: <display-name> # This value will be displayed as a subaccount name in the BTP cockpit
region: eu12 # Adjust if needed
subaccountAdmins:
- <admin-email> # Use the email address of your technical user
subdomain: <subaccount-subdomain> # This value must be unique across all BTP subaccounts
usedForProduction: "NOT_USED_FOR_PRODUCTION" # Other supported values are "USED_FOR_PRODUCTION" and "UNSET"
providerConfigRef:
name: account-provider-config
---
apiVersion: account.btp.sap.crossplane.io/v1beta1
kind: ServiceManager
metadata:
name: my-subaccount-service-manager
spec:
writeConnectionSecretToRef:
name: sap-btp-service-operator
namespace: default
forProvider:
subaccountRef:
name: my-subaccount
providerConfigRef:
name: account-provider-config
---
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Entitlement
metadata:
name: cis-entitlement
spec:
forProvider:
serviceName: cis
servicePlanName: local
enable: true
subaccountRef:
name: my-subaccount
providerConfigRef:
name: account-provider-config
---
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: CloudManagement
metadata:
name: cis-local
spec:
writeConnectionSecretToRef:
name: cis-local
namespace: default
forProvider:
serviceManagerRef:
name: my-subaccount-service-manager # Use the ServiceManager resource created in the previous step
subaccountRef:
name: my-subaccount
providerConfigRef:
name: account-provider-config

Cloud Foundry

With the resources created on the BTP side, we can now provision a Cloud Foundry environment and the space we will later deploy the CAP application to.

  1. Create a Cloud Foundry environment
CloudFoundryEnvironment
apiVersion: environment.btp.sap.crossplane.io/v1alpha1
kind: CloudFoundryEnvironment
metadata:
name: cf-env
spec:
forProvider:
initialOrgManagers:
- technical-user@example.com
landscape: cf-eu12
orgName: test-eu12
environmentName: cf-test-eu12
cloudManagementRef:
name: cis-local
subaccountRef:
name: my-subaccount
writeConnectionSecretToRef:
name: cf-environment-secret # Secret containing connection details including apiEnpoint of the created cloudfoundry environment.
namespace: default
  1. Install and configure the Cloud Foundry provider
Provider, Secret and ProviderConfig
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: cloudfoundry-provider
spec:
package: ghcr.io/sap/crossplane-provider-cloudfoundry/crossplane/provider-cloudfoundry:<provider-version>
---
apiVersion: v1
kind: Secret
metadata:
name: cf-credentials-secret
namespace: default
type: Opaque
stringData:
credentials: |
{
"email": "<your email>",
"username": "<technical-user-name>",
"password": "<technical-user-password>"
}
---
apiVersion: cloudfoundry.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
apiEndpoint: https://api.cf.eu12.hana.ondemand.com/
credentials:
source: Secret
secretRef:
name: cf-credentials-secret
namespace: default
key: credentials
  1. Import the organization
Organization
apiVersion: cloudfoundry.crossplane.io/v1alpha1
kind: Organization
metadata:
name: my-org
annotations:
crossplane.io/external-name: cf-dev ## name of actual CF Org in BTP
spec:
forProvider: {}
managementPolicies:
- Observe
  1. Create a space
Space
apiVersion: cloudfoundry.crossplane.io/v1alpha1
kind: Space
metadata:
name: my-space ## name of custom resource in control plane
spec:
forProvider:
allowSsh: true
name: my-space
orgRef:
name: my-org ## The managed resource name of the Organization in the control plane
  1. Assign the SpaceDeveloper role to the user you want to deploy the CAP application with later on
SpaceRole
apiVersion: cloudfoundry.crossplane.io/v1alpha1
kind: SpaceRole
metadata:
name: space-developer-user1
spec:
forProvider:
type: Developer # valid role types are: Developer, Supporter, Auditor, Manager
username: user1@example.com
spaceRef:
name: my-space
  1. Create an application runtime entitlement
Entitlement
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Entitlement
metadata:
name: cf-quota
spec:
forProvider:
serviceName: APPLICATION_RUNTIME
servicePlanName: MEMORY
amount: 2
subaccountRef:
name: my-subaccount

HANA

Based on our BTP and Cloud Foundry setup, we can now create a SAP HANA Cloud service instance and map it to the space so that our CAP application can create HDI containers in it.

  1. Create an entitlement for HDI containers (serviceName: hana and servicePlanName: hdi-shared)
Entitlement
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Entitlement
metadata:
name: hdi-entitlement
spec:
forProvider:
serviceName: hana
servicePlanName: hdi-shared
enable: true
subaccountRef:
name: my-subaccount
providerConfigRef:
name: account-provider-config
  1. Create a SAP HANA Cloud service instance
Entitlement and ServiceInstance
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Entitlement
metadata:
name: hana-cloud-entitlement
spec:
forProvider:
serviceName: hana-cloud
servicePlanName: hana
servicePlanUniqueIdentifier: hana-cloud-hana
enable: true
subaccountRef:
name: my-subaccount
providerConfigRef:
name: account-provider-config
---
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: ServiceInstance
metadata:
name: hana-cloud-instance
spec:
forProvider:
name: hana-cloud-instance
serviceManagerRef:
name: my-subaccount-service-manager
subaccountRef:
name: my-subaccount
offeringName: hana-cloud
planName: hana
parameters:
data:
memory: 16
systempassword: Cloud-12345! # TODO change
edition: cloud
providerConfigRef:
name: account-provider-config
  1. Create a service binding for the SAP HANA Cloud service instance
ServiceBinding
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: ServiceBinding
metadata:
name: hana-binding
spec:
forProvider:
name: hana-binding
serviceInstanceRef:
name: hana-cloud-instance
subaccountRef:
name: my-subaccount
writeConnectionSecretToRef:
name: hana-binding-secret
namespace: default
providerConfigRef:
name: account-provider-config
  1. Install and configure the HANA provider
Provider, Secret and ProviderConfig
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: hana-provider
spec:
package: ghcr.io/sap/crossplane-provider-hana/crossplane/provider-hana:<VERSION> # Please use the latest version from the releases page
packagePullSecrets:
- name: artifactory-readonly-docker
---
apiVersion: v1
kind: Secret
metadata:
namespace: default
name: hana-provider-secret
type: Opaque
data:
endpoint: abcdefgh-base64-encoded-xyz== # E.g. Base64-encode: my-hana-domain.prod-eu10.hanacloud.ondemand.com
port: NDQz # E.g. Base64-encode: 443
username: REJBRE1JTg== # E.g. Base64-encode: DBADMIN
password: Q2xvdWQtMTIzNDUh # Same password as set during service instance creation E.g. Base64-encode: Cloud-12345!
---
apiVersion: hana.sap.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
name: hana-providerconfig
spec:
credentials:
source: Secret
connectionSecretRef:
namespace: default
name: hana-provider-secret
  1. Create a HANA instance mapping (Cloud Foundry)
Entitlement, ServiceInstance, ServiceBinding, Secret, ResourceGraphDefinition, CfHanaInstanceMapping
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: Entitlement
metadata:
name: hana-cloud-api-entitlement
spec:
forProvider:
serviceName: hana-cloud
servicePlanName: admin-api-access
servicePlanUniqueIdentifier: hana-cloud-admin-api-access
enable: true
subaccountRef:
name: my-subaccount
---
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: ServiceInstance
metadata:
name: hana-api
spec:
forProvider:
name: hana-api
offeringName: hana-cloud
planName: admin-api-access
serviceManagerRef:
name: my-subaccount-service-manager
subaccountRef:
name: my-subaccount
parameters:
technicalUser: true
---
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: ServiceBinding
metadata:
name: hana-api-binding
spec:
forProvider:
name: hana-api-binding
serviceInstanceRef:
name: hana-api
subaccountRef:
name: my-subaccount
writeConnectionSecretToRef:
namespace: default
name: hana-api-binding-secret
---
apiVersion: v1
kind: Secret
metadata:
name: hana-api-secret
namespace: default
type: Opaque
data:
credentials: '{"baseurl":"{{<baseurl>}}","uaa":{{<uaa>}}}'
---
apiVersion: kro.run/v1alpha1
kind: ResourceGraphDefinition
metadata:
name: cf-hana-instance-mapping
spec:
schema:
apiVersion: v1alpha1
kind: CfHanaInstanceMapping
spec:
serviceInstanceRef: string
orgRef: string
spaceRef: string
resources:
- id: serviceInstance
externalRef:
apiVersion: account.btp.sap.crossplane.io/v1alpha1
kind: ServiceInstance
metadata:
name: ${schema.spec.serviceInstanceRef}
- id: org
externalRef:
apiVersion: cloudfoundry.crossplane.io/v1alpha1
kind: Organization
metadata:
name: ${schema.spec.orgRef}
- id: space
externalRef:
apiVersion: cloudfoundry.crossplane.io/v1alpha1
kind: Space
metadata:
name: ${schema.spec.spaceRef}
- id: instanceMapping
template:
apiVersion: inventory.hana.orchestrate.cloud.sap/v1alpha1
kind: InstanceMapping
metadata:
name: ${schema.metadata.name}
spec:
forProvider:
platform: cloudfoundry
serviceInstanceID: ${serviceInstance.status.atProvider.id}
primaryID: ${org.status.atProvider.id}
secondaryID: ${space.status.atProvider.id}
adminCredentialsSecretRef:
name: hana-api-secret
namespace: default
key: credentials
---
apiVersion: kro.run/v1alpha1
kind: CfHanaInstanceMapping
metadata:
name: cf-hana-instance-mapping
spec:
serviceInstanceRef: my-hana # name of BTP Provider ServiceInstance custom resource
orgRef: my-org # name of CF Provider Organization custom resource
spaceRef: my-space # name of CF Provider Space custom resource

Deployment

  1. Work in progress. Follow "Deploy to SAP Business Technology Platform, Cloud Foundry" for now. If you have @sap/cds-dk installed, you can use cds up to automate multiple steps including mbt build and cf deploy.

Result

The CAP application is now successfully deployed in a Cloud Foundry environment on SAP BTP. All underlying infrastructure is managed as data. Changes to this infrastructure can be made by updating the Kubernetes manifests rather than clicking through the SAP BTP cockpit or running manual CLI commands. 🚀

References

⁉ FAQs

No FAQs yet. Got a question? Reach out to us and help us build this section.