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.
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
- You have a running control plane.
- You have cloned cloud-cap-samples-java to your local machine.
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.
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
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.
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
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
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
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
- Assign the
SpaceDeveloperrole 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
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.
- Create an entitlement for HDI containers (
serviceName: hanaandservicePlanName: 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
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
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
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
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
- Work in progress. Follow "Deploy to SAP Business Technology Platform, Cloud Foundry" for now. If you have
@sap/cds-dkinstalled, you can usecds upto automate multiple steps includingmbt buildandcf 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
- Deploy to Cloud Foundry guide in CAP documentation
- Deploy to Kyma guide in CAP documentation
- Set Up Schema or HDI Container (Cloud Foundry) in SAP Help Portal
⁉ FAQs
No FAQs yet. Got a question? Reach out to us and help us build this section.