1 package kclient
2
3 import (
4 "context"
5 "errors"
6
7 "github.com/redhat-developer/odo/pkg/api"
8
9 bindingApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
10 specApi "github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha3"
11
12 ocappsv1 "github.com/openshift/api/apps/v1"
13
14 appsv1 "k8s.io/api/apps/v1"
15 corev1 "k8s.io/api/core/v1"
16 kerrors "k8s.io/apimachinery/pkg/api/errors"
17 "k8s.io/apimachinery/pkg/api/meta"
18 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
20 "k8s.io/apimachinery/pkg/runtime/schema"
21 )
22
23 const (
24 ServiceBindingKind = "ServiceBinding"
25 BindableKindsResource = "bindablekinds"
26 )
27
28 var (
29 NativeWorkloadKinds = []schema.GroupVersionKind{
30 appsv1.SchemeGroupVersion.WithKind("DaemonSet"),
31 appsv1.SchemeGroupVersion.WithKind("Deployment"),
32 appsv1.SchemeGroupVersion.WithKind("ReplicaSet"),
33 corev1.SchemeGroupVersion.WithKind("ReplicationController"),
34 appsv1.SchemeGroupVersion.WithKind("StatefulSet"),
35 }
36
37 CustomWorkloadKinds = []schema.GroupVersionKind{
38 ocappsv1.SchemeGroupVersion.WithKind("DeploymentConfig"),
39 }
40 )
41
42
43 func (c *Client) IsServiceBindingSupported() (bool, error) {
44 gvr := bindingApi.GroupVersionResource
45 return c.IsResourceSupported(gvr.Group, gvr.Version, gvr.Resource)
46 }
47
48
49
50 func (c *Client) GetBindableKinds() (bindingApi.BindableKinds, error) {
51 if c.DynamicClient == nil {
52 return bindingApi.BindableKinds{}, nil
53 }
54
55 var (
56 unstructuredBK *unstructured.Unstructured
57 bindableKind bindingApi.BindableKinds
58 err error
59 )
60
61 unstructuredBK, err = c.DynamicClient.Resource(bindingApi.GroupVersion.WithResource(BindableKindsResource)).Get(context.TODO(), "bindable-kinds", v1.GetOptions{})
62 if err != nil {
63 if kerrors.IsNotFound(err) {
64
65 return bindableKind, errors.New("No bindable operators found on the cluster. Please ensure that at least one bindable operator is installed successfully before proceeding. Known Bindable operators: https://github.com/redhat-developer/service-binding-operator#known-bindable-operators")
66
67 }
68 return bindableKind, err
69 }
70
71 err = ConvertUnstructuredToResource(*unstructuredBK, &bindableKind)
72 if err != nil {
73 return bindableKind, err
74 }
75 return bindableKind, nil
76 }
77
78
79 func (c Client) GetBindableKindStatusRestMapping(bindableKindStatuses []bindingApi.BindableKindsStatus) ([]*meta.RESTMapping, error) {
80 var result []*meta.RESTMapping
81 for _, bks := range bindableKindStatuses {
82 if mappingContainsBKS(result, bks) {
83 continue
84 }
85 restMapping, err := c.GetRestMappingFromGVK(schema.GroupVersionKind{
86 Group: bks.Group,
87 Version: bks.Version,
88 Kind: bks.Kind,
89 })
90 if err != nil {
91 return nil, err
92 }
93 result = append(result, restMapping)
94 }
95 return result, nil
96 }
97
98
99 func (c *Client) NewServiceBindingServiceObject(serviceNs string, unstructuredService unstructured.Unstructured, bindingName string) (bindingApi.Service, error) {
100 serviceRESTMapping, err := c.GetRestMappingFromUnstructured(unstructuredService)
101 if err != nil {
102 return bindingApi.Service{}, err
103 }
104
105 var ns *string
106 if serviceNs != "" {
107 ns = &serviceNs
108 }
109
110 return bindingApi.Service{
111 Id: &bindingName,
112 NamespacedRef: bindingApi.NamespacedRef{
113 Ref: bindingApi.Ref{
114 Group: serviceRESTMapping.GroupVersionKind.Group,
115 Version: serviceRESTMapping.GroupVersionKind.Version,
116 Kind: serviceRESTMapping.GroupVersionKind.Kind,
117 Name: unstructuredService.GetName(),
118 Resource: serviceRESTMapping.Resource.Resource,
119 },
120 Namespace: ns,
121 },
122 }, nil
123 }
124
125
126 func NewServiceBindingObject(
127 bindingName string,
128 bindAsFiles bool,
129 workloadName string,
130 namingStrategy string,
131 workloadGVK schema.GroupVersionKind,
132 mappings []bindingApi.Mapping,
133 services []bindingApi.Service,
134 status bindingApi.ServiceBindingStatus,
135 ) *bindingApi.ServiceBinding {
136 return &bindingApi.ServiceBinding{
137 TypeMeta: v1.TypeMeta{
138 APIVersion: bindingApi.GroupVersion.String(),
139 Kind: ServiceBindingKind,
140 },
141 ObjectMeta: v1.ObjectMeta{
142 Name: bindingName,
143 },
144 Spec: bindingApi.ServiceBindingSpec{
145 DetectBindingResources: true,
146 BindAsFiles: bindAsFiles,
147 NamingStrategy: namingStrategy,
148 Application: bindingApi.Application{
149 Ref: bindingApi.Ref{
150 Name: workloadName,
151 Group: workloadGVK.Group,
152 Version: workloadGVK.Version,
153 Kind: workloadGVK.Kind,
154 },
155 },
156 Mappings: mappings,
157 Services: services,
158 },
159 Status: status,
160 }
161 }
162
163
164 func (c Client) GetBindingServiceBinding(name string) (bindingApi.ServiceBinding, error) {
165 if c.DynamicClient == nil {
166 return bindingApi.ServiceBinding{}, nil
167 }
168
169 u, err := c.GetDynamicResource(bindingApi.GroupVersionResource, name)
170 if err != nil {
171 return bindingApi.ServiceBinding{}, err
172 }
173
174 var result bindingApi.ServiceBinding
175 err = ConvertUnstructuredToResource(*u, &result)
176 if err != nil {
177 return bindingApi.ServiceBinding{}, err
178 }
179 return result, nil
180 }
181
182
183 func (c Client) GetSpecServiceBinding(name string) (specApi.ServiceBinding, error) {
184 if c.DynamicClient == nil {
185 return specApi.ServiceBinding{}, nil
186 }
187
188 u, err := c.GetDynamicResource(specApi.GroupVersionResource, name)
189 if err != nil {
190 return specApi.ServiceBinding{}, err
191 }
192
193 var result specApi.ServiceBinding
194 err = ConvertUnstructuredToResource(*u, &result)
195 if err != nil {
196 return specApi.ServiceBinding{}, err
197 }
198 return result, nil
199 }
200
201
202
203
204
205 func (c Client) ListServiceBindingsFromAllGroups() ([]specApi.ServiceBinding, []bindingApi.ServiceBinding, error) {
206 if c.DynamicClient == nil {
207 return nil, nil, nil
208 }
209
210 specsU, err := c.ListDynamicResources("", specApi.GroupVersionResource, "")
211 var specs specApi.ServiceBindingList
212 if err != nil {
213 if !kerrors.IsForbidden(err) {
214 return nil, nil, err
215 }
216 } else {
217 err = ConvertUnstructuredListToResource(*specsU, &specs)
218 if err != nil {
219 return nil, nil, err
220 }
221 }
222
223 bindingsU, err := c.ListDynamicResources("", bindingApi.GroupVersionResource, "")
224 var bindings bindingApi.ServiceBindingList
225 if err != nil {
226 if !kerrors.IsForbidden(err) {
227 return nil, nil, err
228 }
229 } else {
230 err = ConvertUnstructuredListToResource(*bindingsU, &bindings)
231 if err != nil {
232 return nil, nil, err
233 }
234 }
235
236 return specs.Items, bindings.Items, nil
237 }
238
239
240
241 func APIServiceBindingFromBinding(
242 binding bindingApi.ServiceBinding,
243 ) (api.ServiceBinding, error) {
244
245 var dstSvcs []api.ServiceBindingReference
246 for _, srcSvc := range binding.Spec.Services {
247 dstSvc := api.ServiceBindingReference{
248 Name: srcSvc.Name,
249 }
250 dstSvc.APIVersion, dstSvc.Kind = schema.GroupVersion{
251 Group: srcSvc.Group,
252 Version: srcSvc.Version,
253 }.WithKind(srcSvc.Kind).ToAPIVersionAndKind()
254 if srcSvc.Namespace != nil {
255 dstSvc.Namespace = *srcSvc.Namespace
256 }
257 dstSvcs = append(dstSvcs, dstSvc)
258 }
259
260 application := binding.Spec.Application
261 refToApplication := api.ServiceBindingReference{
262 Name: application.Name,
263 Resource: application.Resource,
264 }
265
266 refToApplication.APIVersion, refToApplication.Kind = schema.GroupVersion{
267 Group: application.Group,
268 Version: application.Version,
269 }.WithKind(application.Kind).ToAPIVersionAndKind()
270
271 return api.ServiceBinding{
272 Name: binding.Name,
273 Spec: api.ServiceBindingSpec{
274 Application: refToApplication,
275 Services: dstSvcs,
276 DetectBindingResources: binding.Spec.DetectBindingResources,
277 BindAsFiles: binding.Spec.BindAsFiles,
278 NamingStrategy: binding.Spec.NamingStrategy,
279 },
280 }, nil
281 }
282
283
284
285 func APIServiceBindingFromSpec(spec specApi.ServiceBinding) api.ServiceBinding {
286
287 service := spec.Spec.Service
288 refToService := api.ServiceBindingReference{
289 APIVersion: service.APIVersion,
290 Kind: service.Kind,
291 Name: service.Name,
292 }
293
294 application := spec.Spec.Workload
295 refToApplication := api.ServiceBindingReference{
296 APIVersion: application.APIVersion,
297 Kind: application.Kind,
298 Name: application.Name,
299 }
300
301 return api.ServiceBinding{
302 Name: spec.Name,
303 Spec: api.ServiceBindingSpec{
304 Application: refToApplication,
305 Services: []api.ServiceBindingReference{refToService},
306 DetectBindingResources: false,
307 BindAsFiles: true,
308 },
309 }
310 }
311
312
313
314
315 func (c Client) GetWorkloadKinds() ([]string, []schema.GroupVersionKind, error) {
316 var allWorkloadsKinds = []schema.GroupVersionKind{}
317 var options []string
318 for _, gvk := range NativeWorkloadKinds {
319 options = append(options, gvk.Kind)
320 allWorkloadsKinds = append(allWorkloadsKinds, gvk)
321 }
322
323
324 for _, gvk := range CustomWorkloadKinds {
325 _, err := c.GetGVRFromGVK(gvk)
326 if err != nil {
327
328 if meta.IsNoMatchError(err) {
329 continue
330 }
331 return nil, nil, err
332 }
333 options = append(options, gvk.Kind)
334 allWorkloadsKinds = append(allWorkloadsKinds, gvk)
335 }
336 return options, allWorkloadsKinds, nil
337 }
338
339 func mappingContainsBKS(bindableObjects []*meta.RESTMapping, bks bindingApi.BindableKindsStatus) bool {
340 var gkAlreadyAdded bool
341
342 for _, bo := range bindableObjects {
343 if bo.GroupVersionKind.Group == bks.Group && bo.GroupVersionKind.Kind == bks.Kind {
344 gkAlreadyAdded = true
345 break
346 }
347 }
348 return gkAlreadyAdded
349 }
350
View as plain text