1 package service
2
3
4
5
6
7
8
9
10
11
12 import (
13 "fmt"
14
15 "github.com/redhat-developer/odo/pkg/log"
16
17 "github.com/redhat-developer/service-binding-operator/apis"
18 "github.com/redhat-developer/service-binding-operator/pkg/binding"
19 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20
21 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
22 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder"
23 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect"
24 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping"
25 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming"
26 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/project"
27 "github.com/redhat-developer/service-binding-operator/pkg/util"
28 kerrors "k8s.io/apimachinery/pkg/api/errors"
29 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30 )
31
32 var defaultFlow = []pipeline.Handler{
33 pipeline.HandlerFunc(project.Unbind),
34 pipeline.HandlerFunc(collect.PreFlight),
35 pipeline.HandlerFunc(ProvisionedService),
36 pipeline.HandlerFunc(collect.DirectSecretReference),
37 pipeline.HandlerFunc(BindingDefinitions),
38 pipeline.HandlerFunc(collect.BindingItems),
39 pipeline.HandlerFunc(collect.OwnedResources),
40 pipeline.HandlerFunc(mapping.Handle),
41 pipeline.HandlerFunc(naming.Handle),
42 pipeline.HandlerFunc(project.PreFlightCheck()),
43 pipeline.HandlerFunc(project.InjectSecretRef),
44 pipeline.HandlerFunc(project.BindingsAsEnv),
45 pipeline.HandlerFunc(project.BindingsAsFiles),
46 pipeline.HandlerFunc(project.PostFlightCheck),
47 }
48
49 var OdoDefaultBuilder = builder.Builder().WithHandlers(defaultFlow...)
50
51 func ProvisionedService(ctx pipeline.Context) {
52 services, _ := ctx.Services()
53
54 for _, service := range services {
55 res := service.Resource()
56 secretName, found, err := unstructured.NestedString(res.Object, "status", "binding", "name")
57 if err != nil {
58 requestRetry(ctx, collect.ErrorReadingBindingReason, err)
59 return
60 }
61 if found {
62 if secretName != "" {
63 secret, err := ctx.ReadSecret(res.GetNamespace(), secretName)
64 if err != nil {
65 requestRetry(ctx, collect.ErrorReadingSecret, err)
66 return
67 }
68 ctx.AddBindings(&pipeline.SecretBackedBindings{Service: service, Secret: secret})
69 }
70 } else {
71 crd, err := service.CustomResourceDefinition()
72 if err != nil {
73
74 if !kerrors.IsForbidden(err) {
75 requestRetry(ctx, collect.ErrorReadingCRD, err)
76 return
77 } else {
78 log.Warning("Skipping the check for CRD, user does not have access")
79 continue
80 }
81 }
82 if crd == nil {
83 continue
84 }
85 v, ok := crd.Resource().GetAnnotations()[binding.ProvisionedServiceAnnotationKey]
86 if ok && v == "true" {
87 requestRetry(ctx, collect.ErrorReadingBindingReason, fmt.Errorf("CRD of service %v/%v indicates provisioned service, but no secret name provided under .status.binding.name", res.GetNamespace(), res.GetName()))
88 return
89 }
90 }
91 }
92 }
93
94 func BindingDefinitions(ctx pipeline.Context) {
95 services, _ := ctx.Services()
96
97 for _, service := range services {
98 anns := make(map[string]string)
99 crd, err := service.CustomResourceDefinition()
100 if err != nil {
101
102 if !kerrors.IsForbidden(err) {
103 requestRetry(ctx, collect.ErrorReadingCRD, err)
104 return
105 } else {
106 log.Warning("Skipping the check for CRD, user does not have access")
107
108 }
109 }
110 if crd != nil {
111 descr, err := crd.Descriptor()
112 if err != nil {
113 requestRetry(ctx, collect.ErrorReadingDescriptorReason, err)
114 return
115 }
116 if descr != nil {
117 util.MergeMaps(anns, descr.BindingAnnotations())
118 }
119 util.MergeMaps(anns, crd.Resource().GetAnnotations())
120 }
121
122 util.MergeMaps(anns, service.Resource().GetAnnotations())
123
124 for k, v := range anns {
125 definition, err := makeBindingDefinition(k, v, ctx)
126 if err != nil {
127 condition := notCollectionReadyCond(collect.InvalidAnnotation, fmt.Errorf("failed to create binding definition from \"%v: %v\": %v", k, v, err))
128 ctx.SetCondition(condition)
129 ctx.Error(err)
130 ctx.StopProcessing()
131 }
132 if definition != nil {
133 service.AddBindingDef(definition)
134 }
135 }
136 }
137 }
138
139 func requestRetry(ctx pipeline.Context, reason string, err error) {
140 ctx.RetryProcessing(err)
141 ctx.SetCondition(notCollectionReadyCond(reason, err))
142 }
143
144 func notCollectionReadyCond(reason string, err error) *metav1.Condition {
145 return apis.Conditions().NotCollectionReady().Reason(reason).Msg(err.Error()).Build()
146 }
147
148 func makeBindingDefinition(key string, value string, ctx pipeline.Context) (binding.Definition, error) {
149 return binding.NewDefinitionBuilder(key,
150 value,
151 func(namespace string, name string) (*unstructured.Unstructured, error) {
152 return ctx.ReadConfigMap(namespace, name)
153 },
154 func(namespace string, name string) (*unstructured.Unstructured, error) {
155 return ctx.ReadSecret(namespace, name)
156 }).Build()
157 }
158
View as plain text