Advanced binding options

Naming strategies

Naming strategies are available only for the binding.operators.coreos.com API group.

Naming strategies use Go templates to help you define custom binding names through the service binding request. Naming strategies apply for all attributes including the mappings in the ServiceBinding custom resource (CR).

A backing service projects the binding names as files or environment variables into the workload. If a workload expects the projected binding names in a particular format, but the binding names to be projected from the backing service are not available in that format, then you can change the binding names using naming strategies.

Predefined post-processing functions

While using naming strategies, depending on the expectations or requirements of your workload, you can use the following predefined post-processing functions in any combination to convert the character strings:

  • upper: Converts the character strings into capital or uppercase letters.

  • lower: Converts the character strings into lowercase letters.

  • title: Converts the character strings where the first letter of each word is capitalized except for certain minor words.

Predefined naming strategies

Binding names declared through annotations or Operator Lifecycle Manager (OLM) descriptors are processed for their name change before their projection into the workload according to the following predefined naming strategies:

  • none: When applied, there are no changes in the binding names.

    Example

    After the template compilation, the binding names take the {{ .name }} form.

    host: example.com
    port: 8080
  • upper: Applied when no namingStrategy is defined. When applied, converts all the character strings of the binding name key into capital or uppercase letters.

    Example

    After the template compilation, the binding names take the {{ .service.kind | upper}}_{{ .name | upper }} form.

    DATABASE_HOST: example.com
    DATABASE_PORT: 8080

    If your workload requires a different format, you can define a custom naming strategy and change the binding name using a prefix and a separator, for example, PORT_DATABASE.

  • When the binding names are projected as files, by default the predefined none naming strategy is applied, and the binding names do not change.

  • When the binding names are projected as environment variables and no namingStrategy is defined, by default the predefined uppercase naming strategy is applied.

  • You can override the predefined naming strategies by defining custom naming strategies using different combinations of custom binding names and predefined post-processing functions.

Changing the binding names before projecting them into the workload

You can specify the rules to change the binding names in the .spec.namingStrategy attribute of the ServiceBinding custom resource (CR) only for the binding.operators.coreos.com API group.

For example, consider a Spring PetClinic sample application that connects to the PostgreSQL database. In this case, the PostgreSQL database service exposes the host and port fields of the database to use for binding. The Spring PetClinic sample application can access this exposed binding data through the binding names.

Example: Spring PetClinic sample application in the ServiceBinding CR
...
    application:
      name: nodejs-app
      group: apps
      version: v1
      resource: deployments
...
Example: PostgreSQL database service in the ServiceBinding CR
...
    services:
    - group: postgres-operator.crunchydata.com
      version: v1beta1
      kind: Database
      name: db-demo
...

If namingStrategy is not defined and the binding names are projected as environment variables, then the host: hippo-pgbouncer value in the backing service and the projected environment variable would appear as shown in the following example:

Example
DATABASE_HOST: example.com

where:

DATABASE

Specifies the kind backend service.

HOST

Specifies the binding name.

After applying the POSTGRESQL_{{ .service.kind | upper }}_{{ .name | upper }}_ENV naming strategy, the list of custom binding names prepared by the service binding request appears as shown in the following example:

Example
POSTGRESQL_DATABASE_HOST_ENV: example.com
POSTGRESQL_DATABASE_PORT_ENV: 8080

The following items describe the expressions defined in the POSTGRESQL_{{ .service.kind | upper }}_{{ .name | upper }}_ENV naming strategy:

  • .name: Refers to the binding name exposed by the backing service. In the previous example, the binding names are HOST and PORT.

  • .service.kind: Refers to the kind of service resource whose binding names are changed with the naming strategy.

  • upper: String function used to post-process the character string while compiling the Go template string.

  • POSTGRESQL: Prefix of the custom binding name.

  • ENV: Suffix of the custom binding name.

Similar to the previous example, you can define the string templates in namingStrategy to define how each key of the binding names should be prepared by the service binding request.

Composing custom binding data

As an application developer, you can compose custom binding data only for the binding.operators.coreos.com API group under the following circumstances:

  • The backing service does not expose binding data.

  • The values exposed are not available in the required format as expected by the workload.

For example, consider a case where the backing service CR exposes the host, port, and database user as binding data, but the workload requires that the binding data be consumed as a connection string. You can compose custom binding data using attributes in the Kubernetes resource representing the backing service.

Example
apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name: multi-service-binding
  namespace: service-binding-demo
spec:

  application:
    name: java-app
    group: apps
    version: v1
    resource: deployments

 services:
  - group: postgresql.baiju.dev
    version: v1alpha1
    kind: Database
    name: db-demo (1)
    id: postgresDB (2)
  - group: ibmcloud.ibm.com
    version: v1alpha1
    kind: Binding
    name: mytranslator-binding (3)
    id: translationService

  mappings:
    ## From the database service
    - name: JDBC_URL
      value: 'jdbc:postgresql://{{ .postgresDB.status.dbConnectionIP }}:{{ .postgresDB.status.dbConnectionPort }}/{{ .postgresDB.status.dbName }}'
    - name: DB_USER
      value: '{{ .postgresDB.status.dbCredentials.user }}'

    ## From the translator service
    - name: LANGUAGE_TRANSLATOR_URL
      value: '{{ index translationService.status.secretName "url" }}'
    - name: LANGUAGE_TRANSLATOR_IAM_APIKEY
      value: '{{ index translationService.status.secretName "apikey" }}'

    ## From both the services!
    - name: EXAMPLE_VARIABLE
      value: '{{ .postgresDB.status.dbName }}{{ translationService.status.secretName}}'

    ## Generate JSON.
    - name: DB_JSON (4)
      value: {{ json .postgresDB.status }} (5)
1 Name of the backing service resource.
2 Optional identifier.
3 Name of the translation service.
4 Generated JSON name that is to be projected as the file content or environment value. The JSON name contains the attributes of the backing service custom resource.
5 Generated JSON value that is to be projected as the file content or environment value. The JSON value contains the attributes of the backing service custom resource.

Binding workloads using a label selector

You can use a label selector to specify the workload that is being bound. If you declare a service binding using the label selectors to pick up workloads, the Service Binding Operator periodically attempts to find and bind new workloads that match the given label selector.

For example, you may want to bind a service to every Deployment in a namespace with the environment: production label. Setting an appropriate label selector, the Service Binding Operator can bind each of these workloads with one ServiceBinding resource.

Example of ServiceBinding CR in the binding.operators.coreos.com/v1alpha1 API:
apiVersion: binding.operators.coreos.com/v1alpha1
kind: ServiceBinding
metadata:
  name: multi-application-binding
  namespace: service-binding-demo
spec:
  application:
    labelSelector: (1)
      matchLabels:
        environment: production
    group: apps
    version: v1
    resource: deployments
  services:
    group: ""
    version: v1
    kind: Secret
    name: super-secret-data
1 Specifies the workload that is being bound.
Example of ServiceBinding CR in the servicebinding.io API:
apiVersion: servicebindings.io/v1alpha3
kind: ServiceBinding
metadata:
  name: multi-application-binding
  namespace: service-binding-demo
spec:
  workload:
    selector: (1)
      matchLabels:
        environment: production
    apiVersion: app/v1
    kind: Deployment
  service:
    apiVersion: v1
    kind: Secret
    name: super-secret-data
1 Specifies the workload that is being bound.

Currently, it is forbidden to attempt a binding with the following fields defined:

  1. Both name: and labelSelector in the binding.operators.coreos.com/v1alpha1 API

  2. Both name: and selector in the servicebinding.io API (Spec API)

Any attempt to do so will result in an error.