Usage
How to use cf-service-operator
cf-service-operator introduces the following resource types:
Space and ClusterSpace: used to represent or manage Cloud Foundry spaces at namespace or cluster level.
A ServiceInstance object always references exactly one Space or ClusterSpace.
ServiceInstance: used to manage (create/update) a Cloud Foundry service instance.
A ServiceInstance references a Space or ClusterSpace, the Cloud Foundry service offering/plan, and optionally defines service parameters.
ServiceBinding: used to manage (create/update) a Cloud Foundry service binding.
A ServiceBinding references a ServiceInstance Object, and defines the Kubernetes secret used to store the retrieved service key.
Optionally binding parameters can be specified.
1 - Space resources
Define Cloud Foundry spaces on namespace level
Objects of type spaces.cf.cs.sap.com
represent Cloud Foundry spaces at the scope of a Kubernetes namespace.
Spaces can be defined as managed or unmanaged, and can be referenced by ServiceInstance
objects deployed into the same namespace.
Unmanaged spaces
A Space
object is called unmanaged if it just references an already existing Cloud Foundry space by its GUID via spec.guid
.
The Cloud Foundry space will not be touched at all by the controller.
It just serves as a reference for ServiceInstance
objects to be linked with the underlying Cloud Foundry space. For example:
apiVersion: cf.cs.sap.com/v1alpha1
kind: Space
metadata:
name: k8s
namespace: demo
spec:
# Cloud Foundry space guid
guid: 0a61a2ea-0326-43b6-bc08-3510bd32c5e8
# Secret containing authentication details (Cloud Foundry API address, username, password)
authSecretName: k8s-space
The referenced secret (expected in the same namespace) contains connection details for the space:
apiVersion: v1
kind: Secret
metadata:
name: k8s-space
namespace: demo
stringData:
url: https://api.cf.sap.hana.ondemand.com
username: "<email>"
password: "<password>"
Here the user specified in username
should have at least the space developer role in Cloud Foundry.
Managed spaces
A managed Space
is not linked with an existing Cloud Foundry space. Instead it contains a reference to the target Cloud Foundry
organization as spec.organizationName
.
The controller will then try to maintain a Cloud Foundry space called metadata.name
in that organization, and also delete it once the Space
object is deleted.
For example:
apiVersion: cf.cs.sap.com/v1alpha1
kind: Space
metadata:
name: k8s
namespace: demo
spec:
# Cloud Foundry organization
organizationName: my-org
# Secret containing authentication details (Cloud Foundry API address, username, password)
authSecretName: k8s-space
The name of the Cloud Foundry space can be overridden by specifying spec.name
.
The referenced secret looks the same as in the unmanaged case, but in addition,
it is possible to provide different credentials for the space management, such as:
apiVersion: v1
kind: Secret
metadata:
name: k8s-space
namespace: demo
stringData:
url: https://api.cf.sap.hana.ondemand.com
username: "<email>"
password: "<password>"
org_username: "<email>"
org_password: "<password>"
The user specified as org_username
is then expected to have the organization manager role in Cloud Foundry.
If omitted, the user specified in username
will be used to create/update/delete the space (and that user of course must be an organization manager in that case).
Finally, the user specified in username
will be added as a space manager to the space.
2 - ClusterSpace resources
Define Cloud Foundry spaces on cluster level
Objects of type clusterspaces.cf.cs.sap.com
represent a Cloud Foundry spaces at Kubernetes cluster scope.
Cluster Spaces can be defined as managed or unmanaged, and can be referenced by ServiceInstance
objects across the whole cluster.
Unmanaged cluster spaces
A ClusterSpace
object is called unmanaged if it just references an already existing Cloud Foundry space by its GUID via spec.guid
.
The Cloud Foundry space will not be touched at all by the controller.
It just serves as a reference for ServiceInstance
objects to be linked with the underlying Cloud Foundry space. For example:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ClusterSpace
metadata:
name: k8s
spec:
# Cloud Foundry space guid
guid: 0a61a2ea-0326-43b6-bc08-3510bd32c5e8
# Secret containing authentication details (Cloud Foundry API address, username, password)
authSecretName: k8s-space
The referenced secret must have the same structure used for Space objects, and by default is looked up in the namespace where the operator is deployed (but this can be overridden by command line flag, see the configuration section for more details).
Managed cluster spaces
A managed ClusterSpace
is not linked with an existing Cloud Foundry space. Instead it contains a reference to the target Cloud Foundry
organization as spec.organizationName
.
The controller will then try to maintain a Cloud Foundry space called metadata.name
in that organization, and also delete it once the Space
object is deleted.
For example:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ClusterSpace
metadata:
name: k8s
spec:
# Cloud Foundry organization
organizationName: my-org
# Secret containing authentication details (Cloud Foundry API address, username, password)
authSecretName: k8s-space
The name of the Cloud Foundry space can be overridden by specifying spec.name
.
The referenced secret must have the same structure used for Space objects, and by default is looked up in the namespace where the operator is deployed (but this can be overridden by command line flag, see the configuration section for more details).
3 - ServiceInstance resources
Manage Cloud Foundry service instances
Objects of type serviceinstances.cf.cs.sap.com
represent Cloud Foundry service instances. For
example, deploying the following descriptor will let the controller create or update a Cloud Foundry
instance of the service offering ‘xsuaa’ with plan ‘application’, in the Cloud Foundry space
referenced through the Space object given in spec.spaceName
:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: uaa
namespace: demo
spec:
# Name of a Space object in the same namespace;
# this defines the Cloud Foundry space where the instance will be created
spaceName: k8s
# Name of service offering to be used
serviceOfferingName: xsuaa
# Name of service plan to be used
servicePlanName: application
In order to reference a ClusterSpace instead of a Space, the definition would change like this:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: uaa
namespace: demo
spec:
# Name of a ClusterSpace object;
# this defines the Cloud Foundry space where the instance will be created
clusterSpaceName: k8s
# Name of service offering to be used
serviceOfferingName: xsuaa
# Name of service plan to be used
servicePlanName: application
Furthermore, instead of specifying service offering and plan by name, it is possible to directly
provide the guid of the service plan, such as:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: uaa
namespace: demo
spec:
# Name of a Space object in the same namespace;
# this defines the Cloud Foundry space where the instance will be created
spaceName: k8s
# Guid of service plan to be used
servicePlanGuid: 432bd9db-20e2-4997-825f-e4a937705b87
Instance parameters can be passed like this:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: uaa
namespace: demo
spec:
# Name of a Space object in the same namespace;
# this defines the Cloud Foundry space where the instance will be created
spaceName: k8s
# Name of service offering to be used
serviceOfferingName: xsuaa
# Name of service plan to be used
servicePlanName: application
# Instance parameters (inline)
# Caveat: never specify sensitive parameters here, but use parametersFrom instead!
parameters:
xsappname: myAppName
# Instance parameters (by secret key reference)
parametersFrom:
- name: uaa-params
key: parameters.json
Following the logic implemented by similar controllers (e.g. the K8s service catalog) it is allowed
to specify both parameters
and parametersFrom
, but it is considered an error if a top level key
occurs in more than one of the sources.
In addition, it is possible to annotate custom instance tags, such as:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: uaa
namespace: demo
spec:
# Name of a Space object in the same namespace;
# this defines the Cloud Foundry space where the instance will be created
spaceName: k8s
# Name of service offering to be used
serviceOfferingName: xsuaa
# Name of service plan to be used
servicePlanName: application
# List of custom tags
tags:
- uaa
- xsuaa
- authentication
Annotations
Kubernetes annotations provide a flexible way of controlling the behavior of the reconciliation
process for custom resources.
The cf-service-operator
uses several such annotations for tweaking the behavior of the
reconciliation for service instances.
service-operator.cf.cs.sap.com/recreate-on-creation-failure
:
By default, in all kinds of error situations, the controller will send an update request, in
order to trigger a reconciliation of the instance. However some service brokers do not really
support this approach, specifically when the initial creation of the instance has failed.
To overcome this, this annotation can be set on the service instance object. If present, the
controller will drop and recreate instances which are in a failed creation statem, i.e.
the LastOperation
reported by the Cloud Foundry API is of type create
and state failed
.
service-operator.cf.cs.sap.com/max-retries
:
This annotation defines the maximum number of retries for a failed operation before considering
the operation as failed permanently. It allows other operators using the custom resources for
service instances to specify how many times the controller should attempt to reconcile the
specific service instance before giving up, providing a mechanism to handle transient errors.
If this annotations is not set the number of retries is unlimited.
service-operator.cf.cs.sap.com/timeout-on-reconcile
:
Specifies the timeout for the reconciliation process. If set, this annotation determines how
long the controller should wait before timing out the reconciliation process. This is useful for
operations that are expected to take longer than usual, allowing them to complete without
prematurely terminating.
How to use these annotations
Here are examples on how these annotations are set in the metadata section of the ServiceInstance
custom resource:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceInstance
metadata:
name: example-instance
annotations:
service-operator.cf.cs.sap.com/recreate-on-creation-failure: "true"
service-operator.cf.cs.sap.com/max-retries: "3"
service-operator.cf.cs.sap.com/timeout-on-reconcile: "10m"
spec:
spaceName: development
serviceOfferingName: my-service
servicePlanName: standard
In this example, the service instance example-instance
is configured to automatically recreate on
initial creation failure, retry up to three times on subsequent failures, and has a timeout of ten
minutes for each reconciliation attempt.
Setting Annotations in Kubernetes
To set these annotations, you can either add them directly in the YAML file when creating or
updating a service instance or use the kubectl
command line tool to patch an existing instance:
kubectl annotate serviceinstances example-instance service-operator.cf.cs.sap.com/max-retries=5 --overwrite
This command will set (or update) the max-retries
annotation to 5 for the example-instance
service instance.
4 - ServiceBinding resources
Manage Cloud Foundry service bindings
Objects of type servicebindings.cf.cs.sap.com
represent Cloud Foundry service bindings. For example,
deploying the following descriptor will let the controller deploy a Cloud Foundry credentials binding for the
service instanced managed through the ServiceInstance object referenced by spec.serviceInstanceName
:
apiVersion: cf.cs.sap.com/v1alpha1
kind: ServiceBinding
metadata:
name: uaa
namespace: demo
spec:
serviceInstanceName: uaa
If the binding is successful, the controller will store the retrieved binding credentials in a Kubernetes secret
in the namespace of the ServiceBinding object. By default, the secret will have the same name as the ServiceBinding,
and the top-level keys of the credentials object will become secret keys. In the above example, the returned secret would look like this:
apiVersion: v1
kind: Secret
metadata:
name: uaa
namespace: demo
type: Opaque
stringData:
apiurl: https://api.authentication.sap.hana.ondemand.com
clientid: sb-myAppName!t39788
clientsecret: ***
credential-type: instance-secret
identityzone: mysubaccount
identityzoneid: a48fa6e4-df75-4128-abdd-9400d01f3a18
sburl: https://internal-xsuaa.authentication.sap.hana.ondemand.com
subaccountid: 56f1b3a2-dbc2-43b1-8bd9-61e0f8290c27
tenantid: a48fa6e4-df75-4128-abdd-9400d01f3a18
tenantmode: shared
uaadomain: authentication.sap.hana.ondemand.com
url: https://mysubaccount.authentication.sap.hana.ondemand.com
verificationkey: '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArF3/FjAEJx3LTt+UgM65/5LwyHVYownXmOUriLcEO82PiEPFW2n4438VTj5JTvyk42VW5E97lPuXRuVaialRjVDGBmPC9PX8U4ljYYOL3Wgpkid/PkpNe4H/s/U51xJzGTd/XoyuPw64h4v9B71L7bSjOysD5WPzI32/dIHMI0QbZTX2foB8MZqHjhJmVGll2BlT+E7Q+fwQ6bFXL3Ge7fylPu2EgAhR8rnlvrO7hIGIsIGmbGhRmrp38vdIkFsIhanRgtjh2imPh9tBhsYGxUirgzQqnEWQTvE3QZtlfNJ5fK6rht1oO7orkALHzZ2/azBIAojPk4nNx9hEvoCaVwIDAQAB-----END
PUBLIC KEY-----'
xsappname: myAppName!t39788
zoneid: a48fa6e4-df75-4128-abdd-9400d01f3a18
The name of the secret can be overridden by setting spec.secretName
.
Furthermore, it is possible to render the whole service credentials object into a single key of the target secret by specifying spec.secretKey
.
Finally, if the binding requires parameters, those can be passed by setting spec.parameters
and/or spec.parametersFrom
;
here the same logic applies as for ServiceInstance objects.
Updating parameters on the ServiceBinding object has no effect by default (because the Cloud Foundry API does not support such updates). However it is possible to enforce a recreation of the Cloud Foundry binding in that situation by setting the annotation service-operator.cf.cs.sap.com/rotate-on-parameter-change: "true"
.
In addition to this, setting the annotation service-operator.cf.cs.sap.com/rotate-on-instance-change: "true"
triggers a recreation of the Cloud Foundry binding whenever the referenced service instance changes (due to plan or instance parameter changes).
Recently, SAP published a specification to extend binding credentials by additional metadata, to leverage better Kubernetes support in the xsenv library. By default, cf-service-operator will not add these metadata (to remain backwards compatible), but there is a global controller flag --sap-binding-metadata
that can be used to enhance all created binding secrets by default. In addition, the default behavior can be overridden on a per service binding basis by setting the annotation service-operator.cf.cs.sap.com/with-sap-binding-metadata: "true"
, or "false"
.