Skip to content
This repository was archived by the owner on Jun 26, 2024. It is now read-only.

Commit 252987b

Browse files
sadlerapIgor Sutton
and
Igor Sutton
authored
Fix crash when annotation's sourceValue is invalid (#967) (#1015)
A service can have a sliceOfMaps-based element annotation. For example: service.binding/java-maven_port: path={.spec.ports},elementType=sliceOfMaps,sourceKey=name,sourceValue=asdf When sourceValue is incorrect, the operator would panic, since it didn't verify that the sourceValue was incorrect. Now, it sets an error condition in the reconciler (which propogates to the binding status). Signed-off-by: Andy Sadler <[email protected]> Co-authored-by: Igor Sutton <[email protected]>
1 parent 2785337 commit 252987b

File tree

4 files changed

+97
-1
lines changed

4 files changed

+97
-1
lines changed

pkg/reconcile/pipeline/handler/collect/impl.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ import (
1818
)
1919

2020
var DataNotMap = errors.New("Returned data are not a map, skip collecting")
21+
var ErrorValueNotFound = errors.New("Value not found in map")
2122

2223
const (
2324
ErrorReadingServicesReason = "ErrorReadingServices"
2425
ErrorReadingCRD = "ErrorReadingCRD"
2526
ErrorReadingDescriptorReason = "ErrorReadingDescriptor"
2627
ErrorReadingBindingReason = "ErrorReadingBinding"
2728
ErrorReadingSecret = "ErrorReadingSecret"
29+
30+
ValueNotFound = "ValueNotFound"
2831
)
2932

3033
func PreFlight(ctx pipeline.Context) {
@@ -249,7 +252,17 @@ func collectItems(prefix string, ctx pipeline.Context, service pipeline.Service,
249252
p = ""
250253
}
251254
for _, n := range v.MapKeys() {
252-
collectItems(p, ctx, service, n, v.MapIndex(n).Interface())
255+
if mapVal := v.MapIndex(n).Interface(); mapVal != nil {
256+
collectItems(p, ctx, service, n, mapVal)
257+
} else {
258+
condition := apis.Conditions().NotCollectionReady().
259+
Msg(fmt.Sprintf("Value for key %v_%v not found", prefix+k.String(), n.String())).
260+
Reason(ValueNotFound).Build()
261+
ctx.SetCondition(condition)
262+
ctx.Error(ErrorValueNotFound)
263+
ctx.StopProcessing()
264+
return
265+
}
253266
}
254267
case reflect.Slice:
255268
for i := 0; i < v.Len(); i++ {

pkg/reconcile/pipeline/handler/collect/impl_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,38 @@ var _ = Describe("Collect Binding Data", func() {
388388
shouldRetry(pipeline.HandlerFunc(collect.BindingItems), collect.ErrorReadingBindingReason, err)
389389
})
390390

391+
Context("on nil value in collected bindings", func() {
392+
It("should set an error condition and stop processing the pipeline",
393+
func() {
394+
serviceResource := &unstructured.Unstructured{}
395+
396+
ctx := mocks.NewMockContext(mockCtrl)
397+
service := mocks.NewMockService(mockCtrl)
398+
definition := bindingmocks.NewMockDefinition(mockCtrl)
399+
value := bindingmocks.NewMockValue(mockCtrl)
400+
401+
ctx.EXPECT().Services().Return([]pipeline.Service{service}, nil)
402+
403+
bindingDefs := []binding.Definition{definition}
404+
service.EXPECT().BindingDefs().Return(bindingDefs)
405+
service.EXPECT().Resource().Return(serviceResource)
406+
407+
definition.EXPECT().Apply(serviceResource).Return(value, nil)
408+
value.EXPECT().Get().Return(map[string]map[string]interface{}{"java-maven_port": {"foo": nil}})
409+
410+
ctx.EXPECT().SetCondition(
411+
apis.Conditions().NotCollectionReady().
412+
Reason(collect.ValueNotFound).
413+
Msg("Value for key java-maven_port_foo not found").
414+
Build())
415+
ctx.EXPECT().Error(collect.ErrorValueNotFound)
416+
ctx.EXPECT().StopProcessing()
417+
418+
collect.BindingItems(ctx)
419+
},
420+
)
421+
})
422+
391423
Context("on returning unexpected data", func() {
392424
var (
393425
service *mocks.MockService

test/acceptance/features/bindAppToServiceAnnotations.feature

+42
Original file line numberDiff line numberDiff line change
@@ -542,3 +542,45 @@ Feature: Bind an application to a service using annotations
542542
"""
543543
Then Service Binding "binding-app-via-gvk" is ready
544544
And The application env var "BACKEND_HOST_INTERNAL_DB" has value "internal.db.stable.example.com"
545+
546+
Scenario: Application cannot be bound to service containing annotation with an invalid sourceValue value
547+
Given Generic test application is running
548+
And CustomResourceDefinition backends.stable.example.com is available
549+
And The Custom Resource is present
550+
"""
551+
apiVersion: stable.example.com/v1
552+
kind: Backend
553+
metadata:
554+
name: $scenario_id
555+
annotations:
556+
service.binding/webarrows: path={.spec.connections},elementType=sliceOfMaps,sourceKey=type,sourceValue=asdf
557+
spec:
558+
connections:
559+
- type: primary
560+
url: primary.example.com
561+
status:
562+
somestatus: good
563+
"""
564+
When Service Binding is applied
565+
"""
566+
apiVersion: binding.operators.coreos.com/v1alpha1
567+
kind: ServiceBinding
568+
metadata:
569+
name: $scenario_id
570+
spec:
571+
bindAsFiles: false
572+
services:
573+
- group: stable.example.com
574+
version: v1
575+
kind: Backend
576+
name: $scenario_id
577+
application:
578+
name: $scenario_id
579+
group: apps
580+
version: v1
581+
resource: deployments
582+
"""
583+
Then Service Binding CollectionReady.status is "False"
584+
And Service Binding CollectionReady.reason is "ValueNotFound"
585+
And Service Binding CollectionReady.message is "Value for key webarrows_primary not found"
586+

test/acceptance/resources/backend_crd.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ spec:
4444
type: string
4545
environment:
4646
type: string
47+
connections:
48+
type: array
49+
items:
50+
type: object
51+
properties:
52+
type:
53+
type: string
54+
url:
55+
type: string
4756
status:
4857
type: object
4958
properties:

0 commit comments

Comments
 (0)