Skip to content

Commit

Permalink
Multi-ServiceBindings for a single application
Browse files Browse the repository at this point in the history
Better handle multiple ServiceBinding resources each targeting the same
application resource. Depending on the order ServiceBindings are applied
to the resource, the order of the resulting volumes, volume mounts and
environment variables could differ. This difference could create churn
on the API server for semantically equivalent resources. Now, we attempt
to sort the entries injected into these lists for the ServiceBindings.

Signed-off-by: Scott Andrews <andrewssc@vmware.com>
  • Loading branch information
scothis committed Oct 5, 2020
1 parent f32ed39 commit 44dfcaa
Showing 1 changed file with 44 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"context"
"crypto/sha1"
"fmt"
"sort"
"strings"

corev1 "k8s.io/api/core/v1"
Expand All @@ -25,6 +26,7 @@ const (
ServiceBindingProjectionConditionApplicationAvailable = "ApplicationAvailable"

ServiceBindingRootEnv = "SERVICE_BINDING_ROOT"
bindingVolumePrefix = "binding-"
)

var sbpCondSet = apis.NewLivingConditionSet(
Expand Down Expand Up @@ -76,7 +78,7 @@ func (b *ServiceBindingProjection) Do(ctx context.Context, ps *duckv1.WithPod) {
newVolumes := sets.NewString()
sb := b.Spec.Binding

bindingVolume := truncateAt63("binding-%x", sha1.Sum([]byte(sb.Name)))
bindingVolume := truncateAt63("%s%x", bindingVolumePrefix, sha1.Sum([]byte(sb.Name)))
if !existingVolumes.Has(bindingVolume) {
ps.Spec.Template.Spec.Volumes = append(ps.Spec.Template.Spec.Volumes, corev1.Volume{
Name: bindingVolume,
Expand All @@ -86,6 +88,16 @@ func (b *ServiceBindingProjection) Do(ctx context.Context, ps *duckv1.WithPod) {
},
},
})
sort.SliceStable(ps.Spec.Template.Spec.Volumes, func(i, j int) bool {
iname := ps.Spec.Template.Spec.Volumes[i].Name
jname := ps.Spec.Template.Spec.Volumes[j].Name
// only sort injected volumes
// TODO be explicit about our bindings vs things that look like it might be our binding
if !strings.HasPrefix(iname, bindingVolumePrefix) || !strings.HasPrefix(jname, bindingVolumePrefix) {
return false
}
return iname < jname
})
existingVolumes.Insert(bindingVolume)
newVolumes.Insert(bindingVolume)
}
Expand Down Expand Up @@ -136,19 +148,41 @@ func (b *ServiceBindingProjection) doContainer(ctx context.Context, ps *duckv1.W
MountPath: fmt.Sprintf("%s/%s", mountPath, b.Spec.Name),
ReadOnly: true,
})
sort.SliceStable(c.VolumeMounts, func(i, j int) bool {
iname := c.VolumeMounts[i].Name
jname := c.VolumeMounts[j].Name
// only sort injected volume mounts
// TODO be explicit about our bindings vs things that look like it might be our binding
if !strings.HasPrefix(iname, bindingVolumePrefix) || !strings.HasPrefix(jname, bindingVolumePrefix) {
return false
}
return iname < jname
})
}

for _, e := range b.Spec.Env {
c.Env = append(c.Env, corev1.EnvVar{
Name: e.Name,
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
if len(b.Spec.Env) != 0 {
for _, e := range b.Spec.Env {
c.Env = append(c.Env, corev1.EnvVar{
Name: e.Name,
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: e.Key,
},
Key: e.Key,
},
},
})
}
sort.SliceStable(c.Env, func(i, j int) bool {
iv := c.Env[i]
jv := c.Env[j]
// only sort injected env
// TODO be explicit about our bindings vs things that look like it might be our binding
if iv.ValueFrom == nil || iv.ValueFrom.SecretKeyRef == nil || jv.ValueFrom == nil || jv.ValueFrom.SecretKeyRef == nil {
return false
}
return iv.Name < jv.Name
})
}
}
Expand Down

0 comments on commit 44dfcaa

Please sign in to comment.