Skip to content

Commit 3d9b05e

Browse files
committed
Cluster Application Resource Mapping
This change adds an extension specification for a cluster-wide mapping of non-Podspec-able resource types acting as applications. Signed-off-by: Ben Hale <[email protected]>
1 parent f383b62 commit 3d9b05e

6 files changed

+260
-8
lines changed

.gitignore

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
*.orig.*
2-
*.toc.*
1+
.idea

README.md

+98-2
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,14 @@ Behavior within the project is governed by the [Contributor Covenant Code of Con
5757
- [Direct Secret Reference](#direct-secret-reference)
5858
- [Direct Secret Reference Example Resource](#direct-secret-reference-example-resource)
5959
- [Extensions](#extensions)
60+
- [Application Resource Mapping](#application-resource-mapping)
61+
- [Resource Type Schema](#resource-type-schema-2)
62+
- [Container-based Example Resource](#container-based-example-resource)
63+
- [Element-based Example Resource](#element-based-example-resource)
64+
- [Reconciler Implementation](#reconciler-implementation-1)
6065
- [Custom Projection](#custom-projection)
6166
- [Custom Projection Service Binding Example Resource](#custom-projection-service-binding-example-resource)
62-
- [Resource Type Schema](#resource-type-schema-2)
67+
- [Resource Type Schema](#resource-type-schema-3)
6368
- [Service Binding Projection Example Resource](#service-binding-projection-example-resource)
6469
- [Binding `Secret` Generation Strategies](#binding-secret-generation-strategies)
6570
- [OLM Operator Descriptors](#olm-operator-descriptors)
@@ -201,7 +206,6 @@ The Service Binding resource **MAY** define `.spec.application.containers`, as a
201206
- if the value is a string (`${containerString}`), a container or init container matching by name (`.spec.template.spec.containers[?(@.name=='${containerString}')]` or `.spec.template.spec.initContainers[?(@.name=='${containerString}')]`) **MUST** be bound
202207
- values that do not match a container or init container **SHOULD** be ignored
203208

204-
205209
A Service Binding Resource **MAY** define a `.spec.mappings` which is an array of `Mapping` objects. A `Mapping` object **MUST** define `name` and `value` entries. The `value` of a `Mapping` **MUST** be handled as a [Go Template][gt] exposing binding `Secret` keys for substitution. The executed output of the template **MUST** be added to the `Secret` exposed to the resource represented by `application` as the key specified by the `name` of the `Mapping`. If the `name` of a `Mapping` matches that of a Provisioned Service `Secret` key, the value from `Mapping` **MUST** be used for binding.
206210

207211
A Service Binding Resource **MAY** define a `.spec.env` which is an array of `EnvMapping`. An `EnvMapping` object **MUST** define `name` and `key` entries. The `key` of an `EnvMapping` **MUST** refer to a binding `Secret` key name including any key defined by a `Mapping`. The value of this `Secret` entry **MUST** be configured as an environment variable on the resource represented by `application`.
@@ -434,6 +438,98 @@ status:
434438

435439
Extensions are optional additions to the core specification as defined above. Implementation and support of these specifications are not required in order for a platform to be considered compliant. However, if the features addressed by these specifications are supported a platform **MUST** be in compliance with the specification that governs that feature.
436440

441+
## Application Resource Mapping
442+
443+
There are scenarios where an application resource is not strictly PodSpec-able but does include the `env`, `volumeMounts`, and `volumes` elements that are required to project a service binding. This extension defines a mapping of those elements onto any type. It **MUST** be codified as a concrete resource type with API version `service.binding/v1alpha2` and kind `ClusterApplicationResourceMapping`. An exemplar CRD can be found [here][cam-crd].
444+
445+
An Application Resource Mapping **MUST** define its name using [CRD syntax][crd-syntax] (`<plural>.<group>`) for the resource that it defines a mapping for. An Application Resource Mapping **MUST** define a `spec.versions` which is an array of `Version` objects. A `Version` object must define a `version` entry that represents a version of the mapped resource. A `Version` object **MAY** define `.containers`, as an array of strings containing [JSONPath][jsonpath], that describes the location of [`Container`][container] entries in the target resource. A `Version` object **MAY** define `.envs`, as an array of strings containing [JSONPath][jsonpath], that describes the location of [`EnvVar`][envvar] entries in the target resource. A `Version` object **MAY** define `.volumeMounts`, as an array of strings containing [JSONPath][jsonpath], that describes the location of [`VolumeMount`][volumemount] entries in the target resource. A `Version` object **MUST** define `.volumes`, as a string containing [JSONPath][jsonpath], that describes the location of [`Volume`][volume] entries in the target resource.
446+
447+
If an Application Resource Mapping defines `containers`, it **MUST NOT** define `envs` and `volumeMounts`. If an Application resources does not define `containers`, it **MUST** define `envs` and `volumeMounts`.
448+
449+
[cam-crd]: service.binding_clusterapplicationmappings.yaml
450+
[container]: https://kubernetes.io/docs/reference/kubernetes-api/workloads-resources/container/
451+
[crd-syntax]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#create-a-customresourcedefinition
452+
[envvar]: https://kubernetes.io/docs/reference/kubernetes-api/workloads-resources/container/#environment-variables
453+
[jsonpath]: https://kubernetes.io/docs/reference/kubectl/jsonpath/
454+
[volume]: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/volume
455+
[volumemount]: https://kubernetes.io/docs/reference/kubernetes-api/workloads-resources/container/#volumes
456+
457+
### Resource Type Schema
458+
459+
```yaml
460+
apiVersion: service.binding/v1alpha2
461+
kind: ClusterApplicationResourceMapping
462+
metadata:
463+
name: # string
464+
generation: # int64, defined by the Kubernetes control plane
465+
...
466+
spec:
467+
versions: # []Version
468+
- version: # string
469+
containers: # []string, optional
470+
envs: # []string, optional
471+
volumeMounts: # []string, optional
472+
volumes: # string
473+
```
474+
475+
### Container-based Example Resource
476+
477+
```yaml
478+
apiVersion: service.binding/v1alpha2
479+
kind: ClusterApplicationResourceMapping
480+
metadata:
481+
name: cronjobs.batch
482+
spec:
483+
versions:
484+
- version: v1beta1
485+
containers:
486+
- .spec.jobTemplate.spec.template.spec.containers
487+
- .spec.jobTemplate.spec.template.spec.initContainers
488+
volumes: .spec.jobTemplate.spec.template.spec.volumes
489+
- version: v2alpha1
490+
containers:
491+
- .spec.jobTemplate.spec.template.spec.containers
492+
- .spec.jobTemplate.spec.template.spec.initContainers
493+
volumes: .spec.jobTemplate.spec.template.spec.volumes
494+
```
495+
496+
### Element-based Example Resource
497+
498+
```yaml
499+
apiVersion: service.binding/v1alpha2
500+
kind: ClusterApplicationResourceMapping
501+
metadata:
502+
name: cronjobs.batch
503+
spec:
504+
versions:
505+
- version: v1beta1
506+
env:
507+
- .spec.jobTemplate.spec.template.spec.containers[*].env
508+
- .spec.jobTemplate.spec.template.spec.initContainers[*].env
509+
volumeMounts:
510+
- .spec.jobTemplate.spec.template.spec.containers[*].volumeMounts
511+
- .spec.jobTemplate.spec.template.spec.initContainers[*].volumeMounts
512+
volumes: .spec.jobTemplate.spec.template.spec.volumes
513+
- version: v2alpha1
514+
env:
515+
- .spec.jobTemplate.spec.template.spec.containers[*].env
516+
- .spec.jobTemplate.spec.template.spec.initContainers[*].env
517+
volumeMounts:
518+
- .spec.jobTemplate.spec.template.spec.containers[*].volumeMounts
519+
- .spec.jobTemplate.spec.template.spec.initContainers[*].volumeMounts
520+
volumes: .spec.jobTemplate.spec.template.spec.volumes
521+
```
522+
523+
### Reconciler Implementation
524+
525+
A reconciler implementation that supports `ClusterApplicationResourceMapping`s **MUST** support `ServiceBinding` resources that refer to applications that are not PodSpec-able. If no Application Resource Mapping exists for the `ServiceBinding` application resource type, the reconciliation **MUST** fail.
526+
527+
If a `ClusterApplicationResourceMapping` defines `containers`, the reconciler **MUST** first resolve a set of candidate locations in the application resource addressed by the `ServiceBinding` using the `Container` type (`.env`, `.volumeMounts`) for all available containers and then filter that collection by the `ServiceBinding` `.spec.application.containers` filter before applying the appropriate modification.
528+
529+
If a `ClusterApplicationResourceMapping` defines `env` and `volumeMounts`, the reconciler **MUST** first resolve a set of candidate locations in the application resource addressed by the `ServiceBinding` for all available containers and then filter that collection by the `ServiceBinding` `.spec.application.containers` filter before applying the appropriate modification.
530+
531+
A reconciler **MUST** apply the appropriate modification to the application resource addressed by the `ServiceBinding` as defined by `volumes`.
532+
437533
## Custom Projection
438534

439535
There are scenarios where the Reconciler that processes a `ServiceBinding` (hereinafter referred to as "Reconciler A") is different than the Reconciler that will project the binding into the Application (hereinafter referred to as "Reconciler B"). To transfer the projection responsibility from Reconciler A to Reconciler B the `ServiceBinding` author **MUST** set the `projection.service.binding/type` annotation to `Custom`. An exemplar CRD can be found [here][sbp-crd].

internal.service.binding_servicebindingprojections.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ spec:
132132
description: Env is the collection of mappings from Secret entries
133133
to environment variables
134134
items:
135-
description: EnvMapping defines a mapping from
136-
the value of a Secret entry to an environment variable
135+
description: EnvMapping defines a mapping from the value of a Secret
136+
entry to an environment variable
137137
properties:
138138
key:
139139
description: Key is the key in the Secret that will be exposed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package v1alpha2
18+
19+
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20+
21+
// ClusterApplicationResourceMappingVersion defines the mapping for a specific version of an application resource.
22+
type ClusterApplicationResourceMappingVersion struct {
23+
// Version is the version of the application resource that this mapping is for.
24+
Version string `json:"version"`
25+
// Containers is the collection of JSONPaths that container configuration may be written to.
26+
Containers []string `json:"containers,omitempty"`
27+
// Envs is the collection of JSONPaths that env configuration may be written to.
28+
Envs []string `json:"envs,omitempty"`
29+
// VolumeMounts is the collection of JSONPaths that volume mount configuration may be written to.
30+
VolumeMounts []string `json:"volumeMounts,omitempty"`
31+
// Volumes is the JSONPath that volume configuration must be written to.
32+
Volumes string `json:"volumes"`
33+
}
34+
35+
36+
// ClusterApplicationResourceMappingSpec defines the desired state of ClusterApplicationResourceMapping
37+
type ClusterApplicationResourceMappingSpec struct {
38+
// Versions is the collection of versions for a given resource, with mappings.
39+
Versions []ClusterApplicationResourceMappingVersion `json:"versions,omitempty"`
40+
}
41+
42+
// +kubebuilder:object:root=true
43+
// +kubebuilder:storageversion
44+
// +kubebuilder:subresource:status
45+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
46+
47+
// ClusterApplicationResourceMapping is the Schema for the clusterapplicationresourcemappings API
48+
type ClusterApplicationResourceMapping struct {
49+
metav1.TypeMeta `json:",inline"`
50+
metav1.ObjectMeta `json:"metadata,omitempty"`
51+
52+
Spec ClusterApplicationResourceMappingSpec `json:"spec,omitempty"`
53+
}
54+
55+
// +kubebuilder:object:root=true
56+
57+
// ClusterApplicationResourceMappingList contains a list of ClusterApplicationResourceMapping
58+
type ClusterApplicationResourceMappingList struct {
59+
metav1.TypeMeta `json:",inline"`
60+
metav1.ListMeta `json:"metadata,omitempty"`
61+
62+
Items []ClusterApplicationResourceMapping `json:"items"`
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
2+
---
3+
apiVersion: apiextensions.k8s.io/v1
4+
kind: CustomResourceDefinition
5+
metadata:
6+
annotations:
7+
controller-gen.kubebuilder.io/version: v0.3.0
8+
creationTimestamp: null
9+
name: clusterapplicationresourcemappings.service.binding
10+
spec:
11+
group: service.binding
12+
names:
13+
kind: ClusterApplicationResourceMapping
14+
listKind: ClusterApplicationResourceMappingList
15+
plural: clusterapplicationresourcemappings
16+
singular: clusterapplicationresourcemapping
17+
scope: Namespaced
18+
versions:
19+
- additionalPrinterColumns:
20+
- jsonPath: .metadata.creationTimestamp
21+
name: Age
22+
type: date
23+
name: v1alpha2
24+
schema:
25+
openAPIV3Schema:
26+
description: ClusterApplicationResourceMapping is the Schema for the clusterapplicationresourcemappings
27+
API
28+
properties:
29+
apiVersion:
30+
description: 'APIVersion defines the versioned schema of this representation
31+
of an object. Servers should convert recognized schemas to the latest
32+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
33+
type: string
34+
kind:
35+
description: 'Kind is a string value representing the REST resource this
36+
object represents. Servers may infer this from the endpoint the client
37+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
38+
type: string
39+
metadata:
40+
type: object
41+
spec:
42+
description: ClusterApplicationResourceMappingSpec defines the desired
43+
state of ClusterApplicationResourceMapping
44+
properties:
45+
versions:
46+
description: Versions is the collection of versions for a given resource,
47+
with mappings.
48+
items:
49+
description: ClusterApplicationResourceMappingVersion defines the
50+
mapping for a specific version of an application resource.
51+
properties:
52+
containers:
53+
description: Containers is the collection of JSONPaths that
54+
container configuration may be written to.
55+
items:
56+
type: string
57+
type: array
58+
envs:
59+
description: Envs is the collection of JSONPaths that env configuration
60+
may be written to.
61+
items:
62+
type: string
63+
type: array
64+
version:
65+
description: Version is the version of the application resource
66+
that this mapping is for.
67+
type: string
68+
volumeMounts:
69+
description: VolumeMounts is the collection of JSONPaths that
70+
volume mount configuration may be written to.
71+
items:
72+
type: string
73+
type: array
74+
volumes:
75+
description: Volumes is the JSONPath that volume configuration
76+
must be written to.
77+
type: string
78+
required:
79+
- version
80+
- volumes
81+
type: object
82+
type: array
83+
type: object
84+
type: object
85+
served: true
86+
storage: true
87+
subresources:
88+
status: {}
89+
status:
90+
acceptedNames:
91+
kind: ""
92+
plural: ""
93+
conditions: []
94+
storedVersions: []

service.binding_servicebindings.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ spec:
121121
description: Env is the collection of mappings from Secret entries
122122
to environment variables
123123
items:
124-
description: EnvMapping defines a mapping from the value
125-
of a Secret entry to an environment variable
124+
description: EnvMapping defines a mapping from the value of a Secret
125+
entry to an environment variable
126126
properties:
127127
key:
128128
description: Key is the key in the Secret that will be exposed

0 commit comments

Comments
 (0)